/// <summary> /// A class containing static methods for computing curvature on a mesh. /// </summary> public static PrincipalCurvature DiagonalizeCurvature(UV src, KUV srcK, Vector3D dstNormal) { UV rotated = Transform.RotateCoordinateSystem(src, dstNormal); double c = 1.0; double s = 0.0; double t = 0.0; // Jacobi rotation to diagonalize if (srcK.UV != 0.0f) { double h = 0.5f * (srcK.V - srcK.U) / srcK.UV; if (h < 0.0f) { t = 1.0f / (h - Math.Sqrt(1.0f + h * h)); } else { t = 1.0f / (h + Math.Sqrt(1.0f + h * h)); } c = 1.0f / Math.Sqrt(1.0f + t * t); s = t * c; } PrincipalCurvature pc = new PrincipalCurvature(); pc.max = srcK.U - t * srcK.UV; pc.min = srcK.V + t * srcK.UV; if (Math.Abs(pc.max) >= Math.Abs(pc.min)) { pc.maxDir = c * rotated.U - s * rotated.V; } else { double temp = pc.min; pc.min = pc.max; pc.max = temp; pc.maxDir = s * rotated.U + c * rotated.V; } pc.minDir = dstNormal.Cross(pc.maxDir); return(pc); }
/// <summary> /// Projects a curvature tensor from an old basis to a new one. /// </summary> public static KUV ProjectCurvature(UV src, KUV srcK, UV dst) { UV rotated = Transform.RotateCoordinateSystem(dst, src.U.Cross(src.V)); double u1 = rotated.U.Dot(src.U); double v1 = rotated.U.Dot(src.V); double u2 = rotated.V.Dot(src.U); double v2 = rotated.V.Dot(src.V); KUV dstK = new KUV() { U = srcK.U * u1 * u1 + srcK.UV * (2.0f * u1 * v1) + srcK.V * v1 * v1, UV = srcK.U * u1 * u2 + srcK.UV * (u1 * v2 + u2 * v1) + srcK.V * v1 * v2, V = srcK.U * u2 * u2 + srcK.UV * (2.0f * u2 * v2) + srcK.V * v2 * v2 }; return(dstK); }
public static PrincipalCurvature[] ComputePrincipleCurvatures(TriMesh mesh, double[] CornerArea, double[] PointArea) { Vector3D[] vertexNormal = TriMeshUtil.ComputeNormalVertex(mesh); // Add dynamic trait for principle curvature computation double[] curv = new double[mesh.Vertices.Count]; PrincipalCurvature[] pc = new PrincipalCurvature[mesh.Vertices.Count]; // Initialize a coordinate system for each vertex foreach (TriMesh.Vertex v in mesh.Vertices) { pc[v.Index] = new PrincipalCurvature(); // Vector that points from this vertex to an adjacent one pc[v.Index].maxDir = (v.HalfEdge.ToVertex.Traits.Position - v.Traits.Position).Cross(vertexNormal[v.Index]).Normalize(); // Get a vector orthogonal to this vector and the vertex normal pc[v.Index].minDir = vertexNormal[v.Index].Cross(pc[v.Index].maxDir); } TriMesh.HalfEdge[] fh = new TriMesh.HalfEdge[3]; TriMesh.Vertex[] fv = new TriMesh.Vertex[3]; Vector3D[] e = new Vector3D[3]; Vector3D t, b, dn, faceNormal; // Compute curvature for each face foreach (TriMesh.Face f in mesh.Faces) { // Get halfedges for this face fh[0] = f.HalfEdge; fh[1] = fh[0].Next; fh[2] = fh[1].Next; // Get vertices for this face fv[0] = fh[0].ToVertex; fv[1] = fh[1].ToVertex; fv[2] = fh[2].ToVertex; // Edge vectors e[0] = fv[2].Traits.Position - fv[1].Traits.Position; e[1] = fv[0].Traits.Position - fv[2].Traits.Position; e[2] = fv[1].Traits.Position - fv[0].Traits.Position; t = e[0]; t.Normalize(); faceNormal = e[0].Cross(e[1]); faceNormal.Normalize(); b = faceNormal.Cross(t); b.Normalize(); // Estimate curvature by variation of normals along edges double[] m = new double[3]; double[,] w = new double[3, 3]; for (int i = 0; i < 3; ++i) { double u = e[i].Dot(t); double v = e[i].Dot(b); w[0, 0] += u * u; w[0, 1] += u * v; w[2, 2] += v * v; dn = vertexNormal[fv[(i + 2) % 3].Index] - vertexNormal[fv[(i + 1) % 3].Index]; double dnu = dn.Dot(t); double dnv = dn.Dot(b); m[0] += dnu * u; m[1] += dnu * v + dnv * u; m[2] += dnv * v; } w[1, 1] = w[0, 0] + w[2, 2]; w[1, 2] = w[0, 1]; // Least squares solution double[] diag = new double[3]; if (Transform.LdlTransposeDecomp(w, diag)) { Transform.LdlTransposeSolveInPlace(w, diag, m); // Adjust curvature for vertices of this face for (int i = 0; i < 3; ++i) { UV tb = new UV { U = t, V = b }; KUV mk = new KUV { U = m[0], UV = m[1], V = m[2] }; UV dst = new UV { U = pc[fv[i].Index].maxDir, V = pc[fv[i].Index].minDir }; KUV c = Transform.ProjectCurvature(tb, mk, dst); double weight = CornerArea[fh[i].Index] / PointArea[fv[i].Index]; pc[fv[i].Index].max += weight * c.U; curv[fv[i].Index] += weight * c.UV; pc[fv[i].Index].min += weight * c.V; } } } // Compute curvature for each vertex foreach (TriMesh.Vertex v in mesh.Vertices) { UV src = new UV { U = pc[v.Index].maxDir, V = pc[v.Index].minDir }; KUV srcK = new KUV { U = pc[v.Index].max, UV = curv[v.Index], V = pc[v.Index].min }; pc[v.Index] = Transform.DiagonalizeCurvature(src, srcK, vertexNormal[v.Index]); } return pc; }
public static Vector4D[] ComputeDCruv(TriMesh mesh, double[] CornerArea, double[] PointArea) { PrincipalCurvature[] PrincipalCurv = ComputePrincipleCurvatures(mesh, CornerArea, PointArea); Vector4D[] dcurv = new Vector4D[mesh.Vertices.Count]; TriMesh.HalfEdge[] fh = new TriMesh.HalfEdge[3]; TriMesh.Vertex[] fv = new TriMesh.Vertex[3]; Vector3D[] e = new Vector3D[3]; Vector3D t, b, faceNormal; // Compute curvature for each face foreach (TriMesh.Face f in mesh.Faces) { // Get halfedges for this face fh[0] = f.HalfEdge; fh[1] = fh[0].Next; fh[2] = fh[1].Next; // Get vertices for this face fv[0] = fh[0].ToVertex; fv[1] = fh[1].ToVertex; fv[2] = fh[2].ToVertex; // Edge vectors e[0] = fv[2].Traits.Position - fv[1].Traits.Position; e[1] = fv[0].Traits.Position - fv[2].Traits.Position; e[2] = fv[1].Traits.Position - fv[0].Traits.Position; t = e[0]; t.Normalize(); faceNormal = e[0].Cross(e[1]); b = faceNormal.Cross(t); b.Normalize(); KUV[] fcurv = new KUV[3]; for (int i = 0; i < 3; i++) { PrincipalCurvature pc = PrincipalCurv[fv[i].Index]; UV src = new UV { U = pc.maxDir, V = pc.minDir }; KUV mk = new KUV { U = pc.max, UV = 0, V = pc.min }; UV tb = new UV { U = t, V = b }; fcurv[i] = Transform.ProjectCurvature(src, mk, tb); } double[] m = new double[4]; double[,] w = new double[4, 4]; for (int i = 0; i < 3; i++) { KUV prev = fcurv[(i + 2) % 3]; KUV next = fcurv[(i + 1) % 3]; KUV dfcurv = new KUV { U = prev.U - next.U, UV = prev.UV - next.UV, V = prev.V - next.V }; double u = e[i].Dot(t); double v = e[i].Dot(b); w[0, 0] += u * u; w[0, 1] += u * v; w[3, 3] += v * v; m[0] += u * dfcurv.U; m[1] += v * dfcurv.U + 2d * u * dfcurv.UV; m[2] += 2d * v * dfcurv.UV + u * dfcurv.V; m[3] += v * dfcurv.V; } w[1, 1] = 2d * w[0, 0] + w[3, 3]; w[1, 2] = 2d * w[0, 1]; w[2, 2] = w[0, 0] + 2d * w[3, 3]; w[2, 3] = w[0, 1]; double[] diag = new double[4]; if (Transform.LdlTransposeDecomp(w, diag)) { Transform.LdlTransposeSolveInPlace(w, diag, m); Vector4D d = new Vector4D(m); // Adjust curvature for vertices of this face for (int i = 0; i < 3; ++i) { UV tb = new UV { U = t, V = b }; PrincipalCurvature pc = PrincipalCurv[fv[i].Index]; UV dst = new UV { U = pc.maxDir, V = pc.minDir }; Vector4D c = Transform.ProjectDCurvature(tb, d, dst); double weight = CornerArea[fh[i].Index] / PointArea[fv[i].Index]; dcurv[fv[i].Index] += weight * d; } } } return dcurv; }
/// <summary> /// Projects a curvature tensor from an old basis to a new one. /// </summary> public static KUV ProjectCurvature(UV src, KUV srcK, UV dst) { UV rotated = Transform.RotateCoordinateSystem(dst, src.U.Cross(src.V)); double u1 = rotated.U.Dot(src.U); double v1 = rotated.U.Dot(src.V); double u2 = rotated.V.Dot(src.U); double v2 = rotated.V.Dot(src.V); KUV dstK = new KUV() { U = srcK.U * u1 * u1 + srcK.UV * (2.0f * u1 * v1) + srcK.V * v1 * v1, UV = srcK.U * u1 * u2 + srcK.UV * (u1 * v2 + u2 * v1) + srcK.V * v1 * v2, V = srcK.U * u2 * u2 + srcK.UV * (2.0f * u2 * v2) + srcK.V * v2 * v2 }; return dstK; }
/// <summary> /// A class containing static methods for computing curvature on a mesh. /// </summary> public static PrincipalCurvature DiagonalizeCurvature(UV src, KUV srcK, Vector3D dstNormal) { UV rotated = Transform.RotateCoordinateSystem(src, dstNormal); double c = 1.0; double s = 0.0; double t = 0.0; // Jacobi rotation to diagonalize if (srcK.UV != 0.0f) { double h = 0.5f * (srcK.V - srcK.U) / srcK.UV; if (h < 0.0f) { t = 1.0f / (h - Math.Sqrt(1.0f + h * h)); } else { t = 1.0f / (h + Math.Sqrt(1.0f + h * h)); } c = 1.0f / Math.Sqrt(1.0f + t * t); s = t * c; } PrincipalCurvature pc = new PrincipalCurvature(); pc.max = srcK.U - t * srcK.UV; pc.min = srcK.V + t * srcK.UV; if (Math.Abs(pc.max) >= Math.Abs(pc.min)) { pc.maxDir = c * rotated.U - s * rotated.V; } else { double temp = pc.min; pc.min = pc.max; pc.max = temp; pc.maxDir = s * rotated.U + c * rotated.V; } pc.minDir = dstNormal.Cross(pc.maxDir); return pc; }
public static PrincipalCurvature[] ComputePrincipleCurvatures(TriMesh mesh, double[] CornerArea, double[] PointArea) { Vector3D[] vertexNormal = TriMeshUtil.ComputeNormalVertex(mesh); // Add dynamic trait for principle curvature computation double[] curv = new double[mesh.Vertices.Count]; PrincipalCurvature[] pc = new PrincipalCurvature[mesh.Vertices.Count]; // Initialize a coordinate system for each vertex foreach (TriMesh.Vertex v in mesh.Vertices) { pc[v.Index] = new PrincipalCurvature(); // Vector that points from this vertex to an adjacent one pc[v.Index].maxDir = (v.HalfEdge.ToVertex.Traits.Position - v.Traits.Position).Cross(vertexNormal[v.Index]).Normalize(); // Get a vector orthogonal to this vector and the vertex normal pc[v.Index].minDir = vertexNormal[v.Index].Cross(pc[v.Index].maxDir); } TriMesh.HalfEdge[] fh = new TriMesh.HalfEdge[3]; TriMesh.Vertex[] fv = new TriMesh.Vertex[3]; Vector3D[] e = new Vector3D[3]; Vector3D t, b, dn, faceNormal; // Compute curvature for each face foreach (TriMesh.Face f in mesh.Faces) { // Get halfedges for this face fh[0] = f.HalfEdge; fh[1] = fh[0].Next; fh[2] = fh[1].Next; // Get vertices for this face fv[0] = fh[0].ToVertex; fv[1] = fh[1].ToVertex; fv[2] = fh[2].ToVertex; // Edge vectors e[0] = fv[2].Traits.Position - fv[1].Traits.Position; e[1] = fv[0].Traits.Position - fv[2].Traits.Position; e[2] = fv[1].Traits.Position - fv[0].Traits.Position; t = e[0]; t.Normalize(); faceNormal = e[0].Cross(e[1]); faceNormal.Normalize(); b = faceNormal.Cross(t); b.Normalize(); // Estimate curvature by variation of normals along edges double[] m = new double[3]; double[,] w = new double[3, 3]; for (int i = 0; i < 3; ++i) { double u = e[i].Dot(t); double v = e[i].Dot(b); w[0, 0] += u * u; w[0, 1] += u * v; w[2, 2] += v * v; dn = vertexNormal[fv[(i + 2) % 3].Index] - vertexNormal[fv[(i + 1) % 3].Index]; double dnu = dn.Dot(t); double dnv = dn.Dot(b); m[0] += dnu * u; m[1] += dnu * v + dnv * u; m[2] += dnv * v; } w[1, 1] = w[0, 0] + w[2, 2]; w[1, 2] = w[0, 1]; // Least squares solution double[] diag = new double[3]; if (Transform.LdlTransposeDecomp(w, diag)) { Transform.LdlTransposeSolveInPlace(w, diag, m); // Adjust curvature for vertices of this face for (int i = 0; i < 3; ++i) { UV tb = new UV { U = t, V = b }; KUV mk = new KUV { U = m[0], UV = m[1], V = m[2] }; UV dst = new UV { U = pc[fv[i].Index].maxDir, V = pc[fv[i].Index].minDir }; KUV c = Transform.ProjectCurvature(tb, mk, dst); double weight = CornerArea[fh[i].Index] / PointArea[fv[i].Index]; pc[fv[i].Index].max += weight * c.U; curv[fv[i].Index] += weight * c.UV; pc[fv[i].Index].min += weight * c.V; } } } // Compute curvature for each vertex foreach (TriMesh.Vertex v in mesh.Vertices) { UV src = new UV { U = pc[v.Index].maxDir, V = pc[v.Index].minDir }; KUV srcK = new KUV { U = pc[v.Index].max, UV = curv[v.Index], V = pc[v.Index].min }; pc[v.Index] = Transform.DiagonalizeCurvature(src, srcK, vertexNormal[v.Index]); } return(pc); }
public static Vector4D[] ComputeDCruv(TriMesh mesh, double[] CornerArea, double[] PointArea) { PrincipalCurvature[] PrincipalCurv = ComputePrincipleCurvatures(mesh, CornerArea, PointArea); Vector4D[] dcurv = new Vector4D[mesh.Vertices.Count]; TriMesh.HalfEdge[] fh = new TriMesh.HalfEdge[3]; TriMesh.Vertex[] fv = new TriMesh.Vertex[3]; Vector3D[] e = new Vector3D[3]; Vector3D t, b, faceNormal; // Compute curvature for each face foreach (TriMesh.Face f in mesh.Faces) { // Get halfedges for this face fh[0] = f.HalfEdge; fh[1] = fh[0].Next; fh[2] = fh[1].Next; // Get vertices for this face fv[0] = fh[0].ToVertex; fv[1] = fh[1].ToVertex; fv[2] = fh[2].ToVertex; // Edge vectors e[0] = fv[2].Traits.Position - fv[1].Traits.Position; e[1] = fv[0].Traits.Position - fv[2].Traits.Position; e[2] = fv[1].Traits.Position - fv[0].Traits.Position; t = e[0]; t.Normalize(); faceNormal = e[0].Cross(e[1]); b = faceNormal.Cross(t); b.Normalize(); KUV[] fcurv = new KUV[3]; for (int i = 0; i < 3; i++) { PrincipalCurvature pc = PrincipalCurv[fv[i].Index]; UV src = new UV { U = pc.maxDir, V = pc.minDir }; KUV mk = new KUV { U = pc.max, UV = 0, V = pc.min }; UV tb = new UV { U = t, V = b }; fcurv[i] = Transform.ProjectCurvature(src, mk, tb); } double[] m = new double[4]; double[,] w = new double[4, 4]; for (int i = 0; i < 3; i++) { KUV prev = fcurv[(i + 2) % 3]; KUV next = fcurv[(i + 1) % 3]; KUV dfcurv = new KUV { U = prev.U - next.U, UV = prev.UV - next.UV, V = prev.V - next.V }; double u = e[i].Dot(t); double v = e[i].Dot(b); w[0, 0] += u * u; w[0, 1] += u * v; w[3, 3] += v * v; m[0] += u * dfcurv.U; m[1] += v * dfcurv.U + 2d * u * dfcurv.UV; m[2] += 2d * v * dfcurv.UV + u * dfcurv.V; m[3] += v * dfcurv.V; } w[1, 1] = 2d * w[0, 0] + w[3, 3]; w[1, 2] = 2d * w[0, 1]; w[2, 2] = w[0, 0] + 2d * w[3, 3]; w[2, 3] = w[0, 1]; double[] diag = new double[4]; if (Transform.LdlTransposeDecomp(w, diag)) { Transform.LdlTransposeSolveInPlace(w, diag, m); Vector4D d = new Vector4D(m); // Adjust curvature for vertices of this face for (int i = 0; i < 3; ++i) { UV tb = new UV { U = t, V = b }; PrincipalCurvature pc = PrincipalCurv[fv[i].Index]; UV dst = new UV { U = pc.maxDir, V = pc.minDir }; Vector4D c = Transform.ProjectDCurvature(tb, d, dst); double weight = CornerArea[fh[i].Index] / PointArea[fv[i].Index]; dcurv[fv[i].Index] += weight * d; } } } return(dcurv); }