/// <summary>
        /// True if the two segments intersect
        /// </summary>
        /// <param name="that">The other segment</param>
        /// <returns></returns>
        internal bool Intersects(OverlayLineSegment that)
        {
            //Console.WriteLine("Checking intersection of THIS segment " + this.ToString());
            //Console.WriteLine("with THAT segment " + that.ToString());
            // Quick check to see if the bounding box of either line segment intersects.
            //if (BoundingBox.IntersectsWith(that.BoundingBox))
            //{
            // If the bounding boxes DO intersect, the segments themselves MAY intersect

            // If the lines overlap, they do intersect
            if (Overlaps(that))
                return true;

            // If the lines do not overlap, and the bounding box of this point
            // contains the intersection point, then they DO intersect
            var intersectionPoint = IntersectionPoint(that);
            //Console.WriteLine("Intersection point calculated to be ({0}, {1})", IntersectionPoint.Latitude, IntersectionPoint.Longitude);
            if ((intersectionPoint != null) && (GeoRect.Contains(intersectionPoint) && that.GeoRect.Contains(intersectionPoint)))
                return true;
            //if (IntersectionPoint.Longitude < BoundingBox.Left)
            //    Console.WriteLine("Intersection point is LEFT of the bounding box by {0}", BoundingBox.Left - IntersectionPoint.Longitude);
            //if (IntersectionPoint.Longitude > BoundingBox.Right)
            //    Console.WriteLine("Intersection point is RIGHT of the bounding box by {0}", IntersectionPoint.Longitude - BoundingBox.Right);
            //if (IntersectionPoint.Latitude > BoundingBox.Top)
            //    Console.WriteLine("Intersection point is ABOVE the bounding box by {0}", IntersectionPoint.Latitude - BoundingBox.Top);
            //if (IntersectionPoint.Latitude < BoundingBox.Bottom)
            //    Console.WriteLine("Intersection point is BELOW the bounding box by {0}", BoundingBox.Bottom - IntersectionPoint.Latitude);
            //}
            // If none of the above conditions were previously met, the segments DO NOT intersect
            return false;
        }
        public Geo IntersectionPoint(OverlayLineSegment that)
        {
            if (IsParallelTo(that))
            {
                if (IsColinearWith(that))
                {
                    if (GeoRect.Contains(that[0])) return that[0];
                    if (GeoRect.Contains(that[1])) return that[1];
                    if (that.GeoRect.Contains(this[0])) return this[0];
                    if (that.GeoRect.Contains(this[1])) return this[1];
                }
                return null;
                //throw new GeometricException(
                //    "OverlayLineSegment: Lines are parallel but not colinear, they do not intersect");
            }
            // After we pass the above tests, we know the lines represented by our segments DO intersect somewhere
            // Now we will figure out exactly where.

            if (IsVertical)
                return new Geo(that.Y(this[0].Longitude), this[0].Longitude);
            if (that.IsVertical)
                return new Geo(Y(that[0].Longitude), that[0].Longitude);
            //if (this.IsHorizontal)
            //    return new PointF(that.X(this.Points[0].Y), this.Points[0].Y);

            // Algebra to solve for the x-coordinate intersection point
            // set the y-coordinates equal to each other:
            // this.m*x + this.b = that.m*x + that.b
            // subtract that.m*x from both sides, yielding:
            // (this.m - that.m)*x + this.b = that.b
            // subtract this.b from both sides, yielding:
            // (this.m - that.m)*x = that.b - this.b
            // divide both sides by this.m - that.m, yielding:
            // x = (that.b - this.b) / (this.m - that.m)
            var xIntersect = (that._b - _b)/(_m - that._m);

            // now that we have xIntersect, we solve for y by plugging in xIntersect into
            // either one of our line equations.  Arbitrarily, we'll pick the first one.
            var yIntersect = Y(xIntersect);

            return new Geo(yIntersect, xIntersect);

            //return new PointF((float)xIntersect, (float)yIntersect);
        }
 /// <summary>
 /// True if the two segments are parallel to each other
 /// </summary>
 /// <param name="that">The other segment</param>
 /// <returns></returns>
 internal bool IsParallelTo(OverlayLineSegment that)
 {
     if (IsVertical && that.IsVertical)
         return true;
     if (Math.Abs(_m - that._m) < 0.0001)
         return true;
     return false;
 }
 /// <summary>
 /// True if the two segments are on the same line (not necessarily overlapping)
 /// </summary>
 /// <param name="that">The other segment</param>
 /// <returns></returns>
 internal bool IsColinearWith(OverlayLineSegment that)
 {
     if (IsVertical && that.IsVertical)
     {
         if (Math.Abs(_geos[0].Longitude - that._geos[0].Longitude) < 0.0001)
             return true;
     }
     if (IsParallelTo(that))
     {
         if (Math.Abs(_b - that._b) < 0.0001)
             return true;
     }
     return false;
 }
        /// <summary>
        /// True if the two segments overlap
        /// </summary>
        /// <param name="that">The other segment</param>
        /// <returns></returns>
        internal bool Overlaps(OverlayLineSegment that)
        {
            // For two segments to overlap, they must first be colinear
            if (IsColinearWith(that))
            {
                // If they are colinear, check if our bounding box contains either of the other segment's endpoints
                if (GeoRect.Contains(that._geos[0]) ||
                    (GeoRect.Contains(that._geos[1])))
                    // If it does, we overlap the other segment
                    return true;

                // If it doesn't, then check if the other segment overlaps us.  This can happen if the other segment
                // completely contains us, and is also longer than us. If that turns out to be the case, then one or
                // both of our endpoints will be contained in the other segment's bounding box.
                if (that.GeoRect.Contains(_geos[0]) ||
                    (that.GeoRect.Contains(_geos[1])))
                    // If it does, we overlap the other segment
                    return true;
            }
            return false;
        }
        /// <summary>
        /// Takes a start location and a proposed end location, and returns a reflected end location
        /// If the proposed end location is outside of the current figure, the end location is reflected
        /// by the normal to the intersecting segment, and returned to the caller.  If the proposed end
        /// location is inside the current figure, then it is simply returned to the caller.
        /// </summary>
        /// <param name="startLocation">Start location for the current proposed move</param>
        /// <param name="proposedEndLocation">End location for the current proposed move</param>
        /// <param name="proposedCourse"> </param>
        /// <returns>Actual end location that remains inside the figure, which may be reflected from the
        /// proposed end location provided if the proposed end location lies outside the figure</returns>
        public override Geo Reflect(Geo startLocation, Geo proposedEndLocation, out Course proposedCourse)
        {
            //Geo start = new Geo(StartLocation);
            //Geo end = new Geo(ProposedEndLocation);
#if MATLAB_DEBUG_OUTPUT
            MatlabDumpVertices();
#endif
            proposedCourse = new Course(startLocation, proposedEndLocation);
            if (Contains(proposedEndLocation))
                return proposedEndLocation;

            //start.Move(ProposedCourse.ReciprocalDegrees, 1000);
            //end.Move(ProposedCourse.Degrees, 1000);
#if MATLAB_DEBUG_OUTPUT
            Console.WriteLine("Course=zeros(2,2);\nCourse(1,:)=[{0} {1}];\nCourse(2,:)=[{2} {3}];",
                startLocation.Longitude, startLocation.Latitude, 
                proposedEndLocation.Longitude, proposedEndLocation.Latitude);
#endif
            
            var proposedCourseSegment = new OverlayLineSegment(startLocation, proposedEndLocation);
            for (var i = 0; i < Segments.Count(); i++)
            {
                var intersect = proposedCourseSegment.IntersectionPoint(Segments[i]);
#if MATLAB_DEBUG_OUTPUT
                Console.WriteLine("Intersects({0},:)=[{1} {2}];", i + 1, intersect.Longitude, intersect.Latitude);
#endif
                //if (intersect == null) continue;
                if (!proposedCourseSegment.Contains(intersect) || !Segments[i].Contains(intersect)) continue;
                proposedCourse = proposedCourse.Reflect(Normals[i]);
                var distance = startLocation.DistanceKilometers(proposedEndLocation);
                var result = startLocation.Offset(Geo.KilometersToRadians(distance), proposedCourse.Radians);
                return result;
            }
#if MATLAB_DEBUG_OUTPUT
            Console.WriteLine("figure;");
            Console.WriteLine("plot(Vertices(:, 1), Vertices(:, 2), 'g-*');");
            Console.WriteLine("hold on;");
            Console.WriteLine("plot(Course(:, 1), Course(:, 2), 'r-o');");
            Console.WriteLine("plot(Intersects(:, 1), Intersects(:, 2), 'bx');");
            Console.WriteLine("legend('Area Boundary', 'Course Segment under review', 'Calculated intersection points');");
#endif
            throw new GeometricException("The proposed course didn't intersect with any of the edges of the figure");
        }