//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)); } }