void find_cut_paths(HashSet <int> CutEdges) { Spans = new List <EdgeSpan>(); Loops = new List <EdgeLoop>(); // [TODO] what about if vert appears more than twice in list? we should check for that! var Remaining = new HashSet <int>(CutEdges); while (Remaining.Count > 0) { int start_edge = Remaining.First(); Remaining.Remove(start_edge); Index2i start_edge_v = Mesh.GetEdgeV(start_edge); bool isLoop; List <int> forwardSpan = walk_edge_span_forward(Mesh, start_edge, start_edge_v.a, Remaining, out isLoop); if (isLoop == false) { List <int> backwardSpan = walk_edge_span_forward(Mesh, start_edge, start_edge_v.b, Remaining, out isLoop); if (isLoop) { throw new Exception("find_cut_paths: how did this possibly happen?!?"); } if (backwardSpan.Count > 1) { backwardSpan.Reverse(); backwardSpan.RemoveAt(backwardSpan.Count - 1); backwardSpan.AddRange(forwardSpan); Index2i start_ev = Mesh.GetEdgeV(backwardSpan[0]); Index2i end_ev = Mesh.GetEdgeV(backwardSpan[backwardSpan.Count - 1]); // [RMS] >2 check here catches two-edge span case, where we do have shared vert but // can never be loop unless we have duplicate edge (!) isLoop = backwardSpan.Count > 2 && IndexUtil.find_shared_edge_v(ref start_ev, ref end_ev) != DMesh3.InvalidID; forwardSpan = backwardSpan; } } if (isLoop) { var loop = EdgeLoop.FromEdges(Mesh, forwardSpan); Util.gDevAssert(loop.CheckValidity()); Loops.Add(loop); } else { var span = EdgeSpan.FromEdges(Mesh, forwardSpan); Util.gDevAssert(span.CheckValidity()); Spans.Add(span); } } }
// Walk along edge loop and collapse to inserted curve vertices. EdgeLoop simplify(EdgeLoop loop) { HashSet <int> curve_verts = new HashSet <int>(CurveVertices); List <int> remaining_edges = new List <int>(); for (int li = 0; li < loop.EdgeCount; ++li) { int eid = loop.Edges[li]; Index2i ev = Mesh.GetEdgeV(eid); // cannot collapse edge between two "original" polygon verts (ie created by face pokes) if (curve_verts.Contains(ev.a) && curve_verts.Contains(ev.b)) { remaining_edges.Add(eid); continue; } // if we have an original vert, we need to keep it (and its position!) int keep = ev.a, discard = ev.b; Vector3d set_to = Vector3d.Zero; if (curve_verts.Contains(ev.b)) { keep = ev.b; discard = ev.a; set_to = Mesh.GetVertex(ev.b); } else if (curve_verts.Contains(ev.a)) { set_to = Mesh.GetVertex(ev.a); } else { set_to = 0.5 * (Mesh.GetVertex(ev.a) + Mesh.GetVertex(ev.b)); } // make sure we are not going to flip any normals // [OPTIMIZATION] May be possible to do this more efficiently because we know we are in // 2D and each tri should have same cw/ccw orientation. But we don't quite "know" we // are in 2D here, as CollapseEdge function is operating on the mesh coordinates... if (MeshUtil.CheckIfCollapseCreatesFlip(Mesh, eid, set_to)) { remaining_edges.Add(eid); continue; } // cannot collapse if the 'other' edges we would discard are OnCutEdges. This would // result in loop potentially being broken. bad! Index4i einfo = Mesh.GetEdge(eid); int c = IndexUtil.find_tri_other_vtx(keep, discard, Mesh.GetTriangle(einfo.c)); int d = IndexUtil.find_tri_other_vtx(keep, discard, Mesh.GetTriangle(einfo.d)); int ec = Mesh.FindEdge(discard, c); int ed = Mesh.FindEdge(discard, d); if (OnCutEdges.Contains(ec) || OnCutEdges.Contains(ed)) { remaining_edges.Add(eid); continue; } // do collapse and update internal data structures DMesh3.EdgeCollapseInfo collapse; MeshResult result = Mesh.CollapseEdge(keep, discard, out collapse); if (result == MeshResult.Ok) { Mesh.SetVertex(collapse.vKept, set_to); OnCutEdges.Remove(collapse.eCollapsed); } else { remaining_edges.Add(eid); } } return(EdgeLoop.FromEdges(Mesh, remaining_edges)); }