public DrawingData DrawRadial()
        {
            DrawingData data = InitDrawingData();

            TreeBorders borders = DrawSubtree(rootId, data, data.Height[rootId] + 1);

            double maxWidth = 0.0;
            double left     = 0.0;
            double right    = 0.0;

            for (int i = 0; i <= data.Height[rootId]; i++)
            {
                left  += borders[i, BorderSide.Left];
                right += borders[i, BorderSide.Right];

                maxWidth = Math.Max(maxWidth, right - left);
            }

            maxWidth += 1.0; // 1 unit space.
            double scale = 360.0 / maxWidth;

            CalculateAbsuluteValues(data, scale, true);

            return(data);
        }
        public DrawingData DrawLayered()
        {
            DrawingData data = InitDrawingData();

            DrawSubtree(rootId, data, data.Height[rootId] + 1);
            CalculateAbsuluteValues(data, 1.0, false);
            return(data);
        }
        private DrawingData InitDrawingData()
        {
            // Preprocessing
            int         size = forest.Size;
            DrawingData data = new DrawingData(size, rootId, isDummyRoot);

            Stack <int> vStack = new Stack <int>(size);

            vStack.Push(rootId);
            data.Depth[rootId] = 0;

            while (vStack.Count > 0)
            {
                int vId = vStack.Peek();
                int pId = forest.GetParent(vId);

                int[] neighs = forest[vId];

                int  maxHeight = -1;
                bool maxFound  = true;

                foreach (int nId in neighs)
                {
                    if (nId == pId)
                    {
                        continue;
                    }

                    data.Depth[nId] = data.Depth[vId] + 1;

                    int nH = data.Height[nId];

                    if (nH == -1)
                    {
                        vStack.Push(nId);
                        maxFound = false;
                    }
                    else
                    {
                        maxHeight = Math.Max(nH, maxHeight);
                    }
                }

                if (maxFound)
                {
                    data.Height[vId] = maxHeight + 1;
                    vStack.Pop();
                }
            } // while -- calculates height and depth for each vertex.

            return(data);
        }
        private void Preprocess()
        {
            hypertree.TransformToDual();

            // Generate and "draw" underlying tree.
            joinForest = hypertree.GetJoinTree();
            drawer     = new RootedDrawing(joinForest);
            data       = drawer.DrawRadial();

            // Computes colouring and max colour.
            colouring = hypertree.GetVertexColouring();
            hypertree.TransformToDual();

            maxCol = 0;
            for (int i = 0; i < colouring.Length; i++)
            {
                maxCol = Math.Max(colouring[i], maxCol);
            }

            // Counting sort to sort edges by their colour.
            edgeByColour = new int[colouring.Length];
            int[] colCounter = new int[maxCol + 1];

            for (int i = 0; i < colouring.Length; i++)
            {
                colCounter[colouring[i]]++;
            }

            for (int i = 1; i < colCounter.Length; i++)
            {
                colCounter[i] += colCounter[i - 1];
            }

            for (int i = colouring.Length - 1; i >= 0; i--)
            {
                int col = colouring[i];

                colCounter[col]--;
                int ind = colCounter[col];

                edgeByColour[ind] = i;
            }
            // End of counting sort.

            Array.Reverse(edgeByColour);

            edges = new List <int> [hypertree.NoOfEdges];
            for (int i = 0; i < edges.Length; i++)
            {
                edges[i] = new List <int>(Math.Max(hypertree.GetCardinality(i) * 2 - 2, 0));
            }

            // Use a DFS to determine the tree-edges of each hyperedge.
            // The search starts at the root.
            // Each time the search reaces a vertex v, it checks for all edges e containing v, if e is already activated.
            // If e is already activated, the tree-edge from v to its parent is part of the edge.

            bool[]      activeEdges = new bool[hypertree.NoOfEdges];
            Stack <int> verStack    = new Stack <int>();
            Stack <int> parStack    = new Stack <int>();

            int[] rootIds = joinForest.GetRoots();
            foreach (int rId in rootIds)
            {
                verStack.Push(rId);
                parStack.Push(-1);

                while (verStack.Count > 0)
                {
                    int vId = verStack.Pop();
                    int pId = parStack.Pop();

                    int[] edgeIds = hypertree.GetEdges(vId);

                    foreach (int eId in edgeIds)
                    {
                        if (activeEdges[eId])
                        {
                            edges[eId].Add(pId);
                            edges[eId].Add(vId);
                        }

                        activeEdges[eId] = true;
                    }

                    int[] neighs = joinForest[vId];

                    foreach (int nId in neighs)
                    {
                        if (nId == pId)
                        {
                            continue;
                        }

                        verStack.Push(nId);
                        parStack.Push(vId);
                    }
                }
            }

            // Now, data contains the radial coordinates of each vertex,
            // edges contains the list of tree-edges of each hyperedge,
            // colouring contains the colours of each hyperedge,
            // and edgeByColur has the edges ordered by their colour.
        }
        private void CalculateAbsuluteValues(DrawingData data, double scale, bool radial)
        {
            Stack <int>    vStack = new Stack <int>(forest.Size);
            Stack <double> sStack = new Stack <double>(forest.Size);

            vStack.Push(rootId);
            sStack.Push(scale);

            while (vStack.Count > 0)
            {
                double maxScale = sStack.Pop();

                int    vId    = vStack.Pop();
                int    pId    = forest.GetParent(vId);
                double xShift = data.XShift[vId];

                int[] neighs = forest[vId];

                data.XShift[vId] = (pId >= 0 ? data.XShift[pId] : 0) + xShift * maxScale;

                if (radial)
                {
                    double minX = 0.0;
                    double maxX = 0.0;

                    foreach (int nId in neighs)
                    {
                        if (nId == pId)
                        {
                            continue;
                        }

                        minX = Math.Min(minX, data.XShift[nId]);
                        maxX = Math.Max(maxX, data.XShift[nId]);
                    }

                    double difX = maxX - minX;

                    if (difX > 0 && data.Depth[vId] > 0)
                    {
                        double rad    = (double)data.Depth[vId];
                        double maxDif = 2 * Math.Acos(rad / (rad + 1.0));
                        maxDif *= (180 / Math.PI);

                        maxScale = Math.Min(maxScale, maxDif / difX);
                    }
                }

                foreach (int nId in neighs)
                {
                    if (nId == pId)
                    {
                        continue;
                    }

                    vStack.Push(nId);
                    sStack.Push(maxScale);
                }


                data.MinX = Math.Min(data.MinX, data.XShift[vId]);
                data.MaxX = Math.Max(data.MaxX, data.XShift[vId]);
            }
        }
        private TreeBorders DrawSubtree(int vId, DrawingData data, int borderCap)
        {
            TreeBorders borders;

            if (data.Height[vId] == 0)
            {
                borders = new TreeBorders(borderCap);
                borders.Add(0.0, 0.0);
                return(borders);
            }

            int maxHeigtIndex = -1;
            int maxHeigtId    = -1;
            int maxHeigt      = -1;

            int pId = forest.GetParent(vId);

            int[] neighs = forest[vId];

            for (int i = 0; i < neighs.Length; i++)
            {
                int nId = neighs[i];
                if (nId == pId)
                {
                    continue;
                }

                if (data.Height[nId] > maxHeigt)
                {
                    maxHeigtIndex = i;
                    maxHeigtId    = nId;
                    maxHeigt      = data.Height[nId];
                }
            }

            // Draw largest subtree with full capacity for borders.
            borders = DrawSubtree(maxHeigtId, data, borderCap);

            // Draw trees left of largest subtree.
            for (int i = maxHeigtIndex - 1; i >= 0; i--)
            {
                int leftId     = neighs[i];
                int leftHeight = data.Height[leftId];
                int hDif       = maxHeigt - leftHeight;

                if (leftId == pId)
                {
                    continue;
                }

                TreeBorders leftBorders = DrawSubtree(leftId, data, leftHeight + 1);

                // The distance the left tree is moved.
                // Because it will move to the left, shiftDist will become negative.
                double shiftDist = 0.0;

                double totalLeftShift = 0.0;
                double totalMaxShift  = 0.0;

                for (int h = 0; h <= leftHeight; h++)
                {
                    totalLeftShift += leftBorders[h, BorderSide.Right];
                    totalMaxShift  += borders[h, BorderSide.Left];

                    double dist = totalMaxShift - totalLeftShift;
                    shiftDist = Math.Min(shiftDist, dist);
                }

                // Have 1 unit space between both trees.
                shiftDist -= 1.0;

                // Move tree.
                data.XShift[leftId]         = shiftDist;
                borders[0, BorderSide.Left] = shiftDist;
                totalLeftShift = shiftDist;

                for (int h = 1; h <= leftHeight; h++)
                {
                    double localShift = leftBorders[h, BorderSide.Left];
                    totalLeftShift += localShift;
                    borders[h, BorderSide.Left] = localShift;
                }

                if (leftHeight < maxHeigt)
                {
                    totalMaxShift += borders[leftHeight + 1, BorderSide.Left];
                    borders[leftHeight + 1, BorderSide.Left] = totalMaxShift - totalLeftShift;
                }
            }


            // Draw trees right of largest subtree.
            for (int i = maxHeigtIndex + 1; i < neighs.Length; i++)
            {
                int rightId     = neighs[i];
                int rightHeight = data.Height[rightId];
                int hDif        = maxHeigt - rightHeight;

                if (rightId == pId)
                {
                    continue;
                }

                TreeBorders rightBorders = DrawSubtree(rightId, data, rightHeight + 1);

                // The distance the right tree is moved.
                // Because it will move to the right, shiftDist will become positive.
                double shiftDist = 0.0;

                double totalRightShift = 0.0;
                double totalMaxShift   = 0.0;

                for (int h = 0; h <= rightHeight; h++)
                {
                    totalRightShift += rightBorders[h, BorderSide.Left];
                    totalMaxShift   += borders[h, BorderSide.Right];

                    double dist = totalMaxShift - totalRightShift;
                    shiftDist = Math.Max(shiftDist, dist);
                }

                // Have 1 unit space between both trees.
                shiftDist += 1.0;

                // Move tree.
                data.XShift[rightId]         = shiftDist;
                borders[0, BorderSide.Right] = shiftDist;
                totalRightShift = shiftDist;

                for (int h = 1; h <= rightHeight; h++)
                {
                    double localShift = rightBorders[h, BorderSide.Right];
                    totalRightShift += localShift;
                    borders[h, BorderSide.Right] = localShift;
                }

                if (rightHeight < maxHeigt)
                {
                    totalMaxShift += borders[rightHeight + 1, BorderSide.Right];
                    borders[rightHeight + 1, BorderSide.Right] = totalMaxShift - totalRightShift;
                }
            }

            // Move trees such that center is 0.
            double xShift = -(borders[0, BorderSide.Right] + borders[0, BorderSide.Left]) / 2.0;

            borders[0, BorderSide.Right] += xShift;
            borders[0, BorderSide.Left]  += xShift;

            for (int i = 0; i < neighs.Length; i++)
            {
                int nId = neighs[i];
                if (nId == pId)
                {
                    continue;
                }

                data.XShift[nId] += xShift;
            }

            borders.Add(0.0, 0.0);
            return(borders);
        }