//-----------------------------------------------------------------------------+ // Copyright (C), 1998-2007, SH Software Co. Ltd. // = FileName : XPolygonEx 类 // = Version : ver2.0 // = Author : zjq // = CreateDate : 2002-09-09 // = Description: XPolygonEx 类定义 // = Maintainers: // //-----------------------------------------------------------------------------+ #include "StdAfx.h" #include "XPolygonEx.h" #include "XPushVar.h" #include "XGlobalFunc.h" #include "XPrivateGlobalFunc.h" #include "XGlobalCurveFunc.h" #include "XCurveInline.h" XPolygonEx::XPolygonEx(XPoly &src) { for (int i = 0; i < src.Length(); i++) { AppendNode(*src[i], 1); } } XPolygonEx::XPolygonEx(Entity &ent) { int nFlag0 = 0; ent.GetData(70, &nFlag0); if (nFlag0 > 1) { return; } XPoly2D poly(ent); if (!poly) { return; } poly.MapToPolygon(*this); if (!nFlag0) { XPoint &ptStart = *(*this)[0]; XPoint &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)); } } XPolygonEx::XPolygonEx() { } XPolygonEx::XPolygonEx(const XPolygonEx &src) { *this = src; } XPolygonEx::~XPolygonEx() { } void XPolygonEx::CopyFrom(const XEntity* pSrc) { if (this != pSrc && pSrc->IsKindOf(XEntity::ePolygonEx)) { Reset(); m_lstVisibleFlag.Reset(); assert(pSrc->GetLength() == m_lstVisibleFlag.Length()); XPoint pt; int nindex; for (int i = 0; i < ((XPolygonEx*)pSrc)->Length(); i++) { pt = *(*(XPolygonEx*)pSrc)[i]; nindex = *((XPolygonEx*)pSrc)->m_lstVisibleFlag[i]; AppendNode(pt,nindex); } } else if (this != pSrc && pSrc->IsKindOf(XEntity::ePoly)) { Reset(); for (int i = 0; i < ((XPoly*)pSrc)->Length(); i++) { Append(new XPoint(*(*(XPoly*)pSrc)[i])); } } } XPolygonEx & XPolygonEx::operator = (const XPolygonEx &src) { if (this != &src) { CopyFrom(&src); } return *this; } LoopList& XPolygonEx::GetVisibleFlag() { return m_lstVisibleFlag; } // 求第 nIndex 个点, 支持循环 XPoint * XPolygonEx::operator [](int nIndex) { int nLen = Length(); nIndex = LimitCycle(nIndex, nLen); return XPoly::operator[](nIndex); } // 求第 nIndex 个点, 支持循环 const XPoint & XPolygonEx::operator [](int nIndex) const { int nLen = Length(); nIndex = LimitCycle(nIndex, nLen); const XPoly &rThis = *this; return rThis[nIndex]; } void XPolygonEx::RemoveNode(int nIndex) { int nEdge = Length(); nIndex = LimitCycle(nIndex, nEdge); Remove(nIndex); m_lstVisibleFlag.Remove(nIndex); } // 求法向量,用来作为坐标变换 int XPolygonEx::GetNormal(XVector3D &vtNormal) const { int nEdgeNum = Length(); if (nEdgeNum < 3) { return RTERROR; } XPoint pt0 = GetVertex(0); XPoint pt1, pt2; int nFlag = 0; for (int i = 1; i < nEdgeNum; i++) { XPoint pt = GetVertex(i); if (pt0.Distance(pt) < _DIST_SNAP) { continue; } if (!nFlag) { pt1 = pt; nFlag++; } else { XLine ln(pt0, pt1); if ((pt & ln) == PR_OUTSIDE) { pt2 = pt; nFlag++; break; } } } if (nFlag < 2) { return RTERROR; } XVector3D vt1 = pt1 - pt0; XVector3D vt2 = pt2 - pt0; BOOL b1 = (vt1.Length() < 1.0E-6); BOOL b2 = (vt2.Length() < 1.0E-6); if (b1 || b2) { #ifndef NDEBUG XGeLib::adsout << _T("\n不好的XPolygonEx!"); #endif } vtNormal = vt1 * vt2; ((AcGeVector3d &)vtNormal).normalize(); // Add on 2002/10/11,上面的vtNormal可能与实际方向相反 //XPolygonExImp tmp(*this); XPolygonEx tmp(*this); tmp.Wcs2Ecs(vtNormal); double nPathArea = tmp.PathArea(); //XPolygonExImp tmp1; XPolygonEx 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 XPolygonEx::Ecs2Wcs(XVector3D vtEcs) { XPoly &poly = *this; for (int i = 0; i < Length(); i++) { *poly[i] = XPrivate::Ecs2Wcs(*poly[i], vtEcs); } } void XPolygonEx::Wcs2Ecs(XVector3D vtEcs) { XPoly &poly = *this; for (int i = 0; i < Length(); i++) { *poly[i] = XPrivate::Wcs2Ecs(*poly[i], vtEcs); } } int XPolygonEx::Trianglize(DList &lstTris, BOOL b2D) const { XPolygonEx polyEx(*this); XVector3D 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 XPolygonEx::GetInsidePoint(XPoint &ptRet, BOOL b2D) const { XPolygonEx polyEx(*this); XVector3D 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 = XPrivate::Ecs2Wcs(ptRet, vtNormal); } return nRet; } // 求第i个顶点的夹角 double XPolygonEx::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; } XPoint ptCur = (*this)[idx]; XPoint ptPrev = (*this)[nPre]; XPoint ptNext = (*this)[nNext]; double nPrevAng = CT_std_angle(ads_angle(ptCur, ptPrev) - ads_angle(ptCur, ptNext)); return nPrevAng; } //是否为凸多边形,2D BOOL XPolygonEx::IsConvex() const { for (int i = 0; i < Length(); i++) { double nAng = GetAngle(i); if (nAng < _angSnap || nAng > PI - _angSnap) { return FALSE; } } return TRUE; } // 测试用 int XPolygonEx::Make(const TCHAR *szLay) { XPushVarStr clayer(_T("CLAYER"), szLay); XPushVar vOsMode(_T("OSMODE"), 0); SHads_command(RTSTR, _T(".PLINE"), RTNONE); for (int i = 0; i < Length(); i++) { SHads_command(RT3DPOINT, (*this)[i], RTNONE); } return SHads_command(RTSTR, _T("C"), RTNONE); } void XPolygonEx::Reverse() { XPoly::Reverse(); m_lstVisibleFlag.Reverse(); } double XPolygonEx::GetEdgeLength(int idx) const { const XPoint &pt = (*this)[idx]; //最后一点与第一个点求距离 if (idx == Length() - 1) { idx = -1; } const XPoint &ptNext = (*this)[idx + 1]; return pt.Distance(ptNext); } BOOL XPolygonEx::IsVisible(int idx) const { return (m_lstVisibleFlag[idx]); } void XPolygonEx::SetVisible(int idx, BOOL bVis) { *(m_lstVisibleFlag[idx]) = bVis; } XPoint XPolygonEx::GetVertex(int idx) const { return (*this)[idx]; } void XPolygonEx::AppendNode(const XPoint &pt, int nIndex/* = 1*/) { Append(new XPoint(pt)); m_lstVisibleFlag.Append(new int(nIndex)); } void XPolygonEx::Reset() { XPoly::Reset(); m_lstVisibleFlag.Reset(); } int XPolygonEx::SubTrianglize(DList &lstTris) { LAB_START: int nEdge = Length(); if (nEdge < 3) { return RTNORM; } // 消除长度为0的边 for (int i = 0; i < nEdge; i++) { if (GetEdgeLength(i) < _DIST_SNAP) { RemoveNode(i); nEdge--; i--; } } // 消除0和PI的顶点,可能没有必要 for (int i = 9; i < nEdge; i++) { if (nEdge < 3) { return RTNORM; } double nAng = GetAngle(i); if (fabs(nAng) < _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) < _angSnap) //消除0度的夹角,可能导致边长为0 { goto LAB_START; } } else if (fabs(nAng - PI) < _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) { int i = 0; int nVisFlag = SIDE1_INVISIBLE * (!IsVisible(i - 1)) + SIDE2_INVISIBLE * (!IsVisible(i)) + SIDE3_INVISIBLE * (!IsVisible(i + 1)); lstTris.Append(new XTriangle(GetVertex(i - 1), GetVertex(i), GetVertex(i + 1), nVisFlag)); Reset(); return RTNORM; } // 消除小于180的凸角 for (int i = 0; i < nEdge; i++) { double nAng = GetAngle(i); if (nAng < PI - _angSnap) { int nVisFlag = SIDE1_INVISIBLE * (!IsVisible(i - 1)) + SIDE2_INVISIBLE * (!IsVisible(i)) + SIDE3_INVISIBLE; XTriangle 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++) { XPoint 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的第三边有交点,且交点在线内 { XLine lnSect(tri.vertex3, tri.vertex1, LS_FINITE); XLine lnOut(ptTest, GetVertex(n + 1), LS_FINITE); XLine lnIn(GetVertex(n - 1), ptTest, LS_FINITE); XPoint ptInt1, ptInt2; BOOL bInt1 = (lnSect.Intersection(&lnOut, ptInt1) > 0); //比ads_inters更加可靠 if (bInt1) { if (lnSect.GetStartPoint().Distance2d(ptInt1) > _DIST_SNAP && lnSect.GetEndPoint().Distance2d(ptInt1) > _DIST_SNAP) { bAllow = FALSE; break; } } BOOL bInt2 = (lnSect.Intersection(&lnIn, ptInt2) > 0); //比ads_inters更加可靠 if (bInt2) { if (lnSect.GetStartPoint().Distance2d(ptInt2) > _DIST_SNAP && lnSect.GetEndPoint().Distance2d(ptInt2) > _DIST_SNAP) { bAllow = FALSE; break; } } } } if (bAllow) { lstTris.Append(new XTriangle(tri)); SetVisible(i - 1, FALSE); //必须在顶点移除前更改可见性,否则如果首点被移除导致序号的变化 RemoveNode(i); goto LAB_START; } } } #ifndef NDEBUG XGeLib::adsout << _T("\n警告:多边形三角化可能不合适, 还有") << Length() << _T("个边未三角化!"); Make(_T("1")); #endif return RTERROR; } int XPolygonEx::SubGetInsidePoint(XPoint &ptRet) { LAB_START: int nEdge = Length(); if (nEdge < 3) { return RTERROR; } // 消除长度为0的边 for (int i = 0; i < nEdge; i++) { if (GetEdgeLength(i) < _DIST_SNAP) { RemoveNode(i); nEdge--; i--; } } // 消除0和PI的顶点 for (int i = 0; i < nEdge; i++) { if (nEdge < 3) { return RTERROR; } double nAng = GetAngle(i); if (fabs(nAng) < _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) < _angSnap) //消除0度的夹角,可能导致边长为0 { goto LAB_START; } } else if (fabs(nAng - PI) < _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 (int 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; XLine ln(GetVertex(i), GetVertex(i + 2), LS_FINITE); //判断i+3到i-2是否的边是否有交点 for (int n = i + 3; n <= i - 2 + nEdge; n++) { XPoint ptInt; XLine 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) { XPoint pt1 = GetVertex(i); XPoint pt2 = GetVertex(i + 1); XPoint 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 (int i = nEdge - 1; i >= 0; i--) { double nAng = GetAngle(i); double nAngPrev = GetAngle(i - 1); if (nAng > nPi && nAngPrev < nPi) { BOOL bCanCut = TRUE; XLine ln(GetVertex(i), GetVertex(i - 2), LS_FINITE); //消i-1 //判断i+1到i-4边是否有交点 for (int n = i + 1; n <= i - 4 + nEdge; n++) { XPoint ptInt; XLine 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) { XPoint pt1 = GetVertex(i - 2); XPoint pt2 = GetVertex(i - 1); XPoint 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; } } } } XPoint pt1 = GetVertex(0); XPoint pt2 = GetVertex(1); XPoint 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 XPolygonEx::IsKindOf(XEntity::TEntityId entType) const { switch(entType) { case XEntity::eEntity: case XEntity::eCurve: case XEntity::ePoly: case XEntity::eShape: case XEntity::ePolygonEx: return true; } return false; } XEntity::TEntityId XPolygonEx::Type() const { return XEntity::ePolygonEx; }