/// <summary> /// Remove all bowtie vertices in mesh. Makes one pass unless /// bRepeatUntilClean = true, in which case repeats until no more bowties found /// Returns true if any vertices were removed /// </summary> public bool RemoveAllBowtieVertices(bool bRepeatUntilClean) { int nRemoved = 0; while (true) { List <int> bowties = new List <int>(); foreach (int vID in Mesh.VertexIndices()) { if (Mesh.IsBowtieVertex(vID)) { bowties.Add(vID); } } if (bowties.Count == 0) { break; } foreach (int vID in bowties) { MeshResult result = Mesh.RemoveVertex(vID, true, false); Debug.Assert(result == MeshResult.Ok); nRemoved++; } if (bRepeatUntilClean == false) { break; } } return(nRemoved > 0); }
public static void flip_tests(bool bTestBoundary, int N = 100) { System.Console.WriteLine("DMesh3:flip_tests() starting"); DMesh3 mesh = TestUtil.MakeCappedCylinder(bTestBoundary); mesh.CheckValidity(); Random r = new Random(31377); for (int k = 0; k < N; ++k) { int eid = r.Next() % mesh.EdgeCount; if (!mesh.IsEdge(eid)) { continue; } bool bBoundary = mesh.IsBoundaryEdge(eid); DMesh3.EdgeFlipInfo flipInfo; MeshResult result = mesh.FlipEdge(eid, out flipInfo); if (bBoundary) { Debug.Assert(result == MeshResult.Failed_IsBoundaryEdge); } else { Debug.Assert(result == MeshResult.Ok || result == MeshResult.Failed_FlippedEdgeExists); } mesh.CheckValidity(); } System.Console.WriteLine("flips ok"); }
/// <summary> /// insert new point into segment eid at parameter value t /// If t is within tol of endpoint of segment, we use that instead. /// </summary> protected Index2i split_segment_at_t(int eid, double t, double tol) { Index2i ev = Graph.GetEdgeV(eid); Segment2d seg = new Segment2d(Graph.GetVertex(ev.a), Graph.GetVertex(ev.b)); int use_vid = -1; int new_eid = -1; if (t < -(seg.Extent - tol)) { use_vid = ev.a; } else if (t > (seg.Extent - tol)) { use_vid = ev.b; } else { DGraph2.EdgeSplitInfo splitInfo; MeshResult result = Graph.SplitEdge(eid, out splitInfo); if (result != MeshResult.Ok) { throw new Exception("insert_into_segment: edge split failed?"); } use_vid = splitInfo.vNew; new_eid = splitInfo.eNewBN; Vector2d pt = seg.PointAt(t); Graph.SetVertex(use_vid, pt); PointHash.InsertPointUnsafe(splitInfo.vNew, pt); } return(new Index2i(use_vid, new_eid)); }
void remove_remaining_interior_verts() { HashSet <int> interiorv = new HashSet <int>(MeshIterators.InteriorVertices(fillmesh)); int prev_count = 0; while (interiorv.Count > 0 && interiorv.Count != prev_count) { prev_count = interiorv.Count; int[] curv = interiorv.ToArray(); foreach (int vid in curv) { foreach (int e in fillmesh.VtxEdgesItr(vid)) { Index2i ev = fillmesh.GetEdgeV(e); int otherv = (ev.a == vid) ? ev.b : ev.a; DMesh3.EdgeCollapseInfo info; MeshResult result = fillmesh.CollapseEdge(otherv, vid, out info); if (result == MeshResult.Ok) { break; } } if (fillmesh.IsVertex(vid) == false) { interiorv.Remove(vid); } } } if (interiorv.Count > 0) { Util.gBreakToDebugger(); } }
public static void split_tests_nonmanifold(int N = 100) { System.Console.WriteLine("split_tests_nonmanifold() starting"); Random r = new Random(31337); NTMesh3 mesh = new NTMesh3(); int a = mesh.AppendVertex(Vector3d.Zero); int b = mesh.AppendVertex(Vector3d.AxisZ); for (int k = 0; k < 5; ++k) { int c = mesh.AppendVertex(TestUtil.RandomPoints3(1, r, Vector3d.Zero, 1)[0]); int tid = mesh.AppendTriangle(new Index3i(a, b, c)); Debug.Assert(tid >= 0); } TestUtil.WriteTestOutputMesh(mesh.Deconstruct(), "nonmanifold_split_input.obj"); for (int k = 0; k < N; ++k) { int eid = r.Next() % mesh.EdgeCount; if (!mesh.IsEdge(eid)) { continue; } NTMesh3.EdgeSplitInfo splitInfo; MeshResult result = mesh.SplitEdge(eid, out splitInfo); Debug.Assert(result == MeshResult.Ok); mesh.CheckValidity(FailMode.DebugAssert); } TestUtil.WriteTestOutputMesh(mesh.Deconstruct(), "nonmanifold_split_output.obj"); }
public static void split_tests(bool bTestBoundary, int N = 100) { System.Console.WriteLine("split_tests() starting"); NTMesh3 mesh = new NTMesh3(TestUtil.MakeCappedCylinder(bTestBoundary)); mesh.CheckValidity(FailMode.DebugAssert); Random r = new Random(31377); for (int k = 0; k < N; ++k) { int eid = r.Next() % mesh.EdgeCount; if (!mesh.IsEdge(eid)) { continue; } NTMesh3.EdgeSplitInfo splitInfo; MeshResult result = mesh.SplitEdge(eid, out splitInfo); Debug.Assert(result == MeshResult.Ok); mesh.CheckValidity(FailMode.DebugAssert); } System.Console.WriteLine("splits ok"); }
public static void poke_test() { NTMesh3 mesh = new NTMesh3(TestUtil.LoadTestInputMesh("plane_250v.obj")); //DMesh3 mesh = TestUtil.LoadTestInputMesh("sphere_bowtie_groups.obj"); mesh.CheckValidity(); int NT = mesh.TriangleCount; for (int i = 0; i < NT; i += 5) { Vector3d n = mesh.GetTriNormal(i); NTMesh3.PokeTriangleInfo pokeinfo; MeshResult result = mesh.PokeTriangle(i, out pokeinfo); Vector3d v = mesh.GetVertex(pokeinfo.new_vid); v += 0.25f * n; mesh.SetVertex(pokeinfo.new_vid, v); mesh.CheckValidity(); } System.Console.WriteLine("pokes ok"); //TestUtil.WriteTestOutputMesh(mesh, "poke_test_result.obj"); }
/***************************************************/ public static List <Mesh> DeformedShape(List <FEMesh> meshes, List <MeshResult> meshDeformations, string adapterId, object loadCase, double scaleFactor = 1.0) { meshDeformations = meshDeformations.SelectCase(loadCase); List <Mesh> defMeshes = new List <Mesh>(); var resGroups = meshDeformations.GroupBy(x => x.ObjectId.ToString()).ToDictionary(x => x.Key); foreach (FEMesh feMesh in meshes) { string id = feMesh.CustomData[adapterId].ToString(); List <MeshResult> deformations; IGrouping <string, MeshResult> outVal; if (resGroups.TryGetValue(id, out outVal)) { deformations = outVal.ToList(); } else { continue; } MeshResult singleDisp = deformations.Where(x => x.ObjectId.ToString() == id && x.Results.First() is MeshDisplacement).First(); defMeshes.Add(DeformedMesh(feMesh, singleDisp.Results.Cast <MeshDisplacement>(), adapterId, scaleFactor)); } return(defMeshes); }
/// <summary> /// Remove vertices that are colinear w/ their two neighbours, within angle tolerance /// </summary> public void CollapseFlatVertices(double fMaxDeviationDeg = 5) { bool done = false; int max_passes = 200; int pass_count = 0; while (done == false && pass_count++ < max_passes) { done = true; // [RMS] do modulo-indexing here to avoid pathological cases where we do things like // continually collapse a short edge adjacent to a long edge (which will result in crazy over-collapse) int N = Graph.MaxVertexID; const int nPrime = 31337; // any prime will do... int cur_vid = 0; do { int vid = cur_vid; cur_vid = (cur_vid + nPrime) % N; if (!Graph.IsVertex(vid)) { continue; } if (Graph.GetVtxEdgeCount(vid) != 2) { continue; } double open = Math.Abs(Graph.OpeningAngle(vid)); if (open < 180 - fMaxDeviationDeg) { continue; } var edges = Graph.GetVtxEdges(vid); int eid = edges.First(); int eid2 = edges.Last(); if (FixedEdgeFilterF(eid) || FixedEdgeFilterF(eid2)) { continue; } Index2i ev = Graph.GetEdgeV(eid); int other_v = (ev.a == vid) ? ev.b : ev.a; DGraph2.EdgeCollapseInfo collapseInfo; MeshResult result = Graph.CollapseEdge(other_v, vid, out collapseInfo); if (result == MeshResult.Ok) { done = false; } else { throw new Exception("DGraph2Resampler.CollapseFlatVertices: failed!"); } } while (cur_vid != 0); } }
public void Initialize(DMesh3 mesh, IEnumerable <int> triangles) { initialize_buffers(mesh); bool has_groups = mesh.HasTriangleGroups; foreach (int tid in triangles) { if (!mesh.IsTriangle(tid)) { continue; } Index3i tv = mesh.GetTriangle(tid); bool va = save_vertex(mesh, tv.a); bool vb = save_vertex(mesh, tv.b); bool vc = save_vertex(mesh, tv.c); Index4i tri = new Index4i(tv.a, tv.b, tv.c, has_groups ? mesh.GetTriangleGroup(tid) : DMesh3.InvalidID); RemovedT.Add(tid); Triangles.Add(tri); MeshResult result = mesh.RemoveTriangle(tid, true, false); if (result != MeshResult.Ok) { throw new Exception("RemoveTrianglesMeshChange.Initialize: exception in RemoveTriangle(" + tid.ToString() + "): " + result.ToString()); } Util.gDevAssert(mesh.IsVertex(tv.a) == va && mesh.IsVertex(tv.b) == vb && mesh.IsVertex(tv.c) == vc); } }
// insert point at bary_coords inside tid. If point is at vtx, just use that vtx. // If it is on an edge, do an edge split. Otherwise poke face. int insert_corner_from_bary(int iCorner, int tid, Vector3d bary_coords, double tol = MathUtil.ZeroTolerance) { Vector2d vInsert = Curve[iCorner]; Index3i tv = Mesh.GetTriangle(tid); // handle cases where corner is on a vertex if (bary_coords.x > 1 - tol) { return(tv.a); } else if (bary_coords.y > 1 - tol) { return(tv.b); } else if (bary_coords.z > 1 - tol) { return(tv.c); } // handle cases where corner is on an edge int split_edge = -1; if (bary_coords.x < tol) { split_edge = 1; } else if (bary_coords.y < tol) { split_edge = 2; } else if (bary_coords.z < tol) { split_edge = 0; } if (split_edge >= 0) { int eid = Mesh.GetTriEdge(tid, split_edge); DMesh3.EdgeSplitInfo split_info; MeshResult splitResult = Mesh.SplitEdge(eid, out split_info); if (splitResult != MeshResult.Ok) { throw new Exception("MeshInsertUVPolyCurve.insert_corner_special: edge split failed in case sum==2"); } SetPointF(split_info.vNew, vInsert); return(split_info.vNew); } // otherwise corner is inside triangle DMesh3.PokeTriangleInfo pokeinfo; MeshResult result = Mesh.PokeTriangle(tid, bary_coords, out pokeinfo); if (result != MeshResult.Ok) { throw new Exception("MeshInsertUVPolyCurve.insert_corner_special: face poke failed!"); } SetPointF(pokeinfo.new_vid, vInsert); return(pokeinfo.new_vid); }
public void Apply(DMesh3 mesh) { int NV = AddedV.size; if (NV > 0) { NewVertexInfo vinfo = new NewVertexInfo(Positions[0]); mesh.BeginUnsafeVerticesInsert(); for (int i = 0; i < NV; ++i) { int vid = AddedV[i]; vinfo.v = Positions[i]; if (Normals != null) { vinfo.bHaveN = true; vinfo.n = Normals[i]; } if (Colors != null) { vinfo.bHaveC = true; vinfo.c = Colors[i]; } if (UVs != null) { vinfo.bHaveUV = true; vinfo.uv = UVs[i]; } MeshResult result = mesh.InsertVertex(vid, ref vinfo, true); if (result != MeshResult.Ok) { throw new Exception("AddTrianglesMeshChange.Revert: error in InsertVertex(" + vid.ToString() + "): " + result.ToString()); } } mesh.EndUnsafeVerticesInsert(); } int NT = AddedT.size; if (NT > 0) { mesh.BeginUnsafeTrianglesInsert(); for (int i = 0; i < NT; ++i) { int tid = AddedT[i]; Index4i tdata = Triangles[i]; Index3i tri = new Index3i(tdata.a, tdata.b, tdata.c); MeshResult result = mesh.InsertTriangle(tid, tri, tdata.d, true); if (result != MeshResult.Ok) { throw new Exception("AddTrianglesMeshChange.Revert: error in InsertTriangle(" + tid.ToString() + "): " + result.ToString()); } } mesh.EndUnsafeTrianglesInsert(); } if (OnApplyF != null) { OnApplyF(AddedV, AddedT); } }
private static void ProcessMesh(IMesh mesh, MeshResult result) { result.NumberOfTriangles += mesh.Triangles.Count; if (!MeshValidator.IsConsistent((Mesh)mesh)) { result.Invalid += 1; } }
public static void collapse_tests(bool bTestBoundary, int N = 100) { bool write_debug_meshes = false; DMesh3 mesh = TestUtil.MakeCappedCylinder(bTestBoundary); mesh.CheckValidity(); System.Console.WriteLine(string.Format("DMesh3:collapse_tests() starting - test bdry {2}, verts {0} tris {1}", mesh.VertexCount, mesh.TriangleCount, bTestBoundary)); if (write_debug_meshes) { TestUtil.WriteDebugMesh(mesh, string.Format("before_collapse_{0}.obj", ((bTestBoundary)?"boundary":"noboundary"))); } Random r = new Random(31377); for (int k = 0; k < N; ++k) { int eid = r.Next() % mesh.EdgeCount; if (!mesh.IsEdge(eid)) { continue; } //bool bBoundary = mesh.IsBoundaryEdge(eid); //if (bTestBoundary && bBoundary == false) // continue; Index2i ev = mesh.GetEdgeV(eid); DMesh3.EdgeCollapseInfo collapseInfo; MeshResult result = mesh.CollapseEdge(ev[0], ev[1], out collapseInfo); Debug.Assert( result != MeshResult.Failed_NotAnEdge && result != MeshResult.Failed_FoundDuplicateTriangle); mesh.CheckValidity(); } System.Console.WriteLine(string.Format("random collapses ok - verts {0} tris {1}", mesh.VertexCount, mesh.TriangleCount)); collapse_to_convergence(mesh); System.Console.WriteLine(string.Format("all possible collapses ok - verts {0} tris {1}", mesh.VertexCount, mesh.TriangleCount)); if (write_debug_meshes) { TestUtil.WriteDebugMesh(mesh, string.Format("after_collapse_{0}.obj", ((bTestBoundary)?"boundary":"noboundary"))); } }
/// <summary> /// Remove vertex vID, and all connected triangles if bRemoveAllTriangles = true /// (if false, them throws exception if there are still any triangles!) /// if bPreserveManifold, checks that we will not create a bowtie vertex first /// </summary> public MeshResult RemoveVertex(int vID, bool bRemoveAllTriangles = true, bool bPreserveManifold = true) { if (vertices_refcount.isValid(vID) == false) { return(MeshResult.Failed_NotAVertex); } if (bRemoveAllTriangles) { // if any one-ring vtx is a boundary vtx and one of its outer-ring edges is an // interior edge then we will create a bowtie if we remove that triangle if (bPreserveManifold) { foreach (int tid in VtxTrianglesItr(vID)) { Index3i tri = GetTriangle(tid); int j = IndexUtil.find_tri_index(vID, tri); int oa = tri[(j + 1) % 3], ob = tri[(j + 2) % 3]; int eid = find_edge(oa, ob); if (edge_is_boundary(eid)) { continue; } if (vertex_is_boundary(oa) || vertex_is_boundary(ob)) { return(MeshResult.Failed_WouldCreateBowtie); } } } List <int> tris = new List <int>(); GetVtxTriangles(vID, tris, true); foreach (int tID in tris) { MeshResult result = RemoveTriangle(tID, false, bPreserveManifold); if (result != MeshResult.Ok) { return(result); } } } if (vertices_refcount.refCount(vID) != 1) { throw new NotImplementedException("DMesh3.RemoveVertex: vertex is still referenced"); } vertices_refcount.decrement(vID); Debug.Assert(vertices_refcount.isValid(vID) == false); vertex_edges[vID] = null; updateTimeStamp(true); return(MeshResult.Ok); }
// this is for backing out changes we have made... bool remove_triangles(int[] tri_list, int count) { for (int i = 0; i < count; ++i) { MeshResult result = Mesh.RemoveTriangle(tri_list[i], false, false); if (result != MeshResult.Ok) { return(false); } } return(true); }
public void Apply(DMesh3 mesh) { int N = RemovedT.size; for (int i = 0; i < N; ++i) { int tid = RemovedT[i]; MeshResult result = mesh.RemoveTriangle(RemovedT[i], true, false); if (result != MeshResult.Ok) { throw new Exception("RemoveTrianglesMeshChange.Apply: error in RemoveTriangle(" + tid.ToString() + "): " + result.ToString()); } } }
public MeshResult RemoveVertex(int vid, bool bRemoveIsolatedVertices) { var edges = new List <int>(GetVtxEdges(vid)); foreach (int eid in edges) { MeshResult result = RemoveEdge(eid, bRemoveIsolatedVertices); if (result != MeshResult.Ok) { return(result); } } return(MeshResult.Ok); }
public static List <Mesh> DeformedShape(List <FEMesh> meshes, List <MeshResult> meshDisplacements, Type adapterIdType, object loadcase, double scaleFactor = 1.0) { if (adapterIdType == null) { Reflection.Compute.RecordError("The provided adapter id type is null."); return(new List <Mesh>()); } if (!typeof(IAdapterId).IsAssignableFrom(adapterIdType)) { Reflection.Compute.RecordError($"The `{adapterIdType.Name}` is not a valid `{typeof(IAdapterId).Name}`."); return(new List <Mesh>()); } meshDisplacements = meshDisplacements.SelectCase(loadcase); List <Mesh> defMeshes = new List <Mesh>(); var resGroups = meshDisplacements.GroupBy(x => x.ObjectId.ToString()).ToDictionary(x => x.Key); foreach (FEMesh feMesh in meshes) { IAdapterId idFragment = feMesh.FindFragment <IAdapterId>(adapterIdType); if (idFragment == null) { Engine.Reflection.Compute.RecordWarning("Could not find the adapter id for at least one FEMesh."); continue; } string id = idFragment.Id.ToString(); List <MeshResult> deformations; IGrouping <string, MeshResult> outVal; if (resGroups.TryGetValue(id, out outVal)) { deformations = outVal.ToList(); } else { continue; } MeshResult singleDisp = deformations.Where(x => x.ObjectId.ToString() == id && x.Results.First() is IMeshDisplacement).First(); defMeshes.Add(DeformedMesh(feMesh, singleDisp.Results.Cast <IMeshDisplacement>(), adapterIdType, scaleFactor)); } return(defMeshes); }
/// <summary> /// For each on-face vtx, we poke the face, and re-sort /// the remaining vertices on that face onto new faces/edges /// </summary> void insert_face_vertices() { while (FaceVertices.Count > 0) { var pair = FaceVertices.First(); int tid = pair.Key; List <SegmentVtx> triVerts = pair.Value; SegmentVtx v = triVerts[triVerts.Count - 1]; triVerts.RemoveAt(triVerts.Count - 1); DMesh3.PokeTriangleInfo pokeInfo; MeshResult result = Target.PokeTriangle(tid, out pokeInfo); if (result != MeshResult.Ok) { throw new Exception("shit"); } int new_v = pokeInfo.new_vid; Target.SetVertex(new_v, v.v); v.vtx_id = new_v; VIDToSegVtxMap[v.vtx_id] = v; PointHash.InsertPoint(v.vtx_id, v.v); // remove this triangles vtx list because it is no longer valid FaceVertices.Remove(tid); // update remaining verts Index3i pokeEdges = pokeInfo.new_edges; var pokeTris = new Index3i(tid, pokeInfo.new_t1, pokeInfo.new_t2); foreach (SegmentVtx sv in triVerts) { update_from_poke(sv, pokeEdges, pokeTris); if (sv.type == 1) { add_edge_vtx(sv.elem_id, sv); } else if (sv.type == 2) { add_face_vtx(sv.elem_id, sv); } } // track poke subfaces add_poke_subfaces(tid, ref pokeInfo); } }
/// <summary> /// for each on-edge vtx, we split the edge and then /// re-sort any of the vertices on that edge onto new edges /// </summary> void insert_edge_vertices() { while (EdgeVertices.Count > 0) { var pair = EdgeVertices.First(); int eid = pair.Key; List <SegmentVtx> edgeVerts = pair.Value; SegmentVtx v = edgeVerts[edgeVerts.Count - 1]; edgeVerts.RemoveAt(edgeVerts.Count - 1); Index2i splitTris = Target.GetEdgeT(eid); DMesh3.EdgeSplitInfo splitInfo; MeshResult result = Target.SplitEdge(eid, out splitInfo); if (result != MeshResult.Ok) { throw new Exception("insert_edge_vertices: split failed!"); } int new_v = splitInfo.vNew; var splitEdges = new Index2i(eid, splitInfo.eNewBN); Target.SetVertex(new_v, v.v); v.vtx_id = new_v; VIDToSegVtxMap[v.vtx_id] = v; PointHash.InsertPoint(v.vtx_id, v.v); // remove this triangles vtx list because it is no longer valid EdgeVertices.Remove(eid); // update remaining verts foreach (SegmentVtx sv in edgeVerts) { update_from_split(sv, splitEdges); if (sv.type == 1) { add_edge_vtx(sv.elem_id, sv); } } // track subfaces add_split_subfaces(splitTris, ref splitInfo); } }
bool collapse_degenerate_edges( double minLength, bool bBoundaryOnly, out int collapseCount) { collapseCount = 0; // don't iterate sequentially because there may be pathological cases foreach (int eid in MathUtil.ModuloIteration(Mesh.MaxEdgeID)) { if (Cancelled()) { break; } if (Mesh.IsEdge(eid) == false) { continue; } bool is_boundary_edge = Mesh.IsBoundaryEdge(eid); if (bBoundaryOnly && is_boundary_edge == false) { continue; } Index2i ev = Mesh.GetEdgeV(eid); Vector3d a = Mesh.GetVertex(ev.a), b = Mesh.GetVertex(ev.b); if (a.Distance(b) < minLength) { int keep = Mesh.IsBoundaryVertex(ev.a) ? ev.a : ev.b; int discard = (keep == ev.a) ? ev.b : ev.a; DMesh3.EdgeCollapseInfo collapseInfo; MeshResult result = Mesh.CollapseEdge(keep, discard, out collapseInfo); if (result == MeshResult.Ok) { ++collapseCount; if (Mesh.IsBoundaryVertex(keep) == false || is_boundary_edge) { Mesh.SetVertex(keep, (a + b) * 0.5); } } } } return(true); }
public void Revert(DMesh3 mesh) { int N = AddedT.size; for (int i = 0; i < N; ++i) { int tid = AddedT[i]; MeshResult result = mesh.RemoveTriangle(AddedT[i], true, false); if (result != MeshResult.Ok) { throw new Exception("AddTrianglesMeshChange.Apply: error in RemoveTriangle(" + tid.ToString() + "): " + result.ToString()); } } if (OnRevertF != null) { OnRevertF(AddedV, AddedT); } }
// [TODO] cannot back-out this operation right now // // Remove list of triangles. Values of triangles[] set to InvalidID are ignored. public bool RemoveTriangles(int[] triangles, bool bRemoveIsolatedVerts) { bool bAllOK = true; for (int i = 0; i < triangles.Length; ++i) { if (triangles[i] == DMesh3.InvalidID) { continue; } MeshResult result = Mesh.RemoveTriangle(triangles[i], bRemoveIsolatedVerts, false); if (result != MeshResult.Ok) { bAllOK = false; } } return(bAllOK); }
// [TODO] cannot back-out this operation right now // // Remove list of triangles. Values of triangles[] set to InvalidID are ignored. public bool RemoveTriangles(IEnumerable <int> triangles, bool bRemoveIsolatedVerts) { bool bAllOK = true; foreach (int tid in triangles) { if (!Mesh.IsTriangle(tid)) { bAllOK = false; continue; } MeshResult result = Mesh.RemoveTriangle(tid, bRemoveIsolatedVerts, false); if (result != MeshResult.Ok) { bAllOK = false; } } return(bAllOK); }
// [TODO] cannot back-out this operation right now // // Remove all triangles identified by selectorF returning true public bool RemoveTriangles(Func <int, bool> selectorF, bool bRemoveIsolatedVerts) { bool bAllOK = true; int NT = Mesh.MaxTriangleID; for (int ti = 0; ti < NT; ++ti) { if (Mesh.IsTriangle(ti) == false || selectorF(ti) == false) { continue; } MeshResult result = Mesh.RemoveTriangle(ti, bRemoveIsolatedVerts, false); if (result != MeshResult.Ok) { bAllOK = false; } } return(bAllOK); }
private bool CollapseDegenerateEdges(DMesh3 mesh, CancellationToken cancellationToken, double minLength, bool bBoundaryOnly, out int collapseCount) { collapseCount = 0; // don't iterate sequentially because there may be pathological cases foreach (int eid in MathUtil.ModuloIteration(mesh.MaxEdgeID)) { cancellationToken.ThrowIfCancellationRequested(); if (mesh.IsEdge(eid) == false) { continue; } bool isBoundaryEdge = mesh.IsBoundaryEdge(eid); if (bBoundaryOnly && isBoundaryEdge == false) { continue; } Index2i ev = mesh.GetEdgeV(eid); Vector3d a = mesh.GetVertex(ev.a), b = mesh.GetVertex(ev.b); if (a.Distance(b) < minLength) { int keep = mesh.IsBoundaryVertex(ev.a) ? ev.a : ev.b; int discard = (keep == ev.a) ? ev.b : ev.a; MeshResult result = mesh.CollapseEdge(keep, discard, out DMesh3.EdgeCollapseInfo collapseInfo); if (result == MeshResult.Ok) { ++collapseCount; if (mesh.IsBoundaryVertex(keep) == false || isBoundaryEdge) { mesh.SetVertex(keep, (a + b) * 0.5); } } } } return(true); }
} // Cut() protected void collapse_degenerate_edges(HashSet <int> OnCutEdges, HashSet <int> ZeroEdges) { var sets = new HashSet <int>[2] { OnCutEdges, ZeroEdges }; double tol2 = DegenerateEdgeTol * DegenerateEdgeTol; Vector3d a = Vector3d.Zero, b = Vector3d.Zero; int collapsed = 0; do { collapsed = 0; foreach (var edge_set in sets) { foreach (int eid in edge_set) { if (Mesh.IsEdge(eid) == false) { continue; } Mesh.GetEdgeV(eid, ref a, ref b); if (a.DistanceSquared(b) > tol2) { continue; } Index2i ev = Mesh.GetEdgeV(eid); DMesh3.EdgeCollapseInfo collapseInfo; MeshResult result = Mesh.CollapseEdge(ev.a, ev.b, out collapseInfo); if (result == MeshResult.Ok) { collapsed++; } } } } while (collapsed != 0); }
void split_missing(MeshMeshCut fromOp, MeshMeshCut toOp, DMesh3 fromMesh, DMesh3 toMesh, HashSet <int> fromVerts, HashSet <int> toVerts) { List <int> missing = new List <int>(); foreach (int vid in fromVerts) { Vector3d v = fromMesh.GetVertex(vid); int near_vid = find_nearest_vertex(toMesh, v, toVerts); if (near_vid == DMesh3.InvalidID) { missing.Add(vid); } } foreach (int vid in missing) { Vector3d v = fromMesh.GetVertex(vid); int near_eid = find_nearest_edge(toMesh, v, toVerts); if (near_eid == DMesh3.InvalidID) { System.Console.WriteLine("could not find edge to split?"); continue; } DMesh3.EdgeSplitInfo splitInfo; MeshResult result = toMesh.SplitEdge(near_eid, out splitInfo); if (result != MeshResult.Ok) { System.Console.WriteLine("edge split failed"); continue; } toMesh.SetVertex(splitInfo.vNew, v); toVerts.Add(splitInfo.vNew); } }
// this function collapses edges until it can't anymore static void collapse_to_convergence(DMesh3 mesh) { bool bContinue = true; while (bContinue) { bContinue = false; for (int eid = 0; eid < mesh.MaxEdgeID; ++eid) { if (!mesh.IsEdge(eid)) { continue; } Index2i ev = mesh.GetEdgeV(eid); DMesh3.EdgeCollapseInfo collapseInfo; MeshResult result = mesh.CollapseEdge(ev[0], ev[1], out collapseInfo); if (result == MeshResult.Ok) { bContinue = true; break; } } } }