정리필요2

과제#4 (Window To Viewport Transformation)

ShineWithMe 2008. 9. 2. 15:43

삼각형 신축, 회전

지난 scanconversion 과제는 너무 어려웠으나...이번건 할만했다....

2005mfc로 작성했으며 헤더파일에 선언한 클래스와 함수들은 생략했당~ 주된 흐름만 살포시 ...


// 삼각형의 갯수와 좌표 정의
void C과제4TransformationView::setTriangle(Triangle t1[], int countT)
{
 int temp[][6] = { // 삼각형 6개 정의
  {10, 100, 100, 10, 150, 150},
  {320, 300, 400, 10, 580, 300},
  {280, 350, 10, 400, 300, 580},
  {610, 40, 650, 60, 620, 90},
  {450, 450, 600, 350, 600, 550},
  {650, 450, 800, 350, 800, 550}
 };
 for(int i=0; i<countT; i++)
 { // Triangle 객체로 넣는다.
  t1[i].x1 = temp[i][0];
  t1[i].y1 = temp[i][1];
  t1[i].x2 = temp[i][2];
  t1[i].y2 = temp[i][3];
  t1[i].x3 = temp[i][4];
  t1[i].y3 = temp[i][5];
 }
}

// 원본 삼각형의 좌표 출력
void C과제4TransformationView::textout(Triangle t1[], int countT)
{
 CClientDC dc(this);
 CString string1;
 for(int i=0; i<countT; i++)
 {
  string1.Format(_T("  %d , %d "), t1[i].x1, t1[i].y1);
  dc.TextOutW(t1[i].x1, t1[i].y1, string1);
  string1.Format(_T("  %d , %d "), t1[i].x2, t1[i].y2);
  dc.TextOutW(t1[i].x2, t1[i].y2, string1);
  string1.Format(_T("  %d , %d "), t1[i].x3, t1[i].y3);
  dc.TextOutW(t1[i].x3, t1[i].y3, string1);
 }

}

// 메인함수
void C과제4TransformationView::Trans(void)
{
 int countT = 6; // 그릴 삼각형 갯수
 COLORREF gcol = RGB(240, 240, 240), tcol = RGB(255, 0, 0);
 // 원본삼각형의 색과 가이드라인 색
 guidline(1000, 800, gcol);// 가이드라인 출력함수 호출

 Triangle *t1 = new Triangle[countT]; // 갯수만큼 공간 할당      
 setTriangle(t1, countT);    // 삼각형 정의함수 호출

 textout(t1, countT);     // 삼각형 좌표값 출력함수 호출

 for(int i=0; i<countT; i++)    
  drawTriangle(t1[i], tcol);   // 원본 삼각형 그리기
 
 // ROTATION - 원본 t1[0]을 60 ~ 300 도까지 t1[0]의 세번째 점을 기준으로 회전
 rotation(t1[0], 60, t1[0].x3, t1[0].y3);
 rotation(t1[0], 120, t1[0].x3, t1[0].y3);
 rotation(t1[0], 180, t1[0].x3, t1[0].y3);
 rotation(t1[0], 240, t1[0].x3, t1[0].y3);
 rotation(t1[0], 300, t1[0].x3, t1[0].y3);

 // ROTATION - 원본 t1[1]을 20 ~ 40 도까지 중심을 기준으로 회전
 rotationCenter(t1[1], 20);
 rotationCenter(t1[1], 30);
 rotationCenter(t1[1], 40);

 // SCAILING - 원본 t1[2]의 세번째점을 기준으로 X, Y 각 0.8, 0.6 배 축소
 scailing(t1[2], 0.8, 0.8, t1[2].x3 +100, t1[2].y3);
 scailing(t1[2], 0.6, 0.6, t1[2].x3 +200, t1[2].y3);

 //ROTATION - 원본 t1[3]을 점(720, 150) 기준으로 60~300도 회전
 rotation(t1[3], 60, 720, 150);
 rotation(t1[3], 120, 720, 150);
 rotation(t1[3], 180, 720, 150);
 rotation(t1[3], 240, 720, 150);
 rotation(t1[3], 300, 720, 150);

 //SCAILING - 원본 t1[4]의 첫번째 점을 기준으로 Y 값만 축소확대
 scailing(t1[4], 1.0, 1.5, t1[4].x1, t1[4].y1);
 scailing(t1[4], 1.0, 1.2, t1[4].x1, t1[4].y1);
 scailing(t1[4], 1.0, 0.8, t1[4].x1, t1[4].y1);
 scailing(t1[4], 1.0, 0.6, t1[4].x1, t1[4].y1);

 //SCAILING - 원본 t1[5]의 첫번째 점을 기준으로 X 값만 축소확대
 scailing(t1[5], 1.5, 1.0, t1[5].x1, t1[5].y1);
 scailing(t1[5], 0.8, 1.0, t1[5].x1, t1[5].y1);
 scailing(t1[5], 0.6, 1.0, t1[5].x1, t1[5].y1);
 scailing(t1[5], 1.2, 1.0, t1[5].x1, t1[5].y1);

}

// 삼각형 그리는 함수
void C과제4TransformationView::drawTriangle(Triangle t1, COLORREF col)
{
 drawLine(t1.x1, t1.y1, t1.x2, t1.y2, col); // 선그리는함수호출
 drawLine(t1.x2, t1.y2, t1.x3, t1.y3, col);
 drawLine(t1.x3, t1.y3, t1.x1, t1.y1, col);

}

// 삼각형 중심구하는 함수
Point C과제4TransformationView::Center(Triangle t1)
{
 Point cp;
 cp.x = (int)(((t1.x1 + t1.x2 + t1.x3) / 3) + 0.5);
 cp.y = (int)(((t1.y1 + t1.y2 + t1.y3) / 3) + 0.5);
 // x, y좌표 세개를 각각 더해 3으로 나눔, 반올림해줌.
 return cp;
}

// 신축함수 - 특정 위치 기준 축소확대
void C과제4TransformationView::scailing(Triangle t1, double xs, double ys, int x0, int y0)
{
 Triangle scail;
 scail = t1;
 // P' = T(x0, y0) * (S(sx, sy)) * T(-x0, -y0) * P = S(x0, y0, sx, sy)
 // 교제 170p 의 합성변환을 이용
 scail.x1 = (int)((xs * t1.x1) + (x0 * (1-xs)) + 0.5);
 scail.x2 = (int)((xs * t1.x2) + (x0 * (1-xs)) + 0.5);
 scail.x3 = (int)((xs * t1.x3) + (x0 * (1-xs)) + 0.5);
 scail.y1 = (int)((ys * t1.y1) + (y0 * (1-ys)) + 0.5);
 scail.y2 = (int)((ys * t1.y2) + (y0 * (1-ys)) + 0.5);
 scail.y3 = (int)((ys * t1.y3) + (y0 * (1-ys)) + 0.5);

 drawTriangle(scail, RGB(0, 255, 0)); // 삼각형 그리는 함수 호출
}

// 신축함수 - 중심기준 축소확대
void C과제4TransformationView::scailingCenter(Triangle t1, double xs, double ys)
{
 Point cp;
 cp = Center(t1); // 삼각형 중심구하는 함수 호출
 scailing(t1, xs, ys, cp.x, cp.y); // 중심점으로 신축함수 호출
}

// 회전 함수 - 임의의 점 기준
void C과제4TransformationView::rotation(Triangle t1, int degree, int x0, int y0)
{
 double angle = PI * degree / 180.0; // 각도를 라디안으로 바꿔줌

 Triangle rotate;
 // P' = T(x0, y0) * R(@) * T(-x0, -y0) * P = R(x0, y0, @) * P
 // 교제 171p 의 합성변환 그대로 이용
 rotate.x1 = (int)(t1.x1 * cos(angle) - t1.y1 * sin(angle) + (x0 * (1-cos(angle))) + y0 * sin(angle) + 0.5);
 rotate.x2 = (int)(t1.x2 * cos(angle) - t1.y2 * sin(angle) + (x0 * (1-cos(angle))) + y0 * sin(angle) + 0.5);
 rotate.x3 = (int)(t1.x3 * cos(angle) - t1.y3 * sin(angle) + (x0 * (1-cos(angle))) + y0 * sin(angle) + 0.5);
 rotate.y1 = (int)(t1.x1 * sin(angle) + t1.y1 * cos(angle) + (y0 * (1-cos(angle))) - x0 * sin(angle) + 0.5);
 rotate.y2 = (int)(t1.x2 * sin(angle) + t1.y2 * cos(angle) + (y0 * (1-cos(angle))) - x0 * sin(angle) + 0.5);
 rotate.y3 = (int)(t1.x3 * sin(angle) + t1.y3 * cos(angle) + (y0 * (1-cos(angle))) - x0 * sin(angle) + 0.5);
 
 drawTriangle(rotate, RGB(0, 0, 255)); // 삼각형 그리는 함수 호출
}

// 회전함수 - 중심기준
void C과제4TransformationView::rotationCenter(Triangle t1, int degree)
{
 Point cp;
 cp = Center(t1); // 중심구하는 함수 호출
 rotation(t1, degree, cp.x, cp.y); // 중심점으로 회전함수 호출
}

// 가이드라인 출력 함수
void C과제4TransformationView::guidline(int width, int height, COLORREF col)
{
 for(int i=10; i<=width; i+=10)
  drawLine(i, 0, i, height, col);

 for(int j=10; j<height; j+=10)
  drawLine(0, j, width, j, col);
}

// 선그리는 함수 (bresenham midpoint)
void C과제4TransformationView::drawLine(int x1, int y1, int x2, int y2, COLORREF col)
{
 CClientDC cdc(this);

 int  x, y;
 int  dx, dy;
 int  incx, incy;
 int  balance;


 // 증가방향이 + 경우 incx incy는 1,  - 일 경우 incx, incy는 -1
 if (x2 >= x1)
 {
  dx = x2 - x1; // 증가폭은 양수로
  incx = 1;
 }
 else
 {
  dx = x1 - x2;
  incx = -1;
 }

 if (y2 >= y1)
 {
  dy = y2 - y1;
  incy = 1;
 }
 else
 {
  dy = y1 - y2;
  incy = -1;
 }

 x = x1;
 y = y1;

 if (dx >= dy) // |m| < 1
 {
 
  dy <<= 1;   // dy * 2 (시프트연산)
  balance = dy - dx; // 2dy - dx 
  dx <<= 1;   // dx * 2 (시프트연산)

  while (x != x2)
  {
   cdc.SetPixel( x, y, col); // 점찍기
   if (balance >= 0)
   // balance = 2dy - dx >= 0 , 즉 dy >= 1/2dx
   // dy가 dx의 절반(midpoint)의 넘으면
   {
    y += incy; // y를 증가 NE를 선택
    balance -= dx; // dx빼준다
   }
   balance += dy; // dy 증가
   x += incx; //아니면 x만 증가 E를 선택
  }
 }
 else // |m| < 1 , 내용은 위와 정반대
 {
  dx <<= 1;   // dx * 2
  balance = dx - dy; // 2dx - dy
  dy <<= 1;   // dy *2

  while (y != y2)
  {
   cdc.SetPixel( x, y, col);
   if (balance >= 0)
   {
    x += incx;
    balance -= dy;
   }
   balance += dx;
   y += incy;
  }
 }


}