Files
web-cad/frontend/tests/hatchPatterns.test.ts

109 lines
3.7 KiB
TypeScript

/**
* Task CAD-2 - Echte Hatch-Muster + Boundary-Erkennung.
*
* HATCH_PATTERNS: Standard-CAD-Muster (ANSI31, NET, GRASS etc.)
* als Linien-Segment-Generatoren fuer eine BBox.
* computeBoundary: umschlossene Flaeche aus Kontur-Punkten.
*/
import { describe, it, expect } from 'vitest';
import {
HATCH_PATTERNS,
getHatchPattern,
generateHatchLines,
computeBoundary,
type HatchPatternId,
} from '../src/services/hatchPatternService';
describe('CAD-2: HATCH_PATTERNS Bibliothek', () => {
it('enthaelt die Standard-CAD-Muster', () => {
const ids = HATCH_PATTERNS.map((p) => p.id);
expect(ids).toContain('ANSI31');
expect(ids).toContain('ANSI32');
expect(ids).toContain('ANSI37');
expect(ids).toContain('NET');
expect(ids).toContain('GRASS');
expect(ids).toContain('DOTS');
expect(ids).toContain('SOLID');
expect(ids).toContain('lines'); // Alte bleiben erhalten
expect(ids).toContain('cross');
});
it('jedes Muster hat id, label, description; spacing nur bei Nicht-SOLID', () => {
for (const p of HATCH_PATTERNS) {
expect(p.id.length).toBeGreaterThan(0);
expect(p.label.length).toBeGreaterThan(0);
// SOLID braucht keinen Abstand (Vollfuellung)
if (!p.solid) {
expect(p.defaultSpacing).toBeGreaterThan(0);
}
}
});
it('getHatchPattern liefert undefined fuer unbekannte ID', () => {
expect(getHatchPattern('gibts-nicht')).toBeUndefined();
expect(getHatchPattern('ANSI31')).toBeDefined();
expect(getHatchPattern('ANSI31')!.label).toContain('1');
});
});
describe('CAD-2: generateHatchLines (Muster-Geometrie)', () => {
const bbox = { minX: 0, minY: 0, maxX: 100, maxY: 50 };
const spacing = 10;
it('ANSI31 (45 Grad): erzeugt Diagonal-Linien', () => {
const lines = generateHatchLines('ANSI31', bbox, spacing);
expect(lines.length).toBeGreaterThan(3);
for (const seg of lines) {
const dx = seg.to.x - seg.from.x;
const dy = seg.to.y - seg.from.y;
expect(Math.abs(dy / dx)).toBeCloseTo(1, 1); // 45 Grad
}
});
it('NET: erzeugt horizontale UND vertikale Linien', () => {
const lines = generateHatchLines('NET', bbox, spacing);
const horiz = lines.filter((l) => l.from.y === l.to.y);
const vert = lines.filter((l) => l.from.x === l.to.x);
expect(horiz.length).toBeGreaterThan(0);
expect(vert.length).toBeGreaterThan(0);
});
it('DOTS: erzeugt kleine Kreise (als 4-Punkt-Polygone)', () => {
const lines = generateHatchLines('DOTS', bbox, spacing);
expect(lines.length).toBeGreaterThan(0);
// DOTS sind als polyline-segments repraesentiert
});
it('SOLID: erzeugt EINE grosse Flaeche (fill)', () => {
const lines = generateHatchLines('SOLID', bbox, spacing);
expect(lines).toHaveLength(1);
expect((lines[0] as { fill?: string }).fill).toBeDefined();
});
it('unbekanntes Muster: leeres Array (renderer-sicher)', () => {
expect(generateHatchLines('gibts-nicht', bbox, spacing)).toEqual([]);
});
});
describe('CAD-2: computeBoundary (Boundary-Erkennung)', () => {
it('Rechteck-Kontur: BBox wird korrekt berechnet', () => {
const pts = [{ x: 0, y: 0 }, { x: 100, y: 0 }, { x: 100, y: 50 }, { x: 0, y: 50 }];
const b = computeBoundary(pts);
expect(b).toEqual({ minX: 0, minY: 0, maxX: 100, maxY: 50 });
});
it('Dreieck: BBox umschliesst alle Punkte', () => {
const pts = [{ x: 10, y: 0 }, { x: 90, y: 80 }, { x: 10, y: 80 }];
const b = computeBoundary(pts);
expect(b.minX).toBe(10);
expect(b.maxX).toBe(90);
expect(b.minY).toBe(0);
expect(b.maxY).toBe(80);
});
it('leere/wenige Punkte: null-Boundary', () => {
expect(computeBoundary([])).toBeNull();
expect(computeBoundary([{ x: 0, y: 0 }])).toBeNull();
});
});