Files
DOSSIER-STANDALONE/src/ui/lineSegments.test.ts
T
karim 3ad1549f45 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.
2026-07-04 01:21:04 +02:00

112 lines
3.5 KiB
TypeScript

// Modulares Linien-Segment-System: Abbildung Segmentliste ↔ dash-Array,
// Punkt-Erkennung (Round-Cap) und die Schnell-Presets.
import { describe, it, expect } from "vitest";
import {
segmentsToDash,
dashToSegments,
dashHasDot,
presetOfDash,
LINE_PRESETS,
type LineSegment,
} from "./lineSegments";
describe("segmentsToDash", () => {
it("bildet eine alternierende Strich/Lücke-Folge direkt ab", () => {
const segs: LineSegment[] = [
{ type: "dash", length: 2 },
{ type: "gap", length: 1 },
{ type: "dash", length: 3 },
{ type: "gap", length: 2 },
];
expect(segmentsToDash(segs)).toEqual([2, 1, 3, 2]);
});
it("bildet einen Punkt als 0-Länge ab (Strich-Punkt)", () => {
const segs: LineSegment[] = [
{ type: "dash", length: 4 },
{ type: "gap", length: 2 },
{ type: "dot", length: 0 },
{ type: "gap", length: 2 },
];
expect(segmentsToDash(segs)).toEqual([4, 2, 0, 2]);
});
it("fügt eine 0-Lücke zwischen zwei AN-Segmenten ein (Strich·Punkt)", () => {
const segs: LineSegment[] = [
{ type: "dash", length: 3 },
{ type: "dot", length: 0 },
];
// 3 (Strich), 0 (eingefügte Lücke), 0 (Punkt), 0 (Schluss-Lücke, gerade Länge)
expect(segmentsToDash(segs)).toEqual([3, 0, 0, 0]);
});
it("fasst zwei Lücken in Folge zusammen", () => {
const segs: LineSegment[] = [
{ type: "dash", length: 2 },
{ type: "gap", length: 1 },
{ type: "gap", length: 2 },
];
expect(segmentsToDash(segs)).toEqual([2, 3]);
});
it("endet stets auf einer AUS-Länge (gerade Array-Länge)", () => {
expect(segmentsToDash([{ type: "dash", length: 5 }])).toEqual([5, 0]);
});
it("leere Folge ⇒ null (Volllinie)", () => {
expect(segmentsToDash([])).toBeNull();
});
});
describe("dashToSegments", () => {
it("kehrt die Abbildung um (0 ⇒ Punkt)", () => {
expect(dashToSegments([4, 2, 0, 2])).toEqual([
{ type: "dash", length: 4 },
{ type: "gap", length: 2 },
{ type: "dot", length: 0 },
{ type: "gap", length: 2 },
]);
});
it("null ⇒ leere Folge", () => {
expect(dashToSegments(null)).toEqual([]);
});
it("round-trip: dash → segments → dash bleibt stabil", () => {
for (const d of [[2, 1, 3, 2], [4, 2, 0, 2], [0, 2], [3, 2]]) {
expect(segmentsToDash(dashToSegments(d))).toEqual(d);
}
});
});
describe("dashHasDot", () => {
it("erkennt Punkte (0 im dash) für die runde Kappe", () => {
expect(dashHasDot([0, 2])).toBe(true);
expect(dashHasDot([4, 2, 0, 2])).toBe(true);
});
it("keine Punkte ⇒ false (Butt-Kappe bleibt)", () => {
expect(dashHasDot([3, 2])).toBe(false);
expect(dashHasDot(null)).toBe(false);
expect(dashHasDot([])).toBe(false);
});
});
describe("Presets", () => {
it("die vier Grundtypen sind erkennbar", () => {
expect(presetOfDash(LINE_PRESETS.solid)).toBe("solid");
expect(presetOfDash(LINE_PRESETS.dash)).toBe("dash");
expect(presetOfDash(LINE_PRESETS.dot)).toBe("dot");
expect(presetOfDash(LINE_PRESETS.dashDot)).toBe("dashDot");
});
it("Punktlinie/Strich-Punkt enthalten einen Dot, Voll/Strich nicht", () => {
expect(dashHasDot(LINE_PRESETS.dot)).toBe(true);
expect(dashHasDot(LINE_PRESETS.dashDot)).toBe(true);
expect(dashHasDot(LINE_PRESETS.solid)).toBe(false);
expect(dashHasDot(LINE_PRESETS.dash)).toBe(false);
});
it("Abweichungen ⇒ custom", () => {
expect(presetOfDash([1, 2, 3, 4])).toBe("custom");
});
});