public ColMatrix Transpose()
            {
                ColMatrixCreator C = new ColMatrixCreator(this.n, this.m);

                for (int i = 0; i < n; i++)
                {
                    int[]    r = rowIndex[i];
                    double[] v = values[i];
                    for (int j = 0; j < r.Length; j++)
                    {
                        try
                        {
                            C.rowIndex[r[j]].Add(i);
                        }
                        catch (OutOfMemoryException e)
                        {
                            Program.PrintText("Exception raised " + e.Message + "\n");
                            GC.Collect();
                            C.rowIndex[r[j]].Add(i);
                        }
                        try
                        {
                            C.values[r[j]].Add(v[j]);
                        }
                        catch (OutOfMemoryException e)
                        {
                            Program.PrintText("Exception raised " + e.Message + "\n");
                            GC.Collect();
                            C.values[r[j]].Add(v[j]);
                        }
                    }
                }

                return(C);
            }
            public ColMatrix Transpose()
            {
                ColMatrixCreator C = new ColMatrixCreator(this.n, this.m);

                for (int i = 0; i < n; i++)
                {
                    int[]    r = rowIndex[i];
                    double[] v = values[i];
                    for (int j = 0; j < r.Length; j++)
                    {
                        C.rowIndex[r[j]].Add(i);
                        C.values[r[j]].Add(v[j]);
                    }
                }

                return(C);
            }
        private ColMatrix BuildMatrixMT_2handle()
        {
            int cn = (regionNum + 1) * 4;
            int vn = mesh.VertexCount;
            int tn = cn;

            ColMatrixCreator C        = new ColMatrixCreator(tn, vn);
            Set <int>        tmpIndex = new Set <int>();

            double[] tmp = new double[tn];

            for (int i = 0, j = 0; i < vn; i++, j += 3)
            {
                Vector3d u = new Vector3d(mesh.VertexPos, j);

                {
                    int k = 0;
                    //double hv = (hf[k][i] > 0) ? hf[k][i] : -hf[k][i];
                    double hv = hf[k][i];
                    if (hv < 0)
                    {
                        hv = 0;
                    }
                    if (hv > regionNum)
                    {
                        hv = regionNum;
                    }
                    int tranIndex = (int)Math.Floor(hv);
                    if (tranIndex < 0)
                    {
                        tranIndex = 0;
                    }

                    int    indexBase = (k * cn) + (tranIndex * 4);
                    double ratio2    = hv - Math.Floor(hv);
                    double ratio1    = 1.0 - ratio2;
                    double weight    = hf[k][i] / regionNum;
                    tmpIndex.Add(indexBase); tmp[indexBase] += u.x * ratio1; indexBase++;
                    tmpIndex.Add(indexBase); tmp[indexBase] += u.y * ratio1; indexBase++;
                    tmpIndex.Add(indexBase); tmp[indexBase] += u.z * ratio1; indexBase++;
                    tmpIndex.Add(indexBase); tmp[indexBase] += ratio1; indexBase++;

                    if (tranIndex < regionNum)
                    {
                        tmpIndex.Add(indexBase); tmp[indexBase] += u.x * ratio2; indexBase++;
                        tmpIndex.Add(indexBase); tmp[indexBase] += u.y * ratio2; indexBase++;
                        tmpIndex.Add(indexBase); tmp[indexBase] += u.z * ratio2; indexBase++;
                        tmpIndex.Add(indexBase); tmp[indexBase] += ratio2;
                    }
                }

                int[] t = tmpIndex.ToArray();
                Array.Sort(t);
                foreach (int k in t)
                {
                    if (tmp[k] == 0)
                    {
                        continue;
                    }
                    C.rowIndex[i].Add(k);
                    C.values[i].Add(tmp[k]);
                    tmp[k] = 0;
                }
                tmpIndex.Clear();
            }

            return(C);
        }
        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);
        }