//-------------------------------------------------------------------------------------------------------+ // 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&vertexs,bool bClosed):points(vertexs) { if (bClosed) { AddFlag(CLOSED_CURVE); } } TGMLine2D::TGMLine2D(const TArray&vertexs,bool bClosed):points(vertexs) { if (bClosed) { AddFlag(CLOSED_CURVE); } } TGMLine2D::~TGMLine2D() { } TGMLine2D& TGMLine2D::operator = (const TArray&vertexs) { SetVertexNum(vertexs.GetLength()); points = vertexs; return *this; } TGMLine2D& TGMLine2D::operator = (const TTable&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 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 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 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 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 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 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 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()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 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 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 lines(GetSegNum()); for (long i = 0;i < lines.GetLength();i++) { GetSegment(i,lines[i]); lines[i].Offset(offset); } TArray 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 lines(GetSegNum()); for (long i = 0; i < lines.GetLength();i++) { GetSegment(i,lines[i]); if (i == iSeg) { lines[i].Offset(offset); } } TArray 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; }