#include "StdAfx.h" #include "globalfunc.h" #include "GePolygonEx.h" #include "GeCurveInline.h" GePolygonEx::GePolygonEx(GePoly &src) { for (int i = 0; i < src.Length(); i++) { AppendNode(*src[i], 1); } } GePolygonEx::GePolygonEx(EntitySet &ent) { int nFlag0 = 0; ent.GetData(70, &nFlag0); if (nFlag0 > 1) { return; } GePoly2D poly(ent); if (!poly) { return; } poly.MapToPolygon(*this); if (!nFlag0) { ADSGePoint3d &ptStart = *(*this)[0]; ADSGePoint3d &ptEnd = *Tail(); if (ptStart == ptEnd) { int nTail = Length() - 1; Remove(nTail); if (!*this) { return; } } else { Reset(); return; } } for (int i = 0; i < Length(); i++) { m_lstVisibleFlag.Append(new int(1)); } } GePolygonEx::GePolygonEx() { } GePolygonEx::GePolygonEx(const GePolygonEx &src) { *this = src; } GePolygonEx::~GePolygonEx() { } void GePolygonEx::CopyFrom(const GeEntity* pSrc) { if (this != pSrc && pSrc->IsKindOf(GeEntity::ePolygonEx)) { Reset(); m_lstVisibleFlag.Reset(); assert(((GePolygonEx*)pSrc)->Length() == m_lstVisibleFlag.Length()); ADSGePoint3d pt; int nindex; for (int i = 0; i < ((GePolygonEx*)pSrc)->Length(); i++) { pt = *(*(GePolygonEx*)pSrc)[i]; nindex = *((GePolygonEx*)pSrc)->m_lstVisibleFlag[i]; AppendNode(pt,nindex); } } else if (this != pSrc && pSrc->IsKindOf(GeEntity::ePoly)) { Reset(); for (int i = 0; i < ((GePoly*)pSrc)->Length(); i++) { Append(new ADSGePoint3d(*(*(GePoly*)pSrc)[i])); } } } GePolygonEx & GePolygonEx::operator = (const GePolygonEx &src) { if (this != &src) { CopyFrom(&src); } return *this; } SHLoopList& GePolygonEx::GetVisibleFlag() { return m_lstVisibleFlag; } // 求第 nIndex 个点, 支持循环 ADSGePoint3d * GePolygonEx::operator [](int nIndex) { int nLen = Length(); nIndex = GlobalFunc::LimitCycle(nIndex, nLen); return GePoly::operator[](nIndex); } // 求第 nIndex 个点, 支持循环 const ADSGePoint3d & GePolygonEx::operator [](int nIndex) const { int nLen = Length(); nIndex = GlobalFunc::LimitCycle(nIndex, nLen); const GePoly &rThis = *this; return rThis[nIndex]; } void GePolygonEx::RemoveNode(int nIndex) { int nEdge = Length(); nIndex = GlobalFunc::LimitCycle(nIndex, nEdge); Remove(nIndex); m_lstVisibleFlag.Remove(nIndex); } // 求法向量,用来作为坐标变换 int GePolygonEx::GetNormal(TVector3D &vtNormal) const { int nEdgeNum = Length(); if (nEdgeNum < 3) { return RTERROR; } ADSGePoint3d pt0 = GetVertex(0); ADSGePoint3d pt1, pt2; int nFlag = 0; for (int i = 1; i < nEdgeNum; i++) { ADSGePoint3d pt = GetVertex(i); if (pt0.Distance(pt) < g_Option::instance()._DIST_SNAP) { continue; } if (!nFlag) { pt1 = pt; nFlag++; } else { GeLine ln(pt0, pt1); if ((pt & ln) == PR_OUTSIDE) { pt2 = pt; nFlag++; break; } } } if (nFlag < 2) { return RTERROR; } TVector3D vt1 = pt1 - pt0; TVector3D vt2 = pt2 - pt0; BOOL b1 = (vt1.Length() < 1.0E-6); BOOL b2 = (vt2.Length() < 1.0E-6); if (b1 || b2) { #ifndef NDEBUG g_Option::instance().adsout << _T("\n不好的GePolygonEx!"); #endif } using namespace GlobalFunc; vtNormal = vt1 * vt2; ((AcGeVector3d &)vtNormal).normalize(); // Add on 2002/10/11,上面的vtNormal可能与实际方向相反 //GePolygonExImp tmp(*this); GePolygonEx tmp(*this); tmp.Wcs2Ecs(vtNormal); double nPathArea = tmp.PathArea(); //GePolygonExImp tmp1; GePolygonEx tmp1; tmp1.AppendNode(pt0); tmp1.AppendNode(pt1); tmp1.AppendNode(pt2); tmp1.Wcs2Ecs(vtNormal); double nPathArea1 = tmp1.PathArea(); if ((nPathArea > 0 && nPathArea1 < 0) || (nPathArea < 0 && nPathArea1 > 0)) { vtNormal.Reverse(); } return RTNORM; } void GePolygonEx::Ecs2Wcs(TVector3D vtEcs) { GePoly &poly = *this; for (int i = 0; i < Length(); i++) { *poly[i] = GlobalFunc::Ecs2Wcs(*poly[i], vtEcs); } } void GePolygonEx::Wcs2Ecs(TVector3D vtEcs) { GePoly &poly = *this; for (int i = 0; i < Length(); i++) { *poly[i] = GlobalFunc::Wcs2Ecs(*poly[i], vtEcs); } } int GePolygonEx::Trianglize(PtrList &lstTris, BOOL b2D) const { GePolygonEx polyEx(*this); TVector3D vtNormal; if (!b2D) { if (GetNormal(vtNormal) != RTNORM) { return RTERROR; } polyEx.Wcs2Ecs(vtNormal); } if (polyEx.PathArea() > 1.0E-6) { polyEx.Reverse(); } int nRet = polyEx.SubTrianglize(lstTris); if (!b2D) { int num = lstTris.Length(); for (int i = 0; i < num; i++) { lstTris[i]->Ecs2Wcs(vtNormal); } } return nRet; } int GePolygonEx::GetInsidePoint(ADSGePoint3d &ptRet, BOOL b2D) const { GePolygonEx polyEx(*this); TVector3D vtNormal; if (!b2D) { if (GetNormal(vtNormal) != RTNORM) { return RTERROR; } polyEx.Wcs2Ecs(vtNormal); } if (polyEx.PathArea() > 1.0E-6) { polyEx.Reverse(); vtNormal.Reverse(); // 2003/2/27,修改以便正确解决ECS转化 } int nRet = polyEx.SubGetInsidePoint(ptRet); if (nRet == RTNORM && !b2D) { ptRet = GlobalFunc::Ecs2Wcs(ptRet, vtNormal); } return nRet; } // 求第i个顶点的夹角 double GePolygonEx::GetAngle(int idx) const { int nEdge = Length(); ASSERT(nEdge >= 3); int nNext = -1; int nPre = -1; nNext = idx + 1; nPre = idx - 1; if (idx == 0) { nPre = nEdge - 1; } if (idx == nEdge - 1) { nNext = 0; } ADSGePoint3d ptCur = (*this)[idx]; ADSGePoint3d ptPrev = (*this)[nPre]; ADSGePoint3d ptNext = (*this)[nNext]; double nPrevAng = GlobalFunc::AngleRangeTo2PI(ads_angle(ptCur, ptPrev) - ads_angle(ptCur, ptNext)); return nPrevAng; } //是否为凸多边形,2D BOOL GePolygonEx::IsConvex() const { for (int i = 0; i < Length(); i++) { double nAng = GetAngle(i); if (nAng < g_DimOption::instance()._angSnap || nAng > PI - g_DimOption::instance()._angSnap) { return FALSE; } } return TRUE; } #if ARX > 19 static int MakeCallBack(void* pData) { if( NULL == pData ) return 0 ; resbuf *rb = (resbuf*)pData; if( acedCmdCWasCancelled() ) { acutRelRb(rb); return 0 ; } resbuf *rbData = rb->rbnext; rb->rbnext = NULL; if( NULL == rbData ) acedCommandC(MakeCallBack, rbData , RT3DPOINT , rb->resval.rpoint, RTSTR , _T("C"), RTNONE); else acedCommandC(MakeCallBack, rbData , RT3DPOINT , rb->resval.rpoint, RTNONE ); acutRelRb(rb); acedCallBackOnCancel(); return 1; } // 测试用 int GePolygonEx::Make(const TCHAR *szLay) { GlobalFunc::PushAcadVar clayer(_T("CLAYER"), szLay); GlobalFunc::PushAcadVar vOsMode(_T("OSMODE"), 0); resbuf *resTep, *resData; int iLen = Length(); if( iLen > 0 ) { resTep = resData = acutNewRb(RT3DPOINT); ads_point_set(*(*this)[0], resTep->resval.rpoint); for( int i=1; irbnext = acutNewRb(RT3DPOINT); ads_point_set(*(*this)[i], resTep->resval.rpoint); } } return acedCommandC(MakeCallBack, resData, RTSTR, _T(".PLINE"), RTNONE); } #else int GePolygonEx::Make(const TCHAR *szLay) { GlobalFunc::PushAcadVar clayer(_T("CLAYER"), szLay); GlobalFunc::PushAcadVar vOsMode(_T("OSMODE"), 0); ads_command(RTSTR, _T(".PLINE"), RTNONE); for (int i = 0; i < Length(); i++) { ads_command(RT3DPOINT, (*this)[i], RTNONE); } return ads_command(RTSTR, _T("C"), RTNONE); } #endif void GePolygonEx::Reverse() { GePoly::Reverse(); m_lstVisibleFlag.Reverse(); } double GePolygonEx::GetEdgeLength(int idx) const { const ADSGePoint3d &pt = (*this)[idx]; //最后一点与第一个点求距离 if (idx == Length() - 1) { idx = -1; } const ADSGePoint3d &ptNext = (*this)[idx + 1]; return pt.Distance(ptNext); } BOOL GePolygonEx::IsVisible(int idx) const { return (m_lstVisibleFlag[idx]); } void GePolygonEx::SetVisible(int idx, BOOL bVis) { *(m_lstVisibleFlag[idx]) = bVis; } ADSGePoint3d GePolygonEx::GetVertex(int idx) const { return (*this)[idx]; } void GePolygonEx::AppendNode(const ADSGePoint3d &pt, int nIndex/* = 1*/) { Append(new ADSGePoint3d(pt)); m_lstVisibleFlag.Append(new int(nIndex)); } void GePolygonEx::Reset() { GePoly::Reset(); m_lstVisibleFlag.Reset(); } int GePolygonEx::SubTrianglize(PtrList &lstTris) { LAB_START: int nEdge = Length(); if (nEdge < 3) { return RTNORM; } // 消除长度为0的边 for (int i = 0; i < nEdge; i++) { if (GetEdgeLength(i) < g_Option::instance()._DIST_SNAP) { RemoveNode(i); nEdge--; i--; } } // 消除0和PI的顶点,可能没有必要 for (i = 9; i < nEdge; i++) { if (nEdge < 3) { return RTNORM; } double nAng = GetAngle(i); if (fabs(nAng) < g_DimOption::instance()._angSnap) //夹角为0 { BOOL bVis = IsVisible(i - 1); if (GetEdgeLength(i - 1) < GetEdgeLength(i)) { bVis = IsVisible(i); } SetVisible(i - 1, bVis); RemoveNode(i); nEdge--; i--; if (fabs(nAng) < g_DimOption::instance()._angSnap) //消除0度的夹角,可能导致边长为0 { goto LAB_START; } } else if (fabs(nAng - PI) < g_DimOption::instance()._angSnap) //夹角为PI { BOOL bVis1 = IsVisible(i - 1); BOOL bVis2 = IsVisible(i); if (bVis1 == bVis2) //可见性相同,可以消除 { SetVisible(i - 1, bVis1); RemoveNode(i); nEdge--; i--; } } } if (nEdge < 3) { return RTNORM; } if (nEdge == 3) { i = 0; int nVisFlag = SIDE1_INVISIBLE * (!IsVisible(i - 1)) + SIDE2_INVISIBLE * (!IsVisible(i)) + SIDE3_INVISIBLE * (!IsVisible(i + 1)); lstTris.Append(new GeTriangle(GetVertex(i - 1), GetVertex(i), GetVertex(i + 1), nVisFlag)); Reset(); return RTNORM; } // 消除小于180的凸角 for (i = 0; i < nEdge; i++) { double nAng = GetAngle(i); if (nAng < PI - g_DimOption::instance()._angSnap) { int nVisFlag = SIDE1_INVISIBLE * (!IsVisible(i - 1)) + SIDE2_INVISIBLE * (!IsVisible(i)) + SIDE3_INVISIBLE; GeTriangle tri(GetVertex(i - 1), GetVertex(i), GetVertex(i + 1), nVisFlag); BOOL bAllow = TRUE; // 其他顶点都在tri外部或第3边,则可以消除 for (int n = i + 2; n < i - 1 + nEdge; n++) { ADSGePoint3d ptTest = GetVertex(n); int nHitFlag = tri.HitTest2d(ptTest); int nFlag = 1; //第一个端点到末尾端点的路径(除首末点外)都需要重新测定 switch(nHitFlag) { case 0: //外部 break; case 1: //第一点 break; case 2: //第2点 nFlag = 2; break; case 3: //第3点 break; case -1: //第1边 nFlag = 2; break; case -2: //第2边 nFlag = 2; break; case -3: //第3边 break; case 4: nFlag = 0; break; default: break; } if (!nFlag) { bAllow = FALSE; break; } if (nFlag == 2) //测定ptTest的2边是否和tri的第三边有交点,且交点在线内 { GeLine lnSect(tri.vertex3, tri.vertex1, LS_FINITE); GeLine lnOut(ptTest, GetVertex(n + 1), LS_FINITE); GeLine lnIn(GetVertex(n - 1), ptTest, LS_FINITE); ADSGePoint3d ptInt1, ptInt2; BOOL bInt1 = (lnSect.Intersection(&lnOut, ptInt1) > 0); //比ads_inters更加可靠 if (bInt1) { if (lnSect.GetStartPoint().Distance2d(ptInt1) > g_Option::instance()._DIST_SNAP && lnSect.GetEndPoint().Distance2d(ptInt1) > g_Option::instance()._DIST_SNAP) { bAllow = FALSE; break; } } BOOL bInt2 = (lnSect.Intersection(&lnIn, ptInt2) > 0); //比ads_inters更加可靠 if (bInt2) { if (lnSect.GetStartPoint().Distance2d(ptInt2) > g_Option::instance()._DIST_SNAP && lnSect.GetEndPoint().Distance2d(ptInt2) > g_Option::instance()._DIST_SNAP) { bAllow = FALSE; break; } } } } if (bAllow) { lstTris.Append(new GeTriangle(tri)); SetVisible(i - 1, FALSE); //必须在顶点移除前更改可见性,否则如果首点被移除导致序号的变化 RemoveNode(i); goto LAB_START; } } } #ifndef NDEBUG g_Option::instance().adsout << _T("\n警告:多边形三角化可能不合适, 还有") << Length() << _T("个边未三角化!"); Make(_T("1")); #endif return RTERROR; } int GePolygonEx::SubGetInsidePoint(ADSGePoint3d &ptRet) { LAB_START: int nEdge = Length(); if (nEdge < 3) { return RTERROR; } // 消除长度为0的边 for (int i = 0; i < nEdge; i++) { if (GetEdgeLength(i) < g_Option::instance()._DIST_SNAP) { RemoveNode(i); nEdge--; i--; } } // 消除0和PI的顶点 for (i = 0; i < nEdge; i++) { if (nEdge < 3) { return RTERROR; } double nAng = GetAngle(i); if (fabs(nAng) < g_DimOption::instance()._angSnap) //夹角为0 { BOOL bVis = IsVisible(i - 1); if (GetEdgeLength(i - 1) < GetEdgeLength(i)) { bVis = IsVisible(i); } SetVisible(i - 1, bVis); RemoveNode(i); nEdge--; i--; if (fabs(nAng) < g_DimOption::instance()._angSnap) //消除0度的夹角,可能导致边长为0 { goto LAB_START; } } else if (fabs(nAng - PI) < g_DimOption::instance()._angSnap) //夹角为PI { BOOL bVis1 = IsVisible(i - 1); BOOL bVis2 = IsVisible(i); if (bVis1 == bVis2) //可见性相同,可以消除 { SetVisible(i - 1, bVis1); RemoveNode(i); nEdge--; i--; } } } if (nEdge < 3) { return RTERROR; } BOOL bAoJiao = FALSE; double nPi = PI - 1.0E-6; // 还没有优化,应当同时向前、向后消除 // 消除凹角, 向前 for (i = 0; i < nEdge; i++) { double nAng = GetAngle(i); double nAngNext = GetAngle(i+1); if (!bAoJiao) { bAoJiao = (nAng > nPi); } if (nAng > nPi && nAngNext < nPi) { BOOL bCanCut = TRUE; GeLine ln(GetVertex(i), GetVertex(i + 2), LS_FINITE); //判断i+3到i-2是否的边是否有交点 for (int n = i + 3; n <= i - 2 + nEdge; n++) { ADSGePoint3d ptInt; GeLine ln1(GetVertex(n), GetVertex(n + 1), LS_FINITE); if (ln.Intersection(&ln1, ptInt)) { int nFlag1 = (ptInt & ln); int nFlag2 = (ptInt & ln1); if (nFlag1 == PR_INSIDE && nFlag2 == PR_INSIDE) { bCanCut = FALSE; break; } } } if (bCanCut) { ADSGePoint3d pt1 = GetVertex(i); ADSGePoint3d pt2 = GetVertex(i + 1); ADSGePoint3d pt3 = GetVertex(i + 2); ptRet.x = (pt1.x + pt2.x + pt3.x) / 3.0; ptRet.y = (pt1.y + pt2.y + pt3.y) / 3.0; ptRet.z = (pt1.z + pt2.z + pt3.z) / 3.0; return RTNORM; } } } if (bAoJiao) { // 消除凹角, 向后 for (i = nEdge - 1; i >= 0; i--) { double nAng = GetAngle(i); double nAngPrev = GetAngle(i - 1); if (nAng > nPi && nAngPrev < nPi) { BOOL bCanCut = TRUE; GeLine ln(GetVertex(i), GetVertex(i - 2), LS_FINITE); //消i-1 //判断i+1到i-4边是否有交点 for (int n = i + 1; n <= i - 4 + nEdge; n++) { ADSGePoint3d ptInt; GeLine ln1(GetVertex(n), GetVertex(n + 1), LS_FINITE); if (ln.Intersection(&ln1, ptInt)) { int nFlag1 = (ptInt & ln); int nFlag2 = (ptInt & ln1); if (nFlag1 == PR_INSIDE && nFlag2 == PR_INSIDE) { bCanCut = FALSE; break; } } } if (bCanCut) { ADSGePoint3d pt1 = GetVertex(i - 2); ADSGePoint3d pt2 = GetVertex(i - 1); ADSGePoint3d pt3 = GetVertex(i); ptRet.x = (pt1.x + pt2.x + pt3.x) / 3.0; ptRet.y = (pt1.y + pt2.y + pt3.y) / 3.0; ptRet.z = (pt1.z + pt2.z + pt3.z) / 3.0; return RTNORM; } } } } ADSGePoint3d pt1 = GetVertex(0); ADSGePoint3d pt2 = GetVertex(1); ADSGePoint3d pt3 = GetVertex(2); ptRet.x = (pt1.x + pt2.x + pt3.x) / 3.0; ptRet.y = (pt1.y + pt2.y + pt3.y) / 3.0; ptRet.z = (pt1.z + pt2.z + pt3.z) / 3.0; return RTNORM; } bool GePolygonEx::IsKindOf(GeEntity::TEntityId entType) const { switch(entType) { case GeEntity::eEntity: case GeEntity::eCurve: case GeEntity::ePoly: case GeEntity::eShape: case GeEntity::ePolygonEx: return true; } return false; } GeEntity::TEntityId GePolygonEx::Type() const { return GeEntity::ePolygonEx; }