日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MFC鼠标绘制直线段并使用编码裁剪算法

發布時間:2023/12/20 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MFC鼠标绘制直线段并使用编码裁剪算法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

聰明的你通過本文可以學會在MFC中

  • 初始化時繪制自定義矩形框
  • 使用鼠標來實時繪制你想要的直線段
  • 實現編碼裁剪算法裁去直線段在自定義矩形框以外的部分

完成效果如下

  • 進入運行界面
  • 鼠標繪制直線
  • 編碼算法裁剪

接下來讓我們共同打敗這三個boss吧!難度也是和闖關類游戲一樣依次遞增呢!一步一步的跟著做哦,很容易就學會了

這篇博客主要講思路,所以要求你已經基本會使用MFC建立項目了,如果還不會的話,沒關系,我已經為你寫好了一篇MFC入門教程手把手教你建立繪制圓形的MFC項目,你保準一學就會,如果具備基本條件了,那還等什么,快開始吧


首先建立【MFC AppWizard (exe)】項目,我將其命名為【LineCut】
其次,將項目調成【Release】版本,這個很重要,否則該項目運行不了 具體步驟在向上數三行的鏈接中可以找到

1. 初始化時繪制自定義矩形框

  • 達到的效果:初次運行程序,每次更新或重繪屏幕都會顯示該矩形框
  • 先在【LineCutView.h】添加變量
  • protected:double wxl,wxr,wyt,wyb;//矩形左上角,右下角坐標或是看成上下左右四個邊界直線坐標
  • 在【LineCutView.cpp】的構造函數中初始化變量
  • //初始化矩形大小wxl=100;wxr=500;wyt=250;wyb=100;
  • 在【LineCutView.cpp】的OnDraw(CDC* pDC)函數中繪制矩形
  • //初始化時繪制矩形CClientDC dc(this);//獲取畫布CPen pen(PS_SOLID,3,RGB(0,0,225));//獲取畫筆dc.SelectObject(&pen);//將畫筆移動到畫布上dc.Rectangle(wxl,wyt,wxr,wyb);//在畫布上繪制矩形
  • 添加完這三部分代碼,運行項目,看看自己的成果,如果效果如下,那么恭喜,你已經通過第一關了,若是沒有這種效果就得回去檢查檢查是哪里出了問題
  • 2.鼠標實時繪制直線段

    • 預期效果:在客戶區內鼠標左鍵單擊觸發直線繪制,單擊點成為直線段起點=》按住鼠標左鍵同時移動光標=》移動過程中光標實際位置與起點總是有線段相連=》松開鼠標左鍵=》直線段固定=》繪制完成
    • 步驟分析:根據效果可知,在此鼠標有三個狀態/動作,左鍵按下,光標移動,左鍵彈起,所以接下來要給這三個動作添加響應函數,也就是消息函數,此三種消息函數在MFC ClassWizard 中的Messages中以存在,接下來為具體步驟:選擇【Class name:】下的【CLineCutView】=》單擊【Messages:】下的【WM_RBUTTONDOWN】=》單擊右上方的【Edit Code】=》進入【CLineCutView.cpp】編輯該響應函數。

    • 變量準備,直線至少需要兩個頂點,并添加一些鼠標左鍵按下的標志
    • 在【LineCutView.h】中添加變量
    protected:BOOL m_Draw;//記錄鼠標左鍵狀態float x1,y1,x0,y0;//起止點坐標
    • 在構造函數中初始化變量
    x0=0;y0=0;x1=0;y1=0;m_Draw=FALSE;

    1. 鼠標左鍵按下的綁定函數OnLButtonDown

    void CLineCutView::OnLButtonDown(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call default//以下4行是自己添加的,其他均為自動生成CClientDC dc(this);m_Draw=TRUE;//標記鼠標左鍵按下x0=point.x;//記錄下起點的 y0=point.y;CView::OnLButtonDown(nFlags, point); }

    2.鼠標移動的綁定函數OnMouseMove

    //鼠標移動:實時更新當前位置到鼠標左鍵單擊位置的直線,動態效果,便于用戶判斷直線段位置與長短 //反復使用兩點確定直線繪制法+不斷更新的動畫制作原理=》從而產生動態效果 void CLineCutView::OnMouseMove(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultCClientDC dc(this); x1=point.x;//記錄當前光標位置y1=point.y;if(m_Draw==TRUE)//若是沒這句,松開鼠標左鍵后直線就消失RedrawWindow();//重新調用OnDraw函數繪制直線,具體步驟稍后補上CView::OnMouseMove(nFlags, point); }

    3. 鼠標左鍵彈起綁定函數

    void CLineCutView::OnLButtonUp(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultm_Draw=FALSE;//標記鼠標左鍵彈起RedrawWindow();CView::OnLButtonUp(nFlags, point); }

    4. 想OnDraw函數添加直線繪制代碼

    在操作前先在【LineCutView.cpp】中添加四舍五入宏定義

    #define ROUND(a) (int)(a+0.5) //編碼宏定義后面千萬別帶分號,不然代入式會把分號一同帶入,造成語法錯誤 //設置直線畫筆CPen pen2(PS_SOLID,1,RGB(0,0,225));dc.SelectObject(&pen2);//將繪制直線封裝到Draw中,這樣每次更新即可重新繪制直線,便于其他部分使用//鼠標左鍵點擊后才開始傳遞鼠標移動信息if(m_Draw==TRUE){ dc.MoveTo(ROUND(x0),ROUND(y0));dc.LineTo(ROUND(x1),ROUND(y1));}

    5. 檢驗時刻: 完成了前四步,運行項目試試,若有如下效果,那么,恭喜你,成功地闖過第二關,你離目標只有1/3了,若沒有如下效果,則請回頭檢查

    編碼裁剪算法實現

    • 編碼函數
  • 添加變量和編碼函數
  • protected: unsigned int RC,RC0,RC1;//變量 public: unsigned int enCode(float x,float y);//函數
  • 完善編碼函數
    先添加四條邊界的宏定義
  • //編碼宏定義后面千萬別帶分號,不然代入式會把分號一同帶入,造成語法錯誤 #define LEFT 1//0001 #define RIGHT 2//0010 #define BOTTOM 4//0100 #define TOP 8//1000

    具體實現

    unsigned int CLineCutView::enCode(float xx,float yy ) {RC=0;//初始化if(xx<wxl)//當前點在左邊界以左RC=RC|LEFT;//利用或運算將相應位置的數置為1if(xx>wxr)RC=RC|RIGHT;if(yy<wyb)RC=RC|BOTTOM;if(yy>wyt)RC=RC|TOP;return RC; }
    • cohen()裁剪函數

    一路破關斬將的你是不是很輕松地到了這里,那么,接下來,有個博主尚未搞清原因的問題,等著聰明的你解答
    問題描述
    【LineCutView】類中的變量x0,y0,x1,y1中的x1,y1在為對其進行任何運算時在鼠標動作綁定的函數與在其他函數中的值竟然不同,而x0,y0,卻沒有這個問題。
    初步猜測
    x1,y1是已經被使用的變量名,于是我將二者換為ttx,tty,問題依舊。
    解決方案
    定義變量ttx,tty,先把終點坐標記錄下來,在使用x1,y1時再賦給二者

  • 添加變量與裁剪標志和相應函數
  • protected:BOOL m_clip;//記錄裁剪狀態float k,ttx,tty;//k為斜率,ttx,tty是為了解決上面的問題而添加的輔助變量 public:void cohen();//裁剪函數
  • 在構造函數初始化m_clip=FLASE;
  • 在OnLButtonUp函數中添加以下代碼,
  • ttx=x1;tty=y1;//保留終點坐標
  • 完善cohen()
  • void CLineCutView::cohen() {//將之前保留的坐標還原x1=ttx;y1=tty;//x1,y1在該類中的不同函數使用值竟然不同,猜測是因為變量名重復,所以使用新的變量來保存while(TRUE){RC0=enCode(x0,y0);//每次循環更新計算起止點的編碼RC1=enCode(x1,y1);if((RC0|RC1)==0)//起止點均在窗口內,簡取之"運算優先級,|要加括號!!!!!!!"{return;}else if((RC0&RC1)!=0){x1=x0;y1=y0;//利用起止點相同,重繪是即沒有直線顯示,等價于完全舍去return;}else //無法簡單取舍{if(RC0==0)//保證起點為外部點{unsigned int t;t=RC0;RC0=RC1;RC1=t;int tmp;tmp=x0;x0=x1;x1=tmp;tmp=y0;y0=y1;y1=tmp;}//斜率不存在單獨考慮if(x1-x0==0){if((RC0&LEFT)||(RC0&RIGHT))//左右兩側外,完全舍棄{y0=y1;return;}else{if(RC1==0)//至少一端在矩形內{if(RC0&BOTTOM)y0=wyb;else if(RC0&TOP)y0=wyt;}else //穿過矩形{y0=wyb;y1=wyt;}return;}}//斜率存在k=(y0-y1)/(x0-x1);//計算時類型需一致!!!//每次循環只處理一側if(RC0&LEFT) //左側之左{x0=wxl; //交點橫坐標y0=y1+k*(x0-x1);//交點縱坐標}else if(RC0&RIGHT)//右側之右{x0=wxr; //交點橫坐標y0=y1+k*(x0-x1);//交點縱坐標}else if(RC0&BOTTOM)//下側之下{y0=wyb; //交點橫坐標x0=x1+(y0-y1)/k;//交點縱坐標}else if(RC0&TOP)//上側之上{y0=wyt; //交點橫坐標x0=x1+(y0-y1)/k;//交點縱坐標}}} }
  • 添加菜單【直線裁剪】,并添加相應菜單響應函數OnMENUcohen(),(詳細步驟間見本文開頭的鏈接)
  • void CLineCutView::OnMENUcohen() {// TODO: Add your command handler code hercohen(); m_clip=TRUE;//裁剪函數已使用RedrawWindow();}
  • 修改OnDraw函數中的直線繪制條件
  • //只需修改此條件,其他皆不動 //若是不改,則裁剪后的直線無法顯示 if(m_Draw==TRUE||m_clip==TRUE){ dc.MoveTo(ROUND(x0),ROUND(y0));dc.LineTo(ROUND(x1),ROUND(y1));}
  • 到此為止,快快運行你的程序,看看是否能如開頭效果所示,若能,那么,恭喜,你通關了,基本掌握了鼠標畫圖與裁剪算法

  • 避坑指南

    • 線段頂點的類型不一致或者是線段頂點的類型均為int,那么計算斜率k則需強制轉換
    • 二進制運算符【|】優先級<【=】,所以用作條件判斷時【|】兩側必須加括號,如if((a|b)==0)
    • 編碼的宏定義要認真,別把自己搞糊涂
    • 最后一個則是我之前提到的問題,目前還不知道原因,期待你的發現

    在學習計算機圖形學時遇到了許多困難,花了許多時間才解決,所以希望該文能夠給你帶來幫助,節約時間,知識的意義在于分享,歡迎廣大朋友互相交流,qq:1140132928

    總結

    以上是生活随笔為你收集整理的MFC鼠标绘制直线段并使用编码裁剪算法的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。