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