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