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 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 simple iteration over the line segments. /// 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 SimpleSnapRounder : INoder { private readonly double scaleFactor; private readonly LineIntersector li = null; private IList nodedSegStrings = null; /// /// Initializes a new instance of the class. /// /// The to use. public SimpleSnapRounder(PrecisionModel pm) { li = new RobustLineIntersector(); li.PrecisionModel = pm; scaleFactor = pm.Scale; } /// /// Computes nodes introduced as a result of /// snapping segments to vertices of other segments. /// /// public void ComputeVertexSnaps(IList edges) { foreach (SegmentString edge0 in edges) { foreach (SegmentString edge1 in edges) { ComputeVertexSnaps(edge0, edge1); } } } /// /// Adds a new node (equal to the snap pt) to the segment /// if the segment passes through the hot pixel. /// /// /// /// /// public static bool AddSnappedNode(HotPixel hotPix, SegmentString segStr, int segIndex) { ICoordinate p0 = segStr.GetCoordinate(segIndex); ICoordinate p1 = segStr.GetCoordinate(segIndex + 1); if (hotPix.Intersects(p0, p1)) { segStr.AddIntersection(hotPix.Coordinate, segIndex); return true; } return false; } /// /// 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) { nodedSegStrings = inputSegmentStrings; 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); ComputeSnaps(segStrings, intersections); ComputeVertexSnaps(segStrings); } /// /// Computes all interior intersections in the collection of s, /// and returns their s. /// Does NOT node the segStrings. /// /// /// /// A list of s for the intersections. private IList FindInteriorIntersections(IList segStrings, LineIntersector li) { IntersectionFinderAdder intFinderAdder = new IntersectionFinderAdder(li); SinglePassNoder noder = new MCIndexNoder(intFinderAdder); noder.ComputeNodes(segStrings); return intFinderAdder.InteriorIntersections; } /// /// Computes nodes introduced as a result of snapping segments to snap points (hot pixels). /// /// /// private void ComputeSnaps(IList segStrings, IList snapPts) { foreach (SegmentString ss in segStrings) { ComputeSnaps(ss, snapPts); } } /// /// /// /// /// private void ComputeSnaps(SegmentString ss, IList snapPts) { foreach (ICoordinate snapPt in snapPts) { HotPixel hotPixel = new HotPixel(snapPt, scaleFactor, li); for (int i = 0; i < ss.Count - 1; i++) { AddSnappedNode(hotPixel, ss, i); } } } /// /// Performs a brute-force comparison of every segment in each . /// This has n^2 performance. /// /// /// private void ComputeVertexSnaps(SegmentString e0, SegmentString e1) { ICoordinate[] pts0 = e0.Coordinates; ICoordinate[] pts1 = e1.Coordinates; for (int i0 = 0; i0 < pts0.Length - 1; i0++) { HotPixel hotPixel = new HotPixel(pts0[i0], scaleFactor, li); for (int i1 = 0; i1 < pts1.Length - 1; i1++) { // don't snap a vertex to itself if (e0 == e1) { if (i0 == i1) { continue; } } bool isNodeAdded = AddSnappedNode(hotPixel, e1, i1); // if a node is created for a vertex, that vertex must be noded too if (isNodeAdded) { e0.AddIntersection(pts0[i0], i0); } } } } } }