/// <summary> /// /// </summary> /// <typeparam name="V"></typeparam> /// <typeparam name="E"></typeparam> /// <typeparam name="F"></typeparam> /// <param name="mesh"></param> /// <param name="position"></param> public static void TriSplit <V, E, F>(HeMeshBase <V, E, F> mesh, Property <V, Vec3d> position) where V : HeMeshBase <V, E, F> .Vertex where E : HeMeshBase <V, E, F> .Halfedge where F : HeMeshBase <V, E, F> .Face { // TODO }
/// <summary> /// /// </summary> /// <param name="mesh"></param> /// <returns></returns> public G CreateFromFaceTopology(HeMeshBase <HeMesh3d.Vertex, HeMesh3d.Halfedge, HeMesh3d.Face> mesh) { var graph = Create(mesh.Faces.Count, mesh.Halfedges.Count); graph.AppendFaceTopology(mesh); return(graph); }
/// <summary> /// /// </summary> /// <typeparam name="V"></typeparam> /// <typeparam name="E"></typeparam> /// <typeparam name="F"></typeparam> /// <param name="mesh"></param> /// <param name="first"></param> /// <param name="position"></param> public static void Unroll <V, E, F>(HeMeshBase <V, E, F> mesh, F first, Property <V, Vec3d> position) where V : HeMeshBase <V, E, F> .Vertex where E : HeMeshBase <V, E, F> .Halfedge where F : HeMeshBase <V, E, F> .Face { Unroll(mesh, first, position, delegate { }); }
/// <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>(HeMeshBase <V, E, F> mesh, Property <V, Vec3d> position) where V : HeMeshBase <V, E, F> .Vertex where E : HeMeshBase <V, E, F> .Halfedge where F : HeMeshBase <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) { position.Set(v, he.Lerp(position.Get, 0.5)); } } }
/// <summary> /// /// </summary> private static void CatmullClarkSmoothFixed <V, E, F>(HeMeshBase <V, E, F> mesh, Property <V, Vec3d> position) 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; int ev0 = verts.Count - mesh.Edges.Count; // index of first edge vertex int fv0 = ev0 - mesh.Faces.Count; // index of first face vertex // set old vertices for (int i = 0; i < fv0; i++) { var v = verts[i]; if (v.IsUnused || v.IsBoundary) { continue; // skip boundary verts } var fsum = new Vec3d(); var 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++; } var t = 1.0 / n; position.Set(v, (position.Get(v) * (n - 3) + fsum * t + 2 * esum * t) * t); } }
/// <summary> /// Applies a single iteration of Catmull-Clark subdivision to the given mesh. /// If using external buffers to store vertex attributes, the number of vertices after subdivision equals the sum of the number of vertices, edges, 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> public static void QuadSplit <V, E, F>(HeMeshBase <V, E, F> mesh, Property <V, Vec3d> position) where V : HeVertex <V, E, F> where E : Halfedge <V, E, F> where F : HeFace <V, E, F> { QuadSplitGeometry(mesh, position); QuadSplitTopology(mesh); }
/// <summary> /// Applies a single iteration of Catmull-Clark subdivision to the given mesh. /// If using external buffers to store vertex attributes, the number of vertices after subdivision equals the sum of the number of vertices edges and faces in the initial 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>(HeMeshBase <V, E, F> mesh, Property <V, Vec3d> position, SmoothBoundaryType boundaryType) where V : HeVertex <V, E, F> where E : Halfedge <V, E, F> where F : HeFace <V, E, F> { CatmullClarkGeometry(mesh, position, boundaryType); QuadSplitTopology(mesh); }
/// <summary> /// /// </summary> /// <typeparam name="V"></typeparam> /// <typeparam name="E"></typeparam> /// <typeparam name="F"></typeparam> /// <param name="mesh"></param> /// <param name="position"></param> public static void Loop <V, E, F>(HeMeshBase <V, E, F> mesh, Property <V, Vec3d> position) where V : HeVertex <V, E, F> where E : Halfedge <V, E, F> where F : HeFace <V, E, F> { // TODO throw new NotImplementedException(); }
/// <summary> /// /// </summary> /// <typeparam name="V"></typeparam> /// <typeparam name="E"></typeparam> /// <typeparam name="F"></typeparam> /// <param name="mesh"></param> /// <param name="hedge"></param> /// <returns></returns> public static HeQuadStrip <V, E, F> GetQuadStrip <V, E, F>(HeMeshBase <V, E, F> mesh, E hedge) where V : HeMeshBase <V, E, F> .Vertex where E : HeMeshBase <V, E, F> .Halfedge where F : HeMeshBase <V, E, F> .Face { mesh.Halfedges.ContainsCheck(hedge); return(GetQuadStrip <V, E, F>(hedge, mesh.Faces.NextTag)); }
/// <summary> /// /// </summary> /// <typeparam name="V"></typeparam> /// <typeparam name="E"></typeparam> /// <typeparam name="F"></typeparam> /// <param name="mesh"></param> /// <param name="first"></param> public static void Unroll <V, E, F>(HeMeshBase <V, E, F> mesh, F first) where V : HeVertex <V, E, F>, IVertex3d where E : Halfedge <V, E, F> where F : HeFace <V, E, F> { var prop = Property.Create <V, Vec3d>(v => v.Position, (v, p) => v.Position = p); Unroll(mesh, first, prop, delegate { }); }
/// <summary> /// /// </summary> /// <typeparam name="TV"></typeparam> /// <typeparam name="TE"></typeparam> /// <typeparam name="TF"></typeparam> /// <param name="mesh"></param> /// <param name="target"></param> /// <param name="features"></param> /// <param name="tolerance"></param> /// <returns></returns> public static Solver Create <TV, TE, TF>(HeMeshBase <TV, TE, TF> mesh, IEnumerable <IFeature> features, double tolerance = 1.0e-4) where TV : HeMeshBase <TV, TE, TF> .Vertex, IVertex3d where TE : HeMeshBase <TV, TE, TF> .Halfedge where TF : HeMeshBase <TV, TE, TF> .Face { var copy = HeMesh.Factory.CreateCopy(mesh, (v0, v1) => v0.Position = v1.Position, delegate { }, delegate { }); return(new Solver(copy, features, tolerance)); }
/// <summary> /// /// </summary> /// <typeparam name="V"></typeparam> /// <typeparam name="E"></typeparam> /// <typeparam name="F"></typeparam> /// <param name="mesh"></param> /// <param name="first"></param> /// <param name="position"></param> /// <param name="setChildIndex"></param> public static void Unroll <V, E, F>(HeMeshBase <V, E, F> mesh, F first, Property <V, Vec3d> position, Action <E, int> setChildIndex) where V : HeVertex <V, E, F> where E : Halfedge <V, E, F> where F : HeFace <V, E, F> { var unroller = new HeMeshUnroller <V, E, F>(mesh, first, position); unroller.Unroll(setChildIndex); }
/// <summary> /// /// </summary> /// <typeparam name="TV"></typeparam> /// <typeparam name="TE"></typeparam> /// <typeparam name="TF"></typeparam> /// <param name="mesh"></param> /// <param name="target"></param> /// <param name="features"></param> /// <param name="tolerance"></param> /// <returns></returns> public static DynamicRemesher Create <TV, TE, TF>(HeMeshBase <TV, TE, TF> mesh, MeshFeature target, IEnumerable <IFeature> features, double tolerance = 1.0e-4) where TV : HeVertex <TV, TE, TF>, IVertex3d where TE : Halfedge <TV, TE, TF> where TF : HeFace <TV, TE, TF> { var copy = HeMeshSim.Factory.CreateCopy(mesh, (v0, v1) => v0.Position = v1.Position, delegate { }, delegate { }); return(new DynamicRemesher(copy, target, features, tolerance)); }
/// <summary> /// /// </summary> /// <typeparam name="V"></typeparam> /// <typeparam name="E"></typeparam> /// <typeparam name="F"></typeparam> /// <param name="mesh"></param> /// <param name="first"></param> /// <param name="setChildIndex"></param> public static void Unroll <V, E, F>(HeMeshBase <V, E, F> mesh, F first, Action <E, int> setChildIndex) where V : HeVertex <V, E, F>, IVertex3d where E : Halfedge <V, E, F> where F : HeFace <V, E, F> { var prop = Property.Create <V, Vec3d>(v => v.Position, (v, p) => v.Position = p); Unroll(mesh, first, prop, setChildIndex); }
/// <summary> /// /// </summary> /// <typeparam name="V"></typeparam> /// <typeparam name="E"></typeparam> /// <typeparam name="F"></typeparam> /// <param name="mesh"></param> /// <param name="first"></param> /// <param name="setChildIndex"></param> public static void Unroll <V, E, F>(HeMeshBase <V, E, F> mesh, F first, Func <E, double> getUnrollFactor, Action <E, int> setChildIndex) where V : HeMeshBase <V, E, F> .Vertex, IVertex3d where E : HeMeshBase <V, E, F> .Halfedge where F : HeMeshBase <V, E, F> .Face { var prop = Property.Create <V, Vec3d>(v => v.Position, (v, p) => v.Position = p); Unroll(mesh, first, prop, getUnrollFactor, setChildIndex); }
/// <summary> /// /// </summary> /// <typeparam name="UV"></typeparam> /// <typeparam name="UE"></typeparam> /// <typeparam name="UF"></typeparam> /// <param name="mesh"></param> /// <param name="setHedge"></param> /// <param name="setVertex"></param> /// <returns></returns> public TG CreateFromFaceTopology <UV, UE, UF>(HeMeshBase <UV, UE, UF> mesh, Action <TV, UF> setVertex, Action <TE, UE> setHedge) where UV : HeVertex <UV, UE, UF> where UE : Halfedge <UV, UE, UF> where UF : HeFace <UV, UE, UF> { var result = Create(mesh.Faces.Count, mesh.Halfedges.Count); result.AppendFaceTopology(mesh, setVertex, setHedge); return(result); }
/// <summary> /// /// </summary> /// <typeparam name="UV"></typeparam> /// <typeparam name="UE"></typeparam> /// <typeparam name="UF"></typeparam> /// <param name="mesh"></param> /// <param name="setVertex"></param> /// <param name="setHedge"></param> /// <returns></returns> public TG CreateFromVertexTopology <UV, UE, UF>(HeMeshBase <UV, UE, UF> mesh, Action <TV, UV> setVertex = null, Action <TE, UE> setHedge = null) where UV : HeMeshBase <UV, UE, UF> .Vertex where UE : HeMeshBase <UV, UE, UF> .Halfedge where UF : HeMeshBase <UV, UE, UF> .Face { var result = Create(mesh.Vertices.Count, mesh.Halfedges.Count); result.AppendVertexTopology(mesh, setVertex, setHedge); return(result); }
/// <summary> /// Action delegates specify how attributes of original elements are mapped to attributes of copied elements. /// </summary> /// <typeparam name="UV"></typeparam> /// <typeparam name="UE"></typeparam> /// <typeparam name="UF"></typeparam> /// <param name="mesh"></param> /// <param name="setVertex"></param> /// <param name="setHedge"></param> /// <param name="setFace"></param> /// <returns></returns> public TM CreateCopy <UV, UE, UF>(HeMeshBase <UV, UE, UF> mesh, Action <TV, UV> setVertex, Action <TE, UE> setHedge, Action <TF, UF> setFace) where UV : HeVertex <UV, UE, UF> where UE : Halfedge <UV, UE, UF> where UF : HeFace <UV, UE, UF> { var copy = Create(mesh.Vertices.Capacity, mesh.Halfedges.Capacity, mesh.Faces.Capacity); copy.Append(mesh, setVertex, setHedge, setFace); return(copy); }
/// <summary> /// /// </summary> /// <param name="path"></param> /// <param name="graph"></param> /// <param name="setVertexAttributes"></param> /// <param name="setHedgeAttributes"></param> public static void ReadFromJson <TV, TE, TF>(string path, HeMeshBase <TV, TE, TF> mesh, Action <TV, object[]> setVertexAttributes = null, Action <TE, object[]> setHedgeAttributes = null, Action <TF, object[]> setFaceAttributes = null) where TV : HeMeshBase <TV, TE, TF> .Vertex where TE : HeMeshBase <TV, TE, TF> .Halfedge where TF : HeMeshBase <TV, TE, TF> .Face { //var buffer = CoreIO.DeserializeJson<HeMeshJsonBuffer>(path); var buffer = CoreIO.DeserializeJson <HeJsonBuffer>(path); buffer.ReadTo(mesh, setVertexAttributes, setHedgeAttributes, setFaceAttributes); }
/// <summary> /// /// </summary> /// <typeparam name="TV"></typeparam> /// <typeparam name="TE"></typeparam> public static void WriteToJson <TV, TE, TF>(HeMeshBase <TV, TE, TF> mesh, string path, Func <TV, IEnumerable <object> > getVertexAttributes = null, Func <TE, IEnumerable <object> > getHedgeAttributes = null, Func <TF, IEnumerable <object> > getFaceAttributes = null) where TV : HeMeshBase <TV, TE, TF> .Vertex where TE : HeMeshBase <TV, TE, TF> .Halfedge where TF : HeMeshBase <TV, TE, TF> .Face { var buffer = new HeJsonBuffer(); buffer.WriteFrom(mesh, getVertexAttributes, getHedgeAttributes, getFaceAttributes); CoreIO.SerializeJson(buffer, path); }
/// <summary> /// Returns the dual of the given mesh. /// Action delegates specify how attributes of primal elements are mapped to attributes of dual elements. /// Note this method preserves indexical correspondance between primal and dual elements. /// </summary> /// <typeparam name="UV"></typeparam> /// <typeparam name="UE"></typeparam> /// <typeparam name="UF"></typeparam> /// <param name="mesh"></param> /// <param name="setVertex"></param> /// <param name="setHedge"></param> /// <param name="setFace"></param> /// <returns></returns> public TM CreateDual <UV, UE, UF>(HeMeshBase <UV, UE, UF> mesh, Action <TV, UF> setVertex, Action <TE, UE> setHedge, Action <TF, UV> setFace) where UV : HeVertex <UV, UE, UF> where UE : Halfedge <UV, UE, UF> where UF : HeFace <UV, UE, UF> { var dual = Create(mesh.Vertices.Capacity, mesh.Halfedges.Capacity, mesh.Faces.Capacity); dual.AppendDual(mesh, setVertex, setHedge, setFace); return(dual); }
/// <summary> /// /// </summary> /// <typeparam name="V"></typeparam> /// <typeparam name="E"></typeparam> /// <typeparam name="F"></typeparam> /// <param name="mesh"></param> /// <param name="first"></param> /// <param name="position"></param> /// <param name="setChildIndex"></param> public static void Unroll <V, E, F>(HeMeshBase <V, E, F> mesh, F first, Property <V, Vec3d> position, Action <E, int> setChildIndex) where V : HeMeshBase <V, E, F> .Vertex where E : HeMeshBase <V, E, F> .Halfedge where F : HeMeshBase <V, E, F> .Face { var unroller = new HeMeshUnroller <V, E, F>(mesh, first, position); unroller.DetachFaceCycles(setChildIndex); unroller.Unroll(); }
/// <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, HeMeshBase <TV, TE, TF> mesh, Action <TV, Vec3d> setPosition) where TV : HeVertex <TV, TE, TF> where TE : Halfedge <TV, TE, TF> where TF : HeFace <TV, TE, TF> { var verts = mesh.Vertices; var faces = mesh.Faces; var face = new List <int>(); using (var reader = new StreamReader(path, Encoding.ASCII)) { 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(_separatorsOBJ, 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(_faceSeparatorsOBJ); face.Add(int.Parse(ids[0]) - 1); } mesh.AddFace(face); face.Clear(); break; } } } } }
/// <summary> /// If using external buffers to store vertex attributes, the number of vertices in the resulting mesh the equals the sum of the number of vertices and halfedges in the given mesh. /// </summary> /// <typeparam name="UV"></typeparam> /// <typeparam name="UE"></typeparam> /// <typeparam name="UF"></typeparam> /// <param name="mesh"></param> /// <param name="getPosition"></param> /// <param name="getScale"></param> /// <param name="getCenter"></param> /// <param name="setPosition"></param> /// <returns></returns> public TM CreateFramedDual <UV, UE, UF>(HeMeshBase <UV, UE, UF> mesh, Func <UV, Vec3d> getPosition, Func <UV, double> getScale, Func <UF, Vec3d> getCenter, Action <TV, Vec3d> setPosition) where UV : HeVertex <UV, UE, UF> where UE : Halfedge <UV, UE, UF> where UF : HeFace <UV, UE, UF> { int ne = mesh.Edges.Count; var result = Create(ne << 3, ne << 4, ne << 3); //CreateWeaveGeometry(mesh, result, getPosition, getScale, getNormal, getCenter, setPosition); //CreateWeaveTopology(mesh, result); return(result); }
/// <summary> /// /// </summary> /// <typeparam name="UV"></typeparam> /// <typeparam name="UE"></typeparam> /// <typeparam name="UF"></typeparam> /// <param name="mesh"></param> /// <param name="setVertex"></param> /// <param name="setHedge"></param> public void AppendVertexTopology <UV, UE, UF>(HeMeshBase <UV, UE, UF> mesh, Action <TV, UV> setVertex, Action <TE, UE> setHedge) where UV : HeVertex <UV, UE, UF> where UE : Halfedge <UV, UE, UF> where UF : HeFace <UV, UE, UF> { int nhe = _hedges.Count; int nv = _vertices.Count; var meshHedges = mesh.Halfedges; var meshVerts = mesh.Vertices; // append new elements for (int i = 0; i < meshVerts.Count; i++) { AddVertex(); } for (int i = 0; i < meshHedges.Count; i += 2) { AddEdge(); } // link new vertices to new halfedges for (int i = 0; i < meshVerts.Count; i++) { var v0 = meshVerts[i]; var v1 = _vertices[i + nv]; setVertex(v1, v0); if (v0.IsRemoved) { continue; } v1.FirstOut = _hedges[v0.FirstOut.Index + nhe]; } // link new halfedges to eachother and new vertices for (int i = 0; i < meshHedges.Count; i++) { var he0 = meshHedges[i]; var he1 = _hedges[i + nhe]; setHedge(he1, he0); if (he0.IsRemoved) { continue; } he1.PrevAtStart = _hedges[he0.PrevAtStart.Index + nhe]; he1.NextAtStart = _hedges[he0.NextAtStart.Index + nhe]; he1.Start = _vertices[he0.Start.Index + nv]; } }
/* * /// <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); } } }
/// <summary> /// /// </summary> private static void CatmullClarkSmoothCornerFixed <V, E, F>(HeMeshBase <V, E, F> mesh, Property <V, Vec3d> position) where V : HeVertex <V, E, F> where E : Halfedge <V, E, F> where F : HeFace <V, E, F> { var verts = mesh.Vertices; int ev0 = verts.Count - mesh.Edges.Count; // index of first edge vertex int fv0 = ev0 - mesh.Faces.Count; // index of first face vertex // set old vertices for (int i = 0; i < fv0; i++) { var v = verts[i]; if (v.IsRemoved) { continue; } if (v.IsBoundary) { var he0 = v.FirstOut; if (he0.IsAtDegree2) { continue; // skip corner verts } 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); } } }
/// <summary> /// /// </summary> private void CreateWeaveGeometry <UV, UE, UF>(HeMeshBase <UV, UE, UF> mesh, TM newMesh, Func <UV, Vec3d> getPosition, Func <UE, double> getScale, Func <UE, Vec3d> getNormal, Func <UF, Vec3d> getCenter, Action <TV, Vec3d> setPosition) where UV : HeVertex <UV, UE, UF> where UE : Halfedge <UV, UE, UF> where UF : HeFace <UV, UE, UF> { var edges = mesh.Edges; int ne = edges.Count; // bulk add new vertices newMesh.AddVertices(ne << 3); var newVerts = newMesh.Vertices; // add vertices (8 per halfedge pair in m0) for (int i = 0; i < ne; i++) { var he0 = edges[i]; var he1 = he0.Twin; var f0 = he0.Face; var f1 = he1.Face; // scale points to mid point of edge Vec3d p0 = getPosition(he0.Start); Vec3d p1 = getPosition(he1.Start); Vec3d p = (p0 + p1) * 0.5; var t = getScale(he0); p0 = Vec3d.Lerp(p, p0, t); p1 = Vec3d.Lerp(p, p1, t); Vec3d p2 = (f0 == null) ? new Vec3d() : Vec3d.Lerp(p, getCenter(f0), t); Vec3d p3 = (f1 == null) ? new Vec3d() : Vec3d.Lerp(p, getCenter(f1), t); // set vertex positions Vec3d d = he0.IsBoundary ? Vec3d.Zero : getNormal(he0); int j = i << 3; setPosition(newVerts[j], p0 - d); setPosition(newVerts[j + 1], p2 - d); setPosition(newVerts[j + 2], p0 + d); setPosition(newVerts[j + 3], p2 + d); setPosition(newVerts[j + 4], p1 - d); setPosition(newVerts[j + 5], p3 - d); setPosition(newVerts[j + 6], p1 + d); setPosition(newVerts[j + 7], p3 + d); } }
/// <summary> /// /// </summary> /// <typeparam name="UV"></typeparam> /// <typeparam name="UE"></typeparam> /// <typeparam name="UF"></typeparam> /// <param name="mesh"></param> /// <param name="setVertex"></param> /// <param name="setHedge"></param> /// <param name="setFace"></param> /// <param name="componentIndices"></param> /// <param name="edgeIndices"></param> /// <returns></returns> public TM[] CreateConnectedComponents <UV, UE, UF>(HeMeshBase <UV, UE, UF> mesh, Action <TV, UV> setVertex, Action <TE, UE> setHedge, Action <TF, UF> setFace, out int[] componentIndices, out int[] edgeIndices) where UV : HeVertex <UV, UE, UF> where UE : Halfedge <UV, UE, UF> where UF : HeFace <UV, UE, UF> { int ne = mesh.Edges.Count; componentIndices = new int[ne]; edgeIndices = new int[ne]; return(CreateConnectedComponents(mesh, setVertex, setHedge, setFace, ToProp(componentIndices), ToProp(edgeIndices))); Property <UE, T> ToProp <T>(T[] values) { return(Property.Create <UE, T>(he => values[he >> 1], (he, i) => values[he >> 1] = i)); } }
/// <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>(HeMeshBase <V, E, F> mesh, Property <V, Vec3d> position, SmoothBoundaryType boundaryType) where V : HeVertex <V, E, F> where E : Halfedge <V, E, F> where F : HeFace <V, E, F> { 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.IsRemoved) { position.Set(v, f.Vertices.Mean(position.Get)); } } // create edge vertices foreach (var he0 in mesh.Edges) { var v = mesh.AddVertex(); if (he0.IsRemoved) { continue; } if (he0.IsBoundary) { position.Set(v, 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(v, (p0 + p1 + p2 + p3) * 0.25); } // smooth old vertices CatmullClarkSmooth(mesh, position, boundaryType); }