/// <summary> /// Remove any connected components with volume < min_volume area lt; min_area /// </summary> public int RemoveSmallComponents(double min_volume, double min_area) { MeshConnectedComponents C = new MeshConnectedComponents(Mesh); C.FindConnectedT(); if (C.Count == 1) { return(0); } int nRemoved = 0; foreach (var comp in C.Components) { Vector2d vol_area = MeshMeasurements.VolumeArea(Mesh, comp.Indices, Mesh.GetVertex); if (vol_area.x < min_volume || vol_area.y < min_area) { MeshEditor.RemoveTriangles(Mesh, comp.Indices); nRemoved++; } } return(nRemoved); }
// Remove the original submesh region and merge in the remeshed version. // You can call this multiple times as the base-triangle-set is updated. // // By default, we allow the submesh to be modified to prevent creation of // non-manifold edges. You can disable this, however then some of the submesh // triangles may be discarded. // // Returns false if there were errors in insertion, ie if some triangles // failed to insert. Does not revert changes that were successful. public bool BackPropropagate(bool bAllowSubmeshRepairs = true) { if (bAllowSubmeshRepairs) { RepairPossibleNonManifoldEdges(); } // remove existing submesh triangles MeshEditor editor = new MeshEditor(BaseMesh); editor.RemoveTriangles(cur_base_tris, true); // insert new submesh int[] new_tris = new int[Region.SubMesh.TriangleCount]; ReinsertSubToBaseMapV = null; bool bOK = editor.ReinsertSubmesh(Region, ref new_tris, out ReinsertSubToBaseMapV, ReinsertDuplicateTriBehavior); // reconstruct this...hacky? int NT = Region.SubMesh.MaxTriangleID; ReinsertSubToBaseMapT = new IndexMap(false, NT); int nti = 0; for (int ti = 0; ti < NT; ++ti) { if (Region.SubMesh.IsTriangle(ti) == false) { continue; } ReinsertSubToBaseMapT[ti] = new_tris[nti++]; } // assert that new triangles are all valid (goes wrong sometimes??) Debug.Assert(IndexUtil.IndicesCheck(new_tris, BaseMesh.IsTriangle)); cur_base_tris = new_tris; return(bOK); }
// Remove the original submesh region and merge in the remeshed version. // You can call this multiple times as the base-triangle-set is updated. // // By default, we allow the submesh to be modified to prevent creation of // non-manifold edges. You can disable this, however then some of the submesh // triangles may be discarded. // // Returns false if there were errors in insertion, ie if some triangles // failed to insert. Does not revert changes that were successful. public bool BackPropropagate(bool bAllowSubmeshRepairs = true) { if (bAllowSubmeshRepairs) { RepairPossibleNonManifoldEdges(); } // remove existing submesh triangles MeshEditor editor = new MeshEditor(BaseMesh); editor.RemoveTriangles(cur_base_tris, true); // insert new submesh int[] new_tris = new int[Region.SubMesh.TriangleCount]; ReinsertSubToBaseMapV = null; bool bOK = editor.ReinsertSubmesh(Region, ref new_tris, out ReinsertSubToBaseMapV, ReinsertDuplicateTriBehavior); // assert that new triangles are all valid (goes wrong sometimes??) Debug.Assert(IndexUtil.IndicesCheck(new_tris, BaseMesh.IsTriangle)); cur_base_tris = new_tris; return(bOK); }
public virtual bool Trim() { if (Spatial == null) { Spatial = new DMeshAABBTree3(new DMesh3(Mesh, false, MeshComponents.None)); Spatial.Build(); } if (seed_tri == -1) { seed_tri = Spatial.FindNearestTriangle(seed_pt); } var loop = new MeshFacesFromLoop(Mesh, TrimLine, Spatial, seed_tri); MeshFaceSelection selection = loop.ToSelection(); selection.LocalOptimize(true, true); var editor = new MeshEditor(Mesh); editor.RemoveTriangles(selection, true); var components = new MeshConnectedComponents(Mesh); components.FindConnectedT(); if (components.Count > 1) { int keep = components.LargestByCount; for (int i = 0; i < components.Count; ++i) { if (i != keep) { editor.RemoveTriangles(components[i].Indices, true); } } } editor.RemoveAllBowtieVertices(true); var loops = new MeshBoundaryLoops(Mesh); bool loopsOK = false; try { loopsOK = loops.Compute(); } catch (Exception) { return(false); } if (!loopsOK) { return(false); } // [TODO] to support trimming mesh w/ existing holes, we need to figure out which // loop we created in RemoveTriangles above! if (loops.Count > 1) { return(false); } int[] loopVerts = loops[0].Vertices; var borderTris = new MeshFaceSelection(Mesh); borderTris.SelectVertexOneRings(loopVerts); borderTris.ExpandToOneRingNeighbours(RemeshBorderRings); var remesh = new RegionRemesher(Mesh, borderTris.ToArray()); remesh.Region.MapVerticesToSubmesh(loopVerts); double target_len = TargetEdgeLength; if (target_len <= 0) { double mine, maxe, avge; MeshQueries.EdgeLengthStatsFromEdges(Mesh, loops[0].Edges, out mine, out maxe, out avge); target_len = avge; } var meshTarget = new MeshProjectionTarget(Spatial.Mesh, Spatial); remesh.SetProjectionTarget(meshTarget); remesh.SetTargetEdgeLength(target_len); remesh.SmoothSpeedT = SmoothingAlpha; var curveTarget = new DCurveProjectionTarget(TrimLine); var multiTarget = new SequentialProjectionTarget(curveTarget, meshTarget); int set_id = 3; MeshConstraintUtil.ConstrainVtxLoopTo(remesh, loopVerts, multiTarget, set_id); for (int i = 0; i < RemeshRounds; ++i) { remesh.BasicRemeshPass(); } remesh.BackPropropagate(); // [TODO] output loop somehow...use MeshConstraints.FindConstrainedEdgesBySetID(set_id)... return(true); } // Trim()
public static bool RemoveTriangles(DMesh3 Mesh, IEnumerable <int> triangles, bool bRemoveIsolatedVerts = true) { MeshEditor editor = new MeshEditor(Mesh); return(editor.RemoveTriangles(triangles, bRemoveIsolatedVerts)); }
private void Remove(TriangleRemoval rem = TriangleRemoval.contained) { #if ACAD var lastColor = 0; #endif DMeshAABBTree3 spatial = new DMeshAABBTree3(CutMesh, true); spatial.WindingNumber(Vector3d.Zero); SafeListBuilder <int> containedT = new SafeListBuilder <int>(); SafeListBuilder <int> removeAnywayT = new SafeListBuilder <int>(); // if the windinging number for the centroid point candidate triangles // is one or more (or close for safety), then it's inside the volume of cutMesh // gParallel.ForEach(Target.TriangleIndices(), (tid) => { if (Target.GetTriArea(tid) < VertexSnapTol) { removeAnywayT.SafeAdd(tid); return; // parallel: equivalent to continue. } Vector3d v = Target.GetTriCentroid(tid); if (AttemptPlanarRemoval) { // slightly offset the point to be evaluated. // var nrm = Target.GetTriNormal(tid); v -= nrm * 5 * VertexSnapTol; } var winding = spatial.WindingNumber(v); bool IsInternal = winding > 0.9; #if ACAD // temporarily here for debug purposes var wantColor = IsInternal ? 1 : 2; if (lastColor != wantColor) { Debug.WriteLine($"-LAYER set L{wantColor}"); Debug.WriteLine($""); lastColor = wantColor; } Triangle3d tri = new Triangle3d(); Target.GetTriVertices(tid, ref tri.V0, ref tri.V1, ref tri.V2); Debug.WriteLine($"3DPOLY {tri.V0.CommaDelimited} {tri.V1.CommaDelimited} {tri.V2.CommaDelimited} {tri.V0.CommaDelimited} {v.CommaDelimited} "); #endif if (IsInternal) { containedT.SafeAdd(tid); } }); if (rem == TriangleRemoval.contained) { MeshEditor.RemoveTriangles(Target, containedT.Result); } else if (rem == TriangleRemoval.external) { var ext = Target.TriangleIndices().Except(containedT.Result); MeshEditor.RemoveTriangles(Target, ext); } MeshEditor.RemoveTriangles(Target, removeAnywayT.Result); // [RMS] construct set of on-cut vertices? This is not // necessarily all boundary vertices... CutVertices = new List <int>(); foreach (int vid in SegmentInsertVertices) { if (Target.IsVertex(vid)) { CutVertices.Add(vid); } } }