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`
This commit is contained in:
Ivan Krysak
2022-05-12 15:10:08 +03:00
parent e5f98a0437
commit 45ede5fd6b
2 changed files with 67 additions and 0 deletions
@@ -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<typename PathType>
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;
}
}
@@ -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;
}