Ejemplo n.º 1
0
        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]);
 *
 *          }
 * */
        }
Ejemplo n.º 2
0
        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);
        }