/// <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"); }