#include "stdafx.h" #include "TCoverBooleanOper.h" #include #include #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 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; }