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;
        }
Exemple #3
0
        /// <summary>
        /// Rotates a 3D coordinate system to match a specified normal.
        /// </summary>
        public static UV RotateCoordinateSystem(UV src, Vector3D dstNormal)
        {
            Vector3D srcNormal = src.U.Cross(src.V);
            double cos = srcNormal.Dot(dstNormal);

            UV dst;
            if (cos <= -1.0f)
            {
                dst.U = -src.U;
                dst.V = -src.V;
            }
            else
            {
                Vector3D perpOld = dstNormal - cos * srcNormal;
                Vector3D dPerp = 1.0f / (1.0f + cos) * (srcNormal + dstNormal);

                dst.U = src.U - dPerp * src.U.Dot(perpOld);
                dst.V = src.V - dPerp * src.V.Dot(perpOld);
            }
            return dst;
        }
Exemple #4
0
        public static Vector4D ProjectDCurvature(UV src, Vector4D srcDCurv, 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);

            Vector4D dstDCurv = Vector4D.Zero;
            dstDCurv[0] = srcDCurv[0] * u1 * u1 * u1 +
                       srcDCurv[1] * 3.0f * u1 * u1 * v1 +
                       srcDCurv[2] * 3.0f * u1 * v1 * v1 +
                       srcDCurv[3] * v1 * v1 * v1;
            dstDCurv[1] = srcDCurv[0] * u1 * u1 * u2 +
                       srcDCurv[1] * (u1 * u1 * v2 + 2.0f * u2 * u1 * v1) +
                       srcDCurv[2] * (u2 * v1 * v1 + 2.0f * u1 * v1 * v2) +
                       srcDCurv[3] * v1 * v1 * v2;
            dstDCurv[2] = srcDCurv[0] * u1 * u2 * u2 +
                       srcDCurv[1] * (u2 * u2 * v1 + 2.0f * u1 * u2 * v2) +
                       srcDCurv[2] * (u1 * v2 * v2 + 2.0f * u2 * v2 * v1) +
                       srcDCurv[3] * v1 * v2 * v2;
            dstDCurv[3] = srcDCurv[0] * u2 * u2 * u2 +
                       srcDCurv[1] * 3.0f * u2 * u2 * v2 +
                       srcDCurv[2] * 3.0f * u2 * v2 * v2 +
                       srcDCurv[3] * v2 * v2 * v2;
            return dstDCurv;
        }
Exemple #5
0
        /// <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;
        }
Exemple #6
0
        /// <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;
        }