public AppendInfo AppendConnectorTo(DMesh3 mesh, Vector3d translate) { validate_geometry(); AppendInfo info = new AppendInfo(); MeshEditor editor = new MeshEditor(mesh); int[] mapV; if (HasInner) { info.InnerGID = mesh.AllocateTriangleGroup(); editor.AppendMesh(InnerMesh, out mapV, info.InnerGID); info.InnerLoop = EdgeLoop.FromVertices(mesh, new MappedList(InnerLoop.Vertices, mapV)); MeshTransforms.PerVertexTransform(mesh, InnerMesh.VertexIndices(), (vid) => { return(mapV[vid]); }, (v, old_vid, new_vid) => { return(v + translate); }); } else { info.InnerGID = -1; info.InnerLoop = null; } info.OuterGID = mesh.AllocateTriangleGroup(); editor.AppendMesh(OuterMesh, out mapV, info.OuterGID); info.OuterLoop = EdgeLoop.FromVertices(mesh, new MappedList(OuterLoop.Vertices, mapV)); MeshTransforms.PerVertexTransform(mesh, OuterMesh.VertexIndices(), (vid) => { return(mapV[vid]); }, (v, old_vid, new_vid) => { return(v + translate); }); return(info); }
public override DMesh3 Cut(CuttingInfo info) { var painted = FindPaintedTriangles(info.mesh, info.data.ColorNum); if (painted.Count <= 0) { return(info.mesh); } var components = FindConnectedComponents(info, painted); var subMeshes = new List <DMesh3>(); foreach (var component in components.Components) { DSubmesh3 subMesh = new DSubmesh3(info.mesh, component.Indices); var newMesh = subMesh.SubMesh; newMesh.EnableTriangleGroups(); newMesh.EnableVertexColors(ColorManager.Instance.GetColorForId(info.data.ColorNum).toVector3f()); foreach (var componentIndex in component.Indices) { info.mesh.RemoveTriangle(componentIndex); } var loops = new MeshBoundaryLoops(newMesh, true); var meshEditorNewMesh = new MeshEditor(newMesh); var meshEditorOldMesh = new MeshEditor(info.mesh); foreach (var meshBoundaryLoop in loops) { var offsettedVerticesNewMesh = new List <int>(); var offsettedVerticesOldMesh = new List <int>(); foreach (var vertex in meshBoundaryLoop.Vertices) { var normal = newMesh.GetVertexNormal(vertex); var vertextPosition = newMesh.GetVertex(vertex); var newVertex = newMesh.AppendVertex(vertextPosition - normal.toVector3d() * info.data.depth); offsettedVerticesNewMesh.Add(newVertex); var newVertexOldMesh = info.mesh.AppendVertex(vertextPosition - normal.toVector3d() * info.data.depth); offsettedVerticesOldMesh.Add(newVertexOldMesh); } var boundaryLoopOfOldMesh = meshBoundaryLoop.Vertices .Select(subv => subMesh.MapVertexToBaseMesh(subv)).ToArray(); var loopNewMesh = meshEditorNewMesh.StitchLoop(meshBoundaryLoop.Vertices, offsettedVerticesNewMesh.ToArray(), info.data.ColorNum); var loopOldMesh = meshEditorOldMesh.StitchLoop(boundaryLoopOfOldMesh, offsettedVerticesOldMesh.ToArray(), info.data.mainColorId); for (var index = 0; index < offsettedVerticesNewMesh.Count; index++) { info.PointToPoint.Add(offsettedVerticesNewMesh[index], offsettedVerticesOldMesh[index]); } var offsettedLoop = EdgeLoop.FromVertices(newMesh, offsettedVerticesNewMesh); var holeFiller = new SimpleHoleFiller(newMesh, offsettedLoop); var valid = holeFiller.Validate(); if (valid == ValidationStatus.Ok) { var res = holeFiller.Fill(info.data.ColorNum); if (res) { var newVertex = holeFiller.NewVertex; var newTriangles = holeFiller.NewTriangles; //Add the same triangles to old mesh. if (newVertex == -1) //case where it added only one tri { var vertices = newMesh.GetTriangle(newTriangles.First()); var edgeAOldMesh = info.PointToPoint[vertices.a]; var edgeBOldMesh = info.PointToPoint[vertices.b]; var edgeCOldMesh = info.PointToPoint[vertices.c]; info.mesh.AppendTriangle(edgeAOldMesh, edgeCOldMesh, edgeBOldMesh, info.data.mainColorId); } else //case where multiple tris and a middle vertex were added { var newVertexOldMesh = info.mesh.AppendVertex(newMesh.GetVertex(newVertex)); foreach (var newTriangle in newTriangles) { //the center is always the first vertex in newTriangle var edgeVertices = newMesh.GetTriangle(newTriangle); var edgeBOldMesh = info.PointToPoint[edgeVertices.b]; var edgeCOldMesh = info.PointToPoint[edgeVertices.c]; info.mesh.AppendTriangle(newVertexOldMesh, edgeCOldMesh, edgeBOldMesh, info.data.mainColorId); } if (info.PointToPoint.ContainsKey(newVertex)) { Debug.Log($"Double insertion from HF: {newVertex}, {newVertexOldMesh}"); } else { info.PointToPoint.Add(newVertex, newVertexOldMesh); } } } } } subMeshes.Add(newMesh); } InstantiateNewObjects(info, subMeshes); return(info.mesh); }
/// <summary> /// This function tries to remove vertices from loop to hit TargetVtxCount. We call this /// when polygon-insertion returns more vertices than polygon. Strategy is to try to find /// co-linear vertices, ie that can be removed without changing shape. If that fails, /// we remove vertices that result in smallest length change (probably should do proper simplification /// here instead). /// /// Basically this is to handle failures in MeshInsertUVPolyCurve.Simplify(), which sometimes /// fails to remove extra vertices because it would case triangle flips. Here we don't /// care about triangle flips. /// /// Note that if the input polygon had splits on edges, this function would remove those /// vertices. Which is not ideal. /// </summary> protected EdgeLoop simplify_loop(DMesh3 mesh, EdgeLoop loop, int TargetVtxCount) { while (loop.VertexCount > TargetVtxCount) { DCurve3 curve = loop.ToCurve(); DMesh3.EdgeCollapseInfo cinfo; int NV = loop.VertexCount; for (int k = 1; k <= NV; ++k) { int prevv = k - 1; int curv = k % NV; int nextv = (k + 1) % NV; //if (curve[prevv].Distance(curve[curv]) < 0.0001 || // curve[nextv].Distance(curve[curv]) < 0.0001) // f3.DebugUtil.Log("DEGENERATE!!"); double angle = curve.OpeningAngleDeg(curv); if (angle > 179) { MeshResult r = mesh.CollapseEdge(loop.Vertices[prevv], loop.Vertices[curv], out cinfo); mesh.SetVertex(loop.Vertices[prevv], curve[prevv]); if (r == MeshResult.Ok) { goto done_this_iter; } else { f3.DebugUtil.Log("collinear collapse failed!"); } } } f3.DebugUtil.Log("Did not find collinear vert..."); int i_shortest = -1; double shortest_len = double.MaxValue; for (int k = 1; k <= NV; ++k) { int prevv = k - 1; int curv = k % NV; int nextv = (k + 1) % NV; Vector3d pc = curve[curv] - curve[prevv]; Vector3d pn = curve[nextv] - curve[curv]; double len_sum = pc.Length + pn.Length; if (len_sum < shortest_len) { i_shortest = curv; shortest_len = len_sum; } } if (i_shortest != -1) { int curv = i_shortest; int prevv = (curv == 0) ? NV - 1 : curv - 1; int nextv = (curv + 1) % NV; Vector3d pc = curve[curv] - curve[prevv]; Vector3d pn = curve[nextv] - curve[curv]; int iWhich = (pc.Length < pn.Length) ? prevv : nextv; MeshResult r = mesh.CollapseEdge(loop.Vertices[iWhich], loop.Vertices[curv], out cinfo); if (r == MeshResult.Ok) { goto done_this_iter; } else { f3.DebugUtil.Log("shortest failed!"); } } f3.DebugUtil.Log("Did not find shortest vert..."); // if we didn't find a vert to remove yet, just arbitrarily remove first one int v0 = loop.Vertices[0], v1 = loop.Vertices[1]; MeshResult result = mesh.CollapseEdge(v1, v0, out cinfo); done_this_iter: List <int> new_verts = new List <int>(); for (int k = 0; k < loop.Vertices.Count(); ++k) { if (mesh.IsVertex(loop.Vertices[k])) { new_verts.Add(loop.Vertices[k]); } } loop = EdgeLoop.FromVertices(mesh, new_verts); } return(loop); }
public static void quick_test_2() { DMesh3 target = TestUtil.LoadTestInputMesh("cylinder_orig.obj"); DMeshAABBTree3 targetSpatial = new DMeshAABBTree3(target, true); DMesh3 mesh = TestUtil.LoadTestInputMesh("cylinder_approx.obj"); DMeshAABBTree3 meshSpatial = new DMeshAABBTree3(mesh, true); double search_dist = 10.0; MeshTopology topo = new MeshTopology(target); topo.Compute(); RemesherPro r = new RemesherPro(mesh); r.SetTargetEdgeLength(2.0); r.SmoothSpeedT = 0.5; r.SetProjectionTarget(MeshProjectionTarget.Auto(target)); MeshConstraints cons = new MeshConstraints(); r.SetExternalConstraints(cons); int set_id = 1; foreach (var loop in topo.Loops) { DCurveProjectionTarget curveTarget = new DCurveProjectionTarget(loop.ToCurve(target)); set_id++; // pick a set of points we will find paths between. We will chain // up those paths and constrain them to target loops. // (this part is the hack!) List <int> target_verts = new List <int>(); List <int> mesh_verts = new List <int>(); for (int k = 0; k < loop.VertexCount; k += 5) { target_verts.Add(loop.Vertices[k]); Vector3d vCurve = target.GetVertex(loop.Vertices[k]); int mesh_vid = meshSpatial.FindNearestVertex(vCurve, search_dist); mesh_verts.Add(mesh_vid); } int NT = target_verts.Count; // find the paths to assemble the edge chain // [TODO] need to filter out junction vertices? or will they just handle themselves // because they can be collapsed away? List <int> vert_seq = new List <int>(); for (int k = 0; k < NT; k++) { EdgeSpan e = find_edge_path(mesh, mesh_verts[k], mesh_verts[(k + 1) % NT]); int n = e.Vertices.Length; for (int i = 0; i < n - 1; ++i) { vert_seq.Add(e.Vertices[i]); } } // now it's easy, just add the loop constraint EdgeLoop full_loop = EdgeLoop.FromVertices(mesh, vert_seq); MeshConstraintUtil.ConstrainVtxLoopTo(cons, mesh, full_loop.Vertices, curveTarget, set_id); } r.FastestRemesh(); TestUtil.WriteTestOutputMesh(mesh, "curves_test_out.obj"); }