public void SelectEdgeTris(int eid) { Index2i et = Mesh.GetEdgeT(eid); add(et.a); if (et.b != DMesh3.InvalidID) { add(et.b); } }
// returns true for both internal and mesh boundary edges // tid_in and tid_out are triangles 'in' and 'out' of set, respectively bool edge_is_boundary(int eid, ref int tid_in, ref int tid_out) { if (edges.Contains(eid) == false) { return(false); } tid_in = tid_out = DMesh3.InvalidID; Index2i et = Mesh.GetEdgeT(eid); if (et.b == DMesh3.InvalidID) // boundary edge! { tid_in = et.a; tid_out = et.b; return(true); } bool in0 = triangles[et.a]; bool in1 = triangles[et.b]; if (in0 != in1) { tid_in = (in0) ? et.a : et.b; tid_out = (in0) ? et.b : et.a; return(true); } return(false); }
/// <summary> /// for each on-edge vtx, we split the edge and then /// re-sort any of the vertices on that edge onto new edges /// </summary> void insert_edge_vertices() { while (EdgeVertices.Count > 0) { var pair = EdgeVertices.First(); int eid = pair.Key; List <SegmentVtx> edgeVerts = pair.Value; SegmentVtx v = edgeVerts[edgeVerts.Count - 1]; edgeVerts.RemoveAt(edgeVerts.Count - 1); Index2i splitTris = Target.GetEdgeT(eid); DMesh3.EdgeSplitInfo splitInfo; MeshResult result = Target.SplitEdge(eid, out splitInfo); if (result != MeshResult.Ok) { throw new Exception("insert_edge_vertices: split failed!"); } int new_v = splitInfo.vNew; var splitEdges = new Index2i(eid, splitInfo.eNewBN); Target.SetVertex(new_v, v.v); v.vtx_id = new_v; VIDToSegVtxMap[v.vtx_id] = v; PointHash.InsertPoint(v.vtx_id, v.v); // remove this triangles vtx list because it is no longer valid EdgeVertices.Remove(eid); // update remaining verts foreach (SegmentVtx sv in edgeVerts) { update_from_split(sv, splitEdges); if (sv.type == 1) { add_edge_vtx(sv.elem_id, sv); } } // track subfaces add_split_subfaces(splitTris, ref splitInfo); } }
public static double OpeningAngleD(DMesh3 mesh, int eid) { Index2i et = mesh.GetEdgeT(eid); if (et[1] == DMesh3.InvalidID) { return(double.MaxValue); // boundary edge!! } Vector3d n0 = mesh.GetTriNormal(et[0]); Vector3d n1 = mesh.GetTriNormal(et[1]); return(Vector3d.AngleD(n0, n1)); }
public void SelectBoundaryTriEdges(MeshFaceSelection triangles) { foreach (int tid in triangles) { Index3i te = Mesh.GetTriEdges(tid); for (int j = 0; j < 3; ++j) { Index2i et = Mesh.GetEdgeT(te[j]); int other_tid = (et.a == tid) ? et.b : et.a; if (triangles.IsSelected(other_tid) == false) { add(te[j]); } } } }
public void ComputeBoundaryInfo(IEnumerable <int> triangles, int tri_count) { // set of base-mesh triangles that are in submesh IndexFlagSet sub_tris = new IndexFlagSet(BaseMesh.MaxTriangleID, tri_count); foreach (int ti in triangles) { sub_tris[ti] = true; } BaseBorderV = new IndexHashSet(); BaseBorderE = new IndexHashSet(); BaseBoundaryE = new IndexHashSet(); // Iterate through edges in submesh roi on base mesh. If // one of the tris of the edge is not in submesh roi, then this // is a boundary edge. // // (edge iteration via triangle iteration processes each internal edge twice...) foreach (int ti in triangles) { Index3i tedges = BaseMesh.GetTriEdges(ti); for (int j = 0; j < 3; ++j) { int eid = tedges[j]; Index2i tris = BaseMesh.GetEdgeT(eid); if (tris.b == DMesh3.InvalidID || sub_tris[tris.a] != sub_tris[tris.b]) { if (tris.b == DMesh3.InvalidID) { BaseBoundaryE[eid] = true; } else { BaseBorderE[eid] = true; } Index2i ve = BaseMesh.GetEdgeV(eid); BaseBorderV[ve.a] = true; BaseBorderV[ve.b] = true; } } } }
public MeshRegionBoundaryLoops(DMesh3 mesh, int[] RegionTris, bool bAutoCompute = true) { this.Mesh = mesh; // make flag set for included triangles triangles = new IndexFlagSet(mesh.MaxTriangleID, RegionTris.Length); for (int i = 0; i < RegionTris.Length; ++i) { triangles[RegionTris[i]] = true; } // make flag set for included edges // NOTE: this currently processes non-boundary-edges twice. Could // avoid w/ another IndexFlagSet, but the check is inexpensive... edges = new IndexFlagSet(mesh.MaxEdgeID, RegionTris.Length); for (int i = 0; i < RegionTris.Length; ++i) { int tid = RegionTris[i]; Index3i te = Mesh.GetTriEdges(tid); for (int j = 0; j < 3; ++j) { int eid = te[j]; if (!edges.Contains(eid)) { Index2i et = mesh.GetEdgeT(eid); if (et.b == DMesh3.InvalidID || triangles[et.a] != triangles[et.b]) { edges.Add(eid); } } } } if (bAutoCompute) { Compute(); } }
// convert face selection to edge selection. Require at least minCount tris of edge to be selected public MeshEdgeSelection(DMesh3 mesh, MeshFaceSelection convertT, int minCount = 1) : this(mesh) { minCount = MathUtil.Clamp(minCount, 1, 2); if (minCount == 1) { foreach (int tid in convertT) { Index3i te = mesh.GetTriEdges(tid); add(te.a); add(te.b); add(te.c); } } else { foreach (int eid in mesh.EdgeIndices()) { Index2i et = mesh.GetEdgeT(eid); if (convertT.IsSelected(et.a) && convertT.IsSelected(et.b)) { add(eid); } } } }
// insert point at bary_coords inside tid. If point is at vtx, just use that vtx. // If it is on an edge, do an edge split. Otherwise poke face. int insert_corner_from_bary(int iCorner, int tid, Vector3d bary_coords, double bary_tol, double spatial_tol, out bool is_existing_v) { is_existing_v = false; Vector2d vInsert = Curve[iCorner]; Index3i tv = Mesh.GetTriangle(tid); // handle cases where corner is on a vertex int cornerv = -1; if (bary_coords.x > 1 - bary_tol) { cornerv = tv.a; } else if (bary_coords.y > 1 - bary_tol) { cornerv = tv.b; } else if (bary_coords.z > 1 - bary_tol) { cornerv = tv.c; } if (cornerv != -1 && PointF(cornerv).Distance(vInsert) < spatial_tol) { is_existing_v = true; return(cornerv); } // handle cases where corner is on an edge int split_edge = -1; if (bary_coords.x < bary_tol) { split_edge = 1; } else if (bary_coords.y < bary_tol) { split_edge = 2; } else if (bary_coords.z < bary_tol) { split_edge = 0; } if (split_edge >= 0) { int eid = Mesh.GetTriEdge(tid, split_edge); Index2i ev = Mesh.GetEdgeV(eid); Segment2d seg = new Segment2d(PointF(ev.a), PointF(ev.b)); if (seg.DistanceSquared(vInsert) < spatial_tol * spatial_tol) { Index2i et = Mesh.GetEdgeT(eid); spatial_remove_triangles(et.a, et.b); DMesh3.EdgeSplitInfo split_info; MeshResult splitResult = Mesh.SplitEdge(eid, out split_info); if (splitResult != MeshResult.Ok) { throw new Exception("MeshInsertUVPolyCurve.insert_corner_from_bary: edge split failed in case sum==2 - " + splitResult.ToString()); } SetPointF(split_info.vNew, vInsert); spatial_add_triangles(et.a, et.b); spatial_add_triangles(split_info.eNewT2, split_info.eNewT3); return(split_info.vNew); } } spatial_remove_triangle(tid); // otherwise corner is inside triangle DMesh3.PokeTriangleInfo pokeinfo; MeshResult result = Mesh.PokeTriangle(tid, bary_coords, out pokeinfo); if (result != MeshResult.Ok) { throw new Exception("MeshInsertUVPolyCurve.insert_corner_from_bary: face poke failed - " + result.ToString()); } SetPointF(pokeinfo.new_vid, vInsert); spatial_add_triangle(tid); spatial_add_triangle(pokeinfo.new_t1); spatial_add_triangle(pokeinfo.new_t2); return(pokeinfo.new_vid); }
/// <summary> /// Disconnect the given triangles from their neighbours, by duplicating "boundary" vertices, ie /// vertices on edges for which one triangle is in-set and the other is not. /// If bComputeEdgePairs is true, we return list of old/new edge pairs (useful for stitching) /// [TODO] currently boundary-edge behaviour is to *not* duplicate boundary verts /// </summary> public bool SeparateTriangles(IEnumerable <int> triangles, bool bComputeEdgePairs, out List <Index2i> EdgePairs) { HashSet <int> in_set = new HashSet <int>(triangles); Dictionary <int, int> VertexMap = new Dictionary <int, int>(); EdgePairs = null; HashSet <int> edges = null; List <Index2i> OldEdgeVerts = null; if (bComputeEdgePairs) { EdgePairs = new List <Index2i>(); edges = new HashSet <int>(); OldEdgeVerts = new List <Index2i>(); } // duplicate vertices on edges that are on boundary of triangles roi foreach (int tid in triangles) { Index3i te = Mesh.GetTriEdges(tid); for (int j = 0; j < 3; ++j) { Index2i et = Mesh.GetEdgeT(te[j]); // [TODO] what about behavior where we want to also duplicate boundary verts?? if (et.b == DMesh3.InvalidID || (et.a == tid && in_set.Contains(et.b)) || (et.b == tid && in_set.Contains(et.a))) { te[j] = -1; } } for (int j = 0; j < 3; ++j) { if (te[j] == -1) { continue; } Index2i ev = Mesh.GetEdgeV(te[j]); if (VertexMap.ContainsKey(ev.a) == false) { VertexMap[ev.a] = Mesh.AppendVertex(Mesh, ev.a); } if (VertexMap.ContainsKey(ev.b) == false) { VertexMap[ev.b] = Mesh.AppendVertex(Mesh, ev.b); } if (bComputeEdgePairs && edges.Contains(te[j]) == false) { edges.Add(te[j]); OldEdgeVerts.Add(ev); EdgePairs.Add(new Index2i(te[j], -1)); } } } // update triangles foreach (int tid in triangles) { Index3i tv = Mesh.GetTriangle(tid); Index3i tv_new = tv; for (int j = 0; j < 3; ++j) { int newv; if (VertexMap.TryGetValue(tv[j], out newv)) { tv_new[j] = newv; } } if (tv_new != tv) { Mesh.SetTriangle(tid, tv_new); } } if (bComputeEdgePairs) { for (int k = 0; k < EdgePairs.Count; ++k) { Index2i old_ev = OldEdgeVerts[k]; int new_a = VertexMap[old_ev.a]; int new_b = VertexMap[old_ev.b]; int new_eid = Mesh.FindEdge(new_a, new_b); Util.gDevAssert(new_eid != DMesh3.InvalidID); EdgePairs[k] = new Index2i(EdgePairs[k].a, new_eid); } } return(true); }
public bool Insert() { OuterInsert = new MeshInsertUVPolyCurve(Mesh, Polygon.Outer); Util.gDevAssert(OuterInsert.Validate() == ValidationStatus.Ok); bool outerApplyOK = OuterInsert.Apply(); if (outerApplyOK == false || OuterInsert.Loops.Count == 0) { return(false); } if (SimplifyInsertion) { OuterInsert.Simplify(); } HoleInserts = new List <MeshInsertUVPolyCurve>(Polygon.Holes.Count); for (int hi = 0; hi < Polygon.Holes.Count; ++hi) { var insert = new MeshInsertUVPolyCurve(Mesh, Polygon.Holes[hi]); Util.gDevAssert(insert.Validate() == ValidationStatus.Ok); insert.Apply(); if (SimplifyInsertion) { insert.Simplify(); } HoleInserts.Add(insert); } // find a triangle connected to loop that is inside the polygon // [TODO] maybe we could be a bit more robust about this? at least // check if triangle is too degenerate... int seed_tri = -1; EdgeLoop outer_loop = OuterInsert.Loops[0]; for (int i = 0; i < outer_loop.EdgeCount; ++i) { if (!Mesh.IsEdge(outer_loop.Edges[i])) { continue; } Index2i et = Mesh.GetEdgeT(outer_loop.Edges[i]); Vector3d ca = Mesh.GetTriCentroid(et.a); bool in_a = Polygon.Outer.Contains(ca.xy); Vector3d cb = Mesh.GetTriCentroid(et.b); bool in_b = Polygon.Outer.Contains(cb.xy); if (in_a && in_b == false) { seed_tri = et.a; break; } else if (in_b && in_a == false) { seed_tri = et.b; break; } } if (seed_tri == -1) { throw new Exception("MeshPolygonsInserter: could not find seed triangle!"); } // make list of all outer & hole edges InsertedPolygonEdges = new HashSet <int>(outer_loop.Edges); foreach (var insertion in HoleInserts) { foreach (int eid in insertion.Loops[0].Edges) { InsertedPolygonEdges.Add(eid); } } // flood-fill inside loop from seed triangle InteriorTriangles = new MeshFaceSelection(Mesh); InteriorTriangles.FloodFill(seed_tri, null, (eid) => { return(InsertedPolygonEdges.Contains(eid) == false); }); return(true); }
// insert point at bary_coords inside tid. If point is at vtx, just use that vtx. // If it is on an edge, do an edge split. Otherwise poke face. int insert_corner_from_bary(int iCorner, int tid, Vector3d bary_coords, double tol = MathUtil.ZeroTolerance) { Vector2d vInsert = Curve[iCorner]; Index3i tv = Mesh.GetTriangle(tid); // handle cases where corner is on a vertex if (bary_coords.x > 1 - tol) { return(tv.a); } else if (bary_coords.y > 1 - tol) { return(tv.b); } else if (bary_coords.z > 1 - tol) { return(tv.c); } // handle cases where corner is on an edge int split_edge = -1; if (bary_coords.x < tol) { split_edge = 1; } else if (bary_coords.y < tol) { split_edge = 2; } else if (bary_coords.z < tol) { split_edge = 0; } if (split_edge >= 0) { int eid = Mesh.GetTriEdge(tid, split_edge); Index2i ev = Mesh.GetEdgeT(eid); spatial_remove_triangles(ev.a, ev.b); DMesh3.EdgeSplitInfo split_info; MeshResult splitResult = Mesh.SplitEdge(eid, out split_info); if (splitResult != MeshResult.Ok) { throw new Exception("MeshInsertUVPolyCurve.insert_corner_from_bary: edge split failed in case sum==2 - " + splitResult.ToString()); } SetPointF(split_info.vNew, vInsert); spatial_add_triangles(ev.a, ev.b); spatial_add_triangles(split_info.eNewT2, split_info.eNewT3); return(split_info.vNew); } spatial_remove_triangle(tid); // otherwise corner is inside triangle DMesh3.PokeTriangleInfo pokeinfo; MeshResult result = Mesh.PokeTriangle(tid, bary_coords, out pokeinfo); if (result != MeshResult.Ok) { throw new Exception("MeshInsertUVPolyCurve.insert_corner_from_bary: face poke failed - " + result.ToString()); } spatial_add_triangle(tid); spatial_add_triangle(pokeinfo.new_t1); spatial_add_triangle(pokeinfo.new_t2); SetPointF(pokeinfo.new_vid, vInsert); return(pokeinfo.new_vid); }