Point handles for routes and outlines; Area corners; bus goes round right
Deploy web Studio / deploy (push) Successful in 1m4s

Studio: one selected object with pts (a route, an outlined area) shows a
handle on each point and a + in the middle of each side: drag a point to
move it, drag a + to add one there, double-click a point to remove it
(open routes keep 2, outlines 3). Points snap to the grid and onto wall,
fence and road ends, at any angle; one undo step each. Handles keep their
screen size (new viewer callback onView on every redraw) and follow
re-renders and selection. The viewer captures the pointer, so a double-
click targets the drawing: the last point pressed is remembered instead.

Prefab meta `outline`: the prefab draws pts as its outline. Area has it:
Edit corners turns its rectangle into four points, Rectangle again
removes them.

Routes: where a path doubles back, the lane offset puts a point on each
side, so it rounds into a U-turn instead of a diagonal across the lanes.
The streets demo bus now runs east, three quarters round the roundabout
(clockwise, left-hand traffic), down south street, turns and comes back
by the short way, instead of going round the wrong way on its way out.

Tests: Rust 81 (a doubling-back route: each mover once, no sort cycles),
Studio 134 (corners, move, add, remove, undo), web 100.
This commit is contained in:
grabowski committed 2026-10-25 18:46:47 +07:00
1 parent 540b37020c
commit c8becc2e59
12 files changed
+189 -11

No files matched your search

+2 -2
View File
@@ -26,8 +26,8 @@ fn prefab_site(o) {
}
fn meta_area() {
#{ label: "Area", category: "Ground", icon: "▱", shape: "rect",
help: "A paved or planted area lying on the ground.",
#{ label: "Area", category: "Ground", icon: "▱", shape: "rect", outline: true,
help: "A paved or planted area lying on the ground. Edit corners turns the rectangle into points you can drag, add (drag a +) and remove (double-click), for any outline.",
props: [
#{ key: "w", type: "float", def: 10.0, min: 0.5, max: 1000.0, step: 0.5, label: "Width (m)" },
#{ key: "d", type: "float", def: 6.0, min: 0.5, max: 1000.0, step: 0.5, label: "Depth (m)" },
+8 -3
View File
@@ -84,7 +84,8 @@ fn route_pts(o, closed) {
out
}
/// The line `d` metres to the left of a path (mitred corners).
/// The line `d` metres to the left of a path (mitred corners). Where the path
/// doubles back, the offset line gets a point on each side: a U-turn once rounded.
fn rt_offset(pts, d, closed) {
if d == 0.0 { return pts; }
let n = pts.len();
@@ -97,8 +98,12 @@ fn rt_offset(pts, d, closed) {
if type_of(n1) == "()" { n1 = n2; }
if type_of(n2) == "()" { n2 = n1; }
let s = 1.0 + n1[0] * n2[0] + n1[1] * n2[1];
let m = if s < 0.3 { n2 } else { rt_mul(rt_add(n1, n2), 1.0 / s) };
out.push(rt_add(pts[i], rt_mul(m, d)));
if s < 0.3 {
out.push(rt_add(pts[i], rt_mul(n1, d)));
out.push(rt_add(pts[i], rt_mul(n2, d)));
} else {
out.push(rt_add(pts[i], rt_mul(rt_mul(rt_add(n1, n2), 1.0 / s), d)));
}
}
out
}