Exemple #1
0
        public virtual void FastCollapsePass(double fMinEdgeLength)
        {
            if (mesh.TriangleCount == 0)    // badness if we don't catch this...
            {
                return;
            }

            MinEdgeLength = fMinEdgeLength;
            double min_sqr = MinEdgeLength * MinEdgeLength;

            // we don't collapse on the boundary
            HaveBoundary = false;

            begin_pass();

            begin_setup();
            Precompute();
            end_setup();

            begin_ops();

            begin_collapse();

            int      N = mesh.MaxEdgeID;
            Vector3d va = Vector3d.Zero, vb = Vector3d.Zero;

            for (int eid = 0; eid < N; ++eid)
            {
                if (!mesh.IsEdge(eid))
                {
                    continue;
                }
                if (mesh.IsBoundaryEdge(eid))
                {
                    continue;
                }

                mesh.GetEdgeV(eid, ref va, ref vb);
                if (va.DistanceSquared(ref vb) > min_sqr)
                {
                    continue;
                }

                COUNT_ITERATIONS++;

                Vector3d      midpoint = (va + vb) * 0.5;
                int           vKept;
                ProcessResult result = CollapseEdge(eid, midpoint, out vKept);
                if (result == ProcessResult.Ok_Collapsed)
                {
                    // do nothing?
                }
            }
            end_collapse();
            end_ops();

            Reproject();

            end_pass();
        }
        /// <summary>
        /// construct EdgeSpan from a list of edges of mesh
        /// </summary>
        public static EdgeSpan FromEdges(DMesh3 mesh, IList <int> edges)
        {
            int[] Edges = new int[edges.Count];
            for (int i = 0; i < Edges.Length; ++i)
            {
                Edges[i] = edges[i];
            }
            int[]   Vertices = new int[Edges.Length + 1];
            Index2i start_ev = mesh.GetEdgeV(Edges[0]);
            Index2i prev_ev  = start_ev;

            if (Edges.Length > 1)
            {
                for (int i = 1; i < Edges.Length; ++i)
                {
                    Index2i next_ev = mesh.GetEdgeV(Edges[i]);
                    Vertices[i] = IndexUtil.find_shared_edge_v(ref prev_ev, ref next_ev);
                    prev_ev     = next_ev;
                }
                Vertices[0] = IndexUtil.find_edge_other_v(ref start_ev, Vertices[1]);
                Vertices[Vertices.Length - 1] = IndexUtil.find_edge_other_v(prev_ev, Vertices[Vertices.Length - 2]);
            }
            else
            {
                Vertices[0] = start_ev[0]; Vertices[1] = start_ev[1];
            }
            return(new EdgeSpan(mesh, Vertices, Edges, false));
        }
Exemple #3
0
        public int MapEdgeToSubmesh(int base_eid)
        {
            Index2i base_ev = BaseMesh.GetEdgeV(base_eid);
            Index2i sub_ev  = MapVerticesToSubmesh(base_ev);

            return(SubMesh.FindEdge(sub_ev.a, sub_ev.b));
        }
Exemple #4
0
        protected virtual void InitializeQueue()
        {
            int NE = mesh.EdgeCount;

            Nodes     = new QEdge[2 * NE];                      // [RMS] do we need this many?
            NodePool  = new MemoryPool <QEdge>(NE);
            EdgeQueue = new g3ext.FastPriorityQueue <QEdge>(NE);

            int  cur_eid = start_edges();
            bool done    = false;

            do
            {
                if (mesh.IsEdge(cur_eid))
                {
                    Index2i ev = mesh.GetEdgeV(cur_eid);

                    QuadricError Q   = new QuadricError(ref vertQuadrics[ev.a], ref vertQuadrics[ev.b]);
                    Vector3d     opt = OptimalPoint(Q, ev.a, ev.b);
                    double       err = Q.Evaluate(opt);

                    QEdge ee = NodePool.Allocate();
                    ee.Initialize(cur_eid, Q, opt);
                    Nodes[cur_eid] = ee;
                    EdgeQueue.Enqueue(ee, (float)err);
                }
                cur_eid = next_edge(cur_eid, out done);
            } while (done == false);
        }
Exemple #5
0
 public void SelectEdgeVertices(int[] edges)
 {
     for (int i = 0; i < edges.Length; ++i)
     {
         Index2i ev = Mesh.GetEdgeV(edges[i]);
         add(ev.a); add(ev.b);
     }
 }
        public virtual ValidationStatus Validate(double fDegenerateTol = MathUtil.ZeroTolerancef)
        {
            double dist_sqr_thresh = fDegenerateTol * fDegenerateTol;

            int nStop = IsLoop ? Curve.VertexCount - 1 : Curve.VertexCount;

            for (int k = 0; k < nStop; ++k)
            {
                Vector2d v0 = Curve[k];
                Vector2d v1 = Curve[(k + 1) % Curve.VertexCount];
                if (v0.DistanceSquared(v1) < dist_sqr_thresh)
                {
                    return(ValidationStatus.NearDenegerateInputGeometry);
                }
            }

            foreach (int eid in Mesh.EdgeIndices())
            {
                Index2i ev = Mesh.GetEdgeV(eid);
                if (PointF(ev.a).DistanceSquared(PointF(ev.b)) < dist_sqr_thresh)
                {
                    return(ValidationStatus.NearDegenerateMeshEdges);
                }
            }

            return(ValidationStatus.Ok);
        }
Exemple #7
0
        protected virtual void InitializeQueue()
        {
            int NE     = mesh.EdgeCount;
            int MaxEID = mesh.MaxEdgeID;

            EdgeQuadrics = new QEdge[MaxEID];
            EdgeQueue    = new IndexPriorityQueue(MaxEID);
            float[] edgeErrors = new float[MaxEID];

            // vertex quadrics can be computed in parallel
            gParallel.ForEach(mesh.EdgeIndices(), (eid) => {
                Index2i ev        = mesh.GetEdgeV(eid);
                QuadricError Q    = new QuadricError(ref vertQuadrics[ev.a], ref vertQuadrics[ev.b]);
                Vector3d opt      = OptimalPoint(eid, ref Q, ev.a, ev.b);
                edgeErrors[eid]   = (float)Q.Evaluate(opt);
                EdgeQuadrics[eid] = new QEdge(eid, Q, opt);
            });

            // sorted pq insert is faster, so sort edge errors array and index map
            int[] indices = new int[MaxEID];
            for (int i = 0; i < MaxEID; ++i)
            {
                indices[i] = i;
            }
            Array.Sort(edgeErrors, indices);

            // now do inserts
            for (int i = 0; i < edgeErrors.Length; ++i)
            {
                int eid = indices[i];
                if (mesh.IsEdge(eid))
                {
                    QEdge edge = EdgeQuadrics[eid];
                    EdgeQueue.Enqueue(edge.eid, edgeErrors[i]);
                }
            }

            /*
             * // previous code that does unsorted insert. This is marginally slower, but
             * // might get even slower on larger meshes? have only tried up to about 350k.
             * // (still, this function is not the bottleneck...)
             * int cur_eid = start_edges();
             * bool done = false;
             * do {
             *  if (mesh.IsEdge(cur_eid)) {
             *      QEdge edge = EdgeQuadrics[cur_eid];
             *      double err = errList[cur_eid];
             *      EdgeQueue.Enqueue(cur_eid, (float)err);
             *  }
             *  cur_eid = next_edge(cur_eid, out done);
             * } while (done == false);
             */
        }
        public int MapEdgeToBaseMesh(int sub_eid)
        {
            Index2i sub_ev  = SubMesh.GetEdgeV(sub_eid);
            Index2i base_ev = MapVerticesToBaseMesh(sub_ev);

            return(BaseMesh.FindEdge(base_ev.a, base_ev.b));
        }
Exemple #9
0
        protected bool is_on_edge(int eid, Vector3d v)
        {
            Index2i   ev  = Target.GetEdgeV(eid);
            Segment3d seg = new Segment3d(Target.GetVertex(ev.a), Target.GetVertex(ev.b));

            return(seg.DistanceSquared(v) < VertexSnapTol * VertexSnapTol);
        }
Exemple #10
0
        /// <summary>
        /// Split the mesh edges at the iso-crossings, unless edge is
        /// shorter than min_len, or inserted point would be within min_len or vertex
        /// [TODO] do we want to return any info here??
        /// </summary>
        public void SplitAtIsoCrossings(double min_len = 0)
        {
            foreach (var pair in EdgeLocations)
            {
                int      eid = pair.Key;
                Vector3d pos = pair.Value;
                if (!Mesh.IsEdge(eid))
                {
                    continue;
                }

                Index2i  ev = Mesh.GetEdgeV(eid);
                Vector3d a  = Mesh.GetVertex(ev.a);
                Vector3d b  = Mesh.GetVertex(ev.b);
                if (a.Distance(b) < min_len)
                {
                    continue;
                }
                Vector3d mid = (a + b) * 0.5;
                if (a.Distance(mid) < min_len || b.Distance(mid) < min_len)
                {
                    continue;
                }

                DMesh3.EdgeSplitInfo splitInfo;
                if (Mesh.SplitEdge(eid, out splitInfo) == MeshResult.Ok)
                {
                    Mesh.SetVertex(splitInfo.vNew, pos);
                }
            }
        }
Exemple #11
0
        public static void EdgeLengthStatsFromEdges(DMesh3 mesh, IEnumerable <int> EdgeItr, out double minEdgeLen, out double maxEdgeLen, out double avgEdgeLen, int samples = 0)
        {
            minEdgeLen = double.MaxValue;
            maxEdgeLen = double.MinValue;
            avgEdgeLen = 0;
            int avg_count = 0;
            int MaxID     = mesh.MaxEdgeID;

            Vector3d a = Vector3d.Zero, b = Vector3d.Zero;

            foreach (int eid in EdgeItr)
            {
                if (mesh.IsEdge(eid))
                {
                    mesh.GetEdgeV(eid, ref a, ref b);
                    double len = a.Distance(b);
                    if (len < minEdgeLen)
                    {
                        minEdgeLen = len;
                    }

                    if (len > maxEdgeLen)
                    {
                        maxEdgeLen = len;
                    }

                    avgEdgeLen += len;
                    avg_count++;
                }
            }
            ;
            avgEdgeLen /= (double)avg_count;
        }
Exemple #12
0
 public static void EdgesToVertices(DMesh3 mesh, HashSet <int> edges, HashSet <int> vertices)
 {
     foreach (int eid in edges)
     {
         Index2i ev = mesh.GetEdgeV(eid);
         vertices.Add(ev.a); vertices.Add(ev.b);
     }
 }
Exemple #13
0
 // convert edge selection to vertex selection.
 public MeshVertexSelection(DMesh3 mesh, MeshEdgeSelection convertE) : this(mesh)
 {
     foreach (int eid in convertE)
     {
         Index2i ev = mesh.GetEdgeV(eid);
         add(ev.a); add(ev.b);
     }
 }
        // return same indices as GetEdgeV, but oriented based on attached triangle
        Index2i get_oriented_edgev(int eID, int tid_in, int tid_out)
        {
            Index2i edgev = Mesh.GetEdgeV(eID);
            int     a = edgev.a, b = edgev.b;
            Index3i tri = Mesh.GetTriangle(tid_in);
            int     ai  = IndexUtil.find_edge_index_in_tri(a, b, ref tri);

            return(new Index2i(tri[ai], tri[(ai + 1) % 3]));
        }
        /// <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);
        }
Exemple #16
0
        /// <summary>
        /// construct EdgeLoop from a list of edges of mesh
        /// </summary>
        public static EdgeLoop FromEdges(DMesh3 mesh, IList <int> edges)
        {
            int[] Edges = new int[edges.Count];
            for (int i = 0; i < Edges.Length; ++i)
            {
                Edges[i] = edges[i];
            }

            int[]   Vertices = new int[Edges.Length];
            Index2i start_ev = mesh.GetEdgeV(Edges[0]);
            Index2i prev_ev  = start_ev;

            for (int i = 1; i < Edges.Length; ++i)
            {
                Index2i next_ev = mesh.GetEdgeV(Edges[i % Edges.Length]);
                Vertices[i] = IndexUtil.find_shared_edge_v(ref prev_ev, ref next_ev);
                prev_ev     = next_ev;
            }
            Vertices[0] = IndexUtil.find_edge_other_v(ref start_ev, Vertices[1]);
            return(new EdgeLoop(mesh, Vertices, Edges, false));
        }
Exemple #17
0
 // for all edges, disable flip/split/collapse
 // for all vertices, pin in current position
 public static void FixEdges(MeshConstraints cons, DMesh3 mesh, IEnumerable <int> edges)
 {
     foreach (int ei in edges)
     {
         if (mesh.IsEdge(ei))
         {
             cons.SetOrUpdateEdgeConstraint(ei, EdgeConstraint.FullyConstrained);
             Index2i ev = mesh.GetEdgeV(ei);
             cons.SetOrUpdateVertexConstraint(ev.a, VertexConstraint.Pinned);
             cons.SetOrUpdateVertexConstraint(ev.b, VertexConstraint.Pinned);
         }
     }
 }
Exemple #18
0
        /// <summary>
        /// boundary vertices of mesh, but based on edges, so returns each vertex twice!
        /// </summary>
        public static IEnumerable <int> BoundaryEdgeVertices(DMesh3 mesh)
        {
            int N = mesh.MaxEdgeID;

            for (int i = 0; i < N; ++i)
            {
                if (mesh.IsEdge(i) && mesh.IsBoundaryEdge(i))
                {
                    Index2i ev = mesh.GetEdgeV(i);
                    yield return(ev.a);

                    yield return(ev.b);
                }
            }
        }
Exemple #19
0
        // for all mesh boundary edges, disable flip/split/collapse
        // for all mesh boundary vertices, pin in current position
        public static void FixAllBoundaryEdges(MeshConstraints cons, DMesh3 mesh)
        {
            int NE = mesh.MaxEdgeID;

            for (int ei = 0; ei < NE; ++ei)
            {
                if (mesh.IsEdge(ei) && mesh.IsBoundaryEdge(ei))
                {
                    cons.SetOrUpdateEdgeConstraint(ei, EdgeConstraint.FullyConstrained);

                    Index2i ev = mesh.GetEdgeV(ei);
                    cons.SetOrUpdateVertexConstraint(ev.a, VertexConstraint.Pinned);
                    cons.SetOrUpdateVertexConstraint(ev.b, VertexConstraint.Pinned);
                }
            }
        }
Exemple #20
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);
                }
            }
        }
Exemple #21
0
        /// <summary>
        /// given list of edges of MeshA, and vertex map from A to B, map to list of edges on B
        /// </summary>
        public static List <int> MapEdgesViaVertexMap(IIndexMap AtoBV, DMesh3 MeshA, DMesh3 MeshB, List <int> edges)
        {
            int        N      = edges.Count;
            List <int> result = new List <int>(N);

            for (int i = 0; i < N; ++i)
            {
                int     eid_a = edges[i];
                Index2i aev   = MeshA.GetEdgeV(eid_a);
                int     bev0  = AtoBV[aev.a];
                int     bev1  = AtoBV[aev.b];
                int     eid_b = MeshB.FindEdge(bev0, bev1);
                Debug.Assert(eid_b != DMesh3.InvalidID);
                result.Add(eid_b);
            }
            return(result);
        }
        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;
                    }
                }
            }
        }
Exemple #23
0
        // for all mesh boundary vertices, pin in current position, but allow splits
        public static void FixAllBoundaryEdges_AllowSplit(MeshConstraints cons, DMesh3 mesh, int setID)
        {
            EdgeConstraint   edgeCons = new EdgeConstraint(EdgeRefineFlags.NoFlip | EdgeRefineFlags.NoCollapse);
            VertexConstraint vertCons = new VertexConstraint(true, setID);

            int NE = mesh.MaxEdgeID;

            for (int ei = 0; ei < NE; ++ei)
            {
                if (mesh.IsEdge(ei) && mesh.IsBoundaryEdge(ei))
                {
                    cons.SetOrUpdateEdgeConstraint(ei, edgeCons);

                    Index2i ev = mesh.GetEdgeV(ei);
                    cons.SetOrUpdateVertexConstraint(ev.a, vertCons);
                    cons.SetOrUpdateVertexConstraint(ev.b, vertCons);
                }
            }
        }
Exemple #24
0
        public static void EdgeLengthStats(DMesh3 mesh, out double minEdgeLen, out double maxEdgeLen, out double avgEdgeLen, int samples = 0)
        {
            minEdgeLen = double.MaxValue;
            maxEdgeLen = double.MinValue;
            avgEdgeLen = 0;
            int avg_count = 0;
            int MaxID     = mesh.MaxEdgeID;

            // if we are only taking some samples, use a prime-modulo-loop instead of random
            int nPrime    = (samples == 0) ? 1 : nPrime = 31337;
            int max_count = (samples == 0) ? MaxID : samples;

            Vector3d a = Vector3d.Zero, b = Vector3d.Zero;
            int      eid   = 0;
            int      count = 0;

            do
            {
                if (mesh.IsEdge(eid))
                {
                    mesh.GetEdgeV(eid, ref a, ref b);
                    double len = a.Distance(b);
                    if (len < minEdgeLen)
                    {
                        minEdgeLen = len;
                    }

                    if (len > maxEdgeLen)
                    {
                        maxEdgeLen = len;
                    }

                    avgEdgeLen += len;
                    avg_count++;
                }
                eid = (eid + nPrime) % MaxID;
            } while (eid != 0 && count++ < max_count);

            avgEdgeLen /= (double)avg_count;
        }
Exemple #25
0
        int find_nearest_edge(DMesh3 mesh, Vector3d v, HashSet <int> vertices)
        {
            int    near_eid = DMesh3.InvalidID;
            double nearSqr  = VertexSnapTol * VertexSnapTol;

            foreach (int eid in mesh.BoundaryEdgeIndices())
            {
                Index2i ev = mesh.GetEdgeV(eid);
                if (vertices.Contains(ev.a) == false || vertices.Contains(ev.b) == false)
                {
                    continue;
                }
                Segment3d seg  = new Segment3d(mesh.GetVertex(ev.a), mesh.GetVertex(ev.b));
                double    dSqr = seg.DistanceSquared(v);
                if (dSqr < nearSqr)
                {
                    near_eid = eid;
                    nearSqr  = dSqr;
                }
            }
            return(near_eid);
        }
Exemple #26
0
        /// <summary>
        /// given EdgeLoop on MeshA, and vertex map from A to B, map to EdgeLoop on B
        /// </summary>
        public static EdgeLoop MapLoopViaVertexMap(IIndexMap AtoBV, DMesh3 MeshA, DMesh3 MeshB, EdgeLoop loopIn)
        {
            int NV = loopIn.VertexCount, NE = loopIn.EdgeCount;

            int[] newVerts = new int[NV];
            for (int i = 0; i < NV; ++i)
            {
                newVerts[i] = AtoBV[loopIn.Vertices[i]];
            }

            int[] newEdges = new int[NE];
            for (int i = 0; i < NE; ++i)
            {
                int     eid_a = loopIn.Edges[i];
                Index2i aev   = MeshA.GetEdgeV(eid_a);
                int     bev0  = AtoBV[aev.a];
                int     bev1  = AtoBV[aev.b];
                newEdges[i] = MeshB.FindEdge(bev0, bev1);
                Debug.Assert(newEdges[i] != DMesh3.InvalidID);
            }

            return(new EdgeLoop(MeshB, newVerts, newEdges, false));
        }
Exemple #27
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);
        }
        static List <int> walk_edge_span_forward(DMesh3 mesh, int start_edge, int start_pivot_v, HashSet <int> EdgeSet, out bool bClosedLoop)
        {
            bClosedLoop = false;

            List <int> edgeSpan = new List <int>();

            edgeSpan.Add(start_edge);

            // we update this as we step
            //int cur_edge = start_edge;
            int cur_pivot_v  = start_pivot_v;
            int stop_pivot_v = IndexUtil.find_edge_other_v(mesh.GetEdgeV(start_edge), start_pivot_v);

            Util.gDevAssert(stop_pivot_v != DMesh3.InvalidID);

            bool done = false;

            while (!done)
            {
                // find outgoing edge in set and connected to current pivot vtx
                int next_edge = -1;
                foreach (int nbr_edge in mesh.VtxEdgesItr(cur_pivot_v))
                {
                    if (EdgeSet.Contains(nbr_edge))
                    {
                        next_edge = nbr_edge;
                        break;
                    }
                }

                // could not find - must be done span
                if (next_edge == -1)
                {
                    done = true;
                    break;
                }

                // figure out next pivot vtx (is 'other' from current pivot on next edge)
                Index2i next_edge_v = mesh.GetEdgeV(next_edge);
                if (next_edge_v.a == cur_pivot_v)
                {
                    cur_pivot_v = next_edge_v.b;
                }
                else if (next_edge_v.b == cur_pivot_v)
                {
                    cur_pivot_v = next_edge_v.a;
                }
                else
                {
                    throw new Exception("walk_edge_span_forward: found valid next edge but not connected to previous vertex??");
                }

                edgeSpan.Add(next_edge);
                EdgeSet.Remove(next_edge);

                // if this happens, we closed a loop
                if (cur_pivot_v == stop_pivot_v)
                {
                    done        = true;
                    bClosedLoop = true;
                }
            }

            return(edgeSpan);
        }
Exemple #29
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()
Exemple #30
0
        /// <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);
        }