Esempio n. 1
0
        // smooths embedded loop in mesh, by first smoothing edge loop and then
        // smoothing vertex neighbourhood
        // [TODO] geodesic nbrhoold instead of # of rings
        // [TODO] reprojection?
        public static void smooth_loop(DMesh3 mesh, EdgeLoop loop, int nRings)
        {
            MeshFaceSelection roi_t = new MeshFaceSelection(mesh);

            roi_t.SelectVertexOneRings(loop.Vertices);
            for (int i = 0; i < nRings; ++i)
            {
                roi_t.ExpandToOneRingNeighbours();
            }
            roi_t.LocalOptimize(true, true);

            MeshVertexSelection roi_v = new MeshVertexSelection(mesh);

            roi_v.SelectTriangleVertices(roi_t.ToArray());
            roi_v.Deselect(loop.Vertices);

            MeshLoopSmooth loop_smooth = new MeshLoopSmooth(mesh, loop);

            loop_smooth.Rounds = 1;

            MeshIterativeSmooth mesh_smooth = new MeshIterativeSmooth(mesh, roi_v.ToArray(), true);

            mesh_smooth.Rounds = 1;

            for (int i = 0; i < 10; ++i)
            {
                loop_smooth.Smooth();
                mesh_smooth.Smooth();
            }
        }
        // convert vertex selection to face selection. Require at least minCount verts of
        // tri to be selected (valid values are 1,2,3)
        public MeshFaceSelection(DMesh3 mesh, MeshVertexSelection convertV, int minCount = 3) : this(mesh)
        {
            minCount = MathUtil.Clamp(minCount, 1, 3);

            foreach (int tid in mesh.TriangleIndices())
            {
                Index3i tri = mesh.GetTriangle(tid);

                if (minCount == 1)
                {
                    if (convertV.IsSelected(tri.a) || convertV.IsSelected(tri.b) || convertV.IsSelected(tri.c))
                    {
                        add(tid);
                    }
                }
                else if (minCount == 3)
                {
                    if (convertV.IsSelected(tri.a) && convertV.IsSelected(tri.b) && convertV.IsSelected(tri.c))
                    {
                        add(tid);
                    }
                }
                else
                {
                    int n = (convertV.IsSelected(tri.a) ? 1 : 0) +
                            (convertV.IsSelected(tri.b) ? 1 : 0) +
                            (convertV.IsSelected(tri.c) ? 1 : 0);
                    if (n >= minCount)
                    {
                        add(tid);
                    }
                }
            }
        }
Esempio n. 3
0
        protected override void begin_smooth()
        {
            base.begin_smooth();

            if (LocalSmoothingRings > 0)
            {
                smoothV.Clear();
                if (LocalSmoothingRings == 1)
                {
                    for (int i = 0; i < CurrentLoopV.Count; ++i)
                    {
                        smoothV.Add(CurrentLoopV[i]);
                        foreach (int nbrv in mesh.VtxVerticesItr(CurrentLoopV[i]))
                        {
                            smoothV.Add(nbrv);
                        }
                    }
                }
                else
                {
                    MeshVertexSelection select = new MeshVertexSelection(mesh);
                    select.Select(CurrentLoopV);
                    select.ExpandToOneRingNeighbours(LocalSmoothingRings);
                    foreach (int vid in select)
                    {
                        smoothV.Add(vid);
                    }
                }
            }
        }
Esempio n. 4
0
        void insert_segment(IntersectSegment seg)
        {
            List <int> subfaces = get_all_baseface_tris(seg.base_tid);

            var op = new RegionOperator(Target, subfaces);

            Vector3d n = BaseFaceNormals[seg.base_tid];
            Vector3d c = BaseFaceCentroids[seg.base_tid];
            Vector3d e0, e1;

            Vector3d.MakePerpVectors(ref n, out e0, out e1);

            DMesh3 mesh = op.Region.SubMesh;

            MeshTransforms.PerVertexTransform(mesh, (v) =>
            {
                v -= c;
                return(new Vector3d(v.Dot(e0), v.Dot(e1), 0));
            });

            Vector3d end0 = seg.v0.v, end1 = seg.v1.v;

            end0 -= c; end1 -= c;
            var p0   = new Vector2d(end0.Dot(e0), end0.Dot(e1));
            var p1   = new Vector2d(end1.Dot(e0), end1.Dot(e1));
            var path = new PolyLine2d();

            path.AppendVertex(p0); path.AppendVertex(p1);

            var insert = new MeshInsertUVPolyCurve(mesh, path);

            insert.Apply();

            var cutVerts = new MeshVertexSelection(mesh);

            cutVerts.SelectEdgeVertices(insert.OnCutEdges);

            MeshTransforms.PerVertexTransform(mesh, (v) =>
            {
                return(c + v.x * e0 + v.y * e1);
            });

            op.BackPropropagate();

            // add new cut vertices to cut list
            foreach (int vid in cutVerts)
            {
                SegmentInsertVertices.Add(op.ReinsertSubToBaseMapV[vid]);
            }

            add_regionop_subfaces(seg.base_tid, op);
        }
Esempio n. 5
0
        // convert vertex selection to edge selection. Require at least minCount verts of edge to be selected
        public MeshEdgeSelection(DMesh3 mesh, MeshVertexSelection convertV, int minCount = 2) : this(mesh)
        {
            minCount = MathUtil.Clamp(minCount, 1, 2);

            // [TODO] if minCount == 1, and convertV is small, it is faster to iterate over convertV!!

            foreach (int eid in mesh.EdgeIndices())
            {
                Index2i ev = mesh.GetEdgeV(eid);
                int     n  = (convertV.IsSelected(ev.a) ? 1 : 0) +
                             (convertV.IsSelected(ev.b) ? 1 : 0);
                if (n >= minCount)
                {
                    add(eid);
                }
            }
        }
Esempio n. 6
0
        // local mesh smooth applied to all vertices in N-rings around input list
        public static void smooth_region(DMesh3 mesh, IEnumerable <int> vertices, int nRings)
        {
            MeshFaceSelection roi_t = new MeshFaceSelection(mesh);

            roi_t.SelectVertexOneRings(vertices);
            for (int i = 0; i < nRings; ++i)
            {
                roi_t.ExpandToOneRingNeighbours();
            }
            roi_t.LocalOptimize(true, true);

            MeshVertexSelection roi_v = new MeshVertexSelection(mesh);

            roi_v.SelectTriangleVertices(roi_t.ToArray());

            MeshIterativeSmooth mesh_smooth = new MeshIterativeSmooth(mesh, roi_v.ToArray(), true);

            mesh_smooth.Alpha  = 0.2f;
            mesh_smooth.Rounds = 10;
            mesh_smooth.Smooth();
        }
Esempio n. 7
0
        public virtual bool Extrude()
        {
            MeshEditor editor = new MeshEditor(Mesh);


            editor.SeparateTriangles(Triangles, true, out EdgePairs);

            MeshNormals normals      = null;
            bool        bHaveNormals = Mesh.HasVertexNormals;

            if (!bHaveNormals)
            {
                normals = new MeshNormals(Mesh);
                normals.Compute();
            }

            ExtrudeVertices = new MeshVertexSelection(Mesh);
            ExtrudeVertices.SelectTriangleVertices(Triangles);

            Vector3d[] NewVertices = new Vector3d[ExtrudeVertices.Count];
            int        k           = 0;

            foreach (int vid in ExtrudeVertices)
            {
                Vector3d v = Mesh.GetVertex(vid);
                Vector3f n = (bHaveNormals) ? Mesh.GetVertexNormal(vid) : (Vector3f)normals.Normals[vid];
                NewVertices[k++] = ExtrudedPositionF(v, n, vid);
            }
            k = 0;
            foreach (int vid in ExtrudeVertices)
            {
                Mesh.SetVertex(vid, NewVertices[k++]);
            }

            SetGroupID    = Group.GetGroupID(Mesh);
            JoinTriangles = editor.StitchUnorderedEdges(EdgePairs, SetGroupID);

            return(true);
        }
Esempio n. 8
0
        protected bool check_for_cracks(DMesh3 mesh, out int boundary_edge_count, double crack_tol = MathUtil.ZeroTolerancef)
        {
            boundary_edge_count = 0;
            var boundary_verts = new MeshVertexSelection(mesh);

            foreach (int eid in mesh.BoundaryEdgeIndices())
            {
                Index2i ev = mesh.GetEdgeV(eid);
                boundary_verts.Select(ev.a); boundary_verts.Select(ev.b);
                boundary_edge_count++;
            }
            if (boundary_verts.Count == 0)
            {
                return(false);
            }

            AxisAlignedBox3d bounds = mesh.CachedBounds;
            var borderV             = new PointHashGrid3d <int>(bounds.MaxDim / 128, -1);

            foreach (int vid in boundary_verts)
            {
                Vector3d v      = mesh.GetVertex(vid);
                var      result = borderV.FindNearestInRadius(v, crack_tol, (existing_vid) =>
                {
                    return(v.Distance(mesh.GetVertex(existing_vid)));
                });
                if (result.Key != -1)
                {
                    return(true);                               // we found a crack vertex!
                }

                borderV.InsertPoint(vid, v);
            }

            // found no cracks
            return(false);
        }
Esempio n. 9
0
        protected void compute_full(IEnumerable <int> Triangles, bool bIsFullMeshHint = false)
        {
            Graph = new DGraph3();
            if (WantGraphEdgeInfo)
            {
                GraphEdges = new DVector <GraphEdgeInfo>();
            }

            Vertices = new Dictionary <Vector3d, int>();


            // multithreaded precomputation of per-vertex values
            double[] vertex_values = null;
            if (PrecomputeVertexValues)
            {
                vertex_values = new double[Mesh.MaxVertexID];
                IEnumerable <int> verts = Mesh.VertexIndices();
                if (bIsFullMeshHint == false)
                {
                    MeshVertexSelection vertices = new MeshVertexSelection(Mesh);
                    vertices.SelectTriangleVertices(Triangles);
                    verts = vertices;
                }
                gParallel.ForEach(verts, (vid) => {
                    vertex_values[vid] = ValueF(Mesh.GetVertex(vid));
                });
                VertexValueF = (vid) => { return(vertex_values[vid]); };
            }


            foreach (int tid in Triangles)
            {
                Vector3dTuple3 tv = new Vector3dTuple3();
                Mesh.GetTriVertices(tid, ref tv.V0, ref tv.V1, ref tv.V2);
                Index3i triVerts = Mesh.GetTriangle(tid);

                Vector3d f = (VertexValueF != null) ?
                             new Vector3d(VertexValueF(triVerts.a), VertexValueF(triVerts.b), VertexValueF(triVerts.c))
                    : new Vector3d(ValueF(tv.V0), ValueF(tv.V1), ValueF(tv.V2));

                // round f to 0 within epsilon?

                if (f.x < 0 && f.y < 0 && f.z < 0)
                {
                    continue;
                }
                if (f.x > 0 && f.y > 0 && f.z > 0)
                {
                    continue;
                }

                Index3i triEdges = Mesh.GetTriEdges(tid);

                if (f.x * f.y * f.z == 0)
                {
                    int z0 = (f.x == 0) ? 0 : ((f.y == 0) ? 1 : 2);
                    int i1 = (z0 + 1) % 3, i2 = (z0 + 2) % 3;
                    if (f[i1] * f[i2] > 0)
                    {
                        continue;       // single-vertex-crossing case, skip here and let other edges catch it
                    }
                    if (f[i1] == 0 || f[i2] == 0)
                    {
                        // on-edge case
                        int z1 = f[i1] == 0 ? i1 : i2;
                        if ((z0 + 1) % 3 != z1)
                        {
                            int tmp = z0; z0 = z1; z1 = tmp;        // catch reverse-orientation cases
                        }
                        int e0        = add_or_append_vertex(Mesh.GetVertex(triVerts[z0]));
                        int e1        = add_or_append_vertex(Mesh.GetVertex(triVerts[z1]));
                        int graph_eid = Graph.AppendEdge(e0, e1, (int)TriangleCase.OnEdge);
                        if (graph_eid >= 0 && WantGraphEdgeInfo)
                        {
                            add_on_edge(graph_eid, tid, triEdges[z0], new Index2i(e0, e1));
                        }
                    }
                    else
                    {
                        // edge/vertex case
                        Util.gDevAssert(f[i1] * f[i2] < 0);

                        int vert_vid = add_or_append_vertex(Mesh.GetVertex(triVerts[z0]));

                        int i = i1, j = i2;
                        if (triVerts[j] < triVerts[i])
                        {
                            int tmp = i; i = j; j = tmp;
                        }
                        Vector3d cross     = find_crossing(tv[i], tv[j], f[i], f[j]);
                        int      cross_vid = add_or_append_vertex(cross);
                        add_edge_pos(triVerts[i], triVerts[j], cross);

                        int graph_eid = Graph.AppendEdge(vert_vid, cross_vid, (int)TriangleCase.EdgeVertex);
                        if (graph_eid >= 0 && WantGraphEdgeInfo)
                        {
                            add_edge_vert(graph_eid, tid, triEdges[(z0 + 1) % 3], triVerts[z0], new Index2i(vert_vid, cross_vid));
                        }
                    }
                }
                else
                {
                    Index3i cross_verts = Index3i.Min;
                    int     less_than   = 0;
                    for (int tei = 0; tei < 3; ++tei)
                    {
                        int i = tei, j = (tei + 1) % 3;
                        if (f[i] < 0)
                        {
                            less_than++;
                        }
                        if (f[i] * f[j] > 0)
                        {
                            continue;
                        }
                        if (triVerts[j] < triVerts[i])
                        {
                            int tmp = i; i = j; j = tmp;
                        }
                        Vector3d cross = find_crossing(tv[i], tv[j], f[i], f[j]);
                        cross_verts[tei] = add_or_append_vertex(cross);
                        add_edge_pos(triVerts[i], triVerts[j], cross);
                    }
                    int e0 = (cross_verts.a == int.MinValue) ? 1 : 0;
                    int e1 = (cross_verts.c == int.MinValue) ? 1 : 2;
                    if (e0 == 0 && e1 == 2)         // preserve orientation order
                    {
                        e0 = 2; e1 = 0;
                    }

                    // preserving orientation does not mean we get a *consistent* orientation across faces.
                    // To do that, we need to assign "sides". Either we have 1 less-than-0 or 1 greater-than-0 vtx.
                    // Arbitrary decide that we want loops oriented like bdry loops would be if we discarded less-than side.
                    // In that case, when we are "cutting off" one vertex, orientation would end up flipped
                    if (less_than == 1)
                    {
                        int tmp = e0; e0 = e1; e1 = tmp;
                    }

                    int ev0 = cross_verts[e0];
                    int ev1 = cross_verts[e1];
                    // [RMS] if function is garbage, we can end up w/ case where both crossings
                    //   happen at same vertex, even though values are not the same (eg if
                    //   some values are double.MaxValue). We will just fail in these cases.
                    if (ev0 != ev1)
                    {
                        Util.gDevAssert(ev0 != int.MinValue && ev1 != int.MinValue);
                        int graph_eid = Graph.AppendEdge(ev0, ev1, (int)TriangleCase.EdgeEdge);
                        if (graph_eid >= 0 && WantGraphEdgeInfo)
                        {
                            add_edge_edge(graph_eid, tid, new Index2i(triEdges[e0], triEdges[e1]), new Index2i(ev0, ev1));
                        }
                    }
                }
            }


            Vertices = null;
        }
        /// <summary>
        /// Apply LaplacianMeshSmoother to subset of mesh triangles.
        /// border of subset always has soft constraint with borderWeight,
        /// but is then snapped back to original vtx pos after solve.
        /// nConstrainLoops inner loops are also soft-constrained, with weight falloff via square roots (defines continuity)
        /// interiorWeight is soft constraint added to all vertices
        /// </summary>
        public static void RegionSmooth(DMesh3 mesh, IEnumerable <int> triangles,
                                        int nConstrainLoops,
                                        int nIncludeExteriorRings,
                                        bool bPreserveExteriorRings,
                                        double borderWeight = 10.0, double interiorWeight = 0.0)
        {
            HashSet <int> fixedVerts = new HashSet <int>();

            if (nIncludeExteriorRings > 0)
            {
                MeshFaceSelection expandTris = new MeshFaceSelection(mesh);
                expandTris.Select(triangles);
                if (bPreserveExteriorRings)
                {
                    MeshEdgeSelection bdryEdges = new MeshEdgeSelection(mesh);
                    bdryEdges.SelectBoundaryTriEdges(expandTris);
                    expandTris.ExpandToOneRingNeighbours(nIncludeExteriorRings);
                    MeshVertexSelection startVerts = new MeshVertexSelection(mesh);
                    startVerts.SelectTriangleVertices(triangles);
                    startVerts.DeselectEdges(bdryEdges);
                    MeshVertexSelection expandVerts = new MeshVertexSelection(mesh, expandTris);
                    foreach (int vid in expandVerts)
                    {
                        if (startVerts.IsSelected(vid) == false)
                        {
                            fixedVerts.Add(vid);
                        }
                    }
                }
                else
                {
                    expandTris.ExpandToOneRingNeighbours(nIncludeExteriorRings);
                }
                triangles = expandTris;
            }

            RegionOperator        region     = new RegionOperator(mesh, triangles);
            DSubmesh3             submesh    = region.Region;
            DMesh3                smoothMesh = submesh.SubMesh;
            LaplacianMeshSmoother smoother   = new LaplacianMeshSmoother(smoothMesh);

            // map fixed verts to submesh
            HashSet <int> subFixedVerts = new HashSet <int>();

            foreach (int base_vid in fixedVerts)
            {
                subFixedVerts.Add(submesh.MapVertexToSubmesh(base_vid));
            }

            // constrain borders
            double w = borderWeight;

            HashSet <int> constrained = (submesh.BaseBorderV.Count > 0) ? new HashSet <int>() : null;

            foreach (int base_vid in submesh.BaseBorderV)
            {
                int sub_vid = submesh.BaseToSubV[base_vid];
                smoother.SetConstraint(sub_vid, smoothMesh.GetVertex(sub_vid), w, true);
                if (constrained != null)
                {
                    constrained.Add(sub_vid);
                }
            }

            if (constrained.Count > 0)
            {
                w = Math.Sqrt(w);
                for (int k = 0; k < nConstrainLoops; ++k)
                {
                    HashSet <int> next_layer = new HashSet <int>();

                    foreach (int sub_vid in constrained)
                    {
                        foreach (int nbr_vid in smoothMesh.VtxVerticesItr(sub_vid))
                        {
                            if (constrained.Contains(nbr_vid) == false)
                            {
                                if (smoother.IsConstrained(nbr_vid) == false)
                                {
                                    smoother.SetConstraint(nbr_vid, smoothMesh.GetVertex(nbr_vid), w, subFixedVerts.Contains(nbr_vid));
                                }
                                next_layer.Add(nbr_vid);
                            }
                        }
                    }

                    constrained.UnionWith(next_layer);
                    w = Math.Sqrt(w);
                }
            }

            // soft constraint on all interior vertices, if requested
            if (interiorWeight > 0)
            {
                foreach (int vid in smoothMesh.VertexIndices())
                {
                    if (smoother.IsConstrained(vid) == false)
                    {
                        smoother.SetConstraint(vid, smoothMesh.GetVertex(vid), interiorWeight, subFixedVerts.Contains(vid));
                    }
                }
            }
            else if (subFixedVerts.Count > 0)
            {
                foreach (int vid in subFixedVerts)
                {
                    if (smoother.IsConstrained(vid) == false)
                    {
                        smoother.SetConstraint(vid, smoothMesh.GetVertex(vid), 0, true);
                    }
                }
            }

            smoother.SolveAndUpdateMesh();
            region.BackPropropagateVertices(true);
        }
Esempio n. 11
0
        public virtual bool Cut()
        {
            double invalidDist = double.MinValue;

            MeshEdgeSelection   CutEdgeSet   = null;
            MeshVertexSelection CutVertexSet = null;

            if (CutFaceSet != null)
            {
                CutEdgeSet   = new MeshEdgeSelection(Mesh, CutFaceSet);
                CutVertexSet = new MeshVertexSelection(Mesh, CutEdgeSet);
            }

            // compute signs
            int MaxVID = Mesh.MaxVertexID;

            double[] signs = new double[MaxVID];
            gParallel.ForEach(Interval1i.Range(MaxVID), (vid) => {
                if (Mesh.IsVertex(vid))
                {
                    Vector3d v = Mesh.GetVertex(vid);
                    signs[vid] = (v - PlaneOrigin).Dot(PlaneNormal);
                }
                else
                {
                    signs[vid] = invalidDist;
                }
            });

            HashSet <int> ZeroEdges    = new HashSet <int>();
            HashSet <int> ZeroVertices = new HashSet <int>();
            HashSet <int> OnCutEdges   = new HashSet <int>();

            // have to skip processing of new edges. If edge id
            // is > max at start, is new. Otherwise if in NewEdges list, also new.
            int           MaxEID   = Mesh.MaxEdgeID;
            HashSet <int> NewEdges = new HashSet <int>();

            IEnumerable <int> edgeItr = Interval1i.Range(MaxEID);

            if (CutEdgeSet != null)
            {
                edgeItr = CutEdgeSet;
            }

            // cut existing edges with plane, using edge split
            foreach (int eid in edgeItr)
            {
                if (Mesh.IsEdge(eid) == false)
                {
                    continue;
                }
                if (eid >= MaxEID || NewEdges.Contains(eid))
                {
                    continue;
                }

                Index2i ev = Mesh.GetEdgeV(eid);
                double  f0 = signs[ev.a];
                double  f1 = signs[ev.b];

                // If both signs are 0, this edge is on-contour
                // If one sign is 0, that vertex is on-contour
                int n0 = (Math.Abs(f0) < MathUtil.Epsilon) ? 1 : 0;
                int n1 = (Math.Abs(f1) < MathUtil.Epsilon) ? 1 : 0;
                if (n0 + n1 > 0)
                {
                    if (n0 + n1 == 2)
                    {
                        ZeroEdges.Add(eid);
                    }
                    else
                    {
                        ZeroVertices.Add((n0 == 1) ? ev[0] : ev[1]);
                    }
                    continue;
                }

                // no crossing
                if (f0 * f1 > 0)
                {
                    continue;
                }

                DMesh3.EdgeSplitInfo splitInfo;
                MeshResult           result = Mesh.SplitEdge(eid, out splitInfo);
                if (result != MeshResult.Ok)
                {
                    throw new Exception("MeshPlaneCut.Cut: failed in SplitEdge");
                    //return false;
                }

                // SplitEdge just bisects edge - use plane intersection instead
                double   t      = f0 / (f0 - f1);
                Vector3d newPos = (1 - t) * Mesh.GetVertex(ev.a) + (t) * Mesh.GetVertex(ev.b);
                Mesh.SetVertex(splitInfo.vNew, newPos);

                NewEdges.Add(splitInfo.eNewBN);
                NewEdges.Add(splitInfo.eNewCN);  OnCutEdges.Add(splitInfo.eNewCN);
                if (splitInfo.eNewDN != DMesh3.InvalidID)
                {
                    NewEdges.Add(splitInfo.eNewDN);
                    OnCutEdges.Add(splitInfo.eNewDN);
                }
            }

            // remove one-rings of all positive-side vertices.
            IEnumerable <int> vertexSet = Interval1i.Range(MaxVID);

            if (CutVertexSet != null)
            {
                vertexSet = CutVertexSet;
            }
            foreach (int vid in vertexSet)
            {
                if (signs[vid] > 0 && Mesh.IsVertex(vid))
                {
                    Mesh.RemoveVertex(vid, true, false);
                }
            }

            // ok now we extract boundary loops, but restricted
            // to either the zero-edges we found, or the edges we created! bang!!
            Func <int, bool> CutEdgeFilterF = (eid) => {
                if (OnCutEdges.Contains(eid) || ZeroEdges.Contains(eid))
                {
                    return(true);
                }
                return(false);
            };

            try {
                MeshBoundaryLoops loops = new MeshBoundaryLoops(Mesh, false);
                loops.EdgeFilterF = CutEdgeFilterF;
                loops.Compute();

                CutLoops       = loops.Loops;
                CutSpans       = loops.Spans;
                CutLoopsFailed = false;
                FoundOpenSpans = CutSpans.Count > 0;
            } catch {
                CutLoops       = new List <EdgeLoop>();
                CutLoopsFailed = true;
            }

            return(true);
        }         // Cut()