From 513547608884484c10a27301239b5c8be36cddcc Mon Sep 17 00:00:00 2001 From: Cyd Date: Fri, 7 Aug 2026 11:05:16 -0500 Subject: [PATCH] Track plans read as outlines, not hatching Nearly every track is one model repeated: cn3, a wall bar whose gauge image is two closed 25x5 rectangles. Five metres of wall thickness is finer than the plan can resolve, so each bar was landing as two parallel lines plus two end caps - several hundred times over, which is the hatching that swamped the arenas. Collapse a thin closed quad to the centreline between its short edges: one stroke for one wall. Walls stacked to build height coincide seen from above, so draw each distinct wall once. And drop placements standing alone more than 200 units from any other - fourteen tracks park a single bar at (1200,0,0) well off the course, and that one placement stretched the frame to twelve times the width of the track. The four tracks without it are exactly the four that always framed correctly. A real branch keeps its neighbours and stays: Paingod's second canyon is sixty bars out at x=-400. --- docs/tracks.html | 137 +++++++++++++++++++----------------- tools/pages/build_tracks.py | 8 +-- tools/pages/navmap.py | 57 ++++++++++++++- tools/pages/tracks.tpl | 11 +++ 4 files changed, 143 insertions(+), 70 deletions(-) diff --git a/docs/tracks.html b/docs/tracks.html index d93ce10..a72c7d2 100644 --- a/docs/tracks.html +++ b/docs/tracks.html @@ -208,7 +208,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+

Paingod's Passage

pain

@@ -217,14 +217,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
255
Cameras
18
Start boxes
12
-
Extent
1779 × 7228
-
Relief
240
+
Extent
624 × 7223
+
Relief
162
-

244 of 255 placements carry map art; the rest the map screen does not draw either

+

241 of 255 placements are drawn; the rest carry no map art or stand alone off the course

-
+

Blade's Edge

blade

@@ -233,14 +233,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
216
Cameras
21
Start boxes
7
-
Extent
1335 × 6791
+
Extent
213 × 6786
Relief
334
-

203 of 216 placements carry map art; the rest the map screen does not draw either

+

202 of 216 placements are drawn; the rest carry no map art or stand alone off the course

-
+

Yip's Yahoorama

yip

@@ -249,14 +249,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
127
Cameras
20
Start boxes
17
-
Extent
1540 × 5964
+
Extent
524 × 5961
Relief
432
-

114 of 127 placements carry map art; the rest the map screen does not draw either

+

113 of 127 placements are drawn; the rest carry no map art or stand alone off the course

-
+

Berserker's Bahnzai

otto

@@ -265,14 +265,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
203
Cameras
24
Start boxes
16
-
Extent
1329 × 5878
+
Extent
219 × 5873
Relief
442
-

190 of 203 placements carry map art; the rest the map screen does not draw either

+

189 of 203 placements are drawn; the rest carry no map art or stand alone off the course

-
+

Firestorm's Fury

frstrm

@@ -281,14 +281,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
325
Cameras
20
Start boxes
15
-
Extent
1329 × 5878
+
Extent
219 × 5873
Relief
382
-

312 of 325 placements carry map art; the rest the map screen does not draw either

+

311 of 325 placements are drawn; the rest carry no map art or stand alone off the course

-
+

Wiseguy's Wake

wise

@@ -297,14 +297,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
133
Cameras
16
Start boxes
9
-
Extent
1744 × 5713
-
Relief
386
+
Extent
231 × 5708
+
Relief
90
-

Same footprint and instance count as -- Wiserguy's --

120 of 133 placements carry map art; the rest the map screen does not draw either

+

Same footprint and instance count as -- Wiserguy's --

118 of 133 placements are drawn; the rest carry no map art or stand alone off the course

-
+

Burnt Cookies

burnt

@@ -313,14 +313,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
251
Cameras
17
Start boxes
3
-
Extent
1589 × 5447
-
Relief
469
+
Extent
589 × 5444
+
Relief
467
-

240 of 251 placements carry map art; the rest the map screen does not draw either

+

239 of 251 placements are drawn; the rest carry no map art or stand alone off the course

-
+

Brewer's Bane

brewers

@@ -329,14 +329,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
607
Cameras
20
Start boxes
20
-
Extent
3160 × 4532
-
Relief
299
+
Extent
3158 × 4529
+
Relief
297
-

595 of 607 placements carry map art; the rest the map screen does not draw either

+

594 of 607 placements are drawn; the rest carry no map art or stand alone off the course

-
+

Lyz's Lane

lyzlane

@@ -345,14 +345,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
105
Cameras
12
Start boxes
44
-
Extent
1387 × 4175
+
Extent
251 × 4170
Relief
313
-

94 of 105 placements carry map art; the rest the map screen does not draw either

+

93 of 105 placements are drawn; the rest carry no map art or stand alone off the course

-
+

Freezemoon's Freeway

headoff

@@ -361,14 +361,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
264
Cameras
18
Start boxes
5
-
Extent
1589 × 5047
-
Relief
247
+
Extent
589 × 5044
+
Relief
200
-

251 of 264 placements carry map art; the rest the map screen does not draw either

+

250 of 264 placements are drawn; the rest carry no map art or stand alone off the course

-
+

Freezemoon's Freeway (Football)

headmf

@@ -377,14 +377,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
274
Cameras
18
Start boxes
5
-
Extent
1589 × 5047
-
Relief
247
+
Extent
589 × 5044
+
Relief
200
-

263 of 274 placements carry map art; the rest the map screen does not draw either

+

262 of 274 placements are drawn; the rest carry no map art or stand alone off the course

-
+

-- Tour De Mars --

tourdemars

@@ -393,14 +393,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
607
Cameras
20
Start boxes
20
-
Extent
1387 × 23303
+
Extent
1187 × 23298
Relief
415
-

595 of 607 placements carry map art; the rest the map screen does not draw either

+

594 of 607 placements are drawn; the rest carry no map art or stand alone off the course

-
+

-- Donut --

donut

@@ -409,14 +409,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
325
Cameras
20
Start boxes
15
-
Extent
3289 × 9697
-
Relief
129
+
Extent
3289 × 9694
+
Relief
124
-

314 of 325 placements carry map art; the rest the map screen does not draw either

+

313 of 325 placements are drawn; the rest carry no map art or stand alone off the course

-
+

-- Ares' Armpits --

trough

@@ -425,14 +425,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
633
Cameras
16
Start boxes
9
-
Extent
1387 × 9219
-
Relief
540
+
Extent
322 × 9217
+
Relief
530
-

582 of 633 placements carry map art; the rest the map screen does not draw either

+

580 of 633 placements are drawn; the rest carry no map art or stand alone off the course

-
+

-- Zaxxis --

rpweekend2014

@@ -441,14 +441,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
695
Cameras
40
Start boxes
3
-
Extent
3389 × 5962
+
Extent
3389 × 5959
Relief
266
-

678 of 695 placements carry map art; the rest the map screen does not draw either

+

678 of 695 placements are drawn; the rest carry no map art or stand alone off the course

-
+

-- Wiserguy's --

wiserguys

@@ -457,14 +457,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
133
Cameras
16
Start boxes
9
-
Extent
1744 × 5713
-
Relief
435
+
Extent
231 × 5708
+
Relief
138
-

Same footprint and instance count as Wiseguy's Wake

119 of 133 placements carry map art; the rest the map screen does not draw either

+

Same footprint and instance count as Wiseguy's Wake

117 of 133 placements are drawn; the rest carry no map art or stand alone off the course

-
+

-- Arena (Large) --

demoderb

@@ -473,14 +473,14 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
455
Cameras
17
Start boxes
3
-
Extent
2197 × 1997
+
Extent
2000 × 1995
Relief
0
-

438 of 455 placements carry map art; the rest the map screen does not draw either

+

437 of 455 placements are drawn; the rest carry no map art or stand alone off the course

-
+

-- Arena (Small) --

arena

@@ -489,10 +489,10 @@ h1 em { font-style: normal; color: var(--sys); }
Instances
695
Cameras
17
Start boxes
3
-
Extent
1844 × 1855
+
Extent
1844 × 1850
Relief
55
-

678 of 695 placements carry map art; the rest the map screen does not draw either

+

678 of 695 placements are drawn; the rest carry no map art or stand alone off the course

@@ -505,6 +505,17 @@ h1 em { font-style: normal; color: var(--sys); } rotated and positioned. A placement whose model has no gauge image is skipped here exactly as the map screen skips it, which is why a card can say fewer placements carry map art than the track contains.

+

Two things are drawn plainer than the pod draws them, so the plan reads + as an outline. Nearly every track is one model repeated — cn3, a + wall bar whose gauge image is two closed 25×5 rectangles. Five metres of wall + thickness is finer than the plan can resolve, so each bar is collapsed to the + centreline between its short edges: one stroke for one wall, instead of two parallel + lines and two end caps several hundred times over. Walls stacked to build height land + on each other seen from above, and are drawn once. Placements standing alone more than + 200 units from any other are dropped — fourteen tracks park a single bar at + (1200, 0, 0) far off the course, and one stray placement stretches the frame + to twelve times the width of the track. A real branch keeps its neighbours and stays: + Paingod's second canyon is sixty bars out at x = -400.

So the walls are the canyon walls and the chambers are real chambers, but there is still no driving surface: the map draws what lines the route, never the tarmac. Extent and relief are the span of the drawn outlines in world units, so a diff --git a/tools/pages/build_tracks.py b/tools/pages/build_tracks.py index 197fe8c..1b0e8af 100644 --- a/tools/pages/build_tracks.py +++ b/tools/pages/build_tracks.py @@ -86,7 +86,7 @@ def era(key): GAUGE_IDS = {rid for rid, r in TABLE.items() if r['desc'].endswith(': GaugeImage')} -def plan_view(segs, box=900): +def plan_view(segs, box=520): """The track's own outlines, straight down, as an alpha mask.""" pts = [p for seg in segs for p in seg] xs = [p[0] for p in pts] @@ -171,9 +171,9 @@ for key in ORDER: kin = [k for k in twins.get(sig, []) if k != key] twin = ('

Same footprint and instance count as ' + ', '.join(tracks[k]['name'] for k in kin) + '

') if kin else '' - short = ('

%d of %d placements carry map art; the rest the ' - 'map screen does not draw either

' % (t['drawn'], t['instances']) - ) if t['skipped'] else '' + short = ('

%d of %d placements are drawn; the rest carry no ' + 'map art or stand alone off the course

' + % (t['drawn'], t['instances'])) if t['skipped'] else '' art = ('' % (html.escape(t['name']), t['art'], t['aw'], t['ah'])) if t['art'] else '' diff --git a/tools/pages/navmap.py b/tools/pages/navmap.py index f36124a..2fa3d7f 100644 --- a/tools/pages/navmap.py +++ b/tools/pages/navmap.py @@ -100,6 +100,29 @@ def instances(res, addr, size, count, gauge_ids): return out +def spine(seg): + """A track is built almost entirely from one model, cn3: a wall bar + drawn as two closed 25x5 rectangles. Five metres of wall thickness is + below the map's own resolution, so drawing the rectangle puts two + parallel lines and two end caps where the wall is one line - and a few + hundred bars of that is the hatching that swamps the plan. Collapse a + thin closed quad to the centreline joining its two short edges: the + same wall, drawn as the single stroke it reads as.""" + p = seg[:-1] if len(seg) >= 5 and seg[0] == seg[-1] else None + if not p or len(p) != 4: + return [seg] + import math + edge = [math.hypot(p[(i + 1) % 4][0] - p[i][0], + p[(i + 1) % 4][2] - p[i][2]) for i in range(4)] + if max(edge) == 0 or min(edge) / max(edge) > 0.5: + return [seg] # not a bar - leave it alone + lo = min(range(4), key=lambda i: edge[i]) + a, b = p[lo], p[(lo + 1) % 4] + c, d = p[(lo + 2) % 4], p[(lo + 3) % 4] + mid = lambda u, v: tuple((u[k] + v[k]) / 2 for k in range(3)) + return [[mid(a, b), mid(c, d)]] + + def rotate(q, p): """Quaternion (x,y,z,w) applied to a point.""" qx, qy, qz, qw = q @@ -120,10 +143,29 @@ def track_lines(res, table, map_addr, map_size, map_count): gauge[rid] = r segs = [] drawn = skipped = 0 - for gid, pos, q in instances(res, map_addr, map_size, map_count, set(gauge)): + placed = instances(res, map_addr, map_size, map_count, set(gauge)) + + # Fourteen of the eighteen tracks carry a single bar parked at exactly + # (1200, 0, 0), well off the course; the four that don't are the four + # that always framed correctly. One stray placement drags the bounding + # box out to twelve times the width of the course and squeezes the + # track into a sliver, so drop placements that stand alone. A real + # branch - Paingod's second canyon is sixty bars out at x=-400 - has + # neighbours and stays. + def isolated(i): + x, _, z = placed[i][1] + for j, (g, p, _) in enumerate(placed): + if j != i and g is not None and (p[0] - x) ** 2 + (p[2] - z) ** 2 < 200 ** 2: + return False + return True + + for i, (gid, pos, q) in enumerate(placed): if gid is None: skipped += 1 continue + if isolated(i): + skipped += 1 + continue r = gauge[gid] img = read_gauge_image(res, r['addr'], r['size']) if img is None: @@ -138,5 +180,14 @@ def track_lines(res, table, map_addr, map_size, map_count): wx, wy, wz = rotate(q, verts[k]) pts.append((wx + pos[0], wy + pos[1], wz + pos[2])) if len(pts) > 1: - segs.append(pts) - return segs, drawn, skipped + segs.extend(spine(pts)) + + # Walls are stacked to build height. Seen from above those copies land + # on each other exactly, so draw each distinct wall once. + seen, out = set(), [] + for s in segs: + key = tuple(round(v, 1) for p in s for v in (p[0], p[2])) + if key not in seen: + seen.add(key) + out.append(s) + return out, drawn, skipped diff --git a/tools/pages/tracks.tpl b/tools/pages/tracks.tpl index 438fbb8..1498ccf 100644 --- a/tools/pages/tracks.tpl +++ b/tools/pages/tracks.tpl @@ -50,6 +50,17 @@ rotated and positioned. A placement whose model has no gauge image is skipped here exactly as the map screen skips it, which is why a card can say fewer placements carry map art than the track contains.

+

Two things are drawn plainer than the pod draws them, so the plan reads + as an outline. Nearly every track is one model repeated — cn3, a + wall bar whose gauge image is two closed 25×5 rectangles. Five metres of wall + thickness is finer than the plan can resolve, so each bar is collapsed to the + centreline between its short edges: one stroke for one wall, instead of two parallel + lines and two end caps several hundred times over. Walls stacked to build height land + on each other seen from above, and are drawn once. Placements standing alone more than + 200 units from any other are dropped — fourteen tracks park a single bar at + (1200, 0, 0) far off the course, and one stray placement stretches the frame + to twelve times the width of the track. A real branch keeps its neighbours and stays: + Paingod's second canyon is sixty bars out at x = -400.

So the walls are the canyon walls and the chambers are real chambers, but there is still no driving surface: the map draws what lines the route, never the tarmac. Extent and relief are the span of the drawn outlines in world units, so a