Daily 2018-12-12

TIL

c++ 사각형 그리기

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

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

class MyRect {
private:
   Point myPoints[4];
   bool 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문을 돌려야함.
bool MyRect::validateRect(Point * points)
{
   Point sortedPoints[4];
   Point swpPoint;
      
   for (int i = 0; i < 4; i++) {
      sortedPoints[i] = points[i];
   }

   // 사각형 네 점을 기준으로 X값 순으로 정렬하고
   // X값이 같을경우 다시 Y로 정렬
   // 즉, sortedPoints[0]에는 X,Y좌표가 가장 작은 좌표가 들어있고.
   // sortedPoints[3]에는 X,Y좌표가 가장 큰 좌표가 들어있음.

   for (int i = 0; i < 3; i++) {
      for (int j = 0; j<3-i; j++) {
         if (sortedPoints[j].posX > sortedPoints[j + 1].posX) {
            swpPoint = sortedPoints[j];
            sortedPoints[j] = sortedPoints[j + 1];
            sortedPoints[j + 1] = swpPoint;
         }
         else if (sortedPoints[j].posX == sortedPoints[j + 1].posX) {
            if (sortedPoints[j].posY > sortedPoints[j + 1].posY) {
               swpPoint = sortedPoints[j];
               sortedPoints[j] = sortedPoints[j + 1];
               sortedPoints[j + 1] = swpPoint;
            }
         }
      }
   }
      
   //for (int i = 0; i < 4; i++) {
   //   printf("x : %d, y : %d\n", sortedPoints[i].posX, sortedPoints[i].posY);
   //}


   // 직사각형 조건.
   // 대각선 2개의 길이가 같고 사각형 4개의 각이 전부 직각(90도)여야 함.
   // 대각선 2개는 길이 구해서 비교하면 됨. sortedPoints[0]부터 sortedPoints[3]의 거리와
   // sortedPoints[1]부터 sortedPoints[2]까지의 거리를 비교.
   // 사각형의 4개의 각은 서로 마주보고 있는 부분의 각도가 
   // 둘다 직각(90도)이면 사각형안의 모든 각은 전부 직각
   // 각이 직간인지 확인하는 방법은 피타고라스 정리를 이용합니다. 각이 직각이면 A^2 = B^2 + C^2이니까
   // 반대로 말하면 A^2 = B^2 + C^2 식을 만족하면 각이 직각
   // 조건이 참이 아니면 일반적으로 들어오는 사각형 좌표 체크를 위해 다음 블럭 진행.
   // 좌표를 그림으로 그리면.
   // myPoints[1]         myPoints[3]
   //
   // myPoints[0]         myPoints[2]
   
   // 대각선 2개의 길이 비교.
   double diagonalA = getDistance(sortedPoints[0], sortedPoints[3]);
   double diagonalB = getDistance(sortedPoints[1], sortedPoints[2]);

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

   double sumOfLineAB = powOfLineA + powOfLineB;
   double sumOfLineCD = powOfLineC + powOfLineD;
   double powOfDiagonalB = getPowOfDistance(sortedPoints[1], sortedPoints[2]);

   // 두 대각선이 일치하고 sumOfLineAB와 sumOfLineCD가 각각 powOfDiagonalB와 일치하면 내 각이 직각
   // 결과가 참이면 클래스 내부 변수에 값 저장.
   if ((diagonalA == diagonalB) && (sumOfLineAB == powOfDiagonalB) && (sumOfLineCD == powOfDiagonalB)) {
      for (int i = 0; i < 4; i++) {
         myPoints[i] = sortedPoints[i];
      }
   }

   return false;
}

// getDistance랑 getPowOfDistance를 2개로 나눈 이유는
// getPowDistance는 각 lineA의 제곱과 lineB의 제곱을 합친 값인데 이를 sqrt를 사용하면 값이 소수단위로 들어감.
// 근데 사각형 판별 식에서 사용할때에는 sqrt하지 않은 값이 필요함. sart한 값을 다시 pow하면 값의 소수점이 미묘하게 다르기 때문에
// 별도로 함수를 구현하여서 사용하여 비교.
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()
{
   double lineA = getDistance(myPoints[0], myPoints[1]);
   double lineB = getDistance(myPoints[0], myPoints[2]);

   return lineA * lineB;
}


int main()
{
   Point points[4];

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

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

   points[2].posX = 3;
   points[2].posY = 5;

   points[3].posX = 5;
   points[3].posY = 3;

   //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 12, 2018