//tree specific properties /// <summary> /// Commits the position of the link to the corresponding Link. /// </summary> /// <remarks> /// This routes the Link's Route. /// </remarks> public override void CommitPosition() { Route s = this.Route; if (s == null) { return; } if (s.Routing == LinkRouting.AvoidsNodes) { return; } TreeLayout layout = this.Network.Layout; TreeVertex parent; TreeVertex child; switch (layout.Path) { case TreePath.Destination: parent = this.FromVertex; child = this.ToVertex; break; case TreePath.Source: parent = this.ToVertex; child = this.FromVertex; break; default: throw new InvalidOperationException("Unhandled Path value " + layout.Path.ToString()); } if (parent == null || child == null) { return; } Point p = this.RelativePoint; if (p.X == 0 && p.Y == 0 && !parent.RouteFirstRow) // no rows { AdjustRouteForAngleChange(parent, child); return; } bool firstrow = (p.X == 0 && p.Y == 0 && parent.RouteFirstRow); Node node = parent.Node; Rect nodebounds = node.Bounds; double angle = TreeLayout.OrthoAngle(parent); double layerspacing = TreeLayout.ComputeLayerSpacing(parent); double rowspacing = parent.RowSpacing; s.UpdatePoints(); bool bezier = s.Curve == LinkCurve.Bezier; bool ortho = s.Orthogonal; int idx; Point prev; Point next; Point last; if (ortho || bezier) { idx = 2; while (s.PointsCount > 4) { s.RemovePoint(2); } prev = s.GetPoint(1); next = s.GetPoint(2); } else { idx = 1; while (s.PointsCount > 3) { s.RemovePoint(1); } prev = s.GetPoint(0); next = s.GetPoint(s.PointsCount - 1); } last = s.GetPoint(s.PointsCount - 1); if (angle == 0) { double c; if (parent.Alignment == TreeAlignment.End) { // route around at Y coordinate relative to the bottom of the parent node c = nodebounds.Bottom + p.Y; // try to keep the links straight from the parent node -- consider room from RowIndent and NodeIndent if (p.Y == 0 && prev.Y > last.Y + parent.RowIndent) { c = Math.Min(c, Math.Max(prev.Y, c - TreeLayout.ComputeNodeIndent(parent))); } } else if (parent.Alignment == TreeAlignment.Start) { // route around at Y coordinate relative to the top of the parent node c = nodebounds.Top + p.Y; // try to keep the links straight from the parent node -- consider room from RowIndent and NodeIndent if (p.Y == 0 && prev.Y < last.Y - parent.RowIndent) { c = Math.Max(c, Math.Min(prev.Y, c + TreeLayout.ComputeNodeIndent(parent))); } } else if (parent.RouteAroundCentered || (parent.RouteAroundLastParent && parent.MaxGenerationCount == 1)) { c = nodebounds.Top - parent.SubtreeOffset.Y + p.Y; } else { c = nodebounds.Y + nodebounds.Height / 2 + p.Y; } if (bezier) // curved segments { if (!firstrow) { // add a straight curve at Y-coord C s.InsertPoint(idx, new Point(prev.X, c)); idx++; s.InsertPoint(idx, new Point(nodebounds.Right + layerspacing, c)); idx++; s.InsertPoint(idx, new Point(nodebounds.Right + layerspacing + (p.X - rowspacing) / 3, c)); idx++; s.InsertPoint(idx, new Point(nodebounds.Right + layerspacing + (p.X - rowspacing) * 2 / 3, c)); idx++; } else { s.InsertPoint(idx, new Point(nodebounds.Right + layerspacing + (p.X - rowspacing), c)); idx++; } s.InsertPoint(idx, new Point(nodebounds.Right + layerspacing + (p.X - rowspacing), c)); idx++; s.InsertPoint(idx, new Point(next.X, c)); idx++; } else // straight line segments { if (ortho) { s.InsertPoint(idx, new Point(nodebounds.Right + layerspacing / 2, prev.Y)); idx++; } s.InsertPoint(idx, new Point(nodebounds.Right + layerspacing / 2, c)); idx++; s.InsertPoint(idx, new Point(nodebounds.Right + layerspacing + p.X - (ortho ? rowspacing / 2 : rowspacing), c)); idx++; if (ortho) { s.InsertPoint(idx, new Point(s.GetPoint(idx - 1).X, next.Y)); idx++; } } } else if (angle == 90) { double c; if (parent.Alignment == TreeAlignment.End) { c = nodebounds.Right + p.X; if (p.X == 0 && prev.X > last.X + parent.RowIndent) { c = Math.Min(c, Math.Max(prev.X, c - TreeLayout.ComputeNodeIndent(parent))); } } else if (parent.Alignment == TreeAlignment.Start) { c = nodebounds.Left + p.X; if (p.X == 0 && prev.X < last.X - parent.RowIndent) { c = Math.Max(c, Math.Min(prev.X, c + TreeLayout.ComputeNodeIndent(parent))); } } else if (parent.RouteAroundCentered || (parent.RouteAroundLastParent && parent.MaxGenerationCount == 1)) { c = nodebounds.Left - parent.SubtreeOffset.X + p.X; } else { c = nodebounds.X + nodebounds.Width / 2 + p.X; } if (bezier) { if (!firstrow) { s.InsertPoint(idx, new Point(c, prev.Y)); idx++; s.InsertPoint(idx, new Point(c, nodebounds.Bottom + layerspacing)); idx++; s.InsertPoint(idx, new Point(c, nodebounds.Bottom + layerspacing + (p.Y - rowspacing) / 3)); idx++; s.InsertPoint(idx, new Point(c, nodebounds.Bottom + layerspacing + (p.Y - rowspacing) * 2 / 3)); idx++; } else { s.InsertPoint(idx, new Point(c, nodebounds.Bottom + layerspacing + (p.Y - rowspacing))); idx++; } s.InsertPoint(idx, new Point(c, nodebounds.Bottom + layerspacing + (p.Y - rowspacing))); idx++; s.InsertPoint(idx, new Point(c, next.Y)); idx++; } else { if (ortho) { s.InsertPoint(idx, new Point(prev.X, nodebounds.Bottom + layerspacing / 2)); idx++; } s.InsertPoint(idx, new Point(c, nodebounds.Bottom + layerspacing / 2)); idx++; s.InsertPoint(idx, new Point(c, nodebounds.Bottom + layerspacing + p.Y - (ortho ? rowspacing / 2 : rowspacing))); idx++; if (ortho) { s.InsertPoint(idx, new Point(next.X, s.GetPoint(idx - 1).Y)); idx++; } } } else if (angle == 180) { double c; if (parent.Alignment == TreeAlignment.End) { c = nodebounds.Bottom + p.Y; if (p.Y == 0 && prev.Y > last.Y + parent.RowIndent) { c = Math.Min(c, Math.Max(prev.Y, c - TreeLayout.ComputeNodeIndent(parent))); } } else if (parent.Alignment == TreeAlignment.Start) { c = nodebounds.Top + p.Y; if (p.Y == 0 && prev.Y < last.Y - parent.RowIndent) { c = Math.Max(c, Math.Min(prev.Y, c + TreeLayout.ComputeNodeIndent(parent))); } } else if (parent.RouteAroundCentered || (parent.RouteAroundLastParent && parent.MaxGenerationCount == 1)) { c = nodebounds.Top - parent.SubtreeOffset.Y + p.Y; } else { c = nodebounds.Y + nodebounds.Height / 2 + p.Y; } if (bezier) { if (!firstrow) { s.InsertPoint(idx, new Point(prev.X, c)); idx++; s.InsertPoint(idx, new Point(nodebounds.Left - layerspacing, c)); idx++; s.InsertPoint(idx, new Point(nodebounds.Left - layerspacing + (p.X + rowspacing) / 3, c)); idx++; s.InsertPoint(idx, new Point(nodebounds.Left - layerspacing + (p.X + rowspacing) * 2 / 3, c)); idx++; } else { s.InsertPoint(idx, new Point(nodebounds.Left - layerspacing + (p.X + rowspacing), c)); idx++; } s.InsertPoint(idx, new Point(nodebounds.Left - layerspacing + (p.X + rowspacing), c)); idx++; s.InsertPoint(idx, new Point(next.X, c)); idx++; } else { if (ortho) { s.InsertPoint(idx, new Point(nodebounds.Left - layerspacing / 2, prev.Y)); idx++; } s.InsertPoint(idx, new Point(nodebounds.Left - layerspacing / 2, c)); idx++; s.InsertPoint(idx, new Point(nodebounds.Left - layerspacing + p.X + (ortho ? rowspacing / 2 : rowspacing), c)); idx++; if (ortho) { s.InsertPoint(idx, new Point(s.GetPoint(idx - 1).X, next.Y)); idx++; } } } else if (angle == 270) { double c; if (parent.Alignment == TreeAlignment.End) { c = nodebounds.Right + p.X; if (p.X == 0 && prev.X > last.X + parent.RowIndent) { c = Math.Min(c, Math.Max(prev.X, c - TreeLayout.ComputeNodeIndent(parent))); } } else if (parent.Alignment == TreeAlignment.Start) { c = nodebounds.Left + p.X; if (p.X == 0 && prev.X < last.X - parent.RowIndent) { c = Math.Max(c, Math.Min(prev.X, c + TreeLayout.ComputeNodeIndent(parent))); } } else if (parent.RouteAroundCentered || (parent.RouteAroundLastParent && parent.MaxGenerationCount == 1)) { c = nodebounds.Left - parent.SubtreeOffset.X + p.X; } else { c = nodebounds.X + nodebounds.Width / 2 + p.X; } if (bezier) { if (!firstrow) { s.InsertPoint(idx, new Point(c, prev.Y)); idx++; s.InsertPoint(idx, new Point(c, nodebounds.Top - layerspacing)); idx++; s.InsertPoint(idx, new Point(c, nodebounds.Top - layerspacing + (p.Y + rowspacing) / 3)); idx++; s.InsertPoint(idx, new Point(c, nodebounds.Top - layerspacing + (p.Y + rowspacing) * 2 / 3)); idx++; } else { s.InsertPoint(idx, new Point(c, nodebounds.Top - layerspacing + (p.Y + rowspacing))); idx++; } s.InsertPoint(idx, new Point(c, nodebounds.Top - layerspacing + (p.Y + rowspacing))); idx++; s.InsertPoint(idx, new Point(c, next.Y)); idx++; } else { if (ortho) { s.InsertPoint(idx, new Point(prev.X, nodebounds.Top - layerspacing / 2)); idx++; } s.InsertPoint(idx, new Point(c, nodebounds.Top - layerspacing / 2)); idx++; s.InsertPoint(idx, new Point(c, nodebounds.Top - layerspacing + p.Y + (ortho ? rowspacing / 2 : rowspacing))); idx++; if (ortho) { s.InsertPoint(idx, new Point(next.X, s.GetPoint(idx - 1).Y)); idx++; } } } else { throw new InvalidOperationException("Invalid angle " + angle.ToString(System.Globalization.CultureInfo.InvariantCulture)); } }
private void AdjustRouteForAngleChange(TreeVertex parent, TreeVertex child) { double angle = TreeLayout.OrthoAngle(parent); double childangle = TreeLayout.OrthoAngle(child); if (angle == childangle) { return; } double layerspacing = TreeLayout.ComputeLayerSpacing(parent); Rect pb = parent.Node.Bounds; Rect cb = child.Node.Bounds; // but maybe an Angle change causes the child node not to be adjacent to the layer // separating it with the parent node; only need to do anything if that's the case if ((angle == 0 && cb.Left - pb.Right < layerspacing + 1) || (angle == 90 && cb.Top - pb.Bottom < layerspacing + 1) || (angle == 180 && pb.Left - cb.Right < layerspacing + 1) || (angle == 270 && pb.Top - cb.Bottom < layerspacing + 1)) { return; } Route s = this.Route; s.UpdatePoints(); bool bezier = s.Curve == LinkCurve.Bezier; bool ortho = s.Orthogonal; if (angle == 0) { double x = pb.Right + layerspacing / 2; if (bezier) // curved segments { if (s.PointsCount == 4) { double y = s.GetPoint(3).Y; s.SetPoint(1, new Point(x - 20, s.GetPoint(1).Y)); s.InsertPoint(2, new Point(x - 20, y)); s.InsertPoint(3, new Point(x, y)); s.InsertPoint(4, new Point(x + 20, y)); s.SetPoint(5, new Point(s.GetPoint(5).X, y)); } } else if (ortho) { if (s.PointsCount == 6) { s.SetPoint(2, new Point(x, s.GetPoint(2).Y)); s.SetPoint(3, new Point(x, s.GetPoint(3).Y)); } } else { if (s.PointsCount == 4) { s.InsertPoint(2, new Point(x, s.GetPoint(2).Y)); } else if (s.PointsCount == 3) { s.SetPoint(1, new Point(x, s.GetPoint(2).Y)); } else if (s.PointsCount == 2) { s.InsertPoint(1, new Point(x, s.GetPoint(1).Y)); } } } else if (angle == 90) { double y = pb.Bottom + layerspacing / 2; if (bezier) // curved segments { if (s.PointsCount == 4) { double x = s.GetPoint(3).X; s.SetPoint(1, new Point(s.GetPoint(1).X, y - 20)); s.InsertPoint(2, new Point(x, y - 20)); s.InsertPoint(3, new Point(x, y)); s.InsertPoint(4, new Point(x, y + 20)); s.SetPoint(5, new Point(x, s.GetPoint(5).Y)); } } else if (ortho) { if (s.PointsCount == 6) { s.SetPoint(2, new Point(s.GetPoint(2).X, y)); s.SetPoint(3, new Point(s.GetPoint(3).X, y)); } } else { if (s.PointsCount == 4) { s.InsertPoint(2, new Point(s.GetPoint(2).X, y)); } else if (s.PointsCount == 3) { s.SetPoint(1, new Point(s.GetPoint(2).X, y)); } else if (s.PointsCount == 2) { s.InsertPoint(1, new Point(s.GetPoint(1).X, y)); } } } else if (angle == 180) { double x = pb.Left - layerspacing / 2; if (bezier) // curved segments { if (s.PointsCount == 4) { double y = s.GetPoint(3).Y; s.SetPoint(1, new Point(x + 20, s.GetPoint(1).Y)); s.InsertPoint(2, new Point(x + 20, y)); s.InsertPoint(3, new Point(x, y)); s.InsertPoint(4, new Point(x - 20, y)); s.SetPoint(5, new Point(s.GetPoint(5).X, y)); } } else if (ortho) { if (s.PointsCount == 6) { s.SetPoint(2, new Point(x, s.GetPoint(2).Y)); s.SetPoint(3, new Point(x, s.GetPoint(3).Y)); } } else { if (s.PointsCount == 4) { s.InsertPoint(2, new Point(x, s.GetPoint(2).Y)); } else if (s.PointsCount == 3) { s.SetPoint(1, new Point(x, s.GetPoint(2).Y)); } else if (s.PointsCount == 2) { s.InsertPoint(1, new Point(x, s.GetPoint(1).Y)); } } } else if (angle == 270) { double y = pb.Top - layerspacing / 2; if (bezier) // curved segments { if (s.PointsCount == 4) { double x = s.GetPoint(3).X; s.SetPoint(1, new Point(s.GetPoint(1).X, y + 20)); s.InsertPoint(2, new Point(x, y + 20)); s.InsertPoint(3, new Point(x, y)); s.InsertPoint(4, new Point(x, y - 20)); s.SetPoint(5, new Point(x, s.GetPoint(5).Y)); } } else if (ortho) { if (s.PointsCount == 6) { s.SetPoint(2, new Point(s.GetPoint(2).X, y)); s.SetPoint(3, new Point(s.GetPoint(3).X, y)); } } else { if (s.PointsCount == 4) { s.InsertPoint(2, new Point(s.GetPoint(2).X, y)); } else if (s.PointsCount == 3) { s.SetPoint(1, new Point(s.GetPoint(2).X, y)); } else if (s.PointsCount == 2) { s.InsertPoint(1, new Point(s.GetPoint(1).X, y)); } } } }