Skip to content

Commit 45fb726

Browse files
committed
orthagonal route preferences
1 parent 83feaac commit 45fb726

22 files changed

+500
-379
lines changed

src/diagram.rs

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1543,7 +1543,7 @@ impl Diagram {
15431543
return best_points;
15441544
}
15451545

1546-
for candidate in generate_axis_detours(from, to, from_bounds, to_bounds) {
1546+
for candidate in generate_orthogonal_routes(from, to, self.direction) {
15471547
if evaluate_candidate_route(
15481548
self,
15491549
edge,
@@ -1562,6 +1562,27 @@ impl Diagram {
15621562
}
15631563
}
15641564

1565+
if !found_perfect {
1566+
for candidate in generate_axis_detours(from, to, from_bounds, to_bounds) {
1567+
if evaluate_candidate_route(
1568+
self,
1569+
edge,
1570+
edge_id,
1571+
from,
1572+
to,
1573+
node_bounds,
1574+
existing_routes,
1575+
existing_label_bounds,
1576+
candidate,
1577+
&mut best_metric,
1578+
&mut best_points,
1579+
) {
1580+
found_perfect = true;
1581+
break;
1582+
}
1583+
}
1584+
}
1585+
15651586
if found_perfect {
15661587
return best_points;
15671588
}
@@ -2103,6 +2124,105 @@ fn generate_axis_detours(
21032124
candidates
21042125
}
21052126

2127+
fn generate_orthogonal_routes(from: Point, to: Point, direction: Direction) -> Vec<Vec<Point>> {
2128+
let dx = to.x - from.x;
2129+
let dy = to.y - from.y;
2130+
2131+
if dx.abs() < 1e-3_f32 || dy.abs() < 1e-3_f32 {
2132+
return Vec::new();
2133+
}
2134+
2135+
let vertical_stub = compute_orthogonal_stub(dy);
2136+
let horizontal_stub = compute_orthogonal_stub(dx);
2137+
2138+
let mut routes = Vec::new();
2139+
2140+
let vertical_first = build_orthogonal_route(from, to, dx, dy, vertical_stub, horizontal_stub, true);
2141+
let horizontal_first = build_orthogonal_route(from, to, dx, dy, vertical_stub, horizontal_stub, false);
2142+
2143+
match direction {
2144+
Direction::TopDown | Direction::BottomTop => {
2145+
routes.push(vertical_first);
2146+
routes.push(horizontal_first);
2147+
}
2148+
Direction::LeftRight | Direction::RightLeft => {
2149+
routes.push(horizontal_first);
2150+
routes.push(vertical_first);
2151+
}
2152+
}
2153+
2154+
routes
2155+
}
2156+
2157+
fn compute_orthogonal_stub(delta: f32) -> f32 {
2158+
let span = delta.abs();
2159+
if span >= EDGE_ORTHO_MIN_STUB * 2.0 {
2160+
EDGE_ORTHO_MIN_STUB
2161+
} else {
2162+
span * 0.5
2163+
}
2164+
}
2165+
2166+
fn build_orthogonal_route(
2167+
from: Point,
2168+
to: Point,
2169+
dx: f32,
2170+
dy: f32,
2171+
vertical_stub: f32,
2172+
horizontal_stub: f32,
2173+
vertical_first: bool,
2174+
) -> Vec<Point> {
2175+
let mut points = Vec::new();
2176+
2177+
if vertical_first {
2178+
let v_sign = if dy >= 0.0 { 1.0 } else { -1.0 };
2179+
let h_sign = if dx >= 0.0 { 1.0 } else { -1.0 };
2180+
2181+
if vertical_stub > 1e-2_f32 {
2182+
points.push(Point {
2183+
x: from.x,
2184+
y: from.y + v_sign * vertical_stub,
2185+
});
2186+
}
2187+
2188+
points.push(Point {
2189+
x: from.x,
2190+
y: to.y,
2191+
});
2192+
2193+
if horizontal_stub > 1e-2_f32 {
2194+
points.push(Point {
2195+
x: to.x - h_sign * horizontal_stub,
2196+
y: to.y,
2197+
});
2198+
}
2199+
} else {
2200+
let h_sign = if dx >= 0.0 { 1.0 } else { -1.0 };
2201+
let v_sign = if dy >= 0.0 { 1.0 } else { -1.0 };
2202+
2203+
if horizontal_stub > 1e-2_f32 {
2204+
points.push(Point {
2205+
x: from.x + h_sign * horizontal_stub,
2206+
y: from.y,
2207+
});
2208+
}
2209+
2210+
points.push(Point {
2211+
x: to.x,
2212+
y: from.y,
2213+
});
2214+
2215+
if vertical_stub > 1e-2_f32 {
2216+
points.push(Point {
2217+
x: to.x,
2218+
y: to.y - v_sign * vertical_stub,
2219+
});
2220+
}
2221+
}
2222+
2223+
points
2224+
}
2225+
21062226
fn format_points(points: &[(f32, f32)]) -> String {
21072227
points
21082228
.iter()

src/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ pub use serve::*;
1414
pub use utils::*;
1515

1616
pub const NODE_WIDTH: f32 = 140.0;
17-
pub const NODE_HEIGHT: f32 = 60.0;
17+
pub const NODE_HEIGHT: f32 = 50.0;
1818
pub const NODE_SPACING: f32 = 160.0;
1919
pub const START_OFFSET: f32 = 120.0;
2020
pub const LAYOUT_MARGIN: f32 = 80.0;
2121
pub const NODE_TEXT_CHAR_WIDTH: f32 = 7.4;
22-
pub const NODE_TEXT_HORIZONTAL_PADDING: f32 = 48.0;
23-
pub const NODE_TEXT_VERTICAL_PADDING: f32 = 32.0;
22+
pub const NODE_TEXT_HORIZONTAL_PADDING: f32 = 60.0;
23+
pub const NODE_TEXT_VERTICAL_PADDING: f32 = 22.0;
2424
pub const EDGE_LABEL_MIN_WIDTH: f32 = 36.0;
2525
pub const EDGE_LABEL_MIN_HEIGHT: f32 = 28.0;
2626
pub const EDGE_LABEL_LINE_HEIGHT: f32 = 16.0;
@@ -38,6 +38,7 @@ pub const EDGE_SINGLE_OFFSET: f32 = 32.0;
3838
pub const EDGE_SINGLE_STUB: f32 = 56.0;
3939
pub const EDGE_SINGLE_OFFSET_STEP: f32 = 14.0;
4040
pub const EDGE_SINGLE_STUB_STEP: f32 = 20.0;
41+
pub const EDGE_ORTHO_MIN_STUB: f32 = 28.0;
4142
pub const EDGE_ARROW_EXTENSION: f32 = 1.0;
4243
pub const LAYOUT_BLOCK_START: &str = "%% OXDRAW LAYOUT START";
4344
pub const LAYOUT_BLOCK_END: &str = "%% OXDRAW LAYOUT END";

tests/output/png/conditional.png

-8.31 KB
Loading

tests/output/png/failure_modes.png

220 KB
Loading

tests/output/png/flow.png

-23 KB
Loading
64.2 KB
Loading

tests/output/png/html_breaks.png

-17.3 KB
Loading

tests/output/png/image_node.png

192 KB
Loading
-8.03 KB
Loading

tests/output/png/shapes.png

-32 KB
Loading

0 commit comments

Comments
 (0)