Beispiel #1
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)
        {
            var q = QuadEdge.Connect(a, b);

            _quadEdges.Add(q);
            return(q);
        }
Beispiel #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
            var leftTri = new QuadEdge[3];

            GetTriangleEdges(e, leftTri);
            // System.out.println(new QuadEdgeTriangle(leftTri).ToString());
            var rightTri = new QuadEdge[3];

            GetTriangleEdges(e.Sym, rightTri);
            // System.out.println(new QuadEdgeTriangle(rightTri).ToString());

            // check other vertex of triangle to left of edge
            var vLeftTriOther = e.LNext.Dest;

            if (IsFrameVertex(vLeftTriOther))
            {
                return(true);
            }
            // check other vertex of triangle to right of edge
            var vRightTriOther = e.Sym.LNext.Dest;

            if (IsFrameVertex(vRightTriOther))
            {
                return(true);
            }

            return(false);
        }
Beispiel #3
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)
        {
            var 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.)
            var baseQE = MakeEdge(e.Orig, v);

            QuadEdge.Splice(baseQE, e);
            var startEdge = baseQE;

            do
            {
                baseQE = Connect(e, baseQE.Sym);
                e      = baseQE.OPrev;
            } while (e.LNext != startEdge);

            return(startEdge);
        }
Beispiel #4
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 Polygon GetVoronoiCellPolygon(QuadEdge qe, GeometryFactory geomFact)
        {
            var cellPts = new List <Coordinate>();
            var startQE = qe;

            do
            {
                // Coordinate cc = circumcentre(qe);
                // use previously computed circumcentre
                var 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);
            }

            var pts      = coordList.ToCoordinateArray();
            var cellPoly = geomFact.CreatePolygon(geomFact.CreateLinearRing(pts));

            var v = startQE.Orig;

            cellPoly.UserData = v.Coordinate;
            return(cellPoly);
        }
Beispiel #5
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)
        {
            var q = QuadEdge.MakeEdge(o, d);

            _quadEdges.Add(q);
            return(q);
        }
Beispiel #6
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);
 }
        /// <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)
        {
            var e = MakeEdge(a.Dest, b.Orig);

            Splice(e, a.LNext);
            Splice(e.Sym, b);
            return(e);
        }
Beispiel #8
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);
        }
Beispiel #9
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);
 }
Beispiel #10
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");
     }
 }
        private static QuadEdge[] CopyOf(QuadEdge[] edge)
        {
            var res = new QuadEdge[edge.Length];

            for (int i = 0; i < edge.Length; i++)
            {
                res[i] = edge[i];
            }
            return(res);
        }
Beispiel #12
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;

            var 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);
        }
Beispiel #13
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);
        }
 /// <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>
        /// Turns an edge counterclockwise inside its enclosing quadrilateral.
        /// </summary>
        /// <param name="e">the quadedge to turn</param>
        public static void Swap(QuadEdge e)
        {
            var a = e.OPrev;
            var 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;
        }
Beispiel #16
0
        private QuadEdge InitSubdiv()
        {
            // build initial subdivision from frame
            var ea = MakeEdge(_frameVertex[0], _frameVertex[1]);
            var eb = MakeEdge(_frameVertex[1], _frameVertex[2]);

            QuadEdge.Splice(ea.Sym, eb);
            var ec = MakeEdge(_frameVertex[2], _frameVertex[0]);

            QuadEdge.Splice(eb.Sym, ec);
            QuadEdge.Splice(ec.Sym, ea);
            return(ea);
        }
Beispiel #17
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>();

            var 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)
        {
            var alpha = a.ONext.Rot;
            var beta  = b.ONext.Rot;

            var t1 = b.ONext;
            var t2 = a.ONext;
            var t3 = beta.ONext;
            var t4 = alpha.ONext;

            a.SetNext(t1);
            b.SetNext(t2);
            alpha.SetNext(t3);
            beta.SetNext(t4);
        }
Beispiel #19
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);

            var eSym    = e.Sym;
            var eRot    = e.Rot;
            var 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>
        /// 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)
        {
            var q0 = new QuadEdge();
            var q1 = new QuadEdge();
            var q2 = new QuadEdge();
            var 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);

            var baseQE = q0;

            baseQE.Orig = o;
            baseQE.Dest = d;
            return(baseQE);
        }
Beispiel #21
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 <c>null</c> 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)
        {
            var  curr      = edge;
            int  edgeCount = 0;
            bool isFrame   = false;

            do
            {
                _triEdges[edgeCount] = curr;

                if (IsFrameEdge(curr))
                {
                    isFrame = true;
                }

                // push sym edges to visit next
                var 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);
        }
 /// <summary>
 /// Sets the connected edge
 /// </summary>
 /// <param name="next">edge</param>
 public void SetNext(QuadEdge next)
 {
     _next = next;
 }