/// <summary>
        ///
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <typeparam name="E"></typeparam>
        /// <typeparam name="F"></typeparam>
        /// <param name="mesh"></param>
        /// <param name="position"></param>
        private static void QuadSplitGeometry <V, E, F>(HeMesh <V, E, F> mesh, Property <V, Vec3d> position)
            where V : HeMesh <V, E, F> .Vertex
            where E : HeMesh <V, E, F> .Halfedge
            where F : HeMesh <V, E, F> .Face
        {
            // create face vertices
            foreach (var f in mesh.Faces)
            {
                var v = mesh.AddVertex();

                if (!f.IsUnused)
                {
                    position.Set(v, f.Vertices.Mean(position.Get));
                }
            }

            // create edge vertices
            foreach (var he in mesh.Edges)
            {
                var v = mesh.AddVertex();

                if (!he.IsUnused)
                {
                    var p = (position.Get(he.Start) + position.Get(he.End)) * 0.5;
                    position.Set(v, p);
                }
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <typeparam name="E"></typeparam>
        /// <typeparam name="F"></typeparam>
        /// <param name="mesh"></param>
        /// <param name="position"></param>
        /// <param name="boundaryType"></param>
        private static void CatmullClarkGeometry <V, E, F>(HeMesh <V, E, F> mesh, Property <V, Vec3d> position, SmoothBoundaryType boundaryType)
            where V : HeMesh <V, E, F> .Vertex
            where E : HeMesh <V, E, F> .Halfedge
            where F : HeMesh <V, E, F> .Face
        {
            var verts = mesh.Vertices;
            int fv0   = verts.Count; // index of first face vertex

            // create face vertices
            foreach (var f in mesh.Faces)
            {
                var v = mesh.AddVertex();

                if (!f.IsUnused)
                {
                    position.Set(v, f.Vertices.Mean(position.Get));
                }
            }

            // create edge vertices
            foreach (var he0 in mesh.Edges)
            {
                var v = mesh.AddVertex();
                if (he0.IsUnused)
                {
                    continue;
                }

                if (he0.IsBoundary)
                {
                    var p = (position.Get(he0.Start) + position.Get(he0.End)) * 0.5;
                    position.Set(v, p);
                    continue;
                }

                var he1 = he0.Twin;
                var p0  = position.Get(he0.Start);
                var p1  = position.Get(he1.Start);
                var p2  = position.Get(verts[he0.Face.Index + fv0]);
                var p3  = position.Get(verts[he1.Face.Index + fv0]);
                position.Set(v, (p0 + p1 + p2 + p3) * 0.25);
            }

            // smooth old vertices
            CatmullClarkSmooth(mesh, position, boundaryType);
        }
Exemple #3
0
        /// <summary>
        /// Implementation currently ignores texture coordinates and normals.
        /// </summary>
        /// <typeparam name="TV"></typeparam>
        /// <typeparam name="TE"></typeparam>
        /// <typeparam name="TF"></typeparam>
        /// <param name="path"></param>
        /// <param name="mesh"></param>
        /// <param name="setPosition"></param>
        public static void ReadFromObj <TV, TE, TF>(string path, HeMesh <TV, TE, TF> mesh, Action <TV, Vec3d> setPosition)
            where TV : HeMesh <TV, TE, TF> .Vertex
            where TE : HeMesh <TV, TE, TF> .Halfedge
            where TF : HeMesh <TV, TE, TF> .Face
        {
            var verts = mesh.Vertices;
            var faces = mesh.Faces;
            var face  = new List <int>();

            using (var reader = new StreamReader(path))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    // skip empty lines and comments
                    if (line.Length == 0 || line[0] == '#')
                    {
                        continue;
                    }

                    // check the first character
                    var segments = line.Split(ObjUtil.Separators, StringSplitOptions.RemoveEmptyEntries);
                    switch (segments[0])
                    {
                    case "v":
                    {
                        // parse vertex
                        double x = double.Parse(segments[1]);
                        double y = double.Parse(segments[2]);
                        double z = double.Parse(segments[3]);

                        var v = mesh.AddVertex();
                        setPosition(v, new Vec3d(x, y, z));
                        break;
                    }

                    case "f":
                    {
                        // parse face
                        for (int i = 1; i < segments.Length; i++)
                        {
                            var ids = segments[i].Split(ObjUtil.FaceSeparators);
                            face.Add(int.Parse(ids[0]) - 1);
                        }

                        mesh.AddFace(face);
                        face.Clear();
                        break;
                    }
                    }
                }
            }
        }
        /*
         * /// <summary>
         * /// Applies a single iteration of Catmull-Clark subdivision to the given mesh.
         * /// http://rosettacode.org/wiki/Catmull%E2%80%93Clark_subdivision_surface
         * /// http://w3.impa.br/~lcruz/courses/cma/surfaces.html
         * /// </summary>
         * /// <typeparam name="V"></typeparam>
         * /// <typeparam name="E"></typeparam>
         * /// <typeparam name="F"></typeparam>
         * /// <param name="mesh"></param>
         * /// <param name="position"></param>
         * /// <param name="boundaryType"></param>
         * public static void CatmullClark<V, E, F>(HeMesh<V, E, F> mesh, Property<V, Vec3d> position, SmoothBoundaryType boundaryType, bool parallel)
         *  where V : HeMeshBase<V, E, F>.Vertex
         *  where E : HeMeshBase<V, E, F>.Halfedge
         *  where F : HeMeshBase<V, E, F>.Face
         * {
         *  CatmullClarkGeometry(mesh, position, boundaryType, parallel);
         *  QuadSplitTopology(mesh);
         * }
         *
         *
         * /// <summary>
         * ///
         * /// </summary>
         * private static void CatmullClarkGeometry<V, E, F>(HeMesh<V, E, F> mesh, Property<V, Vec3d> position, SmoothBoundaryType boundaryType, bool parallel)
         * where V : HeMeshBase<V, E, F>.Vertex
         * where E : HeMeshBase<V, E, F>.Halfedge
         * where F : HeMeshBase<V, E, F>.Face
         * {
         *  var verts = mesh.Vertices;
         *  var edges = mesh.Edges;
         *  var faces = mesh.Faces;
         *
         *  int fv0 = verts.Count; // index of first face vertex
         *  int ev0 = verts.Count + faces.Count;
         *
         *  // add all new vertices
         *  mesh.AddVertices(faces.Count);
         *  mesh.AddVertices(edges.Count);
         *
         *  // set attributes of face vertices
         *  Action<Tuple<int, int>> setFaceVerts = range =>
         *   {
         *       for (int i = range.Item1; i < range.Item2; i++)
         *       {
         *           var f = faces[i];
         *
         *           if (!f.IsUnused)
         *               position.Set(verts[i + fv0], f.Vertices.Mean(position.Get));
         *       }
         *   };
         *
         *  // set attributes of edge vertices
         *  Action<Tuple<int, int>> setEdgeVerts = range =>
         *  {
         *      for (int i = range.Item1; i < range.Item2; i++)
         *      {
         *          var he0 = edges[i];
         *          if (he0.IsUnused) continue;
         *
         *          if (he0.IsBoundary)
         *          {
         *              position.Set(verts[i + ev0], he0.Lerp(position.Get, 0.5));
         *              continue;
         *          }
         *
         *          var he1 = he0.Twin;
         *          var p0 = position.Get(he0.Start);
         *          var p1 = position.Get(he1.Start);
         *          var p2 = position.Get(verts[he0.Face.Index + fv0]);
         *          var p3 = position.Get(verts[he1.Face.Index + fv0]);
         *          position.Set(verts[i + ev0], (p0 + p1 + p2 + p3) * 0.25);
         *      }
         *  };
         *
         *  // set attributes of old vertices
         *  //CatmullClarkSmooth(mesh, position, boundaryType);
         *  Action<Tuple<int, int>> setOldVerts = range =>
         *  {
         *      for (int i = range.Item1; i < range.Item2; i++)
         *      {
         *          var v = verts[i];
         *          if (v.IsUnused) continue;
         *
         *          if (v.IsBoundary)
         *          {
         *              var he0 = v.FirstOut;
         *              var he1 = he0.PrevInFace;
         *              var p0 = position.Get(verts[(he0.Index >> 1) + ev0]);
         *              var p1 = position.Get(verts[(he1.Index >> 1) + ev0]);
         *              position.Set(v, position.Get(v) * 0.5 + (p0 + p1) * 0.25);
         *          }
         *          else
         *          {
         *              Vec3d fsum = new Vec3d();
         *              Vec3d esum = new Vec3d();
         *              int n = 0;
         *
         *              foreach (var he in v.OutgoingHalfedges)
         *              {
         *                  fsum += position.Get(verts[he.Face.Index + fv0]);
         *                  esum += position.Get(verts[(he.Index >> 1) + ev0]);
         *                  n++;
         *              }
         *
         *              double t = 1.0 / n;
         *              position.Set(v, (position.Get(v) * (n - 3) + fsum * t + 2 * esum * t) * t);
         *          }
         *      }
         *  };
         *
         *
         *  if (parallel)
         *  {
         *      Parallel.ForEach(Partitioner.Create(0, faces.Count), setFaceVerts);
         *      Parallel.ForEach(Partitioner.Create(0, edges.Count), setEdgeVerts);
         *      Parallel.ForEach(Partitioner.Create(0, verts.Count), setOldVerts);
         *  }
         *  else
         *  {
         *      setFaceVerts(Tuple.Create(0, faces.Count));
         *      setEdgeVerts(Tuple.Create(0, edges.Count));
         *      setOldVerts(Tuple.Create(0, verts.Count));
         *  }
         * }
         */

        #endregion


        /// <summary>
        /// If using external buffers to store vertex attributes, the number of vertices after subdivision equals the sum of the number of vertices and faces in the initial mesh.
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <typeparam name="E"></typeparam>
        /// <typeparam name="F"></typeparam>
        /// <param name="mesh"></param>
        /// <param name="position"></param>
        /// <param name="skipBoundary"></param>
        public static void Diagonalize <V, E, F>(HeMesh <V, E, F> mesh, Property <V, Vec3d> position, bool skipBoundary)
            where V : HeMesh <V, E, F> .Vertex
            where E : HeMesh <V, E, F> .Halfedge
            where F : HeMesh <V, E, F> .Face
        {
            var edges = mesh.Edges;
            var faces = mesh.Faces;

            int ne = edges.Count;
            int nf = faces.Count;

            // stellate faces
            for (int i = 0; i < nf; i++)
            {
                var f = faces[i];
                if (f.IsUnused)
                {
                    continue;
                }

                var v = mesh.AddVertex();
                position.Set(v, f.GetBarycenter(position.Get));
                mesh.PokeFaceImpl(f.First, v);
            }

            // merge faces
            if (skipBoundary)
            {
                for (int i = 0; i < ne; i++)
                {
                    var he = edges[i];
                    if (he.IsUnused || he.IsBoundary)
                    {
                        continue;
                    }
                    mesh.MergeFaces(he);
                }
            }
            else
            {
                for (int i = 0; i < ne; i++)
                {
                    var he = edges[i];
                    if (he.IsUnused)
                    {
                        continue;
                    }
                    mesh.MergeFaces(he);
                }
            }
        }
Exemple #5
0
            /// <summary>
            /// Reads this buffer to the given mesh.
            /// </summary>
            public void ReadTo <V, E, F>(HeMesh <V, E, F> mesh, Action <V, VA> setVertexAttributes = null, Action <E, EA> setHedgeAttributes = null, Action <F, FA> setFaceAttributes = null)
                where V : HeMesh <V, E, F> .Vertex
                where E : HeMesh <V, E, F> .Halfedge
                where F : HeMesh <V, E, F> .Face
            {
                var verts  = mesh.Vertices;
                var hedges = mesh.Halfedges;
                var faces  = mesh.Faces;

                int nv  = verts.Count;
                int nhe = hedges.Count;
                int nf  = faces.Count;

                // add new vertices
                for (int i = 0; i < _vertexRefs.Length; i++)
                {
                    mesh.AddVertex();
                }

                // add new halfedges
                for (int i = 0; i < _hedgeRefs.Length; i += 2)
                {
                    mesh.AddEdge();
                }

                // add new faces
                for (int i = 0; i < _faceRefs.Length; i++)
                {
                    mesh.AddFace();
                }

                // link up vertices
                for (int i = 0; i < _vertexRefs.Length; i++)
                {
                    var v = verts[i + nv];

                    var first = _vertexRefs[i];
                    if (first != -1)
                    {
                        v.First = hedges[first + nhe];
                    }
                }

                // link up halfedges
                for (int i = 0; i < _hedgeRefs.Length; i++)
                {
                    var he   = hedges[i + nhe];
                    var refs = _hedgeRefs[i];

                    var prev = refs[0];
                    if (prev != -1)
                    {
                        he.Previous = hedges[prev + nhe];
                    }

                    he.Next  = hedges[refs[1] + nhe];
                    he.Start = verts[refs[2] + nv];

                    var face = refs[3];
                    if (face != -1)
                    {
                        he.Face = faces[face + nf];
                    }
                }

                // link up faces
                for (int i = 0; i < _faceRefs.Length; i++)
                {
                    var f = faces[i + nf];

                    var first = _faceRefs[i];
                    if (first != -1)
                    {
                        f.First = hedges[first + nhe];
                    }
                }

                // TODO validate topology?

                // set vertex attributes
                if (setVertexAttributes != null)
                {
                    for (int i = 0; i < _vertexAttributes.Length; i++)
                    {
                        setVertexAttributes(verts[i + nv], _vertexAttributes[i]);
                    }
                }

                // set vertex attributes
                if (setHedgeAttributes != null)
                {
                    for (int i = 0; i < _hedgeAttributes.Length; i++)
                    {
                        setHedgeAttributes(hedges[i + nhe], _hedgeAttributes[i]);
                    }
                }

                // set vertex attributes
                if (setFaceAttributes != null)
                {
                    for (int i = 0; i < _faceAttributes.Length; i++)
                    {
                        setFaceAttributes(faces[i + nf], _faceAttributes[i]);
                    }
                }
            }