Daily 2018-12-11

TIL

c++ 언어로 사각형 그리기

#include "pch.h"
#include <iostream>
#include <math.h>

typedef struct _Point {
   int posX;
   int posY;
} Point;

class MyRect {
private:
   Point myPoints[4];
   int validateRect(Point* points);
   int rectType;
   double getDistance(Point pointA, Point pointB);
   double getPowOfDistance(Point pointA, Point pointB);

public:
   enum {
      RECT_TYPE_NORMAL = 1,
      RECT_TYPE_TILTED = 2
   };

   MyRect(Point* points);

   double CalRectArea();
};


// swift에서는 filter를 사용해서 자체 반복문으로 구할 수 있지만.
// c++의 경우 filter가 없음으로 하나하나 for문을 돌려야함.
int MyRect::validateRect(Point * points)
{
   // 가장 첫번째로 들어온 데이터를 기준으로 처리.
   myPoints[0] = points[0];

   //45도 정도 기울어진 형태의 직사각형 or 정사각형 처리.
   Point symmPoint;
   int symmPointIndex = 0;
   bool sameXPos = false;

   memset(&symmPoint, 0x00, sizeof(symmPoint));

   // symmetry 단어 뜻 대칭, 약자로 symm 사용
   // 좌표(45도 기울어지 사각형)는 4개의 점 중에서 2개는 X좌표가 같고 2개는 Y좌표가 같아야함.
   // 첫번째로 우선 point0에 대칭되는 점을 찾는다. 
   // 대칭점이 X좌표가 같은지 Y좌표가 같은지 모르므로 우선 X먼저 비교하여 같은 지점을 찾는다.
   for (int i = 1; i < 4; i++) {
      if (points[0].posX == points[i].posX) {
         symmPointIndex = i;
         symmPoint = points[i];
         // X좌표가 같은 경우 체크
         sameXPos = true;
         break;
      }
   }

   // 만약 X좌표가 일치하는 좌표가 없다면 Y좌표를 비교.
   if (symmPointIndex == 0) {
      for (int i = 1; i < 4; i++) {
         if (points[0].posY == points[i].posY) {
            symmPointIndex = i;
            symmPoint = points[i];
            break;
         }
      }
   }

   // Y좌표를 비교해서 해당 인덱스가 존재하면 처리하고 아니면
   // 일반적으로 들어오는 사각형 좌표 체크를 한다.
   if (symmPointIndex != 0) {
      int inputIndex = 0;

      for (int i = 1; i < 4; i++) {
         // 위에서 확인한 대칭하는 좌표는 필요 없음.
         if (symmPointIndex == i) {
            continue;
         }

         // 대칭으로 일치하는 것은 0, 1에 들어가있음.
         // 일치하는걸 제외한 나머지를 2,3 번에 저장.
         this->myPoints[2 + inputIndex] = points[i];   
         inputIndex++;

         myPoints[0] = points[0];
         myPoints[1] = symmPoint;
      }
      
      // sameXPos가 true라면 0,1번이 X좌표가 같아야하고, 2,3번이 Y좌표가 같아야함.
      // false일 경우는 반대로, 0,1번이 Y좌표가 같아야하고, 2,3번이 X좌표가 같아야함.
      bool checkPos = false;
      if (sameXPos) {
         if ((myPoints[0].posX == myPoints[1].posX) && (myPoints[2].posY == myPoints[3].posY)) {
            checkPos = true;
         }
      }
      else {
         if ((myPoints[0].posY == myPoints[1].posY) && (myPoints[2].posX == myPoints[3].posX)) {
            checkPos = true;
         }
      }

      // 위의 조건이 참일 경우, 
      // 두 대각선의 길이를 비교하여 같으면서 각이 직각이여야 직각사각형으로 판별.
      // 각이 직간인지 확인하는 방법은 피타고라스 정리를 이용합니다. 각이 직각이면 A^2 = B^2 + C^2이니까
      // 반대로 말하면 A^2 = B^2 + C^2 식을 만족하면 각이 직갑
      // 대각선의 양 끝쪽 각(즉 마주보고있는 각)이 둘다 직각(90도)이면 사각형안의 모든 각은 전부 직각
      // 체크 후, 조건이 참이라면 RECT_TYPE_TILTED를 반환
      // 조건이 참이 아니면 일반적으로 들어오는 사각형 좌표 체크를 위해 다음 블럭 진행.
      // 좌표를 그림으로 그리면.
      // myPoints[0]         myPoints[3]
      //
      // myPoints[2]         myPoints[1]
      // 즉 각을 구하기 위해서는 diagnoalA의 제곱의 값과  
      if (checkPos) {
         double diagonalA = getDistance(myPoints[0], myPoints[1]);
         double diagonalB = getDistance(myPoints[2], myPoints[3]);

         // lineA = myPoint[0]과 myPoint[3]의 거리
         double powOfLineA = getPowOfDistance(myPoints[0], myPoints[3]);
         // lineB = myPoint[0]과 myPoint[2]의 거리
         double powOfLineB = getPowOfDistance(myPoints[0], myPoints[2]);
         // lineC = myPoint[1]과 myPoint[2]의 거리
         double powOfLineC = getPowOfDistance(myPoints[1], myPoints[2]);
         // lineD = myPoint[1]과 myPoint[3]의 거리
         double powOfLineD = getPowOfDistance(myPoints[1], myPoints[3]);

         double powOfLineAB = powOfLineA + powOfLineB;
         double powOfLineCD = powOfLineC + powOfLineD;
         double powOfDiagonalB = getPowOfDistance(myPoints[2], myPoints[3]);

         if ((diagonalA == diagonalB)&&(powOfLineAB == powOfDiagonalB)&&(powOfLineCD == powOfDiagonalB)) {
            return RECT_TYPE_TILTED;
         }
      }
   }
   
   // 일반적으로 들어오는 사각형 좌표.
   Point sameXPoint;
   Point sameYPoint;
   Point otherPoint;

   memset(&sameXPoint, 0x00, sizeof(Point));
   memset(&sameYPoint, 0x00, sizeof(Point));
   memset(&otherPoint, 0x00, sizeof(Point));

   // sameXPoint 구하는 for문.
   for (int i = 1; i < 4; i++) {
      if (points[0].posX == points[i].posX) {
         sameXPoint = points[i];
         break;
      }
   }

   // sameYPoint 구하는 for문.
   for (int i = 1; i < 4; i++) {
      if (points[0].posY == points[i].posY) {
         sameYPoint = points[i];
         break;
      }
   }

   // sameXPoint 구하는 for문.
   for (int i = 1; i < 4; i++) {
      if ((points[0].posX != points[i].posX)&& (points[0].posY != points[i].posY)){
         otherPoint = points[i];
         break;
      }
   }

   // 좌표 최종 확인.
   if ((otherPoint.posX == sameYPoint.posX) && (otherPoint.posY == sameXPoint.posY)) {
      return RECT_TYPE_NORMAL;
   }

   return 0;
}

double MyRect::getDistance(Point pointA, Point pointB)
{
   return sqrt(getPowOfDistance(pointA, pointB));
}

double MyRect::getPowOfDistance(Point pointA, Point pointB)
{
   int lineA = 0;
   int lineB = 0;

   lineA = abs(pointB.posX - pointA.posX);
   lineB = abs(pointB.posY - pointA.posY);

   return pow(lineA, 2) + pow(lineB, 2);
}

MyRect::MyRect(Point * points)
{
   memset(myPoints, 0x00, sizeof(myPoints));

   this->rectType = validateRect(points);
}

double MyRect::CalRectArea()
{
   if (this->rectType == RECT_TYPE_TILTED) {
      double lineA = getDistance(myPoints[0], myPoints[1]);
      double lineB = getDistance(myPoints[2], myPoints[3]);

      return lineA * lineB / 2;
   }
   else if (this->rectType == RECT_TYPE_NORMAL) {
      double lineA = getDistance(myPoints[0], myPoints[1]);
      double lineB = getDistance(myPoints[0], myPoints[2]);

      return lineA * lineB;
      return 0;
   }
   else {
      return 0;
   }
}


int main()
{
   Point points[4];
//확인 테스트
   points[0].posX = 0;
   points[0].posY = 3;

   points[1].posX = 3;
   points[1].posY = 0;

   points[2].posX = 4;
   points[2].posY = 2;

   points[3].posX = 2;
   points[3].posY = 4;
   
   //  테스트 : 정상적으로 돌아갔던 좌표.
   //points[0].posX = 10;
   //points[0].posY = 10;

   //points[1].posX = 22;
   //points[1].posY = 10;

   //points[2].posX = 22;
   //points[2].posY = 18;

   //points[3].posX = 10;
   //points[3].posY = 18;


   MyRect myRect(points);

   int rectArea = myRect.CalRectArea();

   printf("area = %d\n", rectArea);
}
Written on December 11, 2018