/// <summary> /// Inserts a new site into the Subdivision, connecting it to the vertices of /// the containing triangle (or quadrilateral, if the split point falls on an /// existing edge). /// </summary> /// <remarks> /// <para> /// This method does NOT maintain the Delaunay condition. If desired, this must /// be checked and enforced by the caller. /// </para> /// <para> /// This method does NOT check if the inserted vertex falls on an edge. This /// must be checked by the caller, since this situation may cause erroneous /// triangulation /// </para> /// </remarks> /// <param name="v">the vertex to insert</param> /// <returns>a new quad edge terminating in v</returns> public QuadEdge InsertSite(Vertex v) { QuadEdge e = Locate(v); if ((v.Equals(e.Orig, _tolerance)) || (v.Equals(e.Dest, _tolerance))) { return(e); // point already in subdivision. } // Connect the new point to the vertices of the containing // triangle (or quadrilateral, if the new point fell on an // existing edge.) QuadEdge baseQE = MakeEdge(e.Orig, v); QuadEdge.Splice(baseQE, e); QuadEdge startEdge = baseQE; do { baseQE = Connect(e, baseQE.Sym); e = baseQE.OPrev; } while (e.LNext != startEdge); return(startEdge); }
/// <summary> /// Tests whether a QuadEdge is an edge on the border of the frame facets and /// the internal facets. E.g. an edge which does not itself touch a frame /// vertex, but which touches an edge which does. /// </summary> /// <param name="e">the edge to test</param> /// <returns>true if the edge is on the border of the frame</returns> public bool IsFrameBorderEdge(QuadEdge e) { // MD debugging QuadEdge[] leftTri = new QuadEdge[3]; GetTriangleEdges(e, leftTri); // System.out.println(new QuadEdgeTriangle(leftTri).ToString()); QuadEdge[] rightTri = new QuadEdge[3]; GetTriangleEdges(e.Sym, rightTri); // System.out.println(new QuadEdgeTriangle(rightTri).ToString()); // check other vertex of triangle to left of edge Vertex vLeftTriOther = e.LNext.Dest; if (IsFrameVertex(vLeftTriOther)) { return(true); } // check other vertex of triangle to right of edge Vertex vRightTriOther = e.Sym.LNext.Dest; if (IsFrameVertex(vRightTriOther)) { return(true); } return(false); }
/// <summary> /// Locates the edge between the given vertices, if it exists in the /// subdivision. /// </summary> /// <param name="p0">a coordinate</param> /// <param name="p1">another coordinate</param> /// <returns>the edge joining the coordinates, if present, /// or null if no such edge exists /// </returns> public QuadEdge Locate(Coordinate p0, Coordinate p1) { // find an edge containing one of the points QuadEdge e = _locator.Locate(new Vertex(p0)); if (e == null) { return(null); } // normalize so that p0 is origin of base edge QuadEdge baseQE = e; if (e.Dest.Coordinate.Equals2D(p0)) { baseQE = e.Sym; } // check all edges around origin of base edge QuadEdge locEdge = baseQE; do { if (locEdge.Dest.Coordinate.Equals2D(p1)) { return(locEdge); } locEdge = locEdge.ONext; } while (locEdge != baseQE); return(null); }
/// <summary> /// Creates a new QuadEdge connecting the destination of a to the origin of b, /// in such a way that all three have the same left face after the connection /// is complete. The quadedge is recorded in the edges list. /// </summary> /// <param name="a">A quadedge</param> /// <param name="b">A quadedge</param> /// <returns>A quadedge</returns> public QuadEdge Connect(QuadEdge a, QuadEdge b) { QuadEdge q = QuadEdge.Connect(a, b); _quadEdges.Add(q); return(q); }
/// <summary> /// Gets all primary quadedges in the subdivision. /// A primary edge is a <see cref="QuadEdge"/> /// which occupies the 0'th position in its array of associated quadedges. /// These provide the unique geometric edges of the triangulation. /// </summary> /// <param name="includeFrame">true if the frame edges are to be included</param> /// <returns>a List of QuadEdges</returns> public IList <QuadEdge> GetPrimaryEdges(bool includeFrame) { _visitedKey++; var edges = new List <QuadEdge>(); var edgeStack = new Stack <QuadEdge>(); edgeStack.Push(_startingEdge); var visitedEdges = new HashSet <QuadEdge>(); while (edgeStack.Count > 0) { var edge = edgeStack.Pop(); if (!visitedEdges.Contains(edge)) { QuadEdge priQE = edge.GetPrimary(); if (includeFrame || !IsFrameEdge(priQE)) { edges.Add(priQE); } edgeStack.Push(edge.ONext); edgeStack.Push(edge.Sym.ONext); visitedEdges.Add(edge); visitedEdges.Add(edge.Sym); } } return(edges); }
/// <summary> /// Creates a new quadedge, recording it in the edges list. /// </summary> /// <param name="o">The origin vertex</param> /// <param name="d">The destination vertex</param> /// <returns>A new quadedge</returns> public QuadEdge MakeEdge(Vertex o, Vertex d) { QuadEdge q = QuadEdge.MakeEdge(o, d); _quadEdges.Add(q); return(q); }
/// <summary> /// Gets the Voronoi cell around a site specified /// by the origin of a QuadEdge. /// </summary> /// <remarks> /// The userData of the polygon is set to be the <see cref="Coordinate" /> /// of the site. This allows attaching external /// data associated with the site to this cell polygon. /// </remarks> /// <param name="qe">a quadedge originating at the cell site</param> /// <param name="geomFact">a factory for building the polygon</param> /// <returns>a polygon indicating the cell extent</returns> public IPolygon GetVoronoiCellPolygon(QuadEdge qe, IGeometryFactory geomFact) { var cellPts = new List <Coordinate>(); QuadEdge startQE = qe; do { // Coordinate cc = circumcentre(qe); // use previously computed circumcentre Coordinate cc = qe.Rot.Orig.Coordinate; cellPts.Add(cc); // move to next triangle CW around vertex qe = qe.OPrev; } while (qe != startQE); var coordList = new CoordinateList(); coordList.AddAll(cellPts, false); coordList.CloseRing(); if (coordList.Count < 4) { Debug.WriteLine(coordList); coordList.Add(coordList[coordList.Count - 1], true); } Coordinate[] pts = coordList.ToCoordinateArray(); IPolygon cellPoly = geomFact.CreatePolygon(geomFact.CreateLinearRing(pts)); Vertex v = startQE.Orig; cellPoly.UserData = v.Coordinate; return(cellPoly); }
/// <summary> /// Tests whether a <see cref="Vertex"/> is the start or end vertex of a /// <see cref="QuadEdge"/>, up to the subdivision tolerance distance. /// </summary> /// <param name="e" /> /// <param name="v" /> /// <returns>true if the vertex is a endpoint of the edge</returns> public bool IsVertexOfEdge(QuadEdge e, Vertex v) { if ((v.Equals(e.Orig, _tolerance)) || (v.Equals(e.Dest, _tolerance))) { return(true); } return(false); }
/// <summary> /// Creates a new QuadEdge connecting the destination of a to the origin of /// b, in such a way that all three have the same left face after the /// connection is complete. Additionally, the data pointers of the new edge /// are set. /// </summary> /// <returns>the connected edge</returns> public static QuadEdge Connect(QuadEdge a, QuadEdge b) { QuadEdge e = MakeEdge(a.Dest, b.Orig); Splice(e, a.LNext); Splice(e.Sym, b); return(e); }
/// <summary> /// Tests whether a QuadEdge is an edge incident on a frame triangle vertex. /// </summary> /// <param name="e">the edge to test</param> /// <returns>true if the edge is connected to the frame triangle</returns> public bool IsFrameEdge(QuadEdge e) { if (IsFrameVertex(e.Orig) || IsFrameVertex(e.Dest)) { return(true); } return(false); }
/// <summary> /// Tests whether a {@link Coordinate} lies on a {@link QuadEdge}, up to a /// tolerance determined by the subdivision tolerance. /// </summary> /// <param name="e">a QuadEdge</param> /// <param name="p">a point</param> /// <returns>true if the vertex lies on the edge</returns> public bool IsOnEdge(QuadEdge e, Coordinate p) { seg.SetCoordinates(e.Orig.Coordinate, e.Dest.Coordinate); double dist = seg.Distance(p); // heuristic (hack?) return(dist < _edgeCoincidenceTolerance); }
/// <summary> /// Tests if this quadedge and another have the same line segment geometry /// with the same orientation. /// </summary> /// <param name="qe">a quadedge</param> /// <returns>true if the quadedges are based on the same line segment</returns> public bool EqualsOriented(QuadEdge qe) { if (Orig.Coordinate.Equals2D(qe.Orig.Coordinate) && Dest.Coordinate.Equals2D(qe.Dest.Coordinate)) { return(true); } return(false); }
private static QuadEdge[] CopyOf(QuadEdge[] edge) { var res = new QuadEdge[edge.Length]; for (var i = 0; i < edge.Length; i++) { res[i] = edge[i]; } return(res); }
/// <summary> /// Gets the edges for the triangle to the left of the given <see cref="QuadEdge"/>. /// </summary> /// <param name="startQE" /> /// <param name="triEdge" /> /// <exception cref="ArgumentException">if the edges do not form a triangle</exception> public static void GetTriangleEdges(QuadEdge startQE, QuadEdge[] triEdge) { triEdge[0] = startQE; triEdge[1] = triEdge[0].LNext; triEdge[2] = triEdge[1].LNext; if (triEdge[2].LNext != triEdge[0]) { throw new ArgumentException("Edges do not form a triangle"); } }
/// <summary> /// Locates an edge of a triangle which contains a location /// specified by a Vertex v. /// The edge returned has the /// property that either v is on e, or e is an edge of a triangle containing v. /// The search starts from startEdge amd proceeds on the general direction of v. /// </summary> /// <remarks> /// This locate algorithm relies on the subdivision being Delaunay. For /// non-Delaunay subdivisions, this may loop for ever. /// </remarks> /// <param name="v">the location to search for</param> /// <param name="startEdge">an edge of the subdivision to start searching at</param> /// <returns>a QuadEdge which contains v, or is on the edge of a triangle containing v</returns> /// <exception cref="LocateFailureException"> /// if the location algorithm fails to converge in a reasonable /// number of iterations /// </exception> public QuadEdge LocateFromEdge(Vertex v, QuadEdge startEdge) { int iter = 0; int maxIter = _quadEdges.Count; QuadEdge e = startEdge; while (true) { iter++; /* * So far it has always been the case that failure to locate indicates an * invalid subdivision. So just fail completely. (An alternative would be * to perform an exhaustive search for the containing triangle, but this * would mask errors in the subdivision topology) * * This can also happen if two vertices are located very close together, * since the orientation predicates may experience precision failures. */ if (iter > maxIter) { throw new LocateFailureException(e.ToLineSegment()); // String msg = "Locate failed to converge (at edge: " + e + "). // Possible causes include invalid Subdivision topology or very close // sites"; // System.err.println(msg); // dumpTriangles(); } if ((v.Equals(e.Orig)) || (v.Equals(e.Dest))) { break; } if (v.RightOf(e)) { e = e.Sym; } else if (!v.RightOf(e.ONext)) { e = e.ONext; } else if (!v.RightOf(e.DPrev)) { e = e.DPrev; } else { // on edge or in triangle containing edge break; } } // System.out.println("Locate count: " + iter); return(e); }
/// <summary> /// Gets the index for the given edge of this triangle /// </summary> /// <param name="e">a QuadEdge</param> /// <returns>the index of the edge in this triangle,<br/> /// or -1 if the edge is not an edge of this triangle /// </returns> public int GetEdgeIndex(QuadEdge e) { for (int i = 0; i < 3; i++) { if (_edge[i] == e) { return(i); } } return(-1); }
/// <summary> /// Creates a new instance of a quad-edge subdivision based on a frame triangle /// that encloses a supplied bounding box. A new super-bounding box that /// contains the triangle is computed and stored. /// </summary> /// <param name="env">the bounding box to surround</param> /// <param name="tolerance">the tolerance value for determining if two sites are equal</param> public QuadEdgeSubdivision(Envelope env, double tolerance) { // currentSubdiv = this; _tolerance = tolerance; _edgeCoincidenceTolerance = tolerance / EdgeCoincidenceToleranceFactor; CreateFrame(env); _startingEdge = InitSubdiv(); _locator = new LastFoundQuadEdgeLocator(this); }
/// <summary> /// Turns an edge counterclockwise inside its enclosing quadrilateral. /// </summary> /// <param name="e">the quadedge to turn</param> public static void Swap(QuadEdge e) { QuadEdge a = e.OPrev; QuadEdge b = e.Sym.OPrev; Splice(e, a); Splice(e.Sym, b); Splice(e, a.LNext); Splice(e.Sym, b.LNext); e.Orig = a.Dest; e.Dest = b.Dest; }
/// <summary> /// Tests if this quadedge and another have the same line segment geometry, /// regardless of orientation. /// </summary> /// <param name="qe">a quadedge</param> /// <returns>true if the quadedges are based on the same line segment regardless of orientation</returns> public bool EqualsNonOriented(QuadEdge qe) { if (EqualsOriented(qe)) { return(true); } if (EqualsOriented(qe.Sym)) { return(true); } return(false); }
private QuadEdge InitSubdiv() { // build initial subdivision from frame QuadEdge ea = MakeEdge(_frameVertex[0], _frameVertex[1]); QuadEdge eb = MakeEdge(_frameVertex[1], _frameVertex[2]); QuadEdge.Splice(ea.Sym, eb); QuadEdge ec = MakeEdge(_frameVertex[2], _frameVertex[0]); QuadEdge.Splice(eb.Sym, ec); QuadEdge.Splice(ec.Sym, ea); return(ea); }
/// <summary> /// Gets all edges which are incident on the origin of the given edge. /// </summary> /// <param name="start">the edge to start at</param> /// <returns>a List of edges which have their origin at the origin of the given /// edge</returns> public static IList <QuadEdge> FindEdgesIncidentOnOrigin(QuadEdge start) { var incEdge = new List <QuadEdge>(); QuadEdge qe = start; do { incEdge.Add(qe); qe = qe.ONext; } while (qe != start); return(incEdge); }
/// <summary> /// Splices two edges together or apart. /// Splice affects the two edge rings around the origins of a and b, and, independently, the two /// edge rings around the left faces of <tt>a</tt> and <tt>b</tt>. /// In each case, (i) if the two rings are distinct, /// Splice will combine them into one, or (ii) if the two are the same ring, Splice will break it /// into two separate pieces. Thus, Splice can be used both to attach the two edges together, and /// to break them apart. /// </summary> /// <param name="a">an edge to splice</param> /// <param name="b">an edge to splice</param> public static void Splice(QuadEdge a, QuadEdge b) { QuadEdge alpha = a.ONext.Rot; QuadEdge beta = b.ONext.Rot; QuadEdge t1 = b.ONext; QuadEdge t2 = a.ONext; QuadEdge t3 = beta.ONext; QuadEdge t4 = alpha.ONext; a.SetNext(t1); b.SetNext(t2); alpha.SetNext(t3); beta.SetNext(t4); }
/// <summary> /// Deletes a quadedge from the subdivision. Linked quadedges are updated to /// reflect the deletion. /// </summary> /// <param name="e">the quadedge to delete</param> public void Delete(QuadEdge e) { QuadEdge.Splice(e, e.OPrev); QuadEdge.Splice(e.Sym, e.Sym.OPrev); QuadEdge eSym = e.Sym; QuadEdge eRot = e.Rot; QuadEdge eRotSym = e.Rot.Sym; // this is inefficient on an ArrayList, but this method should be called infrequently _quadEdges.Remove(e); _quadEdges.Remove(eSym); _quadEdges.Remove(eRot); _quadEdges.Remove(eRotSym); e.Delete(); eSym.Delete(); eRot.Delete(); eRotSym.Delete(); }
/// <summary> /// Gets the triangles which are adjacent (include) to a /// given vertex of this triangle. /// </summary> /// <param name="vertexIndex">The vertex to query</param> /// <returns>A list of the vertex-adjacent triangles</returns> public IList <QuadEdgeTriangle> GetTrianglesAdjacentToVertex(int vertexIndex) { // Assert: isVertex var adjTris = new List <QuadEdgeTriangle>(); QuadEdge start = GetEdge(vertexIndex); QuadEdge qe = start; do { var adjTri = (QuadEdgeTriangle)qe.Data; if (adjTri != null) { adjTris.Add(adjTri); } qe = qe.ONext; } while (qe != start); return(adjTris); }
/// <summary> /// Creates a new QuadEdge quartet from <see cref="Vertex"/>o to <see cref="Vertex"/> d. /// </summary> /// <param name="o">the origin Vertex</param> /// <param name="d">the destination Vertex</param> /// <returns>the new QuadEdge quartet</returns> public static QuadEdge MakeEdge(Vertex o, Vertex d) { QuadEdge q0 = new QuadEdge(); QuadEdge q1 = new QuadEdge(); QuadEdge q2 = new QuadEdge(); QuadEdge q3 = new QuadEdge(); q0.Rot = q1; q1.Rot = q2; q2.Rot = q3; q3.Rot = q0; q0.SetNext(q0); q1.SetNext(q3); q2.SetNext(q2); q3.SetNext(q1); QuadEdge baseQE = q0; baseQE.Orig = o; baseQE.Dest = d; return(baseQE); }
/// <summary> /// Gets a collection of <see cref="QuadEdge"/>s whose origin /// vertices are a unique set which includes /// all vertices in the subdivision. /// The frame vertices can be included if required. /// </summary> /// <remarks> /// This is useful for algorithms which require traversing the /// subdivision starting at all vertices. /// Returning a quadedge for each vertex /// is more efficient than /// the alternative of finding the actual vertices /// using <see cref="GetVertices"/> and then locating /// quadedges attached to them. /// </remarks> /// <param name="includeFrame">true if the frame vertices should be included</param> /// <returns>a collection of QuadEdge with the vertices of the subdivision as their origins</returns> public IList <QuadEdge> GetVertexUniqueEdges(bool includeFrame) { var edges = new List <QuadEdge>(); var visitedVertices = new HashSet <Vertex>(); foreach (var qe in _quadEdges) { Vertex v = qe.Orig; //System.out.println(v); if (!visitedVertices.Contains(v)) { visitedVertices.Add(v); if (includeFrame || !IsFrameVertex(v)) { edges.Add(qe); } } /* * Inspect the sym edge as well, since it is * possible that a vertex is only at the * dest of all tracked quadedges. */ QuadEdge qd = qe.Sym; Vertex vd = qd.Orig; //System.out.println(vd); if (!visitedVertices.Contains(vd)) { visitedVertices.Add(vd); if (includeFrame || !IsFrameVertex(vd)) { edges.Add(qd); } } } return(edges); }
/// <summary> /// Stores the edges for a visited triangle. Also pushes sym (neighbour) edges /// on stack to visit later. /// </summary> /// <param name="edge" /> /// <param name="edgeStack" /> /// <param name="includeFrame" /> /// <param name="visitedEdges"></param> /// <returns>the visited triangle edges,<br/> /// or <value>null</value> if the triangle should not be visited (for instance, if it is outer) /// </returns> private QuadEdge[] FetchTriangleToVisit(QuadEdge edge, Stack <QuadEdge> edgeStack, bool includeFrame, HashSet <QuadEdge> visitedEdges) { QuadEdge curr = edge; int edgeCount = 0; bool isFrame = false; do { _triEdges[edgeCount] = curr; if (IsFrameEdge(curr)) { isFrame = true; } // push sym edges to visit next QuadEdge sym = curr.Sym; if (!visitedEdges.Contains(sym)) { edgeStack.Push(sym); } // mark this edge as visited visitedEdges.Add(curr); edgeCount++; curr = curr.LNext; } while (curr != edge); if (isFrame && !includeFrame) { return(null); } return(_triEdges); }
private bool LeftOf(QuadEdge e) { return(IsCcw(e.Orig, e.Dest)); }
internal bool RightOf(QuadEdge e) { return(IsCcw(e.Dest, e.Orig)); }
/// <summary> /// Sets the connected edge /// </summary> /// <param name="next">edge</param> public void SetNext(QuadEdge next) { _next = next; }