using System; using GeoAPI.Geometries; using GisSharpBlog.NetTopologySuite.Algorithm; using GisSharpBlog.NetTopologySuite.Geometries; using GisSharpBlog.NetTopologySuite.Index.Chain; namespace GisSharpBlog.NetTopologySuite.Noding { /// /// Computes the intersections between two line segments in s /// and adds them to each string. /// The is passed to a . /// The method is called whenever the /// detects that two s might intersect. /// This class is an example of the Strategy pattern. /// public class IntersectionAdder : ISegmentIntersector { /// /// /// public int NumIntersections = 0; /// /// /// public int NumInteriorIntersections = 0; /// /// /// public int NumProperIntersections = 0; /// /// /// public int NumTests = 0; /** * These variables keep track of what types of intersections were * found during ALL edges that have been intersected. */ // the proper intersection point found private readonly LineIntersector li = null; /// /// Initializes a new instance of the class. /// /// public IntersectionAdder(LineIntersector li) { HasInteriorIntersection = false; HasProperInteriorIntersection = false; HasProperIntersection = false; HasIntersection = false; ProperIntersectionPoint = null; this.li = li; } /// /// /// public LineIntersector LineIntersector { get { return li; } } /// /// Returns the proper intersection point, or null if none was found. /// public ICoordinate ProperIntersectionPoint { get; private set; } /// /// /// public bool HasIntersection { get; private set; } /// /// A proper intersection is an intersection which is interior to at least two /// line segments. Note that a proper intersection is not necessarily /// in the interior of the entire , since another edge may have /// an endpoint equal to the intersection, which according to SFS semantics /// can result in the point being on the Boundary of the . /// public bool HasProperIntersection { get; private set; } /// /// A proper interior intersection is a proper intersection which is not /// contained in the set of boundary nodes set for this . /// public bool HasProperInteriorIntersection { get; private set; } /// /// An interior intersection is an intersection which is /// in the interior of some segment. /// public bool HasInteriorIntersection { get; private set; } /// /// /// /// /// /// public static bool IsAdjacentSegments(int i1, int i2) { return Math.Abs(i1 - i2) == 1; } /// /// This method is called by clients /// of the class to process /// intersections for two segments of the being intersected. /// Note that some clients (such as s) may optimize away /// this call for segment pairs which they have determined do not intersect /// (e.g. by an disjoint envelope test). /// /// /// /// /// public void ProcessIntersections(SegmentString e0, int segIndex0, SegmentString e1, int segIndex1) { if (e0 == e1 && segIndex0 == segIndex1) { return; } NumTests++; ICoordinate p00 = e0.Coordinates[segIndex0]; ICoordinate p01 = e0.Coordinates[segIndex0 + 1]; ICoordinate p10 = e1.Coordinates[segIndex1]; ICoordinate p11 = e1.Coordinates[segIndex1 + 1]; li.ComputeIntersection(p00, p01, p10, p11); if (li.HasIntersection) { NumIntersections++; if (li.IsInteriorIntersection()) { NumInteriorIntersections++; HasInteriorIntersection = true; } // if the segments are adjacent they have at least one trivial intersection, // the shared endpoint. Don't bother adding it if it is the // only intersection. if (!IsTrivialIntersection(e0, segIndex0, e1, segIndex1)) { HasIntersection = true; e0.AddIntersections(li, segIndex0, 0); e1.AddIntersections(li, segIndex1, 1); if (li.IsProper) { NumProperIntersections++; HasProperIntersection = true; HasProperInteriorIntersection = true; } } } } /// /// A trivial intersection is an apparent self-intersection which in fact /// is simply the point shared by adjacent line segments. /// Note that closed edges require a special check for the point shared by the beginning and end segments. /// /// /// /// /// /// private bool IsTrivialIntersection(SegmentString e0, int segIndex0, SegmentString e1, int segIndex1) { if (e0 == e1) { if (li.IntersectionNum == 1) { if (IsAdjacentSegments(segIndex0, segIndex1)) { return true; } if (e0.IsClosed) { int maxSegIndex = e0.Count - 1; if ((segIndex0 == 0 && segIndex1 == maxSegIndex) || (segIndex1 == 0 && segIndex0 == maxSegIndex)) { return true; } } } } return false; } } }