Exemple #1
0
        // After remeshing we may create an internal edge between two boundary vertices [a,b].
        // Those vertices will be merged with vertices c and d in the base mesh. If the edge
        // [c,d] already exists in the base mesh, then after the merge we would have at least
        // 3 triangles at this edge. Dang.
        //
        // A common example is a 'fin' triangle that would duplicate a
        // 'fin' on the border of the base mesh after removing the submesh, but this situation can
        // arise anywhere (eg think about one-triangle-wide strips).
        //
        // This is very hard to remove, but we can at least avoid creating non-manifold edges (which
        // with the current DMesh3 will be prevented, hence leaving a hole) by splitting the
        // internal edge in the submesh (which presumably we were remeshing anyway, so changes are ok).
        public void RepairPossibleNonManifoldEdges()
        {
            // [TODO] do we need to repeat this more than once? I don't think so...

            // repair submesh
            int NE          = Region.SubMesh.MaxEdgeID;
            var split_edges = new List <int>();

            for (int eid = 0; eid < NE; ++eid)
            {
                if (Region.SubMesh.IsEdge(eid) == false)
                {
                    continue;
                }

                if (Region.SubMesh.IsBoundaryEdge(eid))
                {
                    continue;
                }

                Index2i edgev = Region.SubMesh.GetEdgeV(eid);
                if (Region.SubMesh.IsBoundaryVertex(edgev.a) && Region.SubMesh.IsBoundaryVertex(edgev.b))
                {
                    // ok, we have an internal edge where both verts are on the boundary
                    // now check if it is an edge in the base mesh
                    int base_a = Region.MapVertexToBaseMesh(edgev.a);
                    int base_b = Region.MapVertexToBaseMesh(edgev.b);
                    if (base_a != DMesh3.InvalidID && base_b != DMesh3.InvalidID)
                    {
                        // both vertices in base mesh...right?
                        Debug.Assert(Region.BaseMesh.IsVertex(base_a) && Region.BaseMesh.IsVertex(base_b));
                        int base_eid = Region.BaseMesh.FindEdge(base_a, base_b);
                        if (base_eid != DMesh3.InvalidID)
                        {
                            split_edges.Add(eid);
                        }
                    }
                }
            }

            // split any problem edges we found and repeat this loop
            for (int i = 0; i < split_edges.Count; ++i)
            {
                DMesh3.EdgeSplitInfo split_info;
                Region.SubMesh.SplitEdge(split_edges[i], out split_info);
            }
        }
        /// <summary>
        /// For given edge, return it's triangles and the triangles that would
        /// be created if it was flipped (used in edge-flip optimizers)
        /// </summary>
        public static void GetEdgeFlipTris(DMesh3 mesh, int eID,
                                           out Index3i orig_t0, out Index3i orig_t1,
                                           out Index3i flip_t0, out Index3i flip_t1)
        {
            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;
            Index3i tri_v = mesh.GetTriangle(t0);
            int     oa = a, ob = b;

            IndexUtil.orient_tri_edge(ref oa, ref ob, ref tri_v);
            orig_t0 = new Index3i(oa, ob, c);
            orig_t1 = new Index3i(ob, oa, d);
            flip_t0 = new Index3i(c, d, ob);
            flip_t1 = new Index3i(d, c, oa);
        }
Exemple #3
0
        /// <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);
        }
Exemple #4
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 #5
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);
        }
        //
        // [TODO] for internal vertices, there is no ambiguity in which is the left-turn edge,
        //   we should be using 'closest' left-neighbour edge.
        //
        // ok, bdry_edges[0...bdry_edges_count] contains the boundary edges coming out of bowtie_v.
        // We want to pick the best one to continue the loop that came in to bowtie_v on incoming_e.
        // If the loops are all sane, then we will get the smallest loops by "turning left" at bowtie_v.
        // So, we compute the tangent plane at bowtie_v, and then the signed angle for each
        // viable edge in this plane.
        int find_left_turn_edge(int incoming_e, int bowtie_v, int[] bdry_edges, int bdry_edges_count, IndexFlagSet used_edges)
        {
            // compute normal and edge [a,bowtie]
            Vector3d n       = get_vtx_normal(bowtie_v);
            int      other_v = Mesh.edge_other_v(incoming_e, bowtie_v);
            Vector3d ab      = Mesh.GetVertex(bowtie_v) - Mesh.GetVertex(other_v);

            // our winner
            int    best_e     = -1;
            double best_angle = double.MaxValue;

            for (int i = 0; i < bdry_edges_count; ++i)
            {
                int bdry_eid = bdry_edges[i];
                if (used_edges[bdry_eid] == true)
                {
                    continue;                           // this edge is already used
                }


                // [TODO] can do this more efficienty?
                int tid_in = DMesh3.InvalidID, tid_out = DMesh3.InvalidID;
                edge_is_boundary(bdry_eid, ref tid_in, ref tid_out);
                Index2i bdry_ev = get_oriented_edgev(bdry_eid, tid_in, tid_out);
                //Index2i bdry_ev = Mesh.GetOrientedBoundaryEdgeV(bdry_eid);

                if (bdry_ev.a != bowtie_v)
                {
                    continue;                           // have to be able to chain to end of current edge, orientation-wise
                }

                // compute projected angle
                Vector3d bc      = Mesh.GetVertex(bdry_ev.b) - Mesh.GetVertex(bowtie_v);
                float    fAngleS = MathUtil.PlaneAngleSignedD((Vector3f)ab, (Vector3f)bc, (Vector3f)n);

                // turn left!
                if (best_angle == double.MaxValue || fAngleS < best_angle)
                {
                    best_angle = fAngleS;
                    best_e     = bdry_eid;
                }
            }
            Debug.Assert(best_e != -1);

            return(best_e);
        }
        public void debug_print_vertex(int v)
        {
            System.Console.WriteLine("Vertex " + v.ToString());
            List <int> tris = new List <int>();

            GetVtxTriangles(v, tris, false);
            System.Console.WriteLine(string.Format("  Tris {0}  Edges {1}  refcount {2}", tris.Count, GetVtxEdges(v).Count, vertices_refcount.refCount(v)));
            foreach (int t in tris)
            {
                Index3i tv = GetTriangle(t), te = GetTriEdges(t);
                System.Console.WriteLine(string.Format("  t{6} {0} {1} {2}   te {3} {4} {5}", tv[0], tv[1], tv[2], te[0], te[1], te[2], t));
            }
            foreach (int e in GetVtxEdges(v))
            {
                Index2i ev = GetEdgeV(e), et = GetEdgeT(e);
                System.Console.WriteLine(string.Format("  e{4} {0} {1} / {2} {3}", ev[0], ev[1], et[0], et[1], e));
            }
        }
        public double this[int r, int c]
        {
            get
            {
                var    v = new Index2i(Math.Min(r, c), Math.Max(r, c));
                double value;
                if (d.TryGetValue(v, out value))
                {
                    return(value);
                }

                return(0);
            }
            set
            {
                Set(r, c, value);
            }
        }
Exemple #9
0
        /// <summary>
        /// for each on-edge vtx, we split the edge and then
        /// re-sort any of the vertices on that edge onto new edges
        /// </summary>
        void insert_edge_vertices()
        {
            while (EdgeVertices.Count > 0)
            {
                var pair = EdgeVertices.First();
                int eid  = pair.Key;
                List <SegmentVtx> edgeVerts = pair.Value;
                SegmentVtx        v         = edgeVerts[edgeVerts.Count - 1];
                edgeVerts.RemoveAt(edgeVerts.Count - 1);

                Index2i splitTris = Target.GetEdgeT(eid);

                DMesh3.EdgeSplitInfo splitInfo;
                MeshResult           result = Target.SplitEdge(eid, out splitInfo);
                if (result != MeshResult.Ok)
                {
                    throw new Exception("insert_edge_vertices: split failed!");
                }

                int new_v      = splitInfo.vNew;
                var splitEdges = new Index2i(eid, splitInfo.eNewBN);

                Target.SetVertex(new_v, v.v);
                v.vtx_id = new_v;
                VIDToSegVtxMap[v.vtx_id] = v;
                PointHash.InsertPoint(v.vtx_id, v.v);

                // remove this triangles vtx list because it is no longer valid
                EdgeVertices.Remove(eid);

                // update remaining verts
                foreach (SegmentVtx sv in edgeVerts)
                {
                    update_from_split(sv, splitEdges);
                    if (sv.type == 1)
                    {
                        add_edge_vtx(sv.elem_id, sv);
                    }
                }

                // track subfaces
                add_split_subfaces(splitTris, ref splitInfo);
            }
        }
        public 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 #11
0
        public virtual void DoReduce()
        {
            if (mesh.TriangleCount == 0)                // badness if we don't catch this...
            {
                return;
            }

            begin_pass();

            begin_setup();
            InitializeVertexQuadrics();
            InitializeQueue();
            end_setup();

            begin_ops();

            begin_collapse();
            while (EdgeQueue.Count > 0 && mesh.TriangleCount > TargetTriangleCount)
            {
                COUNT_ITERATIONS++;
                QEdge cur = EdgeQueue.Dequeue();
                Nodes[cur.eid] = null;
                NodePool.Return(cur);
                if (!mesh.IsEdge(cur.eid))
                {
                    continue;
                }
                Index2i ev = mesh.GetEdgeV(cur.eid);

                int           vKept;
                ProcessResult result = CollapseEdge(cur.eid, cur.collapse_pt, out vKept);
                if (result == ProcessResult.Ok_Collapsed)
                {
                    vertQuadrics[vKept] = cur.q;
                    UpdateNeighbours(vKept);
                }
            }
            end_collapse();
            end_ops();

            Reproject();

            end_pass();
        }
Exemple #12
0
        public void SplitToMaxEdgeLength(double fMaxLen)
        {
            List <int> queue = new List <int>();
            int        NE    = Graph.MaxEdgeID;

            for (int eid = 0; eid < NE; ++eid)
            {
                if (!Graph.IsEdge(eid))
                {
                    continue;
                }
                Index2i ev   = Graph.GetEdgeV(eid);
                double  dist = Graph.GetVertex(ev.a).Distance(Graph.GetVertex(ev.b));
                if (dist > fMaxLen)
                {
                    DGraph2.EdgeSplitInfo splitInfo;
                    if (Graph.SplitEdge(eid, out splitInfo) == MeshResult.Ok && dist > 2 * fMaxLen)
                    {
                        queue.Add(eid);
                        queue.Add(splitInfo.eNewBN);
                    }
                }
            }
            while (queue.Count > 0)
            {
                int eid = queue[queue.Count - 1];
                queue.RemoveAt(queue.Count - 1);
                if (!Graph.IsEdge(eid))
                {
                    continue;
                }
                Index2i ev   = Graph.GetEdgeV(eid);
                double  dist = Graph.GetVertex(ev.a).Distance(Graph.GetVertex(ev.b));
                if (dist > fMaxLen)
                {
                    DGraph2.EdgeSplitInfo splitInfo;
                    if (Graph.SplitEdge(eid, out splitInfo) == MeshResult.Ok && dist > 2 * fMaxLen)
                    {
                        queue.Add(eid);
                        queue.Add(splitInfo.eNewBN);
                    }
                }
            }
        }
Exemple #13
0
        // Support for ordering a set of unique indices into the vertex pool.  On
        // output it is guaranteed that:  v0 < v1 < v2.  This is used to guarantee
        // consistent queries when the vertex ordering of a primitive is permuted,
        // a necessity when using floating-point arithmetic that suffers from
        // numerical round-off errors.  The input indices are considered the
        // positive ordering.  The output indices are either positively ordered
        // (an even number of transpositions occurs during sorting) or negatively
        // ordered (an odd number of transpositions occurs during sorting).  The
        // functions return 'true' for a positive ordering and 'false' for a
        // negative ordering.

        public static bool Sort(ref int v0, ref int v1)
        {
            int  j0, j1;
            bool positive;

            if (v0 < v1)
            {
                j0 = 0; j1 = 1; positive = true;
            }
            else
            {
                j0 = 1; j1 = 0; positive = false;
            }
            Index2i value = new Index2i(v0, v1);

            v0 = value[j0];
            v1 = value[j1];
            return(positive);
        }
Exemple #14
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);
                }
            }
        }
 // update queue weight for each edge in vertex one-ring
 protected virtual void UpdateNeighbours(int vid)
 {
     foreach (int eid in mesh.VtxEdgesItr(vid))
     {
         Index2i      nev = mesh.GetEdgeV(eid);
         QuadricError Q   = new QuadricError(ref vertQuadrics[nev.a], ref vertQuadrics[nev.b]);
         Vector3d     opt = OptimalPoint(eid, ref Q, nev.a, nev.b);
         double       err = Q.Evaluate(ref opt);
         EdgeQuadrics[eid] = new QEdge(eid, ref Q, ref opt);
         if (EdgeQueue.Contains(eid))
         {
             EdgeQueue.Update(eid, (float)err);
         }
         else
         {
             EdgeQueue.Insert(eid, (float)err);
         }
     }
 }
Exemple #16
0
        // for all mesh boundary edges, disable flip/split/collapse
        // for all mesh boundary vertices, pin in current position
        public static void FixAllGroupBoundaryEdges(MeshConstraints cons, DMesh3 mesh, bool bPinVertices)
        {
            int NE = mesh.MaxEdgeID;

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

                    if (bPinVertices)
                    {
                        Index2i ev = mesh.GetEdgeV(ei);
                        cons.SetOrUpdateVertexConstraint(ev.a, VertexConstraint.Pinned);
                        cons.SetOrUpdateVertexConstraint(ev.b, VertexConstraint.Pinned);
                    }
                }
            }
        }
Exemple #17
0
        /// <summary>
        /// If we are at edge eid, which as one vertex prev_vid, find 'other' vertex, and other edge connected to that vertex,
        /// and return pair [next_edge, shared_vtx]
        /// Returns [int.MaxValue, shared_vtx] if shared_vtx is not valence=2   (ie stops at boundaries and complex junctions)
        /// </summary>
        public static Index2i NextEdgeAndVtx(int eid, int prev_vid, DGraph2 graph)
        {
            Index2i ev       = graph.GetEdgeV(eid);
            int     next_vid = (ev.a == prev_vid) ? ev.b : ev.a;

            if (graph.GetVtxEdgeCount(next_vid) != 2)
            {
                return(new Index2i(int.MaxValue, next_vid));
            }

            foreach (int next_eid in graph.VtxEdgesItr(next_vid))
            {
                if (next_eid != eid)
                {
                    return(new Index2i(next_eid, next_vid));
                }
            }
            return(Index2i.Max);
        }
        // ok, bdry_edges[0...bdry_edges_count] contains the boundary edges coming out of bowtie_v.
        // We want to pick the best one to continue the loop that came in to bowtie_v on incoming_e.
        // If the loops are all sane, then we will get the smallest loops by "turning left" at bowtie_v.
        // So, we compute the tangent plane at bowtie_v, and then the signed angle for each
        // viable edge in this plane.
        //
        // [TODO] handle degenerate edges. what do we do then? Currently will only chose
        //  degenerate edge if there are no other options (I think...)
        int find_left_turn_edge(int incoming_e, int bowtie_v, int[] bdry_edges, int bdry_edges_count, BitArray used_edges)
        {
            // compute normal and edge [a,bowtie]
            Vector3d n       = get_vtx_normal(bowtie_v);
            int      other_v = Mesh.edge_other_v(incoming_e, bowtie_v);
            Vector3d ab      = Mesh.GetVertex(bowtie_v) - Mesh.GetVertex(other_v);

            // our winner
            int    best_e     = -1;
            double best_angle = double.MaxValue;

            for (int i = 0; i < bdry_edges_count; ++i)
            {
                int bdry_eid = bdry_edges[i];
                if (used_edges[bdry_eid] == true)
                {
                    continue;                           // this edge is already used
                }

                Index2i bdry_ev = Mesh.GetOrientedBoundaryEdgeV(bdry_eid);
                if (bdry_ev.a != bowtie_v)
                {
                    continue;                           // have to be able to chain to end of current edge, orientation-wise
                }

                // compute projected angle
                Vector3d bc      = Mesh.GetVertex(bdry_ev.b) - Mesh.GetVertex(bowtie_v);
                float    fAngleS = MathUtil.PlaneAngleSignedD((Vector3f)ab, (Vector3f)bc, (Vector3f)n);

                // turn left!
                if (best_angle == double.MaxValue || fAngleS < best_angle)
                {
                    best_angle = fAngleS;
                    best_e     = bdry_eid;
                }
            }

            // [RMS] w/ bowtie vertices and open spans, this does happen
            //Debug.Assert(best_e != -1);

            return(best_e);
        }
Exemple #19
0
        public virtual int[] AddTriangleFan_OrderedEdgeLoop(int center, int[] edge_loop, int group_id = -1)
        {
            int N = edge_loop.Length;

            int[] new_tris = new int[N];

            int i = 0;

            for (i = 0; i < N; ++i)
            {
                if (Mesh.edge_is_boundary(edge_loop[i]) == false)
                {
                    goto operation_failed;
                }

                Index2i ev = Mesh.GetOrientedBoundaryEdgeV(edge_loop[i]);
                int     a = ev.a, b = ev.b;

                Index3i newT    = new Index3i(center, b, a);
                int     new_tid = Mesh.AppendTriangle(newT, group_id);
                if (new_tid == DMesh3.InvalidID)
                {
                    goto operation_failed;
                }

                new_tris[i] = new_tid;
            }

            return(new_tris);


operation_failed:
            // remove what we added so far
            if (i > 0)
            {
                if (remove_triangles(new_tris, i - 1) == false)
                {
                    throw new Exception("MeshConstructor.AddTriangleFan_OrderedEdgeLoop: failed to add fan, and also failed to back out changes.");
                }
            }
            return(null);
        }
        public void CollapseDegenerateEdges(double fDegenLenThresh = MathUtil.Epsilonf)
        {
            bool done       = false;
            int  max_passes = 100;
            int  pass_count = 0;

            while (done == false && pass_count++ < max_passes)
            {
                done = true;

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

                    if (FixedEdgeFilterF(eid))
                    {
                        continue;
                    }

                    Index2i ev = Graph.GetEdgeV(eid);

                    Vector2d va = Graph.GetVertex(ev.a);
                    Vector2d vb = Graph.GetVertex(ev.b);
                    if (va.Distance(vb) < fDegenLenThresh)
                    {
                        int keep   = ev.a;
                        int remove = ev.b;

                        DGraph2.EdgeCollapseInfo collapseInfo;
                        if (Graph.CollapseEdge(keep, remove, out collapseInfo) == MeshResult.Ok)
                        {
                            done = false;
                        }
                    }
                }
                ;
            }
        }
        /// <summary>
        /// For given edge, return normals of it's two triangles, and normals
        /// of the triangles created if edge is flipped (used in edge-flip optimizers)
        /// </summary>
        public static void GetEdgeFlipNormals(DMesh3 mesh, int eID,
                                              out Vector3d n1, out Vector3d n2,
                                              out Vector3d on1, out Vector3d on2)
        {
            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);

            n1  = MathUtil.Normal(ref vOA, ref vOB, ref vC);
            n2  = MathUtil.Normal(ref vOB, ref vOA, ref vD);
            on1 = MathUtil.Normal(ref vC, ref vD, ref vOB);
            on2 = MathUtil.Normal(ref vD, ref vC, ref vOA);
        }
Exemple #22
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));
        }
 /// <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 #24
0
        void add_split_subfaces(Index2i origTris, ref DMesh3.EdgeSplitInfo splitInfo)
        {
            int           parent_1   = get_parent(origTris.a);
            HashSet <int> subfaces_1 = get_subfaces(parent_1);

            if (origTris.a != parent_1)
            {
                add_subface(subfaces_1, parent_1, origTris.a);
            }
            add_subface(subfaces_1, parent_1, splitInfo.eNewT2);

            if (origTris.b != DMesh3.InvalidID)
            {
                int           parent_2   = get_parent(origTris.b);
                HashSet <int> subfaces_2 = get_subfaces(parent_2);
                if (origTris.b != parent_2)
                {
                    add_subface(subfaces_2, parent_2, origTris.b);
                }
                add_subface(subfaces_2, parent_2, splitInfo.eNewT3);
            }
        }
Exemple #25
0
        }         // Cut()

        protected void collapse_degenerate_edges(HashSet <int> OnCutEdges, HashSet <int> ZeroEdges)
        {
            var sets = new HashSet <int>[2] {
                OnCutEdges, ZeroEdges
            };

            double   tol2 = DegenerateEdgeTol * DegenerateEdgeTol;
            Vector3d a = Vector3d.Zero, b = Vector3d.Zero;
            int      collapsed = 0;

            do
            {
                collapsed = 0;
                foreach (var edge_set in sets)
                {
                    foreach (int eid in edge_set)
                    {
                        if (Mesh.IsEdge(eid) == false)
                        {
                            continue;
                        }

                        Mesh.GetEdgeV(eid, ref a, ref b);
                        if (a.DistanceSquared(b) > tol2)
                        {
                            continue;
                        }

                        Index2i ev = Mesh.GetEdgeV(eid);
                        DMesh3.EdgeCollapseInfo collapseInfo;
                        MeshResult result = Mesh.CollapseEdge(ev.a, ev.b, out collapseInfo);
                        if (result == MeshResult.Ok)
                        {
                            collapsed++;
                        }
                    }
                }
            } while (collapsed != 0);
        }
        public MeshRegionBoundaryLoops(DMesh3 mesh, int[] RegionTris, bool bAutoCompute = true)
        {
            this.Mesh = mesh;

            // make flag set for included triangles
            triangles = new IndexFlagSet(mesh.MaxTriangleID, RegionTris.Length);
            for (int i = 0; i < RegionTris.Length; ++i)
            {
                triangles[RegionTris[i]] = true;
            }

            // make flag set for included edges
            // NOTE: this currently processes non-boundary-edges twice. Could
            // avoid w/ another IndexFlagSet, but the check is inexpensive...
            edges = new IndexFlagSet(mesh.MaxEdgeID, RegionTris.Length);
            for (int i = 0; i < RegionTris.Length; ++i)
            {
                int     tid = RegionTris[i];
                Index3i te  = Mesh.GetTriEdges(tid);
                for (int j = 0; j < 3; ++j)
                {
                    int eid = te[j];
                    if (!edges.Contains(eid))
                    {
                        Index2i et = mesh.GetEdgeT(eid);
                        if (et.b == DMesh3.InvalidID || triangles[et.a] != triangles[et.b])
                        {
                            edges.Add(eid);
                        }
                    }
                }
            }


            if (bAutoCompute)
            {
                Compute();
            }
        }
Exemple #27
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 #28
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 #29
0
 // find the vtx that is the same in both ev0 and ev1
 public static int find_shared_edge_v(ref Index2i ev0, ref Index2i ev1)
 {
     if (ev0.a == ev1.a)
     {
         return(ev0.a);
     }
     else if (ev0.a == ev1.b)
     {
         return(ev0.a);
     }
     else if (ev0.b == ev1.a)
     {
         return(ev0.b);
     }
     else if (ev0.b == ev1.b)
     {
         return(ev0.b);
     }
     else
     {
         return(DMesh3.InvalidID);
     }
 }
        /// <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;
        }