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); }
private void MeshPreviousEdgeValidate() { if (HalfEdges.Any(edge => (edge as IPreviousEdge).PreviousEdgeAccessor == null)) { throw new MeshNavException("Edge doesn't contain a previous edge"); } }
public HalfEdge CreateHalfEdgeRaw() { var halfEdge = new HalfEdge(this); HalfEdges.Add(halfEdge); return(halfEdge); }
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); }
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] ); } } }); }
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); }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <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); }
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))); }
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); } }
/// <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; }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <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); }
// 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); }