List <int> find_neighbour_groups(DMesh3 mesh, int gid, HashSet <int> group_tris) { List <int> result = new List <int>(); foreach (int tid in group_tris) { foreach (int ntid in mesh.TriTrianglesItr(tid)) { int ngid = mesh.GetTriangleGroup(ntid); if (ngid != gid && result.Contains(ngid) == false) { result.Add(ngid); } } } return(result); }
internal bool CheckPositionValid(DMesh3 mesh, Vector3d position, int colorToExclude) { var spatial = new DMeshAABBTree3(mesh); spatial.Build(); spatial.TriangleFilterF = i => mesh.GetTriangleGroup(i) != colorToExclude; int near_tid = spatial.FindNearestTriangle(position, 9f); if (near_tid != DMesh3.InvalidID) { return(false); } return(true); }
public static void test_region_boundary() { List<int> cases = new List<int>() { 0, 1, 2, 3 }; foreach ( int num in cases ) { string name; DMesh3 mesh = MakeBoundaryTestMesh(num, out name); int[][] groups = FaceGroupUtil.FindTriangleSetsByGroup(mesh, 0); System.Console.WriteLine("case {0}:", name); for (int k = 0; k < groups.Length; ++k) { int gid = mesh.GetTriangleGroup(groups[k][0]); MeshRegionBoundaryLoops loops = new MeshRegionBoundaryLoops(mesh, groups[k]); System.Console.WriteLine(" gid {0} : found {1} loops", gid, loops.Loops.Count); } } }
/// <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); } }
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); }
// [RMS] This doesn't work because I did something stupid when // making unwrap meshes. The set of triangles aren't the same. argh. public static DMesh3 ConvertUnwrapToUVs(RemoteControl rc, out DenseMeshUVSet UVSet, string mainName = "main") { int mainID = rc.FindObjectByName(mainName); rc.CompactMesh(mainID); DMesh3 mainMesh = ReadMeshFromMM(rc, mainID); Debug.Assert(mainMesh.IsCompact); List <int> all = rc.ListObjects(); List <int> unwrapIDs = new List <int>(); foreach (int id in all) { string sName = rc.GetObjectName(id); if (sName.StartsWith("unwrap", StringComparison.OrdinalIgnoreCase)) { unwrapIDs.Add(id); } } int[] AllGroups = FaceGroupUtil.FindAllGroups(mainMesh).ToArray(); Dictionary <int, DMesh3> Unwraps = new Dictionary <int, DMesh3>(); foreach (int id in unwrapIDs) { DMesh3 mesh = ReadMeshFromMM(rc, id); HashSet <int> subGroups = FaceGroupUtil.FindAllGroups(mesh); Debug.Assert(subGroups.Count == 1); int gid = subGroups.ToArray()[0]; Unwraps[gid] = mesh; } UVSet = new DenseMeshUVSet(); UVSet.TriangleUVs.resize(mainMesh.TriangleCount); Dictionary <Index2i, int> UVSetMap = new Dictionary <Index2i, int>(); Dictionary <int, int> GroupCounters = new Dictionary <int, int>(); for (int i = 0; i < AllGroups.Length; ++i) { GroupCounters[AllGroups[i]] = 0; } for (int ti = 0; ti < mainMesh.TriangleCount; ++ti) { Index3i main_tri = mainMesh.GetTriangle(ti); int gid = mainMesh.GetTriangleGroup(ti); int sub_tid = GroupCounters[gid]; GroupCounters[gid]++; DMesh3 SubMesh = Unwraps[gid]; Index3i sub_tri = SubMesh.GetTriangle(sub_tid); for (int j = 0; j < 3; ++j) { int sub_vid = sub_tri[j]; Index2i key = new Index2i(gid, sub_vid); int uvset_idx; if (UVSetMap.TryGetValue(key, out uvset_idx) == false) { Vector3d v = SubMesh.GetVertex(sub_vid); Vector2f uv = new Vector2f((float)v.x, (float)v.z); uvset_idx = UVSet.AppendUV(uv); UVSetMap[key] = uvset_idx; } sub_tri[j] = uvset_idx; } UVSet.TriangleUVs[ti] = sub_tri; } return(mainMesh); }
protected void do_flatten(DMesh3 mesh) { double BAND_HEIGHT = flatten_band_height; Vector3d down_axis = -Vector3d.AxisY; double dot_thresh = 0.2; AxisAlignedBox3d bounds = mesh.CachedBounds; DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh, true); Ray3d ray = new Ray3d(bounds.Center - 2 * bounds.Height * Vector3d.AxisY, Vector3d.AxisY); int hit_tid = spatial.FindNearestHitTriangle(ray); Frame3f hitF; MeshQueries.RayHitPointFrame(mesh, spatial, ray, out hitF); Vector3d basePt = hitF.Origin; Frame3f basePlane = new Frame3f(basePt, Vector3f.AxisY); MeshConnectedComponents components = new MeshConnectedComponents(mesh) { FilterF = (tid) => { if (mesh.GetTriangleGroup(tid) != LastExtrudeOuterGroupID) { return(false); } Vector3d n, c; double a; mesh.GetTriInfo(tid, out n, out a, out c); double h = Math.Abs(c.y - basePt.y); if (h > BAND_HEIGHT) { return(false); } if (n.Dot(down_axis) < dot_thresh) { return(false); } return(true); }, SeedFilterF = (tid) => { return(tid == hit_tid); } }; components.FindConnectedT(); MeshFaceSelection all_faces = new MeshFaceSelection(mesh); foreach (var comp in components) { MeshVertexSelection vertices = new MeshVertexSelection(mesh); vertices.SelectTriangleVertices(comp.Indices); foreach (int vid in vertices) { Vector3d v = mesh.GetVertex(vid); v = basePlane.ProjectToPlane((Vector3f)v, 2); mesh.SetVertex(vid, v); } all_faces.SelectVertexOneRings(vertices); } all_faces.ExpandToOneRingNeighbours(3, (tid) => { return(mesh.GetTriangleGroup(tid) == LastExtrudeOuterGroupID); }); RegionRemesher r = new RegionRemesher(mesh, all_faces); r.SetProjectionTarget(MeshProjectionTarget.Auto(mesh)); r.SetTargetEdgeLength(2.0f); r.SmoothSpeedT = 1.0f; for (int k = 0; k < 10; ++k) { r.BasicRemeshPass(); } r.SetProjectionTarget(null); r.SmoothSpeedT = 1.0f; for (int k = 0; k < 10; ++k) { r.BasicRemeshPass(); } r.BackPropropagate(); }