513 lines
14 KiB
C++
513 lines
14 KiB
C++
#include "stdafx.h"
|
|
#include "TCoverBooleanOper.h"
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include "math.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[]=__FILE__;
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
#define E2TOL 1.e-2
|
|
#define E6TOL 1.e-6
|
|
#define E10TOL 1.e-10
|
|
|
|
static void FreeBuffer(AcDbVoidPtrArray& arCurves)
|
|
{
|
|
for (int i = 0;i < arCurves.length();i++)
|
|
{
|
|
AcDbEntity* pEnt = (AcDbEntity*)arCurves.at(i);
|
|
if (pEnt != NULL)
|
|
{
|
|
delete pEnt;
|
|
}
|
|
}
|
|
arCurves.setLogicalLength(0);
|
|
}
|
|
|
|
TCoverBooleanOper::TCoverBooleanOper()
|
|
{
|
|
}
|
|
|
|
TCoverBooleanOper::~TCoverBooleanOper()
|
|
{
|
|
}
|
|
|
|
static bool GreaterCoord(TCoverBooleanOper::PTONCRITEM item1,TCoverBooleanOper::PTONCRITEM item2)
|
|
{
|
|
AcDbCurve * pCurve = item1.m_pCurve;
|
|
AcGePoint3d ptGe1 = item1.m_ptGeOn;
|
|
AcGePoint3d ptGe2 = item2.m_ptGeOn;
|
|
|
|
double dDis1 = 0.0,dDis2 = 0.0;
|
|
pCurve->getClosestPointTo(ptGe1,ptGe1);
|
|
pCurve->getClosestPointTo(ptGe2,ptGe2);
|
|
|
|
pCurve->getParamAtPoint(ptGe1,dDis1);
|
|
pCurve->getParamAtPoint(ptGe2,dDis2);
|
|
|
|
if(dDis1 - dDis2 > E10TOL)
|
|
{
|
|
return false;//up sort
|
|
}
|
|
return true;//down sort
|
|
}
|
|
|
|
AcDbCurve* TCoverBooleanOper::CurveElement2DbCurve(TDb::TCurveElement el)
|
|
{
|
|
AcDbCurve* pCurve = NULL;
|
|
if (el.ptGe[1].distanceTo(el.ptGe[2]) < E2TOL)
|
|
{
|
|
pCurve = new AcDbLine(el.ptGe[0],el.ptGe[1]);
|
|
}
|
|
else
|
|
{
|
|
pCurve = FormatArc(el.ptGe[0],el.ptGe[1],el.ptGe[2]);
|
|
}
|
|
return pCurve;
|
|
}
|
|
|
|
BOOL TCoverBooleanOper::SortPoints(AcGePoint3dArray& points,AcDbCurve * pCurve)
|
|
{
|
|
TCoverBooleanOper::PTONCRITEM ptOnCrItem;
|
|
typedef std::vector<TCoverBooleanOper::PTONCRITEM> PtOnCrItemVector;
|
|
|
|
//排序
|
|
AcGePoint3d ptGeSta,ptGeEnd;
|
|
pCurve->getStartPoint(ptGeSta);
|
|
pCurve->getEndPoint(ptGeEnd);
|
|
|
|
PtOnCrItemVector vectorItems;
|
|
ptOnCrItem.m_pCurve = pCurve;
|
|
|
|
AcGePoint3d ptGeT;
|
|
int nLength = points.length();
|
|
for(int i = 0;i < nLength;i++)
|
|
{
|
|
ptGeT = points.at(i);
|
|
pCurve->getClosestPointTo(ptGeT,ptGeT,Adesk::kTrue);
|
|
ptOnCrItem.m_ptGeOn = ptGeT;
|
|
vectorItems.push_back(ptOnCrItem);
|
|
}
|
|
|
|
PtOnCrItemVector::iterator itHead = vectorItems.begin();
|
|
PtOnCrItemVector::iterator itTail = vectorItems.end();
|
|
std::sort(itHead,itTail,GreaterCoord);
|
|
|
|
itHead = vectorItems.begin();
|
|
itTail = vectorItems.end();
|
|
|
|
points.removeSubArray(0,nLength - 1);
|
|
AcGePoint3d ptGe;
|
|
|
|
for(;itHead != itTail;++itHead)
|
|
{
|
|
ptGe = (*itHead).m_ptGeOn;
|
|
points.append(ptGe);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
AcDbArc* TCoverBooleanOper::FormatArc(AcGePoint3d& ptGe1,AcGePoint3d& ptGe2,AcGePoint3d& ptGe3)
|
|
{
|
|
//三点确认投影到 XY 面上
|
|
ptGe1.z = ptGe2.z = ptGe3.z = 0.0;
|
|
|
|
AcDbArc* pArcThis = NULL;
|
|
AcGeCircArc3d cirArc3d;
|
|
cirArc3d.set(ptGe1,ptGe2,ptGe3);
|
|
|
|
AcGeVector3d vtNorm = cirArc3d.normal();
|
|
AcDbCircle cir;
|
|
cir.setCenter(cirArc3d.center());
|
|
cir.setRadius(cirArc3d.radius());
|
|
cir.setNormal(vtNorm);
|
|
|
|
AcGePoint3dArray arPts;
|
|
arPts.append(ptGe1);
|
|
arPts.append(ptGe3);
|
|
|
|
AcDbVoidPtrArray arCurPtrs;
|
|
cir.getSplitCurves(arPts,arCurPtrs);
|
|
|
|
double dPara = 0.0;
|
|
AcDbCurve* pCurve = NULL;
|
|
for (int j = 0;j < arCurPtrs.length();j++)
|
|
{
|
|
pCurve = (AcDbCurve*)arCurPtrs.at(j);
|
|
if (pCurve != NULL)
|
|
{
|
|
if (Acad::eOk == pCurve->getParamAtPoint(ptGe2,dPara))
|
|
{
|
|
AcDbArc* pArc = AcDbArc::cast(pCurve);
|
|
if (pArc != NULL)
|
|
{
|
|
pArcThis = pArc;
|
|
arCurPtrs.removeAt(j);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
FreeBuffer(arCurPtrs);
|
|
return pArcThis;
|
|
}
|
|
|
|
BOOL TCoverBooleanOper::BoolSubtract(TComplexCurve& curveThisEdge,const TDbExtentsEdge& otherEdge)
|
|
{
|
|
/* a b
|
|
+-------+
|
|
A / /
|
|
______________/_______/____________ B
|
|
| / 1 / 2 |
|
|
| / / |
|
|
D |___________/_______/_______________+ C
|
|
/ 3 / 4
|
|
/_______/
|
|
d c
|
|
|
|
线性布尔运算 ABCD - 12,34 段算法, 同样对圆弧
|
|
otherEdage = 12,34 两段, 这两段 通过 TCoverReleationManager 遮挡管理类计算而得,保存在实地上.
|
|
curveThisEdge = ABCD 自身边界
|
|
*/
|
|
TComplexCurve curveOtherEdge,curveThisEdgeNew;
|
|
otherEdge.GetEdage(curveOtherEdge);
|
|
|
|
BOOL bSubtract = FALSE,bThisSetAt = FALSE;
|
|
TComplexCurve compReal,compRealNew;
|
|
TDb::TCurveElement elReal,elOtherSeg,elReal2;
|
|
AcDbLine lineReal,lineEdge;
|
|
AcGePoint3d ptGeT,ptSta,ptEnd,ptGeT2;
|
|
double dPara = 0.0;
|
|
AcGePoint3dArray arPoints;
|
|
AcGeVector3d vt1,vt2;
|
|
|
|
memset(&elReal2,0,sizeof(TDb::TCurveElement));
|
|
|
|
for (int i = 0;i < curveThisEdge.length();i++)
|
|
{
|
|
elReal = curveThisEdge.at(i);
|
|
if (elReal.ptGe[0].distanceTo(elReal.ptGe[1]) < E2TOL)
|
|
continue;
|
|
|
|
compRealNew.setLogicalLength(0);
|
|
compRealNew.append(elReal);
|
|
|
|
for (int n = 0;n < compRealNew.length();n++)
|
|
{
|
|
elReal = compRealNew.at(n);
|
|
|
|
for (int j = 0;j < curveOtherEdge.length();j++)
|
|
{
|
|
//判断有部分重合的图元段
|
|
elOtherSeg = curveOtherEdge.at(j);
|
|
|
|
//确保遮挡线和原线在同一标高;[正常运算是在同一标高]
|
|
elOtherSeg.ptGe[0].z = elReal.ptGe[0].z;
|
|
elOtherSeg.ptGe[1].z = elReal.ptGe[1].z;
|
|
elOtherSeg.ptGe[2].z = elReal.ptGe[2].z;
|
|
|
|
if (elReal.ptGe[1].distanceTo(elReal.ptGe[2]) < E2TOL) //实段直线
|
|
{
|
|
if (elOtherSeg.ptGe[1].distanceTo(elOtherSeg.ptGe[2]) < E2TOL)//虚段直线
|
|
{
|
|
vt1 = elOtherSeg.ptGe[1] - elOtherSeg.ptGe[0];
|
|
vt2 = elReal.ptGe[1] - elReal.ptGe[0];
|
|
|
|
if (vt1.isParallelTo(vt2)) //两直线平行
|
|
{
|
|
lineReal.setStartPoint(elReal.ptGe[0]);
|
|
lineReal.setEndPoint(elReal.ptGe[1]);
|
|
|
|
lineReal.getClosestPointTo(elOtherSeg.ptGe[0],ptGeT,Adesk::kTrue);
|
|
if (ptGeT.distanceTo(elOtherSeg.ptGe[0]) < E2TOL)//共线
|
|
{
|
|
//判断 lineReal 整体在 lineOther 上
|
|
if (RealInsideOther(lineReal,elOtherSeg))
|
|
{
|
|
compRealNew.removeAt(n);
|
|
n -= 1;
|
|
bSubtract = TRUE;
|
|
break;
|
|
continue;
|
|
}
|
|
|
|
arPoints.setLogicalLength(0);
|
|
if (Acad::eOk == lineReal.getParamAtPoint(ptGeT,dPara)) //在实线上
|
|
{
|
|
if ( ptGeT.distanceTo(elReal.ptGe[0]) < E2TOL ||
|
|
ptGeT.distanceTo(elReal.ptGe[1]) < E2TOL ) //有一端点重合
|
|
{
|
|
//判断是否整体和 real 重合
|
|
lineReal.getClosestPointTo(elOtherSeg.ptGe[1],ptGeT2,Adesk::kTrue);
|
|
if ( ptGeT2.distanceTo(elReal.ptGe[0]) < E2TOL ||
|
|
ptGeT2.distanceTo(elReal.ptGe[1]) < E2TOL ) //另外端点重合
|
|
{
|
|
compRealNew.removeAt(n);
|
|
n -= 1;
|
|
bSubtract = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
arPoints.append(ptGeT);
|
|
}
|
|
}
|
|
|
|
lineReal.getClosestPointTo(elOtherSeg.ptGe[1],ptGeT,Adesk::kTrue);
|
|
if (Acad::eOk == lineReal.getParamAtPoint(ptGeT,dPara)) //在实线上
|
|
{
|
|
if ( ptGeT.distanceTo(elReal.ptGe[0]) < E2TOL ||
|
|
ptGeT.distanceTo(elReal.ptGe[1]) < E2TOL ) //排出端点
|
|
{
|
|
// 不用处理重合的情况, 上面也经作了判断处理
|
|
}
|
|
else
|
|
{
|
|
arPoints.append(ptGeT);
|
|
}
|
|
}
|
|
|
|
// 根据虚线图元在另实线上的实际落点,分割实线,减去虚的部分
|
|
if (arPoints.length() > 0)
|
|
{
|
|
AcDbVoidPtrArray arCurves;
|
|
SortPoints(arPoints,&lineReal);
|
|
lineReal.getSplitCurves(arPoints,arCurves);
|
|
|
|
lineEdge.setStartPoint(elOtherSeg.ptGe[0]);
|
|
lineEdge.setEndPoint(elOtherSeg.ptGe[1]);
|
|
|
|
compReal.setLogicalLength(0);
|
|
AcDbCurve* pCurve = NULL;
|
|
for (int k = 0;k < arCurves.length();k++)
|
|
{
|
|
pCurve = (AcDbCurve*)arCurves.at(k);
|
|
|
|
//判断 pcurve的中点是否在 other 上
|
|
pCurve->getStartPoint(ptSta);
|
|
pCurve->getEndPoint(ptEnd);
|
|
ptGeT = TSupportFunc::Mid(ptSta,ptEnd);
|
|
|
|
if (Acad::eOk == lineEdge.getParamAtPoint(ptGeT,dPara)) //该部分落在虚的图元上,不保留
|
|
{
|
|
|
|
}
|
|
else //该部分不落在虚的图元上,保留;
|
|
{
|
|
if (ptSta.distanceTo(ptEnd) > E2TOL)//不是点
|
|
{
|
|
elReal2 = elReal; //继承属性
|
|
elReal2.ptGe[0] = ptSta;
|
|
elReal2.ptGe[1] = ptEnd;
|
|
elReal2.ptGe[2] = ptEnd;
|
|
elReal2.bHided = 0;
|
|
compReal.append(elReal2);
|
|
bSubtract = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 获取割减后的实线
|
|
for (k = 0;k < compReal.length();k++)
|
|
{
|
|
elReal2 = compReal.at(k);
|
|
if (k == 0)
|
|
{
|
|
//替换本身
|
|
compRealNew.setAt(n,elReal2);
|
|
elReal = elReal2;
|
|
bSubtract = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//继续追加
|
|
compRealNew.append(elReal2);
|
|
bSubtract = TRUE;
|
|
}
|
|
}
|
|
FreeBuffer(arCurves);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else // elReal 是圆弧 ,圆弧的减运算
|
|
{
|
|
if (elOtherSeg.ptGe[1].distanceTo(elOtherSeg.ptGe[2]) > E2TOL ) //圆弧
|
|
{
|
|
//前提条件 : 首先同心,同半径
|
|
AcDbArc* pArcReal = FormatArc(elReal.ptGe[0],elReal.ptGe[1],elReal.ptGe[2]);
|
|
AcDbArc* pArcEdge = FormatArc(elOtherSeg.ptGe[0],elOtherSeg.ptGe[1],elOtherSeg.ptGe[2]);
|
|
|
|
if (pArcReal != NULL && pArcEdge != NULL)
|
|
{
|
|
double dDist1 = pArcReal->center().distanceTo(pArcEdge->center());
|
|
double dDist2 = pArcReal->radius() - pArcEdge->radius();
|
|
|
|
if (pArcReal->center().distanceTo(pArcEdge->center()) < E2TOL &&
|
|
fabs(pArcReal->radius() - pArcEdge->radius()) < E2TOL) //共圆
|
|
{
|
|
//判断 lineReal 整体在 lineOther 上
|
|
if (RealInsideOther(pArcReal,pArcEdge))
|
|
{
|
|
compRealNew.removeAt(n);
|
|
n -= 1;
|
|
bSubtract = TRUE;
|
|
break;
|
|
continue;
|
|
}
|
|
|
|
// 判断是否重合
|
|
pArcReal->getClosestPointTo(elOtherSeg.ptGe[0],ptGeT,Adesk::kTrue);
|
|
|
|
arPoints.setLogicalLength(0);
|
|
if ( ptGeT.distanceTo(elReal.ptGe[0]) < E2TOL ||
|
|
ptGeT.distanceTo(elReal.ptGe[2]) < E2TOL ) //有一端点重合
|
|
{
|
|
//判断是否整体和 real 重合
|
|
pArcReal->getClosestPointTo(elOtherSeg.ptGe[2],ptGeT2,Adesk::kTrue);
|
|
if ( ptGeT2.distanceTo(elReal.ptGe[0]) < E2TOL ||
|
|
ptGeT2.distanceTo(elReal.ptGe[2]) < E2TOL ) //另外端点重合
|
|
{
|
|
compRealNew.removeAt(n);
|
|
n -= 1;
|
|
bSubtract = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
arPoints.append(ptGeT);
|
|
}
|
|
|
|
pArcReal->getClosestPointTo(elOtherSeg.ptGe[2],ptGeT,Adesk::kTrue);
|
|
if (Acad::eOk == pArcReal->getParamAtPoint(ptGeT,dPara)) //在实线上
|
|
{
|
|
if ( ptGeT.distanceTo(elReal.ptGe[0]) < E2TOL ||
|
|
ptGeT.distanceTo(elReal.ptGe[2]) < E2TOL ) //排出端点
|
|
{
|
|
// 不用处理重合的情况, 上面也经作了判断处理
|
|
}
|
|
else
|
|
{
|
|
arPoints.append(ptGeT);
|
|
}
|
|
}
|
|
|
|
// 根据虚线图元在另实线上的实际落点,分割实线,减去虚的部分
|
|
if (arPoints.length() > 0)
|
|
{
|
|
AcDbVoidPtrArray arCurves;
|
|
SortPoints(arPoints,pArcReal);
|
|
pArcReal->getSplitCurves(arPoints,arCurves);
|
|
|
|
compReal.setLogicalLength(0);
|
|
AcDbCurve* pCurve = NULL;
|
|
double dSta = 0.0,dEnd = 0.0;
|
|
|
|
for (int k = 0;k < arCurves.length();k++)
|
|
{
|
|
pCurve = (AcDbCurve*)arCurves.at(k);
|
|
|
|
//判断 pcurve的中点是否在 other 上
|
|
pCurve->getStartParam(dSta);
|
|
pCurve->getEndParam(dEnd);
|
|
|
|
pCurve->getStartPoint(ptSta);
|
|
pCurve->getEndPoint(ptEnd);
|
|
|
|
ptGeT = TSupportFunc::Mid(pCurve);
|
|
if (Acad::eOk == pArcEdge->getParamAtPoint(ptGeT,dPara)) //该部分落在虚的图元上,不保留
|
|
{
|
|
|
|
}
|
|
else //该部分不落在虚的图元上,保留;
|
|
{
|
|
elReal2 = elReal; //继承属性
|
|
elReal2.ptGe[0] = ptSta;
|
|
elReal2.ptGe[1] = ptGeT;
|
|
elReal2.ptGe[2] = ptEnd;
|
|
elReal2.bHided = 0;
|
|
compReal.append(elReal2);
|
|
bSubtract = TRUE;
|
|
}
|
|
}
|
|
|
|
// 获取割减后的实线
|
|
for (k = 0;k < compReal.length();k++)
|
|
{
|
|
elReal2 = compReal.at(k);
|
|
if (k == 0)
|
|
{
|
|
compRealNew.setAt(n,elReal2);
|
|
elReal = elReal2;
|
|
bSubtract = TRUE;
|
|
}
|
|
else
|
|
{
|
|
compRealNew.append(elReal2);
|
|
bSubtract = TRUE;
|
|
}
|
|
}
|
|
FreeBuffer(arCurves);
|
|
}
|
|
}
|
|
}
|
|
//释放 临时圆弧对象
|
|
if (pArcReal != NULL) delete pArcReal;
|
|
if (pArcEdge != NULL) delete pArcEdge;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//缓存减后的实段曲线
|
|
if (compRealNew.length() > 0)
|
|
{
|
|
curveThisEdgeNew.append(compRealNew);
|
|
}
|
|
}
|
|
|
|
//被减后的所有实曲线段
|
|
curveThisEdge.setLogicalLength(0);
|
|
if (curveThisEdgeNew.length() > 0)
|
|
{
|
|
curveThisEdge.append(curveThisEdgeNew);
|
|
}
|
|
return bSubtract;
|
|
}
|
|
|
|
BOOL TCoverBooleanOper::RealInsideOther(AcDbLine& lineReal,TDb::TCurveElement& elOtherSeg)
|
|
{
|
|
//已经判断共线了
|
|
AcDbLine lineEdage(elOtherSeg.ptGe[0],elOtherSeg.ptGe[1]);
|
|
double dPara = 0.0;
|
|
if (Acad::eOk == lineEdage.getParamAtPoint(lineReal.startPoint(),dPara) &&
|
|
Acad::eOk == lineEdage.getParamAtPoint(lineReal.endPoint(),dPara))
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL TCoverBooleanOper::RealInsideOther(AcDbArc* pArcReal,AcDbArc* pArcEdge)
|
|
{
|
|
ASSERT(pArcEdge != NULL);
|
|
ASSERT(pArcReal != NULL);
|
|
|
|
AcGePoint3d ptSta,ptEnd;
|
|
pArcReal->getStartPoint(ptSta);
|
|
pArcReal->getEndPoint(ptEnd);
|
|
|
|
double dPara = 0.0;
|
|
if (Acad::eOk == pArcEdge->getParamAtPoint(ptSta,dPara) &&
|
|
Acad::eOk == pArcEdge->getParamAtPoint(ptEnd,dPara))
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
} |