예제 #1
0
파일: Graph.cs 프로젝트: moto2002/BoEG
        public void DeleteHalfEdge(HalfEdge edge)
        {
            if (edge.Origin.Edge == edge)
            {
                foreach (var temp in edge.Origin.Walk())
                {
                    if (temp == edge)
                    {
                        continue;
                    }
                    edge.Origin.SetEdge(temp);
                    break;
                }

                if (edge.Origin.Edge == edge)
                {
                    edge.Origin.SetEdge(null);
                }
            }

            if (edge.Twin.Origin.Edge == edge.Twin)
            {
                foreach (var temp in edge.Twin.Origin.Walk())
                {
                    if (temp == edge.Twin)
                    {
                        continue;
                    }
                    edge.Twin.Origin.SetEdge(temp);
                    break;
                }

                if (edge.Twin.Origin.Edge == edge)
                {
                    edge.Twin.Origin.SetEdge(null);
                }
            }


//            edge.Next.SetPrevious(edge.Previous);
//            edge.Twin.Next.SetPrevious(edge.Twin.Previous);

            HalfEdges.Remove(edge.Twin);
            HalfEdges.Remove(edge);

            edge.Twin.SetOrigin(null);
            edge.Twin.SetPolygon(null);
            edge.Twin.SetNext(null);
            edge.Twin.SetPrevious(null);
            edge.Twin.SetTwin(null);

            edge.SetPair(null);
            edge.Twin.SetPair(null);

            edge.SetOrigin(null);
            edge.SetPolygon(null);
            edge.SetNext(null);
            edge.SetPrevious(null);
            edge.SetTwin(null);
        }
예제 #2
0
 private void MeshPreviousEdgeValidate()
 {
     if (HalfEdges.Any(edge => (edge as IPreviousEdge).PreviousEdgeAccessor == null))
     {
         throw new MeshNavException("Edge doesn't contain a previous edge");
     }
 }
예제 #3
0
파일: Graph.cs 프로젝트: moto2002/BoEG
        public HalfEdge CreateHalfEdgeRaw()
        {
            var halfEdge = new HalfEdge(this);

            HalfEdges.Add(halfEdge);
            return(halfEdge);
        }
예제 #4
0
파일: Graph.cs 프로젝트: moto2002/BoEG
        public HalfEdge CreateEdge(Node aNode, Node bNode, bool isDirected = false)
        {
//            if (aNode.Edge != null && bNode.Edge != null)
//                throw new Exception();

            var edgeAB = new HalfEdge(this);
            var edgeBA = new HalfEdge(this);
            var edge   = new Edge(this);

            var edgePolygon = CreatePolygon(edgeAB);

            edgeAB.SetOrigin(aNode);
            edgeBA.SetOrigin(bNode);

            edgeAB.SetNext(edgeBA);
            edgeAB.SetPrevious(edgeBA);
            edgeAB.SetTwin(edgeBA);

            edgeAB.SetPolygon(edgePolygon);
            edgeBA.SetPolygon(edgePolygon);

            if (isDirected)
            {
                edgeBA.SetActive(false);
            }

            edge.SetPair(edgeAB);

            Edges.Add(edge);
            HalfEdges.Add(edgeAB);
            HalfEdges.Add(edgeBA);
            return(edgeAB);
        }
예제 #5
0
        private void SubdivideAllFacesWithInternalFace()
        {
            var edges       = new HashSet <HalfEdge>(HalfEdges.Where(a => a.Primary));
            var newVertices = new HashSet <Vertex>();

            foreach (var edge in edges)
            {
                newVertices.Add(edge.Split(GetVertex(edge.End.Position * 0.5f + edge.Twin.End.Position * 0.5f)).End);
            }

            WalkFaces((f, m) =>
            {
                var verts = f.Vertices.ToArray();
                f.Delete();

                GetFace(verts.Where(a => newVertices.Contains(a)));

                for (int i = 0; i < verts.Length; i++)
                {
                    if (newVertices.Contains(verts[i]))
                    {
                        GetFace(
                            verts[i],
                            verts[(i + 1) % verts.Length],
                            verts[(i + 2) % verts.Length]
                            );
                    }
                }
            });
        }
예제 #6
0
 public void Clear()
 {
     Vertices.Clear();
     HalfEdges.Clear();
     Faces.Clear();
     UnboundedFace = null;
 }
        /// <summary>
        /// The Angle between the two adjacent <see cref="Triangles"/> if the Triangle <paramref name="triangle"/> is adjacent to this Triangle.
        /// </summary>
        public double AngleTo(Triangle triangle)
        {
            if (!Triangles.Contains(triangle))
            {
                return(0);
            }

            return(HalfEdges.First(he => he.Triangles[1] == triangle).Angle);
        }
예제 #8
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>   Makes a deep copy of this object. </summary>
        ///
        /// <remarks>   Darrell Plank, 12/31/2017. </remarks>
        ///
        /// <returns>   A copy of this object. </returns>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        public Mesh Clone()
        {
            var newMesh = Factory.CreateMesh();

            var oldToNewVertex   = new Dictionary <Vertex, Vertex>();
            var oldToNewHalfEdge = new Dictionary <HalfEdge, HalfEdge>();
            var oldToNewFace     = new Dictionary <Face, Face>();
            var newVertices      = new List <Vertex>();
            var newHalfEdges     = new List <HalfEdge>();
            var newFaces         = new List <Face>();

            foreach (var vertex in Vertices.Where(v => v.IsAlive))
            {
                var newVertex = Factory.CreateVertex(newMesh, vertex.Position.Clone());
                Factory.CloneVertex(newVertex, vertex);
                newVertices.Add(newVertex);
                oldToNewVertex[vertex] = newVertex;
            }

            foreach (var halfEdge in HalfEdges.Where(he => he.IsAlive))
            {
                var newHalfEdge = Factory.CreateHalfEdge(oldToNewVertex[halfEdge.InitVertex],
                                                         null, null, null);
                Factory.CloneHalfEdge(newHalfEdge, halfEdge, oldToNewVertex);
                newHalfEdges.Add(newHalfEdge);
                oldToNewHalfEdge[halfEdge] = newHalfEdge;
            }

            foreach (var face in Faces.Where(f => f.IsAlive))
            {
                var newFace = Factory.CreateFace();
                newFace.HalfEdge = oldToNewHalfEdge[face.HalfEdge];
                Factory.CloneFace(newFace, face, oldToNewHalfEdge, oldToNewVertex);
                newFaces.Add(newFace);
                oldToNewFace[face] = newFace;
            }

            newMesh.VerticesInternal  = newVertices;
            newMesh.HalfEdgesInternal = newHalfEdges;
            newMesh.FacesInternal     = newFaces;

            newMesh.PatchClone(
                this,
                oldToNewVertex,
                oldToNewHalfEdge,
                oldToNewFace);
#if DEBUG
            newMesh.Validate();
#endif
            return(newMesh);
        }
예제 #9
0
        public IHalfEdge <TEdge, TPoint>?FindHalfEdge(TPoint pointA, TPoint pointB)
        {
            if (pointA is null)
            {
                throw new ArgumentNullException(nameof(pointA));
            }

            if (pointB is null)
            {
                throw new ArgumentNullException(nameof(pointB));
            }

            return(HalfEdges.SingleOrDefault(
                       halfEdge =>
                       halfEdge.Origin.OriginalPoint.Equals(pointA) && halfEdge.Next.Origin.OriginalPoint.Equals(pointB)));
        }
예제 #10
0
파일: Graph.cs 프로젝트: moto2002/BoEG
            public void Update(Graph <NodeData> graph)
            {
                foreach (var node in graph.Nodes)
                {
                    Nodes.Update(node);
                }

                foreach (var halfedge in graph.HalfEdges)
                {
                    HalfEdges.Update(halfedge);
                }

                foreach (var polygon in graph.Polygons)
                {
                    Polygons.Update(polygon);
                }
            }
예제 #11
0
        /// <summary>
        /// Create a subdivision from a single segment (u, v).
        /// </summary>
        public DCEL_Subdivision(VecRat2 u, VecRat2 v)
            : this()
        {
            if (u == v)
            {
                throw new Exception("Tried to create a DCELSubdivision with a segment of length 0.");
            }

            DCEL_Vertex   vertex_u    = new DCEL_Vertex(u);
            DCEL_Vertex   vertex_v    = new DCEL_Vertex(v);
            DCEL_HalfEdge halfedge_uv = new DCEL_HalfEdge();
            DCEL_HalfEdge halfedge_vu = new DCEL_HalfEdge();
            DCEL_Face     face        = new DCEL_Face();

            vertex_u.IncidentEdge = halfedge_uv;
            vertex_v.IncidentEdge = halfedge_vu;

            halfedge_uv.Origin       = vertex_u;
            halfedge_uv.Twin         = halfedge_vu;
            halfedge_uv.IncidentFace = face;
            halfedge_uv.Prev         = halfedge_vu;
            halfedge_uv.Next         = halfedge_vu;

            halfedge_vu.Origin       = vertex_v;
            halfedge_vu.Twin         = halfedge_uv;
            halfedge_vu.IncidentFace = face;
            halfedge_vu.Prev         = halfedge_uv;
            halfedge_vu.Next         = halfedge_uv;

            face.InnerComponents.AddLast(halfedge_uv);

            Vertices.Add(new RBTreeSetNode <DCEL_Vertex>(vertex_u));
            Vertices.Add(new RBTreeSetNode <DCEL_Vertex>(vertex_u));
            HalfEdges.Add(new RBTreeSetNode <DCEL_HalfEdge>(halfedge_uv));
            HalfEdges.Add(new RBTreeSetNode <DCEL_HalfEdge>(halfedge_vu));
            Faces.Add(new RBTreeSetNode <DCEL_Face>(face));

            UnboundedFace = face;
        }
예제 #12
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>   Validates this mesh. </summary>
        ///
        /// <remarks>   TODO: Think about this
        ///             How much do we really want to do at this top level?  Without making certain assumptions
        ///             it's really difficult to do anything useful but we want to be as flexible as possible.
        ///             Since we currently only create elements by adding faces, it's pretty safe, I think, to
        ///             insist that all faces have at least three edges.
        ///
        ///             Darrell Plank, 12/8/2017. </remarks>
        ///
        /// <returns>   True if it succeeds, false if it fails. </returns>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        public virtual bool Validate()
        {
            if (VerticesInternal.Count == 0)
            {
                if (HalfEdgesInternal.Count != 0 && FacesInternal.Count != 0)
                {
                    throw new MeshNavException("No vertices but we have other elements");
                }
            }

            if (Faces.Any(face => face.Edges().Take(3).Count() != 3 && !face.IsBoundary))
            {
                throw new MeshNavException("Faces with less than three sides not allowed");
            }

            if (Faces.Where(f => f.IsAlive).Any(f => !f.HalfEdge.IsAlive))
            {
                throw new MeshNavException("Live faces point to dead halfedges");
            }

            if (Vertices.Where(v => v.IsAlive).Any(v => v.Mesh != this || !v.Edge.IsAlive))
            {
                throw new MeshNavException("Live vertices point at dead half edges or don't belong to this mesh");
            }

            if (HalfEdges.Where(he => he.IsAlive).Any(he => !he.InitVertex.IsAlive || he.Face != null && !he.Face.IsAlive))
            {
                throw new MeshNavException("Live halfedge points at dead component");
            }

            if (HalfEdges.Where(he => he.IsAlive).Any(he => he.InitVertex == he.Opposite.InitVertex))
            {
                throw new MeshNavException("Edge and opposite oriented identically");
            }
            return(true);
        }
예제 #13
0
        // Takes a List containing another List per face with the vertex indexes belonging to that face
        private bool CreateFaces(List <List <int> > faceIndexes)
        {
            Dictionary <string, int>          edgeCount         = new Dictionary <string, int>();
            Dictionary <string, MeshHalfEdge> existingHalfEdges = new Dictionary <string, MeshHalfEdge>();
            Dictionary <MeshHalfEdge, bool>   hasTwinHalfEdge   = new Dictionary <MeshHalfEdge, bool>();

            // Create the faces, edges and half-edges, non-boundary loops and link references when possible;
            foreach (List <int> indexes in faceIndexes)
            {
                MeshFace f = new MeshFace();
                Faces.Add(f);

                List <MeshHalfEdge> tempHEdges = new List <MeshHalfEdge>(indexes.Count);

                // Create empty half-edges
                for (int i = 0; i < indexes.Count; i++)
                {
                    MeshHalfEdge h = new MeshHalfEdge();
                    tempHEdges.Add(h);
                }

                // Fill out each half edge
                for (int i = 0; i < indexes.Count; i++)
                {
                    // Edge goes from v0 to v1
                    int v0 = indexes[i];
                    int v1 = indexes[(i + 1) % indexes.Count];

                    MeshHalfEdge h = tempHEdges[i];

                    // Set previous and next
                    h.Next = tempHEdges[(i + 1) % indexes.Count];
                    h.Prev = tempHEdges[(i + indexes.Count - 1) % indexes.Count];

                    h.OnBoundary = false;
                    hasTwinHalfEdge.Add(h, false);

                    // Set half-edge & vertex mutually
                    h.Vertex = Vertices[v0];
                    Vertices[v0].HalfEdge = h;

                    // Set half-edge face & vice versa
                    h.Face     = f;
                    f.HalfEdge = h;

                    // Reverse v0 and v1 if v0 > v1
                    if (v0 > v1)
                    {
                        int temp = v0;
                        v0 = v1;
                        v1 = temp;
                    }

                    string key = v0 + " " + v1;
                    if (existingHalfEdges.ContainsKey(key))
                    {
                        // If this half-edge key already exists, it is the twin of this current half-edge
                        MeshHalfEdge twin = existingHalfEdges[key];
                        h.Twin                = twin;
                        twin.Twin             = h;
                        h.Edge                = twin.Edge;
                        hasTwinHalfEdge[h]    = true;
                        hasTwinHalfEdge[twin] = true;
                        edgeCount[key]++;
                    }
                    else
                    {
                        // Create an edge and set its half-edge
                        MeshEdge e = new MeshEdge();
                        Edges.Add(e);
                        h.Edge     = e;
                        e.HalfEdge = h;

                        // Record the newly created half-edge
                        existingHalfEdges.Add(key, h);
                        edgeCount.Add(key, 1);
                    }
                }

                HalfEdges.AddRange(tempHEdges);
            }

            // Create boundary edges
            for (int i = 0; i < HalfEdges.Count; i++)
            {
                MeshHalfEdge h = HalfEdges[i];
                if (!hasTwinHalfEdge[h])
                {
                    MeshFace f = new MeshFace();
                    Boundaries.Add(f);

                    List <MeshHalfEdge> boundaryCycle = new List <MeshHalfEdge>();
                    MeshHalfEdge        hE            = h;
                    do
                    {
                        MeshHalfEdge bH = new MeshHalfEdge();
                        HalfEdges.Add(bH);
                        boundaryCycle.Add(bH);

                        MeshHalfEdge nextHE = hE.Next;
                        while (hasTwinHalfEdge[nextHE])
                        {
                            nextHE = nextHE.Twin.Next;
                        }

                        bH.Vertex     = nextHE.Vertex;
                        bH.Edge       = hE.Edge;
                        bH.OnBoundary = true;

                        bH.Face    = f;
                        f.HalfEdge = bH;

                        bH.Twin = hE;
                        hE.Twin = bH;

                        hE = nextHE;
                    }while (hE != h);

                    int n = boundaryCycle.Count;
                    for (int j = 0; j < n; j++)
                    {
                        boundaryCycle[j].Next                  = boundaryCycle[(j + n - 1) % n];
                        boundaryCycle[j].Prev                  = boundaryCycle[(j + 1) % n];
                        hasTwinHalfEdge[boundaryCycle[j]]      = true;
                        hasTwinHalfEdge[boundaryCycle[j].Twin] = true;
                    }
                }

                if (!h.OnBoundary)
                {
                    MeshCorner corner = new MeshCorner
                    {
                        HalfEdge = h,
                    };
                    h.Corner = corner;
                    Corners.Add(corner);
                }
            }

            // Check mesh for common errors
            if (HasIsolatedFaces() || HasIsolatedVertices() || HasNonManifoldEdges())
            {
                return(false);
            }

            // Index elements
            IndexElements();

            return(true);
        }