private ColMatrix BuildMatrixA(List <VertexRecord> records, int[] faceIndex, double[] lapWeight, double[] posWeight, double weightAdjustment)
        {
            // build backward map
            int[] map = new int[mesh.VertexCount];
            for (int i = 0; i < records.Count; i++)
            {
                map[records[i].index] = i;
            }

            int          n  = records.Count;
            int          fn = faceIndex.Length / 3;
            SparseMatrix A  = new SparseMatrix(2 * n, n);

            this.currentArea = new double[n];
            for (int i = 0; i < n; i++)
            {
                currentArea[i] = 0;
            }

            for (int i = 0, j = 0; i < fn; i++, j += 3)
            {
                int      c1   = faceIndex[j];
                int      c2   = faceIndex[j + 1];
                int      c3   = faceIndex[j + 2];
                Vector3d v1   = new Vector3d(mesh.VertexPos, c1 * 3);
                Vector3d v2   = new Vector3d(mesh.VertexPos, c2 * 3);
                Vector3d v3   = new Vector3d(mesh.VertexPos, c3 * 3);
                double   cot1 = (v2 - v1).Dot(v3 - v1) / (v2 - v1).Cross(v3 - v1).Length();
                double   cot2 = (v3 - v2).Dot(v1 - v2) / (v3 - v2).Cross(v1 - v2).Length();
                double   cot3 = (v1 - v3).Dot(v2 - v3) / (v1 - v3).Cross(v2 - v3).Length();
                //cot1 = cot2 = cot3 = 1.0;
                if (double.IsNaN(cot1))
                {
                    throw new Exception();
                }
                if (double.IsNaN(cot2))
                {
                    throw new Exception();
                }
                if (double.IsNaN(cot3))
                {
                    throw new Exception();
                }

                c1 = map[c1];
                c2 = map[c2];
                c3 = map[c3];
                A.AddValueTo(c2, c2, -cot1); A.AddValueTo(c2, c3, cot1);
                A.AddValueTo(c3, c3, -cot1); A.AddValueTo(c3, c2, cot1);
                A.AddValueTo(c3, c3, -cot2); A.AddValueTo(c3, c1, cot2);
                A.AddValueTo(c1, c1, -cot2); A.AddValueTo(c1, c3, cot2);
                A.AddValueTo(c1, c1, -cot3); A.AddValueTo(c1, c2, cot3);
                A.AddValueTo(c2, c2, -cot3); A.AddValueTo(c2, c1, cot3);

                double area = ((v2 - v1).Cross(v3 - v1)).Length() / 2.0;
                currentArea[c1] += area;
                currentArea[c2] += area;
                currentArea[c3] += area;
            }
            for (int i = 0; i < n; i++)
            {
                double tot = 0;
                foreach (SparseMatrix.Element e in A.Rows[i])
                {
                    if (e.i != e.j)
                    {
                        tot += e.value;
                    }
                }
                if (tot > 10000)
                {
                    foreach (SparseMatrix.Element e in A.Rows[i])
                    {
                        e.value /= (tot / 10000);
                    }
                }
                foreach (SparseMatrix.Element e in A.Rows[i])
                {
                    e.value *= lapWeight[records[i].index] * weightAdjustment;
                }
            }

            // positional constraints
            for (int i = 0; i < n; i++)
            {
                int    j      = records[i].index;
                double weight = posWeight[j] * (currentArea[i] / originalArea[j]);
                if (weight <= 0)
                {
                    weight = posWeight[i];
                }
                A.AddValueTo(i + n, i, weight);
            }

            A.SortElement();
            ColMatrixCreator cmA = new ColMatrixCreator(2 * n, n);

            foreach (List <SparseMatrix.Element> r in A.Rows)
            {
                foreach (SparseMatrix.Element e in r)
                {
                    cmA.AddValueTo(e.i, e.j, e.value);
                }
            }

            return(cmA);
        }
        private ColMatrix BuildMatrixA(Resolution r, double[] lapWeight, double[] posWeight)
        {
            // build backward map
            int[] map = new int[mesh.VertexCount];
            for (int i = 0; i < r.vertexList.Length; i++)
            {
                map[r.vertexList[i]] = i;
            }

            int          n  = r.vertexList.Length;
            int          fn = r.faceList.Length / 3;
            SparseMatrix A  = new SparseMatrix(2 * n, n);

            for (int i = 0, j = 0; i < fn; i++, j += 3)
            {
                int      c1   = r.faceList[j];
                int      c2   = r.faceList[j + 1];
                int      c3   = r.faceList[j + 2];
                Vector3d v1   = new Vector3d(mesh.VertexPos, c1 * 3);
                Vector3d v2   = new Vector3d(mesh.VertexPos, c2 * 3);
                Vector3d v3   = new Vector3d(mesh.VertexPos, c3 * 3);
                double   cot1 = (v2 - v1).Dot(v3 - v1) / (v2 - v1).Cross(v3 - v1).Length();
                double   cot2 = (v3 - v2).Dot(v1 - v2) / (v3 - v2).Cross(v1 - v2).Length();
                double   cot3 = (v1 - v3).Dot(v2 - v3) / (v1 - v3).Cross(v2 - v3).Length();
                //cot1 = cot2 = cot3 = 1.0;
                if (double.IsNaN(cot1))
                {
                    throw new Exception();
                }
                if (double.IsNaN(cot2))
                {
                    throw new Exception();
                }
                if (double.IsNaN(cot3))
                {
                    throw new Exception();
                }

                c1 = map[c1];
                c2 = map[c2];
                c3 = map[c3];
                A.AddValueTo(c2, c2, -cot1); A.AddValueTo(c2, c3, cot1);
                A.AddValueTo(c3, c3, -cot1); A.AddValueTo(c3, c2, cot1);
                A.AddValueTo(c3, c3, -cot2); A.AddValueTo(c3, c1, cot2);
                A.AddValueTo(c1, c1, -cot2); A.AddValueTo(c1, c3, cot2);
                A.AddValueTo(c1, c1, -cot3); A.AddValueTo(c1, c2, cot3);
                A.AddValueTo(c2, c2, -cot3); A.AddValueTo(c2, c1, cot3);
            }
            for (int i = 0; i < n; i++)
            {
                double tot = 0;
                foreach (SparseMatrix.Element e in A.Rows[i])
                {
                    if (e.i != e.j)
                    {
                        tot += e.value;
                    }
                }
                if (tot > 10000)
                {
                    foreach (SparseMatrix.Element e in A.Rows[i])
                    {
                        e.value /= (tot / 10000);
                    }
                }
                foreach (SparseMatrix.Element e in A.Rows[i])
                {
                    e.value *= lapWeight[r.vertexList[i]];
                }
            }

            // positional constraints
            for (int i = 0; i < n; i++)
            {
                A.AddElement(i + n, i, posWeight[r.vertexList[i]]);
            }

            A.SortElement();
            ColMatrixCreator cmA = new ColMatrixCreator(2 * n, n);

            foreach (List <SparseMatrix.Element> row in A.Rows)
            {
                foreach (SparseMatrix.Element e in row)
                {
                    cmA.AddValueTo(e.i, e.j, e.value);
                }
            }

            return(cmA);
        }