2010년 2월 26일

윈도우즈에서 곡선을 표현하는 방법의 실체

윈도우즈에서 곡선을 표현하는 방법의 실체는 무엇일까?

윈도우즈에서는 GDI 객체들은 모두 DC(Device Context) 상에 표현된다. 때문에 다음과 같은 방법으로 우리가 원하는 데이타를 추출할 수 있다.

1. 해당 DC의 경로 정보 생성
2. GDI 객체를 DC에 출력
3. 해당 DC의 경로 정보 끝냄
4. 해당 경로정보 조회

여기에서 말하는 경로는 GDI 객체중에 Path 라는 녀석을 말한다.


Path(경로) 란?
GDI 내부에 저장되는 직선과 곡선들의 집합이라고 할 수 있다.
마치 GDI 객체중에 영역(Region)과 흡사하다고 볼수있다. 때문에 Path 를 Region 으로 변환도 가는하다. (PathToRegion)
또한 Path는 다수의 SubPath로 나누어 질수있다. (::CloseFigure()를 호출하여 Sub Path로 나누어진 경로를 끝내는것이 가능하다.)

자 그럼 실제로 Path 추출을 시작해 보자.

HDC hdc = ::GetDC( this->Handle);
::BeginPath(hdc);
::TextOut(hdc,0,0,"HELLO", 5);

이후에 호출되는 GDI관련 객체 생성(선그리기, 곡선 그리기, 텍스트 그리기등)
호출은 모두 GDI 내부적으로 처리되며, DC상에 출력은 되지 않는다.

::EndPath(hdc);

자 그럼 경로를 닫고 해당 경로를 구성하는 좌표정보를 조회해 보도록 하자.

일단 얼마나 많은 좌표정보로 이루어졌는지를 알아낸후, 해당 크기만큼 메모리를 미리 할당하도록 하자.

INT nCount = ::GetPath(hdc, NULL, 0, 0);

POINT *pPoints = new POINT[nCount];
BYTE *pTypes = new BYTE[nCount];
 ::GetPath(hdc, pPoint, pTypes, nCount);

위 호출이 끝나면 해당 GDI객체를 구성하는 점 정보(좌표및 타입)를 얻어올 수 있게 된다.


MSDN의 Type 정보

Pointer to an array of bytes that receives the vertex types. This parameter can be one of the following values.
TypeDescription
PT_MOVETOSpecifies that the corresponding point in the lpPoints parameter starts a disjoint figure.
PT_LINETOSpecifies that the previous point and the corresponding point in lpPoints are the endpoints of a line.
PT_BEZIERTOSpecifies that the corresponding point in lpPoints is a control point or ending point for a Bézier curve.
PT_BEZIERTO values always occur in sets of three. The point in the path immediately preceding them defines the starting point for the Bézier curve. The first two PT_BEZIERTO points are the control points, and the third PT_BEZIERTO point is the ending (if hard-coded) point.




A PT_LINETO or PT_BEZIERTO value may be combined with the following value (by using the bitwise operator OR) to indicate that the corresponding point is the last point in a figure and the figure should be closed.

FlagDescription
PT_CLOSEFIGURESpecifies that the figure is automatically closed after the corresponding line or curve is drawn. The figure is closed by drawing a line from the line or curve endpoint to the point corresponding to the last PT_MOVETO.



여기서 주의할 것은 점의 타입을 나타내는 조합중에 PT_BEZIERTO 가 정확히 어떤 의미인지 파악하는 것이다.

이를 알기위해서 곡선을 표현하는 다양한 방법들중 M$ 에서 채택한 방식을 알아야 한다. 예를 들어 설명하면




위와 같은 곡선을 표현하기 위해서는 2개의 시작과 끝점, 2개의 조절점(P1,P2)로 표현된다.
즉 시작점 끝점은 항상 접하고, 조절점에 의해 곡선의 형태가 좌우되는 방식이다. 4개의 점(2개의 조절점)을 사용한 베지어 곡선을 Cubic Bezier 라 부른다.

Cubic Bézier curves
Four points P0, P1, P2 and P3 in the plane or in three-dimensional space define a cubic Bézier curve. The curve starts at P0 going toward P1 and arrives at P3 coming from the direction of P2. Usually, it will not pass through P1 or P2; these points are only there to provide directional information. The distance between P0 and P1 determines "how long" the curve moves into direction P2 before turning towards P3.

The parametric form of the curve is:


Since the lines and are the tangents of the Bézier curve at and , respectively, cubic Bézier interpolation is essentially the same as cubic Hermite interpolation.

Modern imaging systems like PostScript, Asymptote and Metafont use Bézier splines composed of cubic Bézier curves for drawing curved shapes.

위 수식에서 t 는 일종의 매개변수로 0부터 1까지 점차 증가시켜 대입시키면 해당하는 x,y 좌표가 계산되는 방정식이다.




위에서 예를 든 3차 베지에 곡선은 포스트스크립트 글꼴, 메타폰트(METAFONT), 김프(GIMPS) 등에서 부드러운 곡선을 생성하는 데에 이용되고 있으며, 트루 타입 폰트(TTF)에는 2차 베지에 곡선 알고리즘을 사용한다.

그럼 BEZIERTO 가 바로 제어점(control point)를 의미하는것을 알수있을 것이다.

이 베지어 곡선은 1970년대 Renault car를 디자인하는 과정에서 이 곡선을 사용했던 Pierre Bézier라는 프랑스 엔지니어의 이름을 따서 만들어졌다고 한다.

시리우스 라이브러리 홈페이지 오픈

현재 시리우스(Sirius) 라이브러리라는 제품을 개발하고 이를 소개하는 홈페이지를 오픈 하였습니다. 관심있는 분들의 많은 방문 요청드립니다. 앞으로 업데이트 소식및 변경사항은 스파이럴랩 홈페이지를 통해 진행할 예정입니다. 스파이럴랩 홈페이지 :  h...