예제 #1
0
		//------------------------------------------------------------------------------
		
		private void InitEdge(TEdge e, TEdge eNext,
		                      TEdge ePrev, IntPoint pt)
		{
			e.Next = eNext;
			e.Prev = ePrev;
			e.Curr = pt;
			e.OutIdx = Unassigned;
		}
예제 #2
0
		//------------------------------------------------------------------------------
		#endif
		
		internal bool Pt2IsBetweenPt1AndPt3(IntPoint pt1, IntPoint pt2, IntPoint pt3)
		{
			if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2)) return false;
			else if (pt1.X != pt3.X) return (pt2.X > pt1.X) == (pt2.X < pt3.X);
			else return (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y);
		}
예제 #3
0
		//------------------------------------------------------------------------------
		
		internal bool PointOnPolygon(IntPoint pt, OutPt pp, bool UseFullRange)
		{
			OutPt pp2 = pp;
			while (true)
			{
				if (PointOnLineSegment(pt, pp2.Pt, pp2.Next.Pt, UseFullRange))
					return true;
				pp2 = pp2.Next;
				if (pp2 == pp) break;
			}
			return false;
		}
예제 #4
0
		//------------------------------------------------------------------------------
		
		protected static bool SlopesEqual(IntPoint pt1, IntPoint pt2,
		                                  IntPoint pt3, IntPoint pt4, bool UseFullRange)
		{
			if (UseFullRange)
				return Int128.Int128Mul(pt1.Y - pt2.Y, pt3.X - pt4.X) ==
					Int128.Int128Mul(pt1.X - pt2.X, pt3.Y - pt4.Y);
			else return
				(cInt)(pt1.Y - pt2.Y) * (pt3.X - pt4.X) - (cInt)(pt1.X - pt2.X) * (pt3.Y - pt4.Y) == 0;
		}
예제 #5
0
		//------------------------------------------------------------------------------
		
		private static bool SlopesNearCollinear(IntPoint pt1, 
		                                        IntPoint pt2, IntPoint pt3, double distSqrd)
		{
			if (DistanceSqrd(pt1, pt2) > DistanceSqrd(pt1, pt3)) return false;
			DoublePoint cpol = ClosestPointOnLine(pt2, pt1, pt3);
			double dx = pt2.X - cpol.X;
			double dy = pt2.Y - cpol.Y;
			return (dx*dx + dy*dy) < distSqrd;
		}
예제 #6
0
		//------------------------------------------------------------------------------
		
		internal bool PointIsVertex(IntPoint pt, OutPt pp)
		{
			OutPt pp2 = pp;
			do
			{
				if (pp2.Pt == pt) return true;
				pp2 = pp2.Next;
			}
			while (pp2 != pp);
			return false;
		}
예제 #7
0
		//------------------------------------------------------------------------------
		
		private void SwapIntersectNodes(IntersectNode int1, IntersectNode int2)
		{
			TEdge e1 = int1.Edge1;
			TEdge e2 = int1.Edge2;
			IntPoint p = new IntPoint(int1.Pt);
			int1.Edge1 = int2.Edge1;
			int1.Edge2 = int2.Edge2;
			int1.Pt = int2.Pt;
			int2.Edge1 = e1;
			int2.Edge2 = e2;
			int2.Pt = p;
		}
예제 #8
0
		//------------------------------------------------------------------------------
		
		private static double DistanceSqrd(IntPoint pt1, IntPoint pt2)
		{
			double dx = ((double)pt1.X - pt2.X);
			double dy = ((double)pt1.Y - pt2.Y);
			return (dx*dx + dy*dy);
		}
예제 #9
0
		//------------------------------------------------------------------------------
		
		private void ProcessHorizontal(TEdge horzEdge, bool isTopOfScanbeam)
		{
			Direction dir;
			cInt horzLeft, horzRight;
			
			GetHorzDirection(horzEdge, out dir, out horzLeft, out horzRight);
			
			TEdge eLastHorz = horzEdge, eMaxPair = null;
			while (eLastHorz.NextInLML != null && IsHorizontal(eLastHorz.NextInLML)) 
				eLastHorz = eLastHorz.NextInLML;
			if (eLastHorz.NextInLML == null)
				eMaxPair = GetMaximaPair(eLastHorz);
			
			for (;;)
			{
				bool IsLastHorz = (horzEdge == eLastHorz);
				TEdge e = GetNextInAEL(horzEdge, dir);
				while(e != null)
				{
					//Break if we've got to the end of an intermediate horizontal edge ...
					//nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal.
					if (e.Curr.X == horzEdge.Top.X && horzEdge.NextInLML != null && 
					    e.Dx < horzEdge.NextInLML.Dx) break;
					
					TEdge eNext = GetNextInAEL(e, dir); //saves eNext for later
					
					if ((dir == Direction.dLeftToRight && e.Curr.X <= horzRight) ||
					    (dir == Direction.dRightToLeft && e.Curr.X >= horzLeft))
					{
						//so far we're still in range of the horizontal Edge  but make sure
						//we're at the last of consec. horizontals when matching with eMaxPair
						if(e == eMaxPair && IsLastHorz)
						{
							if (horzEdge.OutIdx >= 0 && horzEdge.WindDelta != 0) 
								PrepareHorzJoins(horzEdge, isTopOfScanbeam);
							if (dir == Direction.dLeftToRight)
								IntersectEdges(horzEdge, e, e.Top);
							else
								IntersectEdges(e, horzEdge, e.Top);
							if (eMaxPair.OutIdx >= 0) throw 
								new ClipperException("ProcessHorizontal error");
							return;
						}
						else if(dir == Direction.dLeftToRight)
						{
							IntPoint Pt = new IntPoint(e.Curr.X, horzEdge.Curr.Y);
							IntersectEdges(horzEdge, e, Pt, true);
						}
						else
						{
							IntPoint Pt = new IntPoint(e.Curr.X, horzEdge.Curr.Y);
							IntersectEdges(e, horzEdge, Pt, true);
						}
						SwapPositionsInAEL(horzEdge, e);
					}
					else if ((dir == Direction.dLeftToRight && e.Curr.X >= horzRight) ||
					         (dir == Direction.dRightToLeft && e.Curr.X <= horzLeft)) break;
					e = eNext;
				} //end while
				
				if (horzEdge.OutIdx >= 0 && horzEdge.WindDelta != 0)
					PrepareHorzJoins(horzEdge, isTopOfScanbeam);
				
				if (horzEdge.NextInLML != null && IsHorizontal(horzEdge.NextInLML))
				{
					UpdateEdgeIntoAEL(ref horzEdge);
					if (horzEdge.OutIdx >= 0) AddOutPt(horzEdge, horzEdge.Bot);
					GetHorzDirection(horzEdge, out dir, out horzLeft, out horzRight);
				} else
					break;
			} //end for (;;)
			
			if(horzEdge.NextInLML != null)
			{
				if(horzEdge.OutIdx >= 0)
				{
					OutPt op1 = AddOutPt( horzEdge, horzEdge.Top);
					UpdateEdgeIntoAEL(ref horzEdge);
					if (horzEdge.WindDelta == 0) return;
					//nb: HorzEdge is no longer horizontal here
					TEdge ePrev = horzEdge.PrevInAEL;
					TEdge eNext = horzEdge.NextInAEL;
					if (ePrev != null && ePrev.Curr.X == horzEdge.Bot.X &&
					    ePrev.Curr.Y == horzEdge.Bot.Y && ePrev.WindDelta != 0 &&
					    (ePrev.OutIdx >= 0 && ePrev.Curr.Y > ePrev.Top.Y &&
					 SlopesEqual(horzEdge, ePrev, m_UseFullRange)))
					{
						OutPt op2 = AddOutPt(ePrev, horzEdge.Bot);
						AddJoin(op1, op2, horzEdge.Top);
					}
					else if (eNext != null && eNext.Curr.X == horzEdge.Bot.X &&
					         eNext.Curr.Y == horzEdge.Bot.Y && eNext.WindDelta != 0 &&
					         eNext.OutIdx >= 0 && eNext.Curr.Y > eNext.Top.Y &&
					         SlopesEqual(horzEdge, eNext, m_UseFullRange))
					{
						OutPt op2 = AddOutPt(eNext, horzEdge.Bot);
						AddJoin(op1, op2, horzEdge.Top);
					}
				}
				else
					UpdateEdgeIntoAEL(ref horzEdge); 
			}
			else if (eMaxPair != null)
			{
				if (eMaxPair.OutIdx >= 0)
				{
					if (dir == Direction.dLeftToRight)
						IntersectEdges(horzEdge, eMaxPair, horzEdge.Top); 
					else
						IntersectEdges(eMaxPair, horzEdge, horzEdge.Top);
					if (eMaxPair.OutIdx >= 0) throw 
						new ClipperException("ProcessHorizontal error");
				} else
				{
					DeleteFromAEL(horzEdge);
					DeleteFromAEL(eMaxPair);
				}
			} else
			{
				if (horzEdge.OutIdx >= 0) AddOutPt(horzEdge, horzEdge.Top);
				DeleteFromAEL(horzEdge);
			}
		}
예제 #10
0
		//------------------------------------------------------------------------------
		
		private void InsertIntersectNode(TEdge e1, TEdge e2, IntPoint pt)
		{
			IntersectNode newNode = new IntersectNode();
			newNode.Edge1 = e1;
			newNode.Edge2 = e2;
			newNode.Pt = pt;
			newNode.Next = null;
			if (m_IntersectNodes == null) m_IntersectNodes = newNode;
			else if (newNode.Pt.Y > m_IntersectNodes.Pt.Y)
			{
				newNode.Next = m_IntersectNodes;
				m_IntersectNodes = newNode;
			}
			else
			{
				IntersectNode iNode = m_IntersectNodes;
				while (iNode.Next != null && newNode.Pt.Y < iNode.Next.Pt.Y)
					iNode = iNode.Next;
				newNode.Next = iNode.Next;
				iNode.Next = newNode;
			}
		}
예제 #11
0
		//------------------------------------------------------------------------------
		
		private void IntersectEdges(TEdge e1, TEdge e2, IntPoint pt, bool protect = false)
		{
			//e1 will be to the left of e2 BELOW the intersection. Therefore e1 is before
			//e2 in AEL except when e1 is being inserted at the intersection point ...
			
			bool e1stops = !protect && e1.NextInLML == null &&
				e1.Top.X == pt.X && e1.Top.Y == pt.Y;
			bool e2stops = !protect && e2.NextInLML == null &&
				e2.Top.X == pt.X && e2.Top.Y == pt.Y;
			bool e1Contributing = (e1.OutIdx >= 0);
			bool e2Contributing = (e2.OutIdx >= 0);
			
			#if use_lines
			//if either edge is on an OPEN path ...
			if (e1.WindDelta == 0 || e2.WindDelta == 0)
			{
				//ignore subject-subject open path intersections UNLESS they
				//are both open paths, AND they are both 'contributing maximas' ...
				if (e1.WindDelta == 0 && e2.WindDelta == 0)
				{
					if ((e1stops || e2stops) && e1Contributing && e2Contributing)
						AddLocalMaxPoly(e1, e2, pt);
				}
				//if intersecting a subj line with a subj poly ...
				else if (e1.PolyTyp == e2.PolyTyp && 
				         e1.WindDelta != e2.WindDelta && m_ClipType == ClipType.ctUnion)
				{
					if (e1.WindDelta == 0)
					{
						if (e2Contributing)
						{
							AddOutPt(e1, pt);
							if (e1Contributing) e1.OutIdx = Unassigned;
						}
					}
					else
					{
						if (e1Contributing)
						{
							AddOutPt(e2, pt);
							if (e2Contributing) e2.OutIdx = Unassigned;
						}
					}
				}
				else if (e1.PolyTyp != e2.PolyTyp)
				{
					if ((e1.WindDelta == 0) && Math.Abs(e2.WindCnt) == 1 && 
					    (m_ClipType != ClipType.ctUnion || e2.WindCnt2 == 0))
					{
						AddOutPt(e1, pt);
						if (e1Contributing) e1.OutIdx = Unassigned;
					}
					else if ((e2.WindDelta == 0) && (Math.Abs(e1.WindCnt) == 1) && 
					         (m_ClipType != ClipType.ctUnion || e1.WindCnt2 == 0))
					{
						AddOutPt(e2, pt);
						if (e2Contributing) e2.OutIdx = Unassigned;
					}
				}
				
				if (e1stops)
					if (e1.OutIdx < 0) DeleteFromAEL(e1);
				else throw new ClipperException("Error intersecting polylines");
				if (e2stops) 
					if (e2.OutIdx < 0) DeleteFromAEL(e2);
				else throw new ClipperException("Error intersecting polylines");
				return;
			}
			#endif
			
			//update winding counts...
			//assumes that e1 will be to the Right of e2 ABOVE the intersection
			if (e1.PolyTyp == e2.PolyTyp)
			{
				if (IsEvenOddFillType(e1))
				{
					int oldE1WindCnt = e1.WindCnt;
					e1.WindCnt = e2.WindCnt;
					e2.WindCnt = oldE1WindCnt;
				}
				else
				{
					if (e1.WindCnt + e2.WindDelta == 0) e1.WindCnt = -e1.WindCnt;
					else e1.WindCnt += e2.WindDelta;
					if (e2.WindCnt - e1.WindDelta == 0) e2.WindCnt = -e2.WindCnt;
					else e2.WindCnt -= e1.WindDelta;
				}
			}
			else
			{
				if (!IsEvenOddFillType(e2)) e1.WindCnt2 += e2.WindDelta;
				else e1.WindCnt2 = (e1.WindCnt2 == 0) ? 1 : 0;
				if (!IsEvenOddFillType(e1)) e2.WindCnt2 -= e1.WindDelta;
				else e2.WindCnt2 = (e2.WindCnt2 == 0) ? 1 : 0;
			}
			
			PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2;
			if (e1.PolyTyp == PolyType.ptSubject)
			{
				e1FillType = m_SubjFillType;
				e1FillType2 = m_ClipFillType;
			}
			else
			{
				e1FillType = m_ClipFillType;
				e1FillType2 = m_SubjFillType;
			}
			if (e2.PolyTyp == PolyType.ptSubject)
			{
				e2FillType = m_SubjFillType;
				e2FillType2 = m_ClipFillType;
			}
			else
			{
				e2FillType = m_ClipFillType;
				e2FillType2 = m_SubjFillType;
			}
			
			int e1Wc, e2Wc;
			switch (e1FillType)
			{
			case PolyFillType.pftPositive: e1Wc = e1.WindCnt; break;
			case PolyFillType.pftNegative: e1Wc = -e1.WindCnt; break;
			default: e1Wc = Math.Abs(e1.WindCnt); break;
			}
			switch (e2FillType)
			{
			case PolyFillType.pftPositive: e2Wc = e2.WindCnt; break;
			case PolyFillType.pftNegative: e2Wc = -e2.WindCnt; break;
			default: e2Wc = Math.Abs(e2.WindCnt); break;
			}
			
			if (e1Contributing && e2Contributing)
			{
				if ( e1stops || e2stops || 
				    (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
				    (e1.PolyTyp != e2.PolyTyp && m_ClipType != ClipType.ctXor))
					AddLocalMaxPoly(e1, e2, pt);
				else
				{
					AddOutPt(e1, pt);
					AddOutPt(e2, pt);
					SwapSides(e1, e2);
					SwapPolyIndexes(e1, e2);
				}
			}
			else if (e1Contributing)
			{
				if (e2Wc == 0 || e2Wc == 1)
				{
					AddOutPt(e1, pt);
					SwapSides(e1, e2);
					SwapPolyIndexes(e1, e2);
				}
				
			}
			else if (e2Contributing)
			{
				if (e1Wc == 0 || e1Wc == 1)
				{
					AddOutPt(e2, pt);
					SwapSides(e1, e2);
					SwapPolyIndexes(e1, e2);
				}
			}
			else if ( (e1Wc == 0 || e1Wc == 1) && 
			         (e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops )
			{
				//neither edge is currently contributing ...
				cInt e1Wc2, e2Wc2;
				switch (e1FillType2)
				{
				case PolyFillType.pftPositive: e1Wc2 = e1.WindCnt2; break;
				case PolyFillType.pftNegative: e1Wc2 = -e1.WindCnt2; break;
				default: e1Wc2 = Math.Abs(e1.WindCnt2); break;
				}
				switch (e2FillType2)
				{
				case PolyFillType.pftPositive: e2Wc2 = e2.WindCnt2; break;
				case PolyFillType.pftNegative: e2Wc2 = -e2.WindCnt2; break;
				default: e2Wc2 = Math.Abs(e2.WindCnt2); break;
				}
				
				if (e1.PolyTyp != e2.PolyTyp)
					AddLocalMinPoly(e1, e2, pt);
				else if (e1Wc == 1 && e2Wc == 1)
					switch (m_ClipType)
				{
					case ClipType.ctIntersection:
					if (e1Wc2 > 0 && e2Wc2 > 0)
						AddLocalMinPoly(e1, e2, pt);
					break;
					case ClipType.ctUnion:
					if (e1Wc2 <= 0 && e2Wc2 <= 0)
						AddLocalMinPoly(e1, e2, pt);
					break;
					case ClipType.ctDifference:
					if (((e1.PolyTyp == PolyType.ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) ||
					    ((e1.PolyTyp == PolyType.ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0)))
						AddLocalMinPoly(e1, e2, pt);
					break;
					case ClipType.ctXor:
					AddLocalMinPoly(e1, e2, pt);
					break;
				}
				else 
					SwapSides(e1, e2);
			}
			
			if ((e1stops != e2stops) &&
			    ((e1stops && (e1.OutIdx >= 0)) || (e2stops && (e2.OutIdx >= 0))))
			{
				SwapSides(e1, e2);
				SwapPolyIndexes(e1, e2);
			}
			
			//finally, delete any non-contributing maxima edges  ...
			if (e1stops) DeleteFromAEL(e1);
			if (e2stops) DeleteFromAEL(e2);
		}
예제 #12
0
		//------------------------------------------------------------------------------
		
		private double GetDx(IntPoint pt1, IntPoint pt2)
		{
			if (pt1.Y == pt2.Y) return horizontal;
			else return (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y);
		}
예제 #13
0
		//------------------------------------------------------------------------------
		
		private OutPt InsertPolyPtBetween(OutPt p1, OutPt p2, IntPoint pt)
		{
			OutPt result = new OutPt();
			result.Pt = pt;
			if (p2 == p1.Next)
			{
				p1.Next = result;
				p2.Prev = result;
				result.Next = p2;
				result.Prev = p1;
			} else
			{
				p2.Next = result;
				p1.Prev = result;
				result.Next = p1;
				result.Prev = p2;
			}
			return result;
		}
예제 #14
0
		//------------------------------------------------------------------------------
		
		private bool HorzSegmentsOverlap(
			IntPoint Pt1a, IntPoint Pt1b, IntPoint Pt2a, IntPoint Pt2b)
		{
			//precondition: both segments are horizontal
			if ((Pt1a.X > Pt2a.X) == (Pt1a.X < Pt2b.X)) return true;
			else if ((Pt1b.X > Pt2a.X) == (Pt1b.X < Pt2b.X)) return true;
			else if ((Pt2a.X > Pt1a.X) == (Pt2a.X < Pt1b.X)) return true;
			else if ((Pt2b.X > Pt1a.X) == (Pt2b.X < Pt1b.X)) return true;
			else if ((Pt1a.X == Pt2a.X) && (Pt1b.X == Pt2b.X)) return true;
			else if ((Pt1a.X == Pt2b.X) && (Pt1b.X == Pt2a.X)) return true;
			else return false;
		}
예제 #15
0
		//------------------------------------------------------------------------------
		
		private bool IntersectPoint(TEdge edge1, TEdge edge2, out IntPoint ip)
		{
			ip = new IntPoint();
			double b1, b2;
			//nb: with very large coordinate values, it's possible for SlopesEqual() to 
			//return false but for the edge.Dx value be equal due to double precision rounding.
			if (SlopesEqual(edge1, edge2, m_UseFullRange) || edge1.Dx == edge2.Dx)
			{
				if (edge2.Bot.Y > edge1.Bot.Y)
					ip.Y = edge2.Bot.Y;
				else
					ip.Y = edge1.Bot.Y;
				return false;
			}
			else if (edge1.Delta.X == 0)
			{
				ip.X = edge1.Bot.X;
				if (IsHorizontal(edge2))
				{
					ip.Y = edge2.Bot.Y;
				}
				else
				{
					b2 = edge2.Bot.Y - (edge2.Bot.X / edge2.Dx);
					ip.Y = Round(ip.X / edge2.Dx + b2);
				}
			}
			else if (edge2.Delta.X == 0)
			{
				ip.X = edge2.Bot.X;
				if (IsHorizontal(edge1))
				{
					ip.Y = edge1.Bot.Y;
				}
				else
				{
					b1 = edge1.Bot.Y - (edge1.Bot.X / edge1.Dx);
					ip.Y = Round(ip.X / edge1.Dx + b1);
				}
			}
			else
			{
				b1 = edge1.Bot.X - edge1.Bot.Y * edge1.Dx;
				b2 = edge2.Bot.X - edge2.Bot.Y * edge2.Dx;
				double q = (b2 - b1) / (edge1.Dx - edge2.Dx);
				ip.Y = Round(q);
				if (Math.Abs(edge1.Dx) < Math.Abs(edge2.Dx))
					ip.X = Round(edge1.Dx * q + b1);
				else
					ip.X = Round(edge2.Dx * q + b2);
			}
			
			if (ip.Y < edge1.Top.Y || ip.Y < edge2.Top.Y)
			{
				if (edge1.Top.Y > edge2.Top.Y)
				{
					ip.Y = edge1.Top.Y;
					ip.X = TopX(edge2, edge1.Top.Y);
					return ip.X < edge1.Top.X;
				}
				else
				{
					ip.Y = edge2.Top.Y;
					ip.X = TopX(edge1, edge2.Top.Y);
					return ip.X > edge2.Top.X;
				}
			}
			else
				return true;
		}
예제 #16
0
		//------------------------------------------------------------------------------
		
		public static Paths OffsetPaths(Paths polys, double delta,
		                                JoinType jointype, EndType endtype, double MiterLimit)
		{
			Paths out_polys = new Paths(polys.Count);
			IntPoint botPt = new IntPoint();
			IntPoint pt;
			int botIdx = -1;
			for (int i = 0; i < polys.Count; ++i)
			{
				out_polys.Add(new Path());
				if (StripDupsAndGetBotPt(polys[i], out_polys[i], endtype == EndType.etClosed, out pt))
					if (botIdx < 0 || pt.Y > botPt.Y || (pt.Y == botPt.Y && pt.X < botPt.X))
				{
					botPt = pt;
					botIdx = i;
				}
			}
			if (endtype == EndType.etClosed && botIdx >= 0 && !Orientation(out_polys[botIdx]))
				ReversePaths(out_polys);
			
			Paths result;
			new PolyOffsetBuilder(out_polys, out result, delta, jointype, endtype, MiterLimit);
			return result;
		}
예제 #17
0
		//------------------------------------------------------------------------------
		
		bool JoinHorz(OutPt op1, OutPt op1b, OutPt op2, OutPt op2b, 
		              IntPoint Pt, bool DiscardLeft)
		{
			Direction Dir1 = (op1.Pt.X > op1b.Pt.X ? 
			                  Direction.dRightToLeft : Direction.dLeftToRight);
			Direction Dir2 = (op2.Pt.X > op2b.Pt.X ?
			                  Direction.dRightToLeft : Direction.dLeftToRight);
			if (Dir1 == Dir2) return false;
			
			//When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we
			//want Op1b to be on the Right. (And likewise with Op2 and Op2b.)
			//So, to facilitate this while inserting Op1b and Op2b ...
			//when DiscardLeft, make sure we're AT or RIGHT of Pt before adding Op1b,
			//otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.)
			if (Dir1 == Direction.dLeftToRight) 
			{
				while (op1.Next.Pt.X <= Pt.X && 
				       op1.Next.Pt.X >= op1.Pt.X && op1.Next.Pt.Y == Pt.Y)  
					op1 = op1.Next;
				if (DiscardLeft && (op1.Pt.X != Pt.X)) op1 = op1.Next;
				op1b = DupOutPt(op1, !DiscardLeft);
				if (op1b.Pt != Pt) 
				{
					op1 = op1b;
					op1.Pt = Pt;
					op1b = DupOutPt(op1, !DiscardLeft);
				}
			} 
			else
			{
				while (op1.Next.Pt.X >= Pt.X && 
				       op1.Next.Pt.X <= op1.Pt.X && op1.Next.Pt.Y == Pt.Y) 
					op1 = op1.Next;
				if (!DiscardLeft && (op1.Pt.X != Pt.X)) op1 = op1.Next;
				op1b = DupOutPt(op1, DiscardLeft);
				if (op1b.Pt != Pt)
				{
					op1 = op1b;
					op1.Pt = Pt;
					op1b = DupOutPt(op1, DiscardLeft);
				}
			}
			
			if (Dir2 == Direction.dLeftToRight)
			{
				while (op2.Next.Pt.X <= Pt.X && 
				       op2.Next.Pt.X >= op2.Pt.X && op2.Next.Pt.Y == Pt.Y)
					op2 = op2.Next;
				if (DiscardLeft && (op2.Pt.X != Pt.X)) op2 = op2.Next;
				op2b = DupOutPt(op2, !DiscardLeft);
				if (op2b.Pt != Pt)
				{
					op2 = op2b;
					op2.Pt = Pt;
					op2b = DupOutPt(op2, !DiscardLeft);
				};
			} else
			{
				while (op2.Next.Pt.X >= Pt.X && 
				       op2.Next.Pt.X <= op2.Pt.X && op2.Next.Pt.Y == Pt.Y) 
					op2 = op2.Next;
				if (!DiscardLeft && (op2.Pt.X != Pt.X)) op2 = op2.Next;
				op2b = DupOutPt(op2, DiscardLeft);
				if (op2b.Pt != Pt)
				{
					op2 = op2b;
					op2.Pt = Pt;
					op2b = DupOutPt(op2, DiscardLeft);
				};
			};
			
			if ((Dir1 == Direction.dLeftToRight) == DiscardLeft)
			{
				op1.Prev = op2;
				op2.Next = op1;
				op1b.Next = op2b;
				op2b.Prev = op1b;
			}
			else
			{
				op1.Next = op2;
				op2.Prev = op1;
				op1b.Prev = op2b;
				op2b.Next = op1b;
			}
			return true;
		}
예제 #18
0
		//------------------------------------------------------------------------------
		
		private static DoublePoint ClosestPointOnLine(IntPoint pt, IntPoint linePt1, IntPoint linePt2)
		{
			double dx = ((double)linePt2.X - linePt1.X);
			double dy = ((double)linePt2.Y - linePt1.Y);
			if (dx == 0 && dy == 0) 
				return new DoublePoint(linePt1.X, linePt1.Y);
			double q = ((pt.X-linePt1.X)*dx + (pt.Y-linePt1.Y)*dy) / (dx*dx + dy*dy);
			return new DoublePoint(
				(1-q)*linePt1.X + q*linePt2.X, 
				(1-q)*linePt1.Y + q*linePt2.Y);
		}
예제 #19
0
		//------------------------------------------------------------------------------
		// OffsetPolygon functions ...
		//------------------------------------------------------------------------------
		
		internal static DoublePoint GetUnitNormal(IntPoint pt1, IntPoint pt2)
		{
			double dx = (pt2.X - pt1.X);
			double dy = (pt2.Y - pt1.Y);
			if ((dx == 0) && (dy == 0)) return new DoublePoint();
			
			double f = 1 * 1.0 / Math.Sqrt(dx * dx + dy * dy);
			dx *= f;
			dy *= f;
			
			return new DoublePoint(dy, -dx);
		}
예제 #20
0
		//------------------------------------------------------------------------------
		
		private static bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd)
		{
			double dx = (double)pt1.X - pt2.X;
			double dy = (double)pt1.Y - pt2.Y;
			return ((dx * dx) + (dy * dy) <= distSqrd);
		}
예제 #21
0
			//------------------------------------------------------------------------------
			
			public PolyOffsetBuilder(Paths pts, out Paths solution, double delta,
			                         JoinType jointype, EndType endtype, double limit = 0)
			{
				//precondition: solution != pts
				solution = new Paths();
				if (ClipperBase.near_zero(delta)) {solution = pts; return; }
				m_p = pts;
				if (endtype != EndType.etClosed && delta < 0) delta = -delta;
				m_delta = delta;
				
				if (jointype == JoinType.jtMiter)
				{
					//m_miterVal: see offset_triginometry.svg in the documentation folder ...
					if (limit > 2) m_miterLim = 2 / (limit * limit);
					else m_miterLim = 0.5;
					if (endtype == EndType.etRound) limit = 0.25;
				}
				if (jointype == JoinType.jtRound || endtype == EndType.etRound)
				{
					if (limit <= 0) limit = 0.25;
					else if (limit > Math.Abs(delta)*0.25) limit = Math.Abs(delta)*0.25;
					//m_roundVal: see offset_triginometry2.svg in the documentation folder ...
					m_Steps360 = Math.PI / Math.Acos(1 - limit / Math.Abs(delta));
					m_sin = Math.Sin(2 * Math.PI / m_Steps360);
					m_cos = Math.Cos(2 * Math.PI / m_Steps360);
					m_Steps360 /= Math.PI * 2;
					if (delta < 0) m_sin = -m_sin;
				}
				
				solution.Capacity = pts.Count;
				for (m_i = 0; m_i < pts.Count; m_i++)
				{
					int len = pts[m_i].Count;
					if (len == 0 || (len < 3 && delta <= 0)) continue;
					
					if (len == 1)
					{
						if (jointype == JoinType.jtRound)
						{
							double X = 1.0, Y = 0.0;
							for (cInt j = 1; j <= Round(m_Steps360 * 2 * Math.PI); j++)
							{
								AddPoint(new IntPoint(
									Round(m_p[m_i][0].X + X * delta),
									Round(m_p[m_i][0].Y + Y * delta)));
								double X2 = X;
								X = X * m_cos - m_sin * Y;
								Y = X2 * m_sin + Y * m_cos;
							}
						}
						else
						{
							double X = -1.0, Y = -1.0;
							for (int j = 0; j < 4; ++j)
							{
								AddPoint(new IntPoint(Round(m_p[m_i][0].X + X * delta),
								                      Round(m_p[m_i][0].Y + Y * delta)));
								if (X < 0) X = 1;
								else if (Y < 0) Y = 1;
								else X = -1;
							}
						}
						continue;
					}
					
					//build normals ...
					normals.Clear();
					normals.Capacity = len;
					for (int j = 0; j < len -1; ++j)
						normals.Add(GetUnitNormal(pts[m_i][j], pts[m_i][j+1]));
					if (endtype == EndType.etClosed)
						normals.Add(GetUnitNormal(pts[m_i][len - 1], pts[m_i][0]));
					else
						normals.Add(new DoublePoint(normals[len - 2]));
					
					currentPoly = new Path();
					if (endtype == EndType.etClosed)
					{
						m_k = len - 1;
						for (m_j = 0; m_j < len; ++m_j)
							OffsetPoint(jointype);
						solution.Add(currentPoly); 
					}
					else
					{
						m_k = 0;
						for (m_j = 1; m_j < len - 1; ++m_j)
							OffsetPoint(jointype);
						
						IntPoint pt1;
						if (endtype == EndType.etButt)
						{
							m_j = len - 1;
							pt1 = new IntPoint((cInt)Round(pts[m_i][m_j].X + normals[m_j].X *
							                               delta), (cInt)Round(pts[m_i][m_j].Y + normals[m_j].Y * delta));
							AddPoint(pt1);
							pt1 = new IntPoint((cInt)Round(pts[m_i][m_j].X - normals[m_j].X *
							                               delta), (cInt)Round(pts[m_i][m_j].Y - normals[m_j].Y * delta));
							AddPoint(pt1);
						}
						else
						{
							m_j = len - 1;
							m_k = len - 2;
							m_sinA = 0;
							normals[m_j] = new DoublePoint(-normals[m_j].X, -normals[m_j].Y);
							if (endtype == EndType.etSquare)
								DoSquare();
							else
								DoRound();
						}
						
						//re-build Normals ...
						for (int j = len - 1; j > 0; j--)
							normals[j] = new DoublePoint(-normals[j - 1].X, -normals[j - 1].Y);
						
						normals[0] = new DoublePoint(-normals[1].X, -normals[1].Y);
						
						m_k = len - 1;
						for (m_j = m_k - 1; m_j > 0; --m_j)
							OffsetPoint(jointype);
						
						if (endtype == EndType.etButt)
						{
							pt1 = new IntPoint((cInt)Round(pts[m_i][0].X - normals[0].X * delta),
							                   (cInt)Round(pts[m_i][0].Y - normals[0].Y * delta));
							AddPoint(pt1);
							pt1 = new IntPoint((cInt)Round(pts[m_i][0].X + normals[0].X * delta),
							                   (cInt)Round(pts[m_i][0].Y + normals[0].Y * delta));
							AddPoint(pt1);
						}
						else
						{
							m_k = 1;
							m_sinA = 0;
							if (endtype == EndType.etSquare) 
								DoSquare();
							else
								DoRound();
						}
						solution.Add(currentPoly);
					}
				}
				
				//finally, clean up untidy corners ...
				Clipper clpr = new Clipper();
				clpr.AddPaths(solution, PolyType.ptSubject, true);
				if (delta > 0)
				{
					clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftPositive, PolyFillType.pftPositive);
				}
				else
				{
					IntRect r = clpr.GetBounds();
					Path outer = new Path(4);
					
					outer.Add(new IntPoint(r.left - 10, r.bottom + 10));
					outer.Add(new IntPoint(r.right + 10, r.bottom + 10));
					outer.Add(new IntPoint(r.right + 10, r.top - 10));
					outer.Add(new IntPoint(r.left - 10, r.top - 10));
					
					clpr.AddPath(outer, PolyType.ptSubject, true);
					clpr.ReverseSolution = true;
					clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative);
					if (solution.Count > 0) solution.RemoveAt(0);
				}
			}
예제 #22
0
		//------------------------------------------------------------------------------
		
		internal bool PointOnLineSegment(IntPoint pt, 
		                                 IntPoint linePt1, IntPoint linePt2, bool UseFullRange)
		{
			if (UseFullRange)
				return ((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) ||
					((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) ||
					(((pt.X > linePt1.X) == (pt.X < linePt2.X)) &&
					 ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) &&
					 ((Int128.Int128Mul((pt.X - linePt1.X), (linePt2.Y - linePt1.Y)) ==
					  Int128.Int128Mul((linePt2.X - linePt1.X), (pt.Y - linePt1.Y)))));
			else
				return ((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) ||
					((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) ||
					(((pt.X > linePt1.X) == (pt.X < linePt2.X)) &&
					 ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) &&
					 ((pt.X - linePt1.X) * (linePt2.Y - linePt1.Y) ==
					 (linePt2.X - linePt1.X) * (pt.Y - linePt1.Y)));
		}
예제 #23
0
			//------------------------------------------------------------------------------
			
			internal void AddPoint(IntPoint pt)
			{
				if (currentPoly.Count == currentPoly.Capacity)
					currentPoly.Capacity += m_buffLength;
				currentPoly.Add(pt);
			}
예제 #24
0
		//------------------------------------------------------------------------------
		
		internal bool PointInPolygon(IntPoint pt, OutPt pp, bool UseFullRange)
		{
			OutPt pp2 = pp;
			bool result = false;
			if (UseFullRange)
			{
				do
				{
					if (((pp2.Pt.Y > pt.Y) != (pp2.Prev.Pt.Y > pt.Y)) && 
					    (new Int128(pt.X - pp2.Pt.X) < 
					 Int128.Int128Mul(pp2.Prev.Pt.X - pp2.Pt.X, pt.Y - pp2.Pt.Y) /
					 new Int128(pp2.Prev.Pt.Y - pp2.Pt.Y))) result = !result;
					pp2 = pp2.Next;
				}
				while (pp2 != pp);
			}
			else
			{
				do
				{
					//http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
					if (((pp2.Pt.Y > pt.Y) != (pp2.Prev.Pt.Y > pt.Y)) &&                     
					    ((pt.X - pp2.Pt.X) < (pp2.Prev.Pt.X - pp2.Pt.X) * (pt.Y - pp2.Pt.Y) / 
					 (pp2.Prev.Pt.Y - pp2.Pt.Y))) result = !result;
					pp2 = pp2.Next;
				}
				while (pp2 != pp);
			}
			return result;
		}
예제 #25
0
		} //end PolyOffsetBuilder
		//------------------------------------------------------------------------------
		
		internal static bool UpdateBotPt(IntPoint pt, ref IntPoint botPt)
		{
			if (pt.Y > botPt.Y || (pt.Y == botPt.Y && pt.X < botPt.X))
			{
				botPt = pt;
				return true;
			}
			else return false;
		}
예제 #26
0
		//------------------------------------------------------------------------------
		
		void RangeTest(IntPoint Pt, ref bool useFullRange)
		{
			if (useFullRange)
			{
				if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange) 
					throw new ClipperException("Coordinate outside allowed range");
			}
			else if (Pt.X > loRange || Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange) 
			{
				useFullRange = true;
				RangeTest(Pt, ref useFullRange);
			}
		}
예제 #27
0
		//------------------------------------------------------------------------------
		
		internal static bool StripDupsAndGetBotPt(Path in_path, 
		                                          Path out_path, bool closed, out IntPoint botPt)
		{
			botPt = new IntPoint(0, 0);
			int len = in_path.Count;
			if (closed)    
				while (len > 0 && (in_path[0] == in_path[len -1])) len--;
			if (len == 0) return false;
			out_path.Capacity = len;
			int j = 0;
			out_path.Add(in_path[0]);
			botPt = in_path[0];
			for (int i = 1; i < len; ++i)
				if (in_path[i] != out_path[j])
			{
				out_path.Add(in_path[i]);
				j++;
				if (out_path[j].Y > botPt.Y ||
				    ((out_path[j].Y == botPt.Y) && out_path[j].X < botPt.X))
					botPt = out_path[j];
			}
			j++;
			if (j < 2 || (closed && (j == 2))) j = 0;
			while (out_path.Count > j) out_path.RemoveAt(j);
			return j > 0;
		}
예제 #28
0
		public DoublePoint(IntPoint ip)
		{
			this.X = ip.X; this.Y = ip.Y;
		}
예제 #29
0
		public IntPoint(IntPoint pt)
		{
			this.X = pt.X; this.Y = pt.Y;
		}
예제 #30
0
        public static Vector3 IntPointToV3(Pathfinding.ClipperLib.IntPoint p)
        {
            VInt3 num = new VInt3((int)p.X, 0, (int)p.Y);

            return((Vector3)num);
        }
예제 #31
0
		//------------------------------------------------------------------------------
		
		internal void SwapPoints(ref IntPoint pt1, ref IntPoint pt2)
		{
			IntPoint tmp = new IntPoint(pt1);
			pt1 = pt2;
			pt2 = tmp;
		}