//
        // 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);
        }
        //
        // 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);
        }
        /// <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);
        }