using System; using System.Collections; using System.Diagnostics; using GeoAPI.Geometries; using GisSharpBlog.NetTopologySuite.Algorithm; using GisSharpBlog.NetTopologySuite.Geometries; namespace GisSharpBlog.NetTopologySuite.Noding.Snapround { /// /// Uses Snap Rounding to compute a rounded, /// fully noded arrangement from a set of {@link SegmentString}s. /// Implements the Snap Rounding technique described in Hobby, Guibas and Marimont, and Goodrich et al. /// Snap Rounding assumes that all vertices lie on a uniform grid /// (hence the precision model of the input must be fixed precision, /// and all the input vertices must be rounded to that precision). /// /// This implementation uses a monotone chains and a spatial index to /// speed up the intersection tests. /// This implementation appears to be fully robust using an integer precision model. /// It will function with non-integer precision models, but the /// results are not 100% guaranteed to be correctly noded. /// /// public class MCIndexSnapRounder : INoder { private LineIntersector li = null; private readonly double scaleFactor; private MCIndexNoder noder = null; private MCIndexPointSnapper pointSnapper = null; private IList nodedSegStrings = null; /// /// Initializes a new instance of the class. /// /// The to use. public MCIndexSnapRounder(PrecisionModel pm) { li = new RobustLineIntersector(); li.PrecisionModel = pm; scaleFactor = pm.Scale; } /// /// Returns a of fully noded s. /// The s have the same context as their parent. /// /// public IList GetNodedSubstrings() { return SegmentString.GetNodedSubstrings(nodedSegStrings); } /// /// Computes the noding for a collection of s. /// Some Noders may add all these nodes to the input s; /// others may only add some or none at all. /// /// public void ComputeNodes(IList inputSegmentStrings) { this.nodedSegStrings = inputSegmentStrings; noder = new MCIndexNoder(); pointSnapper = new MCIndexPointSnapper(noder.MonotoneChains, noder.Index); SnapRound(inputSegmentStrings, li); } /// /// /// /// private void CheckCorrectness(IList inputSegmentStrings) { IList resultSegStrings = SegmentString.GetNodedSubstrings(inputSegmentStrings); NodingValidator nv = new NodingValidator(resultSegStrings); try { nv.CheckValid(); } catch (Exception ex) { Trace.WriteLine(ex.ToString()); } } /// /// /// /// /// private void SnapRound(IList segStrings, LineIntersector li) { IList intersections = FindInteriorIntersections(segStrings, li); ComputeIntersectionSnaps(intersections); ComputeVertexSnaps(segStrings); } /// /// Computes all interior intersections in the collection of s, /// and returns their s. /// /// Does NOT node the segStrings. /// /// /// /// A list of Coordinates for the intersections. private IList FindInteriorIntersections(IList segStrings, LineIntersector li) { IntersectionFinderAdder intFinderAdder = new IntersectionFinderAdder(li); noder.SegmentIntersector = intFinderAdder; noder.ComputeNodes(segStrings); return intFinderAdder.InteriorIntersections; } /// /// Computes nodes introduced as a result of snapping segments to snap points (hot pixels). /// /// private void ComputeIntersectionSnaps(IList snapPts) { foreach (ICoordinate snapPt in snapPts) { HotPixel hotPixel = new HotPixel(snapPt, scaleFactor, li); pointSnapper.Snap(hotPixel); } } /// /// Computes nodes introduced as a result of /// snapping segments to vertices of other segments. /// /// public void ComputeVertexSnaps(IList edges) { foreach (SegmentString edge in edges) ComputeVertexSnaps(edge); } /// /// Performs a brute-force comparison of every segment in each . /// This has n^2 performance. /// /// private void ComputeVertexSnaps(SegmentString e) { ICoordinate[] pts0 = e.Coordinates; for(int i = 0; i < pts0.Length - 1; i++) { HotPixel hotPixel = new HotPixel(pts0[i], scaleFactor, li); bool isNodeAdded = pointSnapper.Snap(hotPixel, e, i); // if a node is created for a vertex, that vertex must be noded too if (isNodeAdded) e.AddIntersection(pts0[i], i); } } } }