Files
envi-code/SourceCode/Code2026/AdsXRx/XPolygonEx.cpp
T
gjm 164968b62e chore
把非utf8-bom编码的cpp/h文件改为 utf8 bom 编码, msvc识别utf8编码时,如果不是bom格式的,会使用当前cp_oem来解码.
2026-10-04 00:04:20 +08:00

787 lines
15 KiB
C++

//-----------------------------------------------------------------------------+
// 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<int>& 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<XTriangle> &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<int> 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<XTriangle> &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;
}