Skip to content

Commit

Permalink
add property EdgeSeparationRectilinear to EdgeRoutingSettings
Browse files Browse the repository at this point in the history
  • Loading branch information
levnach committed Mar 22, 2024
1 parent bc7c7d0 commit a5a56e8
Show file tree
Hide file tree
Showing 10 changed files with 43 additions and 31 deletions.
5 changes: 4 additions & 1 deletion GraphLayout/MSAGL/Core/Routing/EdgeRoutingSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ public double PolylinePadding {
/// For rectilinear, the penalty for a bend, as a percentage of the Manhattan distance between the source and target ports.
/// </summary>
public double BendPenalty { get; set; }

/// <summary>
/// minimal distance between two edges in rectilinear case
/// </summary>
public double EdgeSeparationRectilinear = 0;
///<summary>
///the settings for general edge bundling
///</summary>
Expand Down
2 changes: 1 addition & 1 deletion GraphLayout/MSAGL/Layout/Layered/LayeredLayoutEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ void RunPostLayering() {
//todo: are these good values?
var rer = new RectilinearEdgeRouter(originalGraph, sugiyamaSettings.NodeSeparation/3,
sugiyamaSettings.NodeSeparation/4,
true);
true, sugiyamaSettings.EdgeRoutingSettings.EdgeSeparationRectilinear);
rer.RouteToCenterOfObstacles = routingSettings.EdgeRoutingMode ==
EdgeRoutingMode.RectilinearToCenter;
rer.BendPenaltyAsAPercentageOfDistance = routingSettings.BendPenalty;
Expand Down
3 changes: 2 additions & 1 deletion GraphLayout/MSAGL/Miscellaneous/LayoutHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,14 +208,15 @@ public static void RouteAndLabelEdges(GeometryGraph geometryGraph, LayoutAlgorit
var mode = (straighLineRoutingThreshold == 0 || geometryGraph.Nodes.Count < straighLineRoutingThreshold) ? ers.EdgeRoutingMode : EdgeRoutingMode.StraightLine;
if (mode == EdgeRoutingMode.Rectilinear ||
mode == EdgeRoutingMode.RectilinearToCenter) {
double edgeSepar = layoutSettings.EdgeRoutingSettings == null ? 0 : layoutSettings.EdgeRoutingSettings.EdgeSeparationRectilinear;
RectilinearInteractiveEditor.CreatePortsAndRouteEdges(
ers.CornerRadius,
layoutSettings.NodeSeparation / 3,
nodes,
edgesToRoute,
mode,
true,
ers.BendPenalty, cancelToken);
ers.BendPenalty, edgeSepar, cancelToken);
}
else if (mode == EdgeRoutingMode.Spline || mode == EdgeRoutingMode.SugiyamaSplines) {
new SplineRouter(geometryGraph, filteredEdgesToRoute, ers.Padding, ers.PolylinePadding, ers.ConeAngle, null) {
Expand Down
12 changes: 6 additions & 6 deletions GraphLayout/MSAGL/Routing/Rectilinear/Nudging/Nudger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ bool HasGroups {
/// "nudge" paths to decrease the number of intersections and stores the results inside WidePaths of "paths"
/// </summary>
/// <param name="paths">paths through the graph</param>
/// <param name="cornerFitRad">two parallel paths should be separated by this distance if it is feasible</param>
/// <param name="edgeSeparation">two parallel paths should be separated by this distance if it is feasible</param>
/// <param name="obstacles">polygonal convex obstacles organized in a tree; the obstacles here are padded original obstacles</param>
/// <param name="ancestorsSets"></param>
/// <returns></returns>
internal Nudger(IEnumerable<Path> paths, double cornerFitRad, IEnumerable<Polyline> obstacles,
internal Nudger(IEnumerable<Path> paths, double edgeSeparation, IEnumerable<Polyline> obstacles,
Dictionary<Shape, Set<Shape>> ancestorsSets) {
AncestorsSets = ancestorsSets;
HierarchyOfGroups = RectangleNode<Shape, Point>.CreateRectangleNodeOnEnumeration(
ancestorsSets.Keys.Where(shape => shape.IsGroup).Select(group => new RectangleNode<Shape, Point>(group, group.BoundingBox)));
Obstacles = obstacles;
EdgeSeparation = Math.Max(2 * cornerFitRad, MinimalEdgeSeparation);
EdgeSeparation = Math.Max(2 * edgeSeparation, MinimalEdgeSeparation);
Paths = new List<Path>(paths);
HierarchyOfObstacles =
RectangleNode<Polyline, Point>.CreateRectangleNodeOnEnumeration(
Expand Down Expand Up @@ -885,15 +885,15 @@ static IEnumerable<Point> RemoveSwitchbacksAndMiddlePoints(IEnumerable<Point> po
/// this function defines the final path coordinates
/// </summary>
/// <param name="paths">the set of paths, point sequences</param>
/// <param name="cornerFitRadius">the radius of the arc inscribed into the path corners</param>
/// <param name="edgeSeparation">the radius of the arc inscribed into the path corners</param>
/// <param name="paddedObstacles">an enumeration of padded obstacles</param>
/// <param name="ancestorsSets"></param>
/// <param name="removeStaircases"></param>
/// <returns>the mapping of the path to its modified path</returns>
internal static void NudgePaths(IEnumerable<Path> paths, double cornerFitRadius, IEnumerable<Polyline> paddedObstacles, Dictionary<Shape, Set<Shape>> ancestorsSets, bool removeStaircases) {
internal static void NudgePaths(IEnumerable<Path> paths, double edgeSeparation, IEnumerable<Polyline> paddedObstacles, Dictionary<Shape, Set<Shape>> ancestorsSets, bool removeStaircases) {
if (!paths.Any())
return;
var nudger = new Nudger(paths, cornerFitRadius, paddedObstacles, ancestorsSets);
var nudger = new Nudger(paths, edgeSeparation, paddedObstacles, ancestorsSets);
nudger.Calculate(Direction.North, true);
nudger.Calculate(Direction.East, false);
nudger.Calculate(Direction.North, false);
Expand Down
24 changes: 16 additions & 8 deletions GraphLayout/MSAGL/Routing/Rectilinear/RectilinearEdgeRouter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,10 +317,10 @@ public RectilinearEdgeRouter()
/// <param name="obstacles">The collection of shapes to route around. Contains all source and target shapes
/// as well as any intervening obstacles.</param>
public RectilinearEdgeRouter(IEnumerable<Shape> obstacles)
: this(obstacles, DefaultPadding, DefaultCornerFitRadius, useSparseVisibilityGraph: false) {
: this(obstacles, DefaultPadding, DefaultCornerFitRadius, useSparseVisibilityGraph: false, 0) {
}


/// <summary>
/// Constructor specifying graph and shape information.
/// </summary>
Expand All @@ -330,9 +330,10 @@ public RectilinearEdgeRouter(IEnumerable<Shape> obstacles)
/// <param name="cornerFitRadius">The radius of the arc inscribed into path corners</param>
/// <param name="useSparseVisibilityGraph">If true, use a sparse visibility graph, which saves memory for large graphs
/// but may select suboptimal paths</param>
/// <param name="useObstacleRectangles">Use obstacle bounding boxes in visibility graph</param>
/// <param name="minEdgeSeparation">the minimum distance between parallen nodes</param>
public RectilinearEdgeRouter(IEnumerable<Shape> obstacles, double padding, double cornerFitRadius,
bool useSparseVisibilityGraph) {
bool useSparseVisibilityGraph, double minEdgeSeparation) {
EdgeSeparation = minEdgeSeparation;
Padding = padding;
CornerFitRadius = cornerFitRadius;
BendPenaltyAsAPercentageOfDistance = SsstRectilinearPath.DefaultBendPenaltyAsAPercentageOfDistance;
Expand All @@ -346,19 +347,20 @@ public RectilinearEdgeRouter(IEnumerable<Shape> obstacles, double padding, doubl
AddShapes(obstacles);
}


/// <summary>
/// Constructor specifying graph information.
/// </summary>
/// <param name="graph">The graph whose edges are being routed.</param>
/// <param name="padding">The minimum padding from an obstacle's curve to its enclosing polyline.</param>
/// <param name="cornerFitRadius">The radius of the arc inscribed into path corners</param>
/// <param name="useSparseVisibilityGraph">If true, use a sparse visibility graph, which saves memory for large graphs
/// <param name="minEdgeSeparation">If true, use a sparse visibility graph, which saves memory for large graphs
/// but may select suboptimal paths</param>
/// <param name="useObstacleRectangles">If true, use obstacle bounding boxes in visibility graph</param>
public RectilinearEdgeRouter(GeometryGraph graph, double padding, double cornerFitRadius,
bool useSparseVisibilityGraph)
: this(ShapeCreator.GetShapes(graph), padding, cornerFitRadius, useSparseVisibilityGraph) {
bool useSparseVisibilityGraph, double minEdgeSeparation)
: this(ShapeCreator.GetShapes(graph), padding, cornerFitRadius, useSparseVisibilityGraph, minEdgeSeparation) {
ValidateArg.IsNotNull(graph, "graph");
foreach (var edge in graph.Edges) {
this.AddEdgeGeometryToRoute(edge.EdgeGeometry);
Expand Down Expand Up @@ -518,12 +520,14 @@ internal virtual void NudgePaths(IEnumerable<Path> edgePaths) {

// Using VisibilityPolyline retains any reflection/staircases on the convex hull borders; using
// PaddedPolyline removes them.
Nudger.NudgePaths(edgePaths, CornerFitRadius, PaddedObstacles, ancestorSets, RemoveStaircases);
Nudger.NudgePaths(edgePaths, EdgeSeparation, PaddedObstacles, ancestorSets, RemoveStaircases);
//Nudger.NudgePaths(edgePaths, CornerFitRadius, this.ObstacleTree.GetAllPrimaryObstacles().Select(obs => obs.VisibilityPolyline), ancestorSets, RemoveStaircases);

}

private bool removeStaircases = true;
private double bendPenaltyAsAPercentageOfDistance;
private double edgeSeparation;
readonly List<EdgeGeometry> selfEdges = new List<EdgeGeometry>();

///<summary>
Expand Down Expand Up @@ -561,6 +565,10 @@ private static void CalculateArrowheads(EdgeGeometry edgeGeom) {
private ObstacleTree ObsTree {
get { return this.GraphGenerator.ObsTree; }
}
/// <summary>
/// the minimal distance between to parallel edges
/// </summary>
public double EdgeSeparation { get => Math.Max(edgeSeparation, CornerFitRadius); set => edgeSeparation = value; }

private void GenerateObstacleTree() {
if ((Obstacles == null) || !Obstacles.Any()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ public static class RectilinearInteractiveEditor {
static public void CreatePortsAndRouteEdges(double cornerFitRadius, double padding
, IEnumerable<Node> obstacleNodes, IEnumerable<Edge> geometryEdges
, EdgeRoutingMode edgeRoutingMode, bool useSparseVisibilityGraph
, double bendPenaltyAsAPercentageOfDistance, CancelToken ct = null) {
, double bendPenaltyAsAPercentageOfDistance, double minEdgeSeparation, CancelToken ct = null) {
var r = FillRouter(cornerFitRadius, padding, obstacleNodes, geometryEdges, edgeRoutingMode, useSparseVisibilityGraph
, bendPenaltyAsAPercentageOfDistance);
, bendPenaltyAsAPercentageOfDistance, minEdgeSeparation);
r.Run(ct);
CreateSelfEdges(geometryEdges.Where(e => e.SourcePort.Location == e.TargetPort.Location), cornerFitRadius);
}
Expand All @@ -49,9 +49,9 @@ static public void CreatePortsAndRouteEdges(double cornerFitRadius, double paddi
static public void CreatePortsAndRouteEdges(double cornerFitRadius, double padding
, IEnumerable<Node> obstacleNodes, IEnumerable<Edge> geometryEdges
, EdgeRoutingMode edgeRoutingMode, bool useSparseVisibilityGraph
, bool useObstacleRectangles) {
, bool useObstacleRectangles, double minEdgeSeparation) {
CreatePortsAndRouteEdges(cornerFitRadius, padding, obstacleNodes, geometryEdges, edgeRoutingMode
, useSparseVisibilityGraph, SsstRectilinearPath.DefaultBendPenaltyAsAPercentageOfDistance);
, useSparseVisibilityGraph, SsstRectilinearPath.DefaultBendPenaltyAsAPercentageOfDistance, minEdgeSeparation);
}

/// <summary>
Expand All @@ -66,24 +66,24 @@ static public void CreatePortsAndRouteEdges(double cornerFitRadius, double paddi
/// <param name="useSparseVisibilityGraph">Use a more memory-efficient but possibly path-suboptimal visibility graph</param>
static public void CreatePortsAndRouteEdges(double cornerFitRadius, double padding
, IEnumerable<Node> obstacleNodes, IEnumerable<Edge> geometryEdges
, EdgeRoutingMode edgeRoutingMode, bool useSparseVisibilityGraph)
, EdgeRoutingMode edgeRoutingMode, bool useSparseVisibilityGraph, double minEdgeSeparation)
{
CreatePortsAndRouteEdges(cornerFitRadius, padding, obstacleNodes, geometryEdges, edgeRoutingMode
, useSparseVisibilityGraph, SsstRectilinearPath.DefaultBendPenaltyAsAPercentageOfDistance);
, useSparseVisibilityGraph, SsstRectilinearPath.DefaultBendPenaltyAsAPercentageOfDistance, minEdgeSeparation);
}

/// <summary>
/// Create a RectilinearEdgeRouter populated with the passed obstacles.
/// </summary>
/// <returns>The populated RectilinearEdgeRouter</returns>
static RectilinearEdgeRouter FillRouter(double cornerFitRadius, double padding, IEnumerable<Node> obstacleNodes, IEnumerable<Edge> geomEdges
, EdgeRoutingMode edgeRoutingMode, bool useSparseVisibilityGraph, double bendPenaltyAsAPercentageOfDistance) {
, EdgeRoutingMode edgeRoutingMode, bool useSparseVisibilityGraph, double bendPenaltyAsAPercentageOfDistance, double minEdgeSeparation) {
Debug.Assert((EdgeRoutingMode.Rectilinear == edgeRoutingMode) || (EdgeRoutingMode.RectilinearToCenter == edgeRoutingMode)
, "Non-rectilinear edgeRoutingMode");

var nodeShapesMap = new Dictionary<Node, Shape>();
FillNodeShapesMap(obstacleNodes, geomEdges, nodeShapesMap);
var router = new RectilinearEdgeRouter(nodeShapesMap.Values, padding, cornerFitRadius, useSparseVisibilityGraph) {
var router = new RectilinearEdgeRouter(nodeShapesMap.Values, padding, cornerFitRadius, useSparseVisibilityGraph, minEdgeSeparation) {
RouteToCenterOfObstacles = (edgeRoutingMode == EdgeRoutingMode.RectilinearToCenter),
BendPenaltyAsAPercentageOfDistance = bendPenaltyAsAPercentageOfDistance
};
Expand Down
2 changes: 1 addition & 1 deletion GraphLayout/Samples/EdgeRoutingSample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ static void DemoEdgeRouterHelper(GeometryGraph graph) {
LayoutAlgorithmSettings.ShowGraph(graph);
#endif

var rectRouter = new RectilinearEdgeRouter(graph, 3,3, true);
var rectRouter = new RectilinearEdgeRouter(graph, 3,3, true, 5);
rectRouter.Run();
#if TEST
LayoutAlgorithmSettings.ShowGraph(graph);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ internal class RectilinearEdgeRouterWrapper : RectilinearEdgeRouter

internal RectilinearEdgeRouterWrapper(IEnumerable<Shape> obstacles, double padding, double cornerFitRadius,
bool routeToCenterOfObstacles, bool useSparseVisibilityGraph)
: base(obstacles, padding, cornerFitRadius, useSparseVisibilityGraph)
: base(obstacles, padding, cornerFitRadius, useSparseVisibilityGraph, cornerFitRadius)
{
this.WantPaths = true;
this.WantNudger = true;
Expand Down
2 changes: 1 addition & 1 deletion GraphLayout/Test/MSAGLTests/SplineRouterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ public void SimpleClusterGraphRectilinear()
InitialLayout initialLayout = new InitialLayout(g, new FastIncrementalLayoutSettings() { AvoidOverlaps = true });
initialLayout.Run();

RectilinearEdgeRouter router = new RectilinearEdgeRouter(g, 1, 1, false);
RectilinearEdgeRouter router = new RectilinearEdgeRouter(g, 1, 1, false, 1);
router.Run();
EnableDebugViewer();
ShowGraphInDebugViewer(g);
Expand Down
6 changes: 3 additions & 3 deletions GraphLayout/Test/TestForGDI/test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ static void GroupRoutingTestRect() {
var sugiyamaSettings = (SugiyamaLayoutSettings) settings;
var router = new RectilinearEdgeRouter(graph, sugiyamaSettings.NodeSeparation/6,
sugiyamaSettings.NodeSeparation/6,
true)
true, 0)
{
BendPenaltyAsAPercentageOfDistance = sugiyamaSettings.EdgeRoutingSettings.BendPenalty
};
Expand Down Expand Up @@ -914,7 +914,7 @@ static void RouteRectEdgesOfGeomGraph(EdgeRoutingMode edgeRoutingMode, bool useS
}

var padding = (settings == null) ? 3 : settings.NodeSeparation / 3;
var router = new RectilinearEdgeRouter(nodeShapeMap.Values, padding, 3, useSparseVisibilityGraph)
var router = new RectilinearEdgeRouter(nodeShapeMap.Values, padding, 3, useSparseVisibilityGraph, 0)
{
RouteToCenterOfObstacles = edgeRoutingMode == EdgeRoutingMode.RectilinearToCenter,
BendPenaltyAsAPercentageOfDistance = bendPenalty
Expand Down Expand Up @@ -980,7 +980,7 @@ static void RectilinearTestOnGeomGraph(EdgeRoutingMode edgeRoutingMode, bool use
}

var router = new RectilinearEdgeRouter(nodeShapeMap.Values, RectilinearEdgeRouter.DefaultPadding,
RectilinearEdgeRouter.DefaultCornerFitRadius, useSparseVisibilityGraph) {
RectilinearEdgeRouter.DefaultCornerFitRadius, useSparseVisibilityGraph, 0) {
RouteToCenterOfObstacles = edgeRoutingMode == EdgeRoutingMode.RectilinearToCenter,
BendPenaltyAsAPercentageOfDistance = bendPenalty
};
Expand Down

0 comments on commit a5a56e8

Please sign in to comment.