import { describe, expect, it } from 'vitest'; import { LEERER_LAGEPLAN, planungsgrundlage, type Lageplan, type Planlinie, } from '@/domain/geometrie/lageplan'; import { REGELBREITE } from '@/domain/geometrie/vermessung'; /** * Nachweis der Planungsgrundlage. * * Geprueft wird die Frage, die ein Pruefer an die Unterlagen stellt: Worauf * beruhen die Raeum- und Einfahrwege? Die Funktion buendelt die Antwort; sie * rechnet dabei Massstab und Kantenlaenge aus und darf keinen Wert erfinden, * wenn die Grundlage fehlt. */ const GELADEN_AM = '2026-03-04T09:15:00.000Z'; /** Fahrlinie mit zwei Punkten - genug, um ableitbar zu sein. */ function fahrlinie(id: string): Planlinie { return { id, name: id, mode: 'kfz', movement: 'geradeaus', breiteMeter: REGELBREITE.kfz, punkte: [ { x: 10, y: 10 }, { x: 10, y: 90 }, ], haltlinieId: null, startT: 0.5, signalGroupId: null, }; } /** * Luftbild 800 mal 600 Bildpunkte, Massstab 0,5 m je Bildpunkt. * Die Bezugsstrecke ist 100 Bildpunkte lang und misst 50 m. */ function luftbild(herkunft: 'gemessen' | 'georeferenziert'): Lageplan { return { arbeitsbereiche: [], signalgeber: [], bild: { datenUrl: 'data:image/png;base64,AAAA', breite: 800, hoehe: 600, herkunft: 'Luftbild NRW · Land NRW · Kante 400 m', geladenAm: GELADEN_AM, }, kalibrierung: { von: { x: 100, y: 200 }, bis: { x: 200, y: 200 }, laengeMeter: 50, herkunft, }, haltlinien: [], linien: [fahrlinie('l1'), fahrlinie('l2')], }; } describe('Planungsgrundlage', () => { it('meldet einen leeren Lageplan als Unterlage ohne Bild', () => { const grundlage = planungsgrundlage(LEERER_LAGEPLAN); expect(grundlage.hatBild).toBe(false); expect(grundlage.herkunft).toBe(''); expect(grundlage.geladenAm).toBe(''); expect(grundlage.ladedatumBekannt).toBe(false); expect(grundlage.breiteBildpunkte).toBe(0); expect(grundlage.hoeheBildpunkte).toBe(0); expect(grundlage.auswertbar).toBe(false); }); it('gibt ohne Kalibrierung keinen Massstab und keine Kantenlaenge an', () => { // Ein eingelesenes Bild ohne festgelegten Massstab. Eine Kantenlaenge waere // hier frei erfunden - der Ausdruck darf sie nicht behaupten. const ohneMassstab: Lageplan = { ...luftbild('gemessen'), kalibrierung: null }; const grundlage = planungsgrundlage(ohneMassstab); expect(grundlage.hatBild).toBe(true); expect(grundlage.massstabHerkunft).toBeNull(); expect(grundlage.meterJeBildpunkt).toBeNull(); expect(grundlage.bezugslaengeMeter).toBeNull(); expect(grundlage.bezugslaengeBildpunkte).toBeNull(); expect(grundlage.kantenlaengeMeter).toBeNull(); expect(grundlage.auswertbar).toBe(false); }); it('rechnet Massstab und Kantenlaenge am Boden aus der Bezugsstrecke', () => { const grundlage = planungsgrundlage(luftbild('gemessen')); // 50 m auf 100 Bildpunkten sind 0,5 m je Bildpunkt. expect(grundlage.bezugslaengeMeter).toBe(50); expect(grundlage.bezugslaengeBildpunkte).toBeCloseTo(100, 9); expect(grundlage.meterJeBildpunkt).toBeCloseTo(0.5, 9); // 800 Bildpunkte Bildbreite mal 0,5 m sind 400 m Kantenlaenge. expect(grundlage.kantenlaengeMeter).toBeCloseTo(400, 9); expect(grundlage.massstabHerkunft).toBe('gemessen'); }); it('unterscheidet den georeferenzierten Ausschnitt vom nachgemessenen', () => { expect(planungsgrundlage(luftbild('georeferenziert')).massstabHerkunft).toBe('georeferenziert'); expect(planungsgrundlage(luftbild('gemessen')).massstabHerkunft).toBe('gemessen'); }); it('reicht Herkunft, Ladedatum und Bildgroesse unveraendert durch', () => { const grundlage = planungsgrundlage(luftbild('georeferenziert')); expect(grundlage.herkunft).toBe('Luftbild NRW · Land NRW · Kante 400 m'); expect(grundlage.geladenAm).toBe(GELADEN_AM); expect(grundlage.ladedatumBekannt).toBe(true); expect(grundlage.breiteBildpunkte).toBe(800); expect(grundlage.hoeheBildpunkte).toBe(600); }); it('erkennt ein fehlendes Ladedatum, statt den 1.1.1970 auszuweisen', () => { const plan = luftbild('gemessen'); const ohneDatum: Lageplan = { ...plan, bild: { ...plan.bild!, geladenAm: '' } }; const epoche: Lageplan = { ...plan, bild: { ...plan.bild!, geladenAm: '1970-01-01T00:00:00.000Z' }, }; expect(planungsgrundlage(ohneDatum).ladedatumBekannt).toBe(false); expect(planungsgrundlage(epoche).ladedatumBekannt).toBe(false); }); it('zaehlt Haltlinien und Fahrlinien und meldet die Auswertbarkeit', () => { const plan = luftbild('georeferenziert'); const grundlage = planungsgrundlage({ ...plan, haltlinien: [ { id: 'hl1', name: 'Nord', art: 'zufahrt', armId: null, von: { x: 0, y: 0 }, bis: { x: 20, y: 0 }, }, ], }); expect(grundlage.anzahlHaltlinien).toBe(1); expect(grundlage.anzahlFahrlinien).toBe(2); expect(grundlage.auswertbar).toBe(true); }); it('ist ohne gezeichnete Fahrlinien nicht auswertbar, auch mit Massstab', () => { // Massstab allein genuegt nicht: Ohne Fahrlinien ist nichts zu vermessen. const grundlage = planungsgrundlage({ ...luftbild('gemessen'), linien: [] }); expect(grundlage.meterJeBildpunkt).toBeCloseTo(0.5, 9); expect(grundlage.auswertbar).toBe(false); }); });