public MeshResult RemoveEdge(int eID, bool bRemoveIsolatedVertices) { if (!edges_refcount.isValid(eID)) { Util.gDevAssert(false); return(MeshResult.Failed_NotAnEdge); } int i = 3 * eID; var ev = new Index2i(edges[i], edges[i + 1]); vertex_edges[ev.a].Remove(eID); vertex_edges[ev.b].Remove(eID); edges_refcount.decrement(eID); // Decrement vertex refcounts. If any hit 1 and we got remove-isolated flag, // we need to remove that vertex for (int j = 0; j < 2; ++j) { int vid = ev[j]; vertices_refcount.decrement(vid); if (bRemoveIsolatedVertices && vertices_refcount.refCount(vid) == 1) { vertices_refcount.decrement(vid); Util.gDevAssert(vertices_refcount.isValid(vid) == false); vertex_edges[vid] = null; } } updateTimeStamp(true); return(MeshResult.Ok); }
public virtual void MakeMesh(NTMesh3 m) { int nV = vertices.Count; for (int i = 0; i < nV; ++i) { int vID = m.AppendVertex(vertices[i]); Util.gDevAssert(vID == i); } int nT = triangles.Count; if (WantGroups && groups != null && groups.Length == nT) { m.EnableTriangleGroups(); for (int i = 0; i < nT; ++i) { m.AppendTriangle(triangles[i], groups[i]); } } else { for (int i = 0; i < nT; ++i) { m.AppendTriangle(triangles[i]); } } }
public int AppendEdge(Index2i ev, int gid = -1) { if (IsVertex(ev[0]) == false || IsVertex(ev[1]) == false) { Util.gDevAssert(false); return(InvalidID); } if (ev[0] == ev[1]) { Util.gDevAssert(false); return(InvalidID); } int e0 = FindEdge(ev[0], ev[1]); if (e0 != InvalidID) { return(DuplicateEdgeID); } // increment ref counts and update/create edges vertices_refcount.increment(ev[0]); vertices_refcount.increment(ev[1]); max_group_id = Math.Max(max_group_id, gid + 1); // now safe to insert edge int eid = add_edge(ev[0], ev[1], gid); updateTimeStamp(true); return(eid); }
public void InitializeFromExisting(DMesh3 mesh, IEnumerable <int> added_v, IEnumerable <int> added_t) { initialize_buffers(mesh); bool has_groups = mesh.HasTriangleGroups; if (added_v != null) { foreach (int vid in added_v) { Util.gDevAssert(mesh.IsVertex(vid)); append_vertex(mesh, vid); } } foreach (int tid in added_t) { Util.gDevAssert(mesh.IsTriangle(tid)); Index3i tv = mesh.GetTriangle(tid); Index4i tri = new Index4i(tv.a, tv.b, tv.c, has_groups ? mesh.GetTriangleGroup(tid) : DMesh3.InvalidID); AddedT.Add(tid); Triangles.Add(tri); } }
void update_uv_upwind_expmap(GraphNode node) { int vid = node.id; Vector3f pos = PositionF(vid); Vector2f avg_uv = Vector2f.Zero; float fWeightSum = 0; int nbr_count = 0; foreach (var nbr_id in NeighboursF(node.id)) { GraphNode nbr_node = get_node(nbr_id, false); if (nbr_node.frozen) { Vector3f nbr_pos = PositionF(nbr_id); Frame3f nbr_frame = new Frame3f(nbr_pos, NormalF(nbr_id)); Vector2f nbr_uv = propagate_uv(pos, nbr_node.uv, ref nbr_frame, ref SeedFrame); float fWeight = 1.0f / (pos.DistanceSquared(nbr_pos) + MathUtil.ZeroTolerancef); avg_uv += fWeight * nbr_uv; fWeightSum += fWeight; nbr_count++; } } Util.gDevAssert(nbr_count > 0); //avg_uv /= (float)nbr_count; avg_uv /= fWeightSum; node.uv = avg_uv; }
public static Polygon2d SplitToTargetLength(Polygon2d poly, double length) { Polygon2d result = new Polygon2d(); result.AppendVertex(poly[0]); for (int j = 0; j < poly.VertexCount; ++j) { int next = (j + 1) % poly.VertexCount; double len = poly[j].Distance(poly[next]); if (len < length) { result.AppendVertex(poly[next]); continue; } int steps = (int)Math.Ceiling(len / length); for (int k = 1; k < steps; ++k) { double t = (double)(k) / (double)steps; Vector2d v = (1.0 - t) * poly[j] + (t) * poly[next]; result.AppendVertex(v); } if (j < poly.VertexCount - 1) { Util.gDevAssert(poly[j].Distance(result.Vertices[result.VertexCount - 1]) > 0.0001); result.AppendVertex(poly[next]); } } return(result); }
public void MakeMesh(DMesh3 m) { int nV = vertices.Count; for (int i = 0; i < nV; ++i) { NewVertexInfo ni = new NewVertexInfo() { v = vertices[i] }; if ( WantNormals ) { ni.bHaveN = true; ni.n = normals[i]; } if ( WantUVs ) { ni.bHaveUV = true; ni.uv = uv[i]; } int vID = m.AppendVertex(ni); Util.gDevAssert(vID == i); } int nT = triangles.Count; if (WantGroups && groups != null && groups.Length == nT) { for (int i = 0; i < nT; ++i) m.AppendTriangle(triangles[i], groups[i]); } else { for (int i = 0; i < nT; ++i) m.AppendTriangle(triangles[i]); } }
public void Initialize(DMesh3 mesh, IEnumerable <int> triangles) { initialize_buffers(mesh); bool has_groups = mesh.HasTriangleGroups; foreach (int tid in triangles) { if (!mesh.IsTriangle(tid)) { continue; } Index3i tv = mesh.GetTriangle(tid); bool va = save_vertex(mesh, tv.a); bool vb = save_vertex(mesh, tv.b); bool vc = save_vertex(mesh, tv.c); Index4i tri = new Index4i(tv.a, tv.b, tv.c, has_groups ? mesh.GetTriangleGroup(tid) : DMesh3.InvalidID); RemovedT.Add(tid); Triangles.Add(tri); MeshResult result = mesh.RemoveTriangle(tid, true, false); if (result != MeshResult.Ok) { throw new Exception("RemoveTrianglesMeshChange.Initialize: exception in RemoveTriangle(" + tid.ToString() + "): " + result.ToString()); } Util.gDevAssert(mesh.IsVertex(tv.a) == va && mesh.IsVertex(tv.b) == vb && mesh.IsVertex(tv.c) == vc); } }
/// <summary> /// if before a flip we have normals (n1,n2) and after we have (m1,m2), check if /// the dot between any of the 4 pairs changes sign after the flip, or is /// less than the dot-product tolerance (ie angle tolerance) /// </summary> public static bool CheckIfEdgeFlipCreatesFlip(DMesh3 mesh, int eID, double flip_dot_tol = 0.0) { Util.gDevAssert(mesh.IsBoundaryEdge(eID) == false); Index4i einfo = mesh.GetEdge(eID); Index2i ov = mesh.GetEdgeOpposingV(eID); int a = einfo.a, b = einfo.b, c = ov.a, d = ov.b; int t0 = einfo.c; Vector3d vC = mesh.GetVertex(c), vD = mesh.GetVertex(d); Index3i tri_v = mesh.GetTriangle(t0); int oa = a, ob = b; IndexUtil.orient_tri_edge(ref oa, ref ob, ref tri_v); Vector3d vOA = mesh.GetVertex(oa), vOB = mesh.GetVertex(ob); Vector3d n0 = MathUtil.FastNormalDirection(ref vOA, ref vOB, ref vC); Vector3d n1 = MathUtil.FastNormalDirection(ref vOB, ref vOA, ref vD); Vector3d f0 = MathUtil.FastNormalDirection(ref vC, ref vD, ref vOB); if (edge_flip_metric(ref n0, ref f0, flip_dot_tol) <= flip_dot_tol || edge_flip_metric(ref n1, ref f0, flip_dot_tol) <= flip_dot_tol) { return(true); } Vector3d f1 = MathUtil.FastNormalDirection(ref vD, ref vC, ref vOA); if (edge_flip_metric(ref n0, ref f1, flip_dot_tol) <= flip_dot_tol || edge_flip_metric(ref n1, ref f1, flip_dot_tol) <= flip_dot_tol) { return(true); } return(false); }
public void swap(DenseGrid3f g2) { Util.gDevAssert(ni == g2.ni && nj == g2.nj && nk == g2.nk); var tmp = g2.Buffer; g2.Buffer = this.Buffer; this.Buffer = tmp; }
public int increment(int index, short increment = 1) { Util.gDevAssert(isValid(index)); // debug check for overflow... Util.gDevAssert((short)(ref_counts[index] + increment) > 0); ref_counts[index] += increment; return(ref_counts[index]); }
public virtual void MakeMesh(DMesh3 m) { int nV = vertices.Count; bool bWantNormals = WantNormals && normals != null && normals.Count == vertices.Count; if (bWantNormals) { m.EnableVertexNormals(Vector3f.AxisY); } bool bWantUVs = WantUVs && uv != null && uv.Count == vertices.Count; if (bWantUVs) { m.EnableVertexUVs(Vector2f.Zero); } for (int i = 0; i < nV; ++i) { var ni = new NewVertexInfo() { v = vertices[i] }; if (bWantNormals) { ni.bHaveN = true; ni.n = normals[i]; } if (bWantUVs) { ni.bHaveUV = true; ni.uv = uv[i]; } int vID = m.AppendVertex(ni); Util.gDevAssert(vID == i); } int nT = triangles.Count; if (WantGroups && groups != null && groups.Length == nT) { m.EnableTriangleGroups(); for (int i = 0; i < nT; ++i) { m.AppendTriangle(triangles[i], groups[i]); } } else { for (int i = 0; i < nT; ++i) { m.AppendTriangle(triangles[i]); } } }
void find_cut_paths(HashSet <int> CutEdges) { Spans = new List <EdgeSpan>(); Loops = new List <EdgeLoop>(); // [TODO] what about if vert appears more than twice in list? we should check for that! var Remaining = new HashSet <int>(CutEdges); while (Remaining.Count > 0) { int start_edge = Remaining.First(); Remaining.Remove(start_edge); Index2i start_edge_v = Mesh.GetEdgeV(start_edge); bool isLoop; List <int> forwardSpan = walk_edge_span_forward(Mesh, start_edge, start_edge_v.a, Remaining, out isLoop); if (isLoop == false) { List <int> backwardSpan = walk_edge_span_forward(Mesh, start_edge, start_edge_v.b, Remaining, out isLoop); if (isLoop) { throw new Exception("find_cut_paths: how did this possibly happen?!?"); } if (backwardSpan.Count > 1) { backwardSpan.Reverse(); backwardSpan.RemoveAt(backwardSpan.Count - 1); backwardSpan.AddRange(forwardSpan); Index2i start_ev = Mesh.GetEdgeV(backwardSpan[0]); Index2i end_ev = Mesh.GetEdgeV(backwardSpan[backwardSpan.Count - 1]); // [RMS] >2 check here catches two-edge span case, where we do have shared vert but // can never be loop unless we have duplicate edge (!) isLoop = backwardSpan.Count > 2 && IndexUtil.find_shared_edge_v(ref start_ev, ref end_ev) != DMesh3.InvalidID; forwardSpan = backwardSpan; } } if (isLoop) { var loop = EdgeLoop.FromEdges(Mesh, forwardSpan); Util.gDevAssert(loop.CheckValidity()); Loops.Add(loop); } else { var span = EdgeSpan.FromEdges(Mesh, forwardSpan); Util.gDevAssert(span.CheckValidity()); Spans.Add(span); } } }
// compute FWN cache for all points underneath this box protected void make_box_fast_winding_cache(int iBox, IEnumerable <int> pointIndices) { Util.gDevAssert(FastWindingCache.ContainsKey(iBox) == false); // construct cache var cacheInfo = new FWNInfo(); FastPointWinding.ComputeCoeffs(points, pointIndices, FastWindingAreaCache, ref cacheInfo.Center, ref cacheInfo.R, ref cacheInfo.Order1Vec, ref cacheInfo.Order2Mat); FastWindingCache[iBox] = cacheInfo; }
public void decrement(int index, short decrement = 1) { Util.gDevAssert(isValid(index)); ref_counts[index] -= decrement; Util.gDevAssert(ref_counts[index] >= 0); if (ref_counts[index] == 0) { free_indices.push_back(index); ref_counts[index] = invalid; used_count--; } }
/// <summary> /// Exhaustively check that verts and edges of this EdgeSpan are consistent. Not for production use. /// </summary> public bool CheckValidity(FailMode eFailMode = FailMode.Throw) { bool is_ok = true; Action <bool> CheckOrFailF = (b) => { is_ok = is_ok && b; }; if (eFailMode == FailMode.DebugAssert) { CheckOrFailF = (b) => { Debug.Assert(b); is_ok = is_ok && b; }; } else if (eFailMode == FailMode.gDevAssert) { CheckOrFailF = (b) => { Util.gDevAssert(b); is_ok = is_ok && b; }; } else if (eFailMode == FailMode.Throw) { CheckOrFailF = (b) => { if (b == false) { throw new Exception("EdgeSpan.CheckValidity: check failed"); } }; } CheckOrFailF(Vertices.Length == Edges.Length + 1); for (int ei = 0; ei < Edges.Length; ++ei) { Index2i ev = Mesh.GetEdgeV(Edges[ei]); CheckOrFailF(Mesh.IsVertex(ev.a)); CheckOrFailF(Mesh.IsVertex(ev.b)); CheckOrFailF(Mesh.FindEdge(ev.a, ev.b) != DMesh3.InvalidID); CheckOrFailF(Vertices[ei] == ev.a || Vertices[ei] == ev.b); CheckOrFailF(Vertices[ei + 1] == ev.a || Vertices[ei + 1] == ev.b); } for (int vi = 0; vi < Vertices.Length - 1; ++vi) { int a = Vertices[vi], b = Vertices[vi + 1]; CheckOrFailF(Mesh.IsVertex(a)); CheckOrFailF(Mesh.IsVertex(b)); CheckOrFailF(Mesh.FindEdge(a, b) != DMesh3.InvalidID); if (vi < Vertices.Length - 2) { int n = 0, edge_before_b = Edges[vi], edge_after_b = Edges[vi + 1]; foreach (int nbr_e in Mesh.VtxEdgesItr(b)) { if (nbr_e == edge_before_b || nbr_e == edge_after_b) { n++; } } CheckOrFailF(n == 2); } } return(true); }
void update_uv_expmap(GraphNode node) { int vid = node.id; Util.gDevAssert(node.parent != null && node.parent.frozen == true); int parent_id = node.parent.id; Vector3f parentPos = PositionF(parent_id); Frame3f parentFrame = new Frame3f(parentPos, NormalF(parent_id)); node.uv = propagate_uv(PositionF(vid), node.parent.uv, ref parentFrame, ref SeedFrame); }
/// <summary> /// Compute i'th spherical point /// </summary> public Vector3d Point(int i) { Util.gDevAssert(i < N); double div = (double)i / PHI; double phi = MathUtil.TwoPI * (div - Math.Floor(div)); double cos_phi = Math.Cos(phi), sin_phi = Math.Sin(phi); double z = 1.0 - (2.0 * (double)i + 1.0) / (double)N; double theta = Math.Acos(z); double sin_theta = Math.Sin(theta); return(new Vector3d(cos_phi * sin_theta, sin_phi * sin_theta, z)); }
public int AppendTriangle(Index3i tv, int gid = -1) { if (IsVertex(tv[0]) == false || IsVertex(tv[1]) == false || IsVertex(tv[2]) == false) { Util.gDevAssert(false); return(InvalidID); } if (tv[0] == tv[1] || tv[0] == tv[2] || tv[1] == tv[2]) { Util.gDevAssert(false); return(InvalidID); } // look up edges. if any already have two triangles, this would // create non-manifold geometry and so we do not allow it int e0 = find_edge(tv[0], tv[1]); int e1 = find_edge(tv[1], tv[2]); int e2 = find_edge(tv[2], tv[0]); if ((e0 != InvalidID && edge_is_boundary(e0) == false) || (e1 != InvalidID && edge_is_boundary(e1) == false) || (e2 != InvalidID && edge_is_boundary(e2) == false)) { return(NonManifoldID); } // now safe to insert triangle int tid = triangles_refcount.allocate(); int i = 3 * tid; triangles.insert(tv[2], i + 2); triangles.insert(tv[1], i + 1); triangles.insert(tv[0], i); if (triangle_groups != null) { triangle_groups.insert(gid, tid); } // increment ref counts and update/create edges vertices_refcount.increment(tv[0]); vertices_refcount.increment(tv[1]); vertices_refcount.increment(tv[2]); add_tri_edge(tid, tv[0], tv[1], 0, e0); add_tri_edge(tid, tv[1], tv[2], 1, e1); add_tri_edge(tid, tv[2], tv[0], 2, e2); updateTimeStamp(); return(tid); }
void resolve_vtx_pairs() { //HashSet<int> targetVerts = new HashSet<int>(cutTargetOp.CutVertices); //HashSet<int> toolVerts = new HashSet<int>(cutToolOp.CutVertices); // tracking on-cut vertices is not working yet... Util.gDevAssert(Target.IsClosed() && Tool.IsClosed()); HashSet <int> targetVerts = new HashSet <int>(MeshIterators.BoundaryVertices(cutTargetMesh)); HashSet <int> toolVerts = new HashSet <int>(MeshIterators.BoundaryVertices(cutToolMesh)); split_missing(cutTargetOp, cutToolOp, cutTargetMesh, cutToolMesh, targetVerts, toolVerts); split_missing(cutToolOp, cutTargetOp, cutToolMesh, cutTargetMesh, toolVerts, targetVerts); }
/// <summary> /// Move point from old to new position. This function is thread-safe, uses a SpinLock internally /// </summary> public void UpdatePoint(T value, Vector3d old_pos, Vector3d new_pos) { Vector3i old_idx = Indexer.ToGrid(old_pos); Vector3i new_idx = Indexer.ToGrid(new_pos); if (old_idx == new_idx) { return; } bool ok = remove_point(value, old_idx); Util.gDevAssert(ok); insert_point(value, new_idx); return; }
protected int on_edge_eid(int tid, Vector3d v) { Index3i tv = Target.GetTriangle(tid); Triangle3d tri = new Triangle3d(); Target.GetTriVertices(tid, ref tri.V0, ref tri.V1, ref tri.V2); int eidx = on_edge(ref tri, ref v); if (eidx < 0) { return(DMesh3.InvalidID); } int eid = Target.FindEdge(tv[eidx], tv[(eidx + 1) % 3]); Util.gDevAssert(eid != DMesh3.InvalidID); return(eid); }
/// <summary> /// DGraph3 edges are not oriented, which means they cannot inherit orientation from mesh. /// This function returns true if, for a given graph_eid, the vertex pair returned by /// Graph.GetEdgeV(graph_eid) should be reversed to be consistent with mesh orientation. /// Mainly inteded to be passed to DGraph3Util.ExtractCurves /// </summary> public bool ShouldReverseGraphEdge(int graph_eid) { if (GraphEdges == null) { throw new Exception("MeshIsoCurves.OrientEdge: must track edge graph info to orient edge"); } Index2i graph_ev = Graph.GetEdgeV(graph_eid); GraphEdgeInfo einfo = GraphEdges[graph_eid]; if (graph_ev.b == einfo.order.a && graph_ev.a == einfo.order.b) { return(true); } Util.gDevAssert(graph_ev.a == einfo.order.a && graph_ev.b == einfo.order.b); return(false); }
public void InitializeFromExisting(DMesh3 mesh, IEnumerable <int> remove_t) { initialize_buffers(mesh); bool has_groups = mesh.HasTriangleGroups; HashSet <int> triangles = new HashSet <int>(remove_t); HashSet <int> vertices = new HashSet <int>(); IndexUtil.TrianglesToVertices(mesh, remove_t, vertices); List <int> save_v = new List <int>(); foreach (int vid in vertices) { bool all_contained = true; foreach (int tid in mesh.VtxTrianglesItr(vid)) { if (triangles.Contains(tid) == false) { all_contained = false; break; } } if (all_contained) { save_v.Add(vid); } } foreach (int vid in save_v) { save_vertex(mesh, vid, true); } foreach (int tid in remove_t) { Util.gDevAssert(mesh.IsTriangle(tid)); Index3i tv = mesh.GetTriangle(tid); Index4i tri = new Index4i(tv.a, tv.b, tv.c, has_groups ? mesh.GetTriangleGroup(tid) : DMesh3.InvalidID); RemovedT.Add(tid); Triangles.Add(tri); } }
/// <summary> /// Move segment from old to new position. This function is thread-safe, uses a SpinLock internally /// </summary> public void UpdateSegment(T value, Vector2d old_center, Vector2d new_center, double new_extent) { if (new_extent > MaxExtent) { MaxExtent = new_extent; } Vector2i old_idx = Indexer.ToGrid(old_center); Vector2i new_idx = Indexer.ToGrid(new_center); if (old_idx == new_idx) { return; } bool ok = remove_segment(value, old_idx); Util.gDevAssert(ok); insert_segment(value, new_idx); return; }
/// <summary> /// Apply transforms to normalized vector /// </summary> public Vector2d TransformN(Vector2d n) { int N = Operations.Count; for (int i = 0; i < N; ++i) { switch (Operations[i].type) { case XFormType.Translation: break; case XFormType.Rotation: n = Operations[i].Rotation * n; break; case XFormType.RotateAroundPoint: n = Operations[i].Rotation * n; break; case XFormType.Scale: Util.gDevAssert(Operations[i].ScaleIsUniform); n *= Operations[i].Scale; break; case XFormType.ScaleAroundPoint: Util.gDevAssert(Operations[i].ScaleIsUniform); n *= Operations[i].Scale; break; case XFormType.NestedITransform2: n = Operations[i].NestedITransform2.TransformN(n); break; default: throw new NotImplementedException("TransformSequence.TransformN: unhandled type!"); } } return(n); }
void sanity_check() { if (Quantity == 0) { Util.gDevAssert(Type == IntersectionType.Empty); Util.gDevAssert(Result == IntersectionResult.NoIntersection); } else if (Quantity == 1) { Util.gDevAssert(Type == IntersectionType.Point); Util.gDevAssert(segment1.DistanceSquared(Point0) < MathUtil.ZeroTolerance); Util.gDevAssert(segment2.DistanceSquared(Point0) < MathUtil.ZeroTolerance); } else if (Quantity == 2) { Util.gDevAssert(Type == IntersectionType.Segment); Util.gDevAssert(segment1.DistanceSquared(Point0) < MathUtil.ZeroTolerance); Util.gDevAssert(segment1.DistanceSquared(Point1) < MathUtil.ZeroTolerance); Util.gDevAssert(segment2.DistanceSquared(Point0) < MathUtil.ZeroTolerance); Util.gDevAssert(segment2.DistanceSquared(Point1) < MathUtil.ZeroTolerance); } }
/// <summary> /// Apply transforms to scalar dimension /// </summary> public double TransformScalar(double s) { int N = Operations.Count; for (int i = 0; i < N; ++i) { switch (Operations[i].type) { case XFormType.Translation: break; case XFormType.Rotation: break; case XFormType.RotateAroundPoint: break; case XFormType.Scale: Util.gDevAssert(Operations[i].ScaleIsUniform); s *= Operations[i].Scale.x; break; case XFormType.ScaleAroundPoint: Util.gDevAssert(Operations[i].ScaleIsUniform); s *= Operations[i].Scale.x; break; case XFormType.NestedITransform2: s = Operations[i].NestedITransform2.TransformScalar(s); break; default: throw new NotImplementedException("TransformSequence.TransformScalar: unhandled type!"); } } return(s); }
/// <summary> /// 1) Find intersection segments /// 2) sort onto existing input mesh vtx/edge/face /// </summary> void find_segments() { Dictionary <Vector3d, SegmentVtx> SegVtxMap = new Dictionary <Vector3d, SegmentVtx>(); // find intersection segments // TODO: intersection polygons // TODO: do we need to care about intersection vertices? DMeshAABBTree3 targetSpatial = new DMeshAABBTree3(Target, true); DMeshAABBTree3 cutSpatial = new DMeshAABBTree3(CutMesh, true); var intersections = targetSpatial.FindAllIntersections(cutSpatial); // for each segment, for each vtx, determine if it is // at an existing vertex, on-edge, or in-face Segments = new IntersectSegment[intersections.Segments.Count]; for (int i = 0; i < Segments.Length; ++i) { var isect = intersections.Segments[i]; Vector3dTuple2 points = new Vector3dTuple2(isect.point0, isect.point1); IntersectSegment iseg = new IntersectSegment() { base_tid = isect.t0 }; Segments[i] = iseg; for (int j = 0; j < 2; ++j) { Vector3d v = points[j]; // if this exact vtx coord has been seen, use same vtx SegmentVtx sv; if (SegVtxMap.TryGetValue(v, out sv)) { iseg[j] = sv; continue; } sv = new SegmentVtx() { v = v }; SegVertices.Add(sv); SegVtxMap[v] = sv; iseg[j] = sv; // this vtx is tol-equal to input mesh vtx int existing_v = find_existing_vertex(isect.point0); if (existing_v >= 0) { sv.initial_type = sv.type = 0; sv.elem_id = existing_v; sv.vtx_id = existing_v; VIDToSegVtxMap[sv.vtx_id] = sv; continue; } Triangle3d tri = new Triangle3d(); Target.GetTriVertices(isect.t0, ref tri.V0, ref tri.V1, ref tri.V2); Index3i tv = Target.GetTriangle(isect.t0); // this vtx is tol-on input mesh edge int on_edge_i = on_edge(ref tri, ref v); if (on_edge_i >= 0) { sv.initial_type = sv.type = 1; sv.elem_id = Target.FindEdge(tv[on_edge_i], tv[(on_edge_i + 1) % 3]); Util.gDevAssert(sv.elem_id != DMesh3.InvalidID); add_edge_vtx(sv.elem_id, sv); continue; } // otherwise contained in input mesh face sv.initial_type = sv.type = 2; sv.elem_id = isect.t0; add_face_vtx(sv.elem_id, sv); } } }
public LaplacianMeshSmoother(DMesh3 mesh) { Mesh = mesh; Util.gDevAssert(mesh.IsCompact); }