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); }
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); }
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); }
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); }
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; }
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); }
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); }
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; }
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; }
//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); }
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; }