Files
envi-code/SourceCode/Code2026/tg_shs/shs_subgeLib/TGPLine2D.cpp
T
2026-09-28 15:28:50 +08:00

1956 lines
37 KiB
C++

//-------------------------------------------------------------------------------------------------------+
// Copyright (C), 1998-2007, Beijing Tangent Software Co. Ltd.
// = FileName : TGPLine2D 类
// = Version : ver2.0
// = Author : wlw
// = CreateDate : 2002-09-09
// = Description: TGPLine2D 定义
// = Maintainers:
//
//-------------------------------------------------------------------------------------------------------+
#include "StdAfx.h"
#include "TGPLine2D.h"
#include "TGPa.h"
#include "TPDList.h"
#include "TGPoint2D.h"
#include "TSPTable.h"
IMPLEMENT_RUN_TIME_CLASS1(TGPLine2D,"TGPLine2D",TGMLine2D)
bool TGPLine2D::IsValid() const
{
if (!TGMLine2D::IsValid())
{
return false;
}
for (long i=0;i<bulges.GetLength();i++)
{
if (UPEQUAL_ZEROA(bulges.GetAt(i)-PI2) || DOWNEQUAL_ZEROA(bulges.GetAt(i)+PI2))
{
return false;
}
}
return true;
}
TGPLine2D::TGPLine2D(long vertexNum,bool bClosed):TGMLine2D(vertexNum,bClosed)
{
bulges.Realloc(vertexNum);
bulges.SetAll(0);
}
TGPLine2D::TGPLine2D(const TArray<TGPoint>&vertexs,bool bClosed):TGMLine2D(vertexs,bClosed)
{
bulges.Realloc(vertexs.GetLength());
bulges.SetAll(0);
}
TGPLine2D::TGPLine2D(const TTable<TGPoint>&vertexs,bool bClosed):TGMLine2D(vertexs,bClosed)
{
bulges.Realloc(vertexs.GetLength());
bulges.SetAll(0);
}
TGPLine2D::TGPLine2D(const TArray<TGPoint>&vertexs,const TArray<double>&angles,bool bClosed):TGMLine2D(vertexs,bClosed),
bulges(angles)
{
}
TGPLine2D::TGPLine2D(const TTable<TGPoint>&vertexs,const TTable<double>&angles,bool bClosed):TGMLine2D(vertexs,bClosed),
bulges(angles)
{
}
TGPLine2D::TGPLine2D(const TGMLine2D&mLine):TGMLine2D(mLine)
{
bulges.Realloc(mLine.GetVertexNum());
bulges.SetAll(0);
}
TGPLine2D::TGPLine2D(const TPGeCircle2D&cir):TGMLine2D(2,true)
{
bulges.Realloc(2);
cir.Pa2Pt(0,(*this)[0]);
cir.Pa2Pt(PI,(*this)[1]);
if (cir.IsClockwise())
{
(*this)(0) = -PI;
(*this)(1) = -PI;
}
else
{
(*this)(0) = PI;
(*this)(1) = PI;
}
}
TGPLine2D::TGPLine2D(const TPGeArc2D&arc):TGMLine2D(2,false)
{
bulges.Realloc(2);
(*this)[0] = arc.GetStartPoint();
(*this)[1] = arc.GetEndPoint();
(*this)(0) = arc.IsClockwise()?-arc.centralAngle:arc.centralAngle;
(*this)(1) = 0;
}
TGPLine2D::~TGPLine2D()
{
}
double& TGPLine2D::operator ()(long i)
{
return bulges[i];
}
TGMLine2D* TGPLine2D::PLinearize(double paDist) const
{
return new TGPLine2D(*this);
}
TGObject * TGPLine2D::Clone() const
{
return new TGPLine2D(*this);
}
double TGPLine2D::GetBulge(long i) const
{
return bulges.GetAt(i);
}
bool TGPLine2D::IsArc(long i) const
{
return !EQUAL_ZEROA(bulges.GetAt(i));
}
void TGPLine2D::GetSegment(long i,TPGeLine2D& seg) const
{
TGMLine2D::GetSegment(i,seg);
}
bool TGPLine2D::IsArcExist() const
{
long num = GetSegNum();
for (long i = 0;i<num;i++)
{
if (IsArc(i))
{
return true;
}
}
return false;
}
void TGPLine2D::SetVertexNum(long num,bool bCopy)
{
points.Realloc(num,bCopy);
if (bCopy)
{
long oldNum = bulges.GetLength();
bulges.Realloc(num,true);
for (long i = oldNum;i<num;i++)
{
bulges[i] = 0;
}
}
else
{
bulges.Realloc(num,false);
bulges.SetAll(0);
}
}
bool TGPLine2D::RemoveDupPoint()
{
if (points.GetLength() < 2)
{
return false;
}
TList<TGPoint> ptList;
TList<double> aList;
ptList.AddTail(points.GetAt(0));
for (long i = 1;i<points.GetLength();i++)
{
if (ptList.GetCurData() != points.GetAt(i))
{
ptList.AddTail(points.GetAt(i));
aList.AddTail(bulges.GetAt(i-1));
}
}
aList.AddTail(bulges.GetAt(bulges.GetLastIndex()));
if (Is(CLOSED_CURVE) && ptList.GetLength()>1 && points.GetAt(0) == ptList.GetCurData())
{
ptList.DelCur();
aList.DelCur();
}
if (ptList.GetLength() < 2)
{
return false;
}
if (ptList.GetLength()<points.GetLength())
{
points = ptList;
bulges = aList;
}
return true;
}
bool TGPLine2D::IsSelfCross() const
{
long num = GetSegNum();
if (num < 2)
{
return false;
}
bool bClosed = IsClosed();
long num1 = num-1;;
for (long i = 0;i<num1;i++)
{
TGObjectList buf;
TPGeCurve2D *pSegi = GetSegment(i);
buf << pSegi;
for (long j = i+1;j<num;j++)
{
TPGeCurve2D *pSegj = GetSegment(j);
buf << pSegj;
TGObjectList oList;
if (pSegi->Intersect(*pSegj,oList))
{
if (oList[0]->GetClassID() != CID_GPoint2D)
{
return true;
}
else if (oList.GetLength() == 2)
{
if (!(num == 2 && bClosed))
{
return true;
}
}
else
{
if (j != i+1 && (i != 0 || j != num1 || !bClosed))
{
return true;
}
}
}
}
}
return false;
}
void TGPLine2D::Pa2Pt(double pa,TGPoint&pt) const
{
if (EQUAL_ZERO(pa))
{
GetStartPoint(pt);
}
else if (EQUAL_ZERO(pa-1))
{
GetEndPoint(pt);
}
else
{
long i = Pa2Seg(pa);
TPGeCurve2D* pSeg = GetSegment(i);
pSeg->Pa2Pt(pa,pt);
delete pSeg;
}
}
TPGeCurve2D* TGPLine2D::GetSubCurve(double pa0,double pa1) const
{
TList<TGPoint> ptList;
TList<double> paList;
TGPoint pt;
if (IsClosed())
{
if (EQUAL_ZERO(pa0-1))
{
pa0 = 0;
}
if (EQUAL_ZERO(pa1-1))
{
pa1 = 0;
}
}
if (UP_ZERO(pa1-pa0))
{
long iSeg0 = Pa2Seg(pa0),iSeg1 = Pa2Seg(pa1);
TPGeCurve2D *pSeg0 = GetSegment(iSeg0),*pSeg1 = GetSegment(iSeg1);
if (DOWN_ZERO(pa0-1))
{
pSeg0->Pa2Pt(pa0,pt);
ptList.AddTail(pt);
if (iSeg0 == iSeg1)
{
paList.AddTail(GetBulge(iSeg0)*(pa1-pa0));
}
else
{
paList.AddTail(GetBulge(iSeg0)*(1-pa0));
}
}
for (long i = iSeg0+1;i<iSeg1;i++)
{
ptList.AddTail(GetVertex(i));
paList.AddTail(GetBulge(i));
}
if (iSeg0 != iSeg1)
{
ptList.AddTail(GetVertex(iSeg1));
paList.AddTail(GetBulge(iSeg1)*pa1);
}
if (UP_ZERO(pa1))
{
pSeg1->Pa2Pt(pa1,pt);
ptList.AddTail(pt);
paList.AddTail(0);
}
delete pSeg0;
delete pSeg1;
return new TGPLine2D(ptList,paList,false);
}
else if (DOWN_ZERO(pa1-pa0))
{
long iSeg0 = Pa2Seg(pa0),iSeg1 = Pa2Seg(pa1);
TPGeCurve2D *pSeg0 = GetSegment(iSeg0),*pSeg1 = GetSegment(iSeg1);
if (DOWN_ZERO(pa0-1))
{
pSeg0->Pa2Pt(pa0,pt);
ptList.AddTail(pt);
paList.AddTail(GetBulge(iSeg0)*(1-pa0));
}
for (long i = iSeg0+1;i<GetVertexNum();i++)
{
ptList.AddTail(GetVertex(i));
paList.AddTail(GetBulge(i));
}
for (i = 0;i<iSeg1;i++)
{
ptList.AddTail(GetVertex(i));
paList.AddTail(GetBulge(i));
}
ptList.AddTail(GetVertex(iSeg1));
paList.AddTail(GetBulge(iSeg1)*pa1);
if (UP_ZERO(pa1))
{
pSeg1->Pa2Pt(pa1,pt);
ptList.AddTail(pt);
paList.AddTail(0);
}
delete pSeg0;
delete pSeg1;
return new TGPLine2D(ptList,paList,false);
}
else
{
long iSeg = Pa2Seg(pa0);
TPGeCurve2D* pSeg = GetSegment(iSeg);
if (DOWN_ZERO(pa0-1))
{
pSeg->Pa2Pt(pa0,pt);
ptList.AddTail(pt);
paList.AddTail(GetBulge(iSeg)*(1-pa0));
}
for (long i = iSeg+1;i<GetVertexNum();i++)
{
ptList.AddTail(GetVertex(i));
paList.AddTail(GetBulge(i));
}
for (i = 0;i<iSeg;i++)
{
ptList.AddTail(GetVertex(i));
paList.AddTail(GetBulge(i));
}
if (UP_ZERO(pa0))
{
ptList.AddTail(GetVertex(iSeg));
paList.AddTail(GetBulge(iSeg)*pa0);
}
delete pSeg;
return new TGPLine2D(ptList,paList,true);
}
}
void TGPLine2D::Pt2Pa(const TGPoint&pt,double&pa) const
{
pa = -1;
TGObjectList buf;
for (long i = 0;i<GetSegNum();i++)
{
TPGeCurve2D* pSeg = GetSegment(i);
buf << pSeg;
if (pSeg->HitTest(pt).Is(GR_IN))
{
pSeg->Pt2Pa(pt,pa);
pa = (pa+i)/GetSegNum();
break;
}
}
}
void TGPLine2D::GetTangent(double pa,TPGeLine2D&line) const
{
long i = Pa2Seg(pa);
if (IsArc(i))
{
TPGeArc2D aSeg;
GetSegment(i,aSeg);
aSeg.GetTangent(pa,line);
}
else
{
GetSegment(i,line);
line.Normalize();
}
}
void TGPLine2D::Reverse()
{
if (Is(CLOSED_CURVE))
{
points.Reverse(1);
bulges.Reverse();
}
else
{
points.Reverse();
if (bulges.GetLength()>2)
{
bulges.Reverse(0,bulges.GetLength()-2);
}
}
for (long i = 0;i<bulges.GetLength();i++)
{
bulges[i] = -(bulges[i]);
}
}
double TGPLine2D::Integration(double pa0,double pa1) const
{
double d = pa0-pa1;
if (DOWN_ZERO(d))
{
long seg0 = Pa2Seg(pa0),seg1 = Pa2Seg(pa1);
TPGeCurve2D*pSeg = GetSegment(seg0);
if (seg0 == seg1)
{
double r = pSeg->Integration(pa0,pa1);
delete pSeg;
return r;
}
double r = pSeg->Integration(pa0,1);
delete pSeg;
pSeg = GetSegment(seg1);
r += pSeg->Integration(0,pa1);
delete pSeg;
for (long i = seg0+1;i<seg1;i++)
{
pSeg = GetSegment(i);
r += pSeg->AllIntegration();
delete pSeg;
}
return r;
}
else if (UP_ZERO(d))
{
Exchange(pa0,pa1);
long seg0 = Pa2Seg(pa0),seg1 = Pa2Seg(pa1);
TPGeCurve2D*pSeg = GetSegment(seg0);
if (seg0 == seg1)
{
double r = pSeg->Integration(pa0,pa1);
delete pSeg;
return -r;
}
double r = pSeg->Integration(pa0,1);
delete pSeg;
pSeg = GetSegment(seg1);
r += pSeg->Integration(0,pa1);
delete pSeg;
for (long i = seg0+1;i<seg1;i++)
{
pSeg = GetSegment(i);
r += pSeg->AllIntegration();
delete pSeg;
}
return -r;
}
else
{
return 0;
}
}
bool TGPLine2D::GetExtend2D(TPGeExtend2D&ext) const
{
return TGObject2D::GetExtend2D(ext);
}
GRelation TGPLine2D::HitTest(const TGPoint&pt) const
{
if (IsClosed())
{
//modify by xlc on 101123 解决搜索房间求布尔运算错误的问题
//TPGeGLineRay2D ray(TGVector2D(1,0),pt);
TPGeGLineRay2D ray(TGVector2D(cos(0.005*PI),sin(0.005*PI)),pt);
bool bOutside = true;
long segNum = GetSegNum();
TPGeGLineSeg2D lSeg;
TPGeArc2D aSeg;
for (long i = 0;i<segNum;i++)
{
if (IsArc(i))
{
GetSegment(i,aSeg);
if (aSeg.HitTest(pt).Is(GR_IN))
{
return GR_IN;
}
TGObjectList oList;
if (aSeg.Intersect(ray,oList))
{
for (oList.MoveToFirst();!oList.IsOut();oList.MoveToNext())
{
const TGPoint2D &pt1 = (const TGPoint2D&)(oList.GetCurPData());
if (pt1 != pt)
{
if (pt1 != GetVertex(i))
{
if (pt1 != GetVertex((i+1)%segNum))
{
TGVector2D vt0(aSeg.circle.center,pt1),vt;
vt0.GetLVertVector(vt);
if (!vt.IsParallel(ray))
{
bOutside=!bOutside;
}
}
else
{
TPGeGLine2D tan;
aSeg.GetTangent(1,tan);
bool bLeft1,bLeft2;
if (UP_ZERO(tan.y))
{
bLeft1 = false;
}
else if (DOWN_ZERO(tan.y))
{
bLeft1 = true;
}
else
{
bLeft1 = aSeg.circle.center.y>pt.y;
}
int j = (i+1)%segNum;
while(true)
{
if (IsArc(j))
{
GetSegment(j,aSeg);
aSeg.GetTangent(0,tan);
if (UP_ZERO(tan.y))
{
bLeft2 = true;
}
else if (DOWN_ZERO(tan.y))
{
bLeft2 = false;
}
else
{
bLeft2 = aSeg.circle.center.y>pt.y;
}
break;
}
else
{
GetSegment(j,tan);
tan.Normalize();
if (EQUAL_ZERO(tan.y))
{
j = (j+1)%segNum;
}
else
{
bLeft2 = UP_ZERO(tan.y);
break;
}
}
}
if ((bLeft1 && !bLeft2) || (!bLeft1 && bLeft2))
{
bOutside = !bOutside;
}
}
}
}
else
{
return GR_IN;
}
}
}
}
else
{
GetSegment(i,lSeg);
if (lSeg.HitTest(pt).Is(GR_IN))
return GR_IN;
double pa1,pa2;
int iRet = ray.GetGeLine().Intersect(lSeg,pa1,pa2);
double dpa2 = pa2-1;
if (iRet == INT_1PT && UPEQUAL_ZERO(pa1) &&
UPEQUAL_ZERO(pa2) && DOWNEQUAL_ZERO(dpa2))
{
if (UP_ZERO(pa1))
{
if (UP_ZERO(pa2) && DOWN_ZERO(dpa2))
{
bOutside=!bOutside;
}
else if (EQUAL_ZERO(dpa2)) // 1E-9
// sg add 091109,替换为下面这句话,则可以解决某张图的搜索房间问题
// else if ((dpa2)>=-1E-10 && (dpa2)<=1E-10)
{
TPGeGLine2D tan;
bool bLeft1 = lSeg.GetStartPoint().y>pt.y,bLeft2;
int j = (i+1)%segNum;
while(true)
{
if (IsArc(j))
{
GetSegment(j,aSeg);
aSeg.GetTangent(0,tan);
if (UP_ZERO(tan.y))
{
bLeft2 = true;
}
else if (DOWN_ZERO(tan.y))
{
bLeft2 = false;
}
else
{
bLeft2 = aSeg.circle.center.y>pt.y;
}
break;
}
else
{
GetSegment(j,tan);
tan.Normalize();
if (EQUAL_ZERO(tan.y))
{
j = (j+1)%segNum;
}
else
{
bLeft2 = UP_ZERO(tan.y);
break;
}
}
}
if ((bLeft1 && !bLeft2) || (!bLeft1 && bLeft2))
{
bOutside = !bOutside;
}
}
}
else
{
return GR_IN;
}
}
else if (iRet == INT_LINE)
{
lSeg.Pt2Pa(pt,pa1);
if (UPEQUAL_ZERO(pa1) && DOWNEQUAL_ZERO(pa1-1))
{
return GR_IN;
}
}
}
}
return bOutside?GR_OUTSIDE:GR_INSIDE;
}
else
{
return TGObject::HitTest(pt);
}
}
void TGPLine2D::QuickCut(const TPGeGLine2D&line,TGObjectList&left,TGObjectList&right,TGObjectList&mid) const
{
long segNum = GetSegNum();
const TPGeLine2D &line0 = line;
TPGeGLine2D line1(line);
TPDList<TGPa> cutList;
double pa0,pa1;
TPGeGLineSeg2D lSeg;
TPGeArc2D aSeg;
GRelation r;
for (long i = 0;i<segNum;i++)
{
if (IsArc(i))
{
GetSegment(i,aSeg);
TGObjectList oList;
if (aSeg.Intersect(line1,oList))
{
for (oList.MoveToFirst();!oList.IsOut();oList.MoveToNext())
{
const TGPoint2D&pt = (const TGPoint2D&)(oList.GetCurPData());
if (pt == GetVertex(i))
{
long j = (i-1+segNum)%segNum;
bool bLeft0,bLeft1;
TPGeGLine2D tan;
if (IsArc(j))
{
TPGeArc2D aSeg0;
GetSegment(j,aSeg0);
aSeg0.GetTangent(1,tan);
double s = line0*tan;
if (UP_ZERO(s))
{
bLeft0 = false;
}
else if (DOWN_ZERO(s))
{
bLeft0 = true;
}
else
{
bLeft0 = line0.HitTest(aSeg0.circle.center).Is(GR_LEFT);
}
aSeg.GetTangent(0,tan);
s = line0*tan;
if (UP_ZERO(s))
{
bLeft1 = true;
}
else if (DOWN_ZERO(s))
{
bLeft1 = false;
}
else
{
bLeft1 = line0.HitTest(aSeg.circle.center).Is(GR_LEFT);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
line0.Pt2Pa(pt,pa0);
cutList << new TGPa(pa0);
}
}
else
{
r = line0.HitTest(GetVertex(j));
if (r.IsNot(GR_IN))
{
bLeft0 = r.Is(GR_LEFT);
aSeg.GetTangent(0,tan);
double s = line0*tan;
if (UP_ZERO(s))
{
bLeft1 = true;
}
else if (DOWN_ZERO(s))
{
bLeft1 = false;
}
else
{
bLeft1 = line0.HitTest(aSeg.circle.center).Is(GR_LEFT);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
line0.Pt2Pa(pt,pa0);
cutList << new TGPa(pa0);
}
}
}
}
else if (pt != GetVertex((i+1)%segNum))
{
TGVector2D tan;
TGVector2D(aSeg.circle.center,pt).GetLVertVector(tan);
if (!tan.IsParallel(line0))
{
line0.Pt2Pa(pt,pa0);
cutList << new TGPa(pa0);
}
}
}
}
}
else
{
GetSegment(i,lSeg);
int iRet = line0.Intersect(lSeg,pa0,pa1);
if (iRet == INT_1PT)
{
if (UP_ZERO(pa1) && DOWN_ZERO(pa1-1))
{
cutList << new TGPa(pa0);
}
else if (EQUAL_ZERO(pa1))
{
long j = (i-1+segNum)%segNum;
if (IsArc(j))
{
bool bLeft0,bLeft1 = line0.HitTest(lSeg.GetEndPoint()).Is(GR_LEFT);
GetSegment(j,aSeg);
TPGeGLine2D tan;
aSeg.GetTangent(1,tan);
double s = line0*tan;
if (UP_ZERO(s))
{
bLeft0 = false;
}
else if (DOWN_ZERO(s))
{
bLeft0 = true;
}
else
{
bLeft0 = line0.HitTest(aSeg.circle.center).Is(GR_LEFT);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0);
}
}
else
{
r = line0.HitTest(GetVertex(j));
if (r.IsNot(GR_IN))
{
bool bLeft0 = r.Is(GR_LEFT),bLeft1 = line0.HitTest(lSeg.GetEndPoint()).Is(GR_LEFT);
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0);
}
}
}
}
}
else if (iRet == INT_LINE)
{
long j = (i-1+segNum)%segNum;
bool bLeft0,bLeft1;
if (IsArc(j))
{
GetSegment(j,aSeg);
TPGeGLine2D tan;
aSeg.GetTangent(1,tan);
double s = line0*tan;
if (UP_ZERO(s))
{
bLeft0 = false;
}
else if (DOWN_ZERO(s))
{
bLeft0 = true;
}
else
{
bLeft0 = line0.HitTest(aSeg.circle.center).Is(GR_LEFT);
}
r.AddFlag(GR_IN);
for (j = (i+2)%segNum;r.Is(GR_IN);j = (j+1)%segNum)
{
r = line0.HitTest(GetVertex(j));
}
bLeft1 = r.Is(GR_LEFT);
line0.Pt2Pa(lSeg.GetStartPoint(),pa0);
line0.Pt2Pa(GetVertex((j-2+segNum)%segNum),pa1);
if (pa0>pa1)
{
Exchange(pa0,pa1);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0,MID_PT) << new TGPa(pa1);
}
else
{
cutList << new TGPa(pa0,MID_PT) << new TGPa(pa1,MID_PT);
}
}
else
{
r = line0.HitTest(GetVertex(j));
if (r.IsNot(GR_IN))
{
bLeft0 = r.Is(GR_LEFT),bLeft1;
r.AddFlag(GR_IN);
for (j = (i+2)%segNum;r.Is(GR_IN);j = (j+1)%segNum)
{
r = line0.HitTest(GetVertex(j));
}
bLeft1 = r.Is(GR_LEFT);
line0.Pt2Pa(lSeg.GetStartPoint(),pa0);
line0.Pt2Pa(GetVertex((j-2+segNum)%segNum),pa1);
if (pa0>pa1)
{
Exchange(pa0,pa1);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0,MID_PT) << new TGPa(pa1);
}
else
{
cutList << new TGPa(pa0,MID_PT) << new TGPa(pa1,MID_PT);
}
}
}
}
}
}
if (cutList.IsEmpty())
{
right << new TPGeGLine2D(line);
return;
}
cutList.Arrange();
bool bOut = true;
bool bMid = false;
TGPoint pt0,pt1;
cutList.MoveToFirst();
line0.Pa2Pt(cutList.GetCurPData().pa,pt0);
right << new TPGeGLineRay2D(TGVector2D(-line0),pt0);
if (cutList.GetCurPData().Is(MID_PT))
{
bMid = true;
}
else
{
bOut = false;
}
for (cutList.MoveToNext();!cutList.IsOut();cutList.MoveToNext())
{
const TGPa&pa = cutList.GetCurPData();
line0.Pa2Pt(pa.pa,pt1);
TPGeGLineSeg2D *pNewSeg = new TPGeGLineSeg2D(pt0,pt1);
if (bMid)
{
mid << pNewSeg;
}
else if (bOut)
{
right << pNewSeg;
}
else
{
left << pNewSeg;
}
pt0 = pt1;
if (pa.Is(MID_PT))
{
bMid = !bMid;
}
else
{
bOut = !bOut;
bMid = false;
}
}
right << new TPGeGLineRay2D(TGVector2D(line0),pt0);
}
void TGPLine2D::QuickCut(const TPGeGLineRay2D&line,TGObjectList&left,TGObjectList&right,TGObjectList&mid) const
{
long segNum = GetSegNum();
const TPGeLine2D &line0 = line;
TPGeGLine2D line1(line);
TPDList<TGPa> cutList;
double pa0,pa1;
TPGeGLineSeg2D lSeg;
TPGeArc2D aSeg;
GRelation r;
for (long i = 0;i<segNum;i++)
{
if (IsArc(i))
{
GetSegment(i,aSeg);
TGObjectList oList;
if (aSeg.Intersect(line1,oList))
{
for (oList.MoveToFirst();!oList.IsOut();oList.MoveToNext())
{
const TGPoint2D&pt = (const TGPoint2D&)(oList.GetCurPData());
if (pt == GetVertex(i))
{
long j = (i-1+segNum)%segNum;
bool bLeft0,bLeft1;
TPGeGLine2D tan;
if (IsArc(j))
{
TPGeArc2D aSeg0;
GetSegment(j,aSeg0);
aSeg0.GetTangent(1,tan);
double s = line0*tan;
if (UP_ZERO(s))
{
bLeft0 = false;
}
else if (DOWN_ZERO(s))
{
bLeft0 = true;
}
else
{
bLeft0 = line0.HitTest(aSeg0.circle.center).Is(GR_LEFT);
}
aSeg.GetTangent(0,tan);
s = line0*tan;
if (UP_ZERO(s))
{
bLeft1 = true;
}
else if (DOWN_ZERO(s))
{
bLeft1 = false;
}
else
{
bLeft1 = line0.HitTest(aSeg.circle.center).Is(GR_LEFT);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
line0.Pt2Pa(pt,pa0);
cutList << new TGPa(pa0);
}
}
else
{
r = line0.HitTest(GetVertex(j));
if (r.IsNot(GR_IN))
{
bLeft0 = r.Is(GR_LEFT);
aSeg.GetTangent(0,tan);
double s = line0*tan;
if (UP_ZERO(s))
{
bLeft1 = true;
}
else if (DOWN_ZERO(s))
{
bLeft1 = false;
}
else
{
bLeft1 = line0.HitTest(aSeg.circle.center).Is(GR_LEFT);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
line0.Pt2Pa(pt,pa0);
cutList << new TGPa(pa0);
}
}
}
}
else if (pt != GetVertex((i+1)%segNum))
{
TGVector2D tan;
TGVector2D(aSeg.circle.center,pt).GetLVertVector(tan);
if (!tan.IsParallel(line0))
{
line0.Pt2Pa(pt,pa0);
cutList << new TGPa(pa0);
}
}
}
}
}
else
{
GetSegment(i,lSeg);
int iRet = line0.Intersect(lSeg,pa0,pa1);
if (iRet == INT_1PT)
{
if (UP_ZERO(pa1) && DOWN_ZERO(pa1-1))
{
cutList << new TGPa(pa0);
}
else if (EQUAL_ZERO(pa1))
{
long j = (i-1+segNum)%segNum;
if (IsArc(j))
{
bool bLeft0,bLeft1 = line0.HitTest(lSeg.GetEndPoint()).Is(GR_LEFT);
GetSegment(j,aSeg);
TPGeGLine2D tan;
aSeg.GetTangent(1,tan);
double s = line0*tan;
if (UP_ZERO(s))
{
bLeft0 = false;
}
else if (DOWN_ZERO(s))
{
bLeft0 = true;
}
else
{
bLeft0 = line0.HitTest(aSeg.circle.center).Is(GR_LEFT);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0);
}
}
else
{
r = line0.HitTest(GetVertex(j));
if (r.IsNot(GR_IN))
{
bool bLeft0 = r.Is(GR_LEFT),bLeft1 = line0.HitTest(lSeg.GetEndPoint()).Is(GR_LEFT);
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0);
}
}
}
}
}
else if (iRet == INT_LINE)
{
long j = (i-1+segNum)%segNum;
bool bLeft0,bLeft1;
if (IsArc(j))
{
GetSegment(j,aSeg);
TPGeGLine2D tan;
aSeg.GetTangent(1,tan);
double s = line0*tan;
if (UP_ZERO(s))
{
bLeft0 = false;
}
else if (DOWN_ZERO(s))
{
bLeft0 = true;
}
else
{
bLeft0 = line0.HitTest(aSeg.circle.center).Is(GR_LEFT);
}
r.AddFlag(GR_IN);
for (j = (i+2)%segNum;r.Is(GR_IN);j = (j+1)%segNum)
{
r = line0.HitTest(GetVertex(j));
}
bLeft1 = r.Is(GR_LEFT);
line0.Pt2Pa(lSeg.GetStartPoint(),pa0);
line0.Pt2Pa(GetVertex((j-2+segNum)%segNum),pa1);
if (pa0>pa1)
{
Exchange(pa0,pa1);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0,MID_PT) << new TGPa(pa1);
}
else
{
cutList << new TGPa(pa0,MID_PT) << new TGPa(pa1,MID_PT);
}
}
else
{
r = line0.HitTest(GetVertex(j));
if (r.IsNot(GR_IN))
{
bLeft0 = r.Is(GR_LEFT),bLeft1;
r.AddFlag(GR_IN);
for (j = (i+2)%segNum;r.Is(GR_IN);j = (j+1)%segNum)
{
r = line0.HitTest(GetVertex(j));
}
bLeft1 = r.Is(GR_LEFT);
line0.Pt2Pa(lSeg.GetStartPoint(),pa0);
line0.Pt2Pa(GetVertex((j-2+segNum)%segNum),pa1);
if (pa0>pa1)
{
Exchange(pa0,pa1);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0,MID_PT) << new TGPa(pa1);
}
else
{
cutList << new TGPa(pa0,MID_PT) << new TGPa(pa1,MID_PT);
}
}
}
}
}
}
if (cutList.IsEmpty())
{
right << new TPGeGLineRay2D(line);
return;
}
cutList.Arrange();
bool bOut = true;
bool bMid = false;
for (cutList.MoveToFirst();!cutList.IsOut();cutList.MoveToNext())
{
const TGPa& pa = cutList.GetCurPData();
if (UP_ZERO(pa.pa))
{
break;
}
if (pa.Is(MID_PT))
{
bMid = !bMid;
}
else
{
bOut = !bOut;
bMid = false;
}
}
if (cutList.IsOut())
{
right << new TPGeGLineRay2D(line);
return;
}
TGPoint pt0(line0.basePoint),pt1;
for (;!cutList.IsOut();cutList.MoveToNext())
{
const TGPa&pa = cutList.GetCurPData();
line0.Pa2Pt(pa.pa,pt1);
TPGeGLineSeg2D *pNewSeg = new TPGeGLineSeg2D(pt0,pt1);
if (bMid)
{
mid << pNewSeg;
}
else if (bOut)
{
right << pNewSeg;
}
else
{
left << pNewSeg;
}
pt0 = pt1;
if (pa.Is(MID_PT))
{
bMid = !bMid;
}
else
{
bOut = !bOut;
bMid = false;
}
}
right << new TPGeGLineRay2D(TGVector2D(line0),pt0);
}
void TGPLine2D::QuickCut(const TPGeGLineSeg2D&line,TGObjectList&left,TGObjectList&right,TGObjectList&mid) const
{
long segNum = GetSegNum();
const TPGeLine2D &line0 = line;
TPGeGLine2D line1(line);
TPDList<TGPa> cutList;
double pa0,pa1;
TPGeGLineSeg2D lSeg;
TPGeArc2D aSeg;
GRelation r;
for (long i = 0;i<segNum;i++)
{
if (IsArc(i))
{
GetSegment(i,aSeg);
TGObjectList oList;
if (aSeg.Intersect(line1,oList))
for (oList.MoveToFirst();!oList.IsOut();oList.MoveToNext())
{
const TGPoint2D&pt = (const TGPoint2D&)(oList.GetCurPData());
if (pt == GetVertex(i))
{
long j = (i-1+segNum)%segNum;
bool bLeft0,bLeft1;
TPGeGLine2D tan;
if (IsArc(j))
{
TPGeArc2D aSeg0;
GetSegment(j,aSeg0);
aSeg0.GetTangent(1,tan);
double s = line0*tan;
if (UP_ZERO(s))
{
bLeft0 = false;
}
else if (DOWN_ZERO(s))
{
bLeft0 = true;
}
else
{
bLeft0 = line0.HitTest(aSeg0.circle.center).Is(GR_LEFT);
}
aSeg.GetTangent(0,tan);
s = line0*tan;
if (UP_ZERO(s))
{
bLeft1 = true;
}
else if (DOWN_ZERO(s))
{
bLeft1 = false;
}
else
{
bLeft1 = line0.HitTest(aSeg.circle.center).Is(GR_LEFT);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
line0.Pt2Pa(pt,pa0);
cutList << new TGPa(pa0);
}
}
else
{
r = line0.HitTest(GetVertex(j));
if (r.IsNot(GR_IN))
{
bLeft0 = r.Is(GR_LEFT);
aSeg.GetTangent(0,tan);
double s = line0*tan;
if (UP_ZERO(s))
{
bLeft1 = true;
}
else if (DOWN_ZERO(s))
{
bLeft1 = false;
}
else
{
bLeft1 = line0.HitTest(aSeg.circle.center).Is(GR_LEFT);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
line0.Pt2Pa(pt,pa0);
cutList << new TGPa(pa0);
}
}
}
}
else if (pt != GetVertex((i+1)%segNum))
{
TGVector2D tan;
TGVector2D(aSeg.circle.center,pt).GetLVertVector(tan);
if (!tan.IsParallel(line0))
{
line0.Pt2Pa(pt,pa0);
cutList << new TGPa(pa0);
}
}
}
}
else
{
GetSegment(i,lSeg);
int iRet = line0.Intersect(lSeg,pa0,pa1);
if (iRet == INT_1PT)
{
if (UP_ZERO(pa1) && DOWN_ZERO(pa1-1))
{
cutList << new TGPa(pa0);
}
else if (EQUAL_ZERO(pa1))
{
long j = (i-1+segNum)%segNum;
if (IsArc(j))
{
bool bLeft0,bLeft1 = line0.HitTest(lSeg.GetEndPoint()).Is(GR_LEFT);
GetSegment(j,aSeg);
TPGeGLine2D tan;
aSeg.GetTangent(1,tan);
double s = line0*tan;
if (UP_ZERO(s))
{
bLeft0 = false;
}
else if (DOWN_ZERO(s))
{
bLeft0 = true;
}
else
{
bLeft0 = line0.HitTest(aSeg.circle.center).Is(GR_LEFT);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0);
}
}
else
{
r = line0.HitTest(GetVertex(j));
if (r.IsNot(GR_IN))
{
bool bLeft0 = r.Is(GR_LEFT),bLeft1 = line0.HitTest(lSeg.GetEndPoint()).Is(GR_LEFT);
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0);
}
}
}
}
}
else if (iRet == INT_LINE)
{
long j = (i-1+segNum)%segNum;
bool bLeft0,bLeft1;
if (IsArc(j))
{
GetSegment(j,aSeg);
TPGeGLine2D tan;
aSeg.GetTangent(1,tan);
double s = line0*tan;
if (UP_ZERO(s))
{
bLeft0 = false;
}
else if (DOWN_ZERO(s))
{
bLeft0 = true;
}
else
{
bLeft0 = line0.HitTest(aSeg.circle.center).Is(GR_LEFT);
}
r.AddFlag(GR_IN);
for (j = (i+2)%segNum;r.Is(GR_IN);j = (j+1)%segNum)
{
r = line0.HitTest(GetVertex(j));
}
bLeft1 = r.Is(GR_LEFT);
line0.Pt2Pa(lSeg.GetStartPoint(),pa0);
line0.Pt2Pa(GetVertex((j-2+segNum)%segNum),pa1);
if (pa0>pa1)
{
Exchange(pa0,pa1);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0,MID_PT) << new TGPa(pa1);
}
else
{
cutList << new TGPa(pa0,MID_PT) << new TGPa(pa1,MID_PT);
}
}
else
{
r = line0.HitTest(GetVertex(j));
if (r.IsNot(GR_IN))
{
bLeft0 = r.Is(GR_LEFT),bLeft1;
r.AddFlag(GR_IN);
for (j = (i+2)%segNum;r.Is(GR_IN);j = (j+1)%segNum)
{
r = line0.HitTest(GetVertex(j));
}
bLeft1 = r.Is(GR_LEFT);
line0.Pt2Pa(lSeg.GetStartPoint(),pa0);
line0.Pt2Pa(GetVertex((j-2+segNum)%segNum),pa1);
if (pa0>pa1)
{
Exchange(pa0,pa1);
}
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0,MID_PT) << new TGPa(pa1);
}
else
{
cutList << new TGPa(pa0,MID_PT) << new TGPa(pa1,MID_PT);
}
}
}
}
}
}
if (cutList.IsEmpty())
{
right << new TPGeGLineSeg2D(line);
return;
}
cutList.Arrange();
bool bOut = true;
bool bMid = false;
for (cutList.MoveToFirst();!cutList.IsOut();cutList.MoveToNext())
{
const TGPa& pa = cutList.GetCurPData();
if (UP_ZERO(pa.pa))
{
break;
}
if (pa.Is(MID_PT))
{
bMid = !bMid;
}
else
{
bOut = !bOut;
bMid = false;
}
}
if (cutList.IsOut())
{
right << new TPGeGLineSeg2D(line);
return;
}
TGPoint pt0(line.GetStartPoint()),pt1;
TPGeGLineSeg2D *pNewSeg = NULL;
for (bool bContinue = true;bContinue && !cutList.IsOut();cutList.MoveToNext())
{
const TGPa&pa = cutList.GetCurPData();
if (UPEQUAL_ZERO(pa.pa-1))
{
pNewSeg = new TPGeGLineSeg2D(pt0,line.GetEndPoint());
bContinue = false;
}
else
{
line0.Pa2Pt(pa.pa,pt1);
pNewSeg = new TPGeGLineSeg2D(pt0,pt1);
}
if (bMid)
{
mid << pNewSeg;
}
else if (bOut)
{
right << pNewSeg;
}
else
{
left << pNewSeg;
}
pt0 = pt1;
if (pa.Is(MID_PT))
{
bMid = !bMid;
}
else
{
bOut = !bOut;
bMid = false;
}
}
if (bContinue)
{
right << new TPGeGLineSeg2D(pt0,line.GetEndPoint());
}
}
bool TGPLine2D::IsInclude(const TGObject&obj) const
{
switch(obj.GetClassID())
{
case CID_GArc2D:
case CID_GCircle2D:
return false;
default:
return TGMLine2D::IsInclude(obj);
}
}
bool TGPLine2D::Explode(TGObjectList&res) const
{
long num = GetSegNum();
for (long i = 0;i<num;i++)
{
res << GetSegment(i);
}
return true;
}
TGMLine2D* TGPLine2D::MLinearize(double paDist) const
{
bool bUseDefault = paDist<1E-9;
long num = GetSegNum();
TList<TGPoint> ptList;
long count = 0;
TPGeArc2D arc;
for (long i = 0;i<num;i++)
{
ptList[count++] = points.GetAt(i);
if (IsArc(i))
{
GetSegment(i,arc);
long num1;
if (bUseDefault)
{
num1 = (long)(1/arc.GetMLinePrec()+0.999999);
}
else
{
num1 = (long)(arc.centralAngle/paDist+0.999999);
}
if (num1<1)
{
continue;
}
double paDist1 = 1.0 / num1;
double pa = paDist1;
for (long j = 1; j < num1; j++,pa += paDist1)
{
arc.Pa2Pt(pa,ptList[count++]);
}
}
}
if (!IsClosed())
{
ptList[count] = points.GetAt(i);
}
return new TGMLine2D(ptList,IsClosed());
}
bool TGPLine2D::Offset(double offset)
{
TSPTable<TPGeCurve2D> curves(GetSegNum());
for (long i = 0;i<GetSegNum();i++)
{
if (IsArc(i))
{
TPGeArc2D arc;
GetSegment(i,arc);
if (!arc.Offset(offset))
return false;
curves.AddTail(arc.GetExtendCurve());
}
else
{
TPGeGLine2D *pLine = new TPGeGLine2D;
GetSegment(i,*pLine);
pLine->Offset(offset);
curves.AddTail(pLine);
}
}
TArray<TGPoint> newPt(GetVertexNum());
for (i = 1;i<curves.GetLength();i++)
{
TPGeCurve2D*pCurve0 = curves[i-1],*pCurve1 = curves[i];
TGObjectList buf;
if (pCurve0->Intersect(*pCurve1,buf))
{
TPGeCurve2D*pSeg = GetSegment(i);
pSeg->Offset(offset);
if (IS_CLASS(buf[0],TPGeCurve2D))
{
pSeg->GetStartPoint(newPt[i]);
}
else
{
TGPoint2D &pt0 = (TGPoint2D&)(*buf[0]);
if (buf.GetLength() == 1)
{
newPt[i] = pt0;
}
else
{
TGPoint2D &pt1 = (TGPoint2D&)(*buf[1]),pt2;
pSeg->GetStartPoint(pt2);
double nDist0 = pt2.Distance(pt0),nDist1 = pt2.Distance(pt1);
newPt[i] = nDist0<nDist1?pt0:pt1;
}
}
delete pSeg;
}
else
{
return false;
}
}
if (IsClosed())
{
TPGeCurve2D*pCurve0 = curves[i-1],*pCurve1 = curves[0];
TGObjectList buf;
if (pCurve0->Intersect(*pCurve1,buf))
{
TPGeCurve2D*pSeg = GetSegment(0);
pSeg->Offset(offset);
if (IS_CLASS(buf[0],TPGeCurve2D))
{
pSeg->GetStartPoint(newPt[0]);
}
else
{
TGPoint2D &pt0 = (TGPoint2D&)(*buf[0]);
if (buf.GetLength() == 1)
{
newPt[0] = pt0;
}
else
{
TGPoint2D &pt1 = (TGPoint2D&)(*buf[1]),pt2;
pSeg->GetStartPoint(pt2);
double nDist0 = pt2.Distance(pt0),nDist1 = pt2.Distance(pt1);
newPt[0] = nDist0<nDist1?pt0:pt1;
}
}
delete pSeg;
}
else
{
return false;
}
}
else
{
TPGeCurve2D *pSegFirst = GetSegment(0),*pSegLast = GetSegment(i-1);
pSegFirst->Offset(offset);
pSegLast->Offset(offset);
pSegFirst->GetStartPoint(newPt[0]);
pSegLast->GetEndPoint(newPt[newPt.GetLastIndex()]);
delete pSegFirst;
delete pSegLast;
}
points = newPt;
for (i = 0;i<GetSegNum();i++)
{
if (IsArc(i))
{
double pa0,pa1;
curves[i]->Pt2Pa(newPt[i],pa0);
curves[i]->Pt2Pa(newPt[(i+1)%GetVertexNum()],pa1);
bulges[i] = curves[i]->IsClockwise()?-ALEN(pa0,pa1):ALEN(pa0,pa1);
}
}
return true;
}
bool TGPLine2D::OffsetSeg(long iSeg,double offset)
{
TSPTable<TPGeCurve2D> curves(GetSegNum());
for (long i = 0;i<GetSegNum();i++)
{
if (IsArc(i))
{
TPGeArc2D arc;
GetSegment(i,arc);
if (i == iSeg && !arc.Offset(offset))
{
return false;
}
curves.AddTail(arc.GetExtendCurve());
}
else
{
TPGeGLine2D *pLine = new TPGeGLine2D;
GetSegment(i,*pLine);
if (i == iSeg)
{
pLine->Offset(offset);
}
curves.AddTail(pLine);
}
}
TArray<TGPoint> newPt(points);
for (i = 1;i<curves.GetLength();i++)
{
if (i != iSeg && i != iSeg+1)
{
continue;
}
TPGeCurve2D*pCurve0 = curves[i-1],*pCurve1 = curves[i];
TGObjectList buf;
if (pCurve0->Intersect(*pCurve1,buf))
{
TPGeCurve2D*pSeg = GetSegment(i);
if (IS_CLASS(buf[0],TPGeCurve2D))
{
pSeg->GetStartPoint(newPt[i]);
}
else
{
TGPoint2D &pt0 = (TGPoint2D&)(*buf[0]);
if (buf.GetLength() == 1)
{
newPt[i] = pt0;
}
else
{
TGPoint2D &pt1 = (TGPoint2D&)(*buf[1]),pt2;
pSeg->GetStartPoint(pt2);
double nDist0 = pt2.Distance(pt0),nDist1 = pt2.Distance(pt1);
newPt[i] = nDist0<nDist1?pt0:pt1;
}
}
delete pSeg;
}
else
{
return false;
}
}
if (IsClosed())
{
if (iSeg == 0 || iSeg == i-1)
{
TPGeCurve2D*pCurve0 = curves[i-1],*pCurve1 = curves[0];
TGObjectList buf;
if (pCurve0->Intersect(*pCurve1,buf))
{
TPGeCurve2D*pSeg = GetSegment(0);
if (IS_CLASS(buf[0],TPGeCurve2D))
{
pSeg->GetStartPoint(newPt[0]);
}
else
{
TGPoint2D &pt0 = (TGPoint2D&)(*buf[0]);
if (buf.GetLength() == 1)
{
newPt[0] = pt0;
}
else
{
TGPoint2D &pt1 = (TGPoint2D&)(*buf[1]),pt2;
pSeg->GetStartPoint(pt2);
double nDist0 = pt2.Distance(pt0),nDist1 = pt2.Distance(pt1);
newPt[0] = nDist0<nDist1?pt0:pt1;
}
}
delete pSeg;
}
else
{
return false;
}
}
}
else if (iSeg == 0)
{
TPGeCurve2D *pSegFirst = GetSegment(0);
pSegFirst->Offset(offset);
pSegFirst->GetStartPoint(newPt[0]);
delete pSegFirst;
}
else if (iSeg == i-1)
{
TPGeCurve2D *pSegLast=GetSegment(i-1);
pSegLast->Offset(offset);
pSegLast->GetEndPoint(newPt[newPt.GetLastIndex()]);
delete pSegLast;
}
points = newPt;
for (i = 0;i<GetSegNum();i++)
{
if (IsArc(i))
{
double pa0,pa1;
curves[i]->Pt2Pa(newPt[i],pa0);
curves[i]->Pt2Pa(newPt[(i+1)%GetVertexNum()],pa1);
bulges[i] = curves[i]->IsClockwise()?-ALEN(pa0,pa1):ALEN(pa0,pa1);
}
}
return true;
}
void TGPLine2D::SetClosed(bool bClosed,double angle)
{
if (bulges.GetLength() < 1 || bulges.GetLastIndex() < 0 || bulges.GetLastIndex() >= bulges.GetLength())
{
return;
}
if(bClosed)
{
AddFlag(CLOSED_CURVE);
bulges[bulges.GetLastIndex()]=angle;
}
else
{
RemoveFlag(CLOSED_CURVE);
bulges[bulges.GetLastIndex()]=0;
}
}