Linien: modulares Segment-System (Strich/Punkt/Luecke) + Loop-Vorschau

Der Linien-Editor ist modular: eine Linie ist eine geordnete, loopende Folge
aus Segmenten Strich (Laenge), Punkt (Dot) und Luecke (Laenge) — beliebige
Sequenzen (Volllinie/Strichlinie/Punktlinie/Strich-Punkt als Presets, plus
frei), die Schluss-Luecke ist die letzte Luecke. Datenbasis bleibt
LineStyle.dash (mm, alternierend); ein Punkt ist ein 0-Laengen-AN-Segment.
Enthaelt dash eine 0, wird die Linie mit runder Kappe gezeichnet, damit
Punkte als Dots erscheinen (Live + Print; GL/DXF Folgearbeit). Neue reine
Segment-Logik in ui/lineSegments.ts. LineSwatch zeigt den ersten Loop dunkel
und 2 weitere grau (Loop-Kontext). 14 neue Tests, 127 gruen.
This commit is contained in:
2026-07-04 01:21:04 +02:00
parent f09ba0e49f
commit a302d512d9
10 changed files with 433 additions and 60 deletions
+13
View File
@@ -21,6 +21,7 @@ import { useGlPlanRenderer } from "./useGlPlanRenderer";
import { useWasmPlanRenderer } from "./useWasmPlanRenderer";
import { quantizePen } from "../export/sceneToPrintSvg";
import { buildRandomHatchRuns, zigzagPoints, motifPoints, DASH_MM_TO_M } from "./glPlan/glPlanHatch";
import { dashHasDot } from "../ui/lineSegments";
const PX_PER_M = 90; // viewBox-Einheiten je Meter (Modell → SVG-Benutzerraum)
const PAD = 60; // Rand in viewBox-Einheiten
@@ -2423,6 +2424,8 @@ function HatchPattern({
.map((mm) => (print ? printStrokeVb(mm, paperScale!) : mmToPx(mm)))
.join(" ")
: undefined;
// Punktmuster in den Musterlinien: runde Kappe → Dots (Punkt/Strich-Punkt).
const dashCap = dashHasDot(hatch.dash) ? ("round" as const) : undefined;
if (hatch.kind === "image" && hatch.image) {
// Bild-Schraffur: gekacheltes <image>-Muster. Kachel-Basismaß in viewBox-
@@ -2468,6 +2471,7 @@ function HatchPattern({
stroke={hatch.color}
strokeWidth={sw}
strokeDasharray={dashes}
strokeLinecap={dashCap}
vectorEffect={vfx}
/>
</pattern>
@@ -2493,6 +2497,7 @@ function HatchPattern({
stroke={hatch.color}
strokeWidth={sw}
strokeDasharray={dashes}
strokeLinecap={dashCap}
vectorEffect={vfx}
/>
{hatch.pattern === "crosshatch" && (
@@ -2504,6 +2509,7 @@ function HatchPattern({
stroke={hatch.color}
strokeWidth={sw}
strokeDasharray={dashes}
strokeLinecap={dashCap}
vectorEffect={vfx}
/>
)}
@@ -2668,6 +2674,9 @@ function DrawingRunShape({
? 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(" ");
// Punktmuster (dash enthält eine 0): runde Kappe, damit die 0-Längen-Segmente
// als Dots erscheinen (Punktlinie / Strich-Punkt).
const cap = dashHasDot(run.dash) ? ("round" as const) : undefined;
const shape = run.closed ? (
<polygon
points={pts}
@@ -2676,6 +2685,7 @@ function DrawingRunShape({
stroke={run.color}
strokeWidth={sw}
strokeDasharray={dashStr}
strokeLinecap={cap}
vectorEffect={vfx}
/>
) : (
@@ -2686,6 +2696,7 @@ function DrawingRunShape({
stroke={run.color}
strokeWidth={sw}
strokeDasharray={dashStr}
strokeLinecap={cap}
vectorEffect={vfx}
/>
);
@@ -2912,6 +2923,7 @@ function renderPrimitive(
stroke={p.color}
strokeWidth={weight(p.weightMm)}
strokeDasharray={dashOf(p.dash)}
strokeLinecap={dashHasDot(p.dash) ? "round" : undefined}
vectorEffect={vfx}
/>
);
@@ -2934,6 +2946,7 @@ function renderPrimitive(
className={p.cls}
strokeWidth={weight(p.weightMm)}
strokeDasharray={dashOf(p.dash)}
strokeLinecap={dashHasDot(p.dash) ? "round" : undefined}
vectorEffect={vfx}
/>
);