From 45ede5fd6b9c430aa7cb15150a2a69dcb5fe4b3b Mon Sep 17 00:00:00 2001 From: Ivan Krysak Date: Thu, 12 May 2022 15:10:08 +0300 Subject: [PATCH] Import edge routing from caliban (the following is the original commit message) The last step is pretty simple. All that's left to do is to take the ordered edge container and to `append` their points to their `Path` --- .../SugiyamaStyleGraphLayout/EdgeRouting.cpp | 60 +++++++++++++++++++ .../Support/SugiyamaStyleGraphLayout/Layout.h | 7 +++ 2 files changed, 67 insertions(+) diff --git a/lib/Yield/Support/SugiyamaStyleGraphLayout/EdgeRouting.cpp b/lib/Yield/Support/SugiyamaStyleGraphLayout/EdgeRouting.cpp index 80279ce0a..6cef2339f 100644 --- a/lib/Yield/Support/SugiyamaStyleGraphLayout/EdgeRouting.cpp +++ b/lib/Yield/Support/SugiyamaStyleGraphLayout/EdgeRouting.cpp @@ -279,3 +279,63 @@ OrderedEdgeContainer orderEdges(InternalGraph &&Graph, return Result; } + +/// Adds a point to the edge path or replaces its last point based +/// on their coordinates. +template +void appendPoint(PathType &Path, const Point &P) { + if (Path.size() > 1) { + auto &First = *std::prev(std::prev(Path.end())); + auto &Second = *std::prev(Path.end()); + + auto LHS = (P.Y - Second.Y) * (Second.X - First.X); + auto RHS = (Second.Y - First.Y) * (P.X - Second.X); + if (LHS == RHS) + Path.pop_back(); + } + Path.push_back(P); +} + +void route(const OrderedEdgeContainer &OrderedListOfEdges, + float MarginSize, + float EdgeDistance) { + for (auto &Edge : OrderedListOfEdges) { + if (Edge.Label->Status == ExternalGraph::EdgeStatus::Hidden) + continue; + + if (Edge.Prerouted != std::nullopt) { + appendPoint(Edge.Label->Path, Edge.Prerouted->Start); + appendPoint(Edge.Label->Path, Edge.Prerouted->Center); + appendPoint(Edge.Label->Path, Edge.Prerouted->End); + } else { + // Looking for the lowest point of the edge + auto ToUpperEdge = Edge.ToCenter.Y + Edge.ToSize.H / 2, + FromUpperEdge = Edge.FromCenter.Y + Edge.FromSize.H / 2; + float Corner = std::min(FromUpperEdge, ToUpperEdge); + Corner += MarginSize + Edge.LaneIndex * EdgeDistance; + + // The concept of lanes extends to vertical segments, that otherwise + // would merge at the points where multiple path join or separate. + // Those points have to represent real nodes. + + float PerExit = float(Edge.FromSize.W) / Edge.ExitCount, + PerEntry = float(Edge.ToSize.W) / Edge.EntryCount; + float FromTheGap = std::min(EdgeDistance, PerExit) / 2, + ToTheGap = std::min(EdgeDistance, PerEntry) / 2; + float FromDisplacement = FromTheGap * Edge.CenteredExitIndex, + ToDisplacement = ToTheGap * Edge.CenteredEntryIndex; + float ToLane = Edge.ToCenter.X + ToDisplacement, + ToTop = Edge.ToCenter.Y + Edge.ToSize.H / 2; + + appendPoint(Edge.Label->Path, + Point{ Edge.FromCenter.X + FromDisplacement, + Edge.FromCenter.Y - Edge.FromSize.H / 2 }); + appendPoint(Edge.Label->Path, + Point{ Edge.FromCenter.X + FromDisplacement, Corner }); + appendPoint(Edge.Label->Path, Point{ ToLane, Corner }); + appendPoint(Edge.Label->Path, Point{ ToLane, ToTop }); + } + + Edge.Label->Status = ExternalGraph::EdgeStatus::Routed; + } +} diff --git a/lib/Yield/Support/SugiyamaStyleGraphLayout/Layout.h b/lib/Yield/Support/SugiyamaStyleGraphLayout/Layout.h index 2f873f0b6..10266a920 100644 --- a/lib/Yield/Support/SugiyamaStyleGraphLayout/Layout.h +++ b/lib/Yield/Support/SugiyamaStyleGraphLayout/Layout.h @@ -75,6 +75,10 @@ OrderedEdgeContainer orderEdges(InternalGraph &&Graph, const RankContainer &Ranks, const LaneContainer &Lanes); +void route(const OrderedEdgeContainer &OrderedListOfEdges, + float MarginSize, + float EdgeDistance); + /// Computes the layout given a graph and the configuration. /// /// \note: it only works with `MutableEdgeNode`s. @@ -129,5 +133,8 @@ inline bool calculateSugiyamaLayout(ExternalGraph &Graph, // to get routed (see `OrderedEdgeContainer`). auto Edges = orderEdges(std::move(DAG), std::move(Prerouted), Ranks, Lanes); + // Route the edges. + route(Edges, Margin, EdgeGap); + return true; }