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

1573 lines
29 KiB
C++

//-------------------------------------------------------------------------------------------------------+
// Copyright (C), 1998-2007, Beijing Tangent Software Co. Ltd.
// = FileName : TGMLine2D Àà
// = Version : ver2.0
// = Author : wlw
// = CreateDate : 2002-09-09
// = Description: TGMLine2D ¶¨Òå
// = Maintainers:
//
//-------------------------------------------------------------------------------------------------------+
#include "StdAfx.h"
#include "TGMLine2D.h"
#include "TGMatrix.h"
#include "TPGeGLineSeg2D.h"
#include "TGPa.h"
#include "TGPtPa.h"
#include "TPDList.h"
#include "TGPoint2D.h"
IMPLEMENT_RUN_TIME_CLASS1(TGMLine2D,"TGMLine2D",TPGeCurve2D)
TGMLine2D::TGMLine2D(long vertexNum,bool bClosed)
: points(vertexNum)
{
if (bClosed)
{
AddFlag(CLOSED_CURVE);
}
}
TGMLine2D::TGMLine2D(const TTable<TGPoint>&vertexs,bool bClosed):points(vertexs)
{
if (bClosed)
{
AddFlag(CLOSED_CURVE);
}
}
TGMLine2D::TGMLine2D(const TArray<TGPoint>&vertexs,bool bClosed):points(vertexs)
{
if (bClosed)
{
AddFlag(CLOSED_CURVE);
}
}
TGMLine2D::~TGMLine2D()
{
}
TGMLine2D& TGMLine2D::operator = (const TArray<TGPoint>&vertexs)
{
SetVertexNum(vertexs.GetLength());
points = vertexs;
return *this;
}
TGMLine2D& TGMLine2D::operator = (const TTable<TGPoint>&vertexs)
{
SetVertexNum(vertexs.GetLength());
points = vertexs;
return *this;
}
TGPoint& TGMLine2D::operator[](long i)
{
return points[i];
}
void TGMLine2D::SetClosed(bool bClosed/*=true*/)
{
if (bClosed)
{
AddFlag(CLOSED_CURVE);
}
else
{
RemoveFlag(CLOSED_CURVE);
}
}
void TGMLine2D::SetVertexNum(long num,bool bCopy/*=false*/)
{
points.Realloc(num,bCopy);
}
long TGMLine2D::GetVertexNum() const
{
return points.GetLength();
}
const TGPoint& TGMLine2D::GetVertex(long i) const
{
return points.GetAt(i);
}
bool TGMLine2D::IsClosed() const
{
return Is(CLOSED_CURVE);
}
TGMLine2D* TGMLine2D::MLinearize(double paDist/*=0*/) const
{
return new TGMLine2D(*this);
}
TGPoint TGMLine2D::GetSamplePoint() const
{
TGPoint pt;
Pa2Pt(0.5 / GetSegNum(), pt);
return pt;
}
double TGMLine2D::GetElev() const
{
return points.GetAt(0).z;
}
TGObject * TGMLine2D::Clone() const
{
return new TGMLine2D(*this);
}
void TGMLine2D::GetStartPoint(TGPoint&pt) const
{
if (points.IsEmpty())
{
return;
}
pt = points.GetAt(0);
}
void TGMLine2D::GetEndPoint(TGPoint&pt) const
{
if (IsClosed())
{
GetStartPoint(pt);
return;
}
if (points.IsEmpty())
{
return;
}
pt = points.GetAt(points.GetLastIndex());
}
bool TGMLine2D::IsConcave() const
{
if (points.GetLength() <= 3)
{
return false;
}
TGVector2D vt1(points.GetAt(points.GetLastIndex()),points.GetAt(0));
bool bUp = false,bDown = false;
for (long i = 0;i < points.GetLength();i++)
{
TGVector2D vt2(points.GetAt(i), points.GetAt((i + 1) % points.GetLength()));
double temp = vt1 * vt2;
if (DOWN_ZERO(temp))
{
bDown = true;
}
else if (UP_ZERO(temp))
{
bUp = true;
}
if (bUp && bDown)
{
return true;
}
vt1 = vt2;
}
return false;
}
bool TGMLine2D::IsSelfCross() const
{
long num = GetSegNum();
if (num < 2)
{
return false;
}
TGObjectList oList;
TPGeGLineSeg2D iSeg,jSeg;
long num1 = num - 1;
for (long i = 0;i < num1;i++)
{
GetSegment(i,iSeg);
for (long j = i + 1; j < num;j++)
{
GetSegment(j,jSeg);
if (iSeg.Intersect(jSeg,oList))
{
if (oList[0]->GetClassID() == CID_GLineSeg2D)
{
return true;
}
else
{
if (j == (i+1) || (i == 0 && j == num1 && IsClosed()))
{
oList.Clear();
}
else
{
return true;
}
}
}
}
}
return false;
}
bool TGMLine2D::IsLinear() const
{
if (points.GetLength() <= 2)
{
return true;
}
const TGPoint &pt0 = points.GetAt(0);
for (long i = 1;i < points.GetLength() && pt0 == points.GetAt(i);i++);
TGVector2D vt1(pt0,points.GetAt(i));
for (i += 1;i < points.GetLength();i++)
{
TGVector2D vt2(pt0,points.GetAt(i));
double temp = vt1 * vt2;
if (!EQUAL_ZERO(temp))
{
return false;
}
}
return true;
}
long TGMLine2D::Pa2Seg(double&pa) const
{
pa *= GetSegNum();
long i = (long)pa;
if (i < 0)
{
i = 0;
}
else if (i >= GetSegNum())
{
i = GetSegNum() - 1;
}
pa -= i;
return i;
}
TPGeCurve2D* TGMLine2D::GetSubCurve(double pa0,double pa1) const
{
TList<TGPoint> ptList;
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);
TPGeGLineSeg2D seg0,seg1;
GetSegment(iSeg0,seg0);
GetSegment(iSeg1,seg1);
if (DOWN_ZERO(pa0 - 1))
{
seg0.Pa2Pt(pa0,pt);
ptList.AddTail(pt);
}
long iSeg2 = iSeg1 + 1;
for (long i = iSeg0 + 1; i < iSeg2; i++)
{
ptList.AddTail(GetVertex(i));
}
if (UP_ZERO(pa1))
{
seg1.Pa2Pt(pa1,pt);
ptList.AddTail(pt);
}
return new TGMLine2D(ptList,false);
}
else if (DOWN_ZERO(pa1 - pa0))
{
long iSeg0 = Pa2Seg(pa0),iSeg1 = Pa2Seg(pa1);
TPGeGLineSeg2D seg0,seg1;
GetSegment(iSeg0,seg0);
GetSegment(iSeg1,seg1);
if (DOWN_ZERO(pa0 - 1))
{
seg0.Pa2Pt(pa0,pt);
ptList.AddTail(pt);
}
for (long i = iSeg0 + 1;i < GetVertexNum();i++)
{
ptList.AddTail(GetVertex(i));
}
long iSeg2 = iSeg1 + 1;
for (i = 0; i < iSeg2; i++)
{
ptList.AddTail(GetVertex(i));
}
if (UP_ZERO(pa1))
{
seg1.Pa2Pt(pa1,pt);
ptList.AddTail(pt);
}
return new TGMLine2D(ptList,false);
}
else
{
long iSeg = Pa2Seg(pa0);
TPGeGLineSeg2D seg;
GetSegment(iSeg,seg);
if (DOWN_ZERO(pa0 - 1))
{
seg.Pa2Pt(pa0,pt);
ptList.AddTail(pt);
}
for (long i = iSeg + 1;i < GetVertexNum();i++)
{
ptList.AddTail(GetVertex(i));
}
for (i = 0;i < iSeg;i++)
{
ptList.AddTail(GetVertex(i));
}
if (UP_ZERO(pa0))
{
ptList.AddTail(seg.GetStartPoint());
}
return new TGMLine2D(ptList,true);
}
}
void TGMLine2D::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);
TPGeGLineSeg2D seg;
GetSegment(i,seg);
seg.Pa2Pt(pa,pt);
}
}
void TGMLine2D::Pt2Pa(const TGPoint&pt,double&pa) const
{
TPGeGLineSeg2D seg;
long num = GetSegNum();
pa = -1;
for (long i = 0;i < num;i++)
{
GetSegment(i,seg);
if (seg.HitTest(pt).Is(GR_IN))
{
seg.Pt2Pa(pt,pa);
pa = (pa + i) / num;
break;
}
}
}
void TGMLine2D::GetTangent(double pa,TPGeLine2D&line) const
{
GetSegment(Pa2Seg(pa),line);
line.Normalize();
}
void TGMLine2D::Reverse()
{
if (Is(CLOSED_CURVE))
{
points.Reverse(1);
}
else
{
points.Reverse();
}
}
double TGMLine2D::Integration(double pa0,double pa1) const
{
double d = pa0-pa1;
if (DOWN_ZERO(d))
{
long seg0 = Pa2Seg(pa0),seg1 = Pa2Seg(pa1);
TPGeGLineSeg2D seg;
GetSegment(seg0,seg);
if (seg0 == seg1)
{
return seg.Integration(pa0,pa1);
}
double r = seg.Integration(pa0,1);
GetSegment(seg1,seg);
r += seg.Integration(0,pa1);
for (long i = seg0 + 1; i < seg1; i++)
{
GetSegment(i,seg);
r += seg.AllIntegration();
}
return r;
}
else if (UP_ZERO(d))
{
Exchange(pa0,pa1);
long seg0 = Pa2Seg(pa0),seg1 = Pa2Seg(pa1);
TPGeGLineSeg2D seg;
GetSegment(seg0,seg);
if (seg0 == seg1)
{
return -seg.Integration(pa0,pa1);
}
double r = seg.Integration(pa0,1);
GetSegment(seg1,seg);
r += seg.Integration(0,pa1);
for (long i = seg0 + 1; i < seg1; i++)
{
GetSegment(i,seg);
r += seg.AllIntegration();
}
return -r;
}
else
{
return 0;
}
}
double TGMLine2D::Length() const
{
double len = 0;
long last = points.GetLastIndex();
for (long i = 0;i < last; i++)
{
len += Distance2D(points.GetAt(i),points.GetAt(i + 1));
}
if (Is(CLOSED_CURVE))
{
len += Distance2D(points.GetAt(last),points.GetAt(0));
}
return len;
}
void TGMLine2D::SetElev(double elev)
{
for (long i = 0;i < points.GetLength();i++)
{
points[i].z = elev;
}
}
bool TGMLine2D::GetExtend2D(TPGeExtend2D&ext) const
{
const TGPoint &pt0 = points.GetAt(0);
ext.SetRange(pt0.x,pt0.x,pt0.y,pt0.y);
for (long i = 1; i < points.GetLength(); i++)
{
const TGPoint &pt = points.GetAt(i);
ext += TPGeExtend2D(pt.x,pt.x,pt.y,pt.y);
}
return true;
}
GRelation TGMLine2D::HitTest(const TGPoint&pt) const
{
if (IsClosed())
{
TPGeLine2D ray(TGVector2D(1,0),pt);
bool bOutside = true;
long segNum = GetSegNum();
TPGeGLineSeg2D seg;
double pa1,pa2;
for (long i = 0;i < segNum;i++)
{
GetSegment(i,seg);
if (seg.HitTest(pt).Is(GR_IN))
{
return GR_IN;
}
int iRet = ray.Intersect(seg,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))
{
int j = (i + 1) % segNum;
while(EQUAL_ZEROD(GetVertex(j).y-pt.y))
{
j = (j + 1) % segNum;
}
const TGPoint& pt0 = seg.GetStartPoint(), &pt1 = GetVertex(j);
if ((pt0.y > pt.y && pt1.y < pt.y) || (pt0.y < pt.y && pt1.y > pt.y))
{
bOutside = !bOutside;
}
}
}
else
{
return GR_IN;
}
}
else if (iRet == INT_LINE)
{
seg.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 TGMLine2D::QuickCut(const TPGeGLine2D&line,TGObjectList&left,TGObjectList&right,TGObjectList&mid) const
{
long segNum = GetSegNum();
const TPGeLine2D &line0 = line;
TPDList<TGPa> cutList;
double pa0,pa1;
TPGeGLineSeg2D seg;
GRelation r;
for (long i = 0;i < segNum;i++)
{
GetSegment(i,seg);
int iRet = line0.Intersect(seg,pa0,pa1);
if (iRet == INT_1PT)
{
if (UP_ZERO(pa1) && DOWN_ZERO(pa1 - 1))
{
cutList << new TGPa(pa0);
}
else if (EQUAL_ZERO(pa1))
{
r = line0.HitTest(GetVertex((i - 1 + segNum) % segNum));
if (r.IsNot(GR_IN))
{
bool bLeft0 = r.Is(GR_LEFT),bLeft1 = line0.HitTest(seg.GetEndPoint()).Is(GR_LEFT);
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0);
}
}
}
}
else if (iRet == INT_LINE)
{
r = line0.HitTest(GetVertex((i - 1 + segNum) % segNum));
if (r.IsNot(GR_IN))
{
bool bLeft0 = r.Is(GR_LEFT),bLeft1;
r.AddFlag(GR_IN);
for (long j = (i + 2) % segNum; r.Is(GR_IN); j = (j + 1) % segNum)
{
r = line0.HitTest(GetVertex(j));
}
bLeft1 = r.Is(GR_LEFT);
line0.Pt2Pa(seg.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 TGMLine2D::QuickCut(const TPGeGLineRay2D&line,TGObjectList&left,TGObjectList&right,TGObjectList&mid) const
{
long segNum = GetSegNum();
const TPGeLine2D &line0 = line;
TPDList<TGPa> cutList;
double pa0,pa1;
TPGeGLineSeg2D seg;
GRelation r;
for (long i = 0;i < segNum;i++)
{
GetSegment(i,seg);
int iRet = line0.Intersect(seg,pa0,pa1);
if (iRet == INT_1PT)
{
if (UP_ZERO(pa1) && DOWN_ZERO(pa1 - 1))
{
cutList << new TGPa(pa0);
}
else if (EQUAL_ZERO(pa1))
{
r = line0.HitTest(GetVertex((i - 1 + segNum) % segNum));
if (r.IsNot(GR_IN))
{
bool bLeft0 = r.Is(GR_LEFT),bLeft1 = line0.HitTest(seg.GetEndPoint()).Is(GR_LEFT);
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0);
}
}
}
}
else if (iRet == INT_LINE)
{
r = line0.HitTest(GetVertex((i-1+segNum)%segNum));
if (r.IsNot(GR_IN))
{
bool bLeft0 = r.Is(GR_LEFT),bLeft1;
r.AddFlag(GR_IN);
for (long j = (i + 2) % segNum; r.Is(GR_IN); j = (j + 1) % segNum)
{
r = line0.HitTest(GetVertex(j));
}
bLeft1 = r.Is(GR_LEFT);
line0.Pt2Pa(seg.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 TGMLine2D::QuickCut(const TPGeGLineSeg2D&line,TGObjectList&left,TGObjectList&right,TGObjectList&mid) const
{
long segNum = GetSegNum();
const TPGeLine2D &line0 = line;
TPDList<TGPa> cutList;
double pa0,pa1;
TPGeGLineSeg2D seg;
GRelation r;
for (long i = 0;i < segNum;i++)
{
GetSegment(i,seg);
int iRet = line0.Intersect(seg,pa0,pa1);
if (iRet == INT_1PT)
{
if (UP_ZERO(pa1) && DOWN_ZERO(pa1 - 1))
{
cutList << new TGPa(pa0);
}
else if (EQUAL_ZERO(pa1))
{
r = line0.HitTest(GetVertex((i - 1 + segNum) % segNum));
if (r.IsNot(GR_IN))
{
bool bLeft0 = r.Is(GR_LEFT),bLeft1 = line0.HitTest(seg.GetEndPoint()).Is(GR_LEFT);
if ((bLeft0 && !bLeft1) || (!bLeft0 && bLeft1))
{
cutList << new TGPa(pa0);
}
}
}
}
else if (iRet == INT_LINE)
{
r = line0.HitTest(GetVertex((i - 1 + segNum) % segNum));
if (r.IsNot(GR_IN))
{
bool bLeft0 = r.Is(GR_LEFT),bLeft1;
r.AddFlag(GR_IN);
for (long j = (i + 2) % segNum; r.Is(GR_IN); j = (j + 1) % segNum)
{
r = line0.HitTest(GetVertex(j));
}
bLeft1 = r.Is(GR_LEFT);
line0.Pt2Pa(seg.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());
}
}
void TGMLine2D::QuickCut(const TPGeCircle2D&circle,TGObjectList&left,TGObjectList&right) const
{
TPDList<TGPtPa> cutList;
TGObjectList oList;
double pa[2],cpa;
TGPoint pt;
long segNum = GetSegNum();
TPGeLine2D seg;
for (long i = 0; i < segNum; i++)
{
GetSegment(i,seg);
int iRet = seg.Intersect(&circle,pa[0],pa[1]);
if (iRet == INT_2PT)
{
for (int j = 0; j < 2; j++)
{
double dpa = pa[j] - 1;
if (UP_ZERO(pa[j]) && DOWN_ZERO(dpa))
{
seg.Pa2Pt(pa[j],pt);
circle.Pt2Pa(pt,cpa);
cutList << new TGPtPa(pt,cpa);
}
else if (EQUAL_ZERO(dpa))
{
seg.Pa2Pt(1,pt);
TGVector2D vt;
TGVector2D(circle.center,pt).GetLVertVector(vt);
TPGeLine2D line(vt,pt);
bool bLeft1 = line.HitTest(GetVertex(i)).Is(GR_LEFT);
bool bLeft2 = line.HitTest(GetVertex((i + 2) % segNum)).Is(GR_LEFT);
if ((bLeft1 && !bLeft2) || (!bLeft1 && bLeft2))
{
circle.Pt2Pa(pt,cpa);
cutList << new TGPtPa(pt,cpa);
}
}
}
}
else if (iRet == INT_1PT)
{
double dpa = pa[0] - 1;
if (EQUAL_ZERO(dpa))
{
seg.Pa2Pt(1,pt);
TGVector2D vt;
TGVector2D(circle.center,pt).GetLVertVector(vt);
TPGeLine2D line(vt,pt);
if (line.HitTest(GetVertex((i + 2) % segNum)).Is(GR_LEFT))
{
circle.Pt2Pa(pt,cpa);
cutList << new TGPtPa(pt,cpa);
}
}
}
}
if (cutList.IsEmpty())
{
if (HitTest(circle.center).Is(GR_INSIDE))
{
for (long i = 0;i < segNum;i++)
{
GRelation r = circle.HitTest(GetVertex(i));
if (r.Is(GR_OUTSIDE))
{
left << new TPGeCircle2D(circle);
}
else if (r.Is(GR_INSIDE))
{
right << new TPGeCircle2D(circle);
}
else
{
continue;
}
return;
}
}
right << new TPGeCircle2D(circle);
return;
}
cutList.Arrange();
GRelation r = GR_IN;
double pa0 = cutList(cutList.GetLastIndex()).pa;
double aLen = ALEN(pa0,cutList(0).pa);
for (i = 2; i < 100000 && r.Is(GR_IN); i++)
{
circle.Pa2Pt(pa0 + aLen / i, pt);
r = HitTest(pt);
}
bool bOut = r.Is(GR_OUTSIDE);
cutList.MoveToFirst();
pa0 = cutList.GetCurPData().pa;
bOut = !bOut;
bool bUnclock = !circle.IsClockwise();
for (cutList.MoveToNext();!cutList.IsOut();cutList.MoveToNext())
{
double pa1 = cutList.GetCurPData().pa;
if (bOut)
{
right << new TPGeArc2D(circle.center, circle.r, pa0, pa1 - pa0, bUnclock);
}
else
{
left << new TPGeArc2D(circle.center, circle.r, pa0, pa1 - pa0, bUnclock);
}
pa0 = pa1;
bOut = !bOut;
}
cutList.MoveToFirst();
double pa1 = cutList.GetCurPData().pa;
if (bOut)
{
right << new TPGeArc2D(circle.center, circle.r, pa0, ALEN(pa0,pa1), bUnclock);
}
else
{
left << new TPGeArc2D(circle.center, circle.r, pa0, ALEN(pa0,pa1), bUnclock);
}
}
void TGMLine2D::QuickCut(const TPGeArc2D&arc,TGObjectList&left,TGObjectList&right) const
{
TPDList<TGPtPa> cutList;
TGObjectList oList;
double pa[2],cpa;
TGPoint pt;
long segNum = GetSegNum();
TPGeLine2D seg;
const TPGeCircle2D &circle = arc.circle;
for (long i = 0;i < segNum;i++)
{
GetSegment(i,seg);
int iRet = seg.Intersect(&circle,pa[0],pa[1]);
if (iRet == INT_2PT)
{
for (int j = 0;j < 2;j++)
{
double dpa = pa[j] - 1;
if (UP_ZERO(pa[j]) && DOWN_ZERO(dpa))
{
seg.Pa2Pt(pa[j],pt);
arc.Pt2Pa(pt,cpa);
cutList << new TGPtPa(pt,cpa);
}
else if (EQUAL_ZERO(dpa))
{
seg.Pa2Pt(1,pt);
TGVector2D vt;
TGVector2D(circle.center,pt).GetLVertVector(vt);
TPGeLine2D line(vt,pt);
bool bLeft1 = line.HitTest(GetVertex(i)).Is(GR_LEFT);
bool bLeft2 = line.HitTest(GetVertex((i + 2) % segNum)).Is(GR_LEFT);
if ((bLeft1 && !bLeft2) || (!bLeft1 && bLeft2))
{
arc.Pt2Pa(pt,cpa);
cutList << new TGPtPa(pt,cpa);
}
}
}
}
else if (iRet == INT_1PT)
{
double dpa = pa[0] - 1;
if (EQUAL_ZERO(dpa))
{
seg.Pa2Pt(1,pt);
TGVector2D vt;
TGVector2D(circle.center,pt).GetLVertVector(vt);
TPGeLine2D line(vt,pt);
if (line.HitTest(GetVertex((i + 2) % segNum)).Is(GR_LEFT))
{
arc.Pt2Pa(pt,cpa);
cutList << new TGPtPa(pt,cpa);
}
}
}
}
if (cutList.IsEmpty())
{
if (HitTest(circle.center).Is(GR_INSIDE))
{
for (long i = 0;i < segNum;i++)
{
GRelation r = circle.HitTest(GetVertex(i));
if (r.Is(GR_OUTSIDE))
{
left << new TPGeArc2D(arc);
}
else if (r.Is(GR_INSIDE))
{
right << new TPGeArc2D(arc);
}
else
{
continue;
}
return;
}
}
right << new TPGeArc2D(arc);
return;
}
cutList.Arrange();
GRelation r = GR_IN;
double pa0 = cutList(cutList.GetLastIndex()).pa;
double aLen = pa0-cutList(0).pa;
for (i = 2;i < 100000 && r.Is(GR_IN);i++)
{
arc.Pa2Pt(pa0 + aLen / i, pt);
r = HitTest(pt);
}
bool bOut = r.Is(GR_OUTSIDE);
bool bUnclock = !circle.IsClockwise();
pa0 = 0;
cutList.MoveToFirst();
double pa1 = cutList.GetCurPData().pa;
if (EQUAL_ZERO(pa1))
{
bOut = !bOut;
cutList.MoveToNext();
}
for (bool bContinue = true;bContinue && !cutList.IsOut();cutList.MoveToNext())
{
pa1 = cutList.GetCurPData().pa;
if (UPEQUAL_ZERO(pa1-1))
{
pa1 = 1;
bContinue = false;
}
if (bOut)
{
right << new TPGeArc2D(circle.center, circle.r, NA(arc.startAngle + pa0 * arc.centralAngle),
(pa1 - pa0) * arc.centralAngle, bUnclock);
}
else
{
left << new TPGeArc2D(circle.center, circle.r, NA(arc.startAngle + pa0 * arc.centralAngle),
(pa1 - pa0) * arc.centralAngle, bUnclock);
}
pa0 = pa1;
bOut = !bOut;
}
if (bContinue)
{
pa1 = 1;
if (bOut)
{
right << new TPGeArc2D(circle.center, circle.r, NA(arc.startAngle + pa0 * arc.centralAngle),
ALEN(pa0 * arc.centralAngle, pa1 * arc.centralAngle), bUnclock);
}
else
{
left << new TPGeArc2D(circle.center, circle.r,NA(arc.startAngle + pa0 * arc.centralAngle),
ALEN(pa0 * arc.centralAngle, pa1 * arc.centralAngle), bUnclock);
}
}
}
void TGMLine2D::TransformBy(const TGMatrix& pMatrix)
{
for (long i = 0; i < points.GetLength(); i++)
{
pMatrix.Transform2D(points[i]);
}
}
bool TGMLine2D::Explode(TGObjectList&res) const
{
long last = points.GetLastIndex();
for (long i = 0;i < last;i++)
{
res << new TPGeGLineSeg2D(points.GetAt(i),points.GetAt(i + 1));
}
if (Is(CLOSED_CURVE))
{
res << new TPGeGLineSeg2D(points.GetAt(last),points.GetAt(0));
}
return true;
}
bool TGMLine2D::IsInclude(const TGObject&obj) const
{
switch(obj.GetClassID())
{
case CID_GLine2D:
case CID_GLineRay2D:
case CID_GCircle2D:
case CID_GArc2D:
return false;
case CID_GLineSeg2D:
{
const TPGeGLineSeg2D&seg = (const TPGeGLineSeg2D&)obj;
TGObjectList oList,oList1;
Explode(oList);
seg.SubtractBy(oList,oList1);
return oList1.IsEmpty();
}
default:
return TPGeCurve2D::IsInclude(obj);
}
}
bool TGMLine2D::IsValid() const
{
if (points.GetLength() < 2)
{
return false;
}
long last = points.GetLastIndex();
for (long i = 0;i < last;i++)
{
if (points.GetAt(i) == points.GetAt(i+1))
{
return false;
}
}
if (Is(CLOSED_CURVE))
{
return points.GetAt(last) != points.GetAt(0);
}
else
{
return true;
}
}
bool TGMLine2D::RemoveDupPoint()
{
if (points.GetLength() < 2)
{
return false;
}
TList<TGPoint> ptList;
ptList.AddTail(points.GetAt(0));
for (long i = 1; i < points.GetLength(); i++)
{
if (ptList.GetCurData() != points.GetAt(i))
{
ptList.AddTail(points.GetAt(i));
}
}
if (Is(CLOSED_CURVE) && ptList.GetLength() > 1 && points.GetAt(0) == ptList.GetCurData())
{
ptList.DelCur();
}
if (ptList.GetLength() < 2)
{
return false;
}
if (ptList.GetLength()<points.GetLength())
{
points = ptList;
}
return true;
}
bool TGMLine2D::ExplodeSelfcross(TGObjectList&oList) const
{
long num = GetSegNum();
if (num < 2)
{
return false;
}
TGObjectList oList1;
TPGeGLineSeg2D iSeg,jSeg;
long num1 = num - 1;
for (long i = 0;i < num1;i++)
{
GetSegment(i,iSeg);
for (long j = i + 1; j < num; j++)
{
GetSegment(j,jSeg);
if (iSeg.Intersect(jSeg,oList1))
{
if (oList1[0]->GetClassID() == CID_GLineSeg2D)
{
if (num == 2)
{
oList << new TPGeGLineSeg2D(iSeg) << new TPGeGLineSeg2D(jSeg);
}
else
{
const TPGeGLineSeg2D& seg = (const TPGeGLineSeg2D&)(oList1.GetCurPData());
long jNum = j - i;
long iNum = GetVertexNum()-jNum;
if (iSeg.GetStartPoint() == jSeg.GetEndPoint())
{
iNum--;
}
TGMLine2D *pmli = new TGMLine2D(iNum,Is(CLOSED_CURVE));
TGMLine2D *pmlj = new TGMLine2D(jNum,true);
long iCount = 0,jCount = 0,count = 0;
if (iNum == 0)
{
count = 1;
}
else
{
while(count <= i)
{
(*pmli)[iCount++] = points.GetAt(count++);
}
}
while(count <= j)
{
(*pmlj)[jCount++] = points.GetAt(count++);
}
if (GetVertexNum()>iNum+jNum)
{
count++;
}
while(count<GetVertexNum())
{
(*pmli)[iCount++] = points.GetAt(count++);
}
if (iNum > 1 && !pmli->ExplodeSelfcross(oList))
{
oList << pmli;
}
else
{
delete pmli;
}
if (jNum > 1 && !pmlj->ExplodeSelfcross(oList))
{
oList << pmlj;
}
else
{
delete pmlj;
}
oList << new TPGeGLineSeg2D(iSeg) << new TPGeGLineSeg2D(jSeg);
}
return true;
}
else
{
if (j == (i+1) || (i == 0 && j == num1 && Is(CLOSED_CURVE)))
{
oList1.Clear();
}
else
{
const TGPoint2D& pt = (const TGPoint2D&)(oList1.GetCurPData());
long jNum = j - i + 1;
long iNum = GetVertexNum() - jNum + 2;
bool bjEndPoint = (pt == jSeg.GetEndPoint());
bool biStartPoint = (pt == iSeg.GetStartPoint());
bool biEndPoint = (pt == iSeg.GetEndPoint());
if (bjEndPoint)
{
iNum--;
}
if (biStartPoint)
{
iNum--;
}
if (biEndPoint)
{
jNum--;
}
TGMLine2D *pmli = new TGMLine2D(iNum,Is(CLOSED_CURVE));
TGMLine2D *pmlj = new TGMLine2D(jNum,true);
long iCount = 0,jCount = 0,count = 0;
while(count <= i)
{
(*pmli)[iCount++] = points.GetAt(count++);
}
if (!biStartPoint)
{
(*pmli)[iCount++] = pt;
}
if (!biEndPoint)
{
(*pmlj)[jCount++] = pt;
}
while(count <= j)
{
(*pmlj)[jCount++] = points.GetAt(count++);
}
if (count<GetVertexNum())
{
if (!bjEndPoint)
{
(*pmli)[iCount++] = points.GetAt(count);
}
count++;
while(count<GetVertexNum())
{
(*pmli)[iCount++] = points.GetAt(count++);
}
}
if (iNum > 1 && !pmli->ExplodeSelfcross(oList))
{
oList << pmli;
}
else
{
delete pmli;
}
if (jNum > 1 && !pmlj->ExplodeSelfcross(oList))
{
oList << pmlj;
}
else
{
delete pmlj;
}
return true;
}
}
}
}
}
return false;
}
bool TGMLine2D::Offset(double offset)
{
TArray<TPGeLine2D> lines(GetSegNum());
for (long i = 0;i < lines.GetLength();i++)
{
GetSegment(i,lines[i]);
lines[i].Offset(offset);
}
TArray<TGPoint> newPt(GetVertexNum());
for (i = 1;i < lines.GetLength();i++)
{
TPGeLine2D& line0 = lines[i - 1];
TPGeLine2D& line1 = lines[i];
int iRet = line0.Intersect(line1,newPt[i]);
if (iRet == INT_LINE)
{
newPt[i] = line1.basePoint;
}
else if (iRet == INT_NULL)
{
return false;
}
}
if (IsClosed())
{
int iRet = lines[i-1].Intersect(lines[0],newPt[0]);
if (iRet == INT_LINE)
{
newPt[0] = lines[0].basePoint;
}
else if (iRet == INT_NULL)
{
return false;
}
}
else
{
newPt[0] = lines[0].basePoint;
newPt[newPt.GetLastIndex()] = lines[i - 1].basePoint + lines[i - 1];
}
points = newPt;
return true;
}
bool TGMLine2D::OffsetSeg(long iSeg,double offset)
{
TArray<TPGeLine2D> lines(GetSegNum());
for (long i = 0; i < lines.GetLength();i++)
{
GetSegment(i,lines[i]);
if (i == iSeg)
{
lines[i].Offset(offset);
}
}
TArray<TGPoint> newPt(points);
for (i = 1;i < lines.GetLength();i++)
{
if (i != iSeg && i != iSeg + 1)
{
continue;
}
TPGeLine2D& line0 = lines[i - 1];
TPGeLine2D& line1 = lines[i];
int iRet = line0.Intersect(line1,newPt[i]);
if (iRet == INT_LINE)
{
newPt[i] = line1.basePoint;
}
else if (iRet == INT_NULL)
{
return false;
}
}
if (IsClosed())
{
if (iSeg == i - 1 || iSeg == 0)
{
int iRet = lines[i-1].Intersect(lines[0],newPt[0]);
if (iRet == INT_LINE)
{
newPt[0]=lines[0].basePoint;
}
else if (iRet == INT_NULL)
{
return false;
}
}
}
else if (iSeg == 0)
{
newPt[0] = lines[0].basePoint;
}
else if (iSeg == i - 1)
{
newPt[newPt.GetLastIndex()] = lines[i - 1].basePoint + lines[i - 1];
}
points = newPt;
return true;
}