/* * /// <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 : HeVertex<V, E, F> * where E : Halfedge<V, E, F> * where F : HeFace<V, E, F> * { * 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 : HeVertex<V, E, F> * where E : Halfedge<V, E, F> * where F : HeFace<V, E, F> * { * 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.IsRemoved) * 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.IsRemoved) 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.IsRemoved) 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>(HeMeshBase <V, E, F> mesh, Property <V, Vec3d> position, bool skipBoundary) where V : HeVertex <V, E, F> where E : Halfedge <V, E, F> where F : HeFace <V, E, F> { 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.IsRemoved) { 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.IsRemoved || he.IsBoundary) { continue; } mesh.MergeFaces(he); } } else { for (int i = 0; i < ne; i++) { var he = edges[i]; if (he.IsRemoved) { continue; } mesh.MergeFaces(he); } } }