public void MakeMesh(DMesh3 m)
 {
     int nV = vertices.Count;
     for (int i = 0; i < nV; ++i) {
         NewVertexInfo ni = new NewVertexInfo() { v = vertices[i] };
         if ( WantNormals ) {
             ni.bHaveN = true;
             ni.n = normals[i];
         }
         if ( WantUVs ) {
             ni.bHaveUV = true;
             ni.uv = uv[i];
         }
         int vID = m.AppendVertex(ni);
         Util.gDevAssert(vID == i);
     }
     int nT = triangles.Count;
     if (WantGroups && groups != null && groups.Length == nT) {
         for (int i = 0; i < nT; ++i)
             m.AppendTriangle(triangles[i], groups[i]);
     } else {
         for (int i = 0; i < nT; ++i)
             m.AppendTriangle(triangles[i]);
     }
 }
Beispiel #2
0
        // [RMS] estimate can be zero
        void compute(IEnumerable <int> triangles, int tri_count_est)
        {
            int est_verts = tri_count_est / 2;

            SubMesh = new DMesh3(BaseMesh.Components & WantComponents);

            BaseSubmeshV = new IndexFlagSet(BaseMesh.MaxVertexID, est_verts);
            BaseToSubV   = new IndexMap(BaseMesh.MaxVertexID, est_verts);
            SubToBaseV   = new DVector <int>();

            if (ComputeTriMaps)
            {
                BaseToSubT = new IndexMap(BaseMesh.MaxTriangleID, tri_count_est);
                SubToBaseT = new DVector <int>();
            }

            foreach (int tid in triangles)
            {
                if (!BaseMesh.IsTriangle(tid))
                {
                    throw new Exception("DSubmesh3.compute: triangle " + tid + " does not exist in BaseMesh!");
                }

                Index3i base_t = BaseMesh.GetTriangle(tid);
                Index3i new_t  = Index3i.Zero;
                int     gid    = BaseMesh.GetTriangleGroup(tid);

                for (int j = 0; j < 3; ++j)
                {
                    int base_v = base_t[j];
                    int sub_v  = -1;
                    if (BaseSubmeshV[base_v] == false)
                    {
                        sub_v = SubMesh.AppendVertex(BaseMesh, base_v);
                        BaseSubmeshV[base_v] = true;
                        BaseToSubV[base_v]   = sub_v;
                        SubToBaseV.insert(base_v, sub_v);
                    }
                    else
                    {
                        sub_v = BaseToSubV[base_v];
                    }

                    new_t[j] = sub_v;
                }

                if (OverrideGroupID >= 0)
                {
                    gid = OverrideGroupID;
                }

                int sub_tid = SubMesh.AppendTriangle(new_t, gid);

                if (ComputeTriMaps)
                {
                    BaseToSubT[tid] = sub_tid;
                    SubToBaseT.insert(tid, sub_tid);
                }
            }
        }
Beispiel #3
0
        public virtual bool Extrude(int group_id = -1)
        {
            // duplicate loop vertices
            int NV = Loop.Vertices.Length;

            NewLoop          = new EdgeLoop(Mesh);
            NewLoop.Vertices = new int[NV];

            for (int i = 0; i < NV; ++i)
            {
                int vid = Loop.Vertices[i];
                NewLoop.Vertices[i] = Mesh.AppendVertex(Mesh, vid);
            }

            // move to offset positions
            for (int i = 0; i < NV; ++i)
            {
                Vector3d v     = Mesh.GetVertex(Loop.Vertices[i]);
                Vector3f n     = Mesh.GetVertexNormal(Loop.Vertices[i]);
                Vector3d new_v = PositionF(v, n, i);
                Mesh.SetVertex(NewLoop.Vertices[i], new_v);
            }

            // stitch interior
            MeshEditor edit = new MeshEditor(Mesh);

            NewTriangles = edit.StitchLoop(Loop.Vertices, NewLoop.Vertices, group_id);

            return(true);
        }
        public virtual bool Fill(int group_id = -1)
        {
            if (Loop.Vertices.Length < 3)
            {
                return(false);
            }

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

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


            // compute centroid
            Vector3d c = Vector3d.Zero;

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

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

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

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

            // if fill failed, back out vertex-add
            if (NewTriangles == null)
            {
                Mesh.RemoveVertex(NewVertex, true, false);
                NewVertex = DMesh3.InvalidID;
                return(false);
            }
            else
            {
                return(true);
            }
        }
        //
        // DMesh3 construction utilities
        //

        /// <summary>
        /// ultimate generic mesh-builder, pass it arrays of floats/doubles, or lists
        /// of Vector3d, or anything in-between. Will figure out how to interpret
        ///
        /// This static function attempts to retain a manifold mesh, if you need finer
        /// control use the concrete class.
        ///
        /// Number of issues encountered adding verices or triangls are stored in the
        /// mesh metadata. Metadata can be cleared once the returning object is evaluated.
        /// </summary>
        public static DMesh3 Build <VType, TType, NType>(IEnumerable <VType> Vertices,
                                                         IEnumerable <TType> Triangles,
                                                         IEnumerable <NType> Normals = null,
                                                         IEnumerable <int> TriGroups = null)
        {
            DMesh3 mesh = new DMesh3(Normals != null, false, false, TriGroups != null);

            // build outcomes are stored in the metadata to avoid changes to the function signature
            //
            int iAppendTriangleIssues = 0;

            Vector3d[] v = BufferUtil.ToVector3d(Vertices);
            for (int i = 0; i < v.Length; ++i)
            {
                mesh.AppendVertex(v[i]);
            }


            if (Normals != null)
            {
                Vector3f[] n = BufferUtil.ToVector3f(Normals);
                if (n.Length != v.Length)
                {
                    throw new Exception("DMesh3Builder.Build: incorrect number of normals provided");
                }
                for (int i = 0; i < n.Length; ++i)
                {
                    mesh.SetVertexNormal(i, n[i]);
                }
            }

            Index3i[] t = BufferUtil.ToIndex3i(Triangles);
            for (int i = 0; i < t.Length; ++i)
            {
                var last = mesh.AppendTriangle(t[i]);
                if (last == DMesh3.InvalidID || last == DMesh3.NonManifoldID)
                {
                    iAppendTriangleIssues++;
                }
            }

            if (TriGroups != null)
            {
                List <int> groups = new List <int>(TriGroups);
                if (groups.Count != t.Length)
                {
                    throw new Exception("DMesh3Builder.Build: incorect number of triangle groups");
                }
                for (int i = 0; i < t.Length; ++i)
                {
                    mesh.SetTriangleGroup(i, groups[i]);
                }
            }
            mesh.AttachMetadata("AppendTriangleIssues", iAppendTriangleIssues);

            return(mesh);
        }
        public void Generate()
        {
            append_mesh();

            AxisAlignedBox3i bounds = Voxels.GridBounds;

            bounds.Max -= Vector3i.One;

            int[] vertices = new int[4];

            foreach (Vector3i nz in Voxels.NonZeros())
            {
                check_counts_or_append(6, 2);

                Box3d cube = Box3d.UnitZeroCentered;
                cube.Center = (Vector3d)nz;

                for (int fi = 0; fi < 6; ++fi)
                {
                    // checks dependent on neighbours
                    Index3i nbr = nz + gIndices.GridOffsets6[fi];
                    if (bounds.Contains(nbr))
                    {
                        if (SkipInteriorFaces && Voxels.Get(nbr))
                        {
                            continue;
                        }
                    }
                    else if (CapAtBoundary == false)
                    {
                        continue;
                    }


                    int           ni = gIndices.BoxFaceNormals[fi];
                    Vector3f      n  = (Vector3f)(Math.Sign(ni) * cube.Axis(Math.Abs(ni) - 1));
                    NewVertexInfo vi = new NewVertexInfo(Vector3d.Zero, n);
                    if (ColorSourceF != null)
                    {
                        vi.c      = ColorSourceF(nz);
                        vi.bHaveC = true;
                    }
                    for (int j = 0; j < 4; ++j)
                    {
                        vi.v        = cube.Corner(gIndices.BoxFaces[fi, j]);
                        vertices[j] = cur_mesh.AppendVertex(vi);
                    }

                    Index3i t0 = new Index3i(vertices[0], vertices[1], vertices[2], Clockwise);
                    Index3i t1 = new Index3i(vertices[0], vertices[2], vertices[3], Clockwise);
                    cur_mesh.AppendTriangle(t0);
                    cur_mesh.AppendTriangle(t1);
                }
            }
        }
        public virtual void MakeMesh(DMesh3 m)
        {
            int  nV           = vertices.Count;
            bool bWantNormals = WantNormals && normals != null && normals.Count == vertices.Count;

            if (bWantNormals)
            {
                m.EnableVertexNormals(Vector3f.AxisY);
            }

            bool bWantUVs = WantUVs && uv != null && uv.Count == vertices.Count;

            if (bWantUVs)
            {
                m.EnableVertexUVs(Vector2f.Zero);
            }

            for (int i = 0; i < nV; ++i)
            {
                var ni = new NewVertexInfo()
                {
                    v = vertices[i]
                };
                if (bWantNormals)
                {
                    ni.bHaveN = true;
                    ni.n      = normals[i];
                }
                if (bWantUVs)
                {
                    ni.bHaveUV = true;
                    ni.uv      = uv[i];
                }
                int vID = m.AppendVertex(ni);
                Util.gDevAssert(vID == i);
            }
            int nT = triangles.Count;

            if (WantGroups && groups != null && groups.Length == nT)
            {
                m.EnableTriangleGroups();
                for (int i = 0; i < nT; ++i)
                {
                    m.AppendTriangle(triangles[i], groups[i]);
                }
            }
            else
            {
                for (int i = 0; i < nT; ++i)
                {
                    m.AppendTriangle(triangles[i]);
                }
            }
        }
        //
        // DMesh3 construction utilities
        //

        /// <summary>
        /// ultimate generic mesh-builder, pass it arrays of floats/doubles, or lists
        /// of Vector3d, or anything in-between. Will figure out how to interpret
        /// </summary>
        public static DMesh3 Build <VType, TType, NType>(IEnumerable <VType> Vertices,
                                                         IEnumerable <TType> Triangles,
                                                         IEnumerable <NType> Normals = null,
                                                         IEnumerable <int> TriGroups = null)
        {
            var mesh = new DMesh3(Normals != null, false, false, TriGroups != null);

            Vector3d[] v = BufferUtil.ToVector3d(Vertices);
            for (int i = 0; i < v.Length; ++i)
            {
                mesh.AppendVertex(v[i]);
            }

            if (Normals != null)
            {
                Vector3f[] n = BufferUtil.ToVector3f(Normals);
                if (n.Length != v.Length)
                {
                    throw new Exception("DMesh3Builder.Build: incorrect number of normals provided");
                }

                for (int i = 0; i < n.Length; ++i)
                {
                    mesh.SetVertexNormal(i, n[i]);
                }
            }

            Index3i[] t = BufferUtil.ToIndex3i(Triangles);
            for (int i = 0; i < t.Length; ++i)
            {
                mesh.AppendTriangle(t[i]);
            }

            if (TriGroups != null)
            {
                var groups = new List <int>(TriGroups);
                if (groups.Count != t.Length)
                {
                    throw new Exception("DMesh3Builder.Build: incorect number of triangle groups");
                }

                for (int i = 0; i < t.Length; ++i)
                {
                    mesh.SetTriangleGroup(i, groups[i]);
                }
            }

            return(mesh);
        }
        public static g3.DMesh3 ConvertToD3Mesh(Rhino.Geometry.Mesh mesh)
        {
            g3.DMesh3 ret = new g3.DMesh3(true, false, false, false);

            if (mesh.Normals.Count < mesh.Vertices.Count)
            {
                mesh.Normals.ComputeNormals();
            }

            if (mesh.Normals.Count != mesh.Vertices.Count)
            {
                return(ret);
            }

            for (int i = 0; i < mesh.Vertices.Count; i++)
            {
                var vertex = new g3.NewVertexInfo();
                vertex.n = new g3.Vector3f(mesh.Normals[i].X, mesh.Normals[i].Y, mesh.Normals[i].Z);
                vertex.v = new g3.Vector3d(mesh.Vertices[i].X, mesh.Vertices[i].Y, mesh.Vertices[i].Z);
                ret.AppendVertex(vertex);
            }


            foreach (var mf in mesh.Faces)
            {
                if (mf.IsQuad)
                {
                    double dist1 = mesh.Vertices[mf.A].DistanceTo(mesh.Vertices[mf.C]);
                    double dist2 = mesh.Vertices[mf.B].DistanceTo(mesh.Vertices[mf.D]);
                    if (dist1 > dist2)
                    {
                        ret.AppendTriangle(mf.A, mf.B, mf.D);
                        ret.AppendTriangle(mf.B, mf.C, mf.D);
                    }
                    else
                    {
                        ret.AppendTriangle(mf.A, mf.B, mf.C);
                        ret.AppendTriangle(mf.A, mf.C, mf.D);
                    }
                }
                else
                {
                    ret.AppendTriangle(mf.A, mf.B, mf.C);
                }
            }

            return(ret);
        }
Beispiel #10
0
        public virtual int[] AddTriangleStrip(IList <Frame3f> frames, IList <Interval1d> spans, int group_id = -1)
        {
            int N = frames.Count;

            if (N != spans.Count)
            {
                throw new Exception("MeshEditor.AddTriangleStrip: spans list is not the same size!");
            }

            int[] new_tris = new int[2 * (N - 1)];

            int prev_a = -1, prev_b = -1;
            int i = 0, ti = 0;

            for (i = 0; i < N; ++i)
            {
                Frame3f    f    = frames[i];
                Interval1d span = spans[i];

                Vector3d va = f.Origin + (float)span.a * f.Y;
                Vector3d vb = f.Origin + (float)span.b * f.Y;

                // [TODO] could compute normals here...

                int a = Mesh.AppendVertex(va);
                int b = Mesh.AppendVertex(vb);

                if (prev_a != -1)
                {
                    new_tris[ti++] = Mesh.AppendTriangle(prev_a, b, prev_b);
                    new_tris[ti++] = Mesh.AppendTriangle(prev_a, a, b);
                }
                prev_a = a; prev_b = b;
            }

            return(new_tris);
        }
Beispiel #11
0
        /// <summary>
        /// add vertex to mesh, with locking if we are computing in parallel
        /// </summary>
        int append_vertex(Vector3d v)
        {
            bool lock_taken = false;

            if (bParallel)
            {
                mesh_lock.Enter(ref lock_taken);
            }

            int vid = Mesh.AppendVertex(v);

            if (lock_taken)
            {
                mesh_lock.Exit();
            }

            return(vid);
        }
        void compute(IEnumerable <int> triangles, int tri_count)
        {
            int est_verts = tri_count / 2;

            SubMesh = new DMesh3(BaseMesh.Components & WantComponents);

            BaseSubmeshV = new IndexFlagSet(BaseMesh.MaxVertexID, est_verts);
            BaseToSubV   = new IndexMap(BaseMesh.MaxVertexID, est_verts);
            SubToBaseV   = new DVector <int>();

            foreach (int ti in triangles)
            {
                Index3i base_t = BaseMesh.GetTriangle(ti);
                Index3i new_t  = Index3i.Zero;
                int     gid    = BaseMesh.GetTriangleGroup(ti);

                for (int j = 0; j < 3; ++j)
                {
                    int base_v = base_t[j];
                    int sub_v  = -1;
                    if (BaseSubmeshV[base_v] == false)
                    {
                        sub_v = SubMesh.AppendVertex(BaseMesh, base_v);
                        BaseSubmeshV[base_v] = true;
                        BaseToSubV[base_v]   = sub_v;
                        SubToBaseV.insert(base_v, sub_v);
                    }
                    else
                    {
                        sub_v = BaseToSubV[base_v];
                    }
                    new_t[j] = sub_v;
                }

                SubMesh.AppendTriangle(new_t, gid);
            }
        }
Beispiel #13
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)
        {
            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.vertex_is_boundary(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.vertex_is_boundary(base_v));
                                if (Mesh.vertex_is_boundary(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;
                }

                Debug.Assert(Mesh.FindTriangle(new_t.a, new_t.b, new_t.c) == DMesh3.InvalidID);

                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);
        }
Beispiel #14
0
        /// <summary>
        /// Similar to the static <see cref="Build()"/> method below, but uses the
        /// <see cref="NonManifoldTriBehavior"/> and <see cref="AddTriangleFailBehaviors"/> properties
        /// to affect the meshing process and avoids exceptions, preferring feedback in the mesh metadata.
        /// </summary>
        public DMesh3 AppendMesh <VType, TType, NType>(IEnumerable <VType> Vertices,
                                                       IEnumerable <TType> Triangles,
                                                       IEnumerable <NType> Normals = null,
                                                       IEnumerable <int> TriGroups = null)
        {
            // build outcomes are stored in the metadata to keep the function signature like the static method Build
            //
            int iAppendTriangleIssues = 0;

            bool   addNormals      = Normals != null;
            string NormalsMetadata = "None";

            bool   addTriGroups      = TriGroups != null;
            string TriGroupsMetadata = "None";

            // data preparation
            Vector3d[] v = BufferUtil.ToVector3d(Vertices);
            Vector3f[] n = null;
            if (addNormals)
            {
                n = BufferUtil.ToVector3f(Normals);
                if (n.Length != v.Length)
                {
                    NormalsMetadata = "Error: incorrect number of normals provided, ignored.";
                    addNormals      = false;
                }
            }
            Index3i[] t = BufferUtil.ToIndex3i(Triangles);

            List <int> groups = null;

            if (addTriGroups)
            {
                groups = new List <int>(TriGroups);
                if (groups.Count != t.Length)
                {
                    TriGroupsMetadata = "Error: incorrect number of groups provided, ignored.";
                    addTriGroups      = false;
                }
            }

            DMesh3 mesh = new DMesh3(addNormals, false, false, addTriGroups);

            AppendNewMesh(mesh);

            // vertices
            for (int i = 0; i < v.Length; ++i)
            {
                mesh.AppendVertex(v[i]);
            }

            // normals
            if (addNormals)
            {
                for (int i = 0; i < n.Length; ++i)
                {
                    mesh.SetVertexNormal(i, n[i]);
                }
                NormalsMetadata = "Ok";
            }

            // triangles
            for (int i = 0; i < t.Length; ++i)
            {
                var last = AppendTriangle(t[i]);
                if (last == DMesh3.InvalidID || last == DMesh3.NonManifoldID)
                {
                    iAppendTriangleIssues++;
                }
            }

            // groups
            if (addTriGroups)
            {
                for (int i = 0; i < t.Length; ++i)
                {
                    mesh.SetTriangleGroup(i, groups[i]);
                }
                TriGroupsMetadata = "Ok";
            }

            // adding the metadata
            //
            mesh.AttachMetadata("AppendTriangleIssues", iAppendTriangleIssues);
            mesh.AttachMetadata("Normals", NormalsMetadata);
            mesh.AttachMetadata("TriGroups", TriGroupsMetadata);

            return(mesh);
        }
Beispiel #15
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);
        }
Beispiel #16
0
        protected override Result RunCommand(RhinoDoc doc, RunMode mode)
        {
            bool bHavePreselectedObjects = false;

            const ObjectType geometryFilter = ObjectType.MeshFace;

            OptionDouble  minEdgeLengthOption     = new OptionDouble(minEdgeLength, 0.001, 200);
            OptionDouble  maxEdgeLengthOption     = new OptionDouble(maxEdgeLength, 0.001, 200);
            OptionDouble  constriantAngleOption   = new OptionDouble(constriantAngle, 0.001, 360);
            OptionInteger smoothStepsOptions      = new OptionInteger(smoothSteps, 0, 100);
            OptionDouble  smoothSpeedOption       = new OptionDouble(smoothSpeed, 0.01, 1.0);
            OptionDouble  projectAmountOption     = new OptionDouble(projectedAmount, 0.01, 1.0);
            OptionDouble  projectedDistanceOption = new OptionDouble(projectedDistance, 0.01, 100000.0);

            GetObject go = new GetObject();

            go.SetCommandPrompt("Select mesh faces to project onto another mesh");
            go.GeometryFilter = geometryFilter;

            go.AddOptionDouble("ConstraintAngle", ref constriantAngleOption);
            go.AddOptionDouble("MinEdge", ref minEdgeLengthOption);
            go.AddOptionDouble("MaxEdge", ref maxEdgeLengthOption);
            go.AddOptionInteger("SmoothSteps", ref smoothStepsOptions);
            go.AddOptionDouble("SmoothSpeed", ref smoothSpeedOption);

            go.GroupSelect     = true;
            go.SubObjectSelect = true;

            for (; ;)
            {
                GetResult faceres = go.GetMultiple(1, 0);

                if (faceres == GetResult.Option)
                {
                    go.EnablePreSelect(false, true);
                    continue;
                }

                else if (go.CommandResult() != Result.Success)
                {
                    return(go.CommandResult());
                }

                if (go.ObjectsWerePreselected)
                {
                    bHavePreselectedObjects = true;
                    go.EnablePreSelect(false, true);
                    continue;
                }

                break;
            }

            minEdgeLength   = minEdgeLengthOption.CurrentValue;
            maxEdgeLength   = maxEdgeLengthOption.CurrentValue;
            constriantAngle = constriantAngleOption.CurrentValue;
            smoothSteps     = smoothStepsOptions.CurrentValue;
            smoothSpeed     = smoothSpeedOption.CurrentValue;

            //System.Collections.Generic.List<System.Guid> meshes = new System.Collections.Generic.List<System.Guid>();

            System.Guid rhinoMesh = System.Guid.Empty;

            System.Collections.Generic.List <int> removeFaces = new System.Collections.Generic.List <int>();

            g3.DMesh3 projectFaces = new g3.DMesh3(true, false, false, false);

            Rhino.Geometry.Mesh rhinoInputMesh = new Rhino.Geometry.Mesh();

            for (int i = 0; i < go.ObjectCount; i++)
            {
                ObjRef obj = go.Object(i);

                if (rhinoMesh == System.Guid.Empty)
                {
                    rhinoMesh      = obj.ObjectId;
                    rhinoInputMesh = obj.Mesh();

                    for (int j = 0; j < rhinoInputMesh.Vertices.Count; j++)
                    {
                        var vertex = new g3.NewVertexInfo();
                        vertex.n = new g3.Vector3f(rhinoInputMesh.Normals[j].X, rhinoInputMesh.Normals[j].Y, rhinoInputMesh.Normals[j].Z);
                        vertex.v = new g3.Vector3d(rhinoInputMesh.Vertices[j].X, rhinoInputMesh.Vertices[j].Y, rhinoInputMesh.Vertices[j].Z);
                        projectFaces.AppendVertex(vertex);
                    }
                }

                var m = rhinoInputMesh;

                if (rhinoMesh != obj.ObjectId)
                {
                    continue;
                }

                removeFaces.Add(obj.GeometryComponentIndex.Index);

                var mf = rhinoInputMesh.Faces[obj.GeometryComponentIndex.Index];


                if (mf.IsQuad)
                {
                    double dist1 = m.Vertices[mf.A].DistanceTo(m.Vertices[mf.C]);
                    double dist2 = m.Vertices[mf.B].DistanceTo(m.Vertices[mf.D]);
                    if (dist1 > dist2)
                    {
                        projectFaces.AppendTriangle(mf.A, mf.B, mf.D);
                        projectFaces.AppendTriangle(mf.B, mf.C, mf.D);
                    }
                    else
                    {
                        projectFaces.AppendTriangle(mf.A, mf.B, mf.C);
                        projectFaces.AppendTriangle(mf.A, mf.C, mf.D);
                    }
                }
                else
                {
                    projectFaces.AppendTriangle(mf.A, mf.B, mf.C);
                }
            }

            if (rhinoInputMesh == null)
            {
                return(Result.Failure);
            }

            removeFaces.Sort();
            removeFaces.Reverse();

            foreach (var removeFace in removeFaces)
            {
                rhinoInputMesh.Faces.RemoveAt(removeFace);
            }

            rhinoInputMesh.Compact();

            GetObject goProjected = new GetObject();

            goProjected.EnablePreSelect(false, true);
            goProjected.SetCommandPrompt("Select mesh to project to");
            goProjected.GeometryFilter = ObjectType.Mesh;
            goProjected.AddOptionDouble("ConstraintAngle", ref constriantAngleOption);
            goProjected.AddOptionDouble("MinEdge", ref minEdgeLengthOption);
            goProjected.AddOptionDouble("MaxEdge", ref maxEdgeLengthOption);
            goProjected.AddOptionInteger("SmoothSteps", ref smoothStepsOptions);
            goProjected.AddOptionDouble("SmoothSpeed", ref smoothSpeedOption);
            goProjected.AddOptionDouble("ProjectAmount", ref projectAmountOption);
            goProjected.AddOptionDouble("ProjectDistance", ref projectedDistanceOption);

            goProjected.GroupSelect     = true;
            goProjected.SubObjectSelect = false;
            goProjected.EnableClearObjectsOnEntry(false);
            goProjected.EnableUnselectObjectsOnExit(false);


            for (; ;)
            {
                GetResult resProject = goProjected.Get();

                if (resProject == GetResult.Option)
                {
                    continue;
                }
                else if (goProjected.CommandResult() != Result.Success)
                {
                    return(goProjected.CommandResult());
                }

                break;
            }


            minEdgeLength     = minEdgeLengthOption.CurrentValue;
            maxEdgeLength     = maxEdgeLengthOption.CurrentValue;
            constriantAngle   = constriantAngleOption.CurrentValue;
            smoothSteps       = smoothStepsOptions.CurrentValue;
            smoothSpeed       = smoothSpeedOption.CurrentValue;
            projectedAmount   = projectAmountOption.CurrentValue;
            projectedDistance = projectedDistanceOption.CurrentValue;

            if (bHavePreselectedObjects)
            {
                // Normally, pre-selected objects will remain selected, when a
                // command finishes, and post-selected objects will be unselected.
                // This this way of picking, it is possible to have a combination
                // of pre-selected and post-selected. So, to make sure everything
                // "looks the same", lets unselect everything before finishing
                // the command.
                for (int i = 0; i < go.ObjectCount; i++)
                {
                    RhinoObject rhinoObject = go.Object(i).Object();
                    if (null != rhinoObject)
                    {
                        rhinoObject.Select(false);
                    }
                }
                doc.Views.Redraw();
            }

            bool result = false;

            if (goProjected.ObjectCount < 1)
            {
                return(Result.Failure);
            }


            var rhinoMeshProject = goProjected.Object(0).Mesh();

            if (rhinoMeshProject == null || !rhinoMeshProject.IsValid)
            {
                return(Result.Failure);
            }

            var meshProjected = GopherUtil.ConvertToD3Mesh(rhinoMeshProject);

            var res = GopherUtil.RemeshMesh(projectFaces, (float)minEdgeLength, (float)maxEdgeLength, (float)constriantAngle, (float)smoothSpeed, smoothSteps, meshProjected, (float)projectedAmount, (float)projectedDistance);

            var newRhinoMesh = GopherUtil.ConvertToRhinoMesh(res);

            if (newRhinoMesh != null && newRhinoMesh.IsValid)
            {
                newRhinoMesh.Append(rhinoInputMesh);

                result |= doc.Objects.Replace(rhinoMesh, newRhinoMesh);
            }

            doc.Views.Redraw();

            return(Result.Success);
        }
        //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]);
                            }
                        }
                    }
                }
            }
        }