public double _MeanCurvature(Mesh3D m3d, int index) { double meanCurvature = 0.0; double mixedArea = 0; double barycentricArea = 0; Vector3D normalOperator = new Vector3D(); int[] nbrs = m3d.GetNeighbourVertices(index); HashSet <int> fi = new HashSet <int>(); for (int i = 0; i < nbrs.Length; i++) { int fii = m3d.FindFaceFromEdge(index, nbrs[i]); fi.Add(fii); } int m = fi.Count; int[] vLeft = null; int[] vRight = null; if (m > 1) { vLeft = m3d.Faces.ElementAt(fi.ElementAt(0)); //int[] vRight = m3d.Faces.ElementAt(fi.ElementAt((i + 1) % m)); vRight = m3d.Faces.ElementAt(fi.ElementAt(1)); } else if (m == 1) { //Console.WriteLine(m+" -- "+fi.ElementAt(i) + " - " + fi.ElementAt((i + 1) % m)); vLeft = m3d.Faces.ElementAt(fi.ElementAt(0)); vRight = m3d.Faces.ElementAt(fi.ElementAt(0)); } else { return(_infinity); } // This point is also center point. int vertexInCommon1 = -1; // This point is the other end of common edge between two triangles. int vertexInCommon2 = -1; // These two points are not shared between two triangles. int vertexUniqueForLeftFace = -1; int vertexUniqueForRightFace = -1; // Find common vertexes in two adjacent triangles. for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { // If found vertex is pivotal point, save it as vertexInCommon1. // If found vertex is not pivotal point, then this vertex is // the other end of the common edge of two triangle. Save it as // vertexInCommon2. if (vLeft[j] == vRight[k]) { if (vLeft[j] == index) { vertexInCommon1 = vLeft[j]; break; } else { vertexInCommon2 = vLeft[j]; break; } } else { // If the vertex is not one of common vertexes, save it as // vertexUniqueForLeftFace. if (k == 2) { vertexUniqueForLeftFace = vLeft[j]; } } } } // If two triangles share only center point, the index point is located // on the edge of the surface. For example, for the ucf file the margin // of contours might not lap around, therefore the contour might have // boundary. if (vertexInCommon2 == -1) { return(_infinity); } // Now task is finding a vertex which is unique to right triangle. // Go over each vertex in right face and find a vertex which is // not shared with left triangle. then save it as // vertexUniqueForLeftFace. for (int l = 0; l < 3; l++) { if (vRight[l] == vertexInCommon1) { } else if (vRight[l] == vertexInCommon2) { } else { vertexUniqueForRightFace = vRight[l]; break; } } if (vertexUniqueForLeftFace == -1) { vertexUniqueForLeftFace = vertexInCommon1; } // Obtain vector represent of vertex locations. Point3D pivotalCommonPoint = m3d.Vertices.ElementAt(vertexInCommon1); Point3D theOtherCommonPoint = m3d.Vertices.ElementAt(vertexInCommon2); Point3D leftUniquePoint = m3d.Vertices.ElementAt(vertexUniqueForLeftFace); Point3D rightUniquePoint = m3d.Vertices.ElementAt(vertexUniqueForRightFace); Vector3D centerEdgeVector = Vector3D.Subtract(theOtherCommonPoint.ToVector3D(), pivotalCommonPoint.ToVector3D()); if (!_isAbsoluteMeanCurvature) { Vector3D v1 = Vector3D.Subtract(leftUniquePoint.ToVector3D(), pivotalCommonPoint.ToVector3D()); Vector3D v2 = Vector3D.Subtract(rightUniquePoint.ToVector3D(), pivotalCommonPoint.ToVector3D()); // Normal vector of the first face. Vector3D normal1 = Vector3D.CrossProduct(v1, centerEdgeVector); // Normal vector of the second face. Vector3D normal2 = Vector3D.CrossProduct(centerEdgeVector, v2); // Dihedral angle between adjacent triangular faces and is computed // as the angle between the corresponding normals. double dihedralAngle = Math.Acos(Vector3D.DotProduct(normal1, normal2) / (normal1.Length * normal2.Length)); // Edge is convex edge if the edge type is greater than 0, and edge // is concave edge if the edge type is smaller than 0, and edge is // planner if edge type is 0; double edgeType = Vector3D.DotProduct( Vector3D.CrossProduct(normal1, normal2), centerEdgeVector); double edgeVectorEuclideanNorm = centerEdgeVector.Length; if (edgeType < 0) { meanCurvature += -1 * edgeVectorEuclideanNorm * dihedralAngle; } else if (edgeType > 0) { meanCurvature += edgeVectorEuclideanNorm * dihedralAngle; } else { meanCurvature += 0; } } // Calculate cot x and cot y where x and y are the angles opposite // common edge in two incident triangles. try { double angleAlpha = Vector3D.AngleBetween(pivotalCommonPoint.ToVector3D(), leftUniquePoint.ToVector3D()); //theOtherCommonPoint.ToVector3D())); double angleBetha = Vector3D.AngleBetween(pivotalCommonPoint.ToVector3D(), rightUniquePoint.ToVector3D()); //,theOtherCommonPoint); // angleAlpha, angleTheta, and angleOmega are three angles of left triangles. // Test if any of these angles is obtuse. double angleTheta = Vector3D.AngleBetween(leftUniquePoint.ToVector3D(), pivotalCommonPoint.ToVector3D()); //,theOtherCommonPoint); double angleOmega = Vector3D.AngleBetween(leftUniquePoint.ToVector3D(), theOtherCommonPoint.ToVector3D()); //,pivotalCommonPoint); // Obtain Mean Curvature Normal Operator. double cotAlpha = 1 / Math.Tan(angleAlpha); double cotBetha = 1 / Math.Tan(angleBetha); double scalar = (cotAlpha + cotBetha); Vector3D centerEdgeVectorScalarMultiplied = Vector3D.Multiply(centerEdgeVector, scalar); normalOperator = Vector3D.Add(normalOperator, centerEdgeVectorScalarMultiplied); // Calculate area of the left triangle. Vector3D leftEdgeVector = Vector3D.Subtract(pivotalCommonPoint.ToVector3D(), leftUniquePoint.ToVector3D()); double magnitudeOfLeftEdge = leftEdgeVector.Length; Vector3D rightEdgeVector = Vector3D.Subtract(theOtherCommonPoint.ToVector3D(), leftUniquePoint.ToVector3D()); double magnitudeOfRightEdge = rightEdgeVector.Length; double areaOfLeftTriangle = Math.Sin(angleAlpha) * magnitudeOfLeftEdge * magnitudeOfRightEdge / 2.0; if (_areaCalMethod == BARYCENTRIC_AREA) { barycentricArea = barycentricArea + areaOfLeftTriangle / 3.0; } else if (_areaCalMethod == VORONOI_AREA) { // Obtuse angle exists at pivot vertex. if (angleTheta > Math.PI / 2) { mixedArea = mixedArea + areaOfLeftTriangle / 2.0; } // Obtuse angle exists at other vertex beside the pivot vertex. else if (angleAlpha > Math.PI / 2 || angleOmega > Math.PI / 2) { mixedArea = mixedArea + areaOfLeftTriangle / 4.0; } // No obtuse angle exists else { double magnitudeOfCenterVector = centerEdgeVector.Length; double voronoiAreaInATriangle = magnitudeOfLeftEdge * magnitudeOfLeftEdge * (1 / Math.Tan(angleOmega)) + magnitudeOfCenterVector * magnitudeOfCenterVector * (1 / Math.Tan(angleAlpha)); mixedArea = mixedArea + voronoiAreaInATriangle / 8.0; } } } catch (Exception ige) { Console.WriteLine( "Unable to calculate curvature of face # " + index + " Reason " + ige.Message); } if (_areaCalMethod == BARYCENTRIC_AREA) { normalOperator = Vector3D.Multiply(normalOperator, 1.0 / (2.0 * barycentricArea)); meanCurvature = meanCurvature * (1.0 / (4.0 * barycentricArea)); } else if (_areaCalMethod == VORONOI_AREA) { normalOperator = Vector3D.Multiply(normalOperator, 1.0 / (2.0 * mixedArea)); meanCurvature = meanCurvature * (1.0 / (4.0 * mixedArea)); } double curvature = meanCurvature; if (_isAbsoluteMeanCurvature) { // The mean curvature value is half of the magnitude of Normal Operator. curvature = normalOperator.Length / 2; } return(meanCurvature); }
internal MeshGeometry3D AutoSnake(MeshGeometry3D mesh, ref MeshBuilder newmbP) { //Dictionary<Int32, SmileEdge> neighbours = SmileVisual3D.findNeighbours(mesh); Point3DCollection positions = mesh.Positions; Int32Collection triangleIndices = mesh.TriangleIndices; Mesh3D m3d = new Mesh3D(positions, triangleIndices); Vector3DCollection t = new Vector3DCollection(positions.Count); Vector3DCollection b = new Vector3DCollection(positions.Count); Vector3DCollection n = new Vector3DCollection(positions.Count); double eThreshold = -0.5; double nThreshold = 0.8; double minEnergy = 10; double alpha = 1; double betha = 1; double ballon = 1; double lambda = 1; Vector3DCollection e = new Vector3DCollection(positions.Count); Vector3DCollection eInt = new Vector3DCollection(positions.Count); Vector3DCollection eExt = new Vector3DCollection(positions.Count); Vector3DCollection delta = new Vector3DCollection(positions.Count); Vector3DCollection f = new Vector3DCollection(positions.Count); Vector3DCollection tETF = new Vector3DCollection(positions.Count); //Vector3DCollection k = new Vector3DCollection(); //DoubleCollection kH = new DoubleCollection(); Dictionary <int, Double> kH = new Dictionary <int, double>(); MeshBuilder newmbD = new MeshBuilder(false, false); for (int i = 0; i < triangleIndices.Count; i += 3) { for (int a = 0; a < 3; a++) { int vi = triangleIndices[i + a]; if (!kH.ContainsKey(vi)) { double kHi = _MeanCurvature(m3d, vi); kH.Add(vi, kHi); } //Console.WriteLine("start mean"); //kH.Add(kHi); //Console.WriteLine("end mean"); if (a == 2) { int vi1 = triangleIndices[i + a - 1]; int vi2 = triangleIndices[i + a - 2]; double kH3 = 0; kH.TryGetValue(vi, out kH3); double kH2 = 0; kH.TryGetValue(vi1, out kH2); double kH1 = 0; kH.TryGetValue(vi2, out kH1); if ((kH3 < eThreshold || kH2 < eThreshold || kH1 < eThreshold)) { newmbD.Positions.Add(positions[vi]); newmbD.Positions.Add(positions[vi1]); newmbD.Positions.Add(positions[vi2]); newmbD.TriangleIndices.Add(i + a); newmbD.TriangleIndices.Add(i + a - 1); newmbD.TriangleIndices.Add(i + a - 2); } if ((kH3 > nThreshold || kH2 > nThreshold || kH1 > nThreshold)) { newmbP.Positions.Add(positions[vi]); newmbP.Positions.Add(positions[vi1]); newmbP.Positions.Add(positions[vi2]); newmbP.TriangleIndices.Add(i + a); newmbP.TriangleIndices.Add(i + a - 1); newmbP.TriangleIndices.Add(i + a - 2); } } int[] nbrs = m3d.GetNeighbourVertices(vi); Vector3DCollection N = new Vector3DCollection(positions.Count); Point3D pi = positions[vi]; int i0 = triangleIndices[i + a]; if (i + a - 1 >= 0) { i0 = triangleIndices[i + a - 1]; } Point3D pi0 = positions[i0]; int i1 = vi; if (i + a + i < triangleIndices.Count) { i1 = triangleIndices[i + a + 1]; } Point3D pi1 = positions[i1]; t.Insert(vi, (pi1 - pi0) / (Point3D.Subtract(pi1, pi0).Length)); //t[i] = (pi1 - pi0) / Math.Sqrt((Point3D.Subtract(pi1, pi0).Length)); n.Insert(vi, SmileVisual3D.CalculateNormal(pi0, pi, pi1)); b.Insert(vi, Vector3D.CrossProduct(t[vi], n[vi])); Vector3D eIntV = new Vector3D(); //eInt[vi]; Vector3D eExtV = new Vector3D(); //eExt[vi]; Vector3D eV = new Vector3D(); //e[vi]; Vector3D sumDeltaNbrs = new Vector3D(); Vector3D sumFNbrs = new Vector3D(); int maxNbrs = (nbrs.Length > 2 ? 2 : nbrs.Length); for (int j = 0; j < maxNbrs; j++) { Point3D nbj = positions[nbrs[j]]; N.Add(nbj.ToVector3D()); } double determinantVi = determinant(N); double kv = 0; kH.TryGetValue(vi, out kv); double jminEnergy = minEnergy; Point3D tempNbj = pi; for (int j = 0; j < maxNbrs; j++) { Point3D nbj = positions[nbrs[j]]; double ku = 0; kH.TryGetValue(nbrs[j], out ku); sumDeltaNbrs += Vector3D.Multiply((kv - ku), Vector3D.Divide(Point3D.Subtract(nbj, pi), (Point3D.Subtract(nbj, pi).Length))); delta.Insert(vi, (1 / determinantVi) * sumDeltaNbrs); f.Insert(vi, Vector3D.Multiply((1 - lambda), Vector3D.Multiply((1 / determinantVi), new Vector3D())) + Vector3D.Multiply(lambda, delta[vi])); double eIntj = alpha * (Point3D.Subtract(pi0, nbj).Length) + betha * (Point3D.Subtract(pi0, Point3D.Add(pi1, (Vector3D)nbj)).Length); //TODO: crosscheck double eFaej = ballon * (-(f[vi].Length) - Vector3D.DotProduct((f[vi] / f[vi].Length), (Point3D.Subtract(nbj, pi) / Point3D.Subtract(nbj, pi).Length))); //TODO: crosscheck double ePressj = ballon * Vector3D.DotProduct(b[vi], (Point3D.Subtract(pi0, nbj) / Point3D.Subtract(pi0, nbj).Length)); double eExtj = eFaej + ePressj; double ej = eIntj + eExtj; if (j == 0) { eIntV.X = eIntj; eExtV.X = eExtj; eV.X = ej; } if (j == 1) { eIntV.Y = eIntj; eExtV.Y = eExtj; eV.Y = ej; } if (j == 2) { eIntV.Z = eIntj; eExtV.Z = eExtj; eV.Z = ej; } if (ej < jminEnergy) { jminEnergy = ej; tempNbj = nbj; //TODO: snake movement //AddSnakeElement(nbj); } } AddSnakeElement(tempNbj); eInt.Insert(vi, eIntV); eExt.Insert(vi, eExtV); e.Insert(vi, eV); //delta.Insert(vi, (1 / determinant(N[vi])) * sumDeltaNbrs); //TODO:implemenet //f.Insert(vi, n[vi]);// (1 - lambda) * (1 / (Math.Abs(nbrs.Count))) + lambda *delta[i]; //TODO:implemenet tETF.Insert(vi, Vector3D.CrossProduct(delta[vi], n[vi])); } } return(newmbD.ToMesh()); /* * for (int i = 0; i < positions.Count; i++) * { * Int32Collection nbrs = neighbours[i].neighbours; * * Point3D pi = positions[i]; * int i0 = i; * if (i - 1 >= 0) i0 = i - 1; * Point3D pi0 = positions[i0]; * int i1 = i; * if (i + i < triangleIndices.Count) i = i + 1; * Point3D pi1 = positions[i1]; * * t[i] = (pi1 - pi0) / (Point3D.Subtract(pi1, pi0).Length); * //t[i] = (pi1 - pi0) / Math.Sqrt((Point3D.Subtract(pi1, pi0).Length)); * n[i] = SmileVisual3D.CalculateNormal(pi0, pi, pi1); * b[i] = Vector3D.CrossProduct(t[i], n[i]); * * * Vector3D eIntV = eInt[i]; * Vector3D eExtV = eExt[i]; * Vector3D eV = e[i]; * int maxNbrs = (nbrs.Count > 2 ? 2 : nbrs.Count); * for (int j = 0; j < maxNbrs; j++) * { * Point3D nbj = positions[nbrs[j]]; * double eIntj = alpha * (Point3D.Subtract(pi0, nbj).Length) + betha * (Point3D.Subtract(pi0, Point3D.Add(pi1, (Vector3D)nbj)).Length); //TODO: crosscheck * * * delta[i] = n[i];// 1 / determinant(N[i]); //TODO:implemenet * f[i] = n[i];// (1 - lambda) * (1 / (Math.Abs(nbrs.Count))) + lambda *delta[i]; //TODO:implemenet * * * double eFaej = ballon * (-(f[i].Length) - Vector3D.DotProduct((f[i] / f[i].Length), (Point3D.Subtract(nbj, pi) / Point3D.Subtract(nbj, pi).Length))); //TODO: crosscheck * double ePressj = ballon * Vector3D.DotProduct(b[i], (Point3D.Subtract(pi0, nbj) / Point3D.Subtract(pi0, nbj).Length)); * double eExtj = eFaej + ePressj; * double ej = eIntj + eExtj; * * if (j == 0) * { * eIntV.X = eIntj; * eExtV.X = eExtj; * eV.X = ej; * } * if (j == 1) * { * eIntV.Y = eIntj; * eExtV.Y = eExtj; * eV.Y = ej; * } * if (j == 2) * { * eIntV.Z = eIntj; * eExtV.Z = eExtj; * eV.Z = ej; * } * * if (ej < minEnergy) * { * minEnergy = ej; * //TODO: snake movement * AddSnakeElement(nbj); * } * * eInt[i] = eIntV; * eExt[i] = eExtV; * e[i] = eV; * } * * tETF[i] = Vector3D.CrossProduct(delta[i], n[i]); * * } * */ }
public double __MeanCurvature(Mesh3D m3d, int verticeIndex) { return(0); /* * // Initializing all necessary local variables. * double meanCurvature = 0.0; * double mixedArea = 0; * double barycentricArea = 0; * Vector3D normalOperator = new Vector3D(); * //double[] normalOperator = new double[3]; * * //for(int i=0; i<3; i++){ * // normalOperator[i] = 0.0; * //} * * // no neighbors of this face. * if(nbrs == null){ * return _infinity; * } * * // If the index point is connected with only one triangle, the index point * // is located on the edge of the surface. For example, for the ucf file the * // margin of contours might not lap around, therefore the contour might have * // boundary. * if(nbrs.Count== 1){ * return _infinity; * } * * * // Orientation Specification: * // Look at surface from outside such a way that the pivotal vertex is * // located upward. Then I call a triangle in the left is left triangle * // and the other triangle in the right is right triangle. * // * // Up pivotal vertex * // * * // * * * * // * * * * // * * * * // * * * * * * * * * // Left Right * // Down * // * // * // 1. Absolute Mean Curvature Computation Algorithm Summary: * // Xo - pivot vertex * // X1,..,Xj,..,Xn - the first ring neighbor vertices of the vertex o. * // n - number of the first ring neighbor vertices of the vertex o. * // * // Xo * // * * * * o * // * * * * * * * * // * * * * * * * * // * * * * O * * * * Xj+1 Xj-1 * Aoj * Boj* Xj+1 * // * * * * * * * * // * * * * * * * * // * * * * * * // Xj-1 Xj Xj * // * // Aoj is angle at the vertex Xj-1 * // Boj is angle at the vertex Xj+1 * // * // * // Mean Curvature Normal Operator is calculated by following 2 steps: * // First, calculate summation of (cot Aoj + cot Boj)(Xo - Xj) over j * // from 1 to n, where Xo is the pivot vertex and Xj's are elements of * // first ring neighbors vertices of the pivot vertex. * // Second, divide above value by 2*AreaMixed. * // * // Area Mixed can be calculated by either Barycentric method or * // Voronoi method. * // 1. Barycentric method calculate AreaMixed by adding one third of each * // triangle area. * // * // 2. Voronoi method is following * // if there is obtuse angle at pivot vertex, add half of the triangle * // area. * // else if there is obtuse angle beside pivot vertex, add one fourth of * // triangle area. * // else if there is no obtuse angle, add Voronoi area of triangle. * // * // Finally the Mean Curvature value is computed by taking half of the * // magnitude of the Mean Curvature Normal Operator. * * // 2. Mean Curvature Computation Algorithm Summary: The mean curvature * // (non absolute mean curvature) is computed as a summation over the * // edges adjacent to a vertex of the angle between the faces adjacent to * // the edge multiplied by the edge length, and divided by four times the * // area associated with the vertex. * * * * // Go over two neighbor faces which are connected to pivotal point * // and which share an edge between. * for (int i = 0; i < nbrs.Count; i++) { * * // Obtain vertices which are consist of faces. * Point3D vertiesInLeftFace = points[nbrs[i]]; * Point3D vertiesInRightFace = points[nbrs[i]]; * * if (i + 1 == nbrs.Count) * { * vertiesInRightFace = points[nbrs[0]]; * } * else{ * vertiesInRightFace = points[nbrs[i+1]]; * } * * // This point is also center point. * int vertexInCommon1 = -1; * * // This point is the other end of common edge between two triangles. * int vertexInCommon2 = -1; * * // These two points are not shared between two triangles. * int vertexUniqueForLeftFace = -1; * int vertexUniqueForRightFace = -1; * * // Find common vertexes in two adjacent triangles. * for(int j=0; j<3; j++){ * for(int k=0; k<3; k++){ * * // If found vertex is pivotal point, save it as vertexInCommon1. * // If found vertex is not pivotal point, then this vertex is * // the other end of the common edge of two triangle. Save it as * // vertexInCommon2. * if(vertiesInLeftFace[j] == vertiesInRightFace[k]){ * if(vertiesInLeftFace[j] == index){ * vertexInCommon1 = vertiesInLeftFace[j]; * break; * } * else{ * vertexInCommon2 = vertiesInLeftFace[j]; * break; * } * } * else{ * // If the vertex is not one of common vertexes, save it as * // vertexUniqueForLeftFace. * if(k==2){ * vertexUniqueForLeftFace = vertiesInLeftFace[j]; * } * } * } * } * * // If two triangles share only center point, the index point is located * // on the edge of the surface. For example, for the ucf file the margin * // of contours might not lap around, therefore the contour might have * // boundary. * if(vertexInCommon2 == -1){ * return _infinity; * } * * // Now task is finding a vertex which is unique to right triangle. * // Go over each vertex in right face and find a vertex which is * // not shared with left triangle. then save it as * // vertexUniqueForLeftFace. * for(int l=0; l<3; l++){ * if(vertiesInRightFace[l] == vertexInCommon1 ){ * } * else if(vertiesInRightFace[l] == vertexInCommon2){ * } * else{ * vertexUniqueForRightFace = vertiesInRightFace[l]; * break; * } * } * * // Obtain vector represent of vertex locations. * double[] pivotalCommonPoint = new double[_dimension]; * double[] theOtherCommonPoint = new double[_dimension]; * double[] leftUniquePoint = new double[_dimension]; * double[] rightUniquePoint = new double[_dimension]; * * for(int dim=0; dim<_dimension; dim++){ * * pivotalCommonPoint[dim] = _points.getPoint(vertexInCommon1)[dim]; * theOtherCommonPoint[dim] = _points.getPoint(vertexInCommon2)[dim]; * leftUniquePoint[dim] = _points.getPoint(vertexUniqueForLeftFace)[dim]; * rightUniquePoint[dim] = _points.getPoint(vertexUniqueForRightFace)[dim]; * } * * double[] centerEdgeVector = * VectorMathDouble.difference(theOtherCommonPoint, pivotalCommonPoint); * * if(!_isAbsoluteMeanCurvature){ * * // The mean curvature (non absolute mean curvature) is computed as a * // summation over the edges adjacent to a vertex of the angle between * // the faces adjacent to the edge multiplied by the edge length, and * // divided by four times the area associated with the vertex. * * // Reference: * // Anupama Jagannathan, "Segmentation and Recognition of 3D Point Clouds * // within Graph-theoretic and Thermodynamic Frameworks.", the Department * // of Electrical and Computer Engineering, 61-62, 2005. * // http://www.ece.neu.edu/faculty/elmiller/laisir/pdfs/jagannathan_phd.pdf * * // Seungbum Koo, Kunwoo Lee, "Wrap-around operation to make * // multi-resolution model of part and assembly.", department of Machanical * // and Aerospace Engineering, Seoul National University, 3, 2002, * // http://www.ece.tufts.edu/~elmiller/laisr/pdfs/jagannathan_phd.pdf. * * double[] v1 = VectorMathDouble.difference(leftUniquePoint, pivotalCommonPoint); * double[] v2 = VectorMathDouble.difference(rightUniquePoint, pivotalCommonPoint); * * // Normal vector of the first face. * double[] normal1 = VectorMathDouble.cross(v1, centerEdgeVector); * * // Normal vector of the second face. * double[] normal2 = VectorMathDouble.cross(centerEdgeVector, v2); * * // Dihedral angle between adjacent triangular faces and is computed * // as the angle between the corresponding normals. * double dihedralAngle = * Math.acos(VectorMathDouble.dot(normal1, normal2)/ * (VectorMathDouble.magnitude(normal1)*VectorMathDouble.magnitude(normal2))); * * // Edge is convex edge if the edge type is greater than 0, and edge * // is concave edge if the edge type is smaller than 0, and edge is * // planner if edge type is 0; * double edgeType = * VectorMathDouble.dot( * VectorMathDouble.cross(normal1, normal2), centerEdgeVector); * * double edgeVectorEuclideanNorm = * VectorMathDouble.magnitude(centerEdgeVector); * * if(edgeType < 0){ * meanCurvature += -1*edgeVectorEuclideanNorm*dihedralAngle; * } * else if(edgeType > 0){ * meanCurvature += edgeVectorEuclideanNorm*dihedralAngle; * } * else{ * meanCurvature += 0; * } * } * * // Calculate cot x and cot y where x and y are the angles opposite * // common edge in two incident triangles. * try { * * double angleAlpha = VectorMathDouble.vectorAngle(pivotalCommonPoint, * leftUniquePoint, * theOtherCommonPoint); * * double angleBetha = VectorMathDouble.vectorAngle(pivotalCommonPoint, * rightUniquePoint, * theOtherCommonPoint); * * // angleAlpha, angleTheta, and angleOmega are three angles of left triangles. * // Test if any of these angles is obtuse. * double angleTheta = VectorMathDouble.vectorAngle(leftUniquePoint, * pivotalCommonPoint, * theOtherCommonPoint); * double angleOmega = VectorMathDouble.vectorAngle(leftUniquePoint, * theOtherCommonPoint, * pivotalCommonPoint); * * // Obtain Mean Curvature Normal Operator. * double cotAlpha = 1/Math.tan(angleAlpha); * double cotBetha = 1/Math.tan(angleBetha); * double scalar = (cotAlpha + cotBetha); * double[] centerEdgeVectorScalarMultiplied = * VectorMathDouble.multiply(centerEdgeVector, scalar); * * normalOperator = * VectorMath.add(normalOperator, centerEdgeVectorScalarMultiplied); * * // Calculate area of the left triangle. * double[] leftEdgeVector = VectorMathDouble.difference(pivotalCommonPoint, * leftUniquePoint); * double magnitudeOfLeftEdge = VectorMathDouble.magnitude(leftEdgeVector); * * double[] rightEdgeVector = VectorMathDouble.difference(theOtherCommonPoint, * leftUniquePoint); * double magnitudeOfRightEdge = VectorMathDouble.magnitude(rightEdgeVector); * * double areaOfLeftTriangle = * Math.sin(angleAlpha)*magnitudeOfLeftEdge*magnitudeOfRightEdge/2.0; * * if(_areaCalMethod == BARYCENTRIC_AREA){ * barycentricArea = barycentricArea + areaOfLeftTriangle/3.0; * } * else if(_areaCalMethod == VORONOI_AREA){ * // Obtuse angle exists at pivot vertex. * if(angleTheta > Math.PI/2){ * mixedArea = mixedArea + areaOfLeftTriangle/2.0; * } * // Obtuse angle exists at other vertex beside the pivot vertex. * else if(angleAlpha > Math.PI/2 || angleOmega > Math.PI/2){ * mixedArea = mixedArea + areaOfLeftTriangle/4.0; * } * // No obtuse angle exists * else{ * double magnitudeOfCenterVector = VectorMathDouble.magnitude(centerEdgeVector); * * double voronoiAreaInATriangle = magnitudeOfLeftEdge* * magnitudeOfLeftEdge* * (1/Math.tan(angleOmega)) + * magnitudeOfCenterVector* * magnitudeOfCenterVector* * (1/Math.tan(angleAlpha)); * * mixedArea = mixedArea + voronoiAreaInATriangle/8.0; * } * } * } * catch (InappropriateGeometryException ige) { * throw new CalculationException( * "Unable to calculate curvature of face # " +i + * " Reason " + ige.getMessage()); * } * } * * if(_areaCalMethod == BARYCENTRIC_AREA){ * normalOperator = VectorMathDouble.multiply(normalOperator, 1.0/(2.0*barycentricArea)); * meanCurvature = meanCurvature*(1.0/(4.0*barycentricArea)); * } * else if(_areaCalMethod == VORONOI_AREA){ * * normalOperator = VectorMathDouble.multiply(normalOperator, 1.0/(2.0*mixedArea)); * meanCurvature = meanCurvature*(1.0/(4.0*mixedArea)); * } * * double curvature = meanCurvature; * * if(_isAbsoluteMeanCurvature){ * * // The mean curvature value is half of the magnitude of Normal Operator. * curvature = VectorMath.magnitude(normalOperator) / 2; * } * * return curvature; * */ }