예제 #1
0
        /// <summary>
        /// Given a initial vertex and a new point, finds the face that is split by a new edge in this direction
        /// </summary>
        /// <param name="a_vertex"></param>
        /// <param name="a_point"></param>
        /// <returns></returns>
        private Face GetSplittingFace(DCELVertex a_vertex, Vector2 a_point)
        {
            List <HalfEdge> outedges = OutgoingEdges(a_vertex).ToList();

            if (outedges.Count == 0)
            {
                // a_Vertex1 leaving is null
                throw new GeomException("Vertex should be connected to a face boundary");
            }

            outedges.Sort(EdgeAngleComparer);

            foreach (var curEdge in outedges)
            {
                var angle  = MathUtil.Angle(a_vertex.Pos, a_vertex.Pos + new Vector2(1f, 0f), curEdge.To.Pos);
                var angle2 = MathUtil.Angle(a_vertex.Pos, a_vertex.Pos + new Vector2(1f, 0f), a_point);

                if (angle >= angle2)
                {
                    return(curEdge.Face);
                }
            }

            return(outedges.FirstOrDefault().Face);
        }
예제 #2
0
        /// <summary>
        /// Fix the edge chaining from the given vertex and insert the half edge.
        /// Updates the next/prev data from the adjacent edges of a_Vertex
        /// to include the new edge.
        /// </summary>
        /// <param name="a_Vertex"></param>
        /// <param name="a_Edge"></param>
        private void AddEdgeInVertexChain(DCELVertex a_Vertex, HalfEdge a_Edge)
        {
            List <HalfEdge> outedges = OutgoingEdges(a_Vertex).ToList();

            if (outedges.Count == 0)
            {
                // Add initial edge to vertex
                Chain(a_Edge.Twin, a_Edge);
                a_Vertex.Leaving = a_Edge;
                return;
            }

            outedges.Sort(EdgeAngleComparer);

            // loop over edges in order of angle
            for (int i = 0; i < outedges.Count; i++)
            {
                var curEdge = outedges[i];
                var angle   = MathUtil.Angle(curEdge.From.Pos, curEdge.From.Pos + new Vector2(1f, 0f), curEdge.To.Pos);
                var angle2  = MathUtil.Angle(a_Edge.From.Pos, a_Edge.From.Pos + new Vector2(1f, 0f), a_Edge.To.Pos);

                if (angle >= angle2)
                {
                    // chain new edge correctly
                    var prevEdge = outedges[MathUtil.PositiveMod(i - 1, outedges.Count)];
                    Chain(a_Edge.Twin, curEdge);
                    Chain(prevEdge.Twin, a_Edge);
                    return;
                }
            }

            // new edge between first and last edge
            Chain(a_Edge.Twin, outedges.FirstOrDefault());
            Chain(outedges.Last().Twin, a_Edge);
        }
예제 #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="a_Edge"></param>
        /// <param name="a_Vertex"></param>
        /// <returns> The inserted Vertex.
        /// If the requested insertion Vertex is on a endpoint we insert no vertex
        /// and instead return said endpoint
        ///</returns>
        public DCELVertex AddVertexInEdge(HalfEdge a_Edge, Vector2 a_Point)
        {
            if (!m_Edges.Contains(a_Edge))
            {
                throw new GeomException("Edge should already be part of DCEL");
            }
            if (!a_Edge.Segment.IsOnSegment(a_Point))
            {
                throw new GeomException("Point should lie on edge");
            }
            if (MathUtil.EqualsEpsVertex(a_Edge.From.Pos, a_Point))
            {
                return(a_Edge.From);
                //throw new GeomException("Requested insertion in Edge on From.Pos");
            }
            if (MathUtil.EqualsEpsVertex(a_Edge.To.Pos, a_Point))
            {
                return(a_Edge.To);
                //throw new GeomException("Requested insertion in Edge on To.Pos");
            }

            // create vertex with outgoing edge
            var a_Vertex = new DCELVertex(a_Point, a_Edge.Twin);

            m_Vertices.AddLast(a_Vertex);

            // update old edge pointers
            var oldTo = a_Edge.To;

            a_Edge.To        = a_Vertex;
            a_Edge.Twin.From = a_Vertex;

            // create new halfedges
            var newedge     = new HalfEdge(a_Vertex, oldTo);
            var newtwinedge = new HalfEdge(oldTo, a_Vertex);

            m_Edges.AddLast(newedge);
            m_Edges.AddLast(newtwinedge);
            Twin(newedge, newtwinedge);

            // fix next/prev pointers in the original cycle
            Chain(newedge, a_Edge.Next);
            Chain(a_Edge, newedge);

            // fix pointers in the twin cycle
            Chain(a_Edge.Twin.Prev, newtwinedge);
            Chain(newtwinedge, a_Edge.Twin);

            // set faces
            newedge.Face     = a_Edge.Face;
            newtwinedge.Face = a_Edge.Twin.Face;

            // update old leaving edge as it may point to the wrong edge now
            oldTo.Leaving = newtwinedge;

            return(a_Vertex);
        }
예제 #4
0
        /// <summary>
        /// Find all half edges adjacent to the given vertex, ingoing as well as outgoing.
        /// </summary>
        /// <param name="a_Vertex1"></param>
        /// <returns></returns>
        public List <HalfEdge> AdjacentEdges(DCELVertex a_Vertex1)
        {
            var edges = new List <HalfEdge>();

            foreach (var e in OutgoingEdges(a_Vertex1))
            {
                edges.Add(e);
                edges.Add(e.Twin);
            }

            return(edges);
        }
예제 #5
0
        /// <summary>
        /// Adds a given DCELVertex to the DCEL.
        /// </summary>
        /// <param name="a_Vertex"></param>
        /// <returns>The added vertex</returns>
        public DCELVertex AddVertex(DCELVertex a_Vertex)
        {
            HalfEdge a_Edge;

            if (OnEdge(a_Vertex, out a_Edge))
            {
                return(AddVertexInEdge(a_Edge, a_Vertex.Pos));
            }
            else
            {
                m_Vertices.AddLast(a_Vertex);
                return(a_Vertex);
            }
        }
예제 #6
0
        /// <summary>
        /// Returns all edges that are outgoing from the given vertex.
        /// </summary>
        /// <param name="a_Vertex1"></param>
        /// <returns></returns>
        public List <HalfEdge> OutgoingEdges(DCELVertex a_Vertex1)
        {
            if (a_Vertex1.Leaving == null)
            {
                return(new List <HalfEdge>());
            }

            var edges = new List <HalfEdge>();
            var e     = a_Vertex1.Leaving;

            do
            {
                edges.Add(e);
                e = e.Twin.Next;
            } while (e != a_Vertex1.Leaving);

            return(edges);
        }
예제 #7
0
 /// <summary>
 /// Checks whether the given vertex lies on the cycle
 /// </summary>
 /// <param name="a_Vertex"></param>
 /// <param name="a_Edge"></param>
 /// <returns></returns>
 private bool OnEdge(DCELVertex a_Vertex, out HalfEdge a_Edge)
 {
     a_Edge = m_Edges.FirstOrDefault(e => e.Segment.IsOnSegment(a_Vertex.Pos));
     return(a_Edge != null);
 }
예제 #8
0
 /// <summary>
 /// Checks whether the given vertex lies on the edge cycle specified by the halfedge.
 /// </summary>
 /// <param name="a_startedge"></param>
 /// <param name="a_Vertex"></param>
 /// <returns></returns>
 private static bool OnCycle(HalfEdge a_startedge, DCELVertex a_Vertex)
 {
     return(Cycle(a_startedge).ToList().Exists(e => e.To == a_Vertex));
 }
예제 #9
0
 /// <summary>
 /// Finds a vertex with the given location, or null otherwise.
 /// </summary>
 /// <remarks>
 /// Slow method O(n), not recommended.
 /// </remarks>
 /// <param name="a_Point"></param>
 /// <param name="a_Vertex"></param>
 /// <returns></returns>
 public bool FindVertex(Vector2 a_Point, out DCELVertex a_Vertex)
 {
     a_Vertex = m_Vertices.FirstOrDefault(v => a_Point.Equals(v.Pos));
     return(a_Vertex != null);
 }
예제 #10
0
        /// <summary>
        /// Adds an edge, consisting of two halfedges, between existing vertices in the DCEL.
        /// </summary>
        /// <remarks>
        /// Vertices should be adjacent to a common face.
        /// </remarks>
        /// <param name="a_vertex1"></param>
        /// <param name="a_vertex2"></param>
        /// <returns> One of the newly added edges </returns>
        public HalfEdge AddEdge(DCELVertex a_Vertex1, DCELVertex a_Vertex2)
        {
            if (!m_Vertices.Contains(a_Vertex1) || !m_Vertices.Contains(a_Vertex2))
            {
                throw new GeomException("Vertices should already be part of the DCEL");
            }

            // create edges
            var e1 = new HalfEdge(a_Vertex1, a_Vertex2);
            var e2 = new HalfEdge(a_Vertex2, a_Vertex1);

            m_Edges.AddLast(e1);
            m_Edges.AddLast(e2);

            bool newFace = false;
            Face face1, face2;

            // check if both vertices already part of face
            // or disconnected inside a face
            if (OutgoingEdges(a_Vertex1).Count() != 0 && OutgoingEdges(a_Vertex2).Count() != 0)
            {
                // get faces split by new edge from each vertex
                face1 = GetSplittingFace(a_Vertex1, a_Vertex2.Pos);
                face2 = GetSplittingFace(a_Vertex2, a_Vertex1.Pos);

                // check if new edge will create additional face
                var newInnerFace   = face1.InnerComponents.Exists(e => OnCycle(e, a_Vertex1) && OnCycle(e, a_Vertex2));
                var outerFaceSplit = !face1.IsOuter &&
                                     OnCycle(face1.OuterComponent, a_Vertex1) &&
                                     OnCycle(face1.OuterComponent, a_Vertex2);
                newFace = newInnerFace || outerFaceSplit;
            }
            else if (OutgoingEdges(a_Vertex2).Count() != 0)
            {
                face1 = GetContainingFace(a_Vertex1.Pos);
                face2 = GetSplittingFace(a_Vertex2, a_Vertex1.Pos);
            }
            else if (OutgoingEdges(a_Vertex1).Count() != 0)
            {
                face1 = GetSplittingFace(a_Vertex1, a_Vertex2.Pos);
                face2 = GetContainingFace(a_Vertex2.Pos);
            }
            else
            {
                face1 = GetContainingFace(a_Vertex1.Pos);
                face2 = GetContainingFace(a_Vertex2.Pos);

                // new inner component inside face
                face1.InnerComponents.Add(e1);
            }

            if (face1 != face2)
            {
                throw new GeomException("Vertices do not lie in the same face:\n"
                                        + a_Vertex1 + "\n" + a_Vertex2 + "\n" + face1 + "\n" + face2);
            }

            // fix edge pointers
            e1.Face = face1;
            e2.Face = face1;
            Twin(e1, e2);
            AddEdgeInVertexChain(a_Vertex1, e1);
            AddEdgeInVertexChain(a_Vertex2, e2);

            if (newFace)
            {
                face2 = SplitFace(e1, e2, face1);
            }
            else
            {
                face2 = null;
            }

            // check whether inner component has become part of outer component
            // or inner components have merged
            FixInnerComponents(e1, e2, face1, face2);

            return(e1);
        }