//-------------------------------------------------------------------------------------------------------+ // 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&vertexs,bool bClosed):TGMLine2D(vertexs,bClosed) { bulges.Realloc(vertexs.GetLength()); bulges.SetAll(0); } TGPLine2D::TGPLine2D(const TTable&vertexs,bool bClosed):TGMLine2D(vertexs,bClosed) { bulges.Realloc(vertexs.GetLength()); bulges.SetAll(0); } TGPLine2D::TGPLine2D(const TArray&vertexs,const TArray&angles,bool bClosed):TGMLine2D(vertexs,bClosed), bulges(angles) { } TGPLine2D::TGPLine2D(const TTable&vertexs,const TTable&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 ptList; TList aList; ptList.AddTail(points.GetAt(0)); for (long i = 1;i1 && points.GetAt(0) == ptList.GetCurData()) { ptList.DelCur(); aList.DelCur(); } if (ptList.GetLength() < 2) { return false; } if (ptList.GetLength()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 ptList; TList 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;iPa2Pt(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;iPa2Pt(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;iHitTest(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;iIntegration(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;iAllIntegration(); 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;iAllIntegration(); 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;ipt.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 cutList; double pa0,pa1; TPGeGLineSeg2D lSeg; TPGeArc2D aSeg; GRelation r; for (long i = 0;ipa1) { 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 cutList; double pa0,pa1; TPGeGLineSeg2D lSeg; TPGeArc2D aSeg; GRelation r; for (long i = 0;ipa1) { 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 cutList; double pa0,pa1; TPGeGLineSeg2D lSeg; TPGeArc2D aSeg; GRelation r; for (long i = 0;ipa1) { 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 ptList; long count = 0; TPGeArc2D arc; for (long i = 0;i curves(GetSegNum()); for (long i = 0;iOffset(offset); curves.AddTail(pLine); } } TArray newPt(GetVertexNum()); for (i = 1;iIntersect(*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] = nDist0Intersect(*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] = nDist0Offset(offset); pSegLast->Offset(offset); pSegFirst->GetStartPoint(newPt[0]); pSegLast->GetEndPoint(newPt[newPt.GetLastIndex()]); delete pSegFirst; delete pSegLast; } points = newPt; for (i = 0;iPt2Pa(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 curves(GetSegNum()); for (long i = 0;iOffset(offset); } curves.AddTail(pLine); } } TArray newPt(points); for (i = 1;iIntersect(*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] = nDist0Intersect(*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] = nDist0Offset(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;iPt2Pa(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; } }