Random-Schraffur modellraum-verankert + Motiv-Editor fuer Custom-Linien

Random-Verankerung (Bugfix): die Streu-Striche haengen nicht mehr an der
Polygon-Bounding-Box, sondern an einem absoluten Modellraum-Gitter
(hashCell aus absoluten Zell-Indizes + hatch.seed). Beim Vergroessern der
Flaeche bleiben bestehende Striche stehen, am Rand kommen neue dazu, die
Dichte bleibt konstant, Verschieben wandert nicht; 'Neu wuerfeln' (neuer
Seed) verschiebt das ganze Feld. Alle Renderpfade ziehen aus derselben
Funktion. Verankerungs- und Verschiebe-Dichte-Test ergaenzt.

Motiv-Editor: neuer wiederverwendbarer MotifEditor (Punkte setzen/ziehen in
einer Einheitszelle, Live-Loop-Vorschau). LineStyle.kind 'custom' + motif
(points/length), additiv durchgereicht (analog zigzag) und in allen
Renderpfaden gekachelt (motifPoints, Verallgemeinerung von zigzagPoints).
ResourceManager-Umschalter Vollinie/Strich/Zickzack/Motiv, LineSwatch-
Vorschau. Insgesamt 5 neue Tests, 113 gruen.
This commit is contained in:
2026-07-04 01:09:00 +02:00
parent 07475cbe6c
commit f09ba0e49f
15 changed files with 714 additions and 58 deletions
+37 -3
View File
@@ -20,7 +20,7 @@ import type { DraftShape, SnapResult, ToolHandlers, ToolId, ToolMods } from "../
import { useGlPlanRenderer } from "./useGlPlanRenderer";
import { useWasmPlanRenderer } from "./useWasmPlanRenderer";
import { quantizePen } from "../export/sceneToPrintSvg";
import { buildRandomHatchRuns, zigzagPoints, DASH_MM_TO_M } from "./glPlan/glPlanHatch";
import { buildRandomHatchRuns, zigzagPoints, motifPoints, DASH_MM_TO_M } from "./glPlan/glPlanHatch";
const PX_PER_M = 90; // viewBox-Einheiten je Meter (Modell → SVG-Benutzerraum)
const PAD = 60; // Rand in viewBox-Einheiten
@@ -2526,6 +2526,8 @@ interface DrawingRun {
greyed?: boolean;
/** Zickzack-Parameter (Papier-mm); gesetzt ⇒ Lauf als Zickzack-Pfad zeichnen. */
zigzag?: { amplitude: number; wavelength: number };
/** Custom-Motiv (Papier-mm); gesetzt ⇒ Lauf als gekacheltes Motiv zeichnen. */
motif?: { points: Vec2[]; length: number };
}
/** Kleiner Toleranz-Test auf Punktgleichheit (Modell-Meter). */
@@ -2596,6 +2598,21 @@ function buildDrawingRuns(prims: Primitive[]): DrawingRun[] {
});
continue;
}
// Custom-Motiv-Linien ebenfalls einzeln (analog Zickzack).
if (p.motif) {
flush();
runs.push({
pts: [p.a, p.b],
closed: false,
cls: p.cls,
weightMm: p.weightMm,
dash: p.dash,
color: p.color,
greyed: p.greyed,
motif: p.motif,
});
continue;
}
if (curPts && curSrc && sameLineStyle(curSrc, p) && samePt(curPts[curPts.length - 1], p.a)) {
// An den laufenden Zug anhängen.
curPts.push(p.b);
@@ -2638,7 +2655,7 @@ function DrawingRunShape({
.map((mm) => (print ? printStrokeVb(mm, paperScale!) : mmToPx(mm)))
.join(" ")
: undefined;
// Zickzack-Lauf: im MODELL-Raum tessellieren (amplitude/wavelength Papier-mm →
// Zickzack-/Custom-Motiv-Lauf: im MODELL-Raum tessellieren (Papier-mm →
// Modell-Meter via DASH_MM_TO_M), dann toScreen. Sonst die Roh-Stützpunkte.
const modelPts = run.zigzag
? zigzagPoints(
@@ -2647,7 +2664,9 @@ function DrawingRunShape({
run.zigzag.amplitude * DASH_MM_TO_M,
run.zigzag.wavelength * DASH_MM_TO_M,
)
: run.pts;
: run.motif
? motifPoints(run.pts[0], run.pts[run.pts.length - 1], run.motif, DASH_MM_TO_M)
: run.pts;
const pts = modelPts.map(toScreen).map((s) => `${s.x},${s.y}`).join(" ");
const shape = run.closed ? (
<polygon
@@ -2866,6 +2885,21 @@ function renderPrimitive(
/>
);
}
// Custom-Motiv: gekachelt im MODELL-Raum (Papier-mm → Modell-Meter), analog
// Zickzack. ADDITIV — gerade/gestrichelte Linien bleiben unverändert.
if (p.motif) {
const mpts = motifPoints(p.a, p.b, p.motif, DASH_MM_TO_M).map(toScreen);
return (
<polyline
points={mpts.map((s) => `${s.x},${s.y}`).join(" ")}
className={p.cls}
fill="none"
stroke={p.color}
strokeWidth={weight(p.weightMm)}
vectorEffect={vfx}
/>
);
}
// Strichstärke + Strichmuster in mm Papier. Die Farbe kommt weiterhin aus
// der CSS-Klasse (z. B. .door-leaf / .wall-axis).
return (