import { roundTo } from '../units'; import type { Seconds } from '../units'; import { MOVEMENT_LABELS, OEPNV_UEBERFAHRZEIT_STAFFEL, RILSA_DEFAULTS, RILSA_ENGSTELLE, UEBERFAHRZEIT_ANSATZ_LABELS, type RilsaDefaults, } from './constants'; import type { IntergreenResult, TrafficMode, UeberfahrzeitAnsatz } from './types'; import { intergreenKey, massgebendeRaeumbeziehung } from '../plan/signalPlan'; import type { SignalPlan } from '../plan/signalPlan'; import type { Conflict, Project, SignalGroup } from '../model/project'; /** * Richtung, Groessenordnung und Herkunft der beiden waehlbaren Praxisansaetze - * an EINER Stelle, fuer Pruefbericht, Ausdruck, Tabellenausgabe und Bildschirm. * Dazu der Satz zum raeumenden Strom, der aus demselben Grund hier steht. * * WARUM ES DIESE DATEI GIBT: Saetze wie "beim Abbiegen um bis zu 3 s je Uebergang" und * "raeumt mit 5,0 m/s statt mit 7,0 m/s; die Zwischenzeit faellt laenger aus" * standen an fuenf bzw. drei Stellen als fest eingeschriebener Text. Beide * Aussagen gelten aber nur fuer die REGELWERTE der zugehoerigen Kennwerte: * `crossingTime.kfzAbbiegend` ist von 1 bis 10 s einstellbar, * `clearingSpeed.kfzTurning` von 3 bis 10 m/s. Wer sie anfasst, bekam einen * gedruckten Satz, der seiner eigenen Rechnung widersprach - derselbe * Fehlertyp wie Befund C21, nur an der Fehlerrichtung statt am Zahlenwert. * * Die Texte stehen im Fachkern und nicht in jeder Ausgabe einzeln, aus dem * Grund, der schon fuer `wirkungslosigkeit` (settings.ts) und * UEBERFAHRZEIT_ANSATZ_LABELS (constants.ts) galt: Drei Fassungen derselben * Aussage laufen genau dann auseinander, wenn niemand daran denkt. * * KEINE ABHAENGIGKEIT ZUR OBERFLAECHE: Der Fachkern formatiert seine Zahlen * selbst (formatZahl weiter unten), wie intergreen.ts und settings.ts auch. * Ein Fachkern, der `@/ui/format` einbindet, waere die erste Kehrtwendung in * der Schichtung dieses Programms. */ /** Zahl mit Dezimalkomma und hoechstens zwei Nachkommastellen. */ function formatZahl(value: number): string { return roundTo(value, 2).toString().replace('.', ','); } /** * Raeumgeschwindigkeit mit Einheit und EINER Nachkommastelle - dieselbe * Schreibweise wie fmt.metersPerSecond in Ansicht und Ausdruck ("5,0 m/s"). * Eine Geschwindigkeit, die am Bildschirm "5,0 m/s" heisst und im Pruefbericht * "5 m/s", liest sich wie zwei verschiedene Werte. */ function formatGeschwindigkeit(value: number): string { return `${roundTo(value, 1).toFixed(1).replace('.', ',')} m/s`; } /** * Groesste Gelbzeit der Staffel - der Wert, gegen den sich die feste * Ueberfahrzeit im unguenstigsten Fall vergleicht. */ function hoechsteGelbzeit(defaults: RilsaDefaults): Seconds { const werte = defaults.yellowBySpeed.map((stufe) => stufe.yellow); return werte.length > 0 ? Math.max(...werte) : (RILSA_DEFAULTS.yellowBySpeed[2]?.yellow ?? 5); } /** * Um wie viel der Ansatz "feste Ueberfahrzeit" die Ueberfahrzeit gegenueber * dem Regelansatz hoechstens verkuerzt - je Fahrbeziehung. * * Bezugsgroesse ist die GROESSTE Gelbzeit der Staffel: Der Ansatz gilt * unabhaengig von der zulaessigen Hoechstgeschwindigkeit, die Verkuerzung faellt * also dort am groessten aus, wo die Gelbzeit am laengsten ist. Ein negatives * Ergebnis bedeutet, dass die eingetragene feste Ueberfahrzeit laenger ist als * jede Gelbzeit - dann verkuerzt der Ansatz nichts. */ export function ueberfahrzeitVerkuerzung(defaults: RilsaDefaults = RILSA_DEFAULTS): { readonly geradeaus: Seconds; readonly abbiegend: Seconds; } { const gelb = hoechsteGelbzeit(defaults); return { geradeaus: roundTo(gelb - defaults.crossingTime.kfzGeradeaus, 2), abbiegend: roundTo(gelb - defaults.crossingTime.kfzAbbiegend, 2), }; } /** * Fehlerrichtung des Ansatzes "feste Ueberfahrzeit" als vollstaendiger Satz. * * Der ganze Satz und nicht nur die Zahl: Wer nur die Groessenordnung aus den * Vorgaben holte und das Wort "VERKUERZT" im eigenen Text stehen liesse, druckte * bei einer festen Ueberfahrzeit von 6 s weiterhin eine Verkuerzung - obwohl der * Ansatz dann jede Zwischenzeit verlaengert. Die Richtung gehoert zur Zahl. */ export function ueberfahrzeitAnsatzRichtungSatz(defaults: RilsaDefaults = RILSA_DEFAULTS): string { const { geradeaus, abbiegend } = ueberfahrzeitVerkuerzung(defaults); const teile: string[] = []; if (abbiegend > 0) teile.push(`beim Abbiegen um bis zu ${formatZahl(abbiegend)} s`); if (geradeaus > 0) teile.push(`geradeaus um bis zu ${formatZahl(geradeaus)} s`); if (teile.length === 0) { return ( 'Mit den hier angesetzten festen Überfahrzeiten fällt die Überfahrzeit nirgends kürzer aus ' + 'als die Gelbzeit; die Zwischenzeiten werden durch die Wahl nicht verkürzt. Die ' + 'eingetragenen Werte weichen dann allerdings von den Regelwerten der RiLSA 2015 ab und ' + 'sind zu begründen.' ); } return ( `Diese Wahl VERKÜRZT die Zwischenzeiten gegenüber dem Regelansatz ` + `„${UEBERFAHRZEIT_ANSATZ_LABELS.gelbzeit}" – ${teile.join(' und ')} je Übergang.` ); } /** * Wirkung des Merkmals "enger Innenradius" als Satzteil, anzuhaengen an * "... raeumt an dieser Beziehung": "mit 5,0 m/s statt mit 7,0 m/s; die * Zwischenzeit faellt laenger aus". * * Der zweite Zweig ist seit der Kappung in resolveRilsaSettings (Fassung 5.5.0, * Befund B1) der einzige verbleibende Grenzfall: Wer die Raeumgeschwindigkeit * des Abbiegers auf den Wert des Merkmals absenkt, bekommt ein Kaestchen, das * nichts mehr aendert. Das ist zulaessig - aber es dann als Verlaengerung * auszuweisen waere die Behauptung einer Verschaerfung, die es nicht gibt. */ export function engerRadiusRichtungSatzteil(defaults: RilsaDefaults = RILSA_DEFAULTS): string { const mit = defaults.clearingSpeed.kfzTurningEngerRadius; const ohne = defaults.clearingSpeed.kfzTurning; if (mit < ohne) { return ( `mit ${formatGeschwindigkeit(mit)} statt mit ${formatGeschwindigkeit(ohne)}; die ` + 'Zwischenzeit fällt länger aus' ); } return ( `mit ${formatGeschwindigkeit(mit)} – dem Wert, mit dem er auch ohne dieses Merkmal räumt, weil die ` + 'Räumgeschwindigkeit des Abbiegers in den Vorgaben auf denselben Wert gesetzt ist; die ' + 'Zwischenzeit ändert sich dadurch nicht' ); } /** * "3 s geradeaus und 2 s abbiegend" - die festen Ueberfahrzeiten des * Regelwerks, nicht die dieses Plans. */ function regelwerksFesteWerte(): string { return ( `${formatZahl(RILSA_DEFAULTS.crossingTime.kfzGeradeaus)} s geradeaus und ` + `${formatZahl(RILSA_DEFAULTS.crossingTime.kfzAbbiegend)} s abbiegend` ); } /** * Entsprechen die beiden festen Ueberfahrzeiten dieses Plans den Regelwerten * aus constants.ts? * * WARUM IM FACHKERN UND NICHT IN JEDER AUSGABE (Fassung 5.43.0): * Diese eine Antwort traegt vier Saetze - den Zuschreibungssatz hier, den * Feldhinweis der Projektansicht, den Warnbalken daneben und die Meldung * 'zwischenzeiten.ueberfahrzeit-ansatz-fest' des Pruefberichts. Sie stand * zweimal nachgebaut im Baum (projectView.ts, services/export/bewertung.ts als * `festeWerteNachLeitfaden`) und fehlte im Pruefbericht und im Warnbalken ganz: * Dort war die Zuschreibung an das Regelwerk unbedingt, obwohl beide Felder * ueber die Vorgabenverwaltung von 1 bis 10 s einstellbar sind. Die Kopie in * bewertung.ts ist noch nicht abgeloest - dort haengt derselbe Satz in einem * anderen Satzbau daran. * * DER NAME SAGT JETZT "REGELWERT": Bis 5.26.0 hiess dieselbe Frage * `festeWerteNachLeitfaden`, weil die beiden Zahlen nur in behoerdlichen * Leitfaeden belegt waren. Sie stehen in der RiLSA 2015 (Abschnitt 2.5.2, * Faelle 1 und 2); der Leitfaden bleibt eine zweite, uebereinstimmende Quelle. */ export function festeWerteNachRegelwert(defaults: RilsaDefaults = RILSA_DEFAULTS): boolean { return ( defaults.crossingTime.kfzGeradeaus === RILSA_DEFAULTS.crossingTime.kfzGeradeaus && defaults.crossingTime.kfzAbbiegend === RILSA_DEFAULTS.crossingTime.kfzAbbiegend ); } /** * Woher die beiden ANGESETZTEN festen Ueberfahrzeiten stammen und wie der * Regelansatz dieses Programms dagegen ausfaellt - ein Satz fuer Pruefbericht * und Projektansicht. * * ZU VERWENDEN, WO DIE ZAHLEN SCHON DAVOR STEHEN: Der Satz nennt sie nicht * erneut, sondern beurteilt sie ("Die Werte sind ..."). * * "NIE KUERZER" UND NICHT "LAENGER" (Fassung 5.43.0): Bei 50 km/h geradeaus * ergeben beide Ansaetze 3 s. Wahr bei JEDER zulaessigen Gelbzeitstaffel ist * nur "nie kuerzer" - und auch das nur gegen die Regelwerte der RiLSA: * SAFETY_FLOORS.yellowKfz liegt mit 3 s genau auf dem Regelwert geradeaus und * ueber dem abbiegenden, aber unter jeder festen Vorgabe darueber. Deshalb * vergleicht der zweite Zweig ausdruecklich mit den Regelwerten und nicht mit * den eingetragenen Zahlen: Bei 6 s abbiegend rechnet die Gelbzeit kuerzer als * die Vorgabe, und der Richtungssatz (`ueberfahrzeitAnsatzRichtungSatz`) sagt * das daneben. */ export function festeWerteZuschreibungSatz(defaults: RilsaDefaults = RILSA_DEFAULTS): string { if (festeWerteNachRegelwert(defaults)) { return ( 'Die Werte sind die Regelwerte der RiLSA 2015 (Abschnitt 2.5.2, Fälle 1 und 2); der ' + 'Regelansatz dieses Programms – die Kopplung an die Gelbzeit – rechnet nie kürzer als diese.' ); } return ( `Die Werte sind Vorgaben dieses Plans, nicht die ${regelwerksFesteWerte()} der RiLSA 2015 ` + '(Abschnitt 2.5.2, Fälle 1 und 2); der Regelansatz dieses Programms – die Kopplung an die ' + 'Gelbzeit – rechnet nie kürzer als die Regelwerte der RiLSA 2015.' ); } /** Woher die Ueberfahrzeit einer Beziehung stammt - Zusatzangaben des Stroms. */ export interface UeberfahrzeitHerkunftKontext { /** OePNV mit Halt vor dem Knotenpunkt (RiLSA 2015, Fall 4). */ readonly haltVorKnoten?: boolean; /** An der Beziehung ist eine Ueberfahrzeit von Hand eingetragen. */ readonly vorgegeben?: boolean; /** * Der von Hand eingetragene Wert und der in der Rechnung ANGESETZTE - nur * zusammen auswertbar (Fassung 5.9.0). Weichen sie voneinander ab, hat * resolveCrossingTime die Eingabe verworfen und mit dem Regelwert gerechnet; * die Spalte darf sie dann nicht weiter als Herkunft des gezeigten Werts * ausgeben. Fehlt eines von beiden, bleibt es beim bisherigen Verhalten - * kein Aufrufer muss die Angaben nachruesten. */ readonly vorgabewert?: Seconds; readonly angesetzt?: Seconds; } /** * Woher die Ueberfahrzeit DIESER Beziehung stammt - je Verkehrsart. * * KORREKTUR (Fassung 5.5.0): Die Tabellenausgabe druckte neben JEDE * Ueberfahrzeit die Beschriftung des Kfz-Ueberfahrzeit-Ansatzes - auch neben * die 0,00 s eines Fussgaengerstroms und neben die 5 s eines OePNV-Stroms aus * der Vmax-Staffel. Der Ansatz gilt ausschliesslich fuer Kraftfahrzeuge * (intergreen.ts, kfzUeberfahrzeit wird nur aus dem Kfz-Zweig gerufen); bei * allen uebrigen Verkehrsarten war die Angabe schlicht falsch. * * Eine Handeingabe geht vor: Sie ersetzt den Regelwert des Ansatzes, und eine * Spalte, die dann weiter den Rechenansatz nennt, behauptet eine Herleitung, * die nicht stattgefunden hat. Genannt wird - wie beim Merkmal "enger * Innenradius" -, was ERFASST ist. * * KORREKTUR (Fassung 5.9.0): "Eine Handeingabe geht vor" gilt * nicht immer. resolveCrossingTime VERWIRFT jede Kfz-Ueberfahrzeit unter dem * Regelwert des gewaehlten Ansatzes und jede ungueltige Vorgabe und rechnet * mit dem Regelwert weiter. Die Zeile zeigte dann den Regelwert und behauptete * daneben, er sei von Hand eingetragen worden - genau der Widerspruch, den * dieser Docblock ausschliessen will. Entschieden wird jetzt am ANGESETZTEN * Wert: Nur eine uebernommene Eingabe heisst Handeingabe, eine verworfene wird * als verworfen ausgewiesen. * * KORREKTUR (Fassung 5.43.0): DAS VERFAHREN GEHT VOR. An einer * einstreifigen Verkehrsfuehrung rechnet der Fachkern nach RiLSA 2015, * Abschnitt 5.2.2 mit einer festen Ueberfahrzeit von 4 s * (`computeEngstellenIntergreen`); der gewaehlte Kfz-Ansatz erreicht dieses * Verfahren gar nicht. Neben den 4 s stand gleichwohl seine Beschriftung - im * Rechenweg des Zwischenzeitfensters und in der Spalte * "Ueberfahrzeit-Herkunft" der Tabellenausgabe -, also entweder "3/4/5 s nach * zulaessiger Hoechstgeschwindigkeit" oder "3 s geradeaus / 2 s abbiegend". * Keiner der beiden Ansaetze gibt 4 s her. Dieselbe Korrektur haben die drei * Felder darueber am 11.09.2026 bekommen (`bezugswerte` in intergreen.ts), und * das Verfahren steht hier aus demselben Grund als ERSTES Argument: So muss es * jede Aufrufstelle mitgeben, und eine vergessene bricht beim Uebersetzen statt * still in der Ausgabe. * * UND DIE HANDEINGABE GEHT DORT NICHT VOR, sondern gar nicht ein: Das * Engstellenverfahren liest `crossingTimeOverride` nicht. Eine Eingabe von * genau 4 s hiess deshalb "von Hand eingetragen" - eine Herleitung, die nicht * stattgefunden hat -, eine von 6 s "verworfen", als haette eine Pruefung sie * abgelehnt. Gesagt wird jetzt, was zutrifft: Sie geht in dieses Verfahren * nicht ein. */ export function ueberfahrzeitHerkunft( verfahren: IntergreenResult['verfahren'], mode: TrafficMode, ansatz: UeberfahrzeitAnsatz, kontext: UeberfahrzeitHerkunftKontext = {}, ): string { if (verfahren === 'engstelle') { const regel = `Regelwert der Engstelle: tü = ${formatZahl(RILSA_ENGSTELLE.ueberfahrzeit)} s ` + '(RiLSA 2015, Abschnitt 5.2.2)'; if (kontext.vorgegeben !== true || kontext.vorgabewert === undefined) return regel; return ( `${regel} – die an dieser Beziehung eingetragenen ` + `${formatZahl(kontext.vorgabewert)} s gehen in dieses Verfahren nicht ein` ); } const verworfen = kontext.vorgegeben === true && kontext.vorgabewert !== undefined && kontext.angesetzt !== undefined && roundTo(kontext.vorgabewert, 6) !== roundTo(kontext.angesetzt, 6); if (kontext.vorgegeben === true && !verworfen) { return 'an dieser Beziehung von Hand eingetragen'; } const herleitung = ((): string => { switch (mode) { case 'kfz': return UEBERFAHRZEIT_ANSATZ_LABELS[ansatz]; case 'oepnv': return kontext.haltVorKnoten === true ? 'Halt vor dem Knotenpunkt: tü = 0 s (RiLSA 2015, Fall 4)' : // Die Stufen aus der Staffel und nicht aus dem Satz - sie sind zwar // kein Vorgabenfeld, aber dieselbe Regel gilt: eine Zahl steht dort, // wo mit ihr gerechnet wird. `Vmax-Staffel des ÖPNV (${OEPNV_UEBERFAHRZEIT_STAFFEL.map((s) => formatZahl(s.crossing)).join('/')} s ` + 'nach zulässiger Höchstgeschwindigkeit, RiLSA 2015, Fall 3)'; case 'rad': return 'Regelwert des Radverkehrs aus den Vorgaben'; case 'fuss': return 'Regelwert der Fußgänger aus den Vorgaben'; } })(); if (!verworfen) return herleitung; return ( `${herleitung} – die an dieser Beziehung eingetragenen ` + `${formatZahl(kontext.vorgabewert ?? 0)} s sind verworfen` ); } /** Wodurch die Zwischenzeit eines raeumenden Kraftfahrzeugs zustande kam. */ export type KfzRaeumverfahren = IntergreenResult['verfahren'] | 'vorgegeben'; /** * Nach welchen Verfahren die Zwischenzeiten der RAEUMENDEN Kraftfahrzeuge * dieses Plans zustande gekommen sind - die plangrosse Schwester von * `ueberfahrzeitHerkunft` daneben, die dieselbe Frage je Beziehung beantwortet. * * WARUM DIESE FRAGE EINE STELLE BRAUCHT (Fassung 5.43.0): Vier Ausgaben nennen * den gewaehlten Kfz-Ueberfahrzeit-Ansatz, ohne eine einzelne Beziehung vor * sich zu haben - das Deckblatt der Planunterlage, der Absatz unter der * Zwischenzeitenmatrix, die Tafel "Abweichungen von den Regelwerten" und der * Pruefbericht. Alle vier nannten ihn unbedingt. An einer einstreifigen * Verkehrsfuehrung rechnet `buildSignalPlan` aber jeden raeumenden Kfz-Strom * nach dem Verfahren der Engstellensignalisierung, und die Ueberfahrzeit liegt * dort mit RILSA_ENGSTELLE.ueberfahrzeit fest: Der Ansatz geht in keine Zahl * ein, und vier Stellen behaupteten eine Rechnung, die nicht stattgefunden * hat - neben den Zahlen, die der Pruefer nachrechnet. * * GELESEN WIRD DER PLAN, NICHT DIE ANLAGENART: Ob der Ansatz gerechnet hat, * steht im Ergebnis (`calculation.verfahren`). Die Bedingung aus * `buildSignalPlan` hier ein zweites Mal nachzubauen, waere die naechste Stelle, * die beim naechsten Verfahren auseinanderlaeuft. Deshalb traegt die Antwort * auch den Fall, den keine Anlagenart hergibt: Ist jede Kfz-Zwischenzeit von * Hand vorgegeben, hat der Ansatz ebenfalls nicht gerechnet * (`calculation: null`). * * KFZ HEISST HIER: DER RAEUMENDE STROM IST EIN KRAFTFAHRZEUG. Der Ansatz gilt * allein fuer die Ueberfahrzeit des raeumenden Kfz (intergreen.ts, * `kfzUeberfahrzeit`); einfahrende Kraftfahrzeuge beruehrt er nicht. */ export function verfahrenDerKfzRaeumstroeme( project: Project, plan: SignalPlan, ): ReadonlySet { const verfahren = new Set(); for (const conflict of project.conflicts) { const from = project.signalGroups.find((g) => g.id === conflict.fromId); if (from === undefined || from.mode !== 'kfz') continue; const zwischenzeit = plan.intergreens.get(intergreenKey(conflict.fromId, conflict.toId)); if (zwischenzeit === undefined) continue; verfahren.add(zwischenzeit.calculation?.verfahren ?? 'vorgegeben'); } return verfahren; } /** * Vermerk, Begruendung und Zu-tun zu einem Ansatz, der an diesem Plan in keine * Zahl eingeht - in derselben Gestalt wie `Wirkungslosigkeit` (settings.ts), * damit die Ausgaben ihn behandeln wie einen wirkungslosen Kennwert. */ export interface AnsatzOhneWirkung { /** Kurz, zum Anhaengen an die Benennung des Ansatzes. */ readonly vermerk: string; /** Ganzer Satz: was stattdessen gerechnet hat. */ readonly begruendung: string; /** Was zu tun ist - zu begruenden ist nichts. */ readonly zutun: string; } /** * Geht der gewaehlte Kfz-Ueberfahrzeit-Ansatz in keine Zwischenzeit dieses * Plans ein? Dann steht hier, warum - sonst `null`. * * `null` HEISST: ER RECHNET. Die Richtung ist mit Absicht diese, wie bei * `wirkungslosigkeit` in settings.ts: Eine zu viel verlangte Begruendung ist * harmlos, die Behauptung "ohne Wirkung" ueber einen Ansatz, der gerade jede * Zwischenzeit bildet, waere es nicht. Genannt wird der Grund und nicht nur die * Wirkungslosigkeit - "kein Ansatz genannt" liest sich am Papier wie ein * fehlender Kennwert. */ export function ueberfahrzeitAnsatzOhneWirkung( project: Project, plan: SignalPlan, ): AnsatzOhneWirkung | null { const verfahren = verfahrenDerKfzRaeumstroeme(project, plan); if (verfahren.has('knotenpunkt')) return null; if (verfahren.has('engstelle')) { return { vermerk: 'ohne Wirkung an dieser Anlage: gerechnet nach RiLSA 2015, Abschnitt 5.2.2', begruendung: 'Die Zwischenzeiten mit räumenden Kraftfahrzeugen sind nach dem Verfahren der ' + 'Engstellensignalisierung gerechnet (RiLSA 2015, Abschnitt 5.2.2), mit einer festen ' + `Überfahrzeit von tü = ${formatZahl(RILSA_ENGSTELLE.ueberfahrzeit)} s. Der eingestellte ` + 'Rechenansatz der Kfz-Überfahrzeit geht damit in keine Zwischenzeit dieses Plans ein.', zutun: 'Es ist nichts zu begründen. Prüfen Sie, ob die Anlagenart richtig erfasst ist: An einem ' + 'Knotenpunkt geht die Wahl in jede Zwischenzeit eines räumenden Kraftfahrzeugs ein.', }; } if (verfahren.has('vorgegeben')) { return { vermerk: 'ohne Wirkung an dieser Anlage: Kfz-Zwischenzeiten von Hand vorgegeben', begruendung: 'Jede Zwischenzeit mit einem räumenden Kraftfahrzeug ist an diesem Plan von Hand ' + 'vorgegeben und ersetzt die Berechnung; der eingestellte Rechenansatz der ' + 'Kfz-Überfahrzeit geht in keine Zwischenzeit dieses Plans ein. Er wirkt allenfalls in ' + 'der Gegenprobe, mit der jede Vorgabe gegen den Rechenwert gehalten wird.', zutun: 'Es ist nichts zu begründen. Zu begründen sind die vorgegebenen Zwischenzeiten, nicht ' + 'der Ansatz.', }; } return { vermerk: 'ohne Wirkung an dieser Anlage: kein räumendes Kraftfahrzeug erfasst', begruendung: 'Dieser Plan führt keine Konfliktbeziehung, an der ein Kraftfahrzeug räumt; der ' + 'eingestellte Rechenansatz der Kfz-Überfahrzeit geht in keine Zwischenzeit dieses Plans ' + 'ein.', zutun: 'Es ist nichts zu begründen. Erfassen Sie die Konfliktbeziehungen, wenn der Ansatz wirken ' + 'soll.', }; } /** * DER SATZ ZUM MASSGEBENDEN STROM - einmal formuliert. * * Wo `raeumbeziehung` von der Fahrbeziehung der Signalgruppe abweicht, * beurteilen Pruefbericht, Konfliktfenster und Planunterlage die Beziehung am * STROM - und die Signalgruppentabelle daneben fuehrt weiter die Gruppe. Ohne * diesen Satz stand im Bericht "der raeumende Strom "K1" ist kein abbiegender * Kraftfahrzeugstrom" ueber einer Gruppe, die als rechts abbiegend erfasst * ist, und umgekehrt "Der abbiegende Kraftfahrzeugstrom raeumt deshalb ..." * ueber einer Gruppe, die geradeaus fuehrt. * * Er steht hier und nicht dreimal: Das Konfliktfenster (ui/views/ * conflictsView.ts) setzt ihn in seinen Kopf, der Bericht (validation/ * engine.ts) an beide Meldungen zum engen Innenradius. Drei Formulierungen * desselben Sachverhalts waeren drei Gelegenheiten, auseinanderzulaufen - aus * genau diesem Befund ist die Funktion entstanden. * * IN DIESER DATEI UND NICHT MEHR IM PRUEFBERICHT: Er ist ein Satz des Fachkerns wie * `engerRadiusRichtungSatzteil` und `ueberfahrzeitHerkunft` daneben, und keine * Pruefregel. Im Bericht stehend, band er das Konfliktfenster an die * Pruefschicht, obwohl es sie sonst nicht braucht. Wortlaut und Verhalten sind * beim Umzug unveraendert geblieben. * * Leer, wo die Beziehung mit der Fahrbeziehung ihrer Gruppe raeumt: Dann gibt * es nichts zu erklaeren. */ export function raeumbeziehungSatz( from: Pick, conflict: Pick, ): string { const raeumbeziehung = massgebendeRaeumbeziehung(from, conflict); if (raeumbeziehung === from.movement) return ''; return ( `Den Räumweg dieser Beziehung fährt ein Strom der Signalgruppe „${from.name}“ mit der ` + `Fahrbeziehung „${MOVEMENT_LABELS[raeumbeziehung]}“; geräumt wird mit ihr.` ); }