Exemple #1
0
        static float ABFComputeGradient(ABFSystem sys, ABFChart chart)
        {
            ABFHalfEdge e;
            float       norm = 0f;

            for (int i = 0; i < chart.Faces.Count; i++)
            {
                ABFHalfEdge e1 = chart.Faces[i].HEdge[0], e2 = e1.Next, e3 = e2.Next;

                float gtriangle, galpha1, galpha2, galpha3;

                galpha1 = ABFComputeGradAlpha(sys, chart.Faces[i], e1);
                galpha2 = ABFComputeGradAlpha(sys, chart.Faces[i], e2);
                galpha3 = ABFComputeGradAlpha(sys, chart.Faces[i], e3);


                sys.BAlpha[e1.AngleID] = -galpha1;
                sys.BAlpha[e2.AngleID] = -galpha2;
                sys.BAlpha[e3.AngleID] = -galpha3;

                norm += galpha1 * galpha1 + galpha2 * galpha2 + galpha3 * galpha3;


                gtriangle = sys.Alpha[e1.AngleID] + sys.Alpha[e2.AngleID] + sys.Alpha[e3.AngleID] - (float)Math.PI;
                sys.BTriangle[chart.Faces[i].AngleID] = -gtriangle;

                norm += gtriangle * gtriangle;
            }

            for (int i = 0; i < chart.Vertices.Count; i++)
            {
                if (!chart.Vertices[i].PVertex.IsBorder)
                {
                    float gplanar = -2.0f * (float)Math.PI, glength;
                    e = chart.Vertices[i].HEdge;

                    do
                    {
                        gplanar += sys.Alpha[e.AngleID];
                        e        = e.Next.Next.Pair;
                    } while (e != chart.Vertices[i].HEdge);

                    sys.BInterior[chart.Vertices[i].AngleID] = -gplanar;

                    norm += gplanar * gplanar;

                    glength = ABFComputeSinProduct(sys, chart.Vertices[i], -1);
                    sys.BInterior[sys.InteriorCount + chart.Vertices[i].AngleID] = -glength;

                    norm += glength * glength;
                }
            }

            return(norm);
        }
Exemple #2
0
        public void ABFSolve(ABFChart chart)
        {
            float limit = (chart.Faces.Count > 100) ? .1f : 0.001f;

            int nInterior = 0;
            int nFaces    = 0;
            int nAngles   = 0;

            // 内陸頂点数を集計しつつ、角IDを付与
            foreach (var vertex in chart.Vertices.Where(vertex => !vertex.PVertex.IsBorder))
            {
                vertex.AngleID = nInterior++;
            }

            // 面数・辺数を集計しつつ、面とそれを成す辺のAngleIDを付与
            foreach (ABFFace face in chart.Faces)
            {
                face.AngleID                    = nFaces++;
                face.HEdge[0].AngleID           = nAngles++;
                face.HEdge[0].Next.AngleID      = nAngles++;
                face.HEdge[0].Next.Next.AngleID = nAngles++;
            }

            ABFSystem sys = new ABFSystem(nAngles, nInterior, nFaces);

            // SystemのAlphaとWeightを初期化
            foreach (ABFFace face in chart.Faces)
            {
                float       angle1, angle2, angle3;
                ABFHalfEdge edge1, edge2, edge3;
                edge1 = face.HEdge[0];
                edge2 = edge1.Next;
                edge3 = edge2.Next;
                GetAngles(face, out angle1, out angle2, out angle3);

                // angleをSystemの最大最小に丸める
                if (angle1 < sys.MinAngle)
                {
                    angle1 = sys.MinAngle;
                }
                else if (angle1 > sys.MaxAngle)
                {
                    angle1 = sys.MaxAngle;
                }

                if (angle2 < sys.MinAngle)
                {
                    angle2 = sys.MinAngle;
                }
                else if (angle2 > sys.MaxAngle)
                {
                    angle2 = sys.MaxAngle;
                }

                if (angle3 < sys.MinAngle)
                {
                    angle3 = sys.MinAngle;
                }
                else if (angle3 > sys.MaxAngle)
                {
                    angle3 = sys.MaxAngle;
                }

                // SystemのAlphaとWeightを初期化
                sys.Alpha[edge1.AngleID] = sys.Beta[edge1.AngleID] = angle1;
                sys.Alpha[edge2.AngleID] = sys.Beta[edge2.AngleID] = angle2;
                sys.Alpha[edge3.AngleID] = sys.Beta[edge3.AngleID] = angle3;

                sys.Weight[edge1.AngleID] = 2f / (angle1 * angle1);
                sys.Weight[edge2.AngleID] = 2f / (angle2 * angle2);
                sys.Weight[edge3.AngleID] = 2f / (angle3 * angle3);
            }

            //LSCM
            if (chart.LSCMMode)
            {
                chart.Alpha.Clear();
                chart.Alpha.AddRange(sys.Alpha);
                return;
            }

            //ABF++
            foreach (ABFVertex vertex in chart.Vertices)
            {
                if (!vertex.PVertex.IsBorder)
                {
                    float angleSum = 0.0f;
                    float scale;

                    ABFHalfEdge e = vertex.HEdge;
                    do
                    {
                        angleSum += sys.Beta[e.AngleID];
                        e         = e.Next.Next.Pair;
                    } while (e != vertex.HEdge);

                    scale = (angleSum == 0.0f) ? 0.0f : 2.0f * (float)Math.PI / angleSum;

                    e = vertex.HEdge;
                    do
                    {
                        sys.Beta[e.AngleID] = sys.Alpha[e.AngleID] = sys.Beta[e.AngleID] * scale;
                        e = e.Next.Next.Pair;
                    } while (e != vertex.HEdge);
                }
            }

            if (sys.InteriorCount > 0)
            {
                ABFComputeSines(sys);

                // iteration
                float lastnorm = 1e10f;

                for (int i = 0; i < ABF_MAX_ITER; i++)
                {
                    float norm = ABFComputeGradient(sys, chart);
                    lastnorm = norm;

                    if (norm < limit)
                    {
                        break;
                    }

                    if (!ABFMatrixInvert(sys, chart))
                    {
                        throw new FindInverseMatrixException("逆行列の計算に失敗しました。");
                    }

                    ABFComputeSines(sys);
                }
            }

            chart.Alpha.Clear();
            chart.Alpha.AddRange(sys.Alpha);
        }
Exemple #3
0
 static bool ABFMatrixInvert(ABFSystem sys, ABFChart chart)
 {
     throw new NotImplementedException();
 }