使用數學方法繪製一光柵盤

來源:互聯網
上載者:User

//前兩天看論壇上有人問怎麼程式畫齒輪的問題,覺得蠻有意思的,所以自己索性也畫一個來玩玩
//其實那嚴格說來不是齒輪,而是光柵編碼器的光柵盤
//程式以三角函數為基礎,可以繪製任意角度下的任意齒數光柵盤
//多餘的話就不說了,上代碼和圖
 

 

#include <math.h>//繪製光柵盤//pDC目標DC//rect目的地區域//fAngleDeg 基準角度//TGrid 光柵柵格數void DrawGridCoder(CDC *pDC, CRect &rect, double fAngleDeg, int TGrid=64){  #define PI (4*atan(1.0)) //π  #define AngDeg2Rad(x) ((x)*PI/180.0) //角度換算到弧度  #define AngRad2Deg(x) ((x)*180.0/PI) //弧度換算到角度    //基準角度換算為弧度  while(fAngleDeg > 360)fAngleDeg-=360;  while(fAngleDeg < 0) fAngleDeg+=360;  double fAngleRad = AngDeg2Rad(fAngleDeg); //  //儲存DC  int iSaveDC = pDC->SaveDC();  //填充背景色  pDC->FillSolidRect(rect, RGB(255, 255, 255));   //座標映射 X軸向右 Y軸向上 中心點取rect的中心  int OldMapMode = pDC->SetMapMode(MM_ISOTROPIC);  CSize ptOldWinExt = pDC->SetWindowExt(1700, 1700);  CSize ptOldViewportExt = pDC->SetViewportExt(rect.Width(), -rect.Height());  CPoint ptOldOrigin = pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);  //建立和選入畫筆  CPen LinePen(PS_SOLID, 1, RGB(200, 200, 0));  CPen *pOldPen = pDC->SelectObject(&LinePen);  //小數四捨五入  #define CutToLong(x) (LONG)(((x) >= 0)? ((x)+0.5):((x)-0.5))  //繪製帶限位缺口的內壁  {    double fDeltRad = AngDeg2Rad(10.0); //    double fAngStart = fAngleRad + fDeltRad;    double fAngEnd = fAngleRad - fDeltRad;    int r1 = 60;    int r2 = r1 + 20;    POINT pt1 = { CutToLong(r1 * cos(fAngStart)), CutToLong(r1 * sin(fAngStart)) };    POINT pt2 = { CutToLong(r1 * cos(fAngEnd)), CutToLong(r1 * sin(fAngEnd)) };    double fDAng2 = fDeltRad - asin((r1 * sin(fDeltRad)) / r2);    double fAngStart2 = fAngStart - fDAng2;    double fAngEnd2 = fAngEnd + fDAng2;    POINT pt3 = { CutToLong(r2 * cos(fAngStart2)), CutToLong(r2 * sin(fAngStart2)) };    POINT pt4 = { CutToLong(r2 * cos(fAngEnd2)), CutToLong(r2 * sin(fAngEnd2)) };    pDC->MoveTo(pt2); pDC->LineTo(pt4); pDC->LineTo(pt3); pDC->LineTo(pt1);    pDC->AngleArc(0, 0, r1, (float)AngRad2Deg(-fAngStart), -(float)(360-2*AngRad2Deg(fDeltRad)));  }  //繪製圓  {    int r3 = 100;    pDC->MoveTo(r3, 0);    pDC->AngleArc(0, 0, r3, 0, 360);  }  //繪製4個小標註孔  {    int r4 = 300;    int r5 = 10;    POINT pt5 = { CutToLong(r4 * cos(fAngleRad)), CutToLong(r4 * sin(fAngleRad)) };    pDC->MoveTo(pt5.x + r5, pt5.y);    pDC->AngleArc(pt5.x, pt5.y, r5, 0, 360);    double fDivAngRad = AngDeg2Rad(360.0/8.0);    double fAngRad1 = fAngleRad+fDivAngRad/2;    double fAngRad2 = fAngleRad-fDivAngRad/2;    double r6 = r4 / cos(fDivAngRad/2);    POINT pt6 = { CutToLong(r6 * cos(fAngRad1)),  CutToLong(r6 * sin(fAngRad1)) };    pDC->MoveTo(pt6.x + r5, pt6.y);    pDC->AngleArc(pt6.x, pt6.y, r5, 0, 360);    POINT pt7 = { CutToLong(r6 * cos(fAngRad2)),  CutToLong(r6 * sin(fAngRad2)) };    pDC->MoveTo(pt7.x + r5, pt7.y);    pDC->AngleArc(pt7.x, pt7.y, r5, 0, 360);    int r7 = 470;    POINT pt8 = { CutToLong(r7 * cos(fAngleRad)), CutToLong(r7 * sin(fAngleRad)) };    pDC->MoveTo(pt8.x + r5, pt8.y);    pDC->AngleArc(pt8.x, pt8.y, r5, 0, 360);  }  //繪製8個大孔  {    double fDivAngRad = AngDeg2Rad(360.0/8.0);    int r8 = 500;    int r9 = 50;    double fAngStart3 = (fAngleRad + fDivAngRad/2);    for(int i=0; i<8; i++)    {      POINT pt8 = {CutToLong(r8 * cos(fAngStart3)), CutToLong(r8 * sin(fAngStart3))};      pDC->MoveTo(pt8.x + r9, pt8.y);      pDC->AngleArc(pt8.x, pt8.y, r9, 0, 360);      fAngStart3 += fDivAngRad;    }  }  //繪製大圓  {    int r10 = 600;    POINT pt9 = {CutToLong(r10 * cos(fAngleRad)), CutToLong(r10 * sin(fAngleRad))};    pDC->MoveTo(r10, 0);    pDC->AngleArc(0, 0, r10, 0, 360);  }  //繪製齒  {    int r11 = 800;    int r12 = r11 - 50;    int r13 = r12 - 100;    double fDivAngRad = AngDeg2Rad( 360.0/TGrid );    double fAngStart4 = (fAngleRad + fDivAngRad/2);    double fDAng5 = fDivAngRad/8;    double fDAng6 = fDivAngRad/2 - fDAng5;    for(int i=0; i<TGrid; i++)    {      double f6 = fAngStart4 - fDivAngRad/2;      double f5 = fAngStart4 - fDivAngRad/4;      if(i==0)      {        pDC->MoveTo(CutToLong(r13*cos(f6)), CutToLong(r13*sin(f6)));      }      pDC->AngleArc(0, 0, r13, (float)AngRad2Deg(-f6), (float)AngRad2Deg(f6-f5));            POINT pt6 = {CutToLong(r12 * cos(f5)), CutToLong(r12 * sin(f5))};      pDC->LineTo(pt6);        double f4 = fAngStart4 - fDAng6;      POINT pt5 = {CutToLong(r12 * cos(f4)), CutToLong(r12 * sin(f4))};      pDC->LineTo(pt5);      POINT pt4 = {CutToLong(r11 * cos(f4)), CutToLong(r11 * sin(f4))};      pDC->LineTo(pt4);      double f3 = fAngStart4 + fDAng6;      pDC->AngleArc(0, 0, r11, (float)AngRad2Deg(-f4), (float)AngRad2Deg(f4-f3) );      POINT pt3 = {CutToLong(r12 * cos(f3)), CutToLong(r12 * sin(f3))};      pDC->LineTo(pt3);      double f2 = fAngStart4 + fDivAngRad/4;      POINT pt2 = {CutToLong(r12 * cos(f2)), CutToLong(r12 * sin(f2))};      pDC->LineTo(pt2);      POINT pt1 = {CutToLong(r13 * cos(f2)), CutToLong(r13 * sin(f2))};      pDC->LineTo(pt1);            double f1 = fAngStart4 + fDivAngRad/2;      pDC->AngleArc(0, 0, r13, (float)AngRad2Deg(-f1), (float)AngRad2Deg(f1-f2));      fAngStart4 += fDivAngRad;    }  }  //標註LOG  /*  {    LOGFONT logFont = {0};    _tcscpy_s( logFont.lfFaceName, _T("Arial"));    logFont.lfHeight = -MulDiv(40, pDC->GetDeviceCaps(LOGPIXELSY), 72);    logFont.lfEscapement = CutToLong((-fAngleDeg + 90)*10);    logFont.lfOrientation = logFont.lfEscapement;    //logFont.lfWeight = FW_HEAVY;    CFont font;    font.CreateFontIndirect(&logFont);    CFont *pOldFont = pDC->SelectObject(&font);    LPCTSTR szLog = _T("Grid Coder");    CSize txtSize = pDC->GetTextExtent(szLog);    pDC->LPtoDP(&txtSize);    double r20 = 200;    double fRad2 = fAngleRad + PI - 0.1;//asin( (txtSize.cx/2)/r20 );    POINT pt20 = { CutToLong(r20 * cos(fRad2)), CutToLong(r20 * sin(fRad2)) } ;    pDC->SetTextColor(RGB(255, 0, 0));    pDC->SetBkMode(TRANSPARENT);    pDC->TextOut(pt20.x, pt20.y, szLog);    pDC->SelectObject(pOldFont);  }  */  //恢複映射模式  pDC->SetWindowExt(ptOldWinExt);  pDC->SetViewportExt(ptOldViewportExt);  pDC->SetViewportOrg(ptOldOrigin);  pDC->SetMapMode(OldMapMode);  //恢複畫筆  pDC->SelectObject(pOldPen);  //恢複DC  pDC->RestoreDC(iSaveDC);}

//為測試程式繪製情況,類中添加一double型變數,以記錄角度,使用定時器不斷的更改角度並重新整理
//因此在菜單添加一個啟動、停止和複位三個按鈕
//可以觀察動態和靜態運行情況

 

//雙緩衝繪製void CSDI22View::OnDraw(CDC* pDC){  CSDI22Doc* pDoc = GetDocument();  ASSERT_VALID(pDoc);  if (!pDoc)    return;  CRect rect;  GetClientRect(rect);  CMemDC memDC(*pDC, this);  DrawGridCoder(&memDC.GetDC(), rect, fStartAngleSet);// (double)rand()/RAND_MAX*360.0);//0);//  // TODO: 在此處為本機資料添加繪製代碼}//為防止閃爍 WM_ERASEBKGND 直接返回TRUEBOOL CSDI22View::OnEraseBkgnd(CDC* pDC){  // TODO: 在此添加訊息處理常式代碼和/或調用預設值  return TRUE;  return CView::OnEraseBkgnd(pDC);}//處理菜單訊息和重新整理BOOL CSDI22View::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo){  // TODO: 在此添加專用代碼和/或調用基類  CCmdUI*pCmdUI = (CCmdUI*) pExtra;    if(pHandlerInfo == NULL)  {    BOOL bDone = FALSE;    switch(nID)    {    case(ID_POPUP_START)://啟動      {        if(nCode == CN_UPDATE_COMMAND_UI)        {          pCmdUI->Enable(mRefreshTimerID==0);          pCmdUI->SetCheck(mRefreshTimerID? TRUE:FALSE);          bDone = TRUE;        }        else if(nCode == CN_COMMAND)        {          mRefreshTimerID = SetTimer(10, 10, NULL);          bDone = TRUE;        }        break;      }    case(ID_POPUP_STOP)://停止      {        if(nCode == CN_UPDATE_COMMAND_UI)        {          pCmdUI->Enable(mRefreshTimerID? TRUE:FALSE);          pCmdUI->SetCheck(mRefreshTimerID==0);          bDone = TRUE;        }        else if(nCode == CN_COMMAND)        {          if(mRefreshTimerID)          {            KillTimer(mRefreshTimerID);            mRefreshTimerID = 0;          }          bDone = TRUE;        }        break;      }    case (ID_POPUP_RESET)://複位      {        if(nCode == CN_UPDATE_COMMAND_UI)        {          pCmdUI->Enable(TRUE);          bDone = TRUE;        }        else if(nCode == CN_COMMAND)        {          fStartAngleSet = 0;          InvalidateRect(NULL);          bDone = TRUE;        }        break;      }    }    if(bDone)      return TRUE;  }  return CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);}//定時器訊息void CSDI22View::OnTimer(UINT_PTR nIDEvent){  // TODO: 在此添加訊息處理常式代碼和/或調用預設值  fStartAngleSet += 1.0;  InvalidateRect(NULL);  CView::OnTimer(nIDEvent);}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.