终于完成了相当于GDI中Arc函数的功能了。这次仍然跟API有点误差,不多这里的误差是GDI的问题。这里贴出截图和代码。观看图2和图3,我们知道椭圆是对称的,但是GDI并没有做到这一点。我的算法也不能精确对称,但是左右两边仅相差1个像素。Arc是椭圆的子集,所以Arc在这个局部(椭圆的最上方)中也应该左右对称。图1中我先用GDI绘制黑色Arc,然后使用我的算法绘制红色Arc。这里的自适应步长算法跟上一篇的Bezier曲线的算法是一样的。
图1:运行结果
图2:GDI局部放大
图3: 我的结果图放大
代码:
1 #include "..\..\..\..\Library\Windows\VL_WinMain.h"
2 #include "..\..\..\..\Library\Windows\VL_WinGDI.h"
3
4 using namespace vl;
5 using namespace vl::windows;
6
7 class Evaluator : public VL_Base
8 {
9 protected:
10 VL_WinDIB* FBuffer;
11 VDouble FX1,FY1,FX2,FY2,FStart,FEnd;
12 VDouble FCenX,FCenY,FA,FB;
13 public:
14 Evaluator(VL_WinDIB* Buffer)
15 {
16 FBuffer=Buffer;
17 }
18
19 void SetEllipse(VDouble X1 , VDouble Y1 , VDouble X2 , VDouble Y2 , VDouble Start , VDouble End)
20 {
21 FX1=X1;
22 FY1=Y1;
23 FX2=X2;
24 FY2=Y2;
25 FStart=Start;
26 FEnd=End;
27
28 FCenX=(FX1+FX2)/2;
29 FCenY=(FY1+FY2)/2;
30 FA=(FX2-FX1)/2;
31 FB=(FY2-FY1)/2;
32 }
33
34 void GetP(VDouble T , VDouble& X , VDouble& Y)
35 {
36 VDouble Angle=FStart+T*(FEnd-FStart);
37 VDouble Sin=-sin(Angle);
38 VDouble Cos=cos(Angle);
39 if(abs(Sin)<0.5)
40 {
41 VDouble X2=1/(1/(FA*FA)+(Sin*Sin)/(FB*FB*Cos*Cos));
42 if(Pi_f/2<=Angle && Angle<=Pi_f*3/2)
43 {
44 X=-sqrt(X2);
45 }
46 else
47 {
48 X=sqrt(X2);
49 }
50 Y=X*Sin/Cos;
51 }
52 else
53 {
54 VDouble Y2=1/(1/(FB*FB)+(Cos*Cos)/(FA*FA*Sin*Sin));
55 if(0<=Angle && Angle<=Pi_f)
56 {
57 Y=-sqrt(Y2);
58 }
59 else
60 {
61 Y=sqrt(Y2);
62 }
63 X=Y*Cos/Sin;
64 }
65 X+=FCenX;
66 Y+=FCenY;
67 }
68
69 void SetColor(VInt X , VInt Y , VInt Color)
70 {
71 VByte R=Color%256;
72 VByte G=(Color>>8)%256;
73 VByte B=(Color>>16)%256;
74 if(X>=0 && X<FBuffer->GetWidth() && Y>=0 && Y<FBuffer->GetHeight())
75 {
76 ((VInt32u*)(FBuffer->ScanLines[Y]))[X]=(R<<16)+(G<<8)+B;
77 }
78 }
79
80 POINT GetStartPoint()
81 {
82 VDouble X,Y;
83 GetP(0,X,Y);
84 POINT P;
85 P.x=Round(X);
86 P.y=Round(Y);
87 return P;
88 }
89
90 POINT GetEndPoint()
91 {
92 VDouble X,Y;
93 GetP(1,X,Y);
94 POINT P;
95 P.x=Round(X);
96 P.y=Round(Y);
97 return P;
98 }
99
100 void DrawCurve()
101 {
102 POINT StartPoint=GetStartPoint();
103 POINT EndPoint=GetEndPoint();
104
105 VDouble T=0.0001;
106 VBool Finished=false;
107 VDouble OldX=StartPoint.x;
108 VDouble OldY=StartPoint.y;
109 VDouble X1,Y1;
110 VDouble X2=EndPoint.x;
111 VDouble Y2=EndPoint.y;
112
113 VInt OldX1=StartPoint.x;
114 VInt OldY1=StartPoint.y;
115 VInt OldX2=0;
116 VInt OldY2=0;
117 VBool Old2Available=false;
118 SetColor(OldX1,OldY1,RGB(255,0,0));
119 while(!Finished)
120 {
121 /*初始步长为当前t到结束点*/
122 VDouble dT=(1-T);
123 GetP(T+dT,X1,Y1);
124 VBool AtTail=true;
125 while(true)
126 {
127 /*取半步,检查目标点与当前点的长度*/
128 VDouble dTHalf=dT/2;
129 GetP(T+dTHalf,X2,Y2);
130 VDouble Length=sqrt((X1-OldX)*(X1-OldX)+(Y1-OldY)*(Y1-OldY));
131 VDouble LengthHalf=sqrt((X2-OldX)*(X2-OldX)+(Y2-OldY)*(Y2-OldY));
132 /*如果半步长大于一步则取半步,继续迭代*/
133 if(LengthHalf>Length)
134 {
135 dT=dTHalf;
136 X1=X2;
137 Y1=Y2;
138 }
139 else
140 {
141 /*否则,如果全步长产生的距离<=1则绘制*/
142 if(Length<=1.001)
143 {
144 if(AtTail)
145 {
146 Finished=true;
147 }
148 break;
149 }
150 /*否则进行近似测量*/
151 else
152 {
153 dT*=1/Length;
154 GetP(T+dT,X1,Y1);
155 }
156 }
157 AtTail=false;
158 }
159 /*计算像素位置*/
160 VInt X=Round(X1);
161 VInt Y=Round(Y1);
162 VInt dX_I=(OldX1-X)*(OldX1-X);
163 VInt dY_I=(OldY1-Y)*(OldY1-Y);
164 /*让线条长度保持1*/
165 if(Old2Available)
166 {
167 if(dX_I==1 && dY_I==1)
168 {
169 OldX1=X;
170 OldY1=Y;
171 SetColor(OldX1,OldY1,RGB(255,0,0));
172 }
173 else
174 {
175 OldX1=X;
176 OldY1=Y;
177 SetColor(OldX1,OldY1,RGB(255,0,0));
178 SetColor(OldX2,OldY2,RGB(255,0,0));
179 }
180 Old2Available=false;
181 }
182 else
183 {
184 if(dX_I==1 && dY_I==1)
185 {
186 OldX1=X;
187 OldY1=Y;
188 SetColor(OldX1,OldY1,RGB(255,0,0));
189 }
190 else if(dX_I==1 || dY_I==1)
191 {
192 OldX2=X;
193 OldY2=Y;
194 Old2Available=true;
195 }
196 }
197 OldX=X1;
198 OldY=Y1;
199 T+=dT;
200 }
201 if(Old2Available)
202 {
203 SetColor(OldX2,OldY2,RGB(255,0,0));
204 }
205 }
206 };
207
208 class MyForm : public VL_WinForm
209 {
210 protected:
211 VL_WinDIB* FBuffer;
212 VL_WinDC* FBufferDC;
213 VL_WinDC* FFormDC;
214 Evaluator* FEvaluator;
215
216 public:
217 MyForm():VL_WinForm(true)
218 {
219 FBuffer=new VL_WinDIB(800,600);
220 FBufferDC=&FBuffer->DC;
221 FFormDC=new VL_WinControlDC(GetHandle());
222 FBufferDC->FillRect(0,0,800,600);
223 FEvaluator=new Evaluator(FBuffer);
224
225 VDouble Start=Pi_f*3/18;
226 VDouble End=Pi_f*27/18;
227 FBufferDC->Arc(200,200,600,400,Round(100*cos(Start))+400,Round(100*-sin(Start))+300,Round(100*cos(End))+400,Round(100*-sin(End))+300);
228 FEvaluator->SetEllipse(200,200,600,400,Start,End);
229 FEvaluator->DrawCurve();
230
231 SetMaximizeBox(false);
232 SetMinimizeBox(false);
233 SetBorder(vwfbSingle);
234 SetClientWidth(800);
235 SetClientHeight(600);
236 SetText(L"Vczh Ellipse");
237 MoveCenter();
238
239 OnPaint.Bind(this,&MyForm::Form_OnPaint);
240
241 Show();
242 }
243
244 ~MyForm()
245 {
246 delete FEvaluator;
247 delete FFormDC;
248 delete FBuffer;
249 }
250
251 void Form_OnPaint(VL_Base* Sender)
252 {
253 FFormDC->Draw(0,0,FBuffer);
254 }
255 };
256
257 void main()
258 {
259 new MyForm();
260 GetApplication()->Run();
261 }
posted on 2008-06-12 06:02
陈梓瀚(vczh) 阅读(2339)
评论(5) 编辑 收藏 引用 所属分类:
2D