|
|
#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<CObjBase> pObj = layer.GetFirstObjInRect(rect);
|
|
|
//获得obj 在rect 中的第一条line -----------------------------------------------
|
|
|
Dbxy LinePt1,LinePt2;
|
|
|
GetFirstLineInRect(pObj,rect,LinePt1,LinePt2);
|
|
|
if(LinePt1.Equal(LinePt2))
|
|
|
return;
|
|
|
//获得line 形成的矩形中所有的线段到LineVec -----------------------------------------------
|
|
|
vector<DbLine> LineVec;
|
|
|
DbRect LineRect = GetLineRect(LinePt1,LinePt2);
|
|
|
layer.GetLineInRect(LineRect,LineVec,false);
|
|
|
//计算所有的交点到PointVec -----------------------------------------------
|
|
|
vector<Dbxy> 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<CObjBase> &pObj,DbRect &rect,Dbxy &LinePt1,Dbxy &LinePt2)
|
|
|
{
|
|
|
vector<DbLine> 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<DbLine> &LineVec,vector<Dbxy> &PointVec)
|
|
|
{
|
|
|
vector<DbLine>::iterator iter = LineVec.begin();
|
|
|
vector<DbLine>::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<CObjBase> pObj,vector<Dbxy> &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<CObjBase> 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<CObjBase> sPtr(pObj);
|
|
|
m_TmpObjContainer.AddObject(sPtr);
|
|
|
pCommandCut->AddOpObj(sPtr);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
delete pObj;
|
|
|
}
|
|
|
}
|
|
|
//将obj 剪切为两个部分
|
|
|
bool CMouseToolCut::CutObjExt(Dbxy LinePt1,Dbxy LinePt2,Sptr<CObjBase> pObj,Dbxy CutPt1,Dbxy CutPt2,CObjPline *&pObj1,CObjPline *&pObj2)
|
|
|
{
|
|
|
vector<CDataPoint>&Container = pObj->GetPtContainer();
|
|
|
int size = Container.size();
|
|
|
Dbxy NearPt;//第一部分最后的点
|
|
|
Dbxy FarPt;//第二部分第一个点
|
|
|
//分割第一部分------------------------------------------------------------
|
|
|
int i=0;
|
|
|
for(;i<size;i++)
|
|
|
{
|
|
|
Dbxy pt = Container[i].GetPt();
|
|
|
Dbxy Nextpt = Container[i+1].GetPt();
|
|
|
//检查是否为当前操作的线段
|
|
|
if(IsSelLine(LinePt1,LinePt2,pt,Nextpt))
|
|
|
{
|
|
|
GetNearFarPoint(CutPt1,CutPt2,pt,NearPt,FarPt);
|
|
|
//如果剪切点是obj 的端点, 则没有第一部分
|
|
|
if(i==0 && (pt.Equal(CutPt1) || pt.Equal(CutPt2)))
|
|
|
{
|
|
|
i++;//break 了以后i 不会自增
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
if(i==0)//创建第一部分
|
|
|
{
|
|
|
pObj1 = new CObjPline;
|
|
|
//当前点加入第一部分
|
|
|
CDataPoint DataPoint(Container[i].GetPt());
|
|
|
DataPoint.SetIsNode(true);
|
|
|
pObj1->AddDataPoint(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(;i<size;i++)
|
|
|
{
|
|
|
if(bflg)//分割点的第二个点为第二段的起点
|
|
|
{
|
|
|
|
|
|
pObj2 = new CObjPline;
|
|
|
CDataPoint DataPoint(FarPt);
|
|
|
DataPoint.SetIsNode(true);
|
|
|
pObj2->AddDataPoint(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<Dbxy> &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<Dbxy>::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)<CalDistance(pt2,pt))
|
|
|
{
|
|
|
NearPt = pt1;
|
|
|
FarPt = pt2;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
NearPt = pt2;
|
|
|
FarPt = pt1;
|
|
|
}
|
|
|
}
|
|
|
|