Index: src/Common/NetTopologySuite/GeometriesGraph/GeometryGraph.cs
===================================================================
diff -u -r8f6ae890fed8e8eae3a32f9c0498a10f82e0ddf9 -r5fc71a385897af92ccb092f2f969b5709afab85a
--- src/Common/NetTopologySuite/GeometriesGraph/GeometryGraph.cs (.../GeometryGraph.cs) (revision 8f6ae890fed8e8eae3a32f9c0498a10f82e0ddf9)
+++ src/Common/NetTopologySuite/GeometriesGraph/GeometryGraph.cs (.../GeometryGraph.cs) (revision 5fc71a385897af92ccb092f2f969b5709afab85a)
@@ -13,108 +13,53 @@
///
public class GeometryGraph : PlanarGraph
{
- ///
- /// This method implements the Boundary Determination Rule
- /// for determining whether
- /// a component (node or edge) that appears multiple times in elements
- /// of a MultiGeometry is in the boundary or the interior of the Geometry.
- /// The SFS uses the "Mod-2 Rule", which this function implements.
- /// An alternative (and possibly more intuitive) rule would be
- /// the "At Most One Rule":
- /// isInBoundary = (componentCount == 1)
- ///
- public static bool IsInBoundary(int boundaryCount)
- {
- // the "Mod-2 Rule"
- return boundaryCount % 2 == 1;
- }
-
///
- ///
- ///
- ///
- ///
- public static Locations DetermineBoundary(int boundaryCount)
- {
- return IsInBoundary(boundaryCount) ? Locations.Boundary : Locations.Interior;
- }
-
- private IGeometry parentGeom;
-
- ///
/// The lineEdgeMap is a map of the linestring components of the
/// parentGeometry to the edges which are derived from them.
/// This is used to efficiently perform findEdge queries
///
- private IDictionary lineEdgeMap = new Hashtable();
+ private readonly IDictionary lineEdgeMap = new Hashtable();
///
/// If this flag is true, the Boundary Determination Rule will used when deciding
/// whether nodes are in the boundary or not
///
private bool useBoundaryDeterminationRule = false;
- private int argIndex; // the index of this point as an argument to a spatial function (used for labelling)
+ private readonly int argIndex; // the index of this point as an argument to a spatial function (used for labelling)
private ICollection boundaryNodes;
- private bool hasTooFewPoints = false;
- private ICoordinate invalidPoint = null;
///
///
///
- ///
- private EdgeSetIntersector CreateEdgeSetIntersector()
- {
- // various options for computing intersections, from slowest to fastest
- return new SimpleMCSweepLineIntersector();
- }
-
- ///
- ///
- ///
///
///
public GeometryGraph(int argIndex, IGeometry parentGeom)
{
+ InvalidPoint = null;
+ HasTooFewPoints = false;
this.argIndex = argIndex;
- this.parentGeom = parentGeom;
- if (parentGeom != null)
+ Geometry = parentGeom;
+ if (parentGeom != null)
+ {
Add(parentGeom);
-
+ }
}
///
///
///
- public bool HasTooFewPoints
- {
- get
- {
- return hasTooFewPoints;
- }
- }
+ public bool HasTooFewPoints { get; private set; }
///
///
///
- public ICoordinate InvalidPoint
- {
- get
- {
- return invalidPoint;
- }
- }
+ public ICoordinate InvalidPoint { get; private set; }
///
///
///
- public IGeometry Geometry
- {
- get
- {
- return parentGeom;
- }
- }
+ public IGeometry Geometry { get; private set; }
///
///
@@ -124,21 +69,49 @@
get
{
if (boundaryNodes == null)
+ {
boundaryNodes = nodes.GetBoundaryNodes(argIndex);
+ }
return boundaryNodes;
}
}
+ ///
+ /// This method implements the Boundary Determination Rule
+ /// for determining whether
+ /// a component (node or edge) that appears multiple times in elements
+ /// of a MultiGeometry is in the boundary or the interior of the Geometry.
+ /// The SFS uses the "Mod-2 Rule", which this function implements.
+ /// An alternative (and possibly more intuitive) rule would be
+ /// the "At Most One Rule":
+ /// isInBoundary = (componentCount == 1)
+ ///
+ public static bool IsInBoundary(int boundaryCount)
+ {
+ // the "Mod-2 Rule"
+ return boundaryCount%2 == 1;
+ }
+
///
///
///
+ ///
///
+ public static Locations DetermineBoundary(int boundaryCount)
+ {
+ return IsInBoundary(boundaryCount) ? Locations.Boundary : Locations.Interior;
+ }
+
+ ///
+ ///
+ ///
+ ///
public ICoordinate[] GetBoundaryPoints()
{
ICollection coll = BoundaryNodes;
ICoordinate[] pts = new ICoordinate[coll.Count];
int i = 0;
- for (IEnumerator it = coll.GetEnumerator(); it.MoveNext(); )
+ for (IEnumerator it = coll.GetEnumerator(); it.MoveNext();)
{
Node node = (Node) it.Current;
pts[i++] = (ICoordinate) node.Coordinate.Clone();
@@ -162,44 +135,141 @@
///
public void ComputeSplitEdges(IList edgelist)
{
- for (IEnumerator i = edges.GetEnumerator(); i.MoveNext(); )
- {
- Edge e = (Edge) i.Current;
+ for (IEnumerator i = edges.GetEnumerator(); i.MoveNext();)
+ {
+ Edge e = (Edge) i.Current;
e.EdgeIntersectionList.AddSplitEdges(edgelist);
}
}
+ ///
+ /// Add an Edge computed externally. The label on the Edge is assumed
+ /// to be correct.
+ ///
+ ///
+ public void AddEdge(Edge e)
+ {
+ InsertEdge(e);
+ ICoordinate[] coord = e.Coordinates;
+ // insert the endpoint as a node, to mark that it is on the boundary
+ InsertPoint(argIndex, coord[0], Locations.Boundary);
+ InsertPoint(argIndex, coord[coord.Length - 1], Locations.Boundary);
+ }
+
///
+ /// Add a point computed externally. The point is assumed to be a
+ /// Point Geometry part, which has a location of INTERIOR.
+ ///
+ ///
+ public void AddPoint(ICoordinate pt)
+ {
+ InsertPoint(argIndex, pt, Locations.Interior);
+ }
+
+ ///
+ /// Compute self-nodes, taking advantage of the Geometry type to
+ /// minimize the number of intersection tests. (E.g. rings are
+ /// not tested for self-intersection, since they are assumed to be valid).
+ ///
+ /// The LineIntersector to use.
+ /// If false, intersection checks are optimized to not test rings for self-intersection.
+ /// The SegmentIntersector used, containing information about the intersections found.
+ public SegmentIntersector ComputeSelfNodes(LineIntersector li, bool computeRingSelfNodes)
+ {
+ SegmentIntersector si = new SegmentIntersector(li, true, false);
+ EdgeSetIntersector esi = CreateEdgeSetIntersector();
+ // optimized test for Polygons and Rings
+ if (!computeRingSelfNodes &&
+ (Geometry is ILinearRing || Geometry is IPolygon || Geometry is IMultiPolygon))
+ {
+ esi.ComputeIntersections(edges, si, false);
+ }
+ else
+ {
+ esi.ComputeIntersections(edges, si, true);
+ }
+ AddSelfIntersectionNodes(argIndex);
+ return si;
+ }
+
+ ///
///
///
///
+ ///
+ ///
+ ///
+ public SegmentIntersector ComputeEdgeIntersections(GeometryGraph g,
+ LineIntersector li, bool includeProper)
+ {
+ SegmentIntersector si = new SegmentIntersector(li, includeProper, true);
+ si.SetBoundaryNodes(BoundaryNodes, g.BoundaryNodes);
+ EdgeSetIntersector esi = CreateEdgeSetIntersector();
+ esi.ComputeIntersections(edges, g.edges, si);
+ return si;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ private EdgeSetIntersector CreateEdgeSetIntersector()
+ {
+ // various options for computing intersections, from slowest to fastest
+ return new SimpleMCSweepLineIntersector();
+ }
+
+ ///
+ ///
+ ///
+ ///
private void Add(IGeometry g)
{
if (g.IsEmpty)
+ {
return;
+ }
// check if this Geometry should obey the Boundary Determination Rule
// all collections except MultiPolygons obey the rule
if (g is IGeometryCollection && !(g is IMultiPolygon))
+ {
useBoundaryDeterminationRule = true;
+ }
- if (g is IPolygon)
- AddPolygon((IPolygon) g);
+ if (g is IPolygon)
+ {
+ AddPolygon((IPolygon) g);
+ }
// LineString also handles LinearRings
- else if (g is ILineString)
+ else if (g is ILineString)
+ {
AddLineString((ILineString) g);
- else if (g is IPoint)
+ }
+ else if (g is IPoint)
+ {
AddPoint((IPoint) g);
+ }
else if (g is IMultiPoint)
+ {
AddCollection((IMultiPoint) g);
- else if (g is IMultiLineString)
+ }
+ else if (g is IMultiLineString)
+ {
AddCollection((IMultiLineString) g);
+ }
else if (g is IMultiPolygon)
+ {
AddCollection((IMultiPolygon) g);
- else if (g is IGeometryCollection)
+ }
+ else if (g is IGeometryCollection)
+ {
AddCollection((IGeometryCollection) g);
- else
+ }
+ else
+ {
throw new NotSupportedException(g.GetType().FullName);
+ }
}
///
@@ -208,7 +278,7 @@
///
private void AddCollection(IGeometryCollection gc)
{
- for (int i = 0; i < gc.NumGeometries; i++)
+ for (int i = 0; i < gc.NumGeometries; i++)
{
IGeometry g = gc.GetGeometryN(i);
Add(g);
@@ -236,15 +306,15 @@
private void AddPolygonRing(ILinearRing lr, Locations cwLeft, Locations cwRight)
{
ICoordinate[] coord = CoordinateArrays.RemoveRepeatedPoints(lr.Coordinates);
- if (coord.Length < 4)
+ if (coord.Length < 4)
{
- hasTooFewPoints = true;
- invalidPoint = coord[0];
+ HasTooFewPoints = true;
+ InvalidPoint = coord[0];
return;
}
Locations left = cwLeft;
Locations right = cwRight;
- if (CGAlgorithms.IsCCW(coord))
+ if (CGAlgorithms.IsCCW(coord))
{
left = cwRight;
right = cwLeft;
@@ -264,11 +334,13 @@
{
AddPolygonRing(p.Shell, Locations.Exterior, Locations.Interior);
- for (int i = 0; i < p.NumInteriorRings; i++)
+ for (int i = 0; i < p.NumInteriorRings; i++)
+ {
// Holes are topologically labelled opposite to the shell, since
// the interior of the polygon lies on their opposite side
// (on the left, if the hole is oriented CW)
- AddPolygonRing(p.Holes[i], Locations.Interior, Locations.Exterior);
+ AddPolygonRing(p.Holes[i], Locations.Interior, Locations.Exterior);
+ }
}
///
@@ -278,16 +350,16 @@
private void AddLineString(ILineString line)
{
ICoordinate[] coord = CoordinateArrays.RemoveRepeatedPoints(line.Coordinates);
- if (coord.Length < 2)
+ if (coord.Length < 2)
{
- hasTooFewPoints = true;
- invalidPoint = coord[0];
+ HasTooFewPoints = true;
+ InvalidPoint = coord[0];
return;
}
// add the edge for the LineString
// line edges do not have locations for their left and right sides
- Edge e = new Edge(coord, new Label(argIndex, Locations.Interior));
+ Edge e = new Edge(coord, new Label(argIndex, Locations.Interior));
lineEdgeMap[line] = e;
InsertEdge(e);
@@ -301,81 +373,24 @@
InsertBoundaryPoint(argIndex, coord[coord.Length - 1]);
}
- ///
- /// Add an Edge computed externally. The label on the Edge is assumed
- /// to be correct.
- ///
- ///
- public void AddEdge(Edge e)
- {
- InsertEdge(e);
- ICoordinate[] coord = e.Coordinates;
- // insert the endpoint as a node, to mark that it is on the boundary
- InsertPoint(argIndex, coord[0], Locations.Boundary);
- InsertPoint(argIndex, coord[coord.Length - 1], Locations.Boundary);
- }
-
///
- /// Add a point computed externally. The point is assumed to be a
- /// Point Geometry part, which has a location of INTERIOR.
- ///
- ///
- public void AddPoint(ICoordinate pt)
- {
- InsertPoint(argIndex, pt, Locations.Interior);
- }
-
- ///
- /// Compute self-nodes, taking advantage of the Geometry type to
- /// minimize the number of intersection tests. (E.g. rings are
- /// not tested for self-intersection, since they are assumed to be valid).
- ///
- /// The LineIntersector to use.
- /// If false, intersection checks are optimized to not test rings for self-intersection.
- /// The SegmentIntersector used, containing information about the intersections found.
- public SegmentIntersector ComputeSelfNodes(LineIntersector li, bool computeRingSelfNodes)
- {
- SegmentIntersector si = new SegmentIntersector(li, true, false);
- EdgeSetIntersector esi = CreateEdgeSetIntersector();
- // optimized test for Polygons and Rings
- if (!computeRingSelfNodes &&
- (parentGeom is ILinearRing || parentGeom is IPolygon || parentGeom is IMultiPolygon))
- esi.ComputeIntersections(edges, si, false);
- else esi.ComputeIntersections(edges, si, true);
- AddSelfIntersectionNodes(argIndex);
- return si;
- }
-
- ///
///
///
- ///
- ///
- ///
- ///
- public SegmentIntersector ComputeEdgeIntersections(GeometryGraph g,
- LineIntersector li, bool includeProper)
- {
- SegmentIntersector si = new SegmentIntersector(li, includeProper, true);
- si.SetBoundaryNodes(BoundaryNodes, g.BoundaryNodes);
- EdgeSetIntersector esi = CreateEdgeSetIntersector();
- esi.ComputeIntersections(edges, g.edges, si);
- return si;
- }
-
- ///
- ///
- ///
///
///
///
private void InsertPoint(int argIndex, ICoordinate coord, Locations onLocation)
{
Node n = nodes.AddNode(coord);
Label lbl = n.Label;
- if (lbl == null)
- n.Label = new Label(argIndex, onLocation);
- else lbl.SetLocation(argIndex, onLocation);
+ if (lbl == null)
+ {
+ n.Label = new Label(argIndex, onLocation);
+ }
+ else
+ {
+ lbl.SetLocation(argIndex, onLocation);
+ }
}
///
@@ -394,10 +409,14 @@
int boundaryCount = 1;
// determine the current location for the point (if any)
Locations loc = Locations.Null;
- if (lbl != null)
+ if (lbl != null)
+ {
loc = lbl.GetLocation(argIndex, Positions.On);
- if (loc == Locations.Boundary)
+ }
+ if (loc == Locations.Boundary)
+ {
boundaryCount++;
+ }
// determine the boundary status of the point according to the Boundary Determination Rule
Locations newLoc = DetermineBoundary(boundaryCount);
@@ -410,11 +429,11 @@
///
private void AddSelfIntersectionNodes(int argIndex)
{
- for (IEnumerator i = edges.GetEnumerator(); i.MoveNext(); )
+ for (IEnumerator i = edges.GetEnumerator(); i.MoveNext();)
{
Edge e = (Edge) i.Current;
Locations eLoc = e.Label.GetLocation(argIndex);
- for (IEnumerator eiIt = e.EdgeIntersectionList.GetEnumerator(); eiIt.MoveNext(); )
+ for (IEnumerator eiIt = e.EdgeIntersectionList.GetEnumerator(); eiIt.MoveNext();)
{
EdgeIntersection ei = (EdgeIntersection) eiIt.Current;
AddSelfIntersectionNode(argIndex, ei.Coordinate, eLoc);
@@ -434,11 +453,18 @@
private void AddSelfIntersectionNode(int argIndex, ICoordinate coord, Locations loc)
{
// if this node is already a boundary node, don't change it
- if (IsBoundaryNode(argIndex, coord))
+ if (IsBoundaryNode(argIndex, coord))
+ {
return;
+ }
if (loc == Locations.Boundary && useBoundaryDeterminationRule)
- InsertBoundaryPoint(argIndex, coord);
- else InsertPoint(argIndex, coord, loc);
+ {
+ InsertBoundaryPoint(argIndex, coord);
+ }
+ else
+ {
+ InsertPoint(argIndex, coord, loc);
+ }
}
}
-}
+}
\ No newline at end of file