using System.Collections; using Core.Gis.GeoApi.Geometries; using Core.GIS.NetTopologySuite.Algorithm; using Core.GIS.NetTopologySuite.Geometries; using Core.GIS.NetTopologySuite.Utilities; namespace Core.GIS.NetTopologySuite.GeometriesGraph { /// /// /// public abstract class EdgeRing { /// /// The directed edge which starts the list of edges for this EdgeRing. /// protected DirectedEdge startDe; /// /// /// protected IGeometryFactory geometryFactory; private int maxNodeDegree = -1; private readonly IList edges = new ArrayList(); // the DirectedEdges making up this EdgeRing private readonly IList pts = new ArrayList(); private readonly Label label = new Label(Locations.Null); // label stores the locations of each point on the face surrounded by this ring private EdgeRing shell; // if non-null, the ring is a hole and this EdgeRing is its containing shell private readonly ArrayList holes = new ArrayList(); // a list of EdgeRings which are holes in this EdgeRing /// /// /// /// /// public EdgeRing(DirectedEdge start, IGeometryFactory geometryFactory) { this.geometryFactory = geometryFactory; ComputePoints(start); ComputeRing(); } /// /// /// public bool IsIsolated { get { return label.GeometryCount == 1; } } /// /// /// public bool IsHole { get; private set; } /// /// /// public ILinearRing LinearRing { get; private set; } /// /// /// public Label Label { get { return label; } } /// /// /// public bool IsShell { get { return shell == null; } } /// /// /// public EdgeRing Shell { get { return shell; } set { shell = value; if (value != null) { shell.AddHole(this); } } } /// /// Returns the list of DirectedEdges that make up this EdgeRing. /// public IList Edges { get { return edges; } } /// /// /// public int MaxNodeDegree { get { if (maxNodeDegree < 0) { ComputeMaxNodeDegree(); } return maxNodeDegree; } } /// /// /// /// /// public ICoordinate GetCoordinate(int i) { return (ICoordinate) pts[i]; } /// /// /// /// public void AddHole(EdgeRing ring) { holes.Add(ring); } /// /// /// /// /// public IPolygon ToPolygon(IGeometryFactory geometryFactory) { ILinearRing[] holeLR = new ILinearRing[holes.Count]; for (int i = 0; i < holes.Count; i++) { holeLR[i] = ((EdgeRing) holes[i]).LinearRing; } IPolygon poly = geometryFactory.CreatePolygon(LinearRing, holeLR); return poly; } /// /// Compute a LinearRing from the point list previously collected. /// Test if the ring is a hole (i.e. if it is CCW) and set the hole flag /// accordingly. /// public void ComputeRing() { if (LinearRing != null) { return; // don't compute more than once } ICoordinate[] coord = new ICoordinate[pts.Count]; for (int i = 0; i < pts.Count; i++) { coord[i] = (ICoordinate) pts[i]; } LinearRing = geometryFactory.CreateLinearRing(coord); IsHole = CGAlgorithms.IsCCW(LinearRing.Coordinates); } /// /// /// /// /// public abstract DirectedEdge GetNext(DirectedEdge de); /// /// /// /// /// public abstract void SetEdgeRing(DirectedEdge de, EdgeRing er); /// /// /// public void SetInResult() { DirectedEdge de = startDe; do { de.Edge.InResult = true; de = de.Next; } while (de != startDe); } /// /// This method will cause the ring to be computed. /// It will also check any holes, if they have been assigned. /// /// public bool ContainsPoint(ICoordinate p) { ILinearRing shell = LinearRing; IEnvelope env = shell.EnvelopeInternal; if (!env.Contains(p)) { return false; } if (!CGAlgorithms.IsPointInRing(p, shell.Coordinates)) { return false; } for (IEnumerator i = holes.GetEnumerator(); i.MoveNext();) { EdgeRing hole = (EdgeRing) i.Current; if (hole.ContainsPoint(p)) { return false; } } return true; } /// /// Collect all the points from the DirectedEdges of this ring into a contiguous list. /// /// protected void ComputePoints(DirectedEdge start) { startDe = start; DirectedEdge de = start; bool isFirstEdge = true; do { Assert.IsTrue(de != null, "found null Directed Edge"); if (de.EdgeRing == this) { throw new TopologyException("Directed Edge visited twice during ring-building at " + de.Coordinate); } edges.Add(de); Label label = de.Label; Assert.IsTrue(label.IsArea()); MergeLabel(label); AddPoints(de.Edge, de.IsForward, isFirstEdge); isFirstEdge = false; SetEdgeRing(de, this); de = GetNext(de); } while (de != startDe); } /// /// /// /// protected void MergeLabel(Label deLabel) { MergeLabel(deLabel, 0); MergeLabel(deLabel, 1); } /// /// Merge the RHS label from a DirectedEdge into the label for this EdgeRing. /// The DirectedEdge label may be null. This is acceptable - it results /// from a node which is NOT an intersection node between the Geometries /// (e.g. the end node of a LinearRing). In this case the DirectedEdge label /// does not contribute any information to the overall labelling, and is simply skipped. /// /// /// protected void MergeLabel(Label deLabel, int geomIndex) { Locations loc = deLabel.GetLocation(geomIndex, Positions.Right); // no information to be had from this label if (loc == Locations.Null) { return; } // if there is no current RHS value, set it if (label.GetLocation(geomIndex) == Locations.Null) { label.SetLocation(geomIndex, loc); return; } } /// /// /// /// /// /// protected void AddPoints(Edge edge, bool isForward, bool isFirstEdge) { ICoordinate[] edgePts = edge.Coordinates; if (isForward) { int startIndex = 1; if (isFirstEdge) { startIndex = 0; } for (int i = startIndex; i < edgePts.Length; i++) { pts.Add(edgePts[i]); } } else { // is backward int startIndex = edgePts.Length - 2; if (isFirstEdge) { startIndex = edgePts.Length - 1; } for (int i = startIndex; i >= 0; i--) { pts.Add(edgePts[i]); } } } /// /// /// private void ComputeMaxNodeDegree() { maxNodeDegree = 0; DirectedEdge de = startDe; do { Node node = de.Node; int degree = ((DirectedEdgeStar) node.Edges).GetOutgoingDegree(this); if (degree > maxNodeDegree) { maxNodeDegree = degree; } de = GetNext(de); } while (de != startDe); maxNodeDegree *= 2; } } }