From 4c82b14a57452d9e70455baa78cd5188559cdaa7 Mon Sep 17 00:00:00 2001 From: KNSO Date: Sat, 12 Sep 2026 19:24:00 +0200 Subject: [PATCH] docs: Laternen nicht mehr auf die Kreuzung setzen (Ruling 18) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Seit Task 4 sind die Mittellinien an Kreuzungen getrennt. lampPoints startete bei Streckenlänge 0 und setzte damit je einmündendem Ast eine Laterne in denselben Punkt, mitten auf die Fahrbahn. Start jetzt bei halber Teilung, dazu ein Test, der das Stapeln nachweist. Co-Authored-By: Claude Opus 5 --- .../plans/2026-09-12-leonida-vice-slice.md | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/docs/superpowers/plans/2026-09-12-leonida-vice-slice.md b/docs/superpowers/plans/2026-09-12-leonida-vice-slice.md index 6a87b6d..30eec7b 100644 --- a/docs/superpowers/plans/2026-09-12-leonida-vice-slice.md +++ b/docs/superpowers/plans/2026-09-12-leonida-vice-slice.md @@ -2427,12 +2427,22 @@ import { lampPoints, palmTransforms } from "../src/world/props.js"; describe("props", () => { it("setzt Laternen im gewünschten Abstand entlang der Linie", () => { const pts = lampPoints([[[0, 0], [100, 0]]], 35); - expect(pts.length).toBe(3); // 0, 35, 70 Meter - expect(pts[1].x).toBeCloseTo(35); + expect(pts.length).toBe(3); // 17,5 / 52,5 / 87,5 Meter + expect(pts[0].x).toBeCloseTo(17.5); // nicht auf der Kreuzung + expect(pts[1].x).toBeCloseTo(52.5); }); - it("ignoriert zu kurze Linien", () => { - expect(lampPoints([[[0, 0], [10, 0]]], 35)).toHaveLength(1); + it("setzt auf einer kurzen Linie eine Laterne in die Mitte", () => { + const pts = lampPoints([[[0, 0], [10, 0]]], 35); + expect(pts).toHaveLength(1); + expect(pts[0].x).toBeCloseTo(5); + }); + + it("stapelt an einer Kreuzung keine Laternen", () => { + // Zwei gegenüberliegende Äste, wie centerlines() sie seit Task 4 liefert. + const pts = lampPoints([[[0, 0], [60, 0]], [[0, 0], [-60, 0]]], 35); + const keys = new Set(pts.map((p) => `${p.x.toFixed(2)},${p.z.toFixed(2)}`)); + expect(keys.size).toBe(pts.length); }); it("skaliert Palmen reproduzierbar zwischen 10 und 18 Metern", () => { @@ -2473,7 +2483,14 @@ function hashUnit(seed, key) { export function lampPoints(lines, spacing = 35) { const out = []; for (const line of lines) { - let travelled = 0, next = 0; + let total = 0; + for (let i = 0; i < line.length - 1; i++) { + total += Math.hypot(line[i + 1][0] - line[i][0], line[i + 1][1] - line[i][1]); + } + // Erste Laterne bei halber Teilung: die Mittellinien sind an Kreuzungen getrennt, + // ein Start bei 0 setzt je einmündendem Ast eine Laterne in denselben Punkt — + // an einer Kreuzung mit vier Ästen also vier, mitten auf der Fahrbahn. + let travelled = 0, next = Math.min(spacing / 2, total / 2); for (let i = 0; i < line.length - 1; i++) { const [x0, z0] = line[i], [x1, z1] = line[i + 1]; const len = Math.hypot(x1 - x0, z1 - z0);