Beispiel #1
0
        protected Vector3D Transport(Vector3D wI, TriMesh.Face faceI, TriMesh.Face faceJ, double angle)
        {
            /*
             * triangles i and j according to the following labels:
             *
             *              b
             *             /|\
             *            / | \
             *           /  |  \
             *          /   |   \
             *         c  i | j  d
             \   |   /
             \  |  /
             \ | /
             \|/
             \              a
             \
             */

            //Find Shared edge IJ
            TriMesh.HalfEdge sharedEdgeI = null;
            TriMesh.HalfEdge sharedEdgeJ = null;
            TriMesh.Edge     sharedEdge  = null;

            foreach (TriMesh.HalfEdge edgeI in faceI.Halfedges)
            {
                foreach (TriMesh.HalfEdge edgeJ in faceJ.Halfedges)
                {
                    if (edgeI.Opposite == edgeJ)
                    {
                        sharedEdge  = edgeI.Edge;
                        sharedEdgeI = edgeI;
                        sharedEdgeJ = edgeJ;
                        break;
                    }
                }
            }

            if (sharedEdge == null)
            {
                throw new Exception("Error");
            }

            //Find vertex correspondent to figure above
            Vector3D av = sharedEdgeI.FromVertex.Traits.Position;
            Vector3D bv = sharedEdgeJ.FromVertex.Traits.Position;
            Vector3D cv = sharedEdgeI.Next.ToVertex.Traits.Position;
            Vector3D dv = sharedEdgeJ.Next.ToVertex.Traits.Position;

            //Compute the basis
            Matrix3D Ei = Orthogonalize(bv - av, cv - av);
            Matrix3D Ej = Orthogonalize(bv - av, bv - dv);

            //Build Rotate Matrix between two Faces
            Matrix3D rotateMatrix = Matrix3D.Rotate(angle);

            Vector3D wj = (Ej * rotateMatrix * Ei.Inverse() * wI);

            return(wj);
        }
Beispiel #2
0
        public double[][] ComputeLaplacianDual(TriMesh mesh)
        {
            int fn = mesh.Faces.Count;

            double[][] laplacian = new double[3][];
            laplacian[0] = new double[fn];
            laplacian[1] = new double[fn];
            laplacian[2] = new double[fn];
            for (int i = 0; i < fn; i++)
            {
                int      f1     = mesh.Faces[i].GetFace(0).Index;
                int      f2     = mesh.Faces[i].GetFace(1).Index;
                int      f3     = mesh.Faces[i].GetFace(2).Index;
                Vector3D u      = mesh.DualGetVertexPosition(i);
                Vector3D v1     = mesh.DualGetVertexPosition(f1);
                Vector3D v2     = mesh.DualGetVertexPosition(f2);
                Vector3D v3     = mesh.DualGetVertexPosition(f3);
                Vector3D normal = ((v1 - v3).Cross(v2 - v3)).Normalize();
                Matrix3D m      = new Matrix3D(v1 - v3, v2 - v3, normal);
                Vector3D coord  = m.Inverse() * (u - v3);
                laplacian[0][i] = normal.x * coord[2];
                laplacian[1][i] = normal.y * coord[2];
                laplacian[2][i] = normal.z * coord[2];
            }
            return(laplacian);
        }
Beispiel #3
0
        public static double[] ComputeDualLap(ref NonManifoldMesh mesh)
        {
            int vn = mesh.VertexCount;
            int fn = mesh.FaceCount;

            double[] dLap = new double[fn * 3];

            mesh.ComputeDualPosition();
            for (int i = 0, j = 0; i < fn; i++, j += 3)
            {
                Vector3D u      = new Vector3D(mesh.DualVertexPos, j);
                Vector3D v1     = new Vector3D(mesh.DualVertexPos, mesh.AdjFF[i][0] * 3);
                Vector3D v2     = new Vector3D(mesh.DualVertexPos, mesh.AdjFF[i][1] * 3);
                Vector3D v3     = new Vector3D(mesh.DualVertexPos, mesh.AdjFF[i][2] * 3);
                Vector3D normal = ((v1 - v3).Cross(v2 - v3)).Normalize();
                Matrix3D m      = new Matrix3D(v1 - v3, v2 - v3, normal);
                Vector3D coord  = m.Inverse() * (u - v3);
                //dLap[j] = coord.x;
                //dLap[j + 1] = coord.y;
                //dLap[j + 2] = coord.z;

                dLap[j]     = normal.x * coord[2];
                dLap[j + 1] = normal.x * coord[2];
                dLap[j + 2] = normal.x * coord[2];
            }

            return(dLap);
        }
Beispiel #4
0
        public Vector3D[] ComputeVectorField(double initAngle)
        {
            Vector3D[] vectorFields = new Vector3D[mesh.Faces.Count];
            bool[]     visitedFlags = new bool[mesh.Faces.Count];
            for (int i = 0; i < visitedFlags.Length; i++)
            {
                visitedFlags[i] = false;
            }

            //Find a initial root to expend
            TriMesh.Face rootFace = mesh.Faces[0];
            var          v1       = rootFace.GetVertex(0);
            var          v3       = rootFace.GetVertex(2);
            var          v2       = rootFace.GetVertex(1);

            Vector3D w0 = (rootFace.GetVertex(2).Traits.Position - rootFace.GetVertex(0).Traits.Position).Normalize();

            //Init transpot
            Vector3D av = v1.Traits.Position;
            Vector3D bv = v2.Traits.Position;
            Vector3D cv = v3.Traits.Position;
            Matrix3D Ei = Orthogonalize(bv - av, cv - av);

            Vector3D w0i = (Ei * Matrix3D.Rotate(initAngle) * Ei.Inverse() * w0);

            vectorFields[rootFace.Index] = w0i;
            visitedFlags[rootFace.Index] = true;

            //Recurse all faces
            Queue <TriMesh.Face> queue = new Queue <HalfEdgeMesh.Face>();

            queue.Enqueue(rootFace);

            int ii = 0;

            while (queue.Count > 0)
            {
                TriMesh.Face currentFace = queue.Dequeue();
                Vector3D     wI          = vectorFields[currentFace.Index];

                foreach (TriMesh.Face neighbor in currentFace.Faces)
                {
                    if (visitedFlags[neighbor.Index] == false)
                    {
                        Vector3D wj = Transport2(wI, currentFace, neighbor);
                        vectorFields[neighbor.Index] = wj;
                        queue.Enqueue(neighbor);
                        visitedFlags[neighbor.Index] = true;
                    }
                }

                ii++;
            }

            return(vectorFields);
        }
Beispiel #5
0
        public SparseMatrix BuildLaplaceMatrixDual()
        {
            // build dual Laplacian weight matrix L

            int vn = this.Vertices.Count;
            int fn = this.Faces.Count;
            SparseMatrix L = new SparseMatrix(fn, vn, 6);

            for (int i = 0; i < fn; i++)
            {
                int f1 = this.Faces[i].GetFace(0).Index;
                int f2 = this.Faces[i].GetFace(1).Index;
                int f3 = this.Faces[i].GetFace(2).Index;

                Vector3D dv =  this.DualGetVertexPosition(i);
                Vector3D dv1 = this.DualGetVertexPosition(f1);
                Vector3D dv2 = this.DualGetVertexPosition(f2);
                Vector3D dv3 = this.DualGetVertexPosition(f3);
                Vector3D u = dv - dv3;
                Vector3D v1 = dv1 - dv3;
                Vector3D v2 = dv2 - dv3;
                Vector3D normal = (v1.Cross(v2)).Normalize();
                Matrix3D M = new Matrix3D(v1, v2, normal);
                Vector3D coord = M.Inverse() * u;
                double alpha;

                alpha = 1.0 / 3.0;

                L.AddValueTo(i, this.Faces[i].GetVertex(0).Index, alpha);
                L.AddValueTo(i, this.Faces[i].GetVertex(1).Index, alpha);
                L.AddValueTo(i, this.Faces[i].GetVertex(2).Index, alpha);

                alpha = coord[0] / 3.0;

                L.AddValueTo(i, this.Faces[f1].GetVertex(0).Index, -alpha);
                L.AddValueTo(i, this.Faces[f1].GetVertex(1).Index, -alpha);
                L.AddValueTo(i, this.Faces[f1].GetVertex(2).Index, -alpha);

                alpha = coord[1] / 3.0;

                L.AddValueTo(i, this.Faces[f2].GetVertex(0).Index, -alpha);
                L.AddValueTo(i, this.Faces[f2].GetVertex(1).Index, -alpha);
                L.AddValueTo(i, this.Faces[f2].GetVertex(2).Index, -alpha);

                alpha = (1.0 - coord[0] - coord[1]) / 3.0;

                L.AddValueTo(i, this.Faces[f3].GetVertex(0).Index, -alpha);
                L.AddValueTo(i, this.Faces[f3].GetVertex(1).Index, -alpha);
                L.AddValueTo(i, this.Faces[f3].GetVertex(2).Index, -alpha);


            }

            L.SortElement();
            return L;
        }
Beispiel #6
0
        public SparseMatrix BuildLaplaceMatrixDual()
        {
            // build dual Laplacian weight matrix L

            int          vn = this.Vertices.Count;
            int          fn = this.Faces.Count;
            SparseMatrix L  = new SparseMatrix(fn, vn, 6);

            for (int i = 0; i < fn; i++)
            {
                int f1 = this.Faces[i].GetFace(0).Index;
                int f2 = this.Faces[i].GetFace(1).Index;
                int f3 = this.Faces[i].GetFace(2).Index;

                Vector3D dv     = this.DualGetVertexPosition(i);
                Vector3D dv1    = this.DualGetVertexPosition(f1);
                Vector3D dv2    = this.DualGetVertexPosition(f2);
                Vector3D dv3    = this.DualGetVertexPosition(f3);
                Vector3D u      = dv - dv3;
                Vector3D v1     = dv1 - dv3;
                Vector3D v2     = dv2 - dv3;
                Vector3D normal = (v1.Cross(v2)).Normalize();
                Matrix3D M      = new Matrix3D(v1, v2, normal);
                Vector3D coord  = M.Inverse() * u;
                double   alpha;

                alpha = 1.0 / 3.0;

                L.AddValueTo(i, this.Faces[i].GetVertex(0).Index, alpha);
                L.AddValueTo(i, this.Faces[i].GetVertex(1).Index, alpha);
                L.AddValueTo(i, this.Faces[i].GetVertex(2).Index, alpha);

                alpha = coord[0] / 3.0;

                L.AddValueTo(i, this.Faces[f1].GetVertex(0).Index, -alpha);
                L.AddValueTo(i, this.Faces[f1].GetVertex(1).Index, -alpha);
                L.AddValueTo(i, this.Faces[f1].GetVertex(2).Index, -alpha);

                alpha = coord[1] / 3.0;

                L.AddValueTo(i, this.Faces[f2].GetVertex(0).Index, -alpha);
                L.AddValueTo(i, this.Faces[f2].GetVertex(1).Index, -alpha);
                L.AddValueTo(i, this.Faces[f2].GetVertex(2).Index, -alpha);

                alpha = (1.0 - coord[0] - coord[1]) / 3.0;

                L.AddValueTo(i, this.Faces[f3].GetVertex(0).Index, -alpha);
                L.AddValueTo(i, this.Faces[f3].GetVertex(1).Index, -alpha);
                L.AddValueTo(i, this.Faces[f3].GetVertex(2).Index, -alpha);
            }

            L.SortElement();
            return(L);
        }
Beispiel #7
0
        public static SparseMatrix BuildMatrixDualL(ref NonManifoldMesh mesh)
        {
            // build dual Laplacian weight matrix L

            int          vn = mesh.VertexCount;
            int          fn = mesh.FaceCount;
            SparseMatrix L  = new SparseMatrix(fn, vn, 6);

            for (int i = 0; i < fn; i++)
            {
                int      f1     = mesh.AdjFF[i][0];
                int      f2     = mesh.AdjFF[i][1];
                int      f3     = mesh.AdjFF[i][2];
                Vector3D dv     = mesh.GetDualPosition(i);
                Vector3D dv1    = mesh.GetDualPosition(f1);
                Vector3D dv2    = mesh.GetDualPosition(f2);
                Vector3D dv3    = mesh.GetDualPosition(f3);
                Vector3D u      = dv - dv3;
                Vector3D v1     = dv1 - dv3;
                Vector3D v2     = dv2 - dv3;
                Vector3D normal = (v1.Cross(v2)).Normalize();
                Matrix3D M      = new Matrix3D(v1, v2, normal);
                Vector3D coord  = M.Inverse() * u;
                double   alpha;

                alpha = 1.0 / 3.0;
                for (int j = 0, k = i * 3; j < 3; j++)
                {
                    L.AddValueTo(i, mesh.FaceIndex[k++], alpha);
                }

                alpha = coord[0] / 3.0;
                for (int j = 0, k = f1 * 3; j < 3; j++)
                {
                    L.AddValueTo(i, mesh.FaceIndex[k++], -alpha);
                }

                alpha = coord[1] / 3.0;
                for (int j = 0, k = f2 * 3; j < 3; j++)
                {
                    L.AddValueTo(i, mesh.FaceIndex[k++], -alpha);
                }

                alpha = (1.0 - coord[0] - coord[1]) / 3.0;
                for (int j = 0, k = f3 * 3; j < 3; j++)
                {
                    L.AddValueTo(i, mesh.FaceIndex[k++], -alpha);
                }
            }

            L.SortElement();
            return(L);
        }
Beispiel #8
0
        public static double[] ComputeDualLap(ref NonManifoldMesh mesh)
        {
            int vn = mesh.VertexCount;
            int fn = mesh.FaceCount;
            double[] dLap = new double[fn * 3];

            mesh.ComputeDualPosition();
            for (int i = 0, j = 0; i < fn; i++, j += 3)
            {
                Vector3D u = new Vector3D(mesh.DualVertexPos, j);
                Vector3D v1 = new Vector3D(mesh.DualVertexPos, mesh.AdjFF[i][0] * 3);
                Vector3D v2 = new Vector3D(mesh.DualVertexPos, mesh.AdjFF[i][1] * 3);
                Vector3D v3 = new Vector3D(mesh.DualVertexPos, mesh.AdjFF[i][2] * 3);
                Vector3D normal = ((v1 - v3).Cross(v2 - v3)).Normalize();
                Matrix3D m = new Matrix3D(v1 - v3, v2 - v3, normal);
                Vector3D coord = m.Inverse() * (u - v3);
                //dLap[j] = coord.x;
                //dLap[j + 1] = coord.y;
                //dLap[j + 2] = coord.z;

                dLap[j] = normal.x * coord[2];
                dLap[j + 1] = normal.x * coord[2];
                dLap[j + 2] = normal.x * coord[2];
            }

            return dLap;
        }
Beispiel #9
0
        public static SparseMatrix BuildMatrixDualL(ref NonManifoldMesh mesh)
        {
            // build dual Laplacian weight matrix L

            int vn = mesh.VertexCount;
            int fn = mesh.FaceCount;
            SparseMatrix L = new SparseMatrix(fn, vn, 6);

            for (int i = 0; i < fn; i++)
            {
                int f1 = mesh.AdjFF[i][0];
                int f2 = mesh.AdjFF[i][1];
                int f3 = mesh.AdjFF[i][2];
                Vector3D dv = mesh.GetDualPosition(i);
                Vector3D dv1 = mesh.GetDualPosition(f1);
                Vector3D dv2 = mesh.GetDualPosition(f2);
                Vector3D dv3 = mesh.GetDualPosition(f3);
                Vector3D u = dv - dv3;
                Vector3D v1 = dv1 - dv3;
                Vector3D v2 = dv2 - dv3;
                Vector3D normal = (v1.Cross(v2)).Normalize();
                Matrix3D M = new Matrix3D(v1, v2, normal);
                Vector3D coord = M.Inverse() * u;
                double alpha;

                alpha = 1.0 / 3.0;
                for (int j = 0, k = i * 3; j < 3; j++)
                    L.AddValueTo(i, mesh.FaceIndex[k++], alpha);

                alpha = coord[0] / 3.0;
                for (int j = 0, k = f1 * 3; j < 3; j++)
                    L.AddValueTo(i, mesh.FaceIndex[k++], -alpha);

                alpha = coord[1] / 3.0;
                for (int j = 0, k = f2 * 3; j < 3; j++)
                    L.AddValueTo(i, mesh.FaceIndex[k++], -alpha);

                alpha = (1.0 - coord[0] - coord[1]) / 3.0;
                for (int j = 0, k = f3 * 3; j < 3; j++)
                    L.AddValueTo(i, mesh.FaceIndex[k++], -alpha);

              
            }

            L.SortElement();
            return L;
        }
Beispiel #10
0
        //public void ComputeFrameAngles(double initialAngle)
        //{
        //    TreeNode<TriMesh.Face> Root = transportTree.Root;

        //    Queue<TreeNode<HalfEdgeMesh.Face>> queue = new Queue<TreeNode<HalfEdgeMesh.Face>>();
        //    queue.Enqueue(transportTree.Root);

        //    bool[] processedFlag = new bool[Mesh.Faces.Count];

        //    while (queue.Count != 0)
        //    {
        //        TreeNode<HalfEdgeMesh.Face> currentFaceNode = queue.Dequeue();

        //        TriMesh.HalfEdge startHf = currentFaceNode.Attribute.HalfEdge;
        //        TriMesh.HalfEdge currentHf = startHf;
        //        do
        //        {
        //            TriMesh.Face neighborFace = currentHf.Opposite.Face;

        //            TransportData td = transDatas[currentHf.Index];

        //            td.alphaJ = td.alphaI + td.delta - td.sign * td.omega;

        //            currentHf = currentHf.Next;
        //        } while (currentHf != startHf);


        //    }


        //}


        //public void UpdateAngles(int initAngle)
        //{
        //    TriMesh.Face faceTransport = Mesh.Faces[3];
        //    FaceAngle[faceTransport.Index] = initAngle;
        //    Queue<TriMesh.Face> queue = new Queue<TriMesh.Face>();
        //    queue.Enqueue(faceTransport);

        //    bool[] processedFlag = new bool[Mesh.Faces.Count];

        //    while (queue.Count != 0)
        //    {
        //        TriMesh.Face currentFace = queue.Dequeue();

        //        TriMesh.HalfEdge startHf = currentFace.HalfEdge;
        //        TriMesh.HalfEdge currentHf = startHf;
        //        double currentDelta = Deltas[currentFace.Index];

        //        do
        //        {
        //            TriMesh.Face neighborFace = currentHf.Opposite.Face;


        //            if (processedFlag[neighborFace.Index] == false &&
        //                neighborFace != faceTransport &&
        //                !neighborFace.OnBoundary
        //                )
        //            {
        //                processedFlag[neighborFace.Index] = true;
        //                queue.Enqueue(neighborFace);

        //                double delta = ComputeParallTransport(currentDelta, currentHf);
        //                Deltas[neighborFace.Index] = delta;

        //                double omega = EdgeTheta[currentHf.Edge.Index];
        //                double sign = currentHf.FromVertex.Index > currentHf.ToVertex.Index ? -1 : 1;
        //                FaceAngle[neighborFace.Index] = FaceAngle[currentFace.Index] + delta - sign * omega;

        //            }
        //            currentHf = currentHf.Next;
        //        } while (currentHf != startHf);


        //    }
        //}


        //public void AppendDirectionalConstraints(TriMesh mesh, List<List<TriMesh.HalfEdge>> cycles)
        //{
        //    transDatas = new TransportData[mesh.HalfEdges.Count];
        //    TriMesh.Face faceTransport = mesh.Faces[3];
        //    transportTree = new DynamicTree<HalfEdgeMesh.Face>();
        //    transportTree.Root = new TreeNode<HalfEdgeMesh.Face>(faceTransport);

        //    Queue<TreeNode<HalfEdgeMesh.Face>> queue = new Queue<TreeNode<HalfEdgeMesh.Face>>();
        //    queue.Enqueue(transportTree.Root);

        //    bool[] processedFlag = new bool[mesh.Faces.Count];

        //    while (queue.Count != 0)
        //    {
        //        TreeNode<HalfEdgeMesh.Face> currentFaceNode = queue.Dequeue();

        //        TriMesh.HalfEdge startHf = currentFaceNode.Attribute.HalfEdge;
        //        TriMesh.HalfEdge currentHf = startHf;
        //        do
        //        {
        //            TriMesh.Face neighborFace = currentHf.Opposite.Face;

        //            if (processedFlag[neighborFace.Index] == false &&
        //                neighborFace != faceTransport &&
        //                !neighborFace.OnBoundary
        //                )
        //            {
        //                TreeNode<HalfEdgeMesh.Face> neighNode = new TreeNode<HalfEdgeMesh.Face>(neighborFace);
        //                processedFlag[neighborFace.Index] = true;
        //                currentFaceNode.AddChild(neighNode);
        //                queue.Enqueue(neighNode);


        //                TransportData td = new TransportData();
        //                td.delta = ComputeParallTransport(0, currentHf);
        //                td.sign = currentHf.FromVertex.Index > currentHf.ToVertex.Index ? 1 : -1;
        //                td.omega = EdgeTheta[currentHf.Edge.Index];
        //                td.alphaI = FaceAngle[currentHf.Face.Index];
        //                td.alphaJ = FaceAngle[currentHf.Opposite.Face.Index];
        //                transDatas[currentHf.Index] = td;
        //                Deltas[currentHf.Face.Index] = td.delta;

        //            }
        //            currentHf = currentHf.Next;
        //        } while (currentHf != startHf);


        //    }


        //}

        public Vector3D[] ComputeVectorField(double initAngle)
        {
            Vector3D[] vectorFields = new Vector3D[Mesh.Faces.Count];
            bool[]     visitedFlags = new bool[Mesh.Faces.Count];
            for (int i = 0; i < visitedFlags.Length; i++)
            {
                visitedFlags[i] = false;
            }

            //Find a initial root to expend
            TriMesh.Face rootFace = Mesh.Faces[0];
            var          v1       = rootFace.GetVertex(0);
            var          v3       = rootFace.GetVertex(2);
            var          v2       = rootFace.GetVertex(1);

            Vector3D w0 = (rootFace.GetVertex(2).Traits.Position - rootFace.GetVertex(0).Traits.Position).Normalize();

            //Init transpot
            Vector3D av = v1.Traits.Position;
            Vector3D bv = v2.Traits.Position;
            Vector3D cv = v3.Traits.Position;
            Matrix3D Ei = Orthogonalize(bv - av, cv - av);

            Vector3D w0i = (Ei * Matrix3D.Rotate(initAngle) * Ei.Inverse() * w0);

            vectorFields[rootFace.Index] = w0i;
            visitedFlags[rootFace.Index] = true;

            //Recurse all faces
            Queue <TriMesh.Face> queue = new Queue <HalfEdgeMesh.Face>();

            queue.Enqueue(rootFace);

            int ii = 0;

            while (queue.Count > 0)
            {
                TriMesh.Face currentFace = queue.Dequeue();
                Vector3D     wI          = vectorFields[currentFace.Index];

                TriMesh.HalfEdge cuHe = currentFace.HalfEdge;

                do
                {
                    TriMesh.Face neighbor = cuHe.Opposite.Face;

                    if (neighbor == null)
                    {
                        cuHe = cuHe.Next;
                        continue;
                    }

                    if (visitedFlags[neighbor.Index] == false)
                    {
                        double angle = EdgeTheta[cuHe.Edge.Index];
                        int    i     = cuHe.FromVertex.Index;
                        int    j     = cuHe.ToVertex.Index;

                        if (i > j)
                        {
                            angle = -angle;
                        }

                        Vector3D wj = Transport(wI, currentFace, neighbor, angle);
                        vectorFields[neighbor.Index] = wj;
                        queue.Enqueue(neighbor);
                        visitedFlags[neighbor.Index] = true;
                    }
                    cuHe = cuHe.Next;
                } while (cuHe != currentFace.HalfEdge);


                ii++;
            }

            return(vectorFields);
        }
Beispiel #11
0
 public double[][] ComputeLaplacianDual(TriMesh mesh)
 { 
     int fn = mesh.Faces.Count;
     double[][] laplacian = new double[3][];
     laplacian[0] = new double[fn];
     laplacian[1] = new double[fn];
     laplacian[2] = new double[fn]; 
     for (int i = 0; i < fn; i++)
     {
         int f1 = mesh.Faces[i].GetFace(0).Index;
         int f2 = mesh.Faces[i].GetFace(1).Index;
         int f3 = mesh.Faces[i].GetFace(2).Index; 
         Vector3D u = mesh.DualGetVertexPosition(i);
         Vector3D v1 = mesh.DualGetVertexPosition(f1);
         Vector3D v2 = mesh.DualGetVertexPosition(f2);
         Vector3D v3 = mesh.DualGetVertexPosition(f3); 
         Vector3D normal = ((v1 - v3).Cross(v2 - v3)).Normalize();
         Matrix3D m = new Matrix3D(v1 - v3, v2 - v3, normal);
         Vector3D coord = m.Inverse() * (u - v3); 
         laplacian[0][i] = normal.x * coord[2];
         laplacian[1][i] = normal.y * coord[2];
         laplacian[2][i] = normal.z * coord[2];
     } 
     return laplacian;
 }