/// <summary> /// Check if any shell ring has an unvisited edge. /// A shell ring is a ring which is not a hole and which has the interior /// of the parent area on the RHS. /// (Notice that there may be non-hole rings with the interior on the LHS, /// since the interior of holes will also be polygonized into CW rings /// by the <c>LinkAllDirectedEdges()</c> step). /// </summary> /// <param name="edgeRings"></param> /// <returns><c>true</c> if there is an unvisited edge in a non-hole ring.</returns> private bool HasUnvisitedShellEdge(IList edgeRings) { for (int i = 0; i < edgeRings.Count; i++) { EdgeRing er = (EdgeRing)edgeRings[i]; if (er.IsHole) { continue; } IList edges = er.Edges; DirectedEdge de = (DirectedEdge)edges[0]; // don't check CW rings which are holes if (de.Label.GetLocation(0, PositionType.Right) != LocationType.Interior) { continue; } // must have a CW ring which surrounds the INT of the area, so check all // edges have been visited for (int j = 0; j < edges.Count; j++) { de = (DirectedEdge)edges[j]; if (!de.IsVisited) { _disconnectedRingcoord = de.Coordinate; return(true); } } } return(false); }
/// <summary> /// This method will cause the ring to be computed. /// It will also check any holes, if they have been assigned. /// </summary> /// <param name="p"></param> public virtual bool ContainsPoint(Coordinate 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); }
/// <summary> /// /// </summary> /// <param name="er"></param> /// <returns></returns> public virtual int GetOutgoingDegree(EdgeRing er) { int degree = 0; for (IEnumerator it = GetEnumerator(); it.MoveNext(); ) { DirectedEdge de = (DirectedEdge)it.Current; if (de.EdgeRing == er) degree++; } return degree; }
/// <summary> /// /// </summary> /// <param name="er"></param> public virtual void LinkMinimalDirectedEdges(EdgeRing er) { // find first area edge (if any) to start linking at DirectedEdge firstOut = null; DirectedEdge incoming = null; int state = SCANNING_FOR_INCOMING; // link edges in CW order for (int i = _resultAreaEdgeList.Count - 1; i >= 0; i--) { DirectedEdge nextOut = (DirectedEdge)_resultAreaEdgeList[i]; DirectedEdge nextIn = nextOut.Sym; // record first outgoing edge, in order to link the last incoming edge if (firstOut == null && nextOut.EdgeRing == er) firstOut = nextOut; switch (state) { case SCANNING_FOR_INCOMING: if (nextIn.EdgeRing != er) continue; incoming = nextIn; state = LINKING_TO_OUTGOING; break; case LINKING_TO_OUTGOING: if (nextOut.EdgeRing != er) continue; if (incoming != null) incoming.NextMin = nextOut; state = SCANNING_FOR_INCOMING; break; default: break; } } if (state == LINKING_TO_OUTGOING) { Assert.IsTrue(firstOut != null, "found null for first outgoing dirEdge"); if (firstOut != null) { Assert.IsTrue(firstOut.EdgeRing == er, "unable to link last incoming dirEdge"); if (incoming != null) incoming.NextMin = firstOut; } } }
/// <summary> /// /// </summary> /// <param name="de"></param> /// <param name="er"></param> public abstract void SetEdgeRing(DirectedEdge de, EdgeRing er);
/// <summary> /// /// </summary> /// <param name="ring"></param> public virtual void AddHole(EdgeRing ring) { _holes.Add(ring); }
/// <summary> /// /// </summary> /// <param name="de"></param> /// <param name="er"></param> public override void SetEdgeRing(DirectedEdge de, EdgeRing er) { de.EdgeRing = er; }
/// <summary> /// Find the innermost enclosing shell EdgeRing containing the argument EdgeRing, if any. /// The innermost enclosing ring is the <i>smallest</i> enclosing ring. /// The algorithm used depends on the fact that: /// ring A contains ring B iff envelope(ring A) contains envelope(ring B). /// This routine is only safe to use if the chosen point of the hole /// is known to be properly contained in a shell /// (which is guaranteed to be the case if the hole does not touch its shell). /// </summary> /// <param name="testEr"></param> /// <param name="shellList"></param> /// <returns>Containing EdgeRing, if there is one, OR /// null if no containing EdgeRing is found.</returns> private static EdgeRing FindEdgeRingContaining(EdgeRing testEr, IEnumerable shellList) { ILinearRing teString = testEr.LinearRing; IEnvelope testEnv = teString.EnvelopeInternal; Coordinate testPt = teString.Coordinates[0]; EdgeRing minShell = null; IEnvelope minEnv = null; for (IEnumerator it = shellList.GetEnumerator(); it.MoveNext(); ) { EdgeRing tryShell = (EdgeRing)it.Current; ILinearRing tryRing = tryShell.LinearRing; IEnvelope tryEnv = tryRing.EnvelopeInternal; if (minShell != null) minEnv = minShell.LinearRing.EnvelopeInternal; bool isContained = false; if (tryEnv.Contains(testEnv) && CgAlgorithms.IsPointInRing(testPt, tryRing.Coordinates)) isContained = true; // check if this new containing ring is smaller than the current minimum ring if (isContained) { if (minShell == null || minEnv.Contains(tryEnv)) minShell = tryShell; } } return minShell; }
/// <summary> /// This method assigns the holes for a Polygon (formed from a list of /// MinimalEdgeRings) to its shell. /// Determining the holes for a MinimalEdgeRing polygon serves two purposes: /// it is faster than using a point-in-polygon check later on. /// it ensures correctness, since if the PIP test was used the point /// chosen might lie on the shell, which might return an incorrect result from the /// PIP test. /// </summary> /// <param name="shell"></param> /// <param name="minEdgeRings"></param> private static void PlacePolygonHoles(EdgeRing shell, IEnumerable minEdgeRings) { for (IEnumerator it = minEdgeRings.GetEnumerator(); it.MoveNext(); ) { MinimalEdgeRing er = (MinimalEdgeRing)it.Current; if (er.IsHole) er.Shell = shell; } }