void ModelEdge_Click() { MeshEdge e = Model.Edges[OpObject.Index]; if (IsSplitting) { MeshVertex v = Model.SplitEdgeAt(e, OpObject.Position); if (PreviousSplittedVertex != null) { Model.AddEdge(PreviousSplittedVertex, v, true); } PreviousSplittedVertex = v; Model.UpdateAll(); return; } e.Selected = true; e.V1.Selected = true; e.V2.Selected = true; Model.UpdateAll(); Console.WriteLine(e.V1.Position + "-->" + e.V2.Position); Console.WriteLine((e.F1 == null ? -1 : e.F1.Index) + ", " + (e.F2 == null ? -1 : e.F2.Index)); }
public MeshEdge Eqv(MeshEdge e) { if (e == null) { return(null); } return(edges[e.Index]); }
//////////////////////////////////////////////////////////////////////// public MeshVertex SplitEdgeAt(MeshEdge e, Vector3 pos) { if (Edges[e.Index] != e) { return(null); } MeshVertex new_v = this.AddVertex(pos); // save the vertex sequences of adjacency facets List <MeshVertex> f1v = new List <MeshVertex>(); List <MeshVertex> f2v = new List <MeshVertex>(); if (e.F1 != null) { for (int i = 0; i < e.F1.Vertices.Count; i++) { var vs = e.F1.Vertices; f1v.Add(vs[i]); MeshEdge cur_e = vs[i].EdgeConnecting(vs[(i + 1) % vs.Count]); if (cur_e == e) { f1v.Add(new_v); } } } if (e.F2 != null) { for (int i = 0; i < e.F2.Vertices.Count; i++) { var vs = e.F2.Vertices; f2v.Add(vs[i]); MeshEdge cur_e = vs[i].EdgeConnecting(vs[(i + 1) % vs.Count]); if (cur_e == e) { f2v.Add(new_v); } } } // reconstruct facet this.RemoveEdge(e); if (f1v.Count > 0) { this.AddFacet(f1v.ToArray()); } if (f2v.Count > 0) { this.AddFacet(f2v.ToArray()); } return(new_v); }
public MeshGraph Clone() { MeshGraph mg = new MeshGraph(); mg.triangles = this.triangles; foreach (MeshVertex v in vertices) { MeshVertex new_v = new MeshVertex(v.Position); new_v.SetGraphInfo(mg, mg.vertices.Count); mg.vertices.Add(new_v); } foreach (MeshEdge e in edges) { MeshEdge new_e = new MeshEdge(mg.Eqv(e.V1), mg.Eqv(e.V2)); new_e.SetGraphInfo(mg, mg.edges.Count); mg.edges.Add(new_e); } foreach (MeshFacet f in facets) { MeshFacet new_f = new MeshFacet(); foreach (MeshVertex v in f.vertices) { new_f.vertices.Add(mg.Eqv(v)); } new_f.SetGraphInfo(mg, mg.facets.Count); mg.facets.Add(new_f); } // Maintain adjacency cache foreach (MeshEdge e in mg.edges) { MeshEdge old_e = this.Eqv(e); e.f1 = mg.Eqv(old_e.f1); e.f2 = mg.Eqv(old_e.f2); } foreach (MeshVertex v in mg.vertices) { MeshVertex old_v = this.Eqv(v); foreach (var entry in old_v.adjacency) { v.adjacency.Add(mg.Eqv(entry.Key), mg.Eqv(entry.Value)); } } return(mg); }
public void RemoveEdge(MeshEdge e) { int i = e.Index; if (edges[i] != e) { return; } if (i != edges.Count - 1) { edges[i] = edges.Last(); edges[i].SetGraphInfo(this, i); } edges.RemoveAt(edges.Count - 1); e.Selected = false; e.ClearAdjacency(); e.p1.adjacency.Remove(e.p2); e.p2.adjacency.Remove(e.p1); }
public void CreateTriangle() { MeshVertex v1 = new MeshVertex(1, 0, 1); MeshVertex v2 = new MeshVertex(2, 1, 0); MeshVertex v3 = new MeshVertex(1, 3, 1); MeshGraph mg = new MeshGraph(); mg.AddVertex(v1); mg.AddVertex(v2); mg.AddVertex(v3); MeshEdge e1 = mg.AddEdge(v1, v2); MeshEdge e2 = mg.AddEdge(v3, v2); MeshFacet f = mg.AddFacet(v1, v2, v3); CollectionAssert.Contains(mg.Vertices, v1); CollectionAssert.Contains(mg.Vertices, v2); CollectionAssert.Contains(mg.Vertices, v3); Assert.AreEqual(v1.EdgeConnecting(v2), v2.EdgeConnecting(v1), "", e1); Assert.AreEqual(v3.EdgeConnecting(v2), v2.EdgeConnecting(v3), "", e2); CollectionAssert.Contains(mg.Edges, v1.EdgeConnecting(v2)); CollectionAssert.Contains(mg.Edges, v2.EdgeConnecting(v3)); CollectionAssert.Contains(mg.Edges, v3.EdgeConnecting(v1)); CollectionAssert.Contains(e1.AdjacencyFacets, f); CollectionAssert.Contains(e1.Endpoints, v1); CollectionAssert.Contains(f.Vertices, v1); CollectionAssert.Contains(f.Vertices, v2); CollectionAssert.Contains(f.Vertices, v3); CollectionAssert.Contains(f.Edges, v1.EdgeConnecting(v2)); CollectionAssert.Contains(f.Edges, v2.EdgeConnecting(v3)); CollectionAssert.Contains(f.Edges, v3.EdgeConnecting(v1)); { // Remove the facet MeshGraph rm = mg.Clone(); MeshFacet rmf = rm.Eqv(f); rm.RemoveFacet(rmf); CollectionAssert.DoesNotContain(rm.Facets, rmf); CollectionAssert.DoesNotContain( rm.Eqv(e1).AdjacencyFacets, rmf); CollectionAssert.DoesNotContain( rm.Eqv(e2).AdjacencyFacets, rmf); } { // Remove an edge MeshGraph rm = mg.Clone(); MeshEdge rme = rm.Eqv(e1); MeshFacet rmf = rm.Eqv(f); rm.RemoveEdge(rme); CollectionAssert.DoesNotContain(rm.Edges, rme); CollectionAssert.DoesNotContain(rm.Facets, rmf); CollectionAssert.DoesNotContain( rme.AdjacencyFacets, rmf); CollectionAssert.DoesNotContain( rm.Eqv(e2).AdjacencyFacets, rmf); } { // Remove an vertex MeshGraph rm = mg.Clone(); MeshVertex rmv = rm.Eqv(v2); MeshEdge rme1 = rm.Eqv(v2.EdgeConnecting(rm.Eqv(v1))); MeshEdge rme2 = rm.Eqv(v2.EdgeConnecting(rm.Eqv(v3))); MeshFacet rmf = rm.Eqv(f); rm.RemoveVertex(rmv); CollectionAssert.DoesNotContain(rm.Vertices, rmv); CollectionAssert.DoesNotContain(rm.Edges, rme1); CollectionAssert.DoesNotContain(rm.Edges, rme2); CollectionAssert.DoesNotContain(rm.Facets, rmf); Assert.AreEqual(rmv.Edges.Count, 0); foreach (var v in rm.Vertices) { Assert.AreEqual(v.Edges.Count, 1); } } }
public MeshFacet AddTriangle(Vector3 posdir, params MeshVertex[] vs) { // There should always be one edge that has connected with // another facet to create a correct facet, otherwise the // algorithm will create the facet corresponding to posdir bool has_connected_edge = false; // After sorting, vs[0] -> vs[1] -> vs[2] is a positive order for (int i = 0; i < 2; i++) { for (int j = i + 1; j < 2; j++) { MeshEdge e = vs[i].EdgeConnecting(vs[j]); if (e == null) { continue; } if (e.F1 != null) { has_connected_edge = true; MeshVertex[] sorted_vs = new MeshVertex[3]; sorted_vs[0] = e.V2; sorted_vs[1] = e.V1; sorted_vs[2] = vs[3 - i - j]; vs = sorted_vs; break; } if (e.F2 != null) { has_connected_edge = true; MeshVertex[] sorted_vs = new MeshVertex[3]; sorted_vs[0] = e.V1; sorted_vs[1] = e.V2; sorted_vs[2] = vs[3 - i - j]; vs = sorted_vs; break; } } } if (!has_connected_edge) { Vector3 normal = Vector3.Cross( vs[1].Position - vs[0].Position, vs[2].Position - vs[1].Position); if (Vector3.Dot(posdir, normal) < 0) { MeshVertex[] sorted_vs = new MeshVertex[3]; sorted_vs[0] = vs[2]; sorted_vs[1] = vs[1]; sorted_vs[2] = vs[0]; vs = sorted_vs; } } return(this.AddFacet(vs)); }
public MeshFacet AddFacet(params MeshVertex[] vs) { if (vs.Length < 3) { throw new Exception("Vertex count less than 3."); } for (int vi = 0; vi < vs.Length; vi++) { if (vs[vi] == vs[(vi + 1) % vs.Length]) { throw new Exception("Ill-formed vertex sequence"); } } MeshFacet f = new MeshFacet(vs); string failure = ""; for (int vi = 0; vi < vs.Length; vi++) { MeshVertex p1 = vs[vi]; MeshVertex p2 = vs[(vi + 1) % vs.Length]; MeshEdge e = AddEdge(p1, p2); if (e.V1 == p1 && e.V2 == p2) { if (e.f1 != null) { failure = "Positive facet has been occupied"; break; } e.f1 = f; } else if (e.V1 == p2 && e.V2 == p1) { if (e.f2 != null) { failure = "Negative facet has been occupied"; break; } e.f2 = f; } else { throw new Exception("Unexpected edge"); } } // rollback if (failure.Length > 0) { foreach (MeshEdge e in f.Edges) { if (e == null) { continue; } if (e.f1 == f) { e.f1 = null; } if (e.f2 == f) { e.f2 = null; } } throw new Exception(failure); } int i = facets.Count; facets.Add(f); f.SetGraphInfo(this, i); triangles += f.TrianglesCount; return(f); }
public MeshEdge AddEdge(MeshVertex p1, MeshVertex p2, bool check_facet = false) { MeshEdge e = p1.EdgeConnecting(p2); if (e != null) { return(e); } if (p1 == p2) { return(null); } e = new MeshEdge(p1, p2); p1.adjacency.Add(p2, e); p2.adjacency.Add(p1, e); int i = edges.Count; edges.Add(e); e.SetGraphInfo(this, i); if (check_facet) { // check the intersection MeshFacet common_facet = null; HashSet <MeshFacet> p1f = new HashSet <MeshFacet>( p1.AdjacencyFacets); foreach (MeshFacet f in p2.AdjacencyFacets) { if (p1f.Contains(f)) { common_facet = f; break; } } if (common_facet != null) { List <MeshVertex> f1 = new List <MeshVertex>(); List <MeshVertex> f2 = new List <MeshVertex>(); List <MeshVertex> current = f1; foreach (MeshVertex v in common_facet.Vertices) { // if current vertex matches p1 or p2, add this vertex // to both vertex list and switch current to the other one current.Add(v); if (v == p1) { current = current == f1 ? f2 : f1; current.Add(p1); } else if (v == p2) { current = current == f1 ? f2 : f1; current.Add(p2); } } this.RemoveFacet(common_facet); this.AddFacet(f1.ToArray()); this.AddFacet(f2.ToArray()); } } return(e); }