Files
karim 3d2d4d6321 2D-Plan-Renderer auf WebGL2 (GPU) + akkumulierter Funktionsstand
Neuer GPU-Renderer fuer den Grundriss (src/plan/glPlan/): Earcut-Tessellierung
(konkav-faehig), gehrte Linienzuege (Miter), echte Papier-mm-Strichbreiten im
Massstab (repliziert den SVG-printStrokeVb-Pfad), Hybrid mit scharfem SVG-Text-
Overlay. GPU ist der Standardpfad; der SVG-Renderer bleibt automatischer Fallback,
falls WebGL2/Shader nicht verfuegbar sind. Imperativer Pan (rAF + CSS-transform)
fuer fluessige Interaktion ohne React-Re-Render je Frame.

Enthaelt zudem den bisher nicht committeten Arbeitsstand des Browser-BIM
(Oeffnungen, Treppen, Raeume, Decken, DXF-Export, Materialbibliothek, Kontext-
Import, Tauri-Compute-Boundary-PoC).
2026-07-02 00:12:39 +02:00

109 lines
3.6 KiB
JavaScript

// Verifikation Trim (Quick-Trim „stutzen"). Zwei sich kreuzende Linien zeichnen,
// dann `trim` und auf den Überstand einer Linie klicken → der Überstand ist bis
// zum Schnittpunkt weg (neuer Endpunkt = Schnittpunkt). Liest die gerenderten
// `line.draw2d`-Segmente direkt aus dem SVG (Modellkoord. = SVG/PX_PER_M).
import puppeteer from "puppeteer";
const PX = 90; // PX_PER_M in PlanView
const b = await puppeteer.launch({
headless: "new",
args: ["--no-sandbox", "--use-gl=swiftshader", "--enable-unsafe-swiftshader"],
});
const p = await b.newPage();
await p.setViewport({ width: 1280, height: 820, deviceScaleFactor: 1 });
const errs = [];
p.on("pageerror", (e) => errs.push(e.message));
await p.goto("http://localhost:5187/", { waitUntil: "networkidle0", timeout: 20000 }).catch(() => {});
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
await sleep(800);
const focusCmd = async () => {
const el = await p.$(".cmdline-input");
const bx = await el.boundingBox();
await p.mouse.click(bx.x + bx.width / 2, bx.y + bx.height / 2);
await sleep(60);
};
const typeLine = async (t) => {
await p.type(".cmdline-input", t, { delay: 6 });
await p.keyboard.press("Enter");
await sleep(90);
};
const segs = () =>
p.evaluate((PX) => {
return [...document.querySelectorAll(".plan-svg line.draw2d")].map((l) => ({
x1: +l.getAttribute("x1") / PX,
y1: -l.getAttribute("y1") / PX,
x2: +l.getAttribute("x2") / PX,
y2: -l.getAttribute("y2") / PX,
}));
}, PX);
// Modellpunkt → Client-Pixel über das aktuelle SVG-CTM.
const modelToClient = (mx, my) =>
p.evaluate(
(mx, my, PX) => {
const svg = document.querySelector(".plan-svg");
const ctm = svg.getScreenCTM();
const q = svg.createSVGPoint();
q.x = mx * PX;
q.y = -my * PX;
const s = q.matrixTransform(ctm);
return [s.x, s.y];
},
mx,
my,
PX,
);
// ── Zwei sich kreuzende Linien ───────────────────────────────────────────────
// A: horizontal y=2, x=0..6 (Überstand rechts ab x=4). B: vertikal x=4, y=0..4.
await focusCmd();
await typeLine("line");
await typeLine("0,2");
await typeLine("6,2");
await focusCmd();
await typeLine("line");
await typeLine("4,0");
await typeLine("4,4");
await p.keyboard.press("Escape");
await sleep(120);
const before = await segs();
// ── Trim: auf den Überstand von A (x=5, y=2) klicken ─────────────────────────
await focusCmd();
await typeLine("trim");
// Befehl ist aktiv; jetzt in der Plan-Ansicht auf den Überstand klicken.
// Eingabefeld behält Fokus → der Klick geht trotzdem an PlanView (pick).
const [hx, hy] = await modelToClient(5, 2);
await p.mouse.move(hx, hy);
await sleep(120);
await p.mouse.click(hx, hy);
await sleep(200);
await p.keyboard.press("Escape");
await sleep(120);
const after = await segs();
await p.screenshot({ path: "scripts/probe-trim.png" });
// ── Auswertung: gibt es ein horizontales Segment (y≈2), das bei x≈4 endet und
// NICHT über x=4 hinausragt? Der Überstand x∈(4,6] muss weg sein. ────────────
const horiz = after.filter((s) => Math.abs(s.y1 - 2) < 0.05 && Math.abs(s.y2 - 2) < 0.05);
const maxX = horiz.reduce((m, s) => Math.max(m, s.x1, s.x2), -Infinity);
const trimmedToIntersection = Math.abs(maxX - 4) < 0.05;
console.log(
JSON.stringify(
{
beforeCount: before.length,
afterCount: after.length,
horizSegments: horiz,
maxXofHoriz: maxX,
trimmedToIntersection,
errs,
},
null,
2,
),
);
await b.close();