Files
envi-code/SourceCode/Code2026/Dimension/GePolygonEx.cpp
T
2026-09-28 15:28:50 +08:00

824 lines
16 KiB
C++

#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<int>& 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<GeTriangle> &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<CString,true> clayer(_T("CLAYER"), szLay);
GlobalFunc::PushAcadVar<int> 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; i<iLen; ++i )
{
resTep = resTep->rbnext = 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<CString,true> clayer(_T("CLAYER"), szLay);
GlobalFunc::PushAcadVar<int> 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<GeTriangle> &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;
}