自适应步长Bezier曲线扫描

自适应步长Bezier曲线扫描
    花了两个小时把这个东西做好了。虽然不及[LIEN87 ; SHAN87 ; SHAN89]论文厉害,不过自己弄的这个写起来倒是相当容易的。在这里贴出效果图和代码。效果图中,我先使用蓝色画笔,用PolyBezier绘制曲线,然后使用红色像素使用自己的算法绘制曲线。可以看见有一点点误差,不过效果还是可以接受的。代码仍然使用自己的那套库开发,不过曲线扫描的方法不受库的限制。这个算法保证非交叉部分的点不会被重复绘制。

    有了这个算法之后我就可以把贝塞尔曲线转换成密度刚好的折线了。这才是最终目的。
自适应步长Bezier曲线扫描_第1张图片

  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  MyForm :  public  VL_WinForm
  8  {
  9  protected :
 10      VL_WinDIB *  FBuffer;
 11      VL_WinDC *  FBufferDC;
 12      VL_WinDC *  FFormDC;
 13      VL_WinPen::Ptr FGDIPen;
 14      VL_WinPen::Ptr FMyPen;
 15 
 16      POINT FControlPoints[ 4 ];
 17      VInt FMouseIndex;
 18 
 19       void  Clear()
 20      {
 21          FBufferDC -> FillRect( 0 , 0 , 800 , 600 );
 22      }
 23 
 24       void  GetD(VDouble T , VDouble &  dX , VDouble &  dY)
 25      {
 26          dX =     FControlPoints[ 0 ].x * ( - 3 * ( 1 - T) * ( 1 - T)) +
 27              FControlPoints[ 1 ].x * ( - 6 * T * ( 1 - T) + 3 * ( 1 - T) * ( 1 - T)) +
 28              FControlPoints[ 2 ].x * ( - 3 * T * T + 6 * T * ( 1 - T)) +
 29              FControlPoints[ 3 ].x * 3 * T * T;
 30 
 31          dY =     FControlPoints[ 0 ].y * ( - 3 * ( 1 - T) * ( 1 - T)) +
 32              FControlPoints[ 1 ].y * ( - 6 * T * ( 1 - T) + 3 * ( 1 - T) * ( 1 - T)) +
 33              FControlPoints[ 2 ].y * ( - 3 * T * T + 6 * T * ( 1 - T)) +
 34              FControlPoints[ 3 ].y * 3 * T * T;
 35      }
 36 
 37       void  GetP(VDouble T , VDouble &  X , VDouble &  Y)
 38      {
 39          X =     FControlPoints[ 0 ].x * ( 1 - T) * ( 1 - T) * ( 1 - T) +
 40              FControlPoints[ 1 ].x * 3 * T * ( 1 - T) * ( 1 - T) +
 41              FControlPoints[ 2 ].x * 3 * T * T * ( 1 - T) +
 42              FControlPoints[ 3 ].x * T * T * T;
 43 
 44          Y =     FControlPoints[ 0 ].y * ( 1 - T) * ( 1 - T) * ( 1 - T) +
 45              FControlPoints[ 1 ].y * 3 * T * ( 1 - T) * ( 1 - T) +
 46              FControlPoints[ 2 ].y * 3 * T * T * ( 1 - T) +
 47              FControlPoints[ 3 ].y * T * T * T;
 48      }
 49 
 50       void  SetColor(VInt X , VInt Y , VInt Color)
 51      {
 52          VByte R = Color % 256 ;
 53          VByte G = (Color >> 8 ) % 256 ;
 54          VByte B = (Color >> 16 ) % 256 ;
 55           if (X >= 0   &&  X < FBuffer -> GetWidth()  &&  Y >= 0   &&  Y < FBuffer -> GetHeight())
 56          {
 57              ((VInt32u * )(FBuffer -> ScanLines[Y]))[X] = (R << 16 ) + (G << 8 ) + B;
 58          }
 59      }
 60 
 61       void  DrawCurve()
 62      {
 63          FBufferDC -> MoveTo(FControlPoints[ 0 ].x,FControlPoints[ 0 ].y);
 64          VDouble T = 0.0001 ;
 65          VBool Finished = false ;
 66          VDouble OldX = FControlPoints[ 0 ].x;
 67          VDouble OldY = FControlPoints[ 0 ].y;
 68          VDouble X1,Y1;
 69          VDouble X2 = FControlPoints[ 3 ].x;
 70          VDouble Y2 = FControlPoints[ 3 ].y;
 71 
 72          VInt OldX1 = FControlPoints[ 0 ].x;
 73          VInt OldY1 = FControlPoints[ 0 ].y;
 74          VInt OldX2 = 0 ;
 75          VInt OldY2 = 0 ;
 76          VBool Old2Available = false ;
 77          SetColor(OldX1,OldY1,RGB( 255 , 0 , 0 ));
 78           while ( ! Finished)
 79          {
 80               /* 初始步长为当前t到结束点 */
 81              VDouble dT = ( 1 - T);
 82              VBool AtTail = true ;
 83               while ( true )
 84              {
 85                   /* 取半步,检查目标点与当前点的长度 */
 86                  VDouble dTHalf = dT / 2 ;
 87                   if (dTHalf < 0.00001 )
 88                  {
 89                      dTHalf = dTHalf;
 90                  }
 91                  GetP(T + dT,X1,Y1);
 92                  GetP(T + dTHalf,X2,Y2);
 93                  VDouble Length = sqrt((X1 - OldX) * (X1 - OldX) + (Y1 - OldY) * (Y1 - OldY));
 94                  VDouble LengthHalf = sqrt((X2 - OldX) * (X2 - OldX) + (Y2 - OldY) * (Y2 - OldY));
 95                   /* 如果半步长大于一步则取半步,继续迭代 */
 96                   if (LengthHalf >= Length)
 97                  {
 98                      dT = dTHalf;
 99                  }
100                   else
101                  {
102                       /* 否则,如果全步长产生的距离<=1则绘制 */
103                       if (Length <= 1 )
104                      {
105                           if (AtTail)
106                          {
107                              Finished = true ;
108                          }
109                           break ;
110                      }
111                       /* 否则进行近似测量 */
112                       else
113                      {
114                          dT *= 1 / Length;
115                          GetP(T + dT,X1,Y1);
116                      }
117                  }
118                  AtTail = false ;
119              }
120               /* 计算像素位置 */
121              VInt X = Round(X1);
122              VInt Y = Round(Y1);
123              VInt dX_I = (OldX1 - X) * (OldX1 - X);
124              VInt dY_I = (OldY1 - Y) * (OldY1 - Y);
125               /* 让线条长度保持1 */
126               if (Old2Available)
127              {
128                   if (dX_I == 1   &&  dY_I == 1 )
129                  {
130                      OldX1 = X;
131                      OldY1 = Y;
132                      SetColor(OldX1,OldY1,RGB( 255 , 0 , 0 ));
133                  }
134                   else
135                  {
136                      OldX1 = X;
137                      OldY1 = Y;
138                      SetColor(OldX1,OldY1,RGB( 255 , 0 , 0 ));
139                      SetColor(OldX2,OldY2,RGB( 255 , 0 , 0 ));
140                  }
141                  Old2Available = false ;
142              }
143               else
144              {
145                   if (dX_I == 1   &&  dY_I == 1 )
146                  {
147                      OldX1 = X;
148                      OldY1 = Y;
149                      SetColor(OldX1,OldY1,RGB( 255 , 0 , 0 ));
150                  }
151                   else   if (dX_I == 1   ||  dY_I == 1 )
152                  {
153                      OldX2 = X;
154                      OldY2 = Y;
155                      Old2Available = true ;
156                  }
157              }
158              OldX = X1;
159              OldY = Y1;
160              T += dT;
161          }
162           if (Old2Available)
163          {
164              SetColor(OldX2,OldY2,RGB( 255 , 0 , 0 ));
165          }
166      }
167 
168       void  DrawHandles()
169      {
170           for (VInt i = 0 ;i < 4 ;i ++ )
171          {
172              POINT P = FControlPoints[i];
173              FBufferDC -> Ellipse(P.x - 2 ,P.y - 2 ,P.x + 2 ,P.y + 2 );
174          }
175      }
176 
177       void  Draw()
178      {
179          Clear();
180          FBufferDC -> SetPen(FGDIPen);
181          FBufferDC -> PolyBezier(FControlPoints, 4 );
182          FBufferDC -> SetPen(FMyPen);
183          DrawCurve();
184          DrawHandles();
185          FFormDC -> Draw( 0 , 0 ,FBuffer);
186      }
187  public :
188      MyForm():VL_WinForm( true )
189      {
190          FBuffer = new  VL_WinDIB( 800 , 600 );
191          FBufferDC =& FBuffer -> DC;
192          FBufferDC -> SetBackTransparent( true );
193          FFormDC = new  VL_WinControlDC(GetHandle());
194          FGDIPen = new  VL_WinPen(PS_SOLID, 1 ,RGB( 0 , 0 , 255 ));
195          FMyPen = new  VL_WinPen(PS_SOLID, 1 ,RGB( 255 , 0 , 0 ));
196          FMouseIndex =- 1 ;
197 
198          FControlPoints[ 0 ].x = 200 ;
199          FControlPoints[ 0 ].y = 400 ;
200          FControlPoints[ 1 ].x = 200 ;
201          FControlPoints[ 1 ].y = 200 ;
202          FControlPoints[ 2 ].x = 400 ;
203          FControlPoints[ 2 ].y = 200 ;
204          FControlPoints[ 3 ].x = 400 ;
205          FControlPoints[ 3 ].y = 400 ;
206 
207          OnPaint.Bind( this , & MyForm::Form_OnPaint);
208          OnLeftButtonDown.Bind( this , & MyForm::Form_OnMouseDown);
209          OnMouseMove.Bind( this , & MyForm::Form_OnMouseMove);
210          OnLeftButtonUp.Bind( this , & MyForm::Form_OnMouseUp);
211 
212          SetMaximizeBox( false );
213          SetMinimizeBox( false );
214          SetBorder(vwfbSingle);
215          SetClientWidth( 800 );
216          SetClientHeight( 600 );
217          SetText(L " Vczh Bezier " );
218          MoveCenter();
219          Draw();
220          Show();
221      }
222 
223       ~ MyForm()
224      {
225          delete FFormDC;
226          delete FBuffer;
227      }
228 
229       void  Form_OnPaint(VL_Base *  Sender)
230      {
231          FFormDC -> Draw( 0 , 0 ,FBuffer);
232      }
233 
234       void  Form_OnMouseDown(VL_Base *  Sender,VLS_MouseStruct MouseStruct)
235      {
236           /* 计算出在鼠标控制范围内(6像素)的控制点 */
237           for (VInt i = 0 ;i < 4 ;i ++ )
238          {
239              POINT P = FControlPoints[i];
240               if ((P.x - MouseStruct.X) * (P.x - MouseStruct.X) + (P.y - MouseStruct.Y) * (P.y - MouseStruct.Y) <= 36 )
241              {
242                  FMouseIndex = i;
243                   break ;
244              }
245          }
246          Form_OnMouseMove(Sender,MouseStruct);
247      }
248 
249       void  Form_OnMouseMove(VL_Base *  Sender,VLS_MouseStruct MouseStruct)
250      {
251           /* 抓住有效控制点的话则移动 */
252           if (FMouseIndex !=- 1 )
253          {
254              FControlPoints[FMouseIndex].x = MouseStruct.X;
255              FControlPoints[FMouseIndex].y = MouseStruct.Y;
256              Draw();
257          }
258      }
259 
260       void  Form_OnMouseUp(VL_Base *  Sender,VLS_MouseStruct MouseStruct)
261      {
262           /* 接触控制 */
263          FMouseIndex =- 1 ;
264      }
265  };
266 
267  void  main()
268  {
269       new  MyForm();
270      GetApplication() -> Run();
271  }

你可能感兴趣的:(自适应步长Bezier曲线扫描)