Example #1
0
        /// <summary>
        /// Remove all bowtie vertices in mesh. Makes one pass unless
        ///   bRepeatUntilClean = true, in which case repeats until no more bowties found
        /// Returns true if any vertices were removed
        /// </summary>
        public bool RemoveAllBowtieVertices(bool bRepeatUntilClean)
        {
            int nRemoved = 0;

            while (true)
            {
                var bowties = new List <int>();
                foreach (int vID in Mesh.VertexIndices())
                {
                    if (Mesh.IsBowtieVertex(vID))
                    {
                        bowties.Add(vID);
                    }
                }
                if (bowties.Count == 0)
                {
                    break;
                }

                foreach (int vID in bowties)
                {
                    MeshResult result = Mesh.RemoveVertex(vID, true, false);
                    Debug.Assert(result == MeshResult.Ok);
                    nRemoved++;
                }
                if (bRepeatUntilClean == false)
                {
                    break;
                }
            }
            return(nRemoved > 0);
        }
        public virtual bool Fill(int group_id = -1)
        {
            if (Loop.Vertices.Length < 3)
            {
                return(false);
            }

            // this just needs one triangle
            if (Loop.Vertices.Length == 3)
            {
                Index3i tri     = new Index3i(Loop.Vertices[0], Loop.Vertices[2], Loop.Vertices[1]);
                int     new_tid = Mesh.AppendTriangle(tri, group_id);
                if (new_tid < 0)
                {
                    return(false);
                }
                NewTriangles = new int[1] {
                    new_tid
                };
                NewVertex = DMesh3.InvalidID;
                return(true);
            }

            // [TODO] 4-case? could check nbr normals to figure out best internal edge...


            // compute centroid
            Vector3d c = Vector3d.Zero;

            for (int i = 0; i < Loop.Vertices.Length; ++i)
            {
                c += Mesh.GetVertex(Loop.Vertices[i]);
            }
            c *= 1.0 / Loop.Vertices.Length;

            // add centroid vtx
            NewVertex = Mesh.AppendVertex(c);

            // stitch triangles
            MeshEditor editor = new MeshEditor(Mesh);

            try {
                NewTriangles = editor.AddTriangleFan_OrderedVertexLoop(NewVertex, Loop.Vertices, group_id);
            } catch {
                NewTriangles = null;
            }

            // if fill failed, back out vertex-add
            if (NewTriangles == null)
            {
                Mesh.RemoveVertex(NewVertex, true, false);
                NewVertex = DMesh3.InvalidID;
                return(false);
            }
            else
            {
                return(true);
            }
        }
Example #3
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()