Пример #1
0
 internal MeshNode(int i, int fi, g3.Frame3f f, g3.Index3i neighbors_index, g3.Index3i vertex_index)
 {
     frame = f;
     this.neighbors_index = neighbors_index;
     this.vertex_index    = vertex_index;
     meshIndex            = fi;
     index = i;
 }
Пример #2
0
        // (sequentially) find each triangle that path point lies in, and insert a vertex for
        // that point into mesh.
        void insert_corners(HashSet <int> MeshVertsOnCurve)
        {
            PrimalQuery2d query = new PrimalQuery2d(PointF);

            if (UseTriSpatial)
            {
                int count = Mesh.TriangleCount + Curve.VertexCount;
                int bins  = 32;
                if (count < 25)
                {
                    bins = 8;
                }
                else if (count < 100)
                {
                    bins = 16;
                }
                AxisAlignedBox3d bounds3 = Mesh.CachedBounds;
                AxisAlignedBox2d bounds2 = new AxisAlignedBox2d(bounds3.Min.xy, bounds3.Max.xy);
                triSpatial = new TriangleBinsGrid2d(bounds2, bins);
                foreach (int tid in Mesh.TriangleIndices())
                {
                    spatial_add_triangle(tid);
                }
            }

            Func <int, Vector2d, bool> inTriangleF = (tid, pos) => {
                Index3i tv           = Mesh.GetTriangle(tid);
                int     query_result = query.ToTriangleUnsigned(pos, tv.a, tv.b, tv.c);
                return(query_result == -1 || query_result == 0);
            };

            CurveVertices = new int[Curve.VertexCount];
            for (int i = 0; i < Curve.VertexCount; ++i)
            {
                Vector2d vInsert  = Curve[i];
                bool     inserted = false;

                // find the triangle that contains this curve point
                int contain_tid = DMesh3.InvalidID;
                if (triSpatial != null)
                {
                    contain_tid = triSpatial.FindContainingTriangle(vInsert, inTriangleF);
                }
                else
                {
                    foreach (int tid in Mesh.TriangleIndices())
                    {
                        Index3i tv = Mesh.GetTriangle(tid);
                        // [RMS] using unsigned query here because we do not need to care about tri CW/CCW orientation
                        //   (right? otherwise we have to explicitly invert mesh. Nothing else we do depends on tri orientation)
                        //int query_result = query.ToTriangle(vInsert, tv.a, tv.b, tv.c);
                        int query_result = query.ToTriangleUnsigned(vInsert, tv.a, tv.b, tv.c);
                        if (query_result == -1 || query_result == 0)
                        {
                            contain_tid = tid;
                            break;
                        }
                    }
                }

                // if we found one, insert the point via face-poke or edge-split,
                // unless it is exactly at existing vertex, in which case we can re-use it
                if (contain_tid != DMesh3.InvalidID)
                {
                    Index3i  tv   = Mesh.GetTriangle(contain_tid);
                    Vector3d bary = MathUtil.BarycentricCoords(vInsert, PointF(tv.a), PointF(tv.b), PointF(tv.c));
                    // SpatialEpsilon is our zero-tolerance, so merge if we are closer than that
                    bool is_existing_v;
                    int  vid = insert_corner_from_bary(i, contain_tid, bary, 0.01, 100 * SpatialEpsilon, out is_existing_v);
                    if (vid > 0)
                    {
                        CurveVertices[i] = vid;
                        if (is_existing_v)
                        {
                            MeshVertsOnCurve.Add(vid);
                        }
                        inserted = true;
                    }
                }

                // if we did not find containing triangle,
                // try matching with any existing vertices.
                // This can happen if curve point is right on mesh border...
                if (inserted == false)
                {
                    foreach (int vid in Mesh.VertexIndices())
                    {
                        Vector2d v = PointF(vid);
                        if (vInsert.Distance(v) < SpatialEpsilon)
                        {
                            CurveVertices[i] = vid;
                            MeshVertsOnCurve.Add(vid);
                            inserted = true;
                        }
                    }
                }

                // TODO: also case where curve point is right on mesh border edge,
                // and so it ends up being outside all triangles?


                if (inserted == false)
                {
                    throw new Exception("MeshInsertUVPolyCurve.insert_corners: curve vertex "
                                        + i.ToString() + " is not inside or on any mesh triangle!");
                }
            }
        }
Пример #3
0
        public static bool RandomizeMesh(g3.DMesh3 mesh, out g3.DMesh3 outputMesh, double amount, double moveTries)
        {
            System.Collections.Generic.SortedDictionary <int, MeshNode> faces = new System.Collections.Generic.SortedDictionary <int, MeshNode>();

            int index = 0;

            foreach (var meshFaceIndex in mesh.TriangleIndices())
            {
                var frame = mesh.GetTriFrame(meshFaceIndex);

                g3.Index3i neighbors    = mesh.GetTriNeighbourTris(meshFaceIndex);
                g3.Index3i vertex_index = mesh.GetTriangle(meshFaceIndex);

                faces.Add(meshFaceIndex, new MeshNode(index++, meshFaceIndex, frame, neighbors, vertex_index));
            }

            foreach (var f in faces)
            {
                f.Value.neighbors.Clear();
                f.Value.neighbors.Capacity = 3;
                for (int i = 0; i < 3; ++i)
                {
                    int fn = f.Value.neighbors_index[i];
                    if (fn >= 0)
                    {
                        f.Value.neighbors.Add(faces[fn]);
                    }
                }

                if (f.Value.neighbors.Count < 3)
                {
                    f.Value.locked = true;

                    foreach (var n in f.Value.neighbors)
                    {
                        n.locked = true;
                    }
                }
            }

            DMesh3 projectMeshCopy = new DMesh3(mesh);

            outputMesh = new DMesh3(mesh);

            if (faces.Count == 0)
            {
                return(false);
            }


            DMeshAABBTree3 treeProject = new DMeshAABBTree3(projectMeshCopy);

            treeProject.Build();

            Random r = new Random();

            bool result = false;


            //for (int i = 0; i < moveTries; i++)
            //{
            double faceArea = 0;

            foreach (var f in faces)
            {
                faceArea += f.Value.TriangleArea(outputMesh);
            }

            faceArea /= faces.Count;

            foreach (var f in faces)
            {
                result |= f.Value.Randomize(outputMesh, treeProject, r, amount, moveTries, faceArea);
            }

            double newFaceArea = 0;

            foreach (var f in faces)
            {
                newFaceArea += f.Value.TriangleArea(outputMesh);
            }

            newFaceArea /= faces.Count;

            return(result);
        }
Пример #4
0
        //public static void VoronoiMesh(List<g3.PolyLine3d> mesh, out List<g3.Line3d> listLines, out List<g3.PolyLine3d> listPolylines)
        //{
        //    System.Collections.Generic.SortedDictionary<int, MeshNode> faces = new System.Collections.Generic.SortedDictionary<int, MeshNode>();

        //    int index = 0;
        //    foreach (var meshFaceIndex in mesh.TriangleIndices())
        //    {
        //        var frame = mesh.GetTriFrame(meshFaceIndex);

        //        g3.Index3i neighbors = mesh.GetTriNeighbourTris(meshFaceIndex);
        //        g3.Index3i vertex_index = mesh.GetTriangle(meshFaceIndex);

        //        faces.Add(meshFaceIndex, new MeshNode(index++, meshFaceIndex, frame, neighbors, vertex_index));
        //    }


        //    foreach (var f in faces)
        //    {
        //        f.Value.neighbors.Clear();
        //        f.Value.neighbors.Capacity = 3;
        //        for (int i = 0; i < 3; ++i)
        //        {
        //            int fn = f.Value.neighbors_index[i];
        //            if (fn >= 0)
        //                f.Value.neighbors.Add(faces[fn]);
        //        }

        //        if (f.Value.neighbors.Count < 3)
        //        {
        //            f.Value.locked = true;

        //            foreach (var n in f.Value.neighbors)
        //                n.locked = true;
        //        }
        //    }

        //    outputMesh = new g3.DMesh3(g3.MeshComponents.None);
        //    listLines = new List<g3.Line3d>();
        //    listPolylines = new List<g3.PolyLine3d>();
        //    foreach (var f in faces)
        //    {
        //        outputMesh.AppendVertex(f.Value.frame.Origin);
        //    }

        //    HashSet<int> processedPoints = new HashSet<int>();

        //    foreach (var f in faces)
        //    {
        //        for (int i = 0; i < 3; i++)
        //        {
        //            List<int> outputLine = new List<int>();

        //            if (processedPoints.Contains(f.Value.vertex_index[i]))
        //                continue;

        //            int checkVertex = f.Value.vertex_index[i];

        //            MeshNode currentFaces = f.Value;
        //            MeshNode prevFace = null;

        //            bool fullLoop = false;

        //            while (true)
        //            {
        //                for (int j = 0; j < currentFaces.neighbors.Count; j++)
        //                {

        //                    var neighbor = currentFaces.neighbors[j];
        //                    if (neighbor.UsesVertex(checkVertex))
        //                    {

        //                        if (neighbor == prevFace)
        //                            continue;

        //                        if (neighbor == f.Value)
        //                        {
        //                            fullLoop = true;
        //                            break; // Found full loop
        //                        }

        //                        outputLine.Add(neighbor.index);

        //                        prevFace = currentFaces;
        //                        currentFaces = neighbor;
        //                        j = -1;
        //                    }
        //                }

        //                break;
        //            }

        //            if (fullLoop)
        //            {
        //                processedPoints.Add(checkVertex);

        //                var polyline = new g3.PolyLine3d();

        //                if (outputLine.Count > 2)
        //                {
        //                    g3.Vector3d centerPoint = f.Value.frame.Origin;

        //                    foreach (var p in outputLine)
        //                        centerPoint += outputMesh.GetVertex(p);

        //                    centerPoint /= (outputLine.Count + 1);

        //                    int center = outputMesh.AppendVertex(centerPoint);

        //                    var pS = outputMesh.GetVertex(f.Value.index);
        //                    var p0 = outputMesh.GetVertex(outputLine[0]);
        //                    var pE = outputMesh.GetVertex(outputLine[outputLine.Count - 1]);

        //                    var normal = mesh.GetTriNormal(f.Value.meshIndex);

        //                    polyline.AppendVertex(pS);
        //                    polyline.AppendVertex(p0);

        //                    listLines.Add(new g3.Line3d(pS, p0 - pS));

        //                    var n = MathUtil.Normal(centerPoint, pS, p0);

        //                    bool reverseTri = n.Dot(normal) < 0;

        //                    if (!reverseTri)
        //                        outputMesh.AppendTriangle(center, f.Value.index, outputLine[0]);
        //                    else
        //                        outputMesh.AppendTriangle(center, outputLine[0], f.Value.index);

        //                    for (int j = 0; j < outputLine.Count - 1; j++)
        //                    {
        //                        var p1 = outputMesh.GetVertex(outputLine[j]);
        //                        var p2 = outputMesh.GetVertex(outputLine[j + 1]);

        //                        listLines.Add(new g3.Line3d(p1, p2 - p1));
        //                        polyline.AppendVertex(p2);

        //                        if (!reverseTri)
        //                            outputMesh.AppendTriangle(center, outputLine[j], outputLine[j + 1]);
        //                        else
        //                            outputMesh.AppendTriangle(center, outputLine[j + 1], outputLine[j]);
        //                    }

        //                    polyline.AppendVertex(pS);
        //                    listLines.Add(new g3.Line3d(pE, pS - pE));

        //                    listPolylines.Add(polyline);

        //                    if (!reverseTri)
        //                        outputMesh.AppendTriangle(center, outputLine[outputLine.Count - 1], f.Value.index);
        //                    else
        //                        outputMesh.AppendTriangle(center, f.Value.index, outputLine[outputLine.Count - 1]);
        //                }
        //            }
        //        }

        //    }
        //}

        public static void VoronoiMesh(g3.DMesh3 mesh, out g3.DMesh3 outputMesh, out List <g3.Line3d> listLines, out List <g3.PolyLine3d> listPolylines)
        {
            System.Collections.Generic.SortedDictionary <int, MeshNode> faces = new System.Collections.Generic.SortedDictionary <int, MeshNode>();

            int index = 0;

            foreach (var meshFaceIndex in mesh.TriangleIndices())
            {
                var frame = mesh.GetTriFrame(meshFaceIndex);

                g3.Index3i neighbors    = mesh.GetTriNeighbourTris(meshFaceIndex);
                g3.Index3i vertex_index = mesh.GetTriangle(meshFaceIndex);

                faces.Add(meshFaceIndex, new MeshNode(index++, meshFaceIndex, frame, neighbors, vertex_index));
            }


            foreach (var f in faces)
            {
                f.Value.neighbors.Clear();
                f.Value.neighbors.Capacity = 3;
                for (int i = 0; i < 3; ++i)
                {
                    int fn = f.Value.neighbors_index[i];
                    if (fn >= 0)
                    {
                        f.Value.neighbors.Add(faces[fn]);
                    }
                }

                if (f.Value.neighbors.Count < 3)
                {
                    f.Value.locked = true;

                    foreach (var n in f.Value.neighbors)
                    {
                        n.locked = true;
                    }
                }
            }

            outputMesh    = new g3.DMesh3(g3.MeshComponents.None);
            listLines     = new List <g3.Line3d>();
            listPolylines = new List <g3.PolyLine3d>();
            foreach (var f in faces)
            {
                outputMesh.AppendVertex(f.Value.frame.Origin);
            }

            HashSet <int> processedPoints = new HashSet <int>();

            foreach (var f in faces)
            {
                for (int i = 0; i < 3; i++)
                {
                    List <int> outputLine = new List <int>();

                    if (processedPoints.Contains(f.Value.vertex_index[i]))
                    {
                        continue;
                    }

                    int checkVertex = f.Value.vertex_index[i];

                    MeshNode currentFaces = f.Value;
                    MeshNode prevFace     = null;

                    bool fullLoop = false;

                    while (true)
                    {
                        for (int j = 0; j < currentFaces.neighbors.Count; j++)
                        {
                            var neighbor = currentFaces.neighbors[j];
                            if (neighbor.UsesVertex(checkVertex))
                            {
                                if (neighbor == prevFace)
                                {
                                    continue;
                                }

                                if (neighbor == f.Value)
                                {
                                    fullLoop = true;
                                    break; // Found full loop
                                }

                                outputLine.Add(neighbor.index);

                                prevFace     = currentFaces;
                                currentFaces = neighbor;
                                j            = -1;
                            }
                        }

                        break;
                    }

                    if (fullLoop)
                    {
                        processedPoints.Add(checkVertex);

                        var polyline = new g3.PolyLine3d();

                        if (outputLine.Count > 2)
                        {
                            g3.Vector3d centerPoint = f.Value.frame.Origin;

                            foreach (var p in outputLine)
                            {
                                centerPoint += outputMesh.GetVertex(p);
                            }

                            centerPoint /= (outputLine.Count + 1);

                            int center = outputMesh.AppendVertex(centerPoint);

                            var pS = outputMesh.GetVertex(f.Value.index);
                            var p0 = outputMesh.GetVertex(outputLine[0]);
                            var pE = outputMesh.GetVertex(outputLine[outputLine.Count - 1]);

                            var normal = mesh.GetTriNormal(f.Value.meshIndex);

                            polyline.AppendVertex(pS);
                            polyline.AppendVertex(p0);

                            listLines.Add(new g3.Line3d(pS, p0 - pS));

                            var n = MathUtil.Normal(centerPoint, pS, p0);

                            bool reverseTri = n.Dot(normal) < 0;

                            if (!reverseTri)
                            {
                                outputMesh.AppendTriangle(center, f.Value.index, outputLine[0]);
                            }
                            else
                            {
                                outputMesh.AppendTriangle(center, outputLine[0], f.Value.index);
                            }

                            for (int j = 0; j < outputLine.Count - 1; j++)
                            {
                                var p1 = outputMesh.GetVertex(outputLine[j]);
                                var p2 = outputMesh.GetVertex(outputLine[j + 1]);

                                listLines.Add(new g3.Line3d(p1, p2 - p1));
                                polyline.AppendVertex(p2);

                                if (!reverseTri)
                                {
                                    outputMesh.AppendTriangle(center, outputLine[j], outputLine[j + 1]);
                                }
                                else
                                {
                                    outputMesh.AppendTriangle(center, outputLine[j + 1], outputLine[j]);
                                }
                            }

                            polyline.AppendVertex(pS);
                            listLines.Add(new g3.Line3d(pE, pS - pE));

                            listPolylines.Add(polyline);

                            if (!reverseTri)
                            {
                                outputMesh.AppendTriangle(center, outputLine[outputLine.Count - 1], f.Value.index);
                            }
                            else
                            {
                                outputMesh.AppendTriangle(center, f.Value.index, outputLine[outputLine.Count - 1]);
                            }
                        }
                    }
                }
            }
        }
Пример #5
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);
        }
Пример #6
0
        public void FindConnectedT()
        {
            Components = new List <Component>();

            int NT = Mesh.MaxTriangleID;

            // [TODO] could use Euler formula to determine if mesh is closed genus-0...

            Func <int, bool> filter_func = (i) => { return(Mesh.IsTriangle(i)); };

            if (FilterF != null)
            {
                filter_func = (i) => { return(Mesh.IsTriangle(i) && FilterF(i)); }
            }
            ;



            // initial active set contains all valid triangles
            byte[]     active      = new byte[Mesh.MaxTriangleID];
            Interval1i activeRange = Interval1i.Empty;

            if (FilterSet != null)
            {
                for (int i = 0; i < NT; ++i)
                {
                    active[i] = 255;
                }
                foreach (int tid in FilterSet)
                {
                    bool bValid = filter_func(tid);
                    if (bValid)
                    {
                        active[tid] = 0;
                        activeRange.Contain(tid);
                    }
                }
            }
            else
            {
                for (int i = 0; i < NT; ++i)
                {
                    bool bValid = filter_func(i);
                    if (bValid)
                    {
                        active[i] = 0;
                        activeRange.Contain(i);
                    }
                    else
                    {
                        active[i] = 255;
                    }
                }
            }

            // temporary buffers
            List <int> queue    = new List <int>(NT / 10);
            List <int> cur_comp = new List <int>(NT / 10);

            // keep finding valid seed triangles and growing connected components
            // until we are done
            IEnumerable <int> range = (FilterSet != null) ? FilterSet : activeRange;

            foreach (int i in range)
            {
                //for ( int i = 0; i < NT; ++i ) {
                if (active[i] == 255)
                {
                    continue;
                }

                int seed_t = i;
                if (SeedFilterF != null && SeedFilterF(seed_t) == false)
                {
                    continue;
                }

                queue.Add(seed_t);
                active[seed_t] = 1;      // in queue

                while (queue.Count > 0)
                {
                    int cur_t = queue[queue.Count - 1];
                    queue.RemoveAt(queue.Count - 1);

                    active[cur_t] = 2;   // tri has been processed
                    cur_comp.Add(cur_t);

                    Index3i nbrs = Mesh.GetTriNeighbourTris(cur_t);
                    for (int j = 0; j < 3; ++j)
                    {
                        int nbr_t = nbrs[j];
                        if (nbr_t != DMesh3.InvalidID && active[nbr_t] == 0)
                        {
                            queue.Add(nbr_t);
                            active[nbr_t] = 1;           // in queue
                        }
                    }
                }


                Component comp = new Component()
                {
                    Indices = cur_comp.ToArray()
                };
                Components.Add(comp);

                // remove tris in this component from active set
                for (int j = 0; j < comp.Indices.Length; ++j)
                {
                    active[comp.Indices[j]] = 255;
                }

                cur_comp.Clear();
                queue.Clear();
            }
        }
Пример #7
0
 public static bool is_ordered(int a, int b, ref Index3i tri_verts)
 {
     return((tri_verts.a == a && tri_verts.b == b) ||
            (tri_verts.b == a && tri_verts.c == b) ||
            (tri_verts.c == a && tri_verts.a == b));
 }
Пример #8
0
 public static int find_tri_ordered_edge(int a, int b, Index3i tri_verts)
 {
     return(find_tri_ordered_edge(a, b, ref tri_verts));
 }
Пример #9
0
        // Remove a tID from the mesh. Also removes any unreferenced edges after tri is removed.
        // If bRemoveIsolatedVertices is false, then if you remove all tris from a vert, that vert is also removed.
        // If bPreserveManifold, we check that you will not create a bowtie vertex (and return false).
        //   If this check is not done, you have to make sure you don't create a bowtie, because other
        //   code assumes we don't have bowties, and will not handle it properly
        public bool RemoveTriangle(int tID, bool bRemoveIsolatedVertices = true, bool bPreserveManifold = true)
        {
            if (!triangles_refcount.isValid(tID))
            {
                Debug.Assert(false);
                return(false);
            }

            Index3i tv = GetTriangle(tID);
            Index3i te = GetTriEdges(tID);

            // if any tri vtx is a boundary vtx connected to two interior edges, then
            // we cannot remove this triangle because it would create a bowtie vertex!
            // (that vtx already has 2 boundary edges, and we would add two more)
            if (bPreserveManifold)
            {
                for (int j = 0; j < 3; ++j)
                {
                    if (vertex_is_boundary(tv[j]))
                    {
                        if (edge_is_boundary(te[j]) == false && edge_is_boundary(te[(j + 2) % 3]) == false)
                        {
                            return(false);
                        }
                    }
                }
            }

            // Remove triangle from its edges. if edge has no triangles left,
            // then it is removed.
            for (int j = 0; j < 3; ++j)
            {
                int eid = te[j];
                replace_edge_triangle(eid, tID, InvalidID);
                if (edges[4 * eid + 2] == InvalidID)
                {
                    int        a       = edges[4 * eid];
                    List <int> edges_a = vertex_edges[a];
                    edges_a.Remove(eid);

                    int        b       = edges[4 * eid + 1];
                    List <int> edges_b = vertex_edges[b];
                    edges_b.Remove(eid);

                    edges_refcount.decrement(eid);
                }
            }

            // free this triangle
            triangles_refcount.decrement(tID);
            Debug.Assert(triangles_refcount.isValid(tID) == false);

            // Decrement vertex refcounts. If any hit 1 and we got remove-isolated flag,
            // we need to remove that vertex
            for (int j = 0; j < 3; ++j)
            {
                int vid = tv[j];
                vertices_refcount.decrement(vid);
                if (bRemoveIsolatedVertices && vertices_refcount.refCount(vid) == 1)
                {
                    vertices_refcount.decrement(vid);
                    Debug.Assert(vertices_refcount.isValid(vid) == false);
                    vertex_edges[vid] = null;
                }
            }

            updateTimeStamp();
            return(true);
        }
Пример #10
0
        public MeshResult CollapseEdge(int vKeep, int vRemove, out EdgeCollapseInfo collapse)
        {
            collapse = new EdgeCollapseInfo();

            if (IsVertex(vKeep) == false || IsVertex(vRemove) == false)
            {
                return(MeshResult.Failed_NotAnEdge);
            }

            int        b       = vKeep;         // renaming for sanity. We remove a and keep b
            int        a       = vRemove;
            List <int> edges_b = vertex_edges[b];

            int eab = find_edge(a, b);

            if (eab == InvalidID)
            {
                return(MeshResult.Failed_NotAnEdge);
            }

            int     t0   = edges[4 * eab + 2];
            Index3i T0tv = GetTriangle(t0);
            int     c    = IndexUtil.find_tri_other_vtx(a, b, T0tv);

            // look up opposing triangle/vtx if we are not in boundary case
            bool bIsBoundaryEdge = false;
            int  d  = InvalidID;
            int  t1 = edges[4 * eab + 3];

            if (t1 != InvalidID)
            {
                Index3i T1tv = GetTriangle(t1);
                d = IndexUtil.find_tri_other_vtx(a, b, T1tv);
                if (c == d)
                {
                    return(MeshResult.Failed_FoundDuplicateTriangle);
                }
            }
            else
            {
                bIsBoundaryEdge = true;
            }

            // We cannot collapse if edge lists of a and b share vertices other
            //  than c and d  (because then we will make a triangle [x b b].
            //  Unfortunately I cannot see a way to do this more efficiently than brute-force search
            //  [TODO] if we had tri iterator for a, couldn't we check each tri for b  (skipping t0 and t1) ?
            List <int> edges_a       = vertex_edges[a];
            int        edges_a_count = 0;

            foreach (int eid_a in edges_a)
            {
                int vax = edge_other_v(eid_a, a);
                edges_a_count++;
                if (vax == b || vax == c || vax == d)
                {
                    continue;
                }
                foreach (int eid_b in edges_b)
                {
                    if (edge_other_v(eid_b, b) == vax)
                    {
                        return(MeshResult.Failed_InvalidNeighbourhood);
                    }
                }
            }


            // We cannot collapse if we have a tetrahedron. In this case a has 3 nbr edges,
            //  and edge cd exists. But that is not conclusive, we also have to check that
            //  cd is an internal edge, and that each of its tris contain a or b
            if (edges_a_count == 3 && bIsBoundaryEdge == false)
            {
                int edc   = find_edge(d, c);
                int edc_i = 4 * edc;
                if (edc != InvalidID && edges[edc_i + 3] != InvalidID)
                {
                    int edc_t0 = edges[edc_i + 2];
                    int edc_t1 = edges[edc_i + 3];

                    if ((tri_has_v(edc_t0, a) && tri_has_v(edc_t1, b)) ||
                        (tri_has_v(edc_t0, b) && tri_has_v(edc_t1, a)))
                    {
                        return(MeshResult.Failed_CollapseTetrahedron);
                    }
                }
            }
            else if (edges_a_count == 2 && bIsBoundaryEdge == true)
            {
                // cannot collapse edge if we are down to a single triangle
                if (edges_b.Count == 2 && vertex_edges[c].Count == 2)
                {
                    return(MeshResult.Failed_CollapseTriangle);
                }
            }

            // [RMS] this was added from C++ version...seems like maybe I never hit
            //   this case? Conceivably could be porting bug but looking at the
            //   C++ code I cannot see how we could possibly have caught this case...
            //
            // cannot collapse an edge where both vertices are boundary vertices
            // because that would create a bowtie
            //
            // NOTE: potentially scanning all edges here...couldn't we
            //  pick up eac/bc/ad/bd as we go? somehow?
            if (bIsBoundaryEdge == false && vertex_is_boundary(a) && vertex_is_boundary(b))
            {
                return(MeshResult.Failed_InvalidNeighbourhood);
            }


            // 1) remove edge ab from vtx b
            // 2) find edges ad and ac, and tris tad, tac across those edges  (will use later)
            // 3) for other edges, replace a with b, and add that edge to b
            // 4) replace a with b in all triangles connected to a
            int ead = InvalidID, eac = InvalidID;
            int tad = InvalidID, tac = InvalidID;

            foreach (int eid in edges_a)
            {
                int o = edge_other_v(eid, a);
                if (o == b)
                {
                    if (edges_b.Remove(eid) != true)
                    {
                        debug_fail("remove case o == b");
                    }
                }
                else if (o == c)
                {
                    eac = eid;
                    if (vertex_edges[c].Remove(eid) != true)
                    {
                        debug_fail("remove case o == c");
                    }
                    tac = edge_other_t(eid, t0);
                }
                else if (o == d)
                {
                    ead = eid;
                    if (vertex_edges[d].Remove(eid) != true)
                    {
                        debug_fail("remove case o == c, step 1");
                    }
                    tad = edge_other_t(eid, t1);
                }
                else
                {
                    if (replace_edge_vertex(eid, a, b) == -1)
                    {
                        debug_fail("remove case else");
                    }
                    edges_b.Add(eid);
                }

                // [TODO] perhaps we can already have unique tri list because of the manifold-nbrhood check we need to do...
                for (int j = 0; j < 2; ++j)
                {
                    int t_j = edges[4 * eid + 2 + j];
                    if (t_j != InvalidID && t_j != t0 && t_j != t1)
                    {
                        if (tri_has_v(t_j, a))
                        {
                            if (replace_tri_vertex(t_j, a, b) == -1)
                            {
                                debug_fail("remove last check");
                            }
                            vertices_refcount.increment(b);
                            vertices_refcount.decrement(a);
                        }
                    }
                }
            }

            int ebc = InvalidID, ebd = InvalidID;

            if (bIsBoundaryEdge == false)
            {
                // remove all edges from vtx a, then remove vtx a
                edges_a.Clear();
                Debug.Assert(vertices_refcount.refCount(a) == 3);                               // in t0,t1, and initial ref
                vertices_refcount.decrement(a, 3);
                Debug.Assert(vertices_refcount.isValid(a) == false);

                // remove triangles T0 and T1, and update b/c/d refcounts
                triangles_refcount.decrement(t0);
                triangles_refcount.decrement(t1);
                vertices_refcount.decrement(c);
                vertices_refcount.decrement(d);
                vertices_refcount.decrement(b, 2);
                Debug.Assert(triangles_refcount.isValid(t0) == false);
                Debug.Assert(triangles_refcount.isValid(t1) == false);

                // remove edges ead, eab, eac
                edges_refcount.decrement(ead);
                edges_refcount.decrement(eab);
                edges_refcount.decrement(eac);
                Debug.Assert(edges_refcount.isValid(ead) == false);
                Debug.Assert(edges_refcount.isValid(eab) == false);
                Debug.Assert(edges_refcount.isValid(eac) == false);

                // replace t0 and t1 in edges ebd and ebc that we kept
                ebd = find_edge(b, d);
                ebc = find_edge(b, c);

                if (replace_edge_triangle(ebd, t1, tad) == -1)
                {
                    debug_fail("isboundary=false branch, ebd replace triangle");
                }

                if (replace_edge_triangle(ebc, t0, tac) == -1)
                {
                    debug_fail("isboundary=false branch, ebc replace triangle");
                }

                // update tri-edge-nbrs in tad and tac
                if (tad != InvalidID)
                {
                    if (replace_triangle_edge(tad, ead, ebd) == -1)
                    {
                        debug_fail("isboundary=false branch, ebd replace triangle");
                    }
                }
                if (tac != InvalidID)
                {
                    if (replace_triangle_edge(tac, eac, ebc) == -1)
                    {
                        debug_fail("isboundary=false branch, ebd replace triangle");
                    }
                }
            }
            else
            {
                //  this is basically same code as above, just not referencing t1/d

                // remove all edges from vtx a, then remove vtx a
                edges_a.Clear();
                Debug.Assert(vertices_refcount.refCount(a) == 2);                               // in t0 and initial ref
                vertices_refcount.decrement(a, 2);
                Debug.Assert(vertices_refcount.isValid(a) == false);

                // remove triangle T0 and update b/c refcounts
                triangles_refcount.decrement(t0);
                vertices_refcount.decrement(c);
                vertices_refcount.decrement(b);
                Debug.Assert(triangles_refcount.isValid(t0) == false);

                // remove edges eab and eac
                edges_refcount.decrement(eab);
                edges_refcount.decrement(eac);
                Debug.Assert(edges_refcount.isValid(eab) == false);
                Debug.Assert(edges_refcount.isValid(eac) == false);

                // replace t0 in edge ebc that we kept
                ebc = find_edge(b, c);
                if (replace_edge_triangle(ebc, t0, tac) == -1)
                {
                    debug_fail("isboundary=false branch, ebc replace triangle");
                }

                // update tri-edge-nbrs in tac
                if (tac != InvalidID)
                {
                    if (replace_triangle_edge(tac, eac, ebc) == -1)
                    {
                        debug_fail("isboundary=true branch, ebd replace triangle");
                    }
                }
            }

            collapse.vKept       = vKeep;
            collapse.vRemoved    = vRemove;
            collapse.bIsBoundary = bIsBoundaryEdge;
            collapse.eCollapsed  = eab;
            collapse.tRemoved0   = t0; collapse.tRemoved1 = t1;
            collapse.eRemoved0   = eac; collapse.eRemoved1 = ead;
            collapse.eKept0      = ebc; collapse.eKept1 = ebd;

            updateTimeStamp();
            return(MeshResult.Ok);
        }
Пример #11
0
        public MeshResult SplitEdge(int eab, out EdgeSplitInfo split)
        {
            split = new EdgeSplitInfo();
            if (!IsEdge(eab))
            {
                return(MeshResult.Failed_NotAnEdge);
            }

            // look up primary edge & triangle
            int     eab_i = 4 * eab;
            int     a = edges[eab_i], b = edges[eab_i + 1];
            int     t0   = edges[eab_i + 2];
            Index3i T0tv = GetTriangle(t0);

            int[] T0tv_array = T0tv.array;
            int   c          = IndexUtil.orient_tri_edge_and_find_other_vtx(ref a, ref b, T0tv_array);

            // create new vertex
            Vector3d vNew = 0.5 * (GetVertex(a) + GetVertex(b));
            int      f    = AppendVertex(vNew);

            // quite a bit of code is duplicated between boundary and non-boundary case, but it
            //  is too hard to follow later if we factor it out...
            if (edge_is_boundary(eab))
            {
                // look up edge bc, which needs to be modified
                Index3i T0te = GetTriEdges(t0);
                int     ebc  = T0te[IndexUtil.find_edge_index_in_tri(b, c, T0tv_array)];

                // rewrite existing triangle
                replace_tri_vertex(t0, b, f);

                // add new second triangle
                int t2 = add_triangle_only(f, b, c, InvalidID, InvalidID, InvalidID);
                if (triangle_groups != null)
                {
                    triangle_groups.insert(triangle_groups[t0], t2);
                }

                // rewrite edge bc, create edge af
                replace_edge_triangle(ebc, t0, t2);
                int eaf = eab;
                replace_edge_vertex(eaf, b, f);
                vertex_edges[b].Remove(eab);
                vertex_edges[f].Add(eaf);

                // create new edges fb and fc
                int efb = add_edge(f, b, t2);
                int efc = add_edge(f, c, t0, t2);

                // update triangle edge-nbrs
                replace_triangle_edge(t0, ebc, efc);
                set_triangle_edges(t2, efb, ebc, efc);

                // update vertex refcounts
                vertices_refcount.increment(c);
                vertices_refcount.increment(f, 2);

                split.bIsBoundary = true;
                split.vNew        = f;
                split.eNew        = efb;

                updateTimeStamp();
                return(MeshResult.Ok);
            }
            else                                // interior triangle branch

            // look up other triangle
            {
                int     t1         = edges[eab_i + 3];
                Index3i T1tv       = GetTriangle(t1);
                int[]   T1tv_array = T1tv.array;
                int     d          = IndexUtil.find_tri_other_vtx(a, b, T1tv_array);

                // look up edges that we are going to need to update
                // [TODO OPT] could use ordering to reduce # of compares here
                Index3i T0te = GetTriEdges(t0);
                int     ebc  = T0te[IndexUtil.find_edge_index_in_tri(b, c, T0tv_array)];
                Index3i T1te = GetTriEdges(t1);
                int     edb  = T1te[IndexUtil.find_edge_index_in_tri(d, b, T1tv_array)];

                // rewrite existing triangles
                replace_tri_vertex(t0, b, f);
                replace_tri_vertex(t1, b, f);

                // add two new triangles to close holes we just created
                int t2 = add_triangle_only(f, b, c, InvalidID, InvalidID, InvalidID);
                int t3 = add_triangle_only(f, d, b, InvalidID, InvalidID, InvalidID);
                if (triangle_groups != null)
                {
                    triangle_groups.insert(triangle_groups[t0], t2);
                    triangle_groups.insert(triangle_groups[t1], t3);
                }

                // update the edges we found above, to point to new triangles
                replace_edge_triangle(ebc, t0, t2);
                replace_edge_triangle(edb, t1, t3);

                // edge eab became eaf
                int eaf = eab;                 //Edge * eAF = eAB;
                replace_edge_vertex(eaf, b, f);

                // update a/b/f vertex-edges
                vertex_edges[b].Remove(eab);
                vertex_edges[f].Add(eaf);

                // create new edges connected to f  (also updates vertex-edges)
                int efb = add_edge(f, b, t2, t3);
                int efc = add_edge(f, c, t0, t2);
                int edf = add_edge(d, f, t1, t3);

                // update triangle edge-nbrs
                replace_triangle_edge(t0, ebc, efc);
                replace_triangle_edge(t1, edb, edf);
                set_triangle_edges(t2, efb, ebc, efc);
                set_triangle_edges(t3, edf, edb, efb);

                // update vertex refcounts
                vertices_refcount.increment(c);
                vertices_refcount.increment(d);
                vertices_refcount.increment(f, 4);

                split.bIsBoundary = false;
                split.vNew        = f;
                split.eNew        = efb;

                updateTimeStamp();
                return(MeshResult.Ok);
            }
        }
Пример #12
0
        /// <summary>
        /// 1) Find intersection segments
        /// 2) sort onto existing input mesh vtx/edge/face
        /// </summary>
        void find_segments()
        {
            var SegVtxMap = new Dictionary <Vector3d, SegmentVtx>();

            // find intersection segments
            // TODO: intersection polygons
            // TODO: do we need to care about intersection vertices?
            var targetSpatial = new DMeshAABBTree3(Target, true);
            var cutSpatial    = new DMeshAABBTree3(CutMesh, true);
            var intersections = targetSpatial.FindAllIntersections(cutSpatial);

            // for each segment, for each vtx, determine if it is
            // at an existing vertex, on-edge, or in-face
            Segments = new IntersectSegment[intersections.Segments.Count];
            for (int i = 0; i < Segments.Length; ++i)
            {
                var isect  = intersections.Segments[i];
                var points = new Vector3dTuple2(isect.point0, isect.point1);
                var iseg   = new IntersectSegment()
                {
                    base_tid = isect.t0
                };
                Segments[i] = iseg;
                for (int j = 0; j < 2; ++j)
                {
                    Vector3d v = points[j];

                    // if this exact vtx coord has been seen, use same vtx
                    SegmentVtx sv;
                    if (SegVtxMap.TryGetValue(v, out sv))
                    {
                        iseg[j] = sv;
                        continue;
                    }
                    sv = new SegmentVtx()
                    {
                        v = v
                    };
                    SegVertices.Add(sv);
                    SegVtxMap[v] = sv;
                    iseg[j]      = sv;

                    // this vtx is tol-equal to input mesh vtx
                    int existing_v = find_existing_vertex(isect.point0);
                    if (existing_v >= 0)
                    {
                        sv.initial_type           = sv.type = 0;
                        sv.elem_id                = existing_v;
                        sv.vtx_id                 = existing_v;
                        VIDToSegVtxMap[sv.vtx_id] = sv;
                        continue;
                    }

                    var tri = new Triangle3d();
                    Target.GetTriVertices(isect.t0, ref tri.V0, ref tri.V1, ref tri.V2);
                    Index3i tv = Target.GetTriangle(isect.t0);

                    // this vtx is tol-on input mesh edge
                    int on_edge_i = on_edge(ref tri, ref v);
                    if (on_edge_i >= 0)
                    {
                        sv.initial_type = sv.type = 1;
                        sv.elem_id      = Target.FindEdge(tv[on_edge_i], tv[(on_edge_i + 1) % 3]);
                        Util.gDevAssert(sv.elem_id != DMesh3.InvalidID);
                        add_edge_vtx(sv.elem_id, sv);
                        continue;
                    }

                    // otherwise contained in input mesh face
                    sv.initial_type = sv.type = 2;
                    sv.elem_id      = isect.t0;
                    add_face_vtx(sv.elem_id, sv);
                }
            }
        }
        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 (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 (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 (WantGraphEdgeInfo)
                        {
                            add_edge_edge(graph_eid, tid, new Index2i(triEdges[e0], triEdges[e1]), new Index2i(ev0, ev1));
                        }
                    }
                }
            }


            Vertices = null;
        }
Пример #14
0
        // This function checks that the mesh is well-formed, ie all internal data
        // structures are consistent
        public bool CheckValidity(bool bAllowNonManifoldVertices = false)
        {
            int[] triToVtxRefs = new int[this.MaxVertexID];

            if (normals != null)
            {
                DMESH_CHECK_OR_FAIL(normals.size == vertices.size);
            }
            if (colors != null)
            {
                DMESH_CHECK_OR_FAIL(colors.size == vertices.size);
            }
            if (uv != null)
            {
                DMESH_CHECK_OR_FAIL(uv.size / 2 == vertices.size / 3);
            }
            if (triangle_groups != null)
            {
                DMESH_CHECK_OR_FAIL(triangle_groups.size == triangles.size / 3);
            }

            foreach (int tID in TriangleIndices())
            {
                DMESH_CHECK_OR_FAIL(IsTriangle(tID));
                DMESH_CHECK_OR_FAIL(triangles_refcount.refCount(tID) == 1);

                // vertices must exist
                Index3i tv = GetTriangle(tID);
                for (int j = 0; j < 3; ++j)
                {
                    DMESH_CHECK_OR_FAIL(IsVertex(tv[j]));
                    triToVtxRefs[tv[j]] += 1;
                }

                // edges must exist and reference this tri
                Index3i e = new Index3i();
                for (int j = 0; j < 3; ++j)
                {
                    int a = tv[j], b = tv[(j + 1) % 3];
                    e[j] = FindEdge(a, b);
                    DMESH_CHECK_OR_FAIL(e[j] != InvalidID);
                    DMESH_CHECK_OR_FAIL(edge_has_t(e[j], tID));
                    DMESH_CHECK_OR_FAIL(e[j] == FindEdgeFromTri(a, b, tID));
                }
                DMESH_CHECK_OR_FAIL(e[0] != e[1] && e[0] != e[2] && e[1] != e[2]);

                // tri nbrs must exist and reference this tri, or same edge must be boundary edge
                Index3i te = GetTriEdges(tID);
                for (int j = 0; j < 3; ++j)
                {
                    int eid = te[j];
                    DMESH_CHECK_OR_FAIL(IsEdge(eid));
                    int tOther = edge_other_t(eid, tID);
                    if (tOther == InvalidID)
                    {
                        DMESH_CHECK_OR_FAIL(tri_is_boundary(tID));
                        continue;
                    }

                    DMESH_CHECK_OR_FAIL(tri_has_neighbour_t(tOther, tID) == true);

                    // edge must have same two verts as tri for same index
                    int     a = tv[j], b = tv[(j + 1) % 3];
                    Index2i ev = GetEdgeV(te[j]);
                    DMESH_CHECK_OR_FAIL(IndexUtil.same_pair_unordered(a, b, ev[0], ev[1]));

                    // also check that nbr edge has opposite orientation
                    Index3i othertv = GetTriangle(tOther);
                    int     found   = IndexUtil.find_tri_ordered_edge(b, a, othertv.array);
                    DMESH_CHECK_OR_FAIL(found != InvalidID);
                }
            }


            // edge verts/tris must exist
            foreach (int eID in EdgeIndices())
            {
                DMESH_CHECK_OR_FAIL(IsEdge(eID));
                DMESH_CHECK_OR_FAIL(edges_refcount.refCount(eID) == 1);
                Index2i ev = GetEdgeV(eID);
                Index2i et = GetEdgeT(eID);
                DMESH_CHECK_OR_FAIL(IsVertex(ev[0]));
                DMESH_CHECK_OR_FAIL(IsVertex(ev[1]));
                DMESH_CHECK_OR_FAIL(ev[0] < ev[1]);
                DMESH_CHECK_OR_FAIL(IsTriangle(et[0]));
                if (et[1] != InvalidID)
                {
                    DMESH_CHECK_OR_FAIL(IsTriangle(et[1]));
                }
            }

            // verify compact check
            bool is_compact = vertices_refcount.is_dense;

            for (int vid = 0; vid < vertices.Length; ++vid)
            {
                DMESH_CHECK_OR_FAIL(vertices_refcount.isValid(vid));
            }

            // vertex edges must exist and reference this vert
            foreach (int vID in VertexIndices())
            {
                DMESH_CHECK_OR_FAIL(IsVertex(vID));
                List <int> l = vertex_edges[vID];
                foreach (int edgeid in l)
                {
                    DMESH_CHECK_OR_FAIL(IsEdge(edgeid));
                    DMESH_CHECK_OR_FAIL(edge_has_v(edgeid, vID));

                    int otherV = edge_other_v(edgeid, vID);
                    int e2     = find_edge(vID, otherV);
                    DMESH_CHECK_OR_FAIL(e2 != InvalidID);
                    DMESH_CHECK_OR_FAIL(e2 == edgeid);
                    e2 = find_edge(otherV, vID);
                    DMESH_CHECK_OR_FAIL(e2 != InvalidID);
                    DMESH_CHECK_OR_FAIL(e2 == edgeid);
                }

                List <int> vTris = new List <int>(), vTris2 = new List <int>();
                GetVtxTriangles(vID, vTris, false);
                GetVtxTriangles(vID, vTris2, true);
                DMESH_CHECK_OR_FAIL(vTris.Count == vTris2.Count);
                //System.Console.WriteLine(string.Format("{0} {1} {2}", vID, vTris.Count, GetVtxEdges(vID).Count));
                if (bAllowNonManifoldVertices)
                {
                    DMESH_CHECK_OR_FAIL(vTris.Count <= GetVtxEdges(vID).Count);
                }
                else
                {
                    DMESH_CHECK_OR_FAIL(vTris.Count == GetVtxEdges(vID).Count || vTris.Count == GetVtxEdges(vID).Count - 1);
                }
                DMESH_CHECK_OR_FAIL(vertices_refcount.refCount(vID) == vTris.Count + 1);
                DMESH_CHECK_OR_FAIL(triToVtxRefs[vID] == vTris.Count);
                foreach (int tID in vTris)
                {
                    DMESH_CHECK_OR_FAIL(tri_has_v(tID, vID));
                }

                // check that edges around vert only references tris above, and reference all of them!
                List <int> vRemoveTris = new List <int>(vTris);
                foreach (int edgeid in l)
                {
                    Index2i edget = GetEdgeT(edgeid);
                    DMESH_CHECK_OR_FAIL(vTris.Contains(edget[0]));
                    if (edget[1] != InvalidID)
                    {
                        DMESH_CHECK_OR_FAIL(vTris.Contains(edget[1]));
                    }
                    vRemoveTris.Remove(edget[0]);
                    if (edget[1] != InvalidID)
                    {
                        vRemoveTris.Remove(edget[1]);
                    }
                }
                DMESH_CHECK_OR_FAIL(vRemoveTris.Count == 0);
            }
            return(true);
        }
Пример #15
0
        // insert point at bary_coords inside tid. If point is at vtx, just use that vtx.
        // If it is on an edge, do an edge split. Otherwise poke face.
        int insert_corner_from_bary(int iCorner, int tid, Vector3d bary_coords,
                                    double bary_tol, double spatial_tol, out bool is_existing_v)
        {
            is_existing_v = false;
            Vector2d vInsert = Curve[iCorner];
            Index3i  tv      = Mesh.GetTriangle(tid);

            // handle cases where corner is on a vertex
            int cornerv = -1;

            if (bary_coords.x > 1 - bary_tol)
            {
                cornerv = tv.a;
            }
            else if (bary_coords.y > 1 - bary_tol)
            {
                cornerv = tv.b;
            }
            else if (bary_coords.z > 1 - bary_tol)
            {
                cornerv = tv.c;
            }
            if (cornerv != -1 && PointF(cornerv).Distance(vInsert) < spatial_tol)
            {
                is_existing_v = true;
                return(cornerv);
            }

            // handle cases where corner is on an edge
            int split_edge = -1;

            if (bary_coords.x < bary_tol)
            {
                split_edge = 1;
            }
            else if (bary_coords.y < bary_tol)
            {
                split_edge = 2;
            }
            else if (bary_coords.z < bary_tol)
            {
                split_edge = 0;
            }
            if (split_edge >= 0)
            {
                int eid = Mesh.GetTriEdge(tid, split_edge);

                Index2i   ev  = Mesh.GetEdgeV(eid);
                Segment2d seg = new Segment2d(PointF(ev.a), PointF(ev.b));
                if (seg.DistanceSquared(vInsert) < spatial_tol * spatial_tol)
                {
                    Index2i et = Mesh.GetEdgeT(eid);
                    spatial_remove_triangles(et.a, et.b);

                    DMesh3.EdgeSplitInfo split_info;
                    MeshResult           splitResult = Mesh.SplitEdge(eid, out split_info);
                    if (splitResult != MeshResult.Ok)
                    {
                        throw new Exception("MeshInsertUVPolyCurve.insert_corner_from_bary: edge split failed in case sum==2 - " + splitResult.ToString());
                    }
                    SetPointF(split_info.vNew, vInsert);

                    spatial_add_triangles(et.a, et.b);
                    spatial_add_triangles(split_info.eNewT2, split_info.eNewT3);

                    return(split_info.vNew);
                }
            }

            spatial_remove_triangle(tid);

            // otherwise corner is inside triangle
            DMesh3.PokeTriangleInfo pokeinfo;
            MeshResult result = Mesh.PokeTriangle(tid, bary_coords, out pokeinfo);

            if (result != MeshResult.Ok)
            {
                throw new Exception("MeshInsertUVPolyCurve.insert_corner_from_bary: face poke failed - " + result.ToString());
            }

            SetPointF(pokeinfo.new_vid, vInsert);

            spatial_add_triangle(tid);
            spatial_add_triangle(pokeinfo.new_t1);
            spatial_add_triangle(pokeinfo.new_t2);

            return(pokeinfo.new_vid);
        }
        // (sequentially) find each triangle that path point lies in, and insert a vertex for
        // that point into mesh.
        void insert_corners()
        {
            PrimalQuery2d query = new PrimalQuery2d(PointF);

            if (UseTriSpatial)
            {
                AxisAlignedBox3d bounds3 = Mesh.CachedBounds;
                AxisAlignedBox2d bounds2 = new AxisAlignedBox2d(bounds3.Min.xy, bounds3.Max.xy);
                triSpatial = new TriangleBinsGrid2d(bounds2, 32);
                foreach (int tid in Mesh.TriangleIndices())
                {
                    spatial_add_triangle(tid);
                }
            }

            Func <int, Vector2d, bool> inTriangleF = (tid, pos) => {
                Index3i tv           = Mesh.GetTriangle(tid);
                int     query_result = query.ToTriangleUnsigned(pos, tv.a, tv.b, tv.c);
                return(query_result == -1 || query_result == 0);
            };

            CurveVertices = new int[Curve.VertexCount];
            for (int i = 0; i < Curve.VertexCount; ++i)
            {
                Vector2d vInsert  = Curve[i];
                bool     inserted = false;

                int contain_tid = DMesh3.InvalidID;
                if (triSpatial != null)
                {
                    contain_tid = triSpatial.FindContainingTriangle(vInsert, inTriangleF);
                }
                else
                {
                    foreach (int tid in Mesh.TriangleIndices())
                    {
                        Index3i tv = Mesh.GetTriangle(tid);
                        // [RMS] using unsigned query here because we do not need to care about tri CW/CCW orientation
                        //   (right? otherwise we have to explicitly invert mesh. Nothing else we do depends on tri orientation)
                        //int query_result = query.ToTriangle(vInsert, tv.a, tv.b, tv.c);
                        int query_result = query.ToTriangleUnsigned(vInsert, tv.a, tv.b, tv.c);
                        if (query_result == -1 || query_result == 0)
                        {
                            contain_tid = tid;
                            break;
                        }
                    }
                }

                if (contain_tid != DMesh3.InvalidID)
                {
                    Index3i  tv   = Mesh.GetTriangle(contain_tid);
                    Vector3d bary = MathUtil.BarycentricCoords(vInsert, PointF(tv.a), PointF(tv.b), PointF(tv.c));
                    int      vid  = insert_corner_from_bary(i, contain_tid, bary);
                    if (vid > 0)      // this should be always happening..
                    {
                        CurveVertices[i] = vid;
                        inserted         = true;
                    }
                    else
                    {
                        throw new Exception("MeshInsertUVPolyCurve.insert_corners: failed to insert vertex " + i.ToString());
                    }
                }

                if (inserted == false)
                {
                    throw new Exception("MeshInsertUVPolyCurve.insert_corners: curve vertex "
                                        + i.ToString() + " is not inside or on any mesh triangle!");
                }
            }
        }
        // insert point at bary_coords inside tid. If point is at vtx, just use that vtx.
        // If it is on an edge, do an edge split. Otherwise poke face.
        int insert_corner_from_bary(int iCorner, int tid, Vector3d bary_coords, double tol = MathUtil.ZeroTolerance)
        {
            Vector2d vInsert = Curve[iCorner];
            Index3i  tv      = Mesh.GetTriangle(tid);

            // handle cases where corner is on a vertex
            if (bary_coords.x > 1 - tol)
            {
                return(tv.a);
            }
            else if (bary_coords.y > 1 - tol)
            {
                return(tv.b);
            }
            else if (bary_coords.z > 1 - tol)
            {
                return(tv.c);
            }

            // handle cases where corner is on an edge
            int split_edge = -1;

            if (bary_coords.x < tol)
            {
                split_edge = 1;
            }
            else if (bary_coords.y < tol)
            {
                split_edge = 2;
            }
            else if (bary_coords.z < tol)
            {
                split_edge = 0;
            }
            if (split_edge >= 0)
            {
                int eid = Mesh.GetTriEdge(tid, split_edge);

                Index2i ev = Mesh.GetEdgeT(eid);
                spatial_remove_triangles(ev.a, ev.b);

                DMesh3.EdgeSplitInfo split_info;
                MeshResult           splitResult = Mesh.SplitEdge(eid, out split_info);
                if (splitResult != MeshResult.Ok)
                {
                    throw new Exception("MeshInsertUVPolyCurve.insert_corner_from_bary: edge split failed in case sum==2 - " + splitResult.ToString());
                }
                SetPointF(split_info.vNew, vInsert);

                spatial_add_triangles(ev.a, ev.b);
                spatial_add_triangles(split_info.eNewT2, split_info.eNewT3);

                return(split_info.vNew);
            }

            spatial_remove_triangle(tid);

            // otherwise corner is inside triangle
            DMesh3.PokeTriangleInfo pokeinfo;
            MeshResult result = Mesh.PokeTriangle(tid, bary_coords, out pokeinfo);

            if (result != MeshResult.Ok)
            {
                throw new Exception("MeshInsertUVPolyCurve.insert_corner_from_bary: face poke failed - " + result.ToString());
            }

            spatial_add_triangle(tid);
            spatial_add_triangle(pokeinfo.new_t1);
            spatial_add_triangle(pokeinfo.new_t2);

            SetPointF(pokeinfo.new_vid, vInsert);
            return(pokeinfo.new_vid);
        }
Пример #18
0
        /// <summary>
        // This function checks that the mesh is well-formed, ie all internal data
        // structures are consistent
        /// </summary>
        public bool CheckValidity(bool bAllowNonManifoldVertices = false, FailMode eFailMode = FailMode.Throw)
        {
            int[] triToVtxRefs = new int[this.MaxVertexID];

            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("DMesh3.CheckValidity: check failed");
                                        }
                };
            }

            if (normals != null)
            {
                CheckOrFailF(normals.size == vertices.size);
            }

            if (colors != null)
            {
                CheckOrFailF(colors.size == vertices.size);
            }

            if (uv != null)
            {
                CheckOrFailF(uv.size / 2 == vertices.size / 3);
            }

            if (triangle_groups != null)
            {
                CheckOrFailF(triangle_groups.size == triangles.size / 3);
            }

            foreach (int tID in TriangleIndices())
            {
                CheckOrFailF(IsTriangle(tID));
                CheckOrFailF(triangles_refcount.refCount(tID) == 1);

                // vertices must exist
                Index3i tv = GetTriangle(tID);
                for (int j = 0; j < 3; ++j)
                {
                    CheckOrFailF(IsVertex(tv[j]));
                    triToVtxRefs[tv[j]] += 1;
                }

                // edges must exist and reference this tri
                var e = new Index3i();
                for (int j = 0; j < 3; ++j)
                {
                    int a = tv[j], b = tv[(j + 1) % 3];
                    e[j] = FindEdge(a, b);
                    CheckOrFailF(e[j] != InvalidID);
                    CheckOrFailF(edge_has_t(e[j], tID));
                    CheckOrFailF(e[j] == FindEdgeFromTri(a, b, tID));
                }
                CheckOrFailF(e[0] != e[1] && e[0] != e[2] && e[1] != e[2]);

                // tri nbrs must exist and reference this tri, or same edge must be boundary edge
                Index3i te = GetTriEdges(tID);
                for (int j = 0; j < 3; ++j)
                {
                    int eid = te[j];
                    CheckOrFailF(IsEdge(eid));
                    int tOther = edge_other_t(eid, tID);
                    if (tOther == InvalidID)
                    {
                        CheckOrFailF(tri_is_boundary(tID));
                        continue;
                    }

                    CheckOrFailF(tri_has_neighbour_t(tOther, tID) == true);

                    // edge must have same two verts as tri for same index
                    int     a = tv[j], b = tv[(j + 1) % 3];
                    Index2i ev = GetEdgeV(te[j]);
                    CheckOrFailF(IndexUtil.same_pair_unordered(a, b, ev[0], ev[1]));

                    // also check that nbr edge has opposite orientation
                    Index3i othertv = GetTriangle(tOther);
                    int     found   = IndexUtil.find_tri_ordered_edge(b, a, othertv.array);
                    CheckOrFailF(found != InvalidID);
                }
            }


            // edge verts/tris must exist
            foreach (int eID in EdgeIndices())
            {
                CheckOrFailF(IsEdge(eID));
                CheckOrFailF(edges_refcount.refCount(eID) == 1);
                Index2i ev = GetEdgeV(eID);
                Index2i et = GetEdgeT(eID);
                CheckOrFailF(IsVertex(ev[0]));
                CheckOrFailF(IsVertex(ev[1]));
                CheckOrFailF(et[0] != InvalidID);
                CheckOrFailF(ev[0] < ev[1]);
                CheckOrFailF(IsTriangle(et[0]));
                if (et[1] != InvalidID)
                {
                    CheckOrFailF(IsTriangle(et[1]));
                }
            }

            // verify compact check
            bool is_compact = vertices_refcount.is_dense;

            if (is_compact)
            {
                for (int vid = 0; vid < vertices.Length / 3; ++vid)
                {
                    CheckOrFailF(vertices_refcount.isValid(vid));
                }
            }

            // vertex edges must exist and reference this vert
            foreach (int vID in VertexIndices())
            {
                CheckOrFailF(IsVertex(vID));

                Vector3d v = GetVertex(vID);
                CheckOrFailF(double.IsNaN(v.LengthSquared) == false);
                CheckOrFailF(double.IsInfinity(v.LengthSquared) == false);

                foreach (int edgeid in vertex_edges.ValueItr(vID))
                {
                    CheckOrFailF(IsEdge(edgeid));
                    CheckOrFailF(edge_has_v(edgeid, vID));

                    int otherV = edge_other_v(edgeid, vID);
                    int e2     = find_edge(vID, otherV);
                    CheckOrFailF(e2 != InvalidID);
                    CheckOrFailF(e2 == edgeid);
                    e2 = find_edge(otherV, vID);
                    CheckOrFailF(e2 != InvalidID);
                    CheckOrFailF(e2 == edgeid);
                }

                foreach (int nbr_vid in VtxVerticesItr(vID))
                {
                    CheckOrFailF(IsVertex(nbr_vid));
                    int edge = find_edge(vID, nbr_vid);
                    CheckOrFailF(IsEdge(edge));
                }

                List <int> vTris = new List <int>(), vTris2 = new List <int>();
                GetVtxTriangles(vID, vTris, false);
                GetVtxTriangles(vID, vTris2, true);
                CheckOrFailF(vTris.Count == vTris2.Count);
                //System.Console.WriteLine(string.Format("{0} {1} {2}", vID, vTris.Count, GetVtxEdges(vID).Count));
                if (bAllowNonManifoldVertices)
                {
                    CheckOrFailF(vTris.Count <= GetVtxEdgeCount(vID));
                }
                else
                {
                    CheckOrFailF(vTris.Count == GetVtxEdgeCount(vID) || vTris.Count == GetVtxEdgeCount(vID) - 1);
                }

                CheckOrFailF(vertices_refcount.refCount(vID) == vTris.Count + 1);
                CheckOrFailF(triToVtxRefs[vID] == vTris.Count);
                foreach (int tID in vTris)
                {
                    CheckOrFailF(tri_has_v(tID, vID));
                }

                // check that edges around vert only references tris above, and reference all of them!
                var vRemoveTris = new List <int>(vTris);
                foreach (int edgeid in vertex_edges.ValueItr(vID))
                {
                    Index2i edget = GetEdgeT(edgeid);
                    CheckOrFailF(vTris.Contains(edget[0]));
                    if (edget[1] != InvalidID)
                    {
                        CheckOrFailF(vTris.Contains(edget[1]));
                    }

                    vRemoveTris.Remove(edget[0]);
                    if (edget[1] != InvalidID)
                    {
                        vRemoveTris.Remove(edget[1]);
                    }
                }
                CheckOrFailF(vRemoveTris.Count == 0);
            }

            return(is_ok);
        }
Пример #19
0
 public static bool orient_tri_edge(ref int a, ref int b, Index3i tri_verts)
 {
     return(orient_tri_edge(ref a, ref b, ref tri_verts));
 }
Пример #20
0
        IOReadResult BuildMeshes_ByMaterial(ReadOptions options, IMeshBuilder builder)
        {
            if (vPositions.Length == 0)
            {
                return(new IOReadResult(IOCode.GarbageDataError, "No vertices in file"));
            }
            if (vTriangles.Length == 0)
            {
                return(new IOReadResult(IOCode.GarbageDataError, "No triangles in file"));
            }

            bool bHaveNormals = (vNormals.Length > 0);
            bool bHaveColors  = (vColors.Length > 0);
            bool bHaveUVs     = (vUVs.Length > 0);

            List <int> usedMaterialIDs = new List <int>(UsedMaterials.Keys);

            usedMaterialIDs.Add(Triangle.InvalidMaterialID);
            foreach (int material_id in usedMaterialIDs)
            {
                int matID = Triangle.InvalidMaterialID;
                if (material_id != Triangle.InvalidMaterialID)
                {
                    string      sMatName = UsedMaterials[material_id];
                    OBJMaterial useMat   = Materials[sMatName];
                    matID = builder.BuildMaterial(useMat);
                }
                bool bMatHaveUVs = (material_id == Triangle.InvalidMaterialID) ? false : bHaveUVs;

                // don't append mesh until we actually see triangles
                int meshID = -1;

                Dictionary <Index3i, int> mapV = new Dictionary <Index3i, int>();

                for (int k = 0; k < vTriangles.Length; ++k)
                {
                    Triangle t = vTriangles[k];
                    if (t.nMaterialID == material_id)
                    {
                        if (meshID == -1)
                        {
                            meshID = builder.AppendNewMesh(bHaveNormals, bHaveColors, bMatHaveUVs, false);
                        }

                        Triangle t2 = new Triangle();
                        for (int j = 0; j < 3; ++j)
                        {
                            Index3i vk = new Index3i(
                                t.vIndices[j] - 1, t.vNormals[j] - 1, t.vUVs[j] - 1);

                            int use_vtx = -1;
                            if (mapV.ContainsKey(vk) == false)
                            {
                                use_vtx  = append_vertex(builder, vk, bHaveNormals, bHaveColors, bMatHaveUVs);
                                mapV[vk] = use_vtx;
                            }
                            else
                            {
                                use_vtx = mapV[vk];
                            }

                            t2.vIndices[j] = use_vtx;
                        }
                        append_triangle(builder, t2);
                    }
                }

                if (matID != Triangle.InvalidMaterialID)
                {
                    builder.AssignMaterial(matID, meshID);
                }
            }

            return(new IOReadResult(IOCode.Ok, ""));
        }
Пример #21
0
        ProcessResult ProcessEdge(int edgeID)
        {
            EdgeConstraint constraint =
                (constraints == null) ? EdgeConstraint.Unconstrained : constraints.GetEdgeConstraint(edgeID);

            if (constraint.NoModifications)
            {
                return(ProcessResult.Ignored_EdgeIsFullyConstrained);
            }

            // look up verts and tris for this edge
            int a = 0, b = 0, t0 = 0, t1 = 0;

            if (mesh.GetEdge(edgeID, ref a, ref b, ref t0, ref t1) == false)
            {
                return(ProcessResult.Failed_NotAnEdge);
            }
            bool bIsBoundaryEdge = (t1 == DMesh3.InvalidID);

            // look up 'other' verts c (from t0) and d (from t1, if it exists)
            Index3i T0tv         = mesh.GetTriangle(t0);
            int     c            = IndexUtil.find_tri_other_vtx(a, b, T0tv);
            Index3i T1tv         = (bIsBoundaryEdge) ? DMesh3.InvalidTriangle : mesh.GetTriangle(t1);
            int     d            = (bIsBoundaryEdge) ? DMesh3.InvalidID : IndexUtil.find_tri_other_vtx(a, b, T1tv);

            Vector3d vA           = mesh.GetVertex(a);
            Vector3d vB           = mesh.GetVertex(b);
            double   edge_len_sqr = (vA - vB).LengthSquared;

            begin_collapse();

            // check if we should collapse, and also find which vertex we should collapse to,
            // in cases where we have constraints/etc
            int  collapse_to  = -1;
            bool bCanCollapse = EnableCollapses &&
                                constraint.CanCollapse &&
                                edge_len_sqr < MinEdgeLength * MinEdgeLength &&
                                can_collapse_constraints(edgeID, a, b, c, d, t0, t1, out collapse_to);

            // optimization: if edge cd exists, we cannot collapse or flip. look that up here?
            //  funcs will do it internally...
            //  (or maybe we can collapse if cd exists? edge-collapse doesn't check for it explicitly...)

            // if edge length is too short, we want to collapse it
            bool bTriedCollapse = false;

            if (bCanCollapse)
            {
                int      iKeep = b, iCollapse = a;
                Vector3d vNewPos = (vA + vB) * 0.5;

                // if either vtx is fixed, collapse to that position
                if (collapse_to == b)
                {
                    vNewPos = vB;
                }
                else if (collapse_to == a)
                {
                    iKeep   = a; iCollapse = b;
                    vNewPos = vA;
                }
                else
                {
                    vNewPos = get_projected_collapse_position(iKeep, vNewPos);
                }

                // TODO be smart about picking b (keep vtx).
                //    - swap if one is bdry vtx, for example?
                // lots of cases where we cannot collapse, but we should just let
                // mesh sort that out, right?
                COUNT_COLLAPSES++;
                DMesh3.EdgeCollapseInfo collapseInfo;
                MeshResult result = mesh.CollapseEdge(iKeep, iCollapse, out collapseInfo);
                if (result == MeshResult.Ok)
                {
                    mesh.SetVertex(b, vNewPos);
                    if (constraints != null)
                    {
                        constraints.ClearEdgeConstraint(edgeID);
                        constraints.ClearEdgeConstraint(collapseInfo.eRemoved0);
                        if (collapseInfo.eRemoved1 != DMesh3.InvalidID)
                        {
                            constraints.ClearEdgeConstraint(collapseInfo.eRemoved1);
                        }
                        constraints.ClearVertexConstraint(iCollapse);
                    }
                    DoDebugChecks();

                    return(ProcessResult.Ok_Collapsed);
                }
                else
                {
                    bTriedCollapse = true;
                }
            }

            end_collapse();
            begin_flip();

            // if this is not a boundary edge, maybe we want to flip
            bool bTriedFlip = false;

            if (EnableFlips && constraint.CanFlip && bIsBoundaryEdge == false)
            {
                // don't want to flip if it will invert triangle...tetrahedron sign??

                // can we do this more efficiently somehow?
                bool a_is_boundary_vtx = (MeshIsClosed) ? false : (bIsBoundaryEdge || mesh.vertex_is_boundary(a));
                bool b_is_boundary_vtx = (MeshIsClosed) ? false : (bIsBoundaryEdge || mesh.vertex_is_boundary(b));
                bool c_is_boundary_vtx = (MeshIsClosed) ? false : mesh.vertex_is_boundary(c);
                bool d_is_boundary_vtx = (MeshIsClosed) ? false :  mesh.vertex_is_boundary(d);
                int  valence_a = mesh.GetVtxEdgeValence(a), valence_b = mesh.GetVtxEdgeValence(b);
                int  valence_c = mesh.GetVtxEdgeValence(c), valence_d = mesh.GetVtxEdgeValence(d);
                int  valence_a_target = (a_is_boundary_vtx) ? valence_a : 6;
                int  valence_b_target = (b_is_boundary_vtx) ? valence_b : 6;
                int  valence_c_target = (c_is_boundary_vtx) ? valence_c : 6;
                int  valence_d_target = (d_is_boundary_vtx) ? valence_d : 6;


                // if total valence error improves by flip, we want to do it
                int curr_err = Math.Abs(valence_a - valence_a_target) + Math.Abs(valence_b - valence_b_target)
                               + Math.Abs(valence_c - valence_c_target) + Math.Abs(valence_d - valence_d_target);
                int flip_err = Math.Abs((valence_a - 1) - valence_a_target) + Math.Abs((valence_b - 1) - valence_b_target)
                               + Math.Abs((valence_c + 1) - valence_c_target) + Math.Abs((valence_d + 1) - valence_d_target);

                if (flip_err < curr_err)
                {
                    // try flip
                    DMesh3.EdgeFlipInfo flipInfo;
                    COUNT_FLIPS++;
                    MeshResult result = mesh.FlipEdge(edgeID, out flipInfo);
                    if (result == MeshResult.Ok)
                    {
                        DoDebugChecks();
                        return(ProcessResult.Ok_Flipped);
                    }
                    else
                    {
                        bTriedFlip = true;
                    }
                }
            }

            end_flip();
            begin_split();

            // if edge length is too long, we want to split it
            bool bTriedSplit = false;

            if (EnableSplits && constraint.CanSplit && edge_len_sqr > MaxEdgeLength * MaxEdgeLength)
            {
                DMesh3.EdgeSplitInfo splitInfo;
                COUNT_SPLITS++;
                MeshResult result = mesh.SplitEdge(edgeID, out splitInfo);
                if (result == MeshResult.Ok)
                {
                    update_after_split(edgeID, a, b, splitInfo);
                    DoDebugChecks();
                    return(ProcessResult.Ok_Split);
                }
                else
                {
                    bTriedSplit = true;
                }
            }

            end_split();


            if (bTriedFlip || bTriedSplit || bTriedCollapse)
            {
                return(ProcessResult.Failed_OpNotSuccessful);
            }
            else
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }
        }
Пример #22
0
 public void clear()
 {
     nMaterialID = InvalidMaterialID;
     nGroupID    = InvalidGroupID;
     vIndices    = vNormals = vUVs = new Index3i(-1, -1, -1);
 }
Пример #23
0
        /// <summary>
        /// Stitch two sets of boundary edges that are provided as unordered pairs of edges, by
        /// adding triangulated quads between each edge pair.
        /// If a failure is encountered during stitching, the triangles added up to that point are removed.
        /// </summary>
        public virtual int[] StitchUnorderedEdges(List <Index2i> EdgePairs, int group_id = -1)
        {
            int N = EdgePairs.Count;

            int[] new_tris = new int[N * 2];

            int i = 0;

            for (; i < N; ++i)
            {
                Index2i edges = EdgePairs[i];

                // look up and orient the first edge
                Index4i edge_a = Mesh.GetEdge(edges.a);
                if (edge_a.d != DMesh3.InvalidID)
                {
                    goto operation_failed;
                }
                Index3i edge_a_tri = Mesh.GetTriangle(edge_a.c);
                int     a = edge_a.a, b = edge_a.b;
                IndexUtil.orient_tri_edge(ref a, ref b, edge_a_tri);

                // look up and orient the second edge
                Index4i edge_b = Mesh.GetEdge(edges.b);
                if (edge_b.d != DMesh3.InvalidID)
                {
                    goto operation_failed;
                }
                Index3i edge_b_tri = Mesh.GetTriangle(edge_b.c);
                int     c = edge_b.a, d = edge_b.b;
                IndexUtil.orient_tri_edge(ref c, ref d, edge_b_tri);

                // swap second edge (right? should this be a parameter?)
                int tmp = c; c = d; d = tmp;

                Index3i t1 = new Index3i(b, a, d);
                Index3i t2 = new Index3i(a, c, d);

                int tid1 = Mesh.AppendTriangle(t1, group_id);
                int tid2 = Mesh.AppendTriangle(t2, group_id);

                if (tid1 == DMesh3.InvalidID || tid2 == DMesh3.InvalidID)
                {
                    goto operation_failed;
                }

                new_tris[2 * i]     = tid1;
                new_tris[2 * i + 1] = tid2;
            }

            return(new_tris);

operation_failed:
            // remove what we added so far
            if (i > 0)
            {
                if (remove_triangles(new_tris, 2 * (i - 1)) == false)
                {
                    throw new Exception("MeshEditor.StitchLoop: failed to add all triangles, and also failed to back out changes.");
                }
            }
            return(null);
        }
Пример #24
0
        void make_level_set3(DMesh3 mesh, /*const std::vector<Vec3ui> &tri, const std::vector<Vec3f> &x*/
                             Vector3f origin, float dx,
                             int ni, int nj, int nk,
                             DenseGrid3f phi, int exact_band)
        {
            phi.resize(ni, nj, nk);
            phi.assign((ni + nj + nk) * dx);                                 // upper bound on distance
            DenseGrid3i closest_tri        = new DenseGrid3i(ni, nj, nk, -1);
            DenseGrid3i intersection_count = new DenseGrid3i(ni, nj, nk, 0); // intersection_count(i,j,k) is # of tri intersections in (i-1,i]x{j}x{k}

            // we begin by initializing distances near the mesh, and figuring out intersection counts

            System.Console.WriteLine("start");

            //Vector3f ijkmin, ijkmax;  // [RMS] unused in original code
            double ddx = (double)dx;
            double ox = (double)origin[0], oy = (double)origin[1], oz = (double)origin[2];

            foreach (int t in mesh.TriangleIndices())
            {
                Index3i triangle = mesh.GetTriangle(t);
                int     p = triangle.a, q = triangle.b, r = triangle.c;

                Vector3d xp = mesh.GetVertex(p);
                Vector3d xq = mesh.GetVertex(q);
                Vector3d xr = mesh.GetVertex(r);

                // coordinates in grid to high precision
                double fip = (xp[0] - ox) / ddx, fjp = (xp[1] - oy) / ddx, fkp = (xp[2] - oz) / ddx;
                double fiq = (xq[0] - ox) / ddx, fjq = (xq[1] - oy) / ddx, fkq = (xq[2] - oz) / ddx;
                double fir = (xr[0] - ox) / ddx, fjr = (xr[1] - oy) / ddx, fkr = (xr[2] - oz) / ddx;
                // do distances nearby
                int i0 = MathUtil.Clamp(((int)MathUtil.Min(fip, fiq, fir)) - exact_band, 0, ni - 1);
                int i1 = MathUtil.Clamp(((int)MathUtil.Max(fip, fiq, fir)) + exact_band + 1, 0, ni - 1);
                int j0 = MathUtil.Clamp(((int)MathUtil.Min(fjp, fjq, fjr)) - exact_band, 0, nj - 1);
                int j1 = MathUtil.Clamp(((int)MathUtil.Max(fjp, fjq, fjr)) + exact_band + 1, 0, nj - 1);
                int k0 = MathUtil.Clamp(((int)MathUtil.Min(fkp, fkq, fkr)) - exact_band, 0, nk - 1);
                int k1 = MathUtil.Clamp(((int)MathUtil.Max(fkp, fkq, fkr)) + exact_band + 1, 0, nk - 1);

                for (int k = k0; k <= k1; ++k)
                {
                    for (int j = j0; j <= j1; ++j)
                    {
                        for (int i = i0; i <= i1; ++i)
                        {
                            Vector3f gx = new Vector3f((float)i * dx + origin[0], (float)j * dx + origin[1], (float)k * dx + origin[2]);
                            float    d  = point_triangle_distance(gx, (Vector3f)xp, (Vector3f)xq, (Vector3f)xr);
                            if (d < phi[i, j, k])
                            {
                                phi[i, j, k]         = d;
                                closest_tri[i, j, k] = t;
                            }
                        }
                    }
                }


                // and do intersection counts
                j0 = MathUtil.Clamp((int)Math.Ceiling(MathUtil.Min(fjp, fjq, fjr)), 0, nj - 1);
                j1 = MathUtil.Clamp((int)Math.Floor(MathUtil.Max(fjp, fjq, fjr)), 0, nj - 1);
                k0 = MathUtil.Clamp((int)Math.Ceiling(MathUtil.Min(fkp, fkq, fkr)), 0, nk - 1);
                k1 = MathUtil.Clamp((int)Math.Floor(MathUtil.Max(fkp, fkq, fkr)), 0, nk - 1);
                for (int k = k0; k <= k1; ++k)
                {
                    for (int j = j0; j <= j1; ++j)
                    {
                        double a, b, c;
                        if (point_in_triangle_2d(j, k, fjp, fkp, fjq, fkq, fjr, fkr, out a, out b, out c))
                        {
                            double fi         = a * fip + b * fiq + c * fir; // intersection i coordinate
                            int    i_interval = (int)(Math.Ceiling(fi));     // intersection is in (i_interval-1,i_interval]
                            if (i_interval < 0)
                            {
                                intersection_count.increment(0, j, k); // we enlarge the first interval to include everything to the -x direction
                            }
                            else if (i_interval < ni)
                            {
                                intersection_count.increment(i_interval, j, k);
                            }
                            // we ignore intersections that are beyond the +x side of the grid
                        }
                    }
                }
            }

            System.Console.WriteLine("done narrow-band");

            // and now we fill in the rest of the distances with fast sweeping
            for (int pass = 0; pass < 2; ++pass)
            {
                sweep(mesh, phi, closest_tri, origin, dx, +1, +1, +1);
                sweep(mesh, phi, closest_tri, origin, dx, -1, -1, -1);
                sweep(mesh, phi, closest_tri, origin, dx, +1, +1, -1);
                sweep(mesh, phi, closest_tri, origin, dx, -1, -1, +1);
                sweep(mesh, phi, closest_tri, origin, dx, +1, -1, +1);
                sweep(mesh, phi, closest_tri, origin, dx, -1, +1, -1);
                sweep(mesh, phi, closest_tri, origin, dx, +1, -1, -1);
                sweep(mesh, phi, closest_tri, origin, dx, -1, +1, +1);
            }

            System.Console.WriteLine("done sweeping");

            // then figure out signs (inside/outside) from intersection counts
            for (int k = 0; k < nk; ++k)
            {
                for (int j = 0; j < nj; ++j)
                {
                    int total_count = 0;
                    for (int i = 0; i < ni; ++i)
                    {
                        total_count += intersection_count[i, j, k];
                        if (total_count % 2 == 1)         // if parity of intersections so far is odd,
                        {
                            phi[i, j, k] = -phi[i, j, k]; // we are inside the mesh
                        }
                    }
                }
            }

            System.Console.WriteLine("done signs");
        }   // end make_level_set_3
Пример #25
0
        // Assumption here is that Submesh has been modified, but boundary loop has
        // been preserved, and that old submesh has already been removed from this mesh.
        // So, we just have to append new vertices and then rewrite triangles
        // If new_tris or new_verts is non-null, we will return this info.
        // new_tris should be set to TriangleCount (ie it is not necessarily a map)
        // For new_verts, if we used an existing bdry vtx instead, we set the value to -(existing_index+1),
        // otherwise the value is new_index (+1 is to handle 0)
        //
        // Returns true if submesh successfully inserted, false if any triangles failed
        // (which happens if triangle would result in non-manifold mesh)
        public bool ReinsertSubmesh(DSubmesh3 sub, ref int[] new_tris, out IndexMap SubToNewV,
                                    DuplicateTriBehavior eDuplicateBehavior = DuplicateTriBehavior.AssertAbort)
        {
            if (sub.BaseBorderV == null)
            {
                throw new Exception("MeshEditor.ReinsertSubmesh: Submesh does not have required boundary info. Call ComputeBoundaryInfo()!");
            }

            DMesh3 submesh = sub.SubMesh;
            bool   bAllOK  = true;

            IndexFlagSet done_v = new IndexFlagSet(submesh.MaxVertexID, submesh.TriangleCount / 2);

            SubToNewV = new IndexMap(submesh.MaxVertexID, submesh.VertexCount);

            int nti = 0;
            int NT  = submesh.MaxTriangleID;

            for (int ti = 0; ti < NT; ++ti)
            {
                if (submesh.IsTriangle(ti) == false)
                {
                    continue;
                }

                Index3i sub_t = submesh.GetTriangle(ti);
                int     gid   = submesh.GetTriangleGroup(ti);

                Index3i new_t = Index3i.Zero;
                for (int j = 0; j < 3; ++j)
                {
                    int sub_v = sub_t[j];
                    int new_v = -1;
                    if (done_v[sub_v] == false)
                    {
                        // first check if this is a boundary vtx on submesh and maps to a bdry vtx on base mesh
                        if (submesh.IsBoundaryVertex(sub_v))
                        {
                            int base_v = (sub_v < sub.SubToBaseV.size) ? sub.SubToBaseV[sub_v] : -1;
                            if (base_v >= 0 && Mesh.IsVertex(base_v) && sub.BaseBorderV[base_v] == true)
                            {
                                // [RMS] this should always be true, but assert in tests to find out
                                Debug.Assert(Mesh.IsBoundaryVertex(base_v));
                                if (Mesh.IsBoundaryVertex(base_v))
                                {
                                    new_v = base_v;
                                }
                            }
                        }

                        // if that didn't happen, append new vtx
                        if (new_v == -1)
                        {
                            new_v = Mesh.AppendVertex(submesh, sub_v);
                        }

                        SubToNewV[sub_v] = new_v;
                        done_v[sub_v]    = true;
                    }
                    else
                    {
                        new_v = SubToNewV[sub_v];
                    }

                    new_t[j] = new_v;
                }

                // try to handle duplicate-tri case
                if (eDuplicateBehavior == DuplicateTriBehavior.AssertContinue)
                {
                    Debug.Assert(Mesh.FindTriangle(new_t.a, new_t.b, new_t.c) == DMesh3.InvalidID);
                }
                else
                {
                    int existing_tid = Mesh.FindTriangle(new_t.a, new_t.b, new_t.c);
                    if (existing_tid != DMesh3.InvalidID)
                    {
                        if (eDuplicateBehavior == DuplicateTriBehavior.AssertAbort)
                        {
                            Debug.Assert(existing_tid == DMesh3.InvalidID);
                            return(false);
                        }
                        else if (eDuplicateBehavior == DuplicateTriBehavior.UseExisting)
                        {
                            if (new_tris != null)
                            {
                                new_tris[nti++] = existing_tid;
                            }
                            continue;
                        }
                        else if (eDuplicateBehavior == DuplicateTriBehavior.Replace)
                        {
                            Mesh.RemoveTriangle(existing_tid, false);
                        }
                    }
                }


                int new_tid = Mesh.AppendTriangle(new_t, gid);
                Debug.Assert(new_tid != DMesh3.InvalidID && new_tid != DMesh3.NonManifoldID);
                if (!Mesh.IsTriangle(new_tid))
                {
                    bAllOK = false;
                }

                if (new_tris != null)
                {
                    new_tris[nti++] = new_tid;
                }
            }

            return(bAllOK);
        }
Пример #26
0
        protected virtual ProcessResult CollapseEdge(int edgeID, Vector3d vNewPos, out int collapseToV)
        {
            collapseToV = DMesh3.InvalidID;
            RuntimeDebugCheck(edgeID);

            EdgeConstraint constraint =
                (constraints == null) ? EdgeConstraint.Unconstrained : constraints.GetEdgeConstraint(edgeID);

            if (constraint.NoModifications)
            {
                return(ProcessResult.Ignored_EdgeIsFullyConstrained);
            }
            if (constraint.CanCollapse == false)
            {
                return(ProcessResult.Ignored_EdgeIsFullyConstrained);
            }


            // look up verts and tris for this edge
            int a = 0, b = 0, t0 = 0, t1 = 0;

            if (mesh.GetEdge(edgeID, ref a, ref b, ref t0, ref t1) == false)
            {
                return(ProcessResult.Failed_NotAnEdge);
            }
            bool bIsBoundaryEdge = (t1 == DMesh3.InvalidID);

            // look up 'other' verts c (from t0) and d (from t1, if it exists)
            Index3i T0tv         = mesh.GetTriangle(t0);
            int     c            = IndexUtil.find_tri_other_vtx(a, b, T0tv);
            Index3i T1tv         = (bIsBoundaryEdge) ? DMesh3.InvalidTriangle : mesh.GetTriangle(t1);
            int     d            = (bIsBoundaryEdge) ? DMesh3.InvalidID : IndexUtil.find_tri_other_vtx(a, b, T1tv);

            Vector3d vA           = mesh.GetVertex(a);
            Vector3d vB           = mesh.GetVertex(b);
            double   edge_len_sqr = (vA - vB).LengthSquared;

            if (edge_len_sqr > MinEdgeLength * MinEdgeLength)
            {
                return(ProcessResult.Ignored_EdgeTooLong);
            }

            begin_collapse();

            // check if we should collapse, and also find which vertex we should collapse to,
            // in cases where we have constraints/etc
            int  collapse_to  = -1;
            bool bCanCollapse = can_collapse_constraints(edgeID, a, b, c, d, t0, t1, out collapse_to);

            if (bCanCollapse == false)
            {
                return(ProcessResult.Ignored_Constrained);
            }

            // if we have a boundary, we want to collapse to boundary
            if (PreserveBoundary && HaveBoundary)
            {
                if (collapse_to != -1)
                {
                    if ((IsBoundaryV(b) && collapse_to != b) ||
                        (IsBoundaryV(a) && collapse_to != a))
                    {
                        return(ProcessResult.Ignored_Constrained);
                    }
                }
                if (IsBoundaryV(b))
                {
                    collapse_to = b;
                }
                else if (IsBoundaryV(a))
                {
                    collapse_to = a;
                }
            }

            // optimization: if edge cd exists, we cannot collapse or flip. look that up here?
            //  funcs will do it internally...
            //  (or maybe we can collapse if cd exists? edge-collapse doesn't check for it explicitly...)
            ProcessResult retVal = ProcessResult.Failed_OpNotSuccessful;

            int iKeep = b, iCollapse = a;

            // if either vtx is fixed, collapse to that position
            if (collapse_to == b)
            {
                vNewPos = vB;
            }
            else if (collapse_to == a)
            {
                iKeep   = a; iCollapse = b;
                vNewPos = vA;
            }
            else
            {
                vNewPos = get_projected_collapse_position(iKeep, vNewPos);
            }

            // check if this collapse will create a normal flip. Also checks
            // for invalid collapse nbrhood, since we are doing one-ring iter anyway.
            // [TODO] could we skip this one-ring check in CollapseEdge? pass in hints?
            if (creates_flip_or_invalid(a, b, ref vNewPos, t0, t1) || creates_flip_or_invalid(b, a, ref vNewPos, t0, t1))
            {
                retVal = ProcessResult.Ignored_CreatesFlip;
                goto skip_to_end;
            }

            // lots of cases where we cannot collapse, but we should just let
            // mesh sort that out, right?
            COUNT_COLLAPSES++;
            DMesh3.EdgeCollapseInfo collapseInfo;
            MeshResult result = mesh.CollapseEdge(iKeep, iCollapse, out collapseInfo);

            if (result == MeshResult.Ok)
            {
                collapseToV = iKeep;
                mesh.SetVertex(iKeep, vNewPos);
                if (constraints != null)
                {
                    constraints.ClearEdgeConstraint(edgeID);
                    constraints.ClearEdgeConstraint(collapseInfo.eRemoved0);
                    if (collapseInfo.eRemoved1 != DMesh3.InvalidID)
                    {
                        constraints.ClearEdgeConstraint(collapseInfo.eRemoved1);
                    }
                    constraints.ClearVertexConstraint(iCollapse);
                }
                OnEdgeCollapse(edgeID, iKeep, iCollapse, collapseInfo);
                DoDebugChecks();

                retVal = ProcessResult.Ok_Collapsed;
            }

skip_to_end:
            end_collapse();
            return(retVal);
        }
Пример #27
0
 private int AppendTriangle(Index3i t)
 {
     return(AppendTriangle(t.a, t.b, t.c));
 }
Пример #28
0
        public IOWriteResult Write(TextWriter writer, List <WriteMesh> vMeshes, WriteOptions options)
        {
            int N = vMeshes.Count;

            writer.WriteLine("OFF");

            string three_floats = Util.MakeVec3FormatString(0, 1, 2, options.RealPrecisionDigits);

            int nTotalV = 0, nTotalT = 0, nTotalE = 0;

            // OFF only supports one mesh, so have to collapse all input meshes
            // into a single list, with mapping for triangles
            // [TODO] can skip this if input is a single mesh!
            int[][] mapV = new int[N][];
            for (int mi = 0; mi < N; ++mi)
            {
                nTotalV += vMeshes[mi].Mesh.VertexCount;
                nTotalT += vMeshes[mi].Mesh.TriangleCount;
                nTotalE += 0;
                mapV[mi] = new int[vMeshes[mi].Mesh.MaxVertexID];
            }
            writer.WriteLine(string.Format("{0} {1} {2}", nTotalV, nTotalT, nTotalE));


            // write all vertices, and construct vertex re-map
            int vi = 0;

            for (int mi = 0; mi < N; ++mi)
            {
                IMesh mesh = vMeshes[mi].Mesh;
                if (options.ProgressFunc != null)
                {
                    options.ProgressFunc(mi, 2 * (N - 1));
                }

                foreach (int vid in mesh.VertexIndices())
                {
                    Vector3d v = mesh.GetVertex(vid);
                    writer.WriteLine(three_floats, v.x, v.y, v.z);
                    mapV[mi][vid] = vi;
                    vi++;
                }
            }

            // write all triangles
            for (int mi = 0; mi < N; ++mi)
            {
                IMesh mesh = vMeshes[mi].Mesh;
                if (options.ProgressFunc != null)
                {
                    options.ProgressFunc(N + mi, 2 * (N - 1));
                }

                foreach (int ti in mesh.TriangleIndices())
                {
                    Index3i t = mesh.GetTriangle(ti);
                    t[0] = mapV[mi][t[0]];
                    t[1] = mapV[mi][t[1]];
                    t[2] = mapV[mi][t[2]];
                    writer.WriteLine(string.Format("3 {0} {1} {2}", t[0], t[1], t[2]));
                }
            }

            return(new IOWriteResult(IOCode.Ok, ""));
        }
Пример #29
0
 /// <summary>
 /// Converts the provided integer vector from g3 into the OpenTK variant.
 /// </summary>
 /// <param name="vector">The vector to convert from its current integer variant.
 /// </param>
 /// <returns>An OpenTK vector to use in all calculations.</returns>
 public static Vector3 VectorConvert(g3.Index3i vector)
 {
     return(new Vector3(vector.a, vector.b, vector.c));
 }
Пример #30
0
        public void BuildLinear()
        {
            int NV = mesh.MaxVertexID;

            if (TrackVertexMapping)
            {
                mapTo = new Index2i[NV];
                for (int i = 0; i < NV; ++i)
                {
                    mapTo[i] = Index2i.Zero;
                }
                mapToMulti = new DVector <int>();
            }

            // temporary map from orig vertices to submesh vertices
            int[] mapToCur = new int[NV];
            Array.Clear(mapToCur, 0, mapToCur.Length);

            int nT = mesh.MaxTriangleID;

            // depending on the mesh, either the vertex count or triangle count
            // could hit the upper bound first. For connected meshes we have
            // NT =~ 2*NV by eulers formula, but eg for a pathological triangle
            // soup mesh, we might have NV = 3*NT

            int[] cur_subt = new int[MaxComponentSize];     // accumulated tris for this component
            int   subti    = 0;                             // index into cur_subt
            int   subi     = 1;                             // component index

            // also need to make sure we don't get too many verts. To do this
            // we have to keep count of how many unique verts we have accumulated.
            int[]    cur_subv  = new int[MaxComponentSize];      // temp buffer in add_component
            BitArray vert_bits = new BitArray(mesh.MaxVertexID); // which verts have we seen for this component
            int      subvcount = 0;                              // accumulated vert count for this component


            Action add_component = () => {
                Index2i   mapRange;
                int       max_subv;
                Component new_comp = extract_submesh(subi++, cur_subt, subti, mapToCur, cur_subv, out mapRange, out max_subv);

                // [TODO] perhaps manager can request smaller chunks?
                Manager.AddComponent(new_comp);

                Array.Clear(cur_subt, 0, subti);
                subti = 0;
                Array.Clear(mapToCur, mapRange.a, mapRange.b - mapRange.a + 1);
                Array.Clear(cur_subv, 0, max_subv);
                subvcount = 0;
                vert_bits.SetAll(false);
            };



            int[] tri_order = get_tri_order_by_axis_sort();
            int   tri_count = tri_order.Length;

            for (int ii = 0; ii < tri_count; ++ii)
            {
                int ti = tri_order[ii];

                Index3i tri = mesh.GetTriangle(ti);
                if (vert_bits[tri.a] == false)
                {
                    vert_bits[tri.a] = true; subvcount++;
                }
                if (vert_bits[tri.b] == false)
                {
                    vert_bits[tri.b] = true; subvcount++;
                }
                if (vert_bits[tri.c] == false)
                {
                    vert_bits[tri.c] = true; subvcount++;
                }

                cur_subt[subti++] = ti;

                if (subti == MaxComponentSize || subvcount > MaxComponentSize - 3)
                {
                    add_component();
                }
            }
            if (subti > 0)
            {
                add_component();
            }
        }