public virtual void FastCollapsePass(double fMinEdgeLength) { if (mesh.TriangleCount == 0) // badness if we don't catch this... { return; } MinEdgeLength = fMinEdgeLength; double min_sqr = MinEdgeLength * MinEdgeLength; // we don't collapse on the boundary HaveBoundary = false; begin_pass(); begin_setup(); Precompute(); end_setup(); begin_ops(); begin_collapse(); int N = mesh.MaxEdgeID; Vector3d va = Vector3d.Zero, vb = Vector3d.Zero; for (int eid = 0; eid < N; ++eid) { if (!mesh.IsEdge(eid)) { continue; } if (mesh.IsBoundaryEdge(eid)) { continue; } mesh.GetEdgeV(eid, ref va, ref vb); if (va.DistanceSquared(ref vb) > min_sqr) { continue; } COUNT_ITERATIONS++; Vector3d midpoint = (va + vb) * 0.5; int vKept; ProcessResult result = CollapseEdge(eid, midpoint, out vKept); if (result == ProcessResult.Ok_Collapsed) { // do nothing? } } end_collapse(); end_ops(); Reproject(); end_pass(); }
/// <summary> /// construct EdgeSpan from a list of edges of mesh /// </summary> public static EdgeSpan FromEdges(DMesh3 mesh, IList <int> edges) { int[] Edges = new int[edges.Count]; for (int i = 0; i < Edges.Length; ++i) { Edges[i] = edges[i]; } int[] Vertices = new int[Edges.Length + 1]; Index2i start_ev = mesh.GetEdgeV(Edges[0]); Index2i prev_ev = start_ev; if (Edges.Length > 1) { for (int i = 1; i < Edges.Length; ++i) { Index2i next_ev = mesh.GetEdgeV(Edges[i]); Vertices[i] = IndexUtil.find_shared_edge_v(ref prev_ev, ref next_ev); prev_ev = next_ev; } Vertices[0] = IndexUtil.find_edge_other_v(ref start_ev, Vertices[1]); Vertices[Vertices.Length - 1] = IndexUtil.find_edge_other_v(prev_ev, Vertices[Vertices.Length - 2]); } else { Vertices[0] = start_ev[0]; Vertices[1] = start_ev[1]; } return(new EdgeSpan(mesh, Vertices, Edges, false)); }
public int MapEdgeToSubmesh(int base_eid) { Index2i base_ev = BaseMesh.GetEdgeV(base_eid); Index2i sub_ev = MapVerticesToSubmesh(base_ev); return(SubMesh.FindEdge(sub_ev.a, sub_ev.b)); }
protected virtual void InitializeQueue() { int NE = mesh.EdgeCount; Nodes = new QEdge[2 * NE]; // [RMS] do we need this many? NodePool = new MemoryPool <QEdge>(NE); EdgeQueue = new g3ext.FastPriorityQueue <QEdge>(NE); int cur_eid = start_edges(); bool done = false; do { if (mesh.IsEdge(cur_eid)) { Index2i ev = mesh.GetEdgeV(cur_eid); QuadricError Q = new QuadricError(ref vertQuadrics[ev.a], ref vertQuadrics[ev.b]); Vector3d opt = OptimalPoint(Q, ev.a, ev.b); double err = Q.Evaluate(opt); QEdge ee = NodePool.Allocate(); ee.Initialize(cur_eid, Q, opt); Nodes[cur_eid] = ee; EdgeQueue.Enqueue(ee, (float)err); } cur_eid = next_edge(cur_eid, out done); } while (done == false); }
public void SelectEdgeVertices(int[] edges) { for (int i = 0; i < edges.Length; ++i) { Index2i ev = Mesh.GetEdgeV(edges[i]); add(ev.a); add(ev.b); } }
public virtual ValidationStatus Validate(double fDegenerateTol = MathUtil.ZeroTolerancef) { double dist_sqr_thresh = fDegenerateTol * fDegenerateTol; int nStop = IsLoop ? Curve.VertexCount - 1 : Curve.VertexCount; for (int k = 0; k < nStop; ++k) { Vector2d v0 = Curve[k]; Vector2d v1 = Curve[(k + 1) % Curve.VertexCount]; if (v0.DistanceSquared(v1) < dist_sqr_thresh) { return(ValidationStatus.NearDenegerateInputGeometry); } } foreach (int eid in Mesh.EdgeIndices()) { Index2i ev = Mesh.GetEdgeV(eid); if (PointF(ev.a).DistanceSquared(PointF(ev.b)) < dist_sqr_thresh) { return(ValidationStatus.NearDegenerateMeshEdges); } } return(ValidationStatus.Ok); }
protected virtual void InitializeQueue() { int NE = mesh.EdgeCount; int MaxEID = mesh.MaxEdgeID; EdgeQuadrics = new QEdge[MaxEID]; EdgeQueue = new IndexPriorityQueue(MaxEID); float[] edgeErrors = new float[MaxEID]; // vertex quadrics can be computed in parallel gParallel.ForEach(mesh.EdgeIndices(), (eid) => { Index2i ev = mesh.GetEdgeV(eid); QuadricError Q = new QuadricError(ref vertQuadrics[ev.a], ref vertQuadrics[ev.b]); Vector3d opt = OptimalPoint(eid, ref Q, ev.a, ev.b); edgeErrors[eid] = (float)Q.Evaluate(opt); EdgeQuadrics[eid] = new QEdge(eid, Q, opt); }); // sorted pq insert is faster, so sort edge errors array and index map int[] indices = new int[MaxEID]; for (int i = 0; i < MaxEID; ++i) { indices[i] = i; } Array.Sort(edgeErrors, indices); // now do inserts for (int i = 0; i < edgeErrors.Length; ++i) { int eid = indices[i]; if (mesh.IsEdge(eid)) { QEdge edge = EdgeQuadrics[eid]; EdgeQueue.Enqueue(edge.eid, edgeErrors[i]); } } /* * // previous code that does unsorted insert. This is marginally slower, but * // might get even slower on larger meshes? have only tried up to about 350k. * // (still, this function is not the bottleneck...) * int cur_eid = start_edges(); * bool done = false; * do { * if (mesh.IsEdge(cur_eid)) { * QEdge edge = EdgeQuadrics[cur_eid]; * double err = errList[cur_eid]; * EdgeQueue.Enqueue(cur_eid, (float)err); * } * cur_eid = next_edge(cur_eid, out done); * } while (done == false); */ }
public int MapEdgeToBaseMesh(int sub_eid) { Index2i sub_ev = SubMesh.GetEdgeV(sub_eid); Index2i base_ev = MapVerticesToBaseMesh(sub_ev); return(BaseMesh.FindEdge(base_ev.a, base_ev.b)); }
protected bool is_on_edge(int eid, Vector3d v) { Index2i ev = Target.GetEdgeV(eid); Segment3d seg = new Segment3d(Target.GetVertex(ev.a), Target.GetVertex(ev.b)); return(seg.DistanceSquared(v) < VertexSnapTol * VertexSnapTol); }
/// <summary> /// Split the mesh edges at the iso-crossings, unless edge is /// shorter than min_len, or inserted point would be within min_len or vertex /// [TODO] do we want to return any info here?? /// </summary> public void SplitAtIsoCrossings(double min_len = 0) { foreach (var pair in EdgeLocations) { int eid = pair.Key; Vector3d pos = pair.Value; if (!Mesh.IsEdge(eid)) { continue; } Index2i ev = Mesh.GetEdgeV(eid); Vector3d a = Mesh.GetVertex(ev.a); Vector3d b = Mesh.GetVertex(ev.b); if (a.Distance(b) < min_len) { continue; } Vector3d mid = (a + b) * 0.5; if (a.Distance(mid) < min_len || b.Distance(mid) < min_len) { continue; } DMesh3.EdgeSplitInfo splitInfo; if (Mesh.SplitEdge(eid, out splitInfo) == MeshResult.Ok) { Mesh.SetVertex(splitInfo.vNew, pos); } } }
public static void EdgeLengthStatsFromEdges(DMesh3 mesh, IEnumerable <int> EdgeItr, out double minEdgeLen, out double maxEdgeLen, out double avgEdgeLen, int samples = 0) { minEdgeLen = double.MaxValue; maxEdgeLen = double.MinValue; avgEdgeLen = 0; int avg_count = 0; int MaxID = mesh.MaxEdgeID; Vector3d a = Vector3d.Zero, b = Vector3d.Zero; foreach (int eid in EdgeItr) { if (mesh.IsEdge(eid)) { mesh.GetEdgeV(eid, ref a, ref b); double len = a.Distance(b); if (len < minEdgeLen) { minEdgeLen = len; } if (len > maxEdgeLen) { maxEdgeLen = len; } avgEdgeLen += len; avg_count++; } } ; avgEdgeLen /= (double)avg_count; }
public static void EdgesToVertices(DMesh3 mesh, HashSet <int> edges, HashSet <int> vertices) { foreach (int eid in edges) { Index2i ev = mesh.GetEdgeV(eid); vertices.Add(ev.a); vertices.Add(ev.b); } }
// convert edge selection to vertex selection. public MeshVertexSelection(DMesh3 mesh, MeshEdgeSelection convertE) : this(mesh) { foreach (int eid in convertE) { Index2i ev = mesh.GetEdgeV(eid); add(ev.a); add(ev.b); } }
// return same indices as GetEdgeV, but oriented based on attached triangle Index2i get_oriented_edgev(int eID, int tid_in, int tid_out) { Index2i edgev = Mesh.GetEdgeV(eID); int a = edgev.a, b = edgev.b; Index3i tri = Mesh.GetTriangle(tid_in); int ai = IndexUtil.find_edge_index_in_tri(a, b, ref tri); return(new Index2i(tri[ai], tri[(ai + 1) % 3])); }
/// <summary> /// Exhaustively check that verts and edges of this EdgeSpan are consistent. Not for production use. /// </summary> public bool CheckValidity(FailMode eFailMode = FailMode.Throw) { bool is_ok = true; Action <bool> CheckOrFailF = (b) => { is_ok = is_ok && b; }; if (eFailMode == FailMode.DebugAssert) { CheckOrFailF = (b) => { Debug.Assert(b); is_ok = is_ok && b; }; } else if (eFailMode == FailMode.gDevAssert) { CheckOrFailF = (b) => { Util.gDevAssert(b); is_ok = is_ok && b; }; } else if (eFailMode == FailMode.Throw) { CheckOrFailF = (b) => { if (b == false) { throw new Exception("EdgeSpan.CheckValidity: check failed"); } }; } CheckOrFailF(Vertices.Length == Edges.Length + 1); for (int ei = 0; ei < Edges.Length; ++ei) { Index2i ev = Mesh.GetEdgeV(Edges[ei]); CheckOrFailF(Mesh.IsVertex(ev.a)); CheckOrFailF(Mesh.IsVertex(ev.b)); CheckOrFailF(Mesh.FindEdge(ev.a, ev.b) != DMesh3.InvalidID); CheckOrFailF(Vertices[ei] == ev.a || Vertices[ei] == ev.b); CheckOrFailF(Vertices[ei + 1] == ev.a || Vertices[ei + 1] == ev.b); } for (int vi = 0; vi < Vertices.Length - 1; ++vi) { int a = Vertices[vi], b = Vertices[vi + 1]; CheckOrFailF(Mesh.IsVertex(a)); CheckOrFailF(Mesh.IsVertex(b)); CheckOrFailF(Mesh.FindEdge(a, b) != DMesh3.InvalidID); if (vi < Vertices.Length - 2) { int n = 0, edge_before_b = Edges[vi], edge_after_b = Edges[vi + 1]; foreach (int nbr_e in Mesh.VtxEdgesItr(b)) { if (nbr_e == edge_before_b || nbr_e == edge_after_b) { n++; } } CheckOrFailF(n == 2); } } return(true); }
/// <summary> /// construct EdgeLoop from a list of edges of mesh /// </summary> public static EdgeLoop FromEdges(DMesh3 mesh, IList <int> edges) { int[] Edges = new int[edges.Count]; for (int i = 0; i < Edges.Length; ++i) { Edges[i] = edges[i]; } int[] Vertices = new int[Edges.Length]; Index2i start_ev = mesh.GetEdgeV(Edges[0]); Index2i prev_ev = start_ev; for (int i = 1; i < Edges.Length; ++i) { Index2i next_ev = mesh.GetEdgeV(Edges[i % Edges.Length]); Vertices[i] = IndexUtil.find_shared_edge_v(ref prev_ev, ref next_ev); prev_ev = next_ev; } Vertices[0] = IndexUtil.find_edge_other_v(ref start_ev, Vertices[1]); return(new EdgeLoop(mesh, Vertices, Edges, false)); }
// for all edges, disable flip/split/collapse // for all vertices, pin in current position public static void FixEdges(MeshConstraints cons, DMesh3 mesh, IEnumerable <int> edges) { foreach (int ei in edges) { if (mesh.IsEdge(ei)) { cons.SetOrUpdateEdgeConstraint(ei, EdgeConstraint.FullyConstrained); Index2i ev = mesh.GetEdgeV(ei); cons.SetOrUpdateVertexConstraint(ev.a, VertexConstraint.Pinned); cons.SetOrUpdateVertexConstraint(ev.b, VertexConstraint.Pinned); } } }
/// <summary> /// boundary vertices of mesh, but based on edges, so returns each vertex twice! /// </summary> public static IEnumerable <int> BoundaryEdgeVertices(DMesh3 mesh) { int N = mesh.MaxEdgeID; for (int i = 0; i < N; ++i) { if (mesh.IsEdge(i) && mesh.IsBoundaryEdge(i)) { Index2i ev = mesh.GetEdgeV(i); yield return(ev.a); yield return(ev.b); } } }
// for all mesh boundary edges, disable flip/split/collapse // for all mesh boundary vertices, pin in current position public static void FixAllBoundaryEdges(MeshConstraints cons, DMesh3 mesh) { int NE = mesh.MaxEdgeID; for (int ei = 0; ei < NE; ++ei) { if (mesh.IsEdge(ei) && mesh.IsBoundaryEdge(ei)) { cons.SetOrUpdateEdgeConstraint(ei, EdgeConstraint.FullyConstrained); Index2i ev = mesh.GetEdgeV(ei); cons.SetOrUpdateVertexConstraint(ev.a, VertexConstraint.Pinned); cons.SetOrUpdateVertexConstraint(ev.b, VertexConstraint.Pinned); } } }
// convert vertex selection to edge selection. Require at least minCount verts of edge to be selected public MeshEdgeSelection(DMesh3 mesh, MeshVertexSelection convertV, int minCount = 2) : this(mesh) { minCount = MathUtil.Clamp(minCount, 1, 2); // [TODO] if minCount == 1, and convertV is small, it is faster to iterate over convertV!! foreach (int eid in mesh.EdgeIndices()) { Index2i ev = mesh.GetEdgeV(eid); int n = (convertV.IsSelected(ev.a) ? 1 : 0) + (convertV.IsSelected(ev.b) ? 1 : 0); if (n >= minCount) { add(eid); } } }
/// <summary> /// given list of edges of MeshA, and vertex map from A to B, map to list of edges on B /// </summary> public static List <int> MapEdgesViaVertexMap(IIndexMap AtoBV, DMesh3 MeshA, DMesh3 MeshB, List <int> edges) { int N = edges.Count; List <int> result = new List <int>(N); for (int i = 0; i < N; ++i) { int eid_a = edges[i]; Index2i aev = MeshA.GetEdgeV(eid_a); int bev0 = AtoBV[aev.a]; int bev1 = AtoBV[aev.b]; int eid_b = MeshB.FindEdge(bev0, bev1); Debug.Assert(eid_b != DMesh3.InvalidID); result.Add(eid_b); } return(result); }
public void ComputeBoundaryInfo(IEnumerable <int> triangles, int tri_count) { // set of base-mesh triangles that are in submesh IndexFlagSet sub_tris = new IndexFlagSet(BaseMesh.MaxTriangleID, tri_count); foreach (int ti in triangles) { sub_tris[ti] = true; } BaseBorderV = new IndexHashSet(); BaseBorderE = new IndexHashSet(); BaseBoundaryE = new IndexHashSet(); // Iterate through edges in submesh roi on base mesh. If // one of the tris of the edge is not in submesh roi, then this // is a boundary edge. // // (edge iteration via triangle iteration processes each internal edge twice...) foreach (int ti in triangles) { Index3i tedges = BaseMesh.GetTriEdges(ti); for (int j = 0; j < 3; ++j) { int eid = tedges[j]; Index2i tris = BaseMesh.GetEdgeT(eid); if (tris.b == DMesh3.InvalidID || sub_tris[tris.a] != sub_tris[tris.b]) { if (tris.b == DMesh3.InvalidID) { BaseBoundaryE[eid] = true; } else { BaseBorderE[eid] = true; } Index2i ve = BaseMesh.GetEdgeV(eid); BaseBorderV[ve.a] = true; BaseBorderV[ve.b] = true; } } } }
// for all mesh boundary vertices, pin in current position, but allow splits public static void FixAllBoundaryEdges_AllowSplit(MeshConstraints cons, DMesh3 mesh, int setID) { EdgeConstraint edgeCons = new EdgeConstraint(EdgeRefineFlags.NoFlip | EdgeRefineFlags.NoCollapse); VertexConstraint vertCons = new VertexConstraint(true, setID); int NE = mesh.MaxEdgeID; for (int ei = 0; ei < NE; ++ei) { if (mesh.IsEdge(ei) && mesh.IsBoundaryEdge(ei)) { cons.SetOrUpdateEdgeConstraint(ei, edgeCons); Index2i ev = mesh.GetEdgeV(ei); cons.SetOrUpdateVertexConstraint(ev.a, vertCons); cons.SetOrUpdateVertexConstraint(ev.b, vertCons); } } }
public static void EdgeLengthStats(DMesh3 mesh, out double minEdgeLen, out double maxEdgeLen, out double avgEdgeLen, int samples = 0) { minEdgeLen = double.MaxValue; maxEdgeLen = double.MinValue; avgEdgeLen = 0; int avg_count = 0; int MaxID = mesh.MaxEdgeID; // if we are only taking some samples, use a prime-modulo-loop instead of random int nPrime = (samples == 0) ? 1 : nPrime = 31337; int max_count = (samples == 0) ? MaxID : samples; Vector3d a = Vector3d.Zero, b = Vector3d.Zero; int eid = 0; int count = 0; do { if (mesh.IsEdge(eid)) { mesh.GetEdgeV(eid, ref a, ref b); double len = a.Distance(b); if (len < minEdgeLen) { minEdgeLen = len; } if (len > maxEdgeLen) { maxEdgeLen = len; } avgEdgeLen += len; avg_count++; } eid = (eid + nPrime) % MaxID; } while (eid != 0 && count++ < max_count); avgEdgeLen /= (double)avg_count; }
int find_nearest_edge(DMesh3 mesh, Vector3d v, HashSet <int> vertices) { int near_eid = DMesh3.InvalidID; double nearSqr = VertexSnapTol * VertexSnapTol; foreach (int eid in mesh.BoundaryEdgeIndices()) { Index2i ev = mesh.GetEdgeV(eid); if (vertices.Contains(ev.a) == false || vertices.Contains(ev.b) == false) { continue; } Segment3d seg = new Segment3d(mesh.GetVertex(ev.a), mesh.GetVertex(ev.b)); double dSqr = seg.DistanceSquared(v); if (dSqr < nearSqr) { near_eid = eid; nearSqr = dSqr; } } return(near_eid); }
/// <summary> /// given EdgeLoop on MeshA, and vertex map from A to B, map to EdgeLoop on B /// </summary> public static EdgeLoop MapLoopViaVertexMap(IIndexMap AtoBV, DMesh3 MeshA, DMesh3 MeshB, EdgeLoop loopIn) { int NV = loopIn.VertexCount, NE = loopIn.EdgeCount; int[] newVerts = new int[NV]; for (int i = 0; i < NV; ++i) { newVerts[i] = AtoBV[loopIn.Vertices[i]]; } int[] newEdges = new int[NE]; for (int i = 0; i < NE; ++i) { int eid_a = loopIn.Edges[i]; Index2i aev = MeshA.GetEdgeV(eid_a); int bev0 = AtoBV[aev.a]; int bev1 = AtoBV[aev.b]; newEdges[i] = MeshB.FindEdge(bev0, bev1); Debug.Assert(newEdges[i] != DMesh3.InvalidID); } return(new EdgeLoop(MeshB, newVerts, newEdges, false)); }
protected bool check_for_cracks(DMesh3 mesh, out int boundary_edge_count, double crack_tol = MathUtil.ZeroTolerancef) { boundary_edge_count = 0; var boundary_verts = new MeshVertexSelection(mesh); foreach (int eid in mesh.BoundaryEdgeIndices()) { Index2i ev = mesh.GetEdgeV(eid); boundary_verts.Select(ev.a); boundary_verts.Select(ev.b); boundary_edge_count++; } if (boundary_verts.Count == 0) { return(false); } AxisAlignedBox3d bounds = mesh.CachedBounds; var borderV = new PointHashGrid3d <int>(bounds.MaxDim / 128, -1); foreach (int vid in boundary_verts) { Vector3d v = mesh.GetVertex(vid); var result = borderV.FindNearestInRadius(v, crack_tol, (existing_vid) => { return(v.Distance(mesh.GetVertex(existing_vid))); }); if (result.Key != -1) { return(true); // we found a crack vertex! } borderV.InsertPoint(vid, v); } // found no cracks return(false); }
static List <int> walk_edge_span_forward(DMesh3 mesh, int start_edge, int start_pivot_v, HashSet <int> EdgeSet, out bool bClosedLoop) { bClosedLoop = false; List <int> edgeSpan = new List <int>(); edgeSpan.Add(start_edge); // we update this as we step //int cur_edge = start_edge; int cur_pivot_v = start_pivot_v; int stop_pivot_v = IndexUtil.find_edge_other_v(mesh.GetEdgeV(start_edge), start_pivot_v); Util.gDevAssert(stop_pivot_v != DMesh3.InvalidID); bool done = false; while (!done) { // find outgoing edge in set and connected to current pivot vtx int next_edge = -1; foreach (int nbr_edge in mesh.VtxEdgesItr(cur_pivot_v)) { if (EdgeSet.Contains(nbr_edge)) { next_edge = nbr_edge; break; } } // could not find - must be done span if (next_edge == -1) { done = true; break; } // figure out next pivot vtx (is 'other' from current pivot on next edge) Index2i next_edge_v = mesh.GetEdgeV(next_edge); if (next_edge_v.a == cur_pivot_v) { cur_pivot_v = next_edge_v.b; } else if (next_edge_v.b == cur_pivot_v) { cur_pivot_v = next_edge_v.a; } else { throw new Exception("walk_edge_span_forward: found valid next edge but not connected to previous vertex??"); } edgeSpan.Add(next_edge); EdgeSet.Remove(next_edge); // if this happens, we closed a loop if (cur_pivot_v == stop_pivot_v) { done = true; bClosedLoop = true; } } return(edgeSpan); }
public virtual bool Cut() { double invalidDist = double.MinValue; MeshEdgeSelection CutEdgeSet = null; MeshVertexSelection CutVertexSet = null; if (CutFaceSet != null) { CutEdgeSet = new MeshEdgeSelection(Mesh, CutFaceSet); CutVertexSet = new MeshVertexSelection(Mesh, CutEdgeSet); } // compute signs int MaxVID = Mesh.MaxVertexID; double[] signs = new double[MaxVID]; gParallel.ForEach(Interval1i.Range(MaxVID), (vid) => { if (Mesh.IsVertex(vid)) { Vector3d v = Mesh.GetVertex(vid); signs[vid] = (v - PlaneOrigin).Dot(PlaneNormal); } else { signs[vid] = invalidDist; } }); HashSet <int> ZeroEdges = new HashSet <int>(); HashSet <int> ZeroVertices = new HashSet <int>(); HashSet <int> OnCutEdges = new HashSet <int>(); // have to skip processing of new edges. If edge id // is > max at start, is new. Otherwise if in NewEdges list, also new. int MaxEID = Mesh.MaxEdgeID; HashSet <int> NewEdges = new HashSet <int>(); IEnumerable <int> edgeItr = Interval1i.Range(MaxEID); if (CutEdgeSet != null) { edgeItr = CutEdgeSet; } // cut existing edges with plane, using edge split foreach (int eid in edgeItr) { if (Mesh.IsEdge(eid) == false) { continue; } if (eid >= MaxEID || NewEdges.Contains(eid)) { continue; } Index2i ev = Mesh.GetEdgeV(eid); double f0 = signs[ev.a]; double f1 = signs[ev.b]; // If both signs are 0, this edge is on-contour // If one sign is 0, that vertex is on-contour int n0 = (Math.Abs(f0) < MathUtil.Epsilon) ? 1 : 0; int n1 = (Math.Abs(f1) < MathUtil.Epsilon) ? 1 : 0; if (n0 + n1 > 0) { if (n0 + n1 == 2) { ZeroEdges.Add(eid); } else { ZeroVertices.Add((n0 == 1) ? ev[0] : ev[1]); } continue; } // no crossing if (f0 * f1 > 0) { continue; } DMesh3.EdgeSplitInfo splitInfo; MeshResult result = Mesh.SplitEdge(eid, out splitInfo); if (result != MeshResult.Ok) { throw new Exception("MeshPlaneCut.Cut: failed in SplitEdge"); //return false; } // SplitEdge just bisects edge - use plane intersection instead double t = f0 / (f0 - f1); Vector3d newPos = (1 - t) * Mesh.GetVertex(ev.a) + (t) * Mesh.GetVertex(ev.b); Mesh.SetVertex(splitInfo.vNew, newPos); NewEdges.Add(splitInfo.eNewBN); NewEdges.Add(splitInfo.eNewCN); OnCutEdges.Add(splitInfo.eNewCN); if (splitInfo.eNewDN != DMesh3.InvalidID) { NewEdges.Add(splitInfo.eNewDN); OnCutEdges.Add(splitInfo.eNewDN); } } // remove one-rings of all positive-side vertices. IEnumerable <int> vertexSet = Interval1i.Range(MaxVID); if (CutVertexSet != null) { vertexSet = CutVertexSet; } foreach (int vid in vertexSet) { if (signs[vid] > 0 && Mesh.IsVertex(vid)) { Mesh.RemoveVertex(vid, true, false); } } // ok now we extract boundary loops, but restricted // to either the zero-edges we found, or the edges we created! bang!! Func <int, bool> CutEdgeFilterF = (eid) => { if (OnCutEdges.Contains(eid) || ZeroEdges.Contains(eid)) { return(true); } return(false); }; try { MeshBoundaryLoops loops = new MeshBoundaryLoops(Mesh, false); loops.EdgeFilterF = CutEdgeFilterF; loops.Compute(); CutLoops = loops.Loops; CutSpans = loops.Spans; CutLoopsFailed = false; FoundOpenSpans = CutSpans.Count > 0; } catch { CutLoops = new List <EdgeLoop>(); CutLoopsFailed = true; } return(true); } // Cut()
/// <summary> /// Disconnect the given triangles from their neighbours, by duplicating "boundary" vertices, ie /// vertices on edges for which one triangle is in-set and the other is not. /// If bComputeEdgePairs is true, we return list of old/new edge pairs (useful for stitching) /// [TODO] currently boundary-edge behaviour is to *not* duplicate boundary verts /// </summary> public bool SeparateTriangles(IEnumerable <int> triangles, bool bComputeEdgePairs, out List <Index2i> EdgePairs) { HashSet <int> in_set = new HashSet <int>(triangles); Dictionary <int, int> VertexMap = new Dictionary <int, int>(); EdgePairs = null; HashSet <int> edges = null; List <Index2i> OldEdgeVerts = null; if (bComputeEdgePairs) { EdgePairs = new List <Index2i>(); edges = new HashSet <int>(); OldEdgeVerts = new List <Index2i>(); } // duplicate vertices on edges that are on boundary of triangles roi foreach (int tid in triangles) { Index3i te = Mesh.GetTriEdges(tid); for (int j = 0; j < 3; ++j) { Index2i et = Mesh.GetEdgeT(te[j]); // [TODO] what about behavior where we want to also duplicate boundary verts?? if (et.b == DMesh3.InvalidID || (et.a == tid && in_set.Contains(et.b)) || (et.b == tid && in_set.Contains(et.a))) { te[j] = -1; } } for (int j = 0; j < 3; ++j) { if (te[j] == -1) { continue; } Index2i ev = Mesh.GetEdgeV(te[j]); if (VertexMap.ContainsKey(ev.a) == false) { VertexMap[ev.a] = Mesh.AppendVertex(Mesh, ev.a); } if (VertexMap.ContainsKey(ev.b) == false) { VertexMap[ev.b] = Mesh.AppendVertex(Mesh, ev.b); } if (bComputeEdgePairs && edges.Contains(te[j]) == false) { edges.Add(te[j]); OldEdgeVerts.Add(ev); EdgePairs.Add(new Index2i(te[j], -1)); } } } // update triangles foreach (int tid in triangles) { Index3i tv = Mesh.GetTriangle(tid); Index3i tv_new = tv; for (int j = 0; j < 3; ++j) { int newv; if (VertexMap.TryGetValue(tv[j], out newv)) { tv_new[j] = newv; } } if (tv_new != tv) { Mesh.SetTriangle(tid, tv_new); } } if (bComputeEdgePairs) { for (int k = 0; k < EdgePairs.Count; ++k) { Index2i old_ev = OldEdgeVerts[k]; int new_a = VertexMap[old_ev.a]; int new_b = VertexMap[old_ev.b]; int new_eid = Mesh.FindEdge(new_a, new_b); Util.gDevAssert(new_eid != DMesh3.InvalidID); EdgePairs[k] = new Index2i(EdgePairs[k].a, new_eid); } } return(true); }