bool compute_outer_wall() { SocketMesh = new DMesh3(InnerMesh); LastInnerGroupID = SocketMesh.AllocateTriangleGroup(); FaceGroupUtil.SetGroupID(SocketMesh, LastInnerGroupID); if (DebugStep <= 1) { return(true); } double use_thickness = thickness; MeshExtrudeMesh extrude = new MeshExtrudeMesh(SocketMesh); extrude.ExtrudedPositionF = (v, n, vid) => { return(v + use_thickness * (Vector3d)n); }; if (extrude.Extrude() == false) { return(false); } LastExtrudeOuterGroupID = extrude.OffsetGroupID; LastStitchGroupID = extrude.StitchGroupIDs[0]; return(true); }
List<DMesh3> process_solids(List<DMesh3> solid_components) { // [TODO] maybe we can have special tags that extract out certain meshes? var combinedSolid = new DMesh3(SourceMesh.Components | MeshComponents.FaceGroups); var editor = new MeshEditor(combinedSolid); foreach (DMesh3 solid in solid_components) { editor.AppendMesh(solid, combinedSolid.AllocateTriangleGroup()); } return new List<DMesh3>() { combinedSolid }; }
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 bool Apply() { // do a simple fill SimpleHoleFiller simplefill = new SimpleHoleFiller(Mesh, FillLoop); int fill_gid = Mesh.AllocateTriangleGroup(); bool bOK = simplefill.Fill(fill_gid); if (bOK == false) { return(false); } if (FillLoop.Vertices.Length <= 3) { FillTriangles = simplefill.NewTriangles; FillVertices = new int[0]; return(true); } // extract the simple fill mesh as a submesh, via RegionOperator, so we can backsub later HashSet <int> intial_fill_tris = new HashSet <int>(simplefill.NewTriangles); regionop = new RegionOperator(Mesh, simplefill.NewTriangles, (submesh) => { submesh.ComputeTriMaps = true; }); fillmesh = regionop.Region.SubMesh; // for each boundary vertex, compute the exterior angle sum // we will use this to compute gaussian curvature later boundaryv = new HashSet <int>(MeshIterators.BoundaryEdgeVertices(fillmesh)); exterior_angle_sums = new Dictionary <int, double>(); if (IgnoreBoundaryTriangles == false) { foreach (int sub_vid in boundaryv) { double angle_sum = 0; int base_vid = regionop.Region.MapVertexToBaseMesh(sub_vid); foreach (int tid in regionop.BaseMesh.VtxTrianglesItr(base_vid)) { if (intial_fill_tris.Contains(tid) == false) { Index3i et = regionop.BaseMesh.GetTriangle(tid); int idx = IndexUtil.find_tri_index(base_vid, ref et); angle_sum += regionop.BaseMesh.GetTriInternalAngleR(tid, idx); } } exterior_angle_sums[sub_vid] = angle_sum; } } // try to guess a reasonable edge length that will give us enough geometry to work with in simplify pass double loop_mine, loop_maxe, loop_avge, fill_mine, fill_maxe, fill_avge; MeshQueries.EdgeLengthStatsFromEdges(Mesh, FillLoop.Edges, out loop_mine, out loop_maxe, out loop_avge); MeshQueries.EdgeLengthStats(fillmesh, out fill_mine, out fill_maxe, out fill_avge); double remesh_target_len = loop_avge; if (fill_maxe / remesh_target_len > 10) { remesh_target_len = fill_maxe / 10; } //double remesh_target_len = Math.Min(loop_avge, fill_avge / 4); // remesh up to target edge length, ideally gives us some triangles to work with RemesherPro remesh1 = new RemesherPro(fillmesh); remesh1.SmoothSpeedT = 1.0; MeshConstraintUtil.FixAllBoundaryEdges(remesh1); //remesh1.SetTargetEdgeLength(remesh_target_len / 2); // would this speed things up? on large regions? //remesh1.FastestRemesh(); remesh1.SetTargetEdgeLength(remesh_target_len); remesh1.FastestRemesh(); /* * first round: collapse to minimal mesh, while flipping to try to * get to ballpark minimal mesh. We stop these passes as soon as * we have done two rounds where we couldn't do another collapse * * This is the most unstable part of the algorithm because there * are strong ordering effects. maybe we could sort the edges somehow?? */ int zero_collapse_passes = 0; int collapse_passes = 0; while (collapse_passes++ < 20 && zero_collapse_passes < 2) { // collapse pass int NE = fillmesh.MaxEdgeID; int collapses = 0; for (int ei = 0; ei < NE; ++ei) { if (fillmesh.IsEdge(ei) == false || fillmesh.IsBoundaryEdge(ei)) { continue; } Index2i ev = fillmesh.GetEdgeV(ei); bool a_bdry = boundaryv.Contains(ev.a), b_bdry = boundaryv.Contains(ev.b); if (a_bdry && b_bdry) { continue; } int keepv = (a_bdry) ? ev.a : ev.b; int otherv = (keepv == ev.a) ? ev.b : ev.a; Vector3d newv = fillmesh.GetVertex(keepv); if (MeshUtil.CheckIfCollapseCreatesFlip(fillmesh, ei, newv)) { continue; } DMesh3.EdgeCollapseInfo info; MeshResult result = fillmesh.CollapseEdge(keepv, otherv, out info); if (result == MeshResult.Ok) { collapses++; } } if (collapses == 0) { zero_collapse_passes++; } else { zero_collapse_passes = 0; } // flip pass. we flip in these cases: // 1) if angle between current triangles is too small (slightly more than 90 degrees, currently) // 2) if angle between flipped triangles is smaller than between current triangles // 3) if flipped edge length is shorter *and* such a flip won't flip the normal NE = fillmesh.MaxEdgeID; Vector3d n1, n2, on1, on2; for (int ei = 0; ei < NE; ++ei) { if (fillmesh.IsEdge(ei) == false || fillmesh.IsBoundaryEdge(ei)) { continue; } bool do_flip = false; Index2i ev = fillmesh.GetEdgeV(ei); MeshUtil.GetEdgeFlipNormals(fillmesh, ei, out n1, out n2, out on1, out on2); double dot_cur = n1.Dot(n2); double dot_flip = on1.Dot(on2); if (n1.Dot(n2) < 0.1 || dot_flip > dot_cur + MathUtil.Epsilonf) { do_flip = true; } if (do_flip == false) { Index2i otherv = fillmesh.GetEdgeOpposingV(ei); double len_e = fillmesh.GetVertex(ev.a).Distance(fillmesh.GetVertex(ev.b)); double len_flip = fillmesh.GetVertex(otherv.a).Distance(fillmesh.GetVertex(otherv.b)); if (len_flip < len_e) { if (MeshUtil.CheckIfEdgeFlipCreatesFlip(fillmesh, ei) == false) { do_flip = true; } } } if (do_flip) { DMesh3.EdgeFlipInfo info; MeshResult result = fillmesh.FlipEdge(ei, out info); } } } // Sometimes, for some reason, we have a remaining interior vertex (have only ever seen one?) // Try to force removal of such vertices, even if it makes ugly mesh remove_remaining_interior_verts(); // enable/disable passes. bool DO_FLATTER_PASS = true; bool DO_CURVATURE_PASS = OptimizeDevelopability && true; bool DO_AREA_PASS = OptimizeDevelopability && OptimizeTriangles && true; /* * In this pass we repeat the flipping iterations from the previous pass. * * Note that because of the always-flip-if-dot-is-small case (commented), * this pass will frequently not converge, as some number of edges will * be able to flip back and forth (because neither has large enough dot). * This is not ideal, but also, if we remove this behavior, then we * generally get worse fills. This case basically introduces a sort of * randomization factor that lets us escape local minima... * */ HashSet <int> remaining_edges = new HashSet <int>(fillmesh.EdgeIndices()); HashSet <int> updated_edges = new HashSet <int>(); int flatter_passes = 0; int zero_flips_passes = 0; while (flatter_passes++ < 40 && zero_flips_passes < 2 && remaining_edges.Count() > 0 && DO_FLATTER_PASS) { zero_flips_passes++; foreach (int ei in remaining_edges) { if (fillmesh.IsBoundaryEdge(ei)) { continue; } bool do_flip = false; Index2i ev = fillmesh.GetEdgeV(ei); Vector3d n1, n2, on1, on2; MeshUtil.GetEdgeFlipNormals(fillmesh, ei, out n1, out n2, out on1, out on2); double dot_cur = n1.Dot(n2); double dot_flip = on1.Dot(on2); if (flatter_passes < 20 && dot_cur < 0.1) // this check causes oscillatory behavior { do_flip = true; } if (dot_flip > dot_cur + MathUtil.Epsilonf) { do_flip = true; } if (do_flip) { DMesh3.EdgeFlipInfo info; MeshResult result = fillmesh.FlipEdge(ei, out info); if (result == MeshResult.Ok) { zero_flips_passes = 0; add_all_edges(ei, updated_edges); } } } var tmp = remaining_edges; remaining_edges = updated_edges; updated_edges = tmp; updated_edges.Clear(); } int curvature_passes = 0; if (DO_CURVATURE_PASS) { curvatures = new double[fillmesh.MaxVertexID]; foreach (int vid in fillmesh.VertexIndices()) { update_curvature(vid); } remaining_edges = new HashSet <int>(fillmesh.EdgeIndices()); updated_edges = new HashSet <int>(); /* * In this pass we try to minimize gaussian curvature at all the vertices. * This will recover sharp edges, etc, and do lots of good stuff. * However, this pass will not make much progress if we are not already * relatively close to a minimal mesh, so it really relies on the previous * passes getting us in the ballpark. */ while (curvature_passes++ < 40 && remaining_edges.Count() > 0 && DO_CURVATURE_PASS) { foreach (int ei in remaining_edges) { if (fillmesh.IsBoundaryEdge(ei)) { continue; } Index2i ev = fillmesh.GetEdgeV(ei); Index2i ov = fillmesh.GetEdgeOpposingV(ei); int find_other = fillmesh.FindEdge(ov.a, ov.b); if (find_other != DMesh3.InvalidID) { continue; } double total_curv_cur = curvature_metric_cached(ev.a, ev.b, ov.a, ov.b); if (total_curv_cur < MathUtil.ZeroTolerancef) { continue; } DMesh3.EdgeFlipInfo info; MeshResult result = fillmesh.FlipEdge(ei, out info); if (result != MeshResult.Ok) { continue; } double total_curv_flip = curvature_metric_eval(ev.a, ev.b, ov.a, ov.b); bool keep_flip = total_curv_flip < total_curv_cur - MathUtil.ZeroTolerancef; if (keep_flip == false) { result = fillmesh.FlipEdge(ei, out info); } else { update_curvature(ev.a); update_curvature(ev.b); update_curvature(ov.a); update_curvature(ov.b); add_all_edges(ei, updated_edges); } } var tmp = remaining_edges; remaining_edges = updated_edges; updated_edges = tmp; updated_edges.Clear(); } } //System.Console.WriteLine("collapse {0} flatter {1} curvature {2}", collapse_passes, flatter_passes, curvature_passes); /* * In this final pass, we try to improve triangle quality. We flip if * the flipped triangles have better total aspect ratio, and the * curvature doesn't change **too** much. The .DevelopabilityTolerance * parameter determines what is "too much" curvature change. */ if (DO_AREA_PASS) { remaining_edges = new HashSet <int>(fillmesh.EdgeIndices()); updated_edges = new HashSet <int>(); int area_passes = 0; while (remaining_edges.Count() > 0 && area_passes < 20) { area_passes++; foreach (int ei in remaining_edges) { if (fillmesh.IsBoundaryEdge(ei)) { continue; } Index2i ev = fillmesh.GetEdgeV(ei); Index2i ov = fillmesh.GetEdgeOpposingV(ei); int find_other = fillmesh.FindEdge(ov.a, ov.b); if (find_other != DMesh3.InvalidID) { continue; } double total_curv_cur = curvature_metric_cached(ev.a, ev.b, ov.a, ov.b); double a = aspect_metric(ei); if (a > 1) { continue; } DMesh3.EdgeFlipInfo info; MeshResult result = fillmesh.FlipEdge(ei, out info); if (result != MeshResult.Ok) { continue; } double total_curv_flip = curvature_metric_eval(ev.a, ev.b, ov.a, ov.b); bool keep_flip = Math.Abs(total_curv_cur - total_curv_flip) < DevelopabilityTolerance; if (keep_flip == false) { result = fillmesh.FlipEdge(ei, out info); } else { update_curvature(ev.a); update_curvature(ev.b); update_curvature(ov.a); update_curvature(ov.b); add_all_edges(ei, updated_edges); } } var tmp = remaining_edges; remaining_edges = updated_edges; updated_edges = tmp; updated_edges.Clear(); } } regionop.BackPropropagate(); FillTriangles = regionop.CurrentBaseTriangles; FillVertices = regionop.CurrentBaseInteriorVertices().ToArray(); return(true); }
public void takePointsinandAddtoMesh(List <Vector3d> pointers) { List <int> tris = new List <int>(); List <Vector3d> normals = new List <Vector3d>(); float normal = .01f; if (currentMesh == null) { //ok so first mesh is not been created yet so create it from the first frame int counter = 0; foreach (Vector3d line in pointers) { counter++; //Debug.Log(line); tris.Add(counter); tris.Add(counter); tris.Add(counter); normals.Add(new Vector3d(normal, normal, normal)); } DMesh3 pointSet = DMesh3Builder.Build(pointers, tris, normals); PointAABBTree3 bvtree = new PointAABBTree3(pointSet, true); bvtree.FastWindingNumber(Vector3d.Zero); // estimate point area based on nearest-neighbour distance double[] areas = new double[pointSet.MaxVertexID]; foreach (int vid in pointSet.VertexIndices()) { bvtree.PointFilterF = (i) => { return(i != vid); }; // otherwise vid is nearest to vid! int near_vid = bvtree.FindNearestPoint(pointSet.GetVertex(vid)); double dist = pointSet.GetVertex(vid).Distance(pointSet.GetVertex(near_vid)); areas[vid] = Circle2d.RadiusArea(dist); } bvtree.FWNAreaEstimateF = (vid) => { return(areas[vid]); }; MarchingCubes mc = new MarchingCubes(); mc.Implicit = new PWNImplicit() { Spatial = bvtree }; mc.IsoValue = 0.0; mc.CubeSize = bvtree.Bounds.MaxDim / 10; mc.Bounds = bvtree.Bounds.Expanded(mc.CubeSize * 3); mc.RootMode = MarchingCubes.RootfindingModes.Bisection; mc.Generate(); DMesh3 resultMesh = mc.Mesh; // g3UnityUtils.SetGOMesh(transform.gameObject, resultMesh); currentMesh = resultMesh; } else { //ok so this is where we are proscessing second mesh int counter = 0; foreach (Vector3d line in pointers) { counter++; //Debug.Log(line); tris.Add(counter); tris.Add(counter); tris.Add(counter); normals.Add(new Vector3d(normal, normal, normal)); } DMesh3 pointSet = DMesh3Builder.Build(pointers, tris, normals); PointAABBTree3 bvtree = new PointAABBTree3(pointSet, true); bvtree.FastWindingNumber(Vector3d.Zero); // estimate point area based on nearest-neighbour distance double[] areas = new double[pointSet.MaxVertexID]; foreach (int vid in pointSet.VertexIndices()) { bvtree.PointFilterF = (i) => { return(i != vid); }; // otherwise vid is nearest to vid! int near_vid = bvtree.FindNearestPoint(pointSet.GetVertex(vid)); double dist = pointSet.GetVertex(vid).Distance(pointSet.GetVertex(near_vid)); areas[vid] = Circle2d.RadiusArea(dist); } bvtree.FWNAreaEstimateF = (vid) => { return(areas[vid]); }; MarchingCubes mc = new MarchingCubes(); mc.Implicit = new PWNImplicit() { Spatial = bvtree }; mc.IsoValue = 0.0; mc.CubeSize = bvtree.Bounds.MaxDim / 10; mc.Bounds = bvtree.Bounds.Expanded(mc.CubeSize * 3); mc.RootMode = MarchingCubes.RootfindingModes.Bisection; mc.Generate(); DMesh3 resultMesh = mc.Mesh; MeshEditor editor = new MeshEditor(currentMesh); editor.AppendMesh(resultMesh, currentMesh.AllocateTriangleGroup()); //suspected its crashing after mesh is over 64000 faces, faceLog.text = "Vertex Count = " + transform.gameObject.GetComponent <MeshFilter>().mesh.triangles.Length; g3UnityUtils.SetGOMesh(transform.gameObject, currentMesh); } }
public void fpMeshPointsfromTextFileWithaSecondPoints() { //this is used in the fast points winding scene to optimize algorithm and make sure its working well //it reads points via text files and then meshes them List <Vector3d> points = new List <Vector3d>(); List <int> tris = new List <int>(); List <Vector3d> normals = new List <Vector3d>(); float normal = .01f; string toPull = ReadString(); string[] linesInFile = toPull.Split('\n'); int counter = 0; foreach (string line in linesInFile) { counter++; //Debug.Log(line); if (!string.IsNullOrEmpty(line)) { points.Add(StringToVector3(line)); tris.Add(counter); tris.Add(counter); tris.Add(counter); normals.Add(new Vector3d(normal, normal, normal)); } } DMesh3 pointSet = DMesh3Builder.Build(points, tris, normals); PointAABBTree3 bvtree = new PointAABBTree3(pointSet, true); bvtree.FastWindingNumber(Vector3d.Zero); // estimate point area based on nearest-neighbour distance double[] areas = new double[pointSet.MaxVertexID]; foreach (int vid in pointSet.VertexIndices()) { bvtree.PointFilterF = (i) => { return(i != vid); }; // otherwise vid is nearest to vid! int near_vid = bvtree.FindNearestPoint(pointSet.GetVertex(vid)); double dist = pointSet.GetVertex(vid).Distance(pointSet.GetVertex(near_vid)); areas[vid] = Circle2d.RadiusArea(dist); } bvtree.FWNAreaEstimateF = (vid) => { return(areas[vid]); }; MarchingCubes mc = new MarchingCubes(); mc.Implicit = new PWNImplicit() { Spatial = bvtree }; mc.IsoValue = 0.0; mc.CubeSize = bvtree.Bounds.MaxDim / 50; mc.Bounds = bvtree.Bounds.Expanded(mc.CubeSize * 3); mc.RootMode = MarchingCubes.RootfindingModes.Bisection; mc.Generate(); DMesh3 resultMesh = mc.Mesh; g3UnityUtils.SetGOMesh(transform.gameObject, resultMesh); /* MarchingCubes mc = new MarchingCubes(); * mc.Implicit = new PWNImplicit() { Spatial = bvtree }; * mc.IsoValue = 0.0; * mc.CubeSize = bvtree.Bounds.MaxDim / 10; * mc.Bounds = bvtree.Bounds.Expanded(mc.CubeSize * 3); * mc.RootMode = MarchingCubes.RootfindingModes.Bisection; * mc.Generate(); * DMesh3 resultMesh = mc.Mesh; * g3UnityUtils.SetGOMesh(transform.gameObject, resultMesh); */ //ok now that we meshed the first point set, lets try to take in a second frame of points and then add to orginal dmesh points = new List <Vector3d>(); tris = new List <int>(); normals = new List <Vector3d>(); toPull = ReadString1(); linesInFile = toPull.Split('\n'); counter = 0; foreach (string line in linesInFile) { counter++; Debug.Log(line); if (!string.IsNullOrEmpty(line)) { points.Add(StringToVector3(line)); tris.Add(counter); tris.Add(counter); tris.Add(counter); normals.Add(new Vector3d(normal, normal, normal)); } } pointSet = DMesh3Builder.Build(points, tris, normals); bvtree = new PointAABBTree3(pointSet, true); bvtree.FastWindingNumber(Vector3d.Zero); // estimate point area based on nearest-neighbour distance areas = new double[pointSet.MaxVertexID]; foreach (int vid in pointSet.VertexIndices()) { bvtree.PointFilterF = (i) => { return(i != vid); }; // otherwise vid is nearest to vid! int near_vid = bvtree.FindNearestPoint(pointSet.GetVertex(vid)); double dist = pointSet.GetVertex(vid).Distance(pointSet.GetVertex(near_vid)); areas[vid] = Circle2d.RadiusArea(dist); } bvtree.FWNAreaEstimateF = (vid) => { return(areas[vid]); }; mc = new MarchingCubes(); mc.Implicit = new PWNImplicit() { Spatial = bvtree }; mc.IsoValue = 0.0; mc.CubeSize = bvtree.Bounds.MaxDim / 50; mc.Bounds = bvtree.Bounds.Expanded(mc.CubeSize * 3); mc.RootMode = MarchingCubes.RootfindingModes.Bisection; mc.Generate(); DMesh3 resultMesh1 = mc.Mesh; MeshEditor editor = new MeshEditor(resultMesh); editor.AppendMesh(resultMesh1, resultMesh.AllocateTriangleGroup()); g3UnityUtils.SetGOMesh(transform.gameObject, resultMesh1); // g3UnityUtils.SetGOMesh(transform.gameObject, resultMesh); }
List <Polygon2d> decompose_cluster_up(DMesh3 mesh) { optimize_mesh(mesh); mesh.CompactInPlace(); mesh.DiscardTriangleGroups(); mesh.EnableTriangleGroups(0); double minLength = Settings.MaxBridgeWidthMM * 0.75; double minArea = minLength * minLength; Dictionary <int, double> areas = new Dictionary <int, double>(); Dictionary <int, HashSet <int> > trisets = new Dictionary <int, HashSet <int> >(); HashSet <int> active_groups = new HashSet <int>(); Action <int, int> add_tri_to_group = (tid, gid) => { mesh.SetTriangleGroup(tid, gid); areas[gid] = areas[gid] + mesh.GetTriArea(tid); trisets[gid].Add(tid); }; Action <int, int> add_group_to_group = (gid, togid) => { var set = trisets[togid]; foreach (int tid in trisets[gid]) { mesh.SetTriangleGroup(tid, togid); set.Add(tid); } areas[togid] += areas[gid]; active_groups.Remove(gid); }; Func <IEnumerable <int>, int> find_min_area_group = (tri_itr) => { int min_gid = -1; double min_area = double.MaxValue; foreach (int tid in tri_itr) { int gid = mesh.GetTriangleGroup(tid); double a = areas[gid]; if (a < min_area) { min_area = a; min_gid = gid; } } return(min_gid); }; foreach (int eid in MeshIterators.InteriorEdges(mesh)) { Index2i et = mesh.GetEdgeT(eid); if (mesh.GetTriangleGroup(et.a) != 0 || mesh.GetTriangleGroup(et.b) != 0) { continue; } int gid = mesh.AllocateTriangleGroup(); areas[gid] = 0; trisets[gid] = new HashSet <int>(); active_groups.Add(gid); add_tri_to_group(et.a, gid); add_tri_to_group(et.b, gid); } foreach (int tid in mesh.TriangleIndices()) { if (mesh.GetTriangleGroup(tid) != 0) { continue; } int gid = find_min_area_group(mesh.TriTrianglesItr(tid)); add_tri_to_group(tid, gid); } IndexPriorityQueue pq = new IndexPriorityQueue(mesh.MaxGroupID); foreach (var pair in areas) { pq.Insert(pair.Key, (float)pair.Value); } while (pq.Count > 0) { int gid = pq.First; pq.Remove(gid); if (areas[gid] > minArea) // ?? { break; } List <int> nbr_groups = find_neighbour_groups(mesh, gid, trisets[gid]); int min_gid = -1; double min_area = double.MaxValue; foreach (int ngid in nbr_groups) { double a = areas[ngid]; if (a < min_area) { min_area = a; min_gid = ngid; } } if (min_gid != -1) { add_group_to_group(gid, min_gid); pq.Remove(min_gid); pq.Insert(min_gid, (float)areas[min_gid]); } } List <Polygon2d> result = new List <Polygon2d>(); int[][] sets = FaceGroupUtil.FindTriangleSetsByGroup(mesh); foreach (var set in sets) { result.Add(make_poly(mesh, set)); } return(result); }
public virtual void Update() { base.begin_update(); int start_timestamp = this.CurrentInputTimestamp; if (MeshSource == null) { throw new Exception("CombineMeshesOp: must set valid MeshSource to compute!"); } ResultMesh = null; try { DMesh3 meshIn = new DMesh3(MeshSource.GetDMeshUnsafe()); if (orient_nested_shells) { MeshConnectedComponents comp = new MeshConnectedComponents(meshIn); comp.FindConnectedT(); DSubmesh3Set subMeshes = new DSubmesh3Set(meshIn, comp); List <DMesh3> curMeshes = new List <DMesh3>(); foreach (var submesh in subMeshes) { curMeshes.Add(submesh.SubMesh); } MeshSpatialSort sort = new MeshSpatialSort(); foreach (var mesh in curMeshes) { sort.AddMesh(mesh, mesh); } sort.Sort(); ResultMesh = new DMesh3(); MeshEditor editor = new MeshEditor(ResultMesh); foreach (var solid in sort.Solids) { DMesh3 outer = solid.Outer.Mesh; if (!is_outward_oriented(outer)) { outer.ReverseOrientation(); } editor.AppendMesh(outer, ResultMesh.AllocateTriangleGroup()); foreach (var hole in solid.Cavities) { if (hole.Mesh.CachedIsClosed && is_outward_oriented(hole.Mesh) == true) { hole.Mesh.ReverseOrientation(); } editor.AppendMesh(hole.Mesh, ResultMesh.AllocateTriangleGroup()); } } } else { ResultMesh = meshIn; } base.complete_update(); } catch (Exception e) { PostOnOperatorException(e); ResultMesh = base.make_failure_output(MeshSource.GetDMeshUnsafe()); base.complete_update(); } }