图形编辑“点-线”联动
- 格式:docx
- 大小:183.85 KB
- 文档页数:11
Visual C++图形编辑“点-线”联动摘要以统筹图绘制程序的编制为例,详细给出了应用Visual C++开发工具及MFC实现图形编辑中的节点-箭线联动方法。
该方法对于实现GIS应用、标图应用和统筹图应用中的类似功能有较好的参考价值。
关键词节点;箭线;编辑联动1 引言很多的图形应用如统筹图应用、GIS应用、标图应用中都存在着编辑联动的问题。
所谓编辑联动,是指在对一个图元编辑修改包括位置的变动后,其他图元由于与这个图元有某种关系,而能自动同步被修改。
按图元类型,可将图形联动划分为点-点、点-线、点-面、线-线、线-面、面-面等6种。
文中以统筹图为例,讨论节点-箭线联动编辑问题。
节点与箭线图元的实现以VC自带面向对象图形例程DRAWCLI基础,添加自定义类CDrawNode和CDrawArrow来实现。
依据功能设计,程序的主要工作包括:(1) 基本图元的绘制。
包括绘制节点和箭线。
绘制的节点图形表示为圆心标有编号圆圈;箭线的两侧标注有文字说明,且文字行与箭线保持平行,箭线带有起节点和终节点。
(2) 处理图元及相互位置关系。
包括删除操作和移动操作。
删除某一节点,与该节点相连的箭线全部删除,且调整编号在其后面的节点编号,删除箭线不影响节点。
移动节点时,与之相连的箭线相应移动,其关键是准确计算箭线的位置。
2 基本图元及联动2.1基本图元实现设在VC++6.0的环境下已建立了工程Draw.dsp。
节点类和箭线类都是以CDrawObj为基类派生。
在建立这两个类之前,需要添加以下全局变量enum DrawShape{…,circle,arrow,…};//图元类型以及相应的工具circleTool和arrowTool(arrow)、arrowlineTool2.1.1节点类CDrawNode的设计class CDrawNode : public CDrawObj{public:CDrawNode(const CRect& position,int Radius);void SetCircleIndex(int Index){ m_nIndex=Index}; 设置节点编号virtual int GetObjIndex(){ return m_nIndex} ; //获取编号public:int m_Radius; //节点半径int m_CentreX,m_CentreY;//圆心//在圆中心写上编号,要考虑编号的位数情况virtual void Draw(CDC* pDC,CDrawView* pView);protected:int m_nIndex;//编号CDrawNode* m_pDrawObj;friend class CCircleTool;};绘制节点的工具CCircleTool在鼠标左键按下OnLButtonDown的消息处理函数中,实际分配内存,产生一个节点对象。
2.1.2箭线类CDrawArrow的设计class CDrawArrow: public CDrawObj{public:CDrawRect(const CRect& position);void SetProjectName(CString name){m_ProjectName=name;};void SetProjectTime(int time) { m_ProjectTime=time;};CString GetProjectName() { return m_ProjectName;}void SetProjectTime(int time){ return m_ProjectTime;} bool m_bForeConnect;//箭线始节点标志bool m_bBackConnect;//箭线终节点标志int m_ForeConnect; //箭线连接的始节点序号int m_BackConnect; //箭线连接的终节点序号virtual int GetObjIndex() {return o};//绘制时,计算平行于箭线的说明文字的角度,位置,项目名称总在线的上方virtual void Draw(CDC* pDC,CDrawView* pView);enum ArrowType{ none, pureArrow, openArrow,stealthArrow, diamondArrow, ovalArrow};enum Shape { rectangle, roundRectangle, ellipse,line,arrow };protected:CString m_ProjectName; //项目名称int m_ProjectTime; //时间Shape m_nShape;ArrowType m_lArrow, m_rArrow; //for arrow only int m_lArrowSize, m_rArrowSize; //for arrow onlyprivate:void DrawArrow(ArrowType arrowType, POINT p1, POINT p2, int arrowSize, CDC *,int, int , int, CBrush *);friend class CArrowTool;};绘制箭线的工具CArrowTool在OnLButtonDown中实际生成箭线对象,并记录箭线所连的开始节点,箭线的终节点确定在后面说明。
2. 2图元联动操作2.2.1删除节点及箭线void CDrawView::OnEditClear(){CDrawDoc* pDoc=(CDrawDoc*)GetDocument();POSITION pos = m_selection.GetHeadPosition();while (pos != NULL){CDrawObj* pObj = m_selection.GetNext(pos);GetDocument()->Remove(pObj); //删除节点CDrawNode* pDrawCircle=(CDrawNode*)pObj;nIndex=pDrawCircle->GetObjIndex();//获取节点编号,若不是节点对象,返回0if(nIndex){pDoc->m_nIndex=nIndex;pos=GetDocument()->m_objects.GetHeadPosition();int i=0;int num=pDoc->m_objects.GetCount();m_num=pDoc->m_nIndex;while(i<num){//序号位于被删除节点之后的所有节点序号减1CDrawNode*pDrawCircle=(CDrawNode*)pDoc->m_objects.GetNext(pos);if(pDrawCircle->GetObjIndex()>m_num){pDrawCircle->SetCircleIndex(m_num);m_num++;}i++;}pos=pDoc->m_objects.GetHeadPosition();if(pos!=NULL){i=0;num=pDoc->m_objects.GetCount();while(i<num){//删除与接点相连的所有箭线CDrawRect*pDrawRect=(CDrawRect*)pDoc->m_objects.GetNext(pos);if(pDrawRect!=NULL){if(nIndex==pDrawRect->m_ForeConnect){pDoc->Remove(pDrawRect);pDrawRect->Remove();}if(nIndex==pDrawRect->m_BackConnect){pDoc->Remove(pDrawRect);pDrawRect->Remove();}if(nIndex<pDrawRect->m_ForeConnect){pDrawRect->m_ForeConnect--;}if(nIndex<pDrawRect->m_BackConnect){pDrawRect->m_BackConnect--;}}i++;}}Invalidate();pDoc->m_nIndex=m_num;}pObj->Remove();}m_selection.RemoveAll();UINT nFlags;OnLButtonDown(nFlags,CPoint(0,0));OnLButtonUp(nFlags,CPoint(0,0));}2.2.2用鼠标移动某一节点时,同步移动与其相连接的箭线void CSelectTool::OnMouseMove(CDrawView* pView, UINT nFlags, const CPoint& point){if (pView->GetCapture() != pView){…CPoint local = point;int BackConnect;pView->ClientToDoc(local);POSITION pos;if (c_drawShape == arrow)//判断鼠标移动绘制箭线过程中是否与某一节点相连//此时函数是CRectTool::OnMouseMove()调用selectTool.OnMouseMove();而跳到这里{CRect circlerect;CDrawNode* pForeCircle;CDrawNode* pBackCircle;pos=pView->GetDocument()->m_objects.GetHeadPosition();if(pos!=NULL){int i=0;int num=pView->GetDocument()->m_objects.GetCount();while(i<num){CDrawNode*pDrawCircle=(CDrawNode*)pView->GetDocument()->m_objects.GetNext(p os);if(pDrawCircle!=NULL){int index=pDrawCircle->GetObjIndex();if(index){//判断circlerect=pDrawCircle->m_position;pView->DocToClient(circlerect);if(circlerect.PtInRect(point)){local=pDrawCircle->GetHandle(8);BackConnect=pDrawCircle->GetObjIndex();}}}i++;}}}CPoint delta = (CPoint)(local - lastPoint);pos = pView->m_selection.GetHeadPosition();while (pos != NULL){CDrawObj* pObj = pView->m_selection.GetNext(pos);CRect position = pObj->m_position;if (c_drawShape == arrow){//记录终节点pObj->m_BackConnect=BackConnect;pObj->m_bBackConnect=true;}//以下实现移动节点,使所有的箭线跟随节点同步移动if (selectMode == move){if(pView->m_selection.GetCount()==1){CDrawNode* pDrawCircle=(CDrawNode*)pObj;int Index=pDrawCircle->GetObjIndex();if(Index) //移动节点{POSITIONRectpos=pView->GetDocument()->m_objects.GetHeadPosition();if(Rectpos!=NULL){int i=0;int num=pView->GetDocument()->m_objects.GetCount();while(i<num){//所有与之相连箭线同步移动CDrawRect*pDrawObj=(CDrawRect*)pView->GetDocument()->m_objects.GetNext(Rect pos);if(pDrawObj!=NULL){if(Index==pDrawObj->m_ForeConnect){//节点是箭线始节点CRectdeltarect=pDrawObj->m_position;deltarect.BottomRight()+=delta;intlength=deltarect.top-deltarect.bottom;intwidth=deltarect.left-deltarect.right;//节点移动,箭线与节点的连接点改变,计算连接点位置if(abs(length)<abs(width)&&width<0)deltarect.BottomRight()=pDrawCircle->GetHandle(8);if(abs(length)<abs(width)&&width>0)deltarect.BottomRight()=pDrawCircle->GetHandle(4);if((abs(length)>abs(width)&&width>0&&length<0)|| (abs(length)>abs(width)&&width<0&&length<0))deltarect.BottomRight()=pDrawCircle->GetHandle(2);if((abs(length)>abs(width)&&length>0&&width>0)||(abs(length)>abs(width)&&length>0&&width<0))deltarect.BottomRight()=pDrawCircle->GetHandle(6);int nIndex=pDrawObj->m_BackConnect;POSITIONcirclepos=pView->GetDocument()->m_objects.GetHeadPosition();if(circlepos!=NULL){int i=0;int num=pView->GetDocument()->m_objects.GetCount();while(i<num){CDrawNode*pDrawNode=(CDrawNode*)pView->GetDocument()->m_objects.GetNext(cir clepos);if(pDrawNode!=NULL){if(nIndex==pDrawNode->GetObjIndex()){//计算箭线的新位置if(abs(length)<abs(width)&&width<0)deltarect.TopLeft()=pDrawNode->GetHandle(4);if(abs(length)<abs(width)&&width>0)deltarect.TopLeft()=pDrawNode->GetHandle(8);if((abs(length)>abs(width)&&width>0&&length<0)||(abs(length)>abs(width)&&width<0&&length<0))deltarect.TopLeft()=pDrawNode->GetHandle(6);if((abs(length)>abs(width)&&length>0&&width>0)||(abs(length)>abs(width)&&length>0&&width<0))deltarect.TopLeft()=pDrawNode->GetHandle(2);}}i++;}}}pDrawObj->MoveTo(deltarect,pView);}if(Index==pDrawObj->m_BackConnect){//节点是箭线终节点CRect deltarect=pDrawObj->m_position;deltarect.TopLeft()+=delta;int length=deltarect.top-deltarect.bottom;int width=deltarect.left-deltarect.right;if(abs(length)<abs(width)&&width<0)deltarect.TopLeft()=pDrawCircle->GetHandle(4);if(abs(length)<abs(width)&&width>0)deltarect.TopLeft()=pDrawCircle->GetHandle(8);if((abs(length)>abs(width)&&width>0&&length<0)|| (abs(length)>abs(width)&&width<0&&length<0))deltarect.TopLeft()=pDrawCircle->GetHandle(6);if((abs(length)>abs(width)&&length>0&&width>0)||(abs(length)>abs(width)&&length>0&&width<0))deltarect.TopLeft()=pDrawCircle->GetHandle(2);int nIndex=pDrawObj->m_ForeConnect;POSITIONcirclepos=pView->GetDocument()->m_objects.GetHeadPosition();if(pos!=NULL) {int i=0;intnum=pView->GetDocument()->m_objects.GetCount();while(i<num){ CDrawNode*pDrawNode=(CDrawNode*)pView->GetDocument()->m_objects.GetNext(cir clepos);if(pDrawNode!=NULL){if(nIndex==pDrawNode->GetObjIndex()){if(abs(length)<abs(width)&&width<0)deltarect.BottomRight()=pDrawNode->GetHandle(8);if(abs(length)<abs(width)&&width>0)deltarect.BottomRight()=pDrawNode->GetHandle(4);if((abs(length)>abs(width)&&width>0&&length<0)||(abs(length)>abs(width)&&width<0&&length<0))deltarect.BottomRight()=pDrawNode->GetHandle(2);if((abs(length)>abs(width)&&length>0&&width>0)||(abs(length)>abs(width)&&length>0&&width<0))deltarect.BottomRight()=pDrawNode->GetHandle(6);}}i++;}}}pDrawObj->MoveTo(deltarect,pView); }}i++;}}}}position += delta;pObj->MoveTo(position, pView);}else if (nDragHandle != 0)pObj->MoveHandleTo(nDragHandle, local, pView);}lastPoint = local;if (selectMode == size && c_drawShape == selection){c_last = point;SetCursor(pView->m_selection.GetHead()->GetHandleCursor(nDragH andle));return; // bypass CDrawTool}c_last = point;if (c_drawShape == selection)CDrawTool::OnMouseMove(pView, nFlags, point);}3 结语至此,基本上就达到了预定目标。