development of fashion cad systemfashiontech.snu.ac.kr/note/fashioncad/03-points.pdf ·...
TRANSCRIPT
Sungmin Kim
SEOUL NATIONAL UNIVERSITY
Development of Fashion CAD System
3. Points
Points Topics MDI 기반 프로그램 설계
Child 창에서 패턴을 설계
패턴 형상과 관련된 모든 데이터는 Child 창에서 관리
Event-driven 구조의 기초
Point 정의 및 화면 표시
x,y 좌표를 입력해서 점을 생성하고 화면에 표시
화면 좌표계와 실제 좌표계의 상호 변환
구조체 (Struct)사용을 통한 코드 개선
사용자와의 상호작용
화면 확대, 축소, 이동 등의 구현
마우스를 써서 복수의 점을 선택
선택된 점을 이용한 새로운 점의 정의
2
Framework MDI Structure 기본적인 MDI 구조 만들기
Chapter 2 에서 다룬 방법으로 MDI 기본 틀을 제작
– C++ Builder Projects\PatternCAD 폴더에 PatternCAD.bpr 로 저장
Main Form 창에 다음과 같은 메뉴를 추가
3
Caption 변경 (Project-Options 의 Application-Title 도 변경)
Caption에 ‘&New Project’ 와 같이‘&’ 을 추가하면 밑줄이 그어짐 (단축키)
Caption을 ‘-’ 로 하면 가로줄이 생김(Separator)
Framework MDI Structure 기본적인 MDI 구조 만들기
New Project 메뉴의 event handler 를 다음과 같이 수정
– Child창 (TChildForm 클래스)을 만들 때 창 이름(caption)으로 쓸 문자열을 전달
– MDIChildCount 는 MainForm 의 property 중 하나로, 열려 있는 Child 창의 수를 나타냄
– “.Pattern” 는 파일 이름 확장자
TChildForm.h 와 TChildForm.cpp 의 소스를 다음과 같이 수정
– Source (cpp) 에서 사용될 함수, 변수, 클래스의 모든 정의는 header (h) 에서 이루어져야 함
4
void __fastcall TMainForm::NewWindow1Click(TObject *Sender){new TChildForm(Application,"NewProject-"+AnsiString(MDIChildCount+1)+".Pattern");}
__fastcall TChildForm(TComponent* Owner,AnsiString);
__fastcall TChildForm::TChildForm(TComponent* Owner,AnsiString C) : TForm(Owner){Caption=C;}
header
source
Point Definition 좌표 입력을 통한 점의 정의 다이얼로그 박스를 이용
File-New-Form 으로 새로운 폼을 하나 생성하고 property를 변경
– BorderIcons 모두 false
– BorderStyle bsDialog
– Caption Input Coordinate
– Name PointXYDialog
– Position poScreenCenter
TPointXYDialog.cpp 로 Save
Control 들을 올려 놓고 property를 변경
– TEdit 의 Name 은 X, Y, Text=0
– TButton 의 Caption 은 Ok 와 Cancel
5
Point Definition 좌표 입력을 통한 점의 정의 다이얼로그 박스를 이용
버튼의 이벤트 핸들러 작성
TPointXYDialog.h 에 Result 변수를 추가
6
void __fastcall TPointXYDialog::Button1Click(TObject *Sender){Result=1;Close();}
void __fastcall TPointXYDialog::Button2Click(TObject *Sender){Result=0;Close();}
__fastcall TPointXYDialog(TComponent* Owner);
int Result;
Point Definition 좌표 입력을 통한 점의 정의 다이얼로그 박스 부르기
TChildForm에 다음 메뉴를 추가
Event handler 추가
7
void __fastcall TChildForm::AddXY1Click(TObject *Sender){PointXYDialog->ShowModal();if (PointXYDialog->Result==1){
X[PointNum]=PointXYDialog->X->Text.ToDouble();Y[PointNum]=PointXYDialog->Y->Text.ToDouble();PointNum++;}
}
Point Definition 좌표 입력을 통한 점의 정의 다이얼로그 박스 부르기
TChildForm.h 소스 수정
TChildForm.cpp 소스 수정
– 시작할 때 점의 갯수를 0으로 초기화
8
...
#include "TChildForm.h"#include "TPointXYDialog.h“
...
__fastcall TChildForm::TChildForm(TComponent* Owner,AnsiString C) : TForm(Owner){Caption=C;PointNum=0;}
__fastcall TChildForm(TComponent* Owner,AnsiString);
int PointNum;float X[1000],Y[1000];
Point Definition 점 표시하기 좌표계의 이해
9
+y
+x
Real world coordinate system Screen coordinate system
0
0+x
+y
Point Definition 점 표시하기 좌표 변환
10
RORSCS
RORSCS
yyyy
xxxx
)(
)(
(x1, y1)
(x2, y2)
SC (Screen Center)
(Ox,Oy)
Point Definition 점 표시하기 좌표 변환
창 모양에 무관하게 표시가 가능해야 함
11
W/wRWw If R
hHRHWIf
H/hRHhIf R
wWRHWIf
yyhxxw
HW
/ .2
/ .1
,
HeightScreen th,Screen Wid
2112
Point Definition 점 표시하기 좌표 변환
TChildForm.cpp 에 다음 코드를 추가
12
void __fastcall TChildForm::FitToWindow(float x1,float y1,float x2,float y2){OX=(x1+x2)/2;OY=(y1+y2)/2;float W=(float)ClientWidth;float H=(float)ClientHeight;SCx=W/2;SCy=H/2;float w=x2-x1;float h=y1-y2;if (W>H){
R=W/w;if (R*h>H) R=H/h;}
else{R=H/h;if (R*w>W) R=W/w;}
}
float __fastcall TChildForm::GetSX(float rx){return SCx+(rx-OX)*R;}
float __fastcall TChildForm::GetSY(float ry){return SCy-(ry-OY)*R;}
...
float __fastcall FitToWindow(float,float,float,float);float __fastcall GetSX(float rx);float __fastcall GetSY(float ry);
float SCx,SCy,OX,OY,R;};필요한 함수/변수는 TChildForm.h에 선언 →
Point Definition 점 표시하기 화면에 그리기
Windows 에서 화면을 갱신하는 원리
13
O/SWM_SHOWWM_PAINTWM_RESIZE
Point Definition 점 표시하기 화면에 그리기
각각의 event handler 를 작성
14
void __fastcall TChildForm::FormPaint(TObject *Sender){Canvas->Pen->Color=clWhite;Canvas->Brush->Color=clWhite;Canvas->Rectangle(0,0,ClientWidth,ClientHeight);Canvas->Pen->Color=clLime;Canvas->Brush->Color=clYellow;float x,y;x=GetSX(-500);y=GetSY(0);Canvas->MoveTo(x,y);x=GetSX(500);y=GetSY(0);Canvas->LineTo(x,y);x=GetSX(0);y=GetSY(-500);Canvas->MoveTo(x,y);x=GetSX(0);y=GetSY(500);Canvas->LineTo(x,y);Canvas->Pen->Color=clBlack;int i;for(i=0;i<PointNum;i++){
x=GetSX(X[i]);y=GetSY(Y[i]);Canvas->Ellipse(x-3,y-3,x+3,y+3);}
}
void __fastcall TChildForm::FormResize(TObject *Sender){FitToWindow(-500,500,500,-500);FormPaint(this);}
void __fastcall TChildForm::FormShow(TObject *Sender){FormResize(this);}
Point Definition 점 표시하기 화면에 그리기
점 추가 기능 수정
15
void __fastcall TChildForm::AddXY1Click(TObject *Sender){...FormPaint(this);}
Struct 구조체 (Struct) 서로 연관 있는 데이터를 하나로 묶으면 좋지 않을까 ?
Point 의 좌표 x, y 변수가 따로 있어서 여러모로 귀챦음
관련된 변수를 모아서 하나의 ‘구조체’ 변수로 선언할 수 있음
– 기본형 변수와 동일한 논리로 처리된다
– TChildForm.h 에 구조체를 선언
16
...
struct ptPoint{
float x,y;};
class TChildForm : public TForm
...
Struct 구조체 TChildForm.h에서 변수를 구조체로 다시 선언 한다
17
int PointNum;float X[1000],Y[1000];
void __fastcall FitToWindow(float x1,float y1,float x2,float y2);float __fastcall GetSX(float rx);float __fastcall GetSY(float ry);
float SCx,SCy,OX,OY,R;
int PointNum;ptPoint Point[1000];
void __fastcall FitToWindow(float x1,float y1,float x2,float y2);ptPoint __fastcall Screen(float rx,float ry);
ptPoint SC,O;float R;
Struct 구조체 TChildForm.cpp 소스를 수정
18
void __fastcall TChildForm::FitToWindow(float x1,float y1,float x2,float y2){O.x=(x1+x2)/2;O.y=(y1+y2)/2;float W=(float)ClientWidth;float H=(float)ClientHeight;SC.x=W/2;SC.y=H/2;float w=x2-x1;float h=y1-y2;if (W>H){
R=W/w;if (R*h>H) R=H/h;}
else{R=H/h;if (R*w>W) R=W/w;}
}
void __fastcall TChildForm::AddXY1Click(TObject *Sender){PointXYDialog->ShowModal();if (PointXYDialog->Result==1){
Point[PointNum].x=PointXYDialog->X->Text.ToDouble();Point[PointNum].y=PointXYDialog->Y->Text.ToDouble();PointNum++;}
FormPaint(this);}
ptPoint __fastcall TChildForm::Screen(float rx,float ry){ptPoint P;P.x=SC.x+(rx-O.x)*R;P.y=SC.y-(ry-O.y)*R;return P;}
Struct 구조체 TChildForm.cpp 소스를 수정
19
void __fastcall TChildForm::FormPaint(TObject *Sender){Canvas->Pen->Color=clWhite;Canvas->Brush->Color=clWhite;Canvas->Rectangle(0,0,ClientWidth,ClientHeight);Canvas->Pen->Color=clLime;Canvas->Brush->Color=clYellow;ptPoint P;P=Screen(-500,0);Canvas->MoveTo(P.x,P.y);P=Screen(500,0);Canvas->LineTo(P.x,P.y);P=Screen(0,-500);Canvas->MoveTo(P.x,P.y);P=Screen(0,500);Canvas->LineTo(P.x,P.y);Canvas->Pen->Color=clBlack;int i;for(i=0;i<PointNum;i++){
P=Screen(Point[i].x,Point[i].y);Canvas->Ellipse(P.x-3,P.y-3,P.x+3,P.y+3);}
}
User Interaction 관심 영역 설정 화면의 확대/축소/이동
ChildForm의 마우스 입력 event handler 처리
20
void __fastcall TChildForm::FormMouseDown(TObject *Sender,TMouseButton Button, TShiftState Shift, int X, int Y)
{if (!DragStart){
DragStart=true;if (Button==mbRight) Zooming=true;else Zooming=false;Start.x=(float)X;Start.y=(float)Y;}
}
bool DragStart,Zooming;ptPoint Start;
TChildForm.h에 변수 추가
__fastcall TChildForm::TChildForm(TComponent* Owner,AnsiString C): TForm(Owner){...DragStart=false;}
TChildForm.cpp 에서 변수 초기화
User Interaction 관심 영역 설정 화면의 확대/축소/이동
ChildForm의 마우스 입력 event handler 처리
21
void __fastcall TChildForm::FormMouseMove(TObject *Sender,TShiftState Shift, int X, int Y)
{if (DragStart){
float dx=(float)X-Start.x;float dy=(float)Y-Start.y;if (Zooming==true){
if (dy<0) R*=1.01;else R*=0.99;}
else{O.x-=dx/R;O.y+=dy/R;}
Start.x=(float)X;Start.y=(float)Y;FormPaint(this);
}}
void __fastcall TChildForm::FormMouseUp(TObject *Sender,TMouseButton Button, TShiftState Shift, int X, int Y)
{if (DragStart) DragStart=false;}
User Interaction 관심 영역 설정 화면의 확대/축소/이동
ChildForm에 초기 화면으로 돌리는 메뉴를 추가
22
void __fastcall TChildForm::InitialView1Click(TObject *Sender){FormResize(this); }
User Interaction 개체의 선택 화면상의 점을 선택
Ctrl Key+Mouse 왼쪽 클릭을 써서 선택
Shift 를 누르고 선택하면 여러 개를 선택 가능
선택된 점은 특이하게 표시
23
int SelPointNum;int SelPoint[100];ptPoint __fastcall Real(float sx,float sy);int __fastcall FindPoint(int x,int y);
__fastcall TChildForm::TChildForm(TComponent* Owner,AnsiString C): TForm(Owner)
{...SelPointNum=0;}
TChildForm.h 에 변수와 함수 추가
TChildForm.cpp 에서 변수 초기화
User Interaction 개체의 선택 TChildForm.cpp의 수정
Mouse event handler 수정 및 함수 정의
24
void __fastcall TChildForm::FormMouseDown(TObject *Sender,TMouseButton Button, TShiftState Shift, int X, int Y)
{if (!DragStart){
if (Shift.Contains(ssCtrl)){int p=FindPoint(X,Y);if (!Shift.Contains(ssShift)) SelPointNum=0;if (p!=-1){
SelPoint[SelPointNum]=p;SelPointNum++;}
FormPaint(this);}
else{DragStart=true;if (Button==mbRight) Zooming=true;else Zooming=false;Start.x=(float)X;Start.y=(float)Y;}
}}
ptPoint __fastcall TChildForm::Real(float sx,float sy){ptPoint P;P.x=(sx-SC.x)/R+O.x;P.y=O.y-(sy-SC.y)/R;return P;}
int __fastcall TChildForm::FindPoint(int x,int y){ptPoint P=Real(x,y);int i,MinP=-1;float d,MinD=100;for(i=0;i<PointNum;i++){
d=sqrt((Point[i].x-P.x)*(Point[i].x-P.x)+(Point[i].y-P.y)*(Point[i].y-P.y));if (d<MinD){
MinD=d;MinP=i;}
}return MinP;}
User Interaction 개체의 선택 TChildForm.cpp의 수정
FormPaint 함수의 수정
25
void __fastcall TChildForm::FormPaint(TObject *Sender){...
Canvas->Pen->Color=clRed;Canvas->Brush->Style=bsClear;for(i=0;i<SelPointNum;i++){
P=Screen(Point[SelPoint[i]].x,Point[SelPoint[i]].y);Canvas->Ellipse(P.x-5,P.y-5,P.x+5,P.y+5);}
Canvas->Brush->Style=bsSolid;}
More Points 다양한 점의 정의 선택한 점들을 이동시켜서 다른 점들을 생성
두개의 점을 내분하는 위치에 다른 점을 생성
ChildForm 의 메뉴에 명령을 추가
26
More Points 다양한 점의 정의 선택한 점들을 이동시켜서 만드는 경우
Add Move Points 메뉴의 handler 를 작성
27
void __fastcall TChildForm::MovePoint1Click(TObject *Sender){if (SelPointNum==0) return;PointXYDialog->ShowModal();if (PointXYDialog->Result==1){
int i;float x=PointXYDialog->X->Text.ToDouble();float y=PointXYDialog->Y->Text.ToDouble();for(i=0;i<SelPointNum;i++){
Point[PointNum].x=Point[SelPoint[i]].x+x;Point[PointNum].y=Point[SelPoint[i]].y+y;PointNum++;}
FormPaint(this);}
}
More Points 다양한 점의 정의 두 점의 내분점에 새 점을 만드는 경우
내분 비율을 입력하는 dialog 를 하나 만든다
– TDividePointDialog 로 저장
Add Divide 2 Points 메뉴 handler 를 작성
28
void __fastcall TChildForm::AddDividePoint1Click(TObject *Sender){if (SelPointNum!=2){
MessageBox(Handle,"Select two points","Caution",MB_ICONEXCLAMATION|MB_OK);return;}
DividePointDialog->ShowModal();if (DividePointDialog->Result){
float m=DividePointDialog->M->Text.ToDouble();float n=DividePointDialog->N->Text.ToDouble();Point[PointNum].x=(m*Point[SelPoint[1]].x+n*Point[SelPoint[0]].x)/(m+n);Point[PointNum].y=(m*Point[SelPoint[1]].y+n*Point[SelPoint[0]].y)/(m+n);PointNum++;FormPaint(this);}
}
Value Description
MB_ABORTRETRYIGNORE Abort, Retry, Ignore 세 개의 버튼
MB_OK OK버튼
MB_OKCANCEL OK, Cancel 두 개의 버튼
MB_RETRYCANCEL Retry, Cancel 두 개의 버튼
MB_YESNO Yes, No 두 개의 버튼
MB_YESNOCANCEL Yes, No, Cancel 세 개의 버튼