/// <summary>
        /// Returns the routes (multiple lines or part polygons) either inside or
        /// outside the polygons provided. These are based on the intersections
        /// of the 2 polygons e.g. the routes / part polygons of one inside or
        /// outside the other.
        /// </summary>
        /// <param name="Poly1">The first polygon.</param>
        /// <param name="bP1RoutesInside">True if routes inside the second polygon are
        /// required for the first polygon.</param>
        /// <param name="Poly2">The second polygon.</param>
        /// <param name="bP2RoutesInside">True if routes inside the first polygon are
        /// required for the second polygon.</param>
        /// <param name="Routes1">Output. Set of lines for the first polygon.</param>
        /// <param name="Routes2">Output. Set of lines for the second polygon.</param>
        public static void GetRoutes(C2DPolyBase Poly1, bool bP1RoutesInside,
                                     C2DPolyBase Poly2, bool bP2RoutesInside,
                                     C2DLineBaseSetSet Routes1, C2DLineBaseSetSet Routes2)
        {
            // Set up a collection of intersected points, and corresponding indexes.
            var IntPoints = new C2DPointSet();
            var Indexes1  = new List <int>();
            var Indexes2  = new List <int>();

            // Use the line collections in each shape to find the intersections between them.
            Poly1.Lines.GetIntersections(Poly2.Lines, IntPoints,
                                         Indexes1, Indexes2,
                                         Poly1.BoundingRect, Poly2.BoundingRect);
            // Make a copy of the point set because this will be sorted by line index in the
            // Get routes function later. We need an unsorted set for each polygon.
            var IntPointsCopy = new C2DPointSet();

            IntPointsCopy.MakeCopy(IntPoints);

            // Find out whether the first poly starts inside the second.
            bool bP1StartInside = Poly2.Contains(Poly1.Lines[0].GetPointFrom());
            // Find out if poly 2 starts inside poly 1.
            bool bP2StartInside = Poly1.Contains(Poly2.Lines[0].GetPointFrom());

            if (IntPoints.Count == 0 && !bP1StartInside && !bP2StartInside)
            {
                return; // No interaction between the 2.
            }
            // Get the routes of poly 1 inside / outside the other, passing the unsorted
            // intersection points and polygon1 intersection indexes.
            Poly1.GetRoutes(IntPoints, Indexes1, Routes1, bP1StartInside, bP1RoutesInside);
            // Do the same for poly 2 but pass it the unsorted copy of the intersection points
            // So that they correspond to the indexes.
            Poly2.GetRoutes(IntPointsCopy, Indexes2, Routes2, bP2StartInside, bP2RoutesInside);
        }
        /// <summary>
        /// True if this overlaps the other.
        /// </summary>
        /// <param name="Other">The other polygon.</param>
        public bool Overlaps(C2DPolyBase Other)
        {
            if (Lines.Count == 0 || Other.Lines.Count == 0)
            {
                return(false);
            }

            if (Other.Contains(Lines[0].GetPointTo()))
            {
                return(true);
            }

            if (Crosses(Other))
            {
                return(true);
            }

            return(this.Contains(Other.Lines[0].GetPointTo()));
        }
        /// <summary>
        /// Returns the routes (multiple lines or part polygons) either inside or
        /// outside the polygons provided. These are based on the intersections
        /// of the 2 polygons e.g. the routes / part polygons of one inside or
        /// outside the other.
        /// </summary>
        /// <param name="Poly1">The first polygon.</param> 
        /// <param name="bP1RoutesInside">True if routes inside the second polygon are 
        /// required for the first polygon.</param> 
        /// <param name="Poly2">The second polygon.</param> 
        /// <param name="bP2RoutesInside">True if routes inside the first polygon are 
        /// required for the second polygon.</param> 
        /// <param name="Routes1">Output. Set of lines for the first polygon.</param> 
        /// <param name="Routes2">Output. Set of lines for the second polygon.</param> 
	    public static void GetRoutes(C2DPolyBase Poly1, bool bP1RoutesInside, 
				    C2DPolyBase Poly2, bool bP2RoutesInside, 
				    C2DLineBaseSetSet Routes1, C2DLineBaseSetSet Routes2)
        {
            // Set up a collection of intersected points, and corresponding indexes.
            C2DPointSet IntPoints = new C2DPointSet();
            List<int> Indexes1 = new List<int>();
            List<int> Indexes2 = new List<int>();
            // Use the line collections in each shape to find the intersections between them.
            Poly1.Lines.GetIntersections(Poly2.Lines, IntPoints,
                                                Indexes1, Indexes2,
                                        Poly1.BoundingRect, Poly2.BoundingRect);
            // Make a copy of the point set because this will be sorted by line index in the 
            // Get routes function later. We need an unsorted set for each polygon.
            C2DPointSet IntPointsCopy = new C2DPointSet();
            IntPointsCopy.MakeCopy(IntPoints);

            // Find out whether the first poly starts inside the second.
            bool bP1StartInside = Poly2.Contains(Poly1.Lines[0].GetPointFrom());
            // Find out if poly 2 starts inside poly 1.
            bool bP2StartInside = Poly1.Contains(Poly2.Lines[0].GetPointFrom());

            if (IntPoints.Count == 0 && !bP1StartInside && !bP2StartInside)
                return;	// No interaction between the 2.

            // Get the routes of poly 1 inside / outside the other, passing the unsorted
            // intersection points and polygon1 intersection indexes.
            Poly1.GetRoutes(IntPoints, Indexes1, Routes1, bP1StartInside, bP1RoutesInside);
            // Do the same for poly 2 but pass it the unsorted copy of the intersection points
            // So that they correspond to the indexes.
            Poly2.GetRoutes(IntPointsCopy, Indexes2, Routes2, bP2StartInside, bP2RoutesInside);
        }
        /// <summary>
        /// True if this overlaps the other.
        /// </summary>
        /// <param name="Other">The other polygon.</param>
        public bool Overlaps(C2DPolyBase Other)
        {
            if (Lines.Count == 0 || Other.Lines.Count == 0)
                return false;

            if (Other.Contains(Lines[0].GetPointTo()))
                return true;

            if (Crosses(Other))
                return true;

            return (this.Contains(Other.Lines[0].GetPointTo()));
        }
        /// <summary>
        /// Distance of the poly from the shape. 
        /// </summary> 
        /// <param name="Other">The other polygon test.</param> 
        /// <param name="ptOnThis">Output. The closest point on this.</param> 
        /// <param name="ptOnOther">The closest point on the other.</param> 
        public double Distance(C2DPolyBase Other, C2DPoint ptOnThis, C2DPoint ptOnOther)
        {
	        if (Lines.Count == 0)
		        return 0;

	        if (Other.Lines.Count == 0)
		        return 0;

	        if (Other.LineRects.Count != Other.Lines.Count)
		        return 0;

	        if (Lines.Count != LineRects.Count)
		        return 0;

	        // First we find the closest line rect to the other's bounding rectangle.
	        int usThisClosestLineGuess = 0;
	        C2DRect OtherBoundingRect = Other.BoundingRect;
	        double dClosestDist = LineRects[0].Distance(OtherBoundingRect);
	        for (int i = 1; i < LineRects.Count; i++)
	        {
		        double dDist = LineRects[i].Distance(OtherBoundingRect);
		        if (dDist < dClosestDist)
		        {
			        dClosestDist = dDist;
			        usThisClosestLineGuess = i;
		        }
	        }
	        // Now cycle through all the other poly's line rects to find the closest to the
	        // guessed at closest line on this.
	        int usOtherClosestLineGuess = 0;
	        dClosestDist = Other.LineRects[0].Distance(LineRects[usThisClosestLineGuess]);
	        for (int j = 1; j < Other.LineRects.Count; j++)
	        {
		        double dDist = Other.LineRects[j].Distance(LineRects[usThisClosestLineGuess]);
		        if (dDist < dClosestDist)
		        {
			        dClosestDist = dDist;
			        usOtherClosestLineGuess = j;
		        }
	        }

	        // Now we have a guess at the 2 closest lines.
	        double dMinDistGuess = Lines[usThisClosestLineGuess].Distance(
							        Other.Lines[usOtherClosestLineGuess],
							        ptOnThis,
							        ptOnOther);
	        // If its 0 then return 0.
	        if (dMinDistGuess == 0)
		        return 0;

	        C2DPoint ptOnThisTemp = new C2DPoint();
	        C2DPoint ptOnOtherTemp = new C2DPoint();

	        // Now go through all of our line rects and only check further if they are closer
	        // to the other's bounding rect than the min guess.
	        for (int i = 0; i < Lines.Count; i++)
	        {
		        if (LineRects[i].Distance( OtherBoundingRect ) <  dMinDistGuess)
		        {
			        for (  int j = 0 ; j < Other.Lines.Count ; j++)
			        {
				        double dDist = Lines[i].Distance(Other.Lines[j],
													        ptOnThisTemp,
													        ptOnOtherTemp);
        				
				        if (dDist < dMinDistGuess)
				        {	
						    ptOnThis.Set(ptOnThisTemp);
					        ptOnOther.Set(ptOnOtherTemp);

					        if (dDist == 0)
						        return 0;

					        dMinDistGuess = dDist; 
				        }
			        }
		        }
	        }

	        // if we are here, there is no intersection but the other could be inside this or vice-versa
	        if ( BoundingRect.Contains(Other.BoundingRect)
		        && Contains(ptOnOtherTemp)  )
	        {
		        dMinDistGuess *= -1.0;
	        }
	        else if ( Other.BoundingRect.Contains(BoundingRect)
		        && Other.Contains( ptOnThisTemp ))
	        {
		        dMinDistGuess *= -1.0;
	        }

	        return dMinDistGuess;
        }
        /// <summary>
        /// Distance of the poly from the shape.
        /// </summary>
        /// <param name="Other">The other polygon test.</param>
        /// <param name="ptOnThis">Output. The closest point on this.</param>
        /// <param name="ptOnOther">The closest point on the other.</param>
        public double Distance(C2DPolyBase Other, C2DPoint ptOnThis, C2DPoint ptOnOther)
        {
            if (Lines.Count == 0)
            {
                return(0);
            }

            if (Other.Lines.Count == 0)
            {
                return(0);
            }

            if (Other.LineRects.Count != Other.Lines.Count)
            {
                return(0);
            }

            if (Lines.Count != LineRects.Count)
            {
                return(0);
            }

            // First we find the closest line rect to the other's bounding rectangle.
            var    usThisClosestLineGuess = 0;
            var    OtherBoundingRect      = Other.BoundingRect;
            double dClosestDist           = LineRects[0].Distance(OtherBoundingRect);

            for (var i = 1; i < LineRects.Count; i++)
            {
                double dDist = LineRects[i].Distance(OtherBoundingRect);
                if (dDist < dClosestDist)
                {
                    dClosestDist           = dDist;
                    usThisClosestLineGuess = i;
                }
            }
            // Now cycle through all the other poly's line rects to find the closest to the
            // guessed at closest line on this.
            var usOtherClosestLineGuess = 0;

            dClosestDist = Other.LineRects[0].Distance(LineRects[usThisClosestLineGuess]);
            for (var j = 1; j < Other.LineRects.Count; j++)
            {
                double dDist = Other.LineRects[j].Distance(LineRects[usThisClosestLineGuess]);
                if (dDist < dClosestDist)
                {
                    dClosestDist            = dDist;
                    usOtherClosestLineGuess = j;
                }
            }

            // Now we have a guess at the 2 closest lines.
            double dMinDistGuess = Lines[usThisClosestLineGuess].Distance(
                Other.Lines[usOtherClosestLineGuess],
                ptOnThis,
                ptOnOther);

            // If its 0 then return 0.
            if (dMinDistGuess == 0)
            {
                return(0);
            }

            var ptOnThisTemp  = new C2DPoint();
            var ptOnOtherTemp = new C2DPoint();

            // Now go through all of our line rects and only check further if they are closer
            // to the other's bounding rect than the min guess.
            for (var i = 0; i < Lines.Count; i++)
            {
                if (LineRects[i].Distance(OtherBoundingRect) < dMinDistGuess)
                {
                    for (var j = 0; j < Other.Lines.Count; j++)
                    {
                        double dDist = Lines[i].Distance(Other.Lines[j],
                                                         ptOnThisTemp,
                                                         ptOnOtherTemp);

                        if (dDist < dMinDistGuess)
                        {
                            ptOnThis.Set(ptOnThisTemp);
                            ptOnOther.Set(ptOnOtherTemp);

                            if (dDist == 0)
                            {
                                return(0);
                            }

                            dMinDistGuess = dDist;
                        }
                    }
                }
            }

            // if we are here, there is no intersection but the other could be inside this or vice-versa
            if (BoundingRect.Contains(Other.BoundingRect) &&
                Contains(ptOnOtherTemp))
            {
                dMinDistGuess *= -1.0;
            }
            else if (Other.BoundingRect.Contains(BoundingRect) &&
                     Other.Contains(ptOnThisTemp))
            {
                dMinDistGuess *= -1.0;
            }

            return(dMinDistGuess);
        }
        /// <summary>
        /// Function to convert polygons to complex polygons. Assigning holes to those that are contained.
        /// The set of holed polygons will be filled from the set of simple polygons.
        /// </summary>
        /// <param name="HoledPolys">Holed polygon set.</param>
        /// <param name="Polygons">Simple polygon set.</param>
        public static void PolygonsToHoledPolygons(List <C2DHoledPolyBase> HoledPolys,
                                                   List <C2DPolyBase> Polygons)
        {
            List <C2DPolyBase>      Unmatched     = new List <C2DPolyBase>();
            List <C2DHoledPolyBase> NewHoledPolys = new List <C2DHoledPolyBase>();

            for (int i = Polygons.Count - 1; i >= 0; i--)
            {
                bool bMatched = false;

                C2DPolyBase pPoly = Polygons[i];
                Polygons.RemoveAt(i);

                // Cycle through the newly created polygons to see if it's a hole.
                for (int p = 0; p < NewHoledPolys.Count; p++)
                {
                    if (NewHoledPolys[p].Rim.Contains(pPoly.Lines[0].GetPointFrom()))
                    {
                        NewHoledPolys[p].AddHole(pPoly);
                        bMatched = true;
                        break;
                    }
                }
                // If its not then compare it to all the other unknowns.
                if (!bMatched)
                {
                    int u = 0;

                    bool bKnownRim = false;

                    while (u < Unmatched.Count)
                    {
                        if (!bKnownRim && Unmatched[u].Contains(pPoly.Lines[0].GetPointFrom()))
                        {
                            // This is a hole.
                            NewHoledPolys.Add(new C2DHoledPolyBase());
                            NewHoledPolys[NewHoledPolys.Count - 1].Rim = Unmatched[u];
                            Unmatched.RemoveAt(u);
                            NewHoledPolys[NewHoledPolys.Count - 1].AddHole(pPoly);
                            bMatched = true;
                            break;
                        }
                        else if (pPoly.Contains(Unmatched[u].Lines[0].GetPointFrom()))
                        {
                            //	int nCount = OverlapPolygons->GetCount();
                            // This is a rim.
                            if (!bKnownRim)
                            {
                                // If we haven't alreay worked this out then record that its a rim
                                // and set up the new polygon.
                                bKnownRim = true;
                                NewHoledPolys.Add(new C2DHoledPolyBase());
                                NewHoledPolys[NewHoledPolys.Count - 1].Rim = pPoly;
                                NewHoledPolys[NewHoledPolys.Count - 1].AddHole(Unmatched[u]);
                                Unmatched.RemoveAt(u);
                            }
                            else
                            {
                                // We already worked out this was a rim so it must be the last polygon.
                                NewHoledPolys[NewHoledPolys.Count - 1].AddHole(Unmatched[u]);
                                Unmatched.RemoveAt(u);
                            }
                            // Record that its been matched.
                            bMatched = true;
                        }
                        else
                        {
                            // Only if there was no match do we increment the counter.
                            u++;
                        }
                    }
                }

                if (!bMatched)
                {
                    Unmatched.Add(pPoly);
                }
            }

            for (int i = 0; i < Unmatched.Count; i++)
            {
                C2DHoledPolyBase NewHoled = new C2DHoledPolyBase();
                NewHoled.Rim = Unmatched[i];
                HoledPolys.Add(NewHoled);
            }

            HoledPolys.AddRange(NewHoledPolys);
        }