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