public Drawing.Point[] GetConnectionBezier(ParentChildConnection <Node <T> > connection) { var lineseg = this.GetConnectionLine(connection); var parent_attach_point = lineseg.Start; var child_attach_point = lineseg.End; double scale = this.Options.LevelSeparation / 2.0; var dif = child_attach_point.Subtract(parent_attach_point).Multiply(scale); var handle_displacement = TreeLayout <T> .IsVertical(this.Options.Direction) ? new Drawing.Point(0, dif.Y) : new Drawing.Point(dif.X, 0); var h1 = parent_attach_point.Add(handle_displacement); var h2 = child_attach_point.Add(handle_displacement * (-1)); return(new[] { parent_attach_point, h1, h2, child_attach_point }); }
private static Node <T> get_leftmost(Node <T> node, int level, int maxlevel) { if (level >= maxlevel) { return(node); } if (node.ChildCount == 0) { return(null); } foreach (var child in node.EnumChildren()) { var leftmostDescendant = TreeLayout <T> .get_leftmost(child, level + 1, maxlevel); if (leftmostDescendant != null) { return(leftmostDescendant); } } return(null); }
private void apportion(Node <T> node, int level) { /*------------------------------------------------------ * Clean up the positioning of small sibling subtrees. * Subtrees of a node are formed independently and * placed as close together as possible. By requiring * that the subtrees be rigid at the time they are put * together, we avoid the undesirable effects that can * accrue from positioning nodes rather than subtrees. *----------------------------------------------------*/ var first_child = node.FirstChild; var first_child_left_neighbor = first_child.left_neighbor; int j = 1; for (int k = this.Options.MaximumDepth - level; first_child != null && first_child_left_neighbor != null && j <= k;) { double modifier_sum_right = 0; double modifier_sum_left = 0; var right_ancestor = first_child; var left_ancestor = first_child_left_neighbor; for (int l = 0; l < j; l++) { right_ancestor = right_ancestor.Parent; left_ancestor = left_ancestor.Parent; modifier_sum_right += right_ancestor.modifier; modifier_sum_left += left_ancestor.modifier; } double total_gap = (first_child_left_neighbor.prelim_x + modifier_sum_left + this.GetNodeSize(first_child_left_neighbor) + this.Options.SubtreeSeparation) - (first_child.prelim_x + modifier_sum_right); if (total_gap > 0) { var subtree_aux = node; int num_subtrees = 0; for (; subtree_aux != null && subtree_aux != left_ancestor; subtree_aux = subtree_aux.LeftSibling) { num_subtrees++; } if (subtree_aux != null) { var subtree_move_aux = node; double single_gap = total_gap / num_subtrees; for (; subtree_move_aux != left_ancestor; subtree_move_aux = subtree_move_aux.LeftSibling) { subtree_move_aux.prelim_x += total_gap; subtree_move_aux.modifier += total_gap; total_gap -= single_gap; } } } j++; if (first_child.ChildCount == 0) { first_child = TreeLayout <T> .get_leftmost(node, 0, j); } else { first_child = first_child.FirstChild; } if (first_child != null) { first_child_left_neighbor = first_child.left_neighbor; } } }