#include "StdAfx.h" #include "MouseToolCut.h" #include "GlobalDrawMgr.h" #include "Layer.h" #include "GlobalFunction.h" #include "LogMgr.h" #include "ObjPline.h" #include "CommandCut.h" #include "CommandMgr.h" #if 1//排序用比较函数 //相等返回0, 如果第一个参数优先,返回>0的值, 否则返回小于0的值 bool CompareDbPointX(Dbxy pt1,Dbxy pt2) { return pt1.x>pt2.x; } bool CompareDbPointY(Dbxy pt1,Dbxy pt2) { return pt1.y>pt2.y; } #endif CMouseToolCut::CMouseToolCut(void) { } CMouseToolCut::~CMouseToolCut(void) { } void CMouseToolCut::OnLButtonDown(UINT nFlags, CPoint point,CClientDC &dc) { Dbxy pt = gDraw->CPoint2Dbxy(point); DbRect rect = gDraw->GetCurPointRect(pt); CutLineInRect(rect); } //剪切rect 中的line void CMouseToolCut::CutLineInRect(DbRect &rect) { CLayer &layer = gLayer; if(!layer.HasObjectInRect(rect)) return; //先找到第一个在rect 的obj ----------------------------------------------- Sptr pObj = layer.GetFirstObjInRect(rect); //获得obj 在rect 中的第一条line ----------------------------------------------- Dbxy LinePt1,LinePt2; GetFirstLineInRect(pObj,rect,LinePt1,LinePt2); if(LinePt1.Equal(LinePt2)) return; //获得line 形成的矩形中所有的线段到LineVec ----------------------------------------------- vector LineVec; DbRect LineRect = GetLineRect(LinePt1,LinePt2); layer.GetLineInRect(LineRect,LineVec,false); //计算所有的交点到PointVec ----------------------------------------------- vector PointVec; CalAllIntersection(LinePt1,LinePt2,LineRect,LineVec,PointVec); //如果一个交点没有则只剩最后一个线段了, 不能修剪 if(PointVec.empty()) return; //根据交点情况处理obj ----------------------------------------------- CutObj(LinePt1,LinePt2,pObj,PointVec,rect); } //获得被切割线段形成的矩形 DbRect CMouseToolCut::GetLineRect(const Dbxy &LinePt1,const Dbxy &LinePt2) { double MixGap = 0.01; //避免水平或垂直的情况 Dbxy RectPt1 = LinePt1; Dbxy RectPt2 = LinePt2; if(IsTwoDbEqual(LinePt1.x,LinePt2.x)) { RectPt1.x -= MixGap; RectPt2.x += MixGap; } if(IsTwoDbEqual(LinePt1.y,LinePt2.y)) { RectPt1.y += MixGap; RectPt2.y -= MixGap; } DbRect LineRect(RectPt1,RectPt2); return LineRect; } //获得obj 在rect 中的第一条line void CMouseToolCut::GetFirstLineInRect(Sptr &pObj,DbRect &rect,Dbxy &LinePt1,Dbxy &LinePt2) { vector LineVec; pObj->GetLineInRect(rect,LineVec); LinePt1 = LineVec[0].m_pt1.GetPt(); LinePt2 = LineVec[0].m_pt2.GetPt(); } //计算所有交点,保存到PointVec 中 void CMouseToolCut::CalAllIntersection(Dbxy LinePt1,Dbxy LinePt2,DbRect &LineRect,vector &LineVec,vector &PointVec) { vector::iterator iter = LineVec.begin(); vector::iterator iter_end = LineVec.end(); for(;iter!=iter_end;iter++) { Dbxy pt3 = (*iter).m_pt1.GetPt(); Dbxy pt4 = (*iter).m_pt2.GetPt(); if(pt3.Equal(pt4))//不要处理两个点在一起的线段 { continue; } if(IsTwoLineIntersect(LinePt1,LinePt2,pt3,pt4)) { //如果相交求出交点 Dbxy pt = CalIntersection(LinePt1,LinePt2,pt3,pt4); //交点在rect 内则加入捕捉点 if(IsPointInRect(pt,LineRect)) { PointVec.push_back(pt); } } } } //根据交点来修剪obj //rect 是鼠标点的rect 范围 //pObj 是当前剪切的对象 //PointVec 是线段交点的容器 void CMouseToolCut::CutObj(Dbxy LinePt1,Dbxy LinePt2,Sptr pObj,vector &PointVec,DbRect &rect) { //获取离鼠标最近的剪切点------------------------------------- Dbxy CutPt1,CutPt2; if(GetCutPoint(LinePt1,LinePt2,PointVec,rect,CutPt1,CutPt2)==false) { return; } //将obj 剪切为两个部分------------------------------------------ CObjPline *pObj1 = NULL; CObjPline *pObj2 = NULL; CutObjExt(LinePt1,LinePt2,pObj,CutPt1,CutPt2,pObj1,pObj2); //创建撤销指令----------------------------------- m_TmpObjContainer.Clear(); CreatCommandCut(pObj,pObj1,pObj2); GetCurViewPtr()->RefreshView(); } //创建修剪指令 //pObj 时修剪前obj //pObj1,pObj2 是修剪后的obj void CMouseToolCut::CreatCommandCut(Sptr pObj,CObjPline *&pObj1,CObjPline *&pObj2) { CCommandCut *p = new CCommandCut; p->AddOpObj(pObj); AddToCmd(pObj1,p); AddToCmd(pObj2,p); m_TmpObjContainer.AllObjAddToLayer(); gCommandMgr.AddUndoCommand(p); gLayer.DelObj(pObj); } void CMouseToolCut::AddToCmd(CObjPline *&pObj,CCommandCut *&pCommandCut) { if(pObj) { //保存到智能指针 Sptr sPtr(pObj); m_TmpObjContainer.AddObject(sPtr); pCommandCut->AddOpObj(sPtr); } else { delete pObj; } } //将obj 剪切为两个部分 bool CMouseToolCut::CutObjExt(Dbxy LinePt1,Dbxy LinePt2,Sptr pObj,Dbxy CutPt1,Dbxy CutPt2,CObjPline *&pObj1,CObjPline *&pObj2) { vector&Container = pObj->GetPtContainer(); int size = Container.size(); Dbxy NearPt;//第一部分最后的点 Dbxy FarPt;//第二部分第一个点 //分割第一部分------------------------------------------------------------ int i=0; for(;iAddDataPoint(DataPoint); } else { pObj1->AddDataPoint(Container[i]); } //如果当前线段为操作线段,结束第一部分 if(IsSelLine(LinePt1,LinePt2,pt,Nextpt)) { GetNearFarPoint(CutPt1,CutPt2,pt,NearPt,FarPt); Dbxy pt = Container[i].GetPt(); if(!(pt == NearPt))//避免结尾重复的点2015-12-10 { CDataPoint DataPoint(NearPt); DataPoint.SetIsNode(true); pObj1->AddDataPoint(DataPoint); } i++;//break 了以后i 不会自增 break; } } //分割第二部分-------------------------------------------------------------- if(!(i==size-1 && FarPt.Equal(Container[i].GetPt()))) { bool bflg = true; for(;iAddDataPoint(DataPoint); } //当前点加入第二部分 if(i==size-1)//最后一个点是节点 { CDataPoint DataPoint(Container[i].GetPt()); DataPoint.SetIsNode(true); pObj2->AddDataPoint(DataPoint); } else { //如果FarPt 等于第一个点则不要重复加入 if(!(bflg && FarPt.Equal(Container[i].GetPt()))) { pObj2->AddDataPoint(Container[i]); } } bflg = false; } } return true; } //获取离鼠标最近的剪切点 bool CMouseToolCut::GetCutPoint(Dbxy LinePt1,Dbxy LinePt2,vector &PointVec,DbRect &rect,Dbxy &CutPt1,Dbxy &CutPt2) { //先得到鼠标rect 线段的交点-------------------------------------------------- Dbxy MousePt = IntersectionOfRectAndLine(LinePt1,LinePt2,rect); //计算和MousePt 最近的两个交点---------------------------------------------- PointVec.push_back(MousePt); PointVec.push_back(LinePt1); PointVec.push_back(LinePt2); if(IsTwoDbEqual(LinePt1.x,LinePt2.x))//垂直的情况单独处理 { //按y 排序 sort(PointVec.begin(),PointVec.end(),CompareDbPointY); } else//不垂直 { //按x 排序 sort(PointVec.begin(),PointVec.end(),CompareDbPointX); } vector::iterator MousePtIter = find(PointVec.begin(),PointVec.end(),MousePt); //只处理MousePtIter 在中间的情况 if(MousePtIter==PointVec.end() || MousePtIter==PointVec.end()-1 || MousePtIter==PointVec.begin()) return false; CutPt1 = (*(MousePtIter-1)); CutPt2 = (*(MousePtIter+1)); if(CutPt1.Equal(CutPt2)) return false; return true; } //检查是否为当前操作的线段 bool CMouseToolCut::IsSelLine(Dbxy LinePt1,Dbxy LinePt2,Dbxy pt,Dbxy Nextpt) { return ((LinePt1.Equal(pt) && LinePt2.Equal(Nextpt))||(LinePt1.Equal(Nextpt) && LinePt2.Equal(pt))); } //获得两个点中离pt 较近的点 void CMouseToolCut::GetNearFarPoint(Dbxy pt1,Dbxy pt2,Dbxy pt,Dbxy &NearPt,Dbxy &FarPt) { if(CalDistance(pt1,pt)