1. 程式人生 > >MFC下實現圖形學之Hermite、Bezier曲線的繪製

MFC下實現圖形學之Hermite、Bezier曲線的繪製

//*******************************************************
//捕捉滑鼠左鍵按下訊息,獲得兩個起始控制點的座標
//*******************************************************
void CDrawCurvesView::OnLButtonDown(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 oldPoint = point;
 newPoint = point;
 CurveCtrlPoints[count++] = point;
 SetCapture();
 isLButtonDown = true;
 CRect rect;
    GetClientRect(&rect);
 ClientToScreen(&rect);  //用使用者區座標重新計算螢幕座標
    ClipCursor(&rect);      //限制游標在使用者區內
                            //預設處理,呼叫基類訊息處理函式
    CView::OnLButtonDown(nFlags, point);
}
//******************************************
//按下鍵盤清除客戶區的內容,為下次繪製作準備
//******************************************
void CDrawCurvesView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
 // TODO: Add your message handler code here and/or call default
 count = 0;
 Invalidate();
 CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
//******************
//矩陣乘法
//******************
void CDrawCurvesView::MultiMatrix(int a[4][4],double b[4][2])
{
 int i,j,k;
 for(i=0;i<4;i++)
      for(j=0;j<2;j++)
     result[i][j] = 0;

 for(i=0;i<2;i++)
   for(j=0;j<4;j++)
    for(k=0;k<4;k++)
             result[j][i] += a[j][k]*b[k][i];
}
//***************************************
// 捕捉滑鼠移動訊息,繪製橡皮筋線,
//作為Hermite曲線的控制點處的切線
//***************************************
void CDrawCurvesView::OnMouseMove(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 if(isLButtonDown)
 {
    CView::OnMouseMove(nFlags, point);
    CClientDC dc(this);
    dc.SetROP2(R2_NOT);
    dc.MoveTo(newPoint);
    dc.LineTo(oldPoint);
    dc.MoveTo(newPoint);
    dc.LineTo(point);
    oldPoint = point;
 }
}
//*****************************************************
//捕捉滑鼠左鍵鬆開訊息,並在捕捉到第四個控制點
//後,根據從選單選擇項的不同,開始繪製不同曲線
//******************************************************
void CDrawCurvesView::OnLButtonUp(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 isLButtonDown=false;//標誌滑鼠釋放
    ReleaseCapture();//釋放滑鼠捕捉
    ClipCursor(NULL);//
 CurveCtrlPoints[count++] = point;
  if(count == 4)
  {
  CClientDC dc(this);
  CPen pen;
  pen.CreatePen(PS_SOLID,3,RGB(255,0,0));
  dc.SelectObject(pen);
  switch(type)
  {
    case HERMITE:
             DrawHermiteCurve(dc,200);
    break;
    case BEZIER:
     DrawBezierCurve(dc,400);
     break;
  }
  pen.DeleteObject();
 }
 CView::OnLButtonUp(nFlags, point);
}
//*******************************************
//選單響應函式,當選單項選為Hermite時,
//繪製曲線的型別設定為HERMITE
//*******************************************
void CDrawCurvesView::OnHermite()
{
 // TODO: Add your command handler code here
 type = HERMITE;
}
//******************************************
//選單響應函式,當選單項選為Bezier時,
//繪製曲線的型別設定為BEZIER
//******************************************
void CDrawCurvesView::OnBezier()
{
 // TODO: Add your command handler code here
 type = BEZIER;
}
//**************************
//繪製hermite曲線的函式
//**************************
void CDrawCurvesView::DrawHermiteCurve(CDC &dc,int nPoints)
{
 int a[4][4] =
 {
  {2,-2,1,1},
  {-3,3,-2,-1},
  {0,0,1,0},
  {1,0,0,0}
 };
    double b[4][2] = {
  {CurveCtrlPoints[0].x,CurveCtrlPoints[0].y},
  {CurveCtrlPoints[2].x,CurveCtrlPoints[2].y},
  {CurveCtrlPoints[1].x-CurveCtrlPoints[0].x,CurveCtrlPoints[1].y-CurveCtrlPoints[1].y},
  {CurveCtrlPoints[3].x-CurveCtrlPoints[2].x,CurveCtrlPoints[3].y-CurveCtrlPoints[2].y}
 };
 CPoint *pt=new CPoint[nPoints];
 double delt = 1.0/nPoints;
 double u = 0.0;
    MultiMatrix(a,b);
 for(int i = 0; i < nPoints; i++)
 {
       pt[i].x =(int) (pow(u,3)*result[0][0] + pow(u,2)*result[1][0]
     + u*result[2][0] + result[3][0]);
    pt[i].y =(int) (pow(u,3)*result[0][1] + pow(u,2)*result[1][1]
     + u*result[2][1] + result[3][1]);
    u += delt;
 }
 dc.Polyline(pt,nPoints);
 delete pt;
}
//************************
//繪製Bezier曲線的函式
//************************
void CDrawCurvesView::DrawBezierCurve(CDC &dc,int nPoints)
{
  double t = 0.0,delt = 0.0;
  delt = 1.0/(double)nPoints;
  CPoint *points = new CPoint[nPoints+1];
  for(int i=0; i<= nPoints;i++)
  {
   points[i] = Decas(4,t);
   t += delt;
  }
  dc.Polyline(points,nPoints);
}
//********************************
//繪製Bezier曲線的輔助函式,
//主要完成t在某個值時,bezier
//曲線上的一個點的座標的計算
//*********************************
CPoint CDrawCurvesView::Decas(int ptNum, double t)
{
 CPoint *coeffa = new CPoint[ptNum+1],coeffa0;
    for(int i=0;i<=ptNum;i++)
 {
  coeffa[i] = CurveCtrlPoints[i];
 }
 for(int r = 1;r <= ptNum;r++)
  for(int j = 0;j < ptNum-r;j++)
  {
   coeffa[j].x=(int)(coeffa[j].x+t*(coeffa[j+1].x-coeffa[j].x));
   coeffa[j].y=(int)(coeffa[j].y+t*(coeffa[j+1].y-coeffa[j].y));
  }
     coeffa0 = coeffa[0];
  delete coeffa;
  return coeffa0;
}