public static TRow Row(TAxis axis, int sub_cube_i)
        {
            switch (axis)
            {
            case TAxis.x: return((TRow)(sub_cube_i % 3));

            case TAxis.y: return((TRow)((sub_cube_i % 9) / 3));

            case TAxis.z: return((TRow)(sub_cube_i / 9));
            }
            return(TRow.mid);
        }
        private TAxis chooseSplitAxis(int nodeFather, int nodeChild)
        {
            //Console.WriteLine("chooseSplitAxis work");
            int[]  arr_node;
            int    i, j, k, idx;
            TRNode node_1, node_2;
            double perimetr, perimetr_min;
            TAxis  result = new TAxis();

            arr_node = new int[MAX_M + 1];

            for (i = 0; i < FNodeArr[nodeFather].FChildren.Length; i++)
            {
                arr_node[i] = FNodeArr[nodeFather].FChildren[i];
            }

            arr_node[arr_node.Length - 1] = nodeChild;

            perimetr_min = double.MaxValue;

            node_1 = new TRNode();
            node_2 = new TRNode();

            for (i = 0; i <= 1; i++)
            {
                perimetr = 0;
                for (j = 0; j <= 1; j++)
                {
                    node_1.clearChildren();
                    node_2.clearChildren();

                    QuickSort(arr_node, 0, arr_node.Length - 1, (TAxis)i, (TBound)j);

                    for (k = 1; k <= MAX_M - MIN_M * 2 + 2; k++)
                    {
                        idx = 0;

                        while (idx < ((MIN_M - 1) + k))
                        {
                            node_1.setChild(idx, arr_node[idx]);
                            idx++;
                        }

                        for (; idx < arr_node.Length; idx++)
                        {
                            node_2.setChild(idx - ((MIN_M - 1) + k), arr_node[idx]);
                        }

                        updateMBR(node_1);
                        updateMBR(node_2);

                        perimetr = perimetr + node_1.margin() + node_2.margin();
                    }
                }

                if (perimetr <= perimetr_min)
                {
                    result       = (TAxis)i;
                    perimetr_min = perimetr;
                }

                perimetr = 0;
            }

            node_1   = null;
            node_2   = null;
            arr_node = new int[0];
            return(result);
        }
        /// <summary>
        /// TAXis
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="node_id"></param>
        /// <returns></returns>
        #region
        private TAxis chooseSplitAxis(MyLib.Point obj, int node_id)
        {
            //Console.WriteLine("chooseSplitAxis1 work");
            MyLib.Point[] arr_obj;
            int           i, j, k, idx;
            TRNode        node_1, node_2;
            double        perimetr_min, perimetr;
            TAxis         result = new TAxis();

            arr_obj = new MyLib.Point[MAX_M + 1];

            if (!FNodeArr[node_id].isLeaf)
            {
                return(0);
            }

            for (i = 0; i < FNodeArr[node_id].FObject.Length; i++)
            {
                arr_obj[i] = FNodeArr[node_id].FObject[i];
            }

            arr_obj[arr_obj.Length - 1] = obj;

            node_1 = new TRNode();
            node_2 = new TRNode();

            perimetr_min = double.MaxValue;

            for (i = 0; i <= 1; i++)
            {
                perimetr = 0;

                for (j = 0; j <= 1; j++)
                {
                    node_1.clearObjects();
                    node_2.clearObjects();

                    QuickSort(arr_obj, 0, arr_obj.Length - 1, (TAxis)i);

                    for (k = 1; k <= MAX_M - MIN_M * 2 + 2; k++) // высчитваем периметры
                    {
                        idx = 0;

                        while (idx < ((MIN_M - 1) + k))
                        {
                            node_1.setObject(idx, arr_obj[idx]);
                            idx++;
                        }

                        for (; idx < arr_obj.Length; idx++)
                        {
                            node_2.setObject(idx - ((MIN_M - 1) + k), arr_obj[idx]);
                        }

                        updateMBR(node_1);
                        updateMBR(node_2);

                        perimetr = perimetr + ((node_1.mbr.Right.X - node_1.mbr.Left.X) * 2 + (node_2.mbr.Left.Y - node_2.mbr.Right.Y) * 2);
                    }
                }

                if (perimetr <= perimetr_min)
                {
                    result       = (TAxis)i;
                    perimetr_min = perimetr;
                }
            }
            return(result);
        }
        private int FHeight;                      // высота дерева

        /// <summary>
        /// Бытсрая сортировка массива точек по заданной оси
        /// </summary>
        /// <param name="a">Массив точек</param>
        /// <param name="l">Левая граница</param>
        /// <param name="r">Правая граница</param>
        /// <param name="axe">Ось по которой происходит сортировка</param>
        static void QuickSort(MyLib.Point[] a, int l, int r, TAxis axe)
        {
            MyLib.Point temp;
            double      mid = 0;

            switch (axe)
            {
            case TAxis.X: mid = a[l + (r - l) / 2].x; break;

            case TAxis.Y: mid = a[l + (r - l) / 2].y; break;
            }

            //запись эквивалентна (l+r)/2,
            //но не вызввает переполнения на больших данных
            int i = l;
            int j = r;

            //код в while обычно выносят в процедуру particle
            while (i <= j)
            {
                switch (axe)
                {
                case TAxis.X:
                {
                    while (a[i].x < mid)
                    {
                        i++;
                    }
                    while (a[j].x > mid)
                    {
                        j--;
                    }
                }
                break;

                case TAxis.Y:
                {
                    while (a[i].y < mid)
                    {
                        i++;
                    }
                    while (a[j].y > mid)
                    {
                        j--;
                    }
                }
                break;
                }


                if (i <= j)
                {
                    temp = a[i];
                    a[i] = a[j];
                    a[j] = temp;
                    i++;
                    j--;
                }
            }
            if (i < r)
            {
                QuickSort(a, i, r, axe);
            }

            if (l < j)
            {
                QuickSort(a, l, j, axe);
            }
        }
        /// <summary>
        ///  быстрая сортировка для узлов по их MBR. axe - ось по которой происходит сортировка, bound - граница по которой происходит сортировка (левая/правая)
        /// </summary>
        /// <param name="List"></param>
        /// <param name="iLo"></param>
        /// <param name="iHi"></param>
        /// <param name="axe"></param>
        /// <param name="bound"></param>
        #region
        private void QuickSort(int[] List, int iLo, int iHi, TAxis axe, TBound bound)
        {
            //Console.WriteLine("QuickSort2 work");
            int    Lo = iLo, Hi = iHi;
            int    T;
            double Mid = 0.0;

            switch (bound)
            {
            case TBound.Left:
            {
                switch (axe)
                {
                case TAxis.X: Mid = FNodeArr[List[(Lo + Hi) / 2]].mbr.Left.X; break;

                case TAxis.Y: Mid = FNodeArr[List[(Lo + Hi) / 2]].mbr.Left.Y; break;
                }
            }
            break;

            case TBound.Right:
            {
                switch (axe)
                {
                case TAxis.X: Mid = FNodeArr[List[(Lo + Hi) / 2]].mbr.Right.X; break;

                case TAxis.Y: Mid = FNodeArr[List[(Lo + Hi) / 2]].mbr.Right.Y; break;
                }
            }
            break;
            }

            do
            {
                switch (bound)
                {
                case TBound.Left:
                {
                    switch (axe)
                    {
                    case TAxis.X:
                    {
                        while (FNodeArr[List[Lo]].mbr.Left.X < Mid)
                        {
                            Lo++;
                        }
                        while (FNodeArr[List[Hi]].mbr.Left.X > Mid)
                        {
                            Hi--;
                        }
                    }
                    break;

                    case TAxis.Y:
                    {
                        while (FNodeArr[List[Lo]].mbr.Left.Y < Mid)
                        {
                            Lo++;
                        }
                        while (FNodeArr[List[Hi]].mbr.Left.Y > Mid)
                        {
                            Hi--;
                        }
                    }
                    break;
                    }
                }
                break;

                case TBound.Right:
                {
                    switch (axe)
                    {
                    case TAxis.X:
                    {
                        while (FNodeArr[List[Lo]].mbr.Right.X < Mid)
                        {
                            Lo++;
                        }
                        while (FNodeArr[List[Hi]].mbr.Right.X > Mid)
                        {
                            Hi--;
                        }
                    }
                    break;

                    case TAxis.Y:
                    {
                        while (FNodeArr[List[Lo]].mbr.Right.Y < Mid)
                        {
                            Lo++;
                        }
                        while (FNodeArr[List[Hi]].mbr.Right.Y > Mid)
                        {
                            Hi--;
                        }
                    }
                    break;
                    }
                }
                break;
                }

                if (Lo <= Hi)
                {
                    T        = List[Lo];
                    List[Lo] = List[Hi];
                    List[Hi] = T;
                    Lo++;
                    Hi--;
                }
            } while (Lo <= Hi);

            if (Hi > iLo)
            {
                QuickSort(List, iLo, Hi, axe, bound);
            }
            if (Lo < iHi)
            {
                QuickSort(List, Lo, iHi, axe, bound);
            }
        }