目录一.系统功能设计功能说明:实现基本图元(直线、圆、多边形、曲线)的绘制;功能要求:1)使用静态切分视图,将屏幕切分为左右窗格。
左窗格是控制窗格,右窗格为显示窗格。
2)使用橡皮筋技术动态演示基本图元的绘制过程。
3)基本图元的数据(几何数据和属性数据)可以交互进行输入和修改。
4)可以对二维图形进行颜色填充操作。
5)使用填充算法结合基本图形生成算法绘制下面的图形二.详细设计关于视图是直接基于mfc单文档制作,未能实现静态分切视图功能,实现在视图上部添加控制窗格和控制按钮,视图区用以绘图显示。
详细设计如图所示。
动态演示基本图元的绘制过程:动态演示图元绘制需要添加鼠标响应事件来设置,我的设计思路是这样的,以直线、矩形、圆为例。
首先添加一个鼠标左键单击事件voidCJjyyView::OnLButtonDown(UINT nFlags, CPoint point)在视图类上方定义BOOL型变量m_startRect,设置为确认左键单击可以开始画图元,定义HCURSOR m_HCross,初始化光标为十字型光标,然后用CPoint定义三个过程中需要用到的点:m_ptOrigin;m_OldPoint;m_startPoint;此时把UINT m_ndrawtype;同时定义用以判断画的是什么图形。
定义完后再视图类中CJjyyView::CJjyyView()初始化函数:m_startPoint=0;m_startRect=FALSE;m_ndrawtype=0;m_HCross=AfxGetApp()->LoadStandardCursor(IDC_CROSS);完成后再buttondown中添加关键代码:void CJjyyView::OnLButtonDown(UINT nFlags, CPoint point){ CView::OnLButtonDown(nFlags, point);m_startRect=TRUE;//鼠标左键单击,设置可以开始绘制图形m_startPoint=point; //记录起始点m_OldPoint=point;//设置老点也为起始点::SetCursor(m_HCross);m_ptOrigin = point;这样左键单击的响应事件就暂时设定终了,随后需要用到buttonup的响应事件来画出图形,使用Ctrl+W也就是mfc classwizard添加鼠标松开的响应,首先添加两行代码重置绘制标志m_startRect=FALSE;//重置绘制标志::ClipCursor(NULL);//解锁光标,即将光标恢复为默认光标然后添加获取设备句柄函数CClientDC dc(this);然后用dc.SelectStockObject(NULL_BRUSH);设置画刷为空画刷。
接下来使用一个switch(m_ndrawtype)来判别选择画哪一种图形,首先case1就设置为画直线:添加画直线代码:dc.MoveTo(m_startPoint);dc.LineTo(m_OldPoint); 这两句是擦去MouseMove消息响应中绘制的最后一次临时线,然后输入dc.MoveTo(m_startPoint);dc.LineTo(point);绘制固定线。
Break结束。
接下来case2即是加入画矩形的代码:dc.Rectangle(CRect(m_startPoint,m_OldPoint));dc.Rectangle(CRect(m_startPoint,point));画圆也是依次类推,过程中都是直接调用了vc中现有的函数用以绘制图形,所以这几部很简单就做好了。
画圆的代码为:dc.Ellipse(CRect(m_startPoint,m_OldPoint));dc.Ellipse(CRect(m_startPoint,point));用以上方法在有算法和可选函数的情况下基本都能画出想要的图元了,然而这样的绘制方法并不能让人在画图的时候看到临时线而判断画出的是不是想要的图形,这样就要用到mousemove消息响应机制。
添加了mousemove类后在其中加入代码:CDC *pDC=GetDC();::SetCursor(m_HCross);CClientDC dc(this);dc.SetROP2(R2_NOT);dc.SetROP2(R2_NOT);此处用两次取反来实现临时线的绘制和擦去,然后这里和bottonup中需要设置一个同样的switch()来判定所画图形,但不同的是在循环前要加入一个if(TRUE==m_startRect),根据是否有单击判定是否可以画图形,用直线做实例:case 1://LINE::SetCursor(m_HCross);//擦去上一次绘制的临时线dc.MoveTo(m_startPoint);dc.LineTo(m_OldPoint);//绘制这一次的临时线dc.MoveTo(m_startPoint);dc.LineTo(point);//将临时线的终点复制给m_OldPoint,//使其在消息循环的过程中将该值传递到//擦去上一次画线的过程中,以便擦去上一次所画的线 m_OldPoint=point;break;仿照直线实例即可完成其他基本图元的临时线型绘制,令使用者更直观的了解所画出来的图形,然后松开左键绘制固定图元线。
直线、矩形、圆实现后开始做困难一些的多边形和曲线的实现:我的思路是通过鼠标点击的点存储入数组中,用确定点相连来确定多边形的相应边绘制多边形,曲线也是通过确定点来确定曲线的控制多边形然后绘制出曲线。
在左键单击响应中也添加相应case来存储点的坐标并绘制出一个点再视区中:CDC*pDC=GetDC();x[i]=point.x;y[i]=point.y;pDC->SetPixel(point.x-1,point.y-1,RGB(0,0,0));pDC->SetPixel(point.x-1,point.y,RGB(0,0,0));pDC->SetPixel(point.x-1,point.y+1,RGB(0,0,0));pDC->SetPixel(point.x,point.y-1,RGB(0,0,0));pDC->SetPixel(point.x,point.y,RGB(0,0,0));pDC->SetPixel(point.x,point.y+1,RGB(0,0,0));pDC->SetPixel(point.x+1,point.y+1,RGB(0,0,0));pDC->SetPixel(point.x+1,point.y+1,RGB(0,0,0));pDC->SetPixel(point.x+1,point.y+1,RGB(0,0,0));然后我添加一个右键单击响应事件用以逐点连线绘制多边形和曲线。
此处我设定一个BOOL变量m_bDraw来确定右键是否单击,然后用与bottondown 相同的case来保证调用时不出误差,本人特别钟爱使用switch循环,因为不易出错,可以重复使用:代码如下:void CJjyyView::OnRButtonDown(UINT nFlags, CPoint point){ m_bDraw=TRUE;switch(m_ndrawtype){case 6:{if(m_bDraw){CDC *pDC=GetDC();pDC->MoveTo(x[0],y[0]);for(int j=1;j<i;j++)pDC->LineTo(x[j],y[j]);pDC->LineTo(x[0],y[0]);}}// TODO: Add your message handler code here and/or call default i=0;}此处i=0是消除数组中储存的点,避免重复连线和连线错误。
这是绘制多边形方法。
绘制曲线的方法是用了所学知识中N次比赛尔曲线的画法绘制,代码如下:{CDC*pDC=GetDC();x[i]=point.x;y[i]=point.y;i++;if(pDC->GetPixel(point.x,point.y)==RGB(255,255,255)){pDC->SetPixel(point.x-1,point.y-1,RGB(0,0,0));pDC->SetPixel(point.x-1,point.y,RGB(0,0,0));pDC->SetPixel(point.x-1,point.y+1,RGB(0,0,0));pDC->SetPixel(point.x,point.y-1,RGB(0,0,0));pDC->SetPixel(point.x,point.y,RGB(0,0,0));pDC->SetPixel(point.x,point.y+1,RGB(0,0,0));pDC->SetPixel(point.x+1,point.y+1,RGB(0,0,0));pDC->SetPixel(point.x+1,point.y+1,RGB(0,0,0));pDC->SetPixel(point.x+1,point.y+1,RGB(0,0,0));}}bz3=false;break;其中bz3变量是为了防止误点两次右键时会使曲线第一点连出一条新的直线至原点而添加的。
然后绘制曲线switch(m_ndrawtype){case 7:{if(m_bDraw)if(bz3==false){CDC *pDC=GetDC();float t,xx,yy;float bb;int n=i-1;pDC->MoveTo(x[0],y[0]);for(t=0.05;t<1.00001;t=t+0.05)xx=0;yy=0;for(i=0;i<=n;i++){bb=b(i,n,t);xx=xx+x[i]*bb;yy=yy+y[i]*bb;}pDC->LineTo(int(xx),int(yy));}}}// TODO: Add your message handler code here and/or call default i=0;bz3=true;}此处应在恰当位置先行定义n次曲线需要用到的函数float b(int i,int n,float t){int k,a=1,b=1;for(k=i+1;k<=n;k++) a=a*k;for(k=1;k<=n-i;k++) b=b*k;float bh=(float)a/b;for(k=1;k<=i;k++) bh=bh*t;for(k=1;k<=n-i;k++) bh=bh*(1-t);return bh;}至此,所需图元都可以实现动态绘制。