示例#1
0
        /// <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);
        }
示例#2
0
        /// <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);
        }
示例#3
0
        /// <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);
        }
示例#4
0
        /// <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);
        }
示例#5
0
        /// <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);
        }
示例#6
0
        /// <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);
        }
示例#7
0
        /// <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);
        }
示例#8
0
 /// <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);
 }
示例#9
0
        /// <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);
        }
示例#10
0
 /// <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);
 }
示例#11
0
        /// <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);
        }
示例#12
0
 /// <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);
 }
示例#13
0
        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);
        }
示例#14
0
 /// <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");
     }
 }
示例#15
0
        /// <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);
        }
示例#16
0
 /// <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);
 }
示例#17
0
        /// <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);
        }
示例#18
0
        /// <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;
        }
示例#19
0
 /// <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);
 }
示例#20
0
        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);
        }
示例#21
0
        /// <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);
        }
示例#22
0
        /// <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);
        }
示例#23
0
        /// <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();
        }
示例#24
0
        /// <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);
        }
示例#25
0
        /// <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);
        }
示例#26
0
        /// <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);
        }
示例#27
0
        /// <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);
        }
示例#28
0
 private bool LeftOf(QuadEdge e)
 {
     return(IsCcw(e.Orig, e.Dest));
 }
示例#29
0
 internal bool RightOf(QuadEdge e)
 {
     return(IsCcw(e.Dest, e.Orig));
 }
示例#30
0
 /// <summary>
 /// Sets the connected edge
 /// </summary>
 /// <param name="next">edge</param>
 public void SetNext(QuadEdge next)
 {
     _next = next;
 }