DMesh3 compute_through_hole(Vector3d start, Vector3d end, double tol) { DMesh3 origMesh = MeshSource.GetDMeshUnsafe(); DMeshAABBTree3 origSpatial = MeshSource.GetSpatial() as DMeshAABBTree3; DMesh3 cutMesh = new DMesh3(origMesh); Polygon2d polygon = Polygon2d.MakeCircle(hole_size / 2, hole_subdivisions); Vector3f axis = (Vector3f)(start - end).Normalized; int start_tid = origSpatial.FindNearestTriangle(start); Frame3f start_frame = origMesh.GetTriFrame(start_tid); start_frame.Origin = (Vector3f)start; start_frame.AlignAxis(2, axis); int end_tid = origSpatial.FindNearestTriangle(end); //Frame3f end_frame = origMesh.GetTriFrame(end_tid); end_frame.Origin = (Vector3f)end; Frame3f end_frame = start_frame; end_frame.Origin = (Vector3f)end; MeshInsertProjectedPolygon start_insert = new MeshInsertProjectedPolygon(cutMesh, polygon, start_frame, start_tid); bool start_ok = start_insert.Insert(); MeshInsertProjectedPolygon end_insert = new MeshInsertProjectedPolygon(cutMesh, polygon, end_frame, end_tid); bool end_ok = end_insert.Insert(); if (start_ok == false || end_ok == false) { throw new Exception("CutPolygonHoleOp.compute_through_hole: start or end insertion failed!"); } MeshEditor editor = new MeshEditor(cutMesh); EdgeLoop l0 = start_insert.InsertedLoop; EdgeLoop l1 = end_insert.InsertedLoop; l1.Reverse(); editor.StitchLoop(l0.Vertices, l1.Vertices); return(cutMesh); }
/// <summary> /// Cut through-hole either vertically or horizontally. /// /// One current failure mode is if we get more than two ray-hits, which /// can happen due pathological cases or unexpected mesh shape. Currently /// trying to handle the pathological cases (ie ray hits adjacent triangles cases) /// via sorting, not sure if this works spectacularly well. /// /// </summary> protected bool CutThroughHole(DMesh3 mesh, HoleInfo hi, Vector3d translate) { Vector3d basePoint = CombinedBounds.Center - CombinedBounds.Extents.y * Vector3d.AxisY + translate; // do we need to compute spatial DS for each hole? not super efficient... DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh, true); Vector3d origin = Vector3d.Zero; Vector3d direction = Vector3d.One; if (hi.IsVertical) { direction = Vector3d.AxisY; origin = basePoint + new Vector3d(hi.XZOffset.x, 0, hi.XZOffset.y) - 100 * direction; } else { origin = basePoint + hi.Height * Vector3d.AxisY; direction = Quaterniond.AxisAngleD(Vector3d.AxisY, hi.AroundAngle) * Vector3d.AxisX; } // Find upper and lower triangles that contain center-points of // holes we want to cut. This is the most error-prone part // because we depend on ray-hits, which is not very reliable... Ray3d ray1 = new Ray3d(origin, direction); Ray3d ray2 = new Ray3d(origin + 10000 * direction, -direction); if (hi.GroupIDFilters.a > 0) { spatial.TriangleFilterF = (tid) => { return(mesh.GetTriangleGroup(tid) == hi.GroupIDFilters.a); }; } int hit_1 = spatial.FindNearestHitTriangle(ray1); spatial.TriangleFilterF = null; if (hi.GroupIDFilters.b > 0) { spatial.TriangleFilterF = (tid) => { return(mesh.GetTriangleGroup(tid) == hi.GroupIDFilters.b); }; } int hit_2 = spatial.FindNearestHitTriangle(ray2); spatial.TriangleFilterF = null; if (hit_1 == DMesh3.InvalidID || hit_2 == DMesh3.InvalidID) { return(false); } if (hit_1 == hit_2) { return(false); } List <int> hitTris = new List <int>() { hit_1, hit_2 }; Frame3f projectFrame = new Frame3f(ray1.Origin, ray1.Direction); int nVerts = 32; if (hi.Vertices != 0) { nVerts = hi.Vertices; } double angleShiftRad = hi.AxisAngleD * MathUtil.Deg2Rad; Polygon2d circle = Polygon2d.MakeCircle(hi.Radius, nVerts, angleShiftRad); List <EdgeLoop> edgeLoops = new List <EdgeLoop>(); foreach (int hit_tid in hitTris) { try { MeshInsertProjectedPolygon insert = new MeshInsertProjectedPolygon(mesh, circle, projectFrame, hit_tid) { SimplifyInsertion = true }; if (insert.Insert()) { // if we have extra edges just randomly collapse EdgeLoop loop = insert.InsertedLoop; if (loop.VertexCount > circle.VertexCount) { loop = simplify_loop(mesh, loop, circle.VertexCount); } edgeLoops.Add(loop); } else { f3.DebugUtil.Log("insert.Insert() failed!!"); return(false); } } catch (Exception e) { // ignore this loop but we might already be in trouble... f3.DebugUtil.Log("insert.Insert() threw exception for hole {0}!!", hi.nHole); f3.DebugUtil.Log(e.Message); } } if (edgeLoops.Count != 2) { return(false); } try { MeshEditor editor = new MeshEditor(mesh); EdgeLoop l0 = edgeLoops[0]; EdgeLoop l1 = edgeLoops[1]; l1.Reverse(); editor.StitchVertexLoops_NearestV(l0.Vertices, l1.Vertices); // split edges around the holes we cut. This is helpful // if we are going to do additional operations in these areas, // as it gives us extra rings to work with //MeshEdgeSelection edges = new MeshEdgeSelection(mesh); //edges.SelectVertexEdges(l0.Vertices); //edges.SelectVertexEdges(l1.Vertices); //DMesh3.EdgeSplitInfo splitInfo; //foreach ( int eid in edges ) // mesh.SplitEdge(eid, out splitInfo); return(true); } catch { f3.DebugUtil.Log("stitch threw exception!"); return(false); } }
public static void testInsertPolygon_PlanarProj() { double dscale = 1.0; DMesh3 mesh = TestUtil.LoadTestInputMesh("bunny_solid.obj"); dscale = 0.3; //DMesh3 mesh = TestUtil.LoadTestInputMesh("cylinder.obj"); //DMesh3 mesh = TestUtil.LoadTestInputMesh("cube.obj"); double size = mesh.CachedBounds.MaxDim; Vector3d c = mesh.CachedBounds.Center; Vector3d fw = c + mesh.CachedBounds.DiagonalLength * 2 * Vector3d.AxisZ; Ray3d ray = new Ray3d(fw, (c - fw).Normalized); // projection frame and polygon that lives in this frame Frame3f projectFrame = new Frame3f(ray.Origin, ray.Direction); Polygon2d circle = Polygon2d.MakeCircle(dscale * size * 0.1, 6); DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh, true); List <int> hitTris = new List <int>(); spatial.FindAllHitTriangles(ray, hitTris); while (hitTris.Count != 2) { ray.Origin += 100 * MathUtil.Epsilon * Vector3d.One; hitTris.Clear(); spatial.FindAllHitTriangles(ray, hitTris); } // insert polygons but don't simplify the result DMesh3 noTrimMesh = new DMesh3(mesh); List <int[]> noTrimPolyVerts = new List <int[]>(); List <EdgeLoop> noTrimLoops = new List <EdgeLoop>(); foreach (int hit_tid in hitTris) { MeshInsertProjectedPolygon insert = new MeshInsertProjectedPolygon(noTrimMesh, circle, projectFrame, hit_tid); insert.SimplifyInsertion = false; if (insert.Insert()) { noTrimPolyVerts.Add(insert.InsertedPolygonVerts); noTrimLoops.Add(insert.InsertedLoop); } else { System.Console.WriteLine("testInsertPolygon_PlanarProj: no-trim Insert() failed"); } } TestUtil.WriteTestOutputMesh(noTrimMesh, "insert_polygon_notrim.obj"); // do different-vtx-count stitch if (noTrimLoops.Count == 2) { noTrimLoops[1].Reverse(); MeshStitchLoops stitcher = new MeshStitchLoops(noTrimMesh, noTrimLoops[0], noTrimLoops[1]); stitcher.TrustLoopOrientations = false; stitcher.AddKnownCorrespondences(noTrimPolyVerts[0], noTrimPolyVerts[1]); stitcher.Stitch(); } TestUtil.WriteTestOutputMesh(noTrimMesh, "insert_polygon_notrim_joined.obj"); // now do simplified version, which we can trivially stitch List <EdgeLoop> edgeLoops = new List <EdgeLoop>(); foreach (int hit_tid in hitTris) { MeshInsertProjectedPolygon insert = new MeshInsertProjectedPolygon(mesh, circle, projectFrame, hit_tid); if (insert.Insert()) { edgeLoops.Add(insert.InsertedLoop); } else { System.Console.WriteLine("testInsertPolygon_PlanarProj: Insert() failed"); } } //TestUtil.WriteTestOutputMesh(mesh, "insert_polygon_before_stitch.obj"); // do stitch if (edgeLoops.Count == 2) { MeshEditor editor = new MeshEditor(mesh); EdgeLoop l0 = edgeLoops[0]; EdgeLoop l1 = edgeLoops[1]; l1.Reverse(); editor.StitchLoop(l0.Vertices, l1.Vertices); } TestUtil.WriteTestOutputMesh(mesh, "insert_polygon_joined.obj"); }