Development of Fashion CAD System 3. Points Sungmin Kim SEOUL NATIONAL UNIVERSITY 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 창에다음과같은메뉴를추가 Caption 변경 (Project-Options 의 Application-Title 도변경 ) Caption 에 &New Project 와같이 & 을추가하면밑줄이그어짐 ( 단축키 ) Caption 을 - 로하면가로줄이생김 (Separator) 3 Framework MDI Structure 기본적인 MDI 구조만들기 New Project 메뉴의 event handler 를다음과같이수정 void fastcall TMainForm::NewWindow1Click(TObject *Sender) new TChildForm(Application,"NewProject-"+AnsiString(MDIChildCount+1)+".Pattern"); Child창 (TChildForm 클래스 ) 을만들때창이름 (caption) 으로쓸문자열을전달 MDIChildCount 는 MainForm 의 property 중하나로, 열려있는 Child 창의수를나타냄.Pattern 는파일이름확장자 TChildForm.h 와 TChildForm.cpp 의소스를다음과같이수정 Source (cpp) 에서사용될함수, 변수, 클래스의모든정의는 header (h) 에서이루어져야함 header fastcall TChildForm(TComponent* Owner,AnsiString); source fastcall TChildForm::TChildForm(TComponent* Owner,AnsiString C) : TForm(Owner) Caption=C; 4
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 좌표입력을통한점의정의 다이얼로그박스를이용 버튼의이벤트핸들러작성 void fastcall TPointXYDialog::Button1Click(TObject *Sender) Result=1; Close(); void fastcall TPointXYDialog::Button2Click(TObject *Sender) Result=0; Close(); TPointXYDialog.h 에 Result 변수를추가 fastcall TPointXYDialog(TComponent* Owner); int Result; 6
Point Definition 좌표입력을통한점의정의 다이얼로그박스부르기 TChildForm 에다음메뉴를추가 Event handler 추가 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++; 7 Point Definition 좌표입력을통한점의정의 다이얼로그박스부르기 TChildForm.h 소스수정 fastcall TChildForm(TComponent* Owner,AnsiString); int PointNum; float X[1000],Y[1000]; TChildForm.cpp 소스수정 시작할때점의갯수를 0 으로초기화 #include "TChildForm.h" #include "TPointXYDialog.h fastcall TChildForm::TChildForm(TComponent* Owner,AnsiString C) : TForm(Owner) Caption=C; PointNum=0; 8
Point Definition 점표시하기 좌표계의이해 +y 0 +x 0 +x +y Real world coordinate system Screen coordinate system 9 점표시하기 좌표변환 S S x y = SC = SC x y + ( R x ( R y O ) R x O y Point Definition ) R (x1, y1) (Ox,Oy) SC (Screen Center) (x2, y2) 10
Point Definition 점표시하기 좌표변환 창모양에무관하게표시가가능해야함 W = Screen Width, H w = x 2 x, 1 h = y 1 y 2 = Screen Height 1. If W H R = W / w If R h > H R = H/h 2. If W < H R = H / h If R w > W R = W/w 11 Point Definition 점표시하기 좌표변환 TChildForm.cpp 에다음코드를추가 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); 필요한함수 / 변수는 TChildForm.h 에선언 ; float SCx,SCy,OX,OY,R; 12
Point Definition 점표시하기 화면에그리기 Windows 에서화면을갱신하는원리 O/S WM_SHOW WM_PAINT WM_RESIZE 13 Point Definition 점표시하기 화면에그리기 각각의 event handler 를작성 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); 14
Point Definition 점표시하기 화면에그리기 점추가기능수정 void fastcall TChildForm::AddXY1Click(TObject *Sender) FormPaint(this); 15 Struct 구조체 (Struct) 서로연관있는데이터를하나로묶으면좋지않을까? Point 의좌표 x, y 변수가따로있어서여러모로귀챦음 관련된변수를모아서하나의 구조체 변수로선언할수있음 기본형변수와동일한논리로처리된다 TChildForm.h 에구조체를선언 struct ptpoint float x,y; ; class TChildForm : public TForm 16
Struct 구조체 TChildForm.h 에서변수를구조체로다시선언한다 int float void float float float PointNum; X[1000],Y[1000]; fastcall FitToWindow(float x1,float y1,float x2,float y2); fastcall GetSX(float rx); fastcall GetSY(float ry); SCx,SCy,OX,OY,R; int ptpoint void ptpoint PointNum; Point[1000]; fastcall FitToWindow(float x1,float y1,float x2,float y2); fastcall Screen(float rx,float ry); ptpoint SC,O; float R; 17 Struct 구조체 TChildForm.cpp 소스를수정 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; 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; 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); 18
Struct 구조체 TChildForm.cpp 소스를수정 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); 19 User Interaction 관심영역설정 화면의확대 / 축소 / 이동 ChildForm의마우스입력 event handler 처리 TChildForm.h 에변수추가 bool ptpoint DragStart,Zooming; Start; TChildForm.cpp 에서변수초기화 fastcall TChildForm::TChildForm(TComponent* Owner,AnsiString C): TForm(Owner) DragStart=false; 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; 20
User Interaction 관심영역설정 화면의확대 / 축소 / 이동 ChildForm 의마우스입력 event handler 처리 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; 21 User Interaction 관심영역설정 화면의확대 / 축소 / 이동 ChildForm 에초기화면으로돌리는메뉴를추가 void fastcall TChildForm::InitialView1Click(TObject *Sender) FormResize(this); 22
개체의선택 화면상의점을선택 Ctrl Key+Mouse 왼쪽클릭을써서선택 Shift 를누르고선택하면여러개를선택가능 선택된점은특이하게표시 User Interaction TChildForm.h 에변수와함수추가 int int ptpoint int SelPointNum; SelPoint[100]; fastcall Real(float sx,float sy); fastcall FindPoint(int x,int y); TChildForm.cpp 에서변수초기화 fastcall TChildForm::TChildForm(TComponent* Owner,AnsiString C) : TForm(Owner) SelPointNum=0; 23 User Interaction 개체의선택 TChildForm.cpp 의수정 Mouse event handler 수정및함수정의 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; else SelPointNum++; FormPaint(this); 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; 24
User Interaction 개체의선택 TChildForm.cpp 의수정 FormPaint 함수의수정 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; 25 More Points 다양한점의정의 선택한점들을이동시켜서다른점들을생성 두개의점을내분하는위치에다른점을생성 ChildForm 의메뉴에명령을추가 26
More Points 다양한점의정의 선택한점들을이동시켜서만드는경우 Add Move Points 메뉴의 handler 를작성 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); 27 More Points 다양한점의정의 두점의내분점에새점을만드는경우 내분비율을입력하는 dialog 를하나만든다 TDividePointDialog 로저장 Add Divide 2 Points 메뉴 handler 를작성 void fastcall TChildForm::AddDividePoint1Click(TObject *Sender) if (SelPointNum!=2) Application->MessageBox("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); Description Point[PointNum].y=(m*Point[SelPoint[1]].y+n*Point[SelPoint[0]].y)/(m+n); 세개의버튼 PointNum++; 버튼 FormPaint(this); 두개의버튼 두개의버튼 두개의버튼 세개의버튼 28