diff --git a/src/app/app.module.ts b/src/app/app.module.ts index aae6d957c..7636519f0 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -43,6 +43,7 @@ import {EditorSideViewComponent} from "./view/editor-side-view/editor-side-view. import {StammdatenDialogComponent} from "./view/dialogs/stammdaten-dialog/stammdaten-dialog.component"; import {TrainrunAndSectionDialogComponent} from "./view/dialogs/trainrun-and-section-dialog/trainrun-and-section-dialog.component"; import {ConfirmationDialogComponent} from "./view/dialogs/confirmation-dialog/confirmation-dialog.component"; +import {SymmetrySelectionDialogComponent} from "./view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component"; import {FilterMainSideViewComponent} from "./view/filter-main-side-view/filter-main-side-view.component"; import {KnotenAuslastungViewComponent} from "./view/knoten-auslastung-view/knoten-auslastung-view.component"; import {environment} from "../environments/environment"; @@ -126,6 +127,7 @@ import {ToggleSwitchButtonComponent} from "./view/toggle-switch-button/toggle-sw EditorSideViewComponent, TrainrunAndSectionDialogComponent, ConfirmationDialogComponent, + SymmetrySelectionDialogComponent, FilterMainSideViewComponent, KnotenAuslastungViewComponent, ProjectsViewComponent, diff --git a/src/app/data-structures/business.data.structures.ts b/src/app/data-structures/business.data.structures.ts index 665a51f38..389a318c7 100644 --- a/src/app/data-structures/business.data.structures.ts +++ b/src/app/data-structures/business.data.structures.ts @@ -117,11 +117,14 @@ export interface TrainrunSectionDto { targetNodeId: number; // reference to the node by Node.id targetPortId: number; // reference to the node by Node.id + sourceSymmetry: boolean; // binds sourceDeparture and sourceArrival times + targetSymmetry: boolean; // binds targetDeparture and targetArrival times sourceArrival: TimeLockDto; // declares the soruce arrival time sourceDeparture: TimeLockDto; // declares the soruce departure time targetArrival: TimeLockDto; // declares the target arrival time targetDeparture: TimeLockDto; // declares the target departure time - travelTime: TimeLockDto; // declares the travel arrival time + travelTime: TimeLockDto; // declares the travel time (forward direction) + backwardTravelTime: TimeLockDto; // declares the travel time in the opposite direction numberOfStops: number; // number of stops - not declared in detail (no node attached) @@ -290,8 +293,10 @@ export interface FilterSettingDto { filterNoteLabels: number[]; // labels to filter out (labels only of type - LabelRef: note) filterTrainrunLabels: number[]; // labels to filter out (labels only of type - LabelRef: trainrun) filterDirectionArrows: boolean; // flag for trainrun direction arrows (hide/show) + filterAsymmetryArrows: boolean; // flag for trainrun section asymmetry arrows (hide/show) filterArrivalDepartureTime: boolean; // flag for arrival and departure time filtering (hide/show) filterTravelTime: boolean; // flag for travel time filter (hide/show) + filterBackwardTravelTime: boolean; // flag for trainrun section backward travel times (hide/show) filterTrainrunName: boolean; // flag for trainrun time filter (hide/show) filterConnections: boolean; // flag for connections filtering (hide/show) filterShowNonStopTime: boolean; // flag for non-stop time filtering (hide/show) @@ -299,6 +304,7 @@ export interface FilterSettingDto { filterTrainrunFrequency: TrainrunFrequency[]; // list of frequency to filter out filterTrainrunTimeCategory: TrainrunTimeCategory[]; // list of time categroy to filter out filterDirection: Direction[]; // list of trainrun direction to filter out + filterSymmetry: boolean[]; // list of trainrun symmetry values (true/false) to filter out filterAllEmptyNodes: boolean; // flag to filter all empty nodes (hide/show) filterAllNonStopNodes: boolean; // flag to filter all only non-stop nodes (hide/show) filterNotes: boolean; // flag to filter notes (hide/show) diff --git a/src/app/data-structures/technical.data.structures.ts b/src/app/data-structures/technical.data.structures.ts index 51abe079a..07f9e4f99 100644 --- a/src/app/data-structures/technical.data.structures.ts +++ b/src/app/data-structures/technical.data.structures.ts @@ -23,6 +23,7 @@ export enum TrainrunSectionText { TargetDeparture, TrainrunSectionName, TrainrunSectionTravelTime, + TrainrunSectionBackwardTravelTime, TrainrunSectionNumberOfStops, } @@ -38,6 +39,7 @@ export interface TrainrunSectionTextPositions { [TrainrunSectionText.TargetDeparture]: PointDto; [TrainrunSectionText.TrainrunSectionName]: PointDto; [TrainrunSectionText.TrainrunSectionTravelTime]: PointDto; + [TrainrunSectionText.TrainrunSectionBackwardTravelTime]: PointDto; [TrainrunSectionText.TrainrunSectionNumberOfStops]: PointDto; } diff --git a/src/app/models/filterSettings.model.ts b/src/app/models/filterSettings.model.ts index 0bfc149f4..d5741866b 100644 --- a/src/app/models/filterSettings.model.ts +++ b/src/app/models/filterSettings.model.ts @@ -19,9 +19,11 @@ export class FilterSetting { public filterNodeLabels: number[]; public filterNoteLabels: number[]; public filterTrainrunLabels: number[]; - public filterDirectionArrows; + public filterDirectionArrows: boolean; + public filterAsymmetryArrows: boolean; public filterArrivalDepartureTime; public filterTravelTime; + public filterBackwardTravelTime: boolean; public filterTrainrunName; public filterConnections; public filterShowNonStopTime; @@ -29,6 +31,7 @@ export class FilterSetting { public filterTrainrunFrequency: TrainrunFrequency[]; public filterTrainrunTimeCategory: TrainrunTimeCategory[]; public filterDirection: Direction[]; + public filterSymmetry: boolean[]; public filterAllEmptyNodes; public filterAllNonStopNodes; public filterNotes; @@ -44,9 +47,11 @@ export class FilterSetting { filterNodeLabels, filterNoteLabels, filterTrainrunLabels, - filterDirectionArrows: filterDirectionArrows, + filterDirectionArrows, + filterAsymmetryArrows, filterArrivalDepartureTime, filterTravelTime, + filterBackwardTravelTime, filterTrainrunName, filterConnections, filterShowNonStopTime, @@ -54,6 +59,7 @@ export class FilterSetting { filterTrainrunFrequency, filterTrainrunTimeCategory, filterDirection: filterDirection, + filterSymmetry: filterSymmetry, filterAllEmptyNodes, filterAllNonStopNodes, filterNotes, @@ -68,8 +74,10 @@ export class FilterSetting { filterNoteLabels: [], filterTrainrunLabels: [], filterDirectionArrows: true, + filterAsymmetryArrows: true, filterArrivalDepartureTime: true, filterTravelTime: true, + filterBackwardTravelTime: true, filterTrainrunName: true, filterConnections: true, filterShowNonStopTime: true, @@ -77,6 +85,7 @@ export class FilterSetting { filterTrainrunFrequency: null, filterTrainrunTimeCategory: null, filterDirection: null, + filterSymmetry: null, filterAllEmptyNodes: false, filterAllNonStopNodes: false, filterNotes: false, @@ -92,8 +101,10 @@ export class FilterSetting { this.filterNoteLabels = filterNoteLabels; this.filterTrainrunLabels = filterTrainrunLabels; this.filterDirectionArrows = filterDirectionArrows; + this.filterAsymmetryArrows = filterAsymmetryArrows; this.filterArrivalDepartureTime = filterArrivalDepartureTime; this.filterTravelTime = filterTravelTime; + this.filterBackwardTravelTime = filterBackwardTravelTime; this.filterTrainrunName = filterTrainrunName; this.filterConnections = filterConnections; this.filterShowNonStopTime = filterShowNonStopTime; @@ -101,6 +112,7 @@ export class FilterSetting { this.filterTrainrunFrequency = filterTrainrunFrequency; this.filterTrainrunTimeCategory = filterTrainrunTimeCategory; this.filterDirection = filterDirection; + this.filterSymmetry = filterSymmetry; this.filterAllEmptyNodes = filterAllEmptyNodes; this.filterAllNonStopNodes = filterAllNonStopNodes; this.filterNotes = filterNotes; @@ -165,8 +177,10 @@ export class FilterSetting { this.filterNoteLabels.length === 0 && this.filterTrainrunLabels.length === 0 && this.filterDirectionArrows === true && + this.filterAsymmetryArrows === true && this.filterArrivalDepartureTime === true && this.filterTravelTime === true && + this.filterBackwardTravelTime === true && this.filterTrainrunName === true && this.filterConnections === true && this.filterShowNonStopTime === true && @@ -174,6 +188,7 @@ export class FilterSetting { this.filterTrainrunFrequency.length === frainrunFrequenciesLength && this.filterTrainrunTimeCategory.length === trainrunTimeCategoryLength && this.filterDirection.length === Object.values(Direction).length && + this.filterSymmetry.length === 2 && this.filterAllEmptyNodes === false && this.filterAllNonStopNodes === false && this.filterNotes === false && @@ -192,8 +207,10 @@ export class FilterSetting { filterNoteLabels: this.filterNoteLabels, filterTrainrunLabels: this.filterTrainrunLabels, filterDirectionArrows: this.filterDirectionArrows, + filterAsymmetryArrows: this.filterAsymmetryArrows, filterArrivalDepartureTime: this.filterArrivalDepartureTime, filterTravelTime: this.filterTravelTime, + filterBackwardTravelTime: this.filterBackwardTravelTime, filterTrainrunName: this.filterTrainrunName, filterConnections: this.filterConnections, filterShowNonStopTime: this.filterShowNonStopTime, @@ -201,6 +218,7 @@ export class FilterSetting { filterTrainrunFrequency: this.filterTrainrunFrequency, filterTrainrunTimeCategory: this.filterTrainrunTimeCategory, filterDirection: this.filterDirection, + filterSymmetry: this.filterSymmetry, filterAllEmptyNodes: this.filterAllEmptyNodes, filterAllNonStopNodes: this.filterAllNonStopNodes, filterNotes: this.filterNotes, diff --git a/src/app/models/trainrun.model.ts b/src/app/models/trainrun.model.ts index 30d26edfd..3ce427946 100644 --- a/src/app/models/trainrun.model.ts +++ b/src/app/models/trainrun.model.ts @@ -34,7 +34,7 @@ export class Trainrun { frequencyId, trainrunTimeCategoryId, labelIds, - direction = Direction.ROUND_TRIP, // temporary, to allow migration of old trainruns + direction = Direction.ROUND_TRIP, // temporary, to allow migration of old trainruns from file }: TrainrunDto = { id: Trainrun.incrementId(), name: Trainrun.DEFAULT_TRAINRUN_NAME, diff --git a/src/app/models/trainrunsection.model.spec.ts b/src/app/models/trainrunsection.model.spec.ts index a9ba3e858..ab703c8fa 100644 --- a/src/app/models/trainrunsection.model.spec.ts +++ b/src/app/models/trainrunsection.model.spec.ts @@ -159,11 +159,13 @@ describe("TrainrunSection Model Test", () => { ts.setSourceDepartureLock(false); ts.setSourceArrivalLock(false); ts.setTravelTimeLock(false); + ts.setBackwardTravelTimeLock(false); expect(ts.getTargetDepartureLock()).toBe(false); expect(ts.getTargetArrivalLock()).toBe(false); expect(ts.getSourceDepartureLock()).toBe(false); expect(ts.getSourceArrivalLock()).toBe(false); expect(ts.getTravelTimeLock()).toBe(false); + expect(ts.getBackwardTravelTimeLock()).toBe(false); }); it("set...lock - 1", () => { @@ -174,11 +176,13 @@ describe("TrainrunSection Model Test", () => { ts.setSourceArrivalLock(false); ts.setTravelTimeLock(false); ts.setTargetDepartureLock(true); + ts.setBackwardTravelTimeLock(false); expect(ts.getTargetDepartureLock()).toBe(true); expect(ts.getTargetArrivalLock()).toBe(false); expect(ts.getSourceDepartureLock()).toBe(false); expect(ts.getSourceArrivalLock()).toBe(false); expect(ts.getTravelTimeLock()).toBe(false); + expect(ts.getBackwardTravelTimeLock()).toBe(false); }); it("set...lock - 2", () => { @@ -189,11 +193,13 @@ describe("TrainrunSection Model Test", () => { ts.setSourceArrivalLock(false); ts.setTravelTimeLock(false); ts.setTargetArrivalLock(true); + ts.setBackwardTravelTimeLock(false); expect(ts.getTargetDepartureLock()).toBe(false); expect(ts.getTargetArrivalLock()).toBe(true); expect(ts.getSourceDepartureLock()).toBe(false); expect(ts.getSourceArrivalLock()).toBe(false); expect(ts.getTravelTimeLock()).toBe(false); + expect(ts.getBackwardTravelTimeLock()).toBe(false); }); it("set...lock - 3", () => { @@ -203,12 +209,14 @@ describe("TrainrunSection Model Test", () => { ts.setSourceDepartureLock(false); ts.setSourceArrivalLock(false); ts.setTravelTimeLock(false); + ts.setBackwardTravelTimeLock(false); ts.setSourceDepartureLock(true); expect(ts.getTargetDepartureLock()).toBe(false); expect(ts.getTargetArrivalLock()).toBe(false); expect(ts.getSourceDepartureLock()).toBe(true); expect(ts.getSourceArrivalLock()).toBe(false); expect(ts.getTravelTimeLock()).toBe(false); + expect(ts.getBackwardTravelTimeLock()).toBe(false); }); it("set...lock - 4", () => { @@ -219,11 +227,13 @@ describe("TrainrunSection Model Test", () => { ts.setSourceArrivalLock(false); ts.setTravelTimeLock(false); ts.setSourceArrivalLock(true); + ts.setBackwardTravelTimeLock(false); expect(ts.getTargetDepartureLock()).toBe(false); expect(ts.getTargetArrivalLock()).toBe(false); expect(ts.getSourceDepartureLock()).toBe(false); expect(ts.getSourceArrivalLock()).toBe(true); expect(ts.getTravelTimeLock()).toBe(false); + expect(ts.getBackwardTravelTimeLock()).toBe(false); }); it("set...lock - 5", () => { @@ -233,12 +243,15 @@ describe("TrainrunSection Model Test", () => { ts.setSourceDepartureLock(false); ts.setSourceArrivalLock(false); ts.setTravelTimeLock(false); + ts.setBackwardTravelTimeLock(false); ts.setTravelTimeLock(true); + ts.setBackwardTravelTimeLock(true); expect(ts.getTargetDepartureLock()).toBe(false); expect(ts.getTargetArrivalLock()).toBe(false); expect(ts.getSourceDepartureLock()).toBe(false); expect(ts.getSourceArrivalLock()).toBe(false); expect(ts.getTravelTimeLock()).toBe(true); + expect(ts.getBackwardTravelTimeLock()).toBe(true); }); it("select", () => { diff --git a/src/app/models/trainrunsection.model.ts b/src/app/models/trainrunsection.model.ts index 0410b232f..f609e8387 100644 --- a/src/app/models/trainrunsection.model.ts +++ b/src/app/models/trainrunsection.model.ts @@ -12,6 +12,7 @@ import { } from "../data-structures/technical.data.structures"; import {TrainrunSectionValidator} from "../services/util/trainrunsection.validator"; import {formatDate} from "@angular/common"; +import {TrainrunsectionHelper} from "../services/util/trainrunsection.helper"; export class TrainrunSection { private static currentId = 0; @@ -23,11 +24,15 @@ export class TrainrunSection { private targetNodeId: number; private targetPortId: number; + private sourceSymmetry: boolean; + private targetSymmetry: boolean; private sourceArrival: TimeLockDto; private sourceDeparture: TimeLockDto; private targetArrival: TimeLockDto; private targetDeparture: TimeLockDto; private travelTime: TimeLockDto; + private backwardTravelTime: TimeLockDto; + private numberOfStops: number; private trainrunId: number; @@ -49,11 +54,14 @@ export class TrainrunSection { sourcePortId, targetNodeId, targetPortId, + sourceSymmetry = true, // temporary, to allow migration of old trainrunSections from file + targetSymmetry = true, // temporary, to allow migration of old trainrunSections from file sourceDeparture, sourceArrival, targetDeparture, targetArrival, travelTime, + backwardTravelTime = travelTime, // temporary, to allow migration of old trainrunSections from file numberOfStops, trainrunId, resourceId, @@ -66,6 +74,8 @@ export class TrainrunSection { sourcePortId: 0, targetNodeId: 0, targetPortId: 0, + sourceSymmetry: true, + targetSymmetry: true, sourceDeparture: { time: 0, consecutiveTime: 0, @@ -101,6 +111,13 @@ export class TrainrunSection { warning: null, timeFormatter: null, }, + backwardTravelTime: { + time: 1, + consecutiveTime: 1, + lock: true, + warning: null, + timeFormatter: null, + }, trainrunId: 0, resourceId: 0, specificTrainrunSectionFrequencyId: null, @@ -114,6 +131,7 @@ export class TrainrunSection { [TrainrunSectionText.TargetDeparture]: {x: 0, y: 0}, [TrainrunSectionText.TrainrunSectionName]: {x: 0, y: 0}, [TrainrunSectionText.TrainrunSectionTravelTime]: {x: 0, y: 0}, + [TrainrunSectionText.TrainrunSectionBackwardTravelTime]: {x: 0, y: 0}, [TrainrunSectionText.TrainrunSectionNumberOfStops]: {x: 0, y: 0}, }, }, @@ -125,11 +143,14 @@ export class TrainrunSection { this.sourcePortId = sourcePortId; this.targetNodeId = targetNodeId; this.targetPortId = targetPortId; + this.sourceSymmetry = sourceSymmetry; + this.targetSymmetry = targetSymmetry; this.sourceDeparture = sourceDeparture; this.sourceArrival = sourceArrival; this.targetDeparture = targetDeparture; this.targetArrival = targetArrival; this.travelTime = travelTime; + this.backwardTravelTime = backwardTravelTime; this.trainrunId = trainrunId; this.resourceId = resourceId; this.specificTrainrunSectionFrequencyId = specificTrainrunSectionFrequencyId; @@ -237,6 +258,19 @@ export class TrainrunSection { this.trainrunId = trainrun.getId(); } + setSourceSymmetry(sourceSymmetry: boolean) { + this.sourceSymmetry = sourceSymmetry; + } + + setTargetSymmetry(targetSymmetry: boolean) { + this.targetSymmetry = targetSymmetry; + } + + resetSymmetry() { + this.sourceSymmetry = true; + this.targetSymmetry = true; + } + setSourceArrivalDto(sourceArrivalDto: TimeLockDto) { this.sourceArrival = sourceArrivalDto; } @@ -257,6 +291,41 @@ export class TrainrunSection { this.travelTime = travelTimeDto; } + setBackwardTravelTimeDto(backwardTravelTimeDto: TimeLockDto) { + this.backwardTravelTime = backwardTravelTimeDto; + } + + getSourceSymmetry(): boolean { + return this.sourceSymmetry; + } + + getTargetSymmetry(): boolean { + return this.targetSymmetry; + } + + isSymmetric(): boolean { + return this.sourceSymmetry && this.targetSymmetry; + } + + isSourceSymmetricOrTimesSymmetric(): boolean { + return ( + this.sourceSymmetry || + TrainrunsectionHelper.getSymmetricTime(this.sourceDeparture.time) === this.sourceArrival.time + ); + } + + isTargetSymmetricOrTimesSymmetric(): boolean { + return ( + this.targetSymmetry || + TrainrunsectionHelper.getSymmetricTime(this.targetDeparture.time) === this.targetArrival.time + ); + } + + areTravelTimesEqual(): boolean { + // indirectly checks this.isSymmetric() as well, because if not symmetric, travel times must be different + return this.travelTime.time === this.backwardTravelTime.time; + } + getSourceArrivalDto(): TimeLockDto { return this.sourceArrival; } @@ -277,6 +346,10 @@ export class TrainrunSection { return this.travelTime; } + getBackwardTravelTimeDto(): TimeLockDto { + return this.backwardTravelTime; + } + getId(): number { return this.id; } @@ -285,6 +358,10 @@ export class TrainrunSection { return this.travelTime.time; } + getBackwardTravelTime(): number { + return this.backwardTravelTime.time; + } + getSourceDeparture(): number { return this.sourceDeparture.time; } @@ -305,6 +382,10 @@ export class TrainrunSection { return TrainrunSection.formatDisplayText(this.travelTime, offset); } + getBackwardTravelTimeFormattedDisplayText(offset = 0): string { + return TrainrunSection.formatDisplayText(this.backwardTravelTime, offset); + } + getSourceDepartureFormattedDisplayText(offset = 0): string { return TrainrunSection.formatDisplayText(this.sourceDeparture, offset); } @@ -325,6 +406,10 @@ export class TrainrunSection { return TrainrunSection.getDisplayTextWidth(this.travelTime); } + getBackwardTravelTimeFormattedDisplayTextWidth(): number { + return TrainrunSection.getDisplayTextWidth(this.backwardTravelTime); + } + getSourceDepartureFormattedDisplayTextWidth(): number { return TrainrunSection.getDisplayTextWidth(this.sourceDeparture); } @@ -345,6 +430,10 @@ export class TrainrunSection { return TrainrunSection.getDisplayHtmlStyle(this.travelTime); } + getBackwardTravelTimeFormattedDisplayHtmlStyle(): string { + return TrainrunSection.getDisplayHtmlStyle(this.backwardTravelTime); + } + getSourceDepartureFormattedDisplayHtmlStyle(): string { return TrainrunSection.getDisplayHtmlStyle(this.sourceDeparture); } @@ -365,6 +454,10 @@ export class TrainrunSection { return TrainrunSection.getDisplayColorRef(this.travelTime); } + getBackwardTravelTimeFormatterColorRef(): ColorRefType { + return TrainrunSection.getDisplayColorRef(this.backwardTravelTime); + } + getSourceDepartureFormatterColorRef(): ColorRefType { return TrainrunSection.getDisplayColorRef(this.sourceDeparture); } @@ -390,6 +483,11 @@ export class TrainrunSection { TrainrunSectionValidator.validateTravelTime(this); } + setBackwardTravelTime(time: number) { + this.backwardTravelTime.time = time; + TrainrunSectionValidator.validateBackwardTravelTime(this); + } + setSourceDeparture(time: number) { this.sourceDeparture.time = time; TrainrunSectionValidator.validateOneSection(this); @@ -414,6 +512,10 @@ export class TrainrunSection { return this.travelTime.lock; } + getBackwardTravelTimeLock(): boolean { + return this.backwardTravelTime.lock; + } + getSourceDepartureLock(): boolean { return this.sourceDeparture.lock; } @@ -434,6 +536,10 @@ export class TrainrunSection { this.travelTime.lock = lock; } + setBackwardTravelTimeLock(lock: boolean) { + this.backwardTravelTime.lock = lock; + } + setSourceDepartureLock(lock: boolean) { this.sourceDeparture.lock = lock; } @@ -458,6 +564,10 @@ export class TrainrunSection { return this.travelTime.warning !== null; } + hasBackwardTravelTimeWarning(): boolean { + return this.backwardTravelTime.warning !== null; + } + hasSourceDepartureWarning(): boolean { return this.sourceDeparture.warning !== null; } @@ -509,6 +619,13 @@ export class TrainrunSection { }; } + setBackwardTravelTimeWarning(warningTitle: string, warningDescription: string) { + this.backwardTravelTime.warning = { + title: warningTitle, + description: warningDescription, + }; + } + getTargetArrivalWarning() { return this.targetArrival.warning; } @@ -529,6 +646,10 @@ export class TrainrunSection { return this.travelTime.warning; } + getBackwardTravelTimeWarning() { + return this.backwardTravelTime.warning; + } + resetTargetArrivalWarning() { this.targetArrival.warning = null; } @@ -549,6 +670,10 @@ export class TrainrunSection { this.travelTime.warning = null; } + resetBackwardTravelTimeWarning() { + this.backwardTravelTime.warning = null; + } + getTrainrunId(): number { return this.trainrunId; } @@ -617,8 +742,23 @@ export class TrainrunSection { return this.pathVec2D; } - isPathEmpty(): boolean { - return this.pathVec2D.length === 0; + isPathInvalid(): boolean { + if (this.pathVec2D.length === 0 || !this.path || !this.path.textPositions) { + return true; + } + + // Check if all required TrainrunSectionText enum values have corresponding textPositions + const keys = [ + TrainrunSectionText.SourceArrival, + TrainrunSectionText.SourceDeparture, + TrainrunSectionText.TargetArrival, + TrainrunSectionText.TargetDeparture, + TrainrunSectionText.TrainrunSectionName, + TrainrunSectionText.TrainrunSectionTravelTime, + TrainrunSectionText.TrainrunSectionBackwardTravelTime, + TrainrunSectionText.TrainrunSectionNumberOfStops, + ]; + return keys.some((key) => !(key in this.path.textPositions)); } routeEdgeAndPlaceText() { @@ -632,6 +772,7 @@ export class TrainrunSection { this.path.textPositions = SimpleTrainrunSectionRouter.placeTextOnTrainrunSection( this.pathVec2D, this.sourceNode.getPort(this.sourcePortId), + !this.areTravelTimesEqual(), ); } @@ -651,12 +792,15 @@ export class TrainrunSection { sourcePortId: this.sourcePortId, targetNodeId: this.targetNodeId, targetPortId: this.targetPortId, - travelTime: this.travelTime, + sourceSymmetry: this.sourceSymmetry, + targetSymmetry: this.targetSymmetry, sourceDeparture: this.sourceDeparture, sourceArrival: this.sourceArrival, targetDeparture: this.targetDeparture, targetArrival: this.targetArrival, + travelTime: this.travelTime, + backwardTravelTime: this.backwardTravelTime, numberOfStops: this.numberOfStops, diff --git a/src/app/perlenkette/perlenkette-section/perlenkette-section.component.html b/src/app/perlenkette/perlenkette-section/perlenkette-section.component.html index 6ae4287a8..cb364acbe 100644 --- a/src/app/perlenkette/perlenkette-section/perlenkette-section.component.html +++ b/src/app/perlenkette/perlenkette-section/perlenkette-section.component.html @@ -3,29 +3,46 @@ (click)="disableSectionView($event)" [class.readonly]="!getVariantIsWritable()" > - + + + + + + @@ -49,7 +66,7 @@ 'LinePatternRef_7/24', ]" class="edge_line_stops PerlenketteFill5 PerlenketteStopElement" - (click)="clickStopElement(perlenketteSection)" + (click)="clickStopElement()" > @@ -70,7 +87,11 @@ - + - + - + - + - {{ getLeftArrivalTime() }} + {{ trainrunSectionTimesService.getTimeStructure().leftArrivalTime }} - + - {{ getLeftDepartureTime() }} + {{ trainrunSectionTimesService.getTimeStructure().leftDepartureTime }} - + - {{ getTravelTime() }} + {{ getDefaultDisplayTravelTime() }} + + + + + + + {{ getDefaultDisplayBottomTravelTime() }} - + - {{ getRightDepartureTime() }} + {{ trainrunSectionTimesService.getTimeStructure().rightDepartureTime }} - + - {{ getRightArrivalTime() }} + {{ trainrunSectionTimesService.getTimeStructure().rightArrivalTime }} - + - +
@@ -226,33 +277,54 @@ + + + + - +
@@ -266,8 +338,8 @@ sbbInput spellcheck="false" pattern="^[0-9]*" - [(ngModel)]="leftAndRightTimeStructure.leftArrivalTime" - (change)="onNodeLeftArrivalTimeChanged()" + [(ngModel)]="trainrunSectionTimesService.getTimeStructure().leftArrivalTime" + (change)="trainrunSectionTimesService.onNodeLeftArrivalTimeChanged()" />
@@ -275,7 +347,10 @@ tabindex="-1" mode="ghost" class="ButtonPlus" - (click)="onNodeLeftArrivalTimeButtonPlus($event)" + (click)=" + trainrunSectionTimesService.onNodeLeftArrivalTimeButtonPlus(); + stopPropagation($event) + " > + @@ -284,26 +359,38 @@
-
+
-
+
@@ -312,14 +399,20 @@
@@ -333,8 +426,8 @@ sbbInput spellcheck="false" pattern="^[0-9]*" - [(ngModel)]="leftAndRightTimeStructure.leftDepartureTime" - (change)="onNodeLeftDepartureTimeChanged()" + [(ngModel)]="trainrunSectionTimesService.getTimeStructure().leftDepartureTime" + (change)="trainrunSectionTimesService.onNodeLeftDepartureTimeChanged()" />
@@ -342,48 +435,86 @@ tabindex="-1" mode="ghost" class="ButtonPlus" - (click)="onNodeLeftDepartureTimeButtonPlus($event)" + (click)=" + trainrunSectionTimesService.onNodeLeftDepartureTimeButtonPlus(); + stopPropagation($event) + " > +
+ + +
-
+
-
+
-
+
@@ -397,8 +528,8 @@ sbbInput spellcheck="false" pattern="^[0-9]*" - [(ngModel)]="leftAndRightTimeStructure.travelTime" - (change)="onInputTravelTimeChanged()" + [(ngModel)]="trainrunSectionTimesService.getTimeStructure().travelTime" + (change)="trainrunSectionTimesService.onTravelTimeChanged()" />
@@ -406,7 +537,54 @@ tabindex="-1" mode="ghost" class="ButtonPlus" - (click)="onInputTravelTimeElementButtonPlus($event)" + (click)=" + trainrunSectionTimesService.onTravelTimeButtonPlus(); stopPropagation($event) + " + > + + + +
+
+ +
+
+ +
+
+ +
+
+ @@ -415,14 +593,20 @@
@@ -436,8 +620,8 @@ sbbInput spellcheck="false" pattern="^[0-9]*" - [(ngModel)]="leftAndRightTimeStructure.rightDepartureTime" - (change)="onNodeRightDepartureTimeChanged()" + [(ngModel)]="trainrunSectionTimesService.getTimeStructure().rightDepartureTime" + (change)="trainrunSectionTimesService.onNodeRightDepartureTimeChanged()" />
@@ -445,7 +629,10 @@ tabindex="-1" mode="ghost" class="ButtonPlus" - (click)="onNodeRightDepartureTimeButtonPlus($event)" + (click)=" + trainrunSectionTimesService.onNodeRightDepartureTimeButtonPlus(); + stopPropagation($event) + " > + @@ -454,26 +641,38 @@
-
+
-
+
@@ -482,14 +681,20 @@
@@ -503,8 +708,8 @@ sbbInput spellcheck="false" pattern="^[0-9]*" - [(ngModel)]="leftAndRightTimeStructure.rightArrivalTime" - (change)="onNodeRightArrivalTimeChanged()" + [(ngModel)]="trainrunSectionTimesService.getTimeStructure().rightArrivalTime" + (change)="trainrunSectionTimesService.onNodeRightArrivalTimeChanged()" />
@@ -512,25 +717,51 @@ tabindex="-1" mode="ghost" class="ButtonPlus" - (click)="onNodeRightArrivalTimeButtonPlus($event)" + (click)=" + trainrunSectionTimesService.onNodeRightArrivalTimeButtonPlus(); + stopPropagation($event) + " > +
+ +
- +
@@ -655,7 +906,7 @@ sbbInput spellcheck="false" pattern="^[0-9]*" - [(ngModel)]="this.leftAndRightTimeStructure.nbrOfStops" + [(ngModel)]="perlenketteSection.numberOfStops" (change)="onInputNbrStopsChanged()" />
@@ -664,7 +915,7 @@ tabindex="-1" mode="ghost" class="ButtonPlus" - (click)="onInputNbrStopsElementButtonPlus($event)" + (click)="onInputNbrStopsElementButtonPlus($event); stopPropagation($event)" > + @@ -675,4 +926,5 @@
+
diff --git a/src/app/perlenkette/perlenkette-section/perlenkette-section.component.scss b/src/app/perlenkette/perlenkette-section/perlenkette-section.component.scss index abab4db5d..75df917ba 100644 --- a/src/app/perlenkette/perlenkette-section/perlenkette-section.component.scss +++ b/src/app/perlenkette/perlenkette-section/perlenkette-section.component.scss @@ -45,6 +45,7 @@ svg text.edge_text { .editingContainer { display: flex; + position: relative; .mainGridLayout { margin: 6px 0 !important; @@ -77,11 +78,21 @@ svg text.edge_text { grid-row: 2 / span 3; } + .nodeBorderContainerCenterLeft { + grid-column: 1 / span 3; + grid-row: 6 / span 3; // ou grid-row: 7 / span 3; + } + .nodeBorderContainerCenter { grid-column: 3 / span 3; grid-row: 7 / span 3; } + .nodeBorderContainerCenterRight { + grid-column: 5 / span 3; + grid-row: 8 / span 3; // ou grid-row: 7 / span 3; + } + .nodeBorderContainerBottomLeft { grid-column: 1 / span 3; grid-row: 12 / span 3; @@ -160,6 +171,20 @@ svg text.edge_text { } } + .LeftSymmetryToggle { + grid-column: 8 / span 2; + grid-row: 2 / span 3; + margin-left: 5px; + margin-top: 6px; + } + + .RightSymmetryToggle { + grid-column: 8 / span 2; + grid-row: 13 / span 3; + margin-left: 5px; + margin-top: 6px; + } + .propagationButtonContainer { display: flex; flex-direction: column; diff --git a/src/app/perlenkette/perlenkette-section/perlenkette-section.component.ts b/src/app/perlenkette/perlenkette-section/perlenkette-section.component.ts index 8a7da6161..d08925dad 100644 --- a/src/app/perlenkette/perlenkette-section/perlenkette-section.component.ts +++ b/src/app/perlenkette/perlenkette-section/perlenkette-section.component.ts @@ -1,5 +1,6 @@ import { AfterContentInit, + ChangeDetectorRef, Component, ElementRef, EventEmitter, @@ -12,6 +13,7 @@ import { import {PerlenketteSection} from "../model/perlenketteSection"; import {PerlenketteTrainrun} from "../model/perlenketteTrainrun"; import {TrainrunsectionHelper} from "../../services/util/trainrunsection.helper"; +import {SymmetryToggleService} from "../../services/util/symmetry-toggle.service"; import {TrainrunService} from "../../services/data/trainrun.service"; import {TrainrunSectionService} from "../../services/data/trainrunsection.service"; import {takeUntil} from "rxjs/operators"; @@ -21,9 +23,7 @@ import {TrainrunSection} from "../../models/trainrunsection.model"; import {TrainrunSectionTimesService} from "../../services/data/trainrun-section-times.service"; import {TrainrunSectionsView} from "../../view/editor-main-view/data-views/trainrunsections.view"; import {FilterService} from "../../services/ui/filter.service"; -import {Node} from "../../models/node.model"; import {LoadPerlenketteService} from "../service/load-perlenkette.service"; -import {NodeService} from "../../services/data/node.service"; import {EditorMode} from "../../view/editor-menu/editor-mode"; import {Vec2D} from "../../utils/vec2D"; import {PortAlignment} from "../../data-structures/technical.data.structures"; @@ -32,23 +32,9 @@ import { TRAINRUN_SECTION_PORT_SPAN_VERTICAL, } from "../../view/rastering/definitions"; import {StaticDomTags} from "../../view/editor-main-view/data-views/static.dom.tags"; -import {MathUtils} from "../../utils/math"; import {VersionControlService} from "../../services/data/version-control.service"; - -export interface TopAndBottomTimeStructure { - leftDepartureTime: number; - leftArrivalTime: number; - rightDepartureTime: number; - rightArrivalTime: number; - travelTime: number; - nbrOfStops: number; -} - -export interface LeftAndRightLockStructure { - leftLock: boolean; - rightLock: boolean; - travelTimeLock: boolean; -} +import {ToggleSwitchButtonComponent} from "../../view/toggle-switch-button/toggle-switch-button.component"; +import {MathUtils} from "src/app/utils/math"; @Component({ selector: "sbb-perlenkette-section", @@ -74,57 +60,57 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On @ViewChild("rightDepartureTime", {static: false}) rightDepartureTimeElement: ElementRef; @ViewChild("travelTime", {static: false}) travelTimeElement: ElementRef; + @ViewChild("bottomTravelTime", {static: false}) bottomTravelTimeElement: ElementRef; @ViewChild("leftDepartureTime", {static: false}) leftDepartureTimeElement: ElementRef; @ViewChild("leftArrivalTime", {static: false}) leftArrivalTimeElement: ElementRef; @ViewChild("nbrOfStops", {static: false}) nbrOfStops: ElementRef; + @ViewChild("leftSymmetryToggle") leftSymmetryToggle: ToggleSwitchButtonComponent; + @ViewChild("rightSymmetryToggle") rightSymmetryToggle: ToggleSwitchButtonComponent; private static timeEditor = true; stationNumberArray: number[]; public trainrunSection: TrainrunSection; - private trainrunSectionHelper: TrainrunsectionHelper; - - public leftAndRightTimeStructure: TopAndBottomTimeStructure; - lockStructure: LeftAndRightLockStructure = { - leftLock: false, - rightLock: false, - travelTimeLock: false, - }; + public trainrunSectionHelper: TrainrunsectionHelper; + // for static methods + public TrainrunsectionHelper = TrainrunsectionHelper; - private nodesOrdered: Node[] = []; + public numberOfStops: number; private destroyed$ = new Subject(); constructor( private trainrunService: TrainrunService, private trainrunSectionService: TrainrunSectionService, - private nodeService: NodeService, private uiInteractionService: UiInteractionService, public trainrunSectionTimesService: TrainrunSectionTimesService, readonly filterService: FilterService, private loadPerlenketteService: LoadPerlenketteService, private versionControlService: VersionControlService, + private changeDetectionRef: ChangeDetectorRef, + private symmetryToggleService: SymmetryToggleService, ) { this.trainrunSectionHelper = new TrainrunsectionHelper(this.trainrunService); } ngOnInit() { + this.numberOfStops = this.perlenketteSection.numberOfStops; this.stationNumberArray = Array(this.perlenketteSection.numberOfStops) .fill(1) .map((x, i) => i + 1); this.trainrunSection = this.trainrunSectionService.getTrainrunSectionFromId( this.perlenketteSection.trainrunSectionId, ); - this.trainrunSectionTimesService.setTrainrunSection(this.trainrunSection); + this.trainrunSectionTimesService.setTrainrunSection(this.trainrunSection, true); + this.trainrunSectionTimesService.setOffset(0); this.trainrunSectionTimesService.setLockStructure( this.trainrunSectionHelper.getLeftAndRightLock( this.trainrunSection, this.trainrunSectionTimesService.getNodesOrdered(), ), ); - this.updateLeftAndRightTimeStructure(); } ngAfterContentInit() { @@ -141,20 +127,6 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On } } }); - this.trainrunSectionTimesService.setNodesOrdered([ - this.perlenketteSection.fromNode, - this.perlenketteSection.toNode, - ]); - this.trainrunSectionTimesService.setLockStructure( - this.trainrunSectionHelper.getLeftAndRightLock( - this.trainrunSection, - this.trainrunSectionTimesService.getNodesOrdered(), - ), - ); - - this.nodesOrdered = [this.perlenketteSection.fromNode, this.perlenketteSection.toNode]; - - this.updateLockStructure(); this.signalHeightChanged.next(192); } @@ -164,10 +136,6 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On this.destroyed$.complete(); } - isRoundTrip(): boolean { - return this.trainrunSection.getTrainrun().isRoundTrip(); - } - getEdgeLineArrowClass() { const trainrun = this.trainrunSection.getTrainrun(); return ( @@ -187,10 +155,20 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On ); } - getArrowTranslateAndRotate(y: number) { - if (this.isRightSideDisplayed() && !this.isLeftSideDisplayed()) { + shouldDisplayDirectionArrow(): boolean { + return !this.trainrunSection.getTrainrun().isRoundTrip(); + } + + getDirectionArrowTranslateAndRotate(y: number) { + if ( + TrainrunsectionHelper.isRightSideDisplayed(this.trainrunSection) && + !TrainrunsectionHelper.isLeftSideDisplayed(this.trainrunSection) + ) { return `translate(137, ${y}) rotate(90)`; - } else if (!this.isRightSideDisplayed() && this.isLeftSideDisplayed()) { + } else if ( + !TrainrunsectionHelper.isRightSideDisplayed(this.trainrunSection) && + TrainrunsectionHelper.isLeftSideDisplayed(this.trainrunSection) + ) { return `translate(137, ${y + 15}) rotate(-90)`; } return ""; @@ -203,28 +181,24 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On ); } - isLeftSideDisplayed(): boolean { - if (this.trainrunSection === null) { - return false; + shouldDisplayAsymmetryArrows(arrow: "top" | "bottom"): boolean { + if (arrow === "top") { + if (this.isTargetRightOrBottom()) { + return !this.trainrunSection.isSourceSymmetricOrTimesSymmetric(); + } else { + return !this.trainrunSection.isTargetSymmetricOrTimesSymmetric(); + } + } else { + if (this.isTargetRightOrBottom()) { + return !this.trainrunSection.isTargetSymmetricOrTimesSymmetric(); + } else { + return !this.trainrunSection.isSourceSymmetricOrTimesSymmetric(); + } } - const isTargetRightOrBottom = TrainrunsectionHelper.isTargetRightOrBottom( - this.trainrunSectionService.getAllTrainrunSectionsForTrainrun( - this.trainrunSection.getTrainrunId(), - )[0], - ); - return this.trainrunSection.getTrainrun().isRoundTrip() || !isTargetRightOrBottom; } - isRightSideDisplayed(): boolean { - if (this.trainrunSection === null) { - return false; - } - const isTargetRightOrBottom = TrainrunsectionHelper.isTargetRightOrBottom( - this.trainrunSectionService.getAllTrainrunSectionsForTrainrun( - this.trainrunSection.getTrainrunId(), - )[0], - ); - return this.trainrunSection.getTrainrun().isRoundTrip() || isTargetRightOrBottom; + getAsymmetryArrowTranslate(y: number) { + return `translate(137, ${y}) rotate(90)`; } getVariantIsWritable(): boolean { @@ -245,21 +219,21 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On if (this.showAllLockStates) { return true; } - return this.lockStructure.travelTimeLock; + return this.trainrunSectionTimesService.getLockStructure().travelTimeLock; } showLeftLock(): boolean { if (this.showAllLockStates) { return true; } - return this.lockStructure.leftLock; + return this.trainrunSectionTimesService.getLockStructure().leftLock; } showRightLock(): boolean { if (this.showAllLockStates) { return true; } - return this.lockStructure.rightLock; + return this.trainrunSectionTimesService.getLockStructure().rightLock; } getPathClassTag(noLinePatterns = false): string { @@ -292,51 +266,19 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On event.stopPropagation(); if (fieldKey === "leftDepartureTime") { - this.onButtonNodeLeftLock(event); + this.trainrunSectionTimesService.onButtonNodeLeftLock(); return; } if (fieldKey === "travelTime") { - this.onButtonTravelTimeLock(event); + this.trainrunSectionTimesService.onButtonTravelTimeLock(); return; } if (fieldKey === "rightDepartureTime") { - this.onButtonNodeRightLock(event); + this.trainrunSectionTimesService.onButtonNodeRightLock(); return; } } - handleSwitchSection(fieldKey: string) { - this.perlenketteSection.isBeingEdited = !this.perlenketteSection.isBeingEdited; - if (this.perlenketteSection.isBeingEdited) { - this.signalIsBeingEdited.next(this.perlenketteSection); - } - - if (fieldKey === "rightArrivalTime") { - PerlenketteSectionComponent.timeEditor = true; - setTimeout(() => this.focusAndSelect(this.rightArrivalTimeElement), 100); - } - if (fieldKey === "rightDepartureTime") { - PerlenketteSectionComponent.timeEditor = true; - setTimeout(() => this.focusAndSelect(this.rightDepartureTimeElement), 100); - } - if (fieldKey === "travelTime") { - PerlenketteSectionComponent.timeEditor = true; - setTimeout(() => this.focusAndSelect(this.travelTimeElement), 100); - } - if (fieldKey === "leftDepartureTime") { - PerlenketteSectionComponent.timeEditor = true; - setTimeout(() => this.focusAndSelect(this.leftDepartureTimeElement), 100); - } - if (fieldKey === "leftArrivalTime") { - PerlenketteSectionComponent.timeEditor = true; - setTimeout(() => this.focusAndSelect(this.leftArrivalTimeElement), 100); - } - if (fieldKey === "stops") { - PerlenketteSectionComponent.timeEditor = false; - setTimeout(() => this.focusAndSelect(this.nbrOfStops), 100); - } - } - focusAndSelect(el: ElementRef) { el.nativeElement.focus(); el.nativeElement.select(); @@ -347,15 +289,6 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On } /* right departure time */ - getRightDepartureTime(): number { - const targetId = this.trainrunSection.getTargetNodeId(); - const toId = this.perlenketteSection.toNode.getId(); - if (targetId === toId) { - return this.roundTime(this.trainrunSection.getTargetDeparture()); - } - return this.roundTime(this.trainrunSection.getSourceDeparture()); - } - getRightDepartureTimeClassTag(): string { const targetId = this.trainrunSection.getTargetNodeId(); const toId = this.perlenketteSection.toNode.getId(); @@ -379,23 +312,7 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On ); } - showRightDepartureTime() { - if (this.filterService.isTemporaryDisableFilteringOfItemsInViewEnabled()) { - return true; - } - return this.filterService.isFilterArrivalDepartureTimeEnabled(); - } - /* right arrival time */ - getRightArrivalTime(): number { - const targetId = this.trainrunSection.getTargetNodeId(); - const toId = this.perlenketteSection.toNode.getId(); - if (targetId === toId) { - return this.roundTime(this.trainrunSection.getTargetArrival()); - } - return this.roundTime(this.trainrunSection.getSourceArrival()); - } - getRightArrivalTimeClassTag(): string { const targetId = this.trainrunSection.getTargetNodeId(); const toId = this.perlenketteSection.toNode.getId(); @@ -464,15 +381,6 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On } /* left departure time */ - getLeftDepartureTime(): number { - const sourceId = this.trainrunSection.getSourceNodeId(); - const fromId = this.perlenketteSection.fromNode.getId(); - if (sourceId === fromId) { - return this.roundTime(this.trainrunSection.getSourceDeparture()); - } - return this.roundTime(this.trainrunSection.getTargetDeparture()); - } - getLeftDepartureTimeClassTag(): string { const sourceId = this.trainrunSection.getSourceNodeId(); const fromId = this.perlenketteSection.fromNode.getId(); @@ -496,23 +404,7 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On ); } - showLeftDepartureTime() { - if (this.filterService.isTemporaryDisableFilteringOfItemsInViewEnabled()) { - return true; - } - return this.filterService.isFilterArrivalDepartureTimeEnabled(); - } - /* left arrival time */ - getLeftArrivalTime(): number { - const sourceId = this.trainrunSection.getSourceNodeId(); - const fromId = this.perlenketteSection.fromNode.getId(); - if (sourceId === fromId) { - return this.roundTime(this.trainrunSection.getSourceArrival()); - } - return this.roundTime(this.trainrunSection.getTargetArrival()); - } - getLeftArrivalTimeClassTag(): string { const sourceId = this.trainrunSection.getSourceNodeId(); const fromId = this.perlenketteSection.fromNode.getId(); @@ -555,425 +447,147 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On } /* travel time */ - showTravelTime() { - if (this.filterService.isTemporaryDisableFilteringOfItemsInViewEnabled()) { - return true; - } - return this.filterService.isFilterTravelTimeEnabled(); - } - - /* Get Section Times */ - getSectionSourceArrivalTime(): number { - const sourceId = this.trainrunSection.getSourceNodeId(); - const fromId = this.perlenketteSection.fromNode.getId(); - if (sourceId === fromId) { - return this.leftAndRightTimeStructure.leftArrivalTime; - } - return this.leftAndRightTimeStructure.rightArrivalTime; - } - - showArrivalAndDepartureTime(): boolean { - if (this.filterService.isTemporaryDisableFilteringOfItemsInViewEnabled()) { - return true; - } - return this.filterService.isFilterArrivalDepartureTimeEnabled(); - } - - getNodeRightLockClassTag(): string { - let tag = "NodeRightLock"; - if (!this.showArrivalAndDepartureTime()) { - tag += " Center"; - } - return tag; - } - - getNodeLeftLockClassTag(): string { - let tag = "NodeLeftLock"; - if (!this.showArrivalAndDepartureTime()) { - tag += " Center"; - } - return tag; - } - - getTravelTimeLockClassTag(): string { - let tag = "TravelTimeLock"; - if (!this.showTravelTime()) { - tag += " Center"; - } - return tag; - } - - getSectionSourceDepartureTime(): number { - const sourceId = this.trainrunSection.getSourceNodeId(); - const fromId = this.perlenketteSection.fromNode.getId(); - if (sourceId === fromId) { - return this.leftAndRightTimeStructure.leftDepartureTime; - } - return this.leftAndRightTimeStructure.rightDepartureTime; - } - - getSectionTargetDepartureTime(): number { - const sourceId = this.trainrunSection.getSourceNodeId(); - const toId = this.perlenketteSection.toNode.getId(); - if (sourceId === toId) { - return this.leftAndRightTimeStructure.leftDepartureTime; - } - return this.leftAndRightTimeStructure.rightDepartureTime; - } - - getSectionTargetArrivalTime(): number { - const sourceId = this.trainrunSection.getSourceNodeId(); - const toId = this.perlenketteSection.toNode.getId(); - if (sourceId === toId) { - return this.leftAndRightTimeStructure.leftArrivalTime; + getDefaultDisplayTravelTime() { + if ( + TrainrunSectionsView.getNode(this.trainrunSection, true).isNonStop(this.trainrunSection) || + TrainrunSectionsView.getNode(this.trainrunSection, false).isNonStop(this.trainrunSection) + ) { + const cumulativeTravelTime = TrainrunsectionHelper.isTargetRightOrBottom(this.trainrunSection) + ? this.trainrunService.getCumulativeTravelTime(this.trainrunSection) + : this.trainrunService.getCumulativeBackwardTravelTime(this.trainrunSection); + const travelTime = TrainrunsectionHelper.isTargetRightOrBottom(this.trainrunSection) + ? this.trainrunSection.getTravelTime() + : this.trainrunSection.getBackwardTravelTime(); + return "" + this.roundTime(cumulativeTravelTime) + "' (" + this.roundTime(travelTime) + "')"; } - return this.leftAndRightTimeStructure.rightArrivalTime; + return ( + "" + this.roundTime(this.trainrunSectionTimesService.getTimeStructure().travelTime) + "'" + ); } - getTravelTime() { + getDefaultDisplayBottomTravelTime() { if ( TrainrunSectionsView.getNode(this.trainrunSection, true).isNonStop(this.trainrunSection) || TrainrunSectionsView.getNode(this.trainrunSection, false).isNonStop(this.trainrunSection) ) { + const cumulativeBackwardTravelTime = TrainrunsectionHelper.isTargetRightOrBottom( + this.trainrunSection, + ) + ? this.trainrunService.getCumulativeBackwardTravelTime(this.trainrunSection) + : this.trainrunService.getCumulativeTravelTime(this.trainrunSection); + const bottomTravelTime = TrainrunsectionHelper.isTargetRightOrBottom(this.trainrunSection) + ? this.trainrunSection.getBackwardTravelTime() + : this.trainrunSection.getTravelTime(); return ( "" + - this.roundTime(this.trainrunSectionTimesService.getTimeStructure().travelTime) + + this.roundTime(cumulativeBackwardTravelTime) + "' (" + - this.roundTime(this.trainrunSection.getTravelTime()) + + this.roundTime(bottomTravelTime) + "')" ); } return ( - "" + this.roundTime(this.trainrunSectionTimesService.getTimeStructure().travelTime) + "'" + "" + + this.roundTime(this.trainrunSectionTimesService.getTimeStructure().bottomTravelTime) + + "'" ); } - getSectionTravelTime() { - return this.leftAndRightTimeStructure.travelTime; - } - - private getTimeButtonPlusMinusStep(val: number) { - return 1 - val + Math.floor(val); - } - - /* Left Departure Time */ - onNodeLeftDepartureTimeButtonPlus(event: MouseEvent) { - this.stopPropagation(event); - this.leftAndRightTimeStructure.leftDepartureTime += this.getTimeButtonPlusMinusStep( - this.leftAndRightTimeStructure.leftDepartureTime, - ); - this.leftAndRightTimeStructure.leftDepartureTime %= 60; - this.onNodeLeftDepartureTimeChanged(); - } - - onNodeLeftDepartureTimeButtonMinus(event: MouseEvent) { - this.stopPropagation(event); - this.leftAndRightTimeStructure.leftDepartureTime -= this.getTimeButtonPlusMinusStep( - this.leftAndRightTimeStructure.leftDepartureTime, - ); - this.leftAndRightTimeStructure.leftDepartureTime += - this.leftAndRightTimeStructure.leftDepartureTime < 0 ? 60 : 0; - this.onNodeLeftDepartureTimeChanged(); - } - - onNodeLeftDepartureTimeChanged() { - this.leftAndRightTimeStructure.leftDepartureTime = - this.leftAndRightTimeStructure.leftDepartureTime % 60; - this.leftAndRightTimeStructure.leftDepartureTime += - this.leftAndRightTimeStructure.leftDepartureTime < 0 ? 60 : 0; - - this.leftAndRightTimeStructure.leftArrivalTime = TrainrunsectionHelper.getSymmetricTime( - this.leftAndRightTimeStructure.leftDepartureTime, - ); - if (!this.lockStructure.rightLock) { - this.leftAndRightTimeStructure.rightArrivalTime = - this.leftAndRightTimeStructure.leftDepartureTime + - (this.leftAndRightTimeStructure.travelTime % 60); - this.leftAndRightTimeStructure.rightArrivalTime %= 60; - this.leftAndRightTimeStructure.rightDepartureTime = TrainrunsectionHelper.getSymmetricTime( - this.leftAndRightTimeStructure.rightArrivalTime, - ); - } else if (!this.lockStructure.travelTimeLock && this.lockStructure.rightLock) { - this.leftAndRightTimeStructure.travelTime = - this.leftAndRightTimeStructure.leftArrivalTime - - this.leftAndRightTimeStructure.rightDepartureTime; - this.leftAndRightTimeStructure.travelTime += - this.leftAndRightTimeStructure.travelTime < 0 ? 60 : 0; + showTravelTime() { + if (this.filterService.isTemporaryDisableFilteringOfItemsInViewEnabled()) { + return true; } - - this.updateTrainrunSectionTime(); - } - - /* Left Arrival Time */ - onNodeLeftArrivalTimeButtonPlus(event: MouseEvent) { - this.stopPropagation(event); - this.leftAndRightTimeStructure.leftArrivalTime += this.getTimeButtonPlusMinusStep( - this.leftAndRightTimeStructure.leftArrivalTime, - ); - this.leftAndRightTimeStructure.leftArrivalTime %= 60; - this.onNodeLeftArrivalTimeChanged(); - } - - onNodeLeftArrivalTimeButtonMinus(event: MouseEvent) { - this.stopPropagation(event); - this.leftAndRightTimeStructure.leftArrivalTime -= this.getTimeButtonPlusMinusStep( - this.leftAndRightTimeStructure.leftArrivalTime, - ); - this.leftAndRightTimeStructure.leftArrivalTime += - this.leftAndRightTimeStructure.leftArrivalTime < 0 ? 60 : 0; - this.onNodeLeftArrivalTimeChanged(); + return this.filterService.isFilterTravelTimeEnabled(); } - onNodeLeftArrivalTimeChanged() { - this.leftAndRightTimeStructure.leftArrivalTime = - this.leftAndRightTimeStructure.leftArrivalTime % 60; - this.leftAndRightTimeStructure.leftArrivalTime += - this.leftAndRightTimeStructure.leftArrivalTime < 0 ? 60 : 0; - - this.leftAndRightTimeStructure.leftDepartureTime = TrainrunsectionHelper.getSymmetricTime( - this.leftAndRightTimeStructure.leftArrivalTime, - ); - if (!this.lockStructure.rightLock) { - this.leftAndRightTimeStructure.rightDepartureTime = - this.leftAndRightTimeStructure.leftArrivalTime - - (this.leftAndRightTimeStructure.travelTime % 60); - this.leftAndRightTimeStructure.rightDepartureTime += - this.leftAndRightTimeStructure.rightDepartureTime < 0 ? 60 : 0; - this.leftAndRightTimeStructure.rightArrivalTime = TrainrunsectionHelper.getSymmetricTime( - this.leftAndRightTimeStructure.rightDepartureTime, - ); - } else if (!this.lockStructure.travelTimeLock && this.lockStructure.rightLock) { - this.leftAndRightTimeStructure.travelTime = - this.leftAndRightTimeStructure.leftArrivalTime - - this.leftAndRightTimeStructure.rightDepartureTime; - this.leftAndRightTimeStructure.travelTime += - this.leftAndRightTimeStructure.travelTime < 0 ? 60 : 0; + showBottomTravelTime() { + if (this.filterService.isTemporaryDisableFilteringOfItemsInViewEnabled()) { + return true; } - - this.updateTrainrunSectionTime(); - } - - /* Right Arrival Time */ - onNodeRightArrivalTimeButtonPlus(event: MouseEvent) { - this.stopPropagation(event); - this.leftAndRightTimeStructure.rightArrivalTime += this.getTimeButtonPlusMinusStep( - this.leftAndRightTimeStructure.rightArrivalTime, - ); - this.leftAndRightTimeStructure.rightArrivalTime %= 60; - this.onNodeRightArrivalTimeChanged(); - } - - onNodeRightArrivalTimeButtonMinus(event: MouseEvent) { - this.stopPropagation(event); - this.leftAndRightTimeStructure.rightArrivalTime -= this.getTimeButtonPlusMinusStep( - this.leftAndRightTimeStructure.rightArrivalTime, + return ( + !this.trainrunSection.isSymmetric() && this.filterService.isFilterBackwardTravelTimeEnabled() ); - this.leftAndRightTimeStructure.rightArrivalTime += - this.leftAndRightTimeStructure.rightArrivalTime < 0 ? 60 : 0; - this.onNodeRightArrivalTimeChanged(); } - onNodeRightArrivalTimeChanged() { - this.leftAndRightTimeStructure.rightArrivalTime = - this.leftAndRightTimeStructure.rightArrivalTime % 60; - this.leftAndRightTimeStructure.rightArrivalTime += - this.leftAndRightTimeStructure.rightArrivalTime < 0 ? 60 : 0; - - this.leftAndRightTimeStructure.rightDepartureTime = TrainrunsectionHelper.getSymmetricTime( - this.leftAndRightTimeStructure.rightArrivalTime, - ); - if (!this.lockStructure.leftLock) { - this.leftAndRightTimeStructure.leftDepartureTime = - this.leftAndRightTimeStructure.rightArrivalTime - - (this.leftAndRightTimeStructure.travelTime % 60); - this.leftAndRightTimeStructure.leftDepartureTime += - this.leftAndRightTimeStructure.leftDepartureTime < 0 ? 60 : 0; - this.leftAndRightTimeStructure.leftArrivalTime = TrainrunsectionHelper.getSymmetricTime( - this.leftAndRightTimeStructure.leftDepartureTime, - ); - } else if (!this.lockStructure.travelTimeLock && this.lockStructure.leftLock) { - this.leftAndRightTimeStructure.travelTime = - this.leftAndRightTimeStructure.rightArrivalTime - - this.leftAndRightTimeStructure.leftDepartureTime; - this.leftAndRightTimeStructure.travelTime += - this.leftAndRightTimeStructure.travelTime < 0 ? 60 : 0; + showArrivalAndDepartureTime(): boolean { + if (this.filterService.isTemporaryDisableFilteringOfItemsInViewEnabled()) { + return true; } - - this.updateTrainrunSectionTime(); - } - - /* Right Departure Time */ - onNodeRightDepartureTimeButtonPlus(event: MouseEvent) { - this.stopPropagation(event); - this.leftAndRightTimeStructure.rightDepartureTime += this.getTimeButtonPlusMinusStep( - this.leftAndRightTimeStructure.rightDepartureTime, - ); - this.leftAndRightTimeStructure.rightDepartureTime %= 60; - this.onNodeRightDepartureTimeChanged(); - } - - onNodeRightDepartureTimeButtonMinus(event: MouseEvent) { - this.stopPropagation(event); - this.leftAndRightTimeStructure.rightDepartureTime -= this.getTimeButtonPlusMinusStep( - this.leftAndRightTimeStructure.rightDepartureTime, - ); - this.leftAndRightTimeStructure.rightDepartureTime += - this.leftAndRightTimeStructure.rightDepartureTime < 0 ? 60 : 0; - this.onNodeRightDepartureTimeChanged(); + return this.filterService.isFilterArrivalDepartureTimeEnabled(); } - onNodeRightDepartureTimeChanged() { - this.leftAndRightTimeStructure.rightDepartureTime = - this.leftAndRightTimeStructure.rightDepartureTime % 60; - this.leftAndRightTimeStructure.rightDepartureTime += - this.leftAndRightTimeStructure.rightDepartureTime < 0 ? 60 : 0; - - this.leftAndRightTimeStructure.rightArrivalTime = TrainrunsectionHelper.getSymmetricTime( - this.leftAndRightTimeStructure.rightDepartureTime, - ); - if (!this.lockStructure.leftLock) { - this.leftAndRightTimeStructure.leftArrivalTime = - this.leftAndRightTimeStructure.rightDepartureTime + - (this.leftAndRightTimeStructure.travelTime % 60); - this.leftAndRightTimeStructure.leftArrivalTime %= 60; - this.leftAndRightTimeStructure.leftDepartureTime = TrainrunsectionHelper.getSymmetricTime( - this.leftAndRightTimeStructure.leftArrivalTime, - ); - } else if (!this.lockStructure.travelTimeLock && this.lockStructure.leftLock) { - this.leftAndRightTimeStructure.travelTime = - this.leftAndRightTimeStructure.rightArrivalTime - - this.leftAndRightTimeStructure.leftDepartureTime; - this.leftAndRightTimeStructure.travelTime += - this.leftAndRightTimeStructure.travelTime < 0 ? 60 : 0; + getTravelTimeTransform(element: "travelTime" | "bottomTravelTime") { + if (element === "travelTime") { + if (this.trainrunSection.isSymmetric()) { + // default position + return "translate(121, 93)"; + } + // position swapped when asymmetric to match leftDepartureTime and rightArrivalTime that are always shown on the right side + if (this.stationNumberArray.length > 5) { + // move a bit more to the right when many stops are shown + return "translate(165, 106)"; + } + return "translate(155, 106)"; + } else { + // position on the left side to match leftArrivalTime and rightDepartureTime that are always shown on the left side + return "translate(121, 93)"; } - - this.updateTrainrunSectionTime(); - } - - /* Travel Time */ - onInputTravelTimeElementButtonPlus(event: MouseEvent) { - this.stopPropagation(event); - this.leftAndRightTimeStructure.travelTime += this.getTimeButtonPlusMinusStep( - this.leftAndRightTimeStructure.travelTime, - ); - this.onInputTravelTimeChanged(); } - onInputTravelTimeElementButtonMinus(event: MouseEvent) { - this.stopPropagation(event); - this.leftAndRightTimeStructure.travelTime -= this.getTimeButtonPlusMinusStep( - this.leftAndRightTimeStructure.travelTime, - ); - this.leftAndRightTimeStructure.travelTime = Math.max( - 1, - this.leftAndRightTimeStructure.travelTime, - ); - this.onInputTravelTimeChanged(); - } - - updateTravelTimeChanged() { - this.leftAndRightTimeStructure.travelTime = Math.max( - this.leftAndRightTimeStructure.travelTime, - 1, - ); - - if (!this.lockStructure.rightLock) { - this.leftAndRightTimeStructure.rightArrivalTime = - this.leftAndRightTimeStructure.leftDepartureTime + - this.leftAndRightTimeStructure.travelTime; - this.leftAndRightTimeStructure.rightArrivalTime += - this.leftAndRightTimeStructure.rightArrivalTime < 0 ? 60 : 0; - this.leftAndRightTimeStructure.rightArrivalTime %= 60; - this.leftAndRightTimeStructure.rightDepartureTime = TrainrunsectionHelper.getSymmetricTime( - this.leftAndRightTimeStructure.rightArrivalTime, - ); - } else if (!this.lockStructure.leftLock) { - this.leftAndRightTimeStructure.leftArrivalTime = - this.leftAndRightTimeStructure.rightDepartureTime + - this.leftAndRightTimeStructure.travelTime; - this.leftAndRightTimeStructure.leftArrivalTime += - this.leftAndRightTimeStructure.leftArrivalTime < 0 ? 60 : 0; - this.leftAndRightTimeStructure.leftArrivalTime %= 60; - this.leftAndRightTimeStructure.leftDepartureTime = TrainrunsectionHelper.getSymmetricTime( - this.leftAndRightTimeStructure.leftArrivalTime, - ); + getNodeBorderContainerScssSuffix(): string { + if (this.trainrunSection.isSymmetric()) { + return ""; } + // show travel time on the right side + return "Right"; } - onInputTravelTimeChanged() { - this.updateTravelTimeChanged(); - this.updateTrainrunSectionTime(); - } - - roundTime(time: number) { - return MathUtils.round(time, this.filterService.getTimeDisplayPrecision()); - } - - /* Lock */ - onButtonTravelTimeLock(event: MouseEvent) { - this.stopPropagation(event); - this.lockStructure.travelTimeLock = !this.lockStructure.travelTimeLock; - this.updateTrainrunSectionTimeLock(); - } - - onButtonNodeLeftLock(event: MouseEvent) { - this.stopPropagation(event); - this.lockStructure.leftLock = !this.lockStructure.leftLock; - this.updateTrainrunSectionTimeLock(); - } - - onButtonNodeRightLock(event: MouseEvent) { - this.stopPropagation(event); - this.lockStructure.rightLock = !this.lockStructure.rightLock; - this.updateTrainrunSectionTimeLock(); - } - - getSourceLock(): boolean { - const sourceId = this.trainrunSection.getSourceNodeId(); - const fromNode = this.perlenketteSection.fromNode.getId(); - if (sourceId === fromNode) { - return this.lockStructure.leftLock; + /* lock icons */ + getNodeRightLockClassTag(): string { + let tag = "NodeRightLock"; + if (!this.showArrivalAndDepartureTime()) { + tag += " Center"; } - return this.lockStructure.rightLock; + return tag; } - getTargetLock(): boolean { - const targetId = this.trainrunSection.getTargetNodeId(); - const toId = this.perlenketteSection.toNode.getId(); - if (targetId === toId) { - return this.lockStructure.rightLock; + getNodeLeftLockClassTag(): string { + let tag = "NodeLeftLock"; + if (!this.showArrivalAndDepartureTime()) { + tag += " Center"; } - return this.lockStructure.leftLock; - } - - updateTrainrunSectionTimeLock() { - this.trainrunSectionService.updateTrainrunSectionTimeLock( - this.trainrunSection.getId(), - this.getSourceLock(), - this.getTargetLock(), - this.lockStructure.travelTimeLock, - ); + return tag; } - /* Buttons in Footer */ - onPropagateTimeLeft(event: MouseEvent) { - this.stopPropagation(event); - const toId = this.perlenketteSection.toNode.getId(); - this.trainrunSectionService.propagateTimeAlongTrainrun(this.trainrunSection.getId(), toId); - this.loadPerlenketteService.render(); + getTravelTimeLockClassTag(): string { + let tag = "TravelTimeLock"; + if (!this.showTravelTime() || !this.trainrunSection.isSymmetric()) { + // lock in center when trainrun is asymmetric or travel time is not shown + tag += " Center"; + } + return tag; } - onPropagateTimeRight(event: MouseEvent) { - this.stopPropagation(event); - const fromId = this.perlenketteSection.fromNode.getId(); - this.trainrunSectionService.propagateTimeAlongTrainrun(this.trainrunSection.getId(), fromId); - this.loadPerlenketteService.render(); + getTravelTimeLockTransform() { + if (this.stationNumberArray.length > 0) { + if (this.stationNumberArray.length <= 5) { + // move a bit to the right when some stops are shown + return this.trainrunSection.isSymmetric() ? "translate(142, 82)" : "translate(159, 82)"; + } else { + // move a bit more to the right when many stops are shown + return this.trainrunSection.isSymmetric() ? "translate(155, 82)" : "translate(168, 82)"; + } + } else { + // default position + return "translate(125, 82)"; + } } - clickStopElement(perlenketteSection: PerlenketteSection) { + clickStopElement() { this.handleSwitchSection("stops"); } + /* number of stops */ onInputNbrStopsElementButtonMinus(event: MouseEvent) { event.stopPropagation(); const nos = Math.max(0, this.trainrunSection.getNumberOfStops() - 1); @@ -981,7 +595,7 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On } onInputNbrStopsChanged() { - const nos = Math.max(this.leftAndRightTimeStructure.nbrOfStops); + const nos = Math.max(this.numberOfStops); this.trainrunSectionService.updateTrainrunSectionNumberOfStops(this.trainrunSection, nos); } @@ -1034,17 +648,6 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On } } - getLockOpenSvgPath(): string { - return "M4 6a3 3 0 1 1 6 0v3h8v11H6V9h3V6a2 2 0 1 0-4 0H4Zm8.5 7v4h-1v-4h1ZM7 19v-9h10v9H7Z"; - } - - getLockCloseSvgPath(): string { - return ( - "M12 4a2 2 0 0 0-2 2v3h4V6a2 2 0 0 0-2-2Zm3 5V6a3 3 0 0 0-6 0v3H6v11h12V9h-3Zm-2.5 " + - "4v4h-1v-4h1ZM7 19v-9h10v9H7Z" - ); - } - getLockSvgPath(isClosed: boolean) { if (isClosed) { return this.getLockCloseSvgPath(); @@ -1052,51 +655,104 @@ export class PerlenketteSectionComponent implements OnInit, AfterContentInit, On return this.getLockOpenSvgPath(); } - private updateTrainrunSectionTime() { - const trsId = this.trainrunSection.getId(); - const sourceArrivalTime = this.getSectionSourceArrivalTime(); - const sourceDeparture = this.getSectionSourceDepartureTime(); - const targetArrival = this.getSectionTargetArrivalTime(); - const targetDeparture = this.getSectionTargetDepartureTime(); - const travelTime = this.getSectionTravelTime(); - - this.trainrunSectionService.updateTrainrunSectionTime( - trsId, - sourceArrivalTime, - sourceDeparture, - targetArrival, - targetDeparture, - travelTime, + onLeftNodeSymmetryToggleChanged(symmetry: boolean) { + const originalState = this.trainrunSectionHelper.isLeftNextStopNodeSymmetric( + this.trainrunSection, + this.trainrunSectionTimesService.getNodesOrdered(), + ); + this.symmetryToggleService.onLeftNodeSymmetryToggleChanged( + this.trainrunSection, + this.trainrunSectionTimesService, + symmetry, + () => { + // Revert the toggle state + if (this.leftSymmetryToggle) { + this.leftSymmetryToggle.checked = !originalState; + } + this.changeDetectionRef.detectChanges(); + }, ); - this.trainrunSectionService.trainrunSectionsUpdated(); } - private updateLeftAndRightTimeStructure() { - this.leftAndRightTimeStructure = { - leftArrivalTime: this.getLeftArrivalTime(), - leftDepartureTime: this.getLeftDepartureTime(), - rightArrivalTime: this.getRightArrivalTime(), - rightDepartureTime: this.getRightDepartureTime(), - travelTime: this.trainrunSection.getTravelTime(), - nbrOfStops: this.trainrunSection.getNumberOfStops(), - }; + onRightNodeSymmetryToggleChanged(symmetry: boolean) { + const originalState = this.trainrunSectionHelper.isRightNextStopNodeSymmetric( + this.trainrunSection, + this.trainrunSectionTimesService.getNodesOrdered(), + ); + this.symmetryToggleService.onRightNodeSymmetryToggleChanged( + this.trainrunSection, + this.trainrunSectionTimesService, + symmetry, + () => { + // Revert the toggle state + if (this.rightSymmetryToggle) { + this.rightSymmetryToggle.checked = !originalState; + } + this.changeDetectionRef.detectChanges(); + }, + ); } - private updateLockStructure() { - const sourceId = this.trainrunSection.getSourceNodeId(); - const fromId = this.perlenketteSection.fromNode.getId(); - if (sourceId === fromId) { - this.lockStructure.leftLock = this.trainrunSection.getSourceDepartureLock(); - } else { - this.lockStructure.leftLock = this.trainrunSection.getTargetArrivalLock(); + isTrainrunSymmetric() { + return this.trainrunSectionService.isTrainrunSymmetric(this.trainrunSection.getTrainrunId()); + } + + private roundTime(time: number) { + return MathUtils.round(time, this.filterService.getTimeDisplayPrecision()); + } + + private handleSwitchSection(fieldKey: string) { + this.perlenketteSection.isBeingEdited = !this.perlenketteSection.isBeingEdited; + if (this.perlenketteSection.isBeingEdited) { + this.signalIsBeingEdited.next(this.perlenketteSection); } - const targetId = this.trainrunSection.getTargetNodeId(); - const toId = this.perlenketteSection.toNode.getId(); - if (targetId === toId) { - this.lockStructure.rightLock = this.trainrunSection.getTargetArrivalLock(); - } else { - this.lockStructure.rightLock = this.trainrunSection.getSourceDepartureLock(); + + if (fieldKey === "rightArrivalTime") { + PerlenketteSectionComponent.timeEditor = true; + setTimeout(() => this.focusAndSelect(this.rightArrivalTimeElement), 100); + } + if (fieldKey === "rightDepartureTime") { + PerlenketteSectionComponent.timeEditor = true; + setTimeout(() => this.focusAndSelect(this.rightDepartureTimeElement), 100); + } + if (fieldKey === "travelTime") { + PerlenketteSectionComponent.timeEditor = true; + setTimeout(() => this.focusAndSelect(this.travelTimeElement), 100); } - this.lockStructure.travelTimeLock = this.trainrunSection.getTravelTimeLock(); + if (fieldKey === "bottomTravelTime") { + PerlenketteSectionComponent.timeEditor = true; + setTimeout(() => this.focusAndSelect(this.bottomTravelTimeElement), 100); + } + if (fieldKey === "leftDepartureTime") { + PerlenketteSectionComponent.timeEditor = true; + setTimeout(() => this.focusAndSelect(this.leftDepartureTimeElement), 100); + } + if (fieldKey === "leftArrivalTime") { + PerlenketteSectionComponent.timeEditor = true; + setTimeout(() => this.focusAndSelect(this.leftArrivalTimeElement), 100); + } + if (fieldKey === "stops") { + PerlenketteSectionComponent.timeEditor = false; + setTimeout(() => this.focusAndSelect(this.nbrOfStops), 100); + } + } + + private getLockOpenSvgPath(): string { + return "M4 6a3 3 0 1 1 6 0v3h8v11H6V9h3V6a2 2 0 1 0-4 0H4Zm8.5 7v4h-1v-4h1ZM7 19v-9h10v9H7Z"; + } + + private getLockCloseSvgPath(): string { + return ( + "M12 4a2 2 0 0 0-2 2v3h4V6a2 2 0 0 0-2-2Zm3 5V6a3 3 0 0 0-6 0v3H6v11h12V9h-3Zm-2.5 " + + "4v4h-1v-4h1ZM7 19v-9h10v9H7Z" + ); + } + + private isTargetRightOrBottom() { + return TrainrunsectionHelper.isTargetRightOrBottom( + this.trainrunSectionService.getAllTrainrunSectionsForTrainrun( + this.trainrunSection.getTrainrunId(), + )[0], + ); } } diff --git a/src/app/perlenkette/perlenkette.component.html b/src/app/perlenkette/perlenkette.component.html index b7f8668ab..dbacd307d 100644 --- a/src/app/perlenkette/perlenkette.component.html +++ b/src/app/perlenkette/perlenkette.component.html @@ -1,33 +1,21 @@
-
- - - - - - -
+ + + + + +
@@ -147,21 +135,32 @@
- - -
-

- {{ - pathItem.getPerlenketteNode().shortName - }} +

+ +
+ +
+

+ {{ + pathItem.getPerlenketteNode().shortName + }} - - - -

+ + + +

+
+
- + + +
diff --git a/src/app/perlenkette/perlenkette.component.scss b/src/app/perlenkette/perlenkette.component.scss index c22dfaed1..926e6580b 100644 --- a/src/app/perlenkette/perlenkette.component.scss +++ b/src/app/perlenkette/perlenkette.component.scss @@ -132,7 +132,33 @@ span.smallstation:hover { stroke: var(--COLOR_Edit); } +.ToggleAllEyesButton { + pointer-events: auto; + position: fixed; + bottom: 20px; + right: 30px; +} + .ToggleAllEyesButton:hover { stroke: var(--COLOR_Edit); stroke-width: 0.5px; } + +.station-toggle-container { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + gap: 10px; + min-height: 30px; +} + +.station-list { + flex: 1; + min-width: 0; + + p { + display: inline; + margin: 0; + } +} diff --git a/src/app/perlenkette/perlenkette.component.ts b/src/app/perlenkette/perlenkette.component.ts index 8b202bcb2..08eca6ee7 100644 --- a/src/app/perlenkette/perlenkette.component.ts +++ b/src/app/perlenkette/perlenkette.component.ts @@ -24,8 +24,11 @@ import {PerlenketteConnection} from "./model/perlenketteConnection"; import {VersionControlService} from "../services/data/version-control.service"; import {Direction} from "../data-structures/business.data.structures"; import {TrainrunsectionHelper} from "../services/util/trainrunsection.helper"; +import {SymmetryToggleService} from "../services/util/symmetry-toggle.service"; import {TrainrunSectionService} from "../services/data/trainrunsection.service"; import {TrainrunService} from "../services/data/trainrun.service"; +import {TrainrunSectionTimesService} from "../services/data/trainrun-section-times.service"; +import {ToggleSwitchButtonComponent} from "../view/toggle-switch-button/toggle-switch-button.component"; enum ShowTrainrunEditTab { sbb_trainrun_tab = "GENERAL", @@ -41,6 +44,7 @@ export class PerlenketteComponent implements AfterContentChecked, OnDestroy { perlenketteTrainrun: PerlenketteTrainrun; @ViewChild("svgPerlenkette") svgPerlenkette: ElementRef; @ViewChild("drawingContainer") drawingContainer: ElementRef; + @ViewChild("trainrunSymmetryToggle") trainrunSymmetryToggle: ToggleSwitchButtonComponent; @Input() sidebarElementHeight: number; private readonly destroyed$ = new Subject(); @@ -73,6 +77,8 @@ export class PerlenketteComponent implements AfterContentChecked, OnDestroy { private changeDetectorRef: ChangeDetectorRef, private trainrunService: TrainrunService, private trainrunSectionService: TrainrunSectionService, + public trainrunSectionTimesService: TrainrunSectionTimesService, + private symmetryToggleService: SymmetryToggleService, ) { this.selectedPerlenketteConnection = undefined; this.trainrunSectionHelper = new TrainrunsectionHelper(this.trainrunService); @@ -331,10 +337,6 @@ export class PerlenketteComponent implements AfterContentChecked, OnDestroy { return this.versionControlService.getVariantIsWritable(); } - getPositionY(): number { - return this.contentHeight * window.devicePixelRatio - 40; - } - disableSectionView() { this.signalIsBeingEdited(undefined); } @@ -458,5 +460,25 @@ export class PerlenketteComponent implements AfterContentChecked, OnDestroy { } } + isSymmetric(): boolean { + return this.trainrunSectionService.isTrainrunSymmetric(this.perlenketteTrainrun.trainrunId); + } + + onTrainrunSymmetryToggleChanged() { + this.symmetryToggleService.onTrainrunSymmetryToggleChanged( + this.perlenketteTrainrun.trainrunId, + this.trainrunSectionTimesService, + () => this.revertTrainrunSymmetryToggleState(false), + ); + } + protected readonly ShowTrainrunEditTab = ShowTrainrunEditTab; + + private revertTrainrunSymmetryToggleState(originalState: boolean) { + if (this.trainrunSymmetryToggle) { + // Manually set the checked state to revert the toggle + this.trainrunSymmetryToggle.checked = !originalState; + } + this.changeDetectorRef.detectChanges(); + } } diff --git a/src/app/sample-netzgrafik/Demo_OL_LZ.json b/src/app/sample-netzgrafik/Demo_OL_LZ.json index 43896df87..3db4d9c01 100644 --- a/src/app/sample-netzgrafik/Demo_OL_LZ.json +++ b/src/app/sample-netzgrafik/Demo_OL_LZ.json @@ -368,11 +368,14 @@ "sourcePortId": 86, "targetNodeId": 7, "targetPortId": 87, - "travelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 0, "warning": null, "consecutiveTime": 0}, "sourceArrival": {"lock": false, "time": 0, "warning": null, "consecutiveTime": 180}, "targetDeparture": {"lock": false, "time": 37, "warning": null, "consecutiveTime": 157}, "targetArrival": {"lock": false, "time": 23, "warning": null, "consecutiveTime": 23}, + "travelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 11, "resourceId": 0, @@ -391,7 +394,8 @@ "3": {"x": 208, "y": 188}, "4": {"x": -304, "y": 164}, "5": {"x": -304, "y": 164}, - "6": {"x": -304, "y": 188} + "6": {"x": -304, "y": 188}, + "7": {"x": -304, "y": 188} } }, "warnings": null @@ -402,11 +406,14 @@ "sourcePortId": 88, "targetNodeId": 4, "targetPortId": 89, - "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 23, "warning": null, "consecutiveTime": 23}, "sourceArrival": {"lock": false, "time": 37, "warning": null, "consecutiveTime": 157}, "targetDeparture": {"lock": false, "time": 32, "warning": null, "consecutiveTime": 152}, "targetArrival": {"lock": false, "time": 28, "warning": null, "consecutiveTime": 28}, + "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 11, "resourceId": 0, @@ -425,7 +432,8 @@ "3": {"x": 784, "y": 604}, "4": {"x": 592, "y": 452}, "5": {"x": 592, "y": 452}, - "6": {"x": 592, "y": 476} + "6": {"x": 592, "y": 476}, + "7": {"x": 592, "y": 476} } }, "warnings": null @@ -436,11 +444,14 @@ "sourcePortId": 90, "targetNodeId": 6, "targetPortId": 91, - "travelTime": {"lock": true, "time": 13, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 29, "warning": null, "consecutiveTime": 29}, "sourceArrival": {"lock": false, "time": 31, "warning": null, "consecutiveTime": 151}, "targetDeparture": {"lock": false, "time": 18, "warning": null, "consecutiveTime": 138}, "targetArrival": {"lock": false, "time": 42, "warning": null, "consecutiveTime": 42}, + "travelTime": {"lock": true, "time": 13, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 13, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 11, "resourceId": 0, @@ -459,7 +470,8 @@ "3": {"x": 836, "y": 976}, "4": {"x": 836, "y": 832}, "5": {"x": 836, "y": 832}, - "6": {"x": 860, "y": 832} + "6": {"x": 836, "y": 832}, + "7": {"x": 860, "y": 832} } }, "warnings": null @@ -470,11 +482,14 @@ "sourcePortId": 92, "targetNodeId": 3, "targetPortId": 93, - "travelTime": {"lock": true, "time": 18, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 43, "warning": null, "consecutiveTime": 43}, "sourceArrival": {"lock": false, "time": 17, "warning": null, "consecutiveTime": 137}, "targetDeparture": {"lock": false, "time": 59, "warning": null, "consecutiveTime": 119}, "targetArrival": {"lock": false, "time": 1, "warning": null, "consecutiveTime": 61}, + "travelTime": {"lock": true, "time": 18, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 18, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 11, "resourceId": 0, @@ -493,7 +508,8 @@ "3": {"x": 836, "y": 1392}, "4": {"x": 836, "y": 1264}, "5": {"x": 836, "y": 1264}, - "6": {"x": 860, "y": 1264} + "6": {"x": 836, "y": 1264}, + "7": {"x": 860, "y": 1264} } }, "warnings": null @@ -504,11 +520,14 @@ "sourcePortId": 94, "targetNodeId": 7, "targetPortId": 95, - "travelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 31, "warning": null, "consecutiveTime": 31}, "sourceArrival": {"lock": false, "time": 29, "warning": null, "consecutiveTime": 149}, "targetDeparture": {"lock": false, "time": 6, "warning": null, "consecutiveTime": 126}, "targetArrival": {"lock": false, "time": 54, "warning": null, "consecutiveTime": 54}, + "travelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 12, "resourceId": 0, @@ -527,7 +546,8 @@ "3": {"x": 208, "y": 124}, "4": {"x": -304, "y": 100}, "5": {"x": -304, "y": 100}, - "6": {"x": -304, "y": 124} + "6": {"x": -304, "y": 124}, + "7": {"x": -304, "y": 124} } }, "warnings": null @@ -538,11 +558,14 @@ "sourcePortId": 96, "targetNodeId": 1, "targetPortId": 97, - "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 54, "warning": null, "consecutiveTime": 54}, "sourceArrival": {"lock": false, "time": 6, "warning": null, "consecutiveTime": 126}, "targetDeparture": {"lock": false, "time": 1, "warning": null, "consecutiveTime": 121}, "targetArrival": {"lock": false, "time": 59, "warning": null, "consecutiveTime": 59}, + "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 12, "resourceId": 0, @@ -561,7 +584,8 @@ "3": {"x": 784, "y": 124}, "4": {"x": 592, "y": 100}, "5": {"x": 592, "y": 100}, - "6": {"x": 592, "y": 124} + "6": {"x": 592, "y": 124}, + "7": {"x": 592, "y": 124} } }, "warnings": null @@ -572,11 +596,14 @@ "sourcePortId": 98, "targetNodeId": 2, "targetPortId": 99, - "travelTime": {"lock": true, "time": 29, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 59, "warning": null, "consecutiveTime": 59}, "sourceArrival": {"lock": false, "time": 1, "warning": null, "consecutiveTime": 121}, "targetDeparture": {"lock": false, "time": 32, "warning": null, "consecutiveTime": 92}, "targetArrival": {"lock": false, "time": 28, "warning": null, "consecutiveTime": 88}, + "travelTime": {"lock": true, "time": 29, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 29, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 12, "resourceId": 0, @@ -595,7 +622,8 @@ "3": {"x": 2416, "y": 92}, "4": {"x": 1744, "y": 68}, "5": {"x": 1744, "y": 68}, - "6": {"x": 1744, "y": 92} + "6": {"x": 1744, "y": 92}, + "7": {"x": 1744, "y": 92} } }, "warnings": null @@ -606,11 +634,14 @@ "sourcePortId": 104, "targetNodeId": 7, "targetPortId": 105, - "travelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 4, "warning": null, "consecutiveTime": 4}, "sourceArrival": {"lock": false, "time": 56, "warning": null, "consecutiveTime": 176}, "targetDeparture": {"lock": false, "time": 33, "warning": null, "consecutiveTime": 153}, "targetArrival": {"lock": false, "time": 27, "warning": null, "consecutiveTime": 27}, + "travelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 14, "resourceId": 0, @@ -629,7 +660,8 @@ "3": {"x": 208, "y": 156}, "4": {"x": -304, "y": 132}, "5": {"x": -304, "y": 132}, - "6": {"x": -304, "y": 156} + "6": {"x": -304, "y": 156}, + "7": {"x": -304, "y": 156} } }, "warnings": null @@ -640,11 +672,14 @@ "sourcePortId": 106, "targetNodeId": 1, "targetPortId": 107, - "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 27, "warning": null, "consecutiveTime": 27}, "sourceArrival": {"lock": false, "time": 33, "warning": null, "consecutiveTime": 153}, "targetDeparture": {"lock": false, "time": 28, "warning": null, "consecutiveTime": 148}, "targetArrival": {"lock": false, "time": 32, "warning": null, "consecutiveTime": 32}, + "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 14, "resourceId": 0, @@ -663,7 +698,8 @@ "3": {"x": 784, "y": 156}, "4": {"x": 592, "y": 132}, "5": {"x": 592, "y": 132}, - "6": {"x": 592, "y": 156} + "6": {"x": 592, "y": 156}, + "7": {"x": 592, "y": 156} } }, "warnings": null @@ -674,11 +710,14 @@ "sourcePortId": 108, "targetNodeId": 106, "targetPortId": 109, - "travelTime": {"lock": true, "time": 27, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 34, "warning": null, "consecutiveTime": 34}, "sourceArrival": {"lock": false, "time": 26, "warning": null, "consecutiveTime": 146}, "targetDeparture": {"lock": false, "time": 59, "warning": null, "consecutiveTime": 119}, "targetArrival": {"lock": false, "time": 1, "warning": null, "consecutiveTime": 61}, + "travelTime": {"lock": true, "time": 27, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 27, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 14, "resourceId": 0, @@ -697,7 +736,8 @@ "3": {"x": 892, "y": -240}, "4": {"x": 868, "y": -128}, "5": {"x": 868, "y": -128}, - "6": {"x": 892, "y": -128} + "6": {"x": 892, "y": -128}, + "7": {"x": 892, "y": -128} } }, "warnings": null @@ -708,11 +748,14 @@ "sourcePortId": 118, "targetNodeId": 7, "targetPortId": 119, - "travelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 2, "warning": null, "consecutiveTime": 2}, "sourceArrival": {"lock": false, "time": 58, "warning": null, "consecutiveTime": 58}, "targetDeparture": {"lock": false, "time": 35, "warning": null, "consecutiveTime": 35}, "targetArrival": {"lock": false, "time": 25, "warning": null, "consecutiveTime": 25}, + "travelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 16, "resourceId": 0, @@ -731,7 +774,8 @@ "3": {"x": 208, "y": 60}, "4": {"x": -304, "y": 36}, "5": {"x": -304, "y": 36}, - "6": {"x": -304, "y": 60} + "6": {"x": -304, "y": 60}, + "7": {"x": -304, "y": 60} } }, "warnings": null @@ -742,11 +786,14 @@ "sourcePortId": 120, "targetNodeId": 1, "targetPortId": 121, - "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 25, "warning": null, "consecutiveTime": 25}, "sourceArrival": {"lock": false, "time": 35, "warning": null, "consecutiveTime": 35}, "targetDeparture": {"lock": false, "time": 30, "warning": null, "consecutiveTime": 30}, "targetArrival": {"lock": false, "time": 30, "warning": null, "consecutiveTime": 30}, + "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 16, "resourceId": 0, @@ -765,7 +812,8 @@ "3": {"x": 784, "y": 60}, "4": {"x": 592, "y": 36}, "5": {"x": 592, "y": 36}, - "6": {"x": 592, "y": 60} + "6": {"x": 592, "y": 60}, + "7": {"x": 592, "y": 60} } }, "warnings": null @@ -776,11 +824,14 @@ "sourcePortId": 122, "targetNodeId": 2, "targetPortId": 123, - "travelTime": {"lock": true, "time": 28, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 30, "warning": null, "consecutiveTime": 30}, "sourceArrival": {"lock": false, "time": 30, "warning": null, "consecutiveTime": 30}, "targetDeparture": {"lock": false, "time": 2, "warning": null, "consecutiveTime": 2}, "targetArrival": {"lock": false, "time": 58, "warning": null, "consecutiveTime": 58}, + "travelTime": {"lock": true, "time": 28, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 28, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 16, "resourceId": 0, @@ -799,7 +850,8 @@ "3": {"x": 2416, "y": 60}, "4": {"x": 1744, "y": 36}, "5": {"x": 1744, "y": 36}, - "6": {"x": 1744, "y": 60} + "6": {"x": 1744, "y": 60}, + "7": {"x": 1744, "y": 60} } }, "warnings": null @@ -810,11 +862,14 @@ "sourcePortId": 126, "targetNodeId": 7, "targetPortId": 127, - "travelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 33, "warning": null, "consecutiveTime": 33}, "sourceArrival": {"lock": false, "time": 27, "warning": null, "consecutiveTime": 147}, "targetDeparture": {"lock": false, "time": 4, "warning": null, "consecutiveTime": 124}, "targetArrival": {"lock": false, "time": 56, "warning": null, "consecutiveTime": 56}, + "travelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 23, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 18, "resourceId": 0, @@ -833,7 +888,8 @@ "3": {"x": 208, "y": 220}, "4": {"x": -304, "y": 196}, "5": {"x": -304, "y": 196}, - "6": {"x": -304, "y": 220} + "6": {"x": -304, "y": 220}, + "7": {"x": -304, "y": 220} } }, "warnings": null @@ -844,11 +900,14 @@ "sourcePortId": 128, "targetNodeId": 1, "targetPortId": 129, - "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 56, "warning": null, "consecutiveTime": 56}, "sourceArrival": {"lock": false, "time": 4, "warning": null, "consecutiveTime": 124}, "targetDeparture": {"lock": false, "time": 59, "warning": null, "consecutiveTime": 119}, "targetArrival": {"lock": false, "time": 1, "warning": null, "consecutiveTime": 61}, + "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 18, "resourceId": 0, @@ -867,7 +926,8 @@ "3": {"x": 784, "y": 220}, "4": {"x": 592, "y": 196}, "5": {"x": 592, "y": 196}, - "6": {"x": 592, "y": 220} + "6": {"x": 592, "y": 220}, + "7": {"x": 592, "y": 220} } }, "warnings": null @@ -878,11 +938,14 @@ "sourcePortId": 137, "targetNodeId": 7, "targetPortId": 138, - "travelTime": {"lock": true, "time": 22, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 36, "warning": null, "consecutiveTime": 36}, "sourceArrival": {"lock": false, "time": 24, "warning": null, "consecutiveTime": 144}, "targetDeparture": {"lock": false, "time": 2, "warning": null, "consecutiveTime": 122}, "targetArrival": {"lock": false, "time": 58, "warning": null, "consecutiveTime": 58}, + "travelTime": {"lock": true, "time": 22, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 22, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 20, "resourceId": 0, @@ -901,7 +964,8 @@ "3": {"x": 208, "y": 92}, "4": {"x": -304, "y": 68}, "5": {"x": -304, "y": 68}, - "6": {"x": -304, "y": 92} + "6": {"x": -304, "y": 92}, + "7": {"x": -304, "y": 92} } }, "warnings": null @@ -912,11 +976,14 @@ "sourcePortId": 139, "targetNodeId": 1, "targetPortId": 140, - "travelTime": {"lock": false, "time": 5, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 58, "warning": null, "consecutiveTime": 58}, "sourceArrival": {"lock": false, "time": 2, "warning": null, "consecutiveTime": 122}, "targetDeparture": {"lock": false, "time": 57, "warning": null, "consecutiveTime": 117}, "targetArrival": {"lock": false, "time": 3, "warning": null, "consecutiveTime": 63}, + "travelTime": {"lock": false, "time": 5, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": false, "time": 5, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 20, "resourceId": 0, @@ -935,7 +1002,8 @@ "3": {"x": 784, "y": 92}, "4": {"x": 592, "y": 68}, "5": {"x": 592, "y": 68}, - "6": {"x": 592, "y": 92} + "6": {"x": 592, "y": 92}, + "7": {"x": 592, "y": 92} } }, "warnings": null @@ -946,11 +1014,14 @@ "sourcePortId": 141, "targetNodeId": 106, "targetPortId": 142, - "travelTime": {"lock": true, "time": 27, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 5, "warning": null, "consecutiveTime": 65}, "sourceArrival": {"lock": false, "time": 55, "warning": null, "consecutiveTime": 115}, "targetDeparture": {"lock": true, "time": 28, "warning": null, "consecutiveTime": 88}, "targetArrival": {"lock": true, "time": 32, "warning": null, "consecutiveTime": 92}, + "travelTime": {"lock": true, "time": 27, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 27, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 20, "resourceId": 0, @@ -969,7 +1040,8 @@ "3": {"x": 860, "y": -240}, "4": {"x": 836, "y": -128}, "5": {"x": 836, "y": -128}, - "6": {"x": 860, "y": -128} + "6": {"x": 860, "y": -128}, + "7": {"x": 860, "y": -128} } }, "warnings": null @@ -980,11 +1052,14 @@ "sourcePortId": 143, "targetNodeId": 8, "targetPortId": 144, - "travelTime": {"lock": true, "time": 33, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 7, "warning": null, "consecutiveTime": 7}, "sourceArrival": {"lock": false, "time": 53, "warning": null, "consecutiveTime": 53}, "targetDeparture": {"lock": false, "time": 20, "warning": null, "consecutiveTime": 20}, "targetArrival": {"lock": false, "time": 40, "warning": null, "consecutiveTime": 40}, + "travelTime": {"lock": true, "time": 33, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 33, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 21, "resourceId": 0, @@ -1003,7 +1078,8 @@ "3": {"x": -368, "y": 284}, "4": {"x": -592, "y": 260}, "5": {"x": -592, "y": 260}, - "6": {"x": -592, "y": 284} + "6": {"x": -592, "y": 284}, + "7": {"x": -592, "y": 284} } }, "warnings": null @@ -1014,11 +1090,14 @@ "sourcePortId": 145, "targetNodeId": 7, "targetPortId": 203, - "travelTime": {"lock": true, "time": 4, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 42, "warning": null, "consecutiveTime": 42}, "sourceArrival": {"lock": false, "time": 18, "warning": null, "consecutiveTime": 18}, "targetDeparture": {"lock": false, "time": 14, "warning": null, "consecutiveTime": 14}, "targetArrival": {"lock": false, "time": 46, "warning": null, "consecutiveTime": 46}, + "travelTime": {"lock": true, "time": 4, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 4, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 21, "resourceId": 0, @@ -1037,7 +1116,8 @@ "3": {"x": 208, "y": 284}, "4": {"x": 16, "y": 260}, "5": {"x": 16, "y": 260}, - "6": {"x": 16, "y": 284} + "6": {"x": 16, "y": 284}, + "7": {"x": 16, "y": 284} } }, "warnings": null @@ -1048,11 +1128,14 @@ "sourcePortId": 147, "targetNodeId": 8, "targetPortId": 148, - "travelTime": {"lock": true, "time": 32, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 38, "warning": null, "consecutiveTime": 38}, "sourceArrival": {"lock": false, "time": 22, "warning": null, "consecutiveTime": 262}, "targetDeparture": {"lock": false, "time": 50, "warning": null, "consecutiveTime": 230}, "targetArrival": {"lock": false, "time": 10, "warning": null, "consecutiveTime": 70}, + "travelTime": {"lock": true, "time": 32, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 32, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 22, "resourceId": 0, @@ -1071,7 +1154,8 @@ "3": {"x": -368, "y": 316}, "4": {"x": -592, "y": 292}, "5": {"x": -592, "y": 292}, - "6": {"x": -592, "y": 316} + "6": {"x": -592, "y": 316}, + "7": {"x": -592, "y": 316} } }, "warnings": null @@ -1082,11 +1166,14 @@ "sourcePortId": 149, "targetNodeId": 7, "targetPortId": 205, - "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 12, "warning": null, "consecutiveTime": 72}, "sourceArrival": {"lock": false, "time": 48, "warning": null, "consecutiveTime": 228}, "targetDeparture": {"lock": false, "time": 43, "warning": null, "consecutiveTime": 223}, "targetArrival": {"lock": false, "time": 17, "warning": null, "consecutiveTime": 77}, + "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 22, "resourceId": 0, @@ -1105,7 +1192,8 @@ "3": {"x": 208, "y": 316}, "4": {"x": 16, "y": 292}, "5": {"x": 16, "y": 292}, - "6": {"x": 16, "y": 316} + "6": {"x": 16, "y": 316}, + "7": {"x": 16, "y": 316} } }, "warnings": null @@ -1116,11 +1204,14 @@ "sourcePortId": 151, "targetNodeId": 2, "targetPortId": 152, - "travelTime": {"lock": true, "time": 36, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 24, "warning": null, "consecutiveTime": 84}, "sourceArrival": {"lock": false, "time": 36, "warning": null, "consecutiveTime": 216}, "targetDeparture": {"lock": false, "time": 0, "warning": null, "consecutiveTime": 180}, "targetArrival": {"lock": false, "time": 0, "warning": null, "consecutiveTime": 120}, + "travelTime": {"lock": true, "time": 36, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 36, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 22, "resourceId": 0, @@ -1139,7 +1230,8 @@ "3": {"x": 2416, "y": 124}, "4": {"x": 1744, "y": 100}, "5": {"x": 1744, "y": 100}, - "6": {"x": 1744, "y": 124} + "6": {"x": 1744, "y": 124}, + "7": {"x": 1744, "y": 124} } }, "warnings": null @@ -1150,11 +1242,14 @@ "sourcePortId": 153, "targetNodeId": 4, "targetPortId": 154, - "travelTime": {"lock": true, "time": 6, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 6, "warning": null, "consecutiveTime": 6}, "sourceArrival": {"lock": false, "time": 54, "warning": null, "consecutiveTime": 54}, "targetDeparture": {"lock": false, "time": 48, "warning": null, "consecutiveTime": 48}, "targetArrival": {"lock": false, "time": 12, "warning": null, "consecutiveTime": 12}, + "travelTime": {"lock": true, "time": 6, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 6, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 23, "resourceId": 0, @@ -1173,7 +1268,8 @@ "3": {"x": 900, "y": 528}, "4": {"x": 900, "y": 462}, "5": {"x": 900, "y": 462}, - "6": {"x": 924, "y": 462} + "6": {"x": 900, "y": 462}, + "7": {"x": 924, "y": 462} } }, "warnings": null @@ -1184,11 +1280,14 @@ "sourcePortId": 155, "targetNodeId": 6, "targetPortId": 156, - "travelTime": {"lock": true, "time": 17, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 13, "warning": null, "consecutiveTime": 13}, "sourceArrival": {"lock": false, "time": 47, "warning": null, "consecutiveTime": 47}, "targetDeparture": {"lock": false, "time": 30, "warning": null, "consecutiveTime": 30}, "targetArrival": {"lock": false, "time": 30, "warning": null, "consecutiveTime": 30}, + "travelTime": {"lock": true, "time": 17, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 17, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 23, "resourceId": 0, @@ -1207,7 +1306,8 @@ "3": {"x": 932, "y": 976}, "4": {"x": 932, "y": 832}, "5": {"x": 932, "y": 832}, - "6": {"x": 956, "y": 832} + "6": {"x": 932, "y": 832}, + "7": {"x": 956, "y": 832} } }, "warnings": null @@ -1218,11 +1318,14 @@ "sourcePortId": 157, "targetNodeId": 3, "targetPortId": 158, - "travelTime": {"lock": true, "time": 24, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 31, "warning": null, "consecutiveTime": 31}, "sourceArrival": {"lock": false, "time": 29, "warning": null, "consecutiveTime": 29}, "targetDeparture": {"lock": false, "time": 5, "warning": null, "consecutiveTime": 5}, "targetArrival": {"lock": false, "time": 55, "warning": null, "consecutiveTime": 55}, + "travelTime": {"lock": true, "time": 24, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 24, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 23, "resourceId": 0, @@ -1241,7 +1344,8 @@ "3": {"x": 932, "y": 1392}, "4": {"x": 932, "y": 1264}, "5": {"x": 932, "y": 1264}, - "6": {"x": 956, "y": 1264} + "6": {"x": 932, "y": 1264}, + "7": {"x": 956, "y": 1264} } }, "warnings": null @@ -1252,11 +1356,14 @@ "sourcePortId": 159, "targetNodeId": 4, "targetPortId": 160, - "travelTime": {"lock": true, "time": 9, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 12, "warning": null, "consecutiveTime": 12}, "sourceArrival": {"lock": false, "time": 48, "warning": null, "consecutiveTime": 48}, "targetDeparture": {"lock": false, "time": 39, "warning": null, "consecutiveTime": 39}, "targetArrival": {"lock": false, "time": 21, "warning": null, "consecutiveTime": 21}, + "travelTime": {"lock": true, "time": 9, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 9, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 24, "resourceId": 0, @@ -1275,7 +1382,8 @@ "3": {"x": 964, "y": 528}, "4": {"x": 964, "y": 462}, "5": {"x": 964, "y": 462}, - "6": {"x": 988, "y": 462} + "6": {"x": 964, "y": 462}, + "7": {"x": 988, "y": 462} } }, "warnings": null @@ -1286,11 +1394,14 @@ "sourcePortId": 161, "targetNodeId": 4, "targetPortId": 162, - "travelTime": {"lock": true, "time": 8, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 36, "warning": null, "consecutiveTime": 36}, "sourceArrival": {"lock": false, "time": 24, "warning": null, "consecutiveTime": 144}, "targetDeparture": {"lock": false, "time": 16, "warning": null, "consecutiveTime": 136}, "targetArrival": {"lock": false, "time": 44, "warning": null, "consecutiveTime": 44}, + "travelTime": {"lock": true, "time": 8, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 8, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 25, "resourceId": 0, @@ -1309,7 +1420,8 @@ "3": {"x": 932, "y": 528}, "4": {"x": 932, "y": 462}, "5": {"x": 932, "y": 462}, - "6": {"x": 956, "y": 462} + "6": {"x": 932, "y": 462}, + "7": {"x": 956, "y": 462} } }, "warnings": null @@ -1320,11 +1432,14 @@ "sourcePortId": 163, "targetNodeId": 6, "targetPortId": 164, - "travelTime": {"lock": true, "time": 22, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 45, "warning": null, "consecutiveTime": 45}, "sourceArrival": {"lock": false, "time": 15, "warning": null, "consecutiveTime": 135}, "targetDeparture": {"lock": false, "time": 53, "warning": null, "consecutiveTime": 113}, "targetArrival": {"lock": false, "time": 7, "warning": null, "consecutiveTime": 67}, + "travelTime": {"lock": true, "time": 22, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 22, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 25, "resourceId": 0, @@ -1343,7 +1458,8 @@ "3": {"x": 964, "y": 976}, "4": {"x": 964, "y": 832}, "5": {"x": 964, "y": 832}, - "6": {"x": 988, "y": 832} + "6": {"x": 964, "y": 832}, + "7": {"x": 988, "y": 832} } }, "warnings": null @@ -1354,11 +1470,14 @@ "sourcePortId": 165, "targetNodeId": 1, "targetPortId": 166, - "travelTime": {"lock": true, "time": 25, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 3, "warning": null, "consecutiveTime": 3}, "sourceArrival": {"lock": false, "time": 57, "warning": null, "consecutiveTime": 177}, "targetDeparture": {"lock": false, "time": 32, "warning": null, "consecutiveTime": 152}, "targetArrival": {"lock": false, "time": 28, "warning": null, "consecutiveTime": 28}, + "travelTime": {"lock": true, "time": 25, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 25, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 26, "resourceId": 0, @@ -1377,7 +1496,8 @@ "3": {"x": 900, "y": -16}, "4": {"x": 900, "y": -128}, "5": {"x": 900, "y": -128}, - "6": {"x": 924, "y": -128} + "6": {"x": 900, "y": -128}, + "7": {"x": 924, "y": -128} } }, "warnings": null @@ -1388,11 +1508,14 @@ "sourcePortId": 167, "targetNodeId": 4, "targetPortId": 168, - "travelTime": {"lock": true, "time": 6, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 30, "warning": null, "consecutiveTime": 30}, "sourceArrival": {"lock": false, "time": 30, "warning": null, "consecutiveTime": 150}, "targetDeparture": {"lock": false, "time": 24, "warning": null, "consecutiveTime": 144}, "targetArrival": {"lock": false, "time": 36, "warning": null, "consecutiveTime": 36}, + "travelTime": {"lock": true, "time": 6, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 6, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 26, "resourceId": 0, @@ -1411,7 +1534,8 @@ "3": {"x": 836, "y": 528}, "4": {"x": 836, "y": 462}, "5": {"x": 836, "y": 462}, - "6": {"x": 860, "y": 462} + "6": {"x": 836, "y": 462}, + "7": {"x": 860, "y": 462} } }, "warnings": null @@ -1422,11 +1546,14 @@ "sourcePortId": 169, "targetNodeId": 6, "targetPortId": 170, - "travelTime": {"lock": true, "time": 10, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 36, "warning": null, "consecutiveTime": 36}, "sourceArrival": {"lock": false, "time": 24, "warning": null, "consecutiveTime": 144}, "targetDeparture": {"lock": false, "time": 14, "warning": null, "consecutiveTime": 134}, "targetArrival": {"lock": false, "time": 46, "warning": null, "consecutiveTime": 46}, + "travelTime": {"lock": true, "time": 10, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 10, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 26, "resourceId": 0, @@ -1445,7 +1572,8 @@ "3": {"x": 868, "y": 976}, "4": {"x": 868, "y": 832}, "5": {"x": 868, "y": 832}, - "6": {"x": 892, "y": 832} + "6": {"x": 868, "y": 832}, + "7": {"x": 892, "y": 832} } }, "warnings": null @@ -1456,11 +1584,14 @@ "sourcePortId": 171, "targetNodeId": 3, "targetPortId": 172, - "travelTime": {"lock": true, "time": 19, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 46, "warning": null, "consecutiveTime": 46}, "sourceArrival": {"lock": false, "time": 14, "warning": null, "consecutiveTime": 134}, "targetDeparture": {"lock": false, "time": 55, "warning": null, "consecutiveTime": 115}, "targetArrival": {"lock": false, "time": 5, "warning": null, "consecutiveTime": 65}, + "travelTime": {"lock": true, "time": 19, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 19, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 26, "resourceId": 0, @@ -1479,7 +1610,8 @@ "3": {"x": 868, "y": 1392}, "4": {"x": 868, "y": 1264}, "5": {"x": 868, "y": 1264}, - "6": {"x": 892, "y": 1264} + "6": {"x": 868, "y": 1264}, + "7": {"x": 892, "y": 1264} } }, "warnings": null @@ -1490,11 +1622,14 @@ "sourcePortId": 173, "targetNodeId": 1, "targetPortId": 174, - "travelTime": {"lock": true, "time": 32, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 16, "warning": null, "consecutiveTime": 16}, "sourceArrival": {"lock": false, "time": 44, "warning": null, "consecutiveTime": 164}, "targetDeparture": {"lock": false, "time": 12, "warning": null, "consecutiveTime": 132}, "targetArrival": {"lock": false, "time": 48, "warning": null, "consecutiveTime": 48}, + "travelTime": {"lock": true, "time": 32, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 32, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 27, "resourceId": 0, @@ -1513,7 +1648,8 @@ "3": {"x": 932, "y": -16}, "4": {"x": 932, "y": -128}, "5": {"x": 932, "y": -128}, - "6": {"x": 956, "y": -128} + "6": {"x": 932, "y": -128}, + "7": {"x": 956, "y": -128} } }, "warnings": null @@ -1524,11 +1660,14 @@ "sourcePortId": 175, "targetNodeId": 4, "targetPortId": 176, - "travelTime": {"lock": true, "time": 7, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 49, "warning": null, "consecutiveTime": 49}, "sourceArrival": {"lock": false, "time": 11, "warning": null, "consecutiveTime": 131}, "targetDeparture": {"lock": false, "time": 4, "warning": null, "consecutiveTime": 124}, "targetArrival": {"lock": false, "time": 56, "warning": null, "consecutiveTime": 56}, + "travelTime": {"lock": true, "time": 7, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 7, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 27, "resourceId": 0, @@ -1547,7 +1686,8 @@ "3": {"x": 868, "y": 528}, "4": {"x": 868, "y": 462}, "5": {"x": 868, "y": 462}, - "6": {"x": 892, "y": 462} + "6": {"x": 868, "y": 462}, + "7": {"x": 892, "y": 462} } }, "warnings": null @@ -1558,11 +1698,14 @@ "sourcePortId": 177, "targetNodeId": 6, "targetPortId": 178, - "travelTime": {"lock": true, "time": 12, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 58, "warning": null, "consecutiveTime": 58}, "sourceArrival": {"lock": false, "time": 2, "warning": null, "consecutiveTime": 122}, "targetDeparture": {"lock": false, "time": 50, "warning": null, "consecutiveTime": 110}, "targetArrival": {"lock": false, "time": 10, "warning": null, "consecutiveTime": 70}, + "travelTime": {"lock": true, "time": 12, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 12, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 27, "resourceId": 0, @@ -1581,7 +1724,8 @@ "3": {"x": 900, "y": 976}, "4": {"x": 900, "y": 832}, "5": {"x": 900, "y": 832}, - "6": {"x": 924, "y": 832} + "6": {"x": 900, "y": 832}, + "7": {"x": 924, "y": 832} } }, "warnings": null @@ -1592,11 +1736,14 @@ "sourcePortId": 179, "targetNodeId": 3, "targetPortId": 180, - "travelTime": {"lock": true, "time": 18, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 12, "warning": null, "consecutiveTime": 72}, "sourceArrival": {"lock": false, "time": 48, "warning": null, "consecutiveTime": 108}, "targetDeparture": {"lock": false, "time": 30, "warning": null, "consecutiveTime": 90}, "targetArrival": {"lock": false, "time": 30, "warning": null, "consecutiveTime": 90}, + "travelTime": {"lock": true, "time": 18, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 18, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 27, "resourceId": 0, @@ -1615,7 +1762,8 @@ "3": {"x": 900, "y": 1392}, "4": {"x": 900, "y": 1264}, "5": {"x": 900, "y": 1264}, - "6": {"x": 924, "y": 1264} + "6": {"x": 900, "y": 1264}, + "7": {"x": 924, "y": 1264} } }, "warnings": null @@ -1626,11 +1774,14 @@ "sourcePortId": 181, "targetNodeId": 8, "targetPortId": 201, - "travelTime": {"lock": true, "time": 44, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 48, "warning": null, "consecutiveTime": 48}, "sourceArrival": {"lock": false, "time": 12, "warning": null, "consecutiveTime": 252}, "targetDeparture": {"lock": false, "time": 28, "warning": null, "consecutiveTime": 208}, "targetArrival": {"lock": false, "time": 32, "warning": null, "consecutiveTime": 92}, + "travelTime": {"lock": true, "time": 44, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 44, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 28, "resourceId": 0, @@ -1649,7 +1800,8 @@ "3": {"x": -368, "y": 348}, "4": {"x": -592, "y": 324}, "5": {"x": -592, "y": 324}, - "6": {"x": -592, "y": 348} + "6": {"x": -592, "y": 348}, + "7": {"x": -592, "y": 348} } }, "warnings": null @@ -1660,11 +1812,14 @@ "sourcePortId": 202, "targetNodeId": 7, "targetPortId": 207, - "travelTime": {"lock": true, "time": 6, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 44, "warning": null, "consecutiveTime": 104}, "sourceArrival": {"lock": false, "time": 16, "warning": null, "consecutiveTime": 196}, "targetDeparture": {"lock": false, "time": 10, "warning": null, "consecutiveTime": 190}, "targetArrival": {"lock": false, "time": 50, "warning": null, "consecutiveTime": 110}, + "travelTime": {"lock": true, "time": 6, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 6, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 28, "resourceId": 0, @@ -1683,7 +1838,8 @@ "3": {"x": 208, "y": 348}, "4": {"x": 16, "y": 324}, "5": {"x": 16, "y": 324}, - "6": {"x": 16, "y": 348} + "6": {"x": 16, "y": 348}, + "7": {"x": 16, "y": 348} } }, "warnings": null @@ -1694,11 +1850,14 @@ "sourcePortId": 185, "targetNodeId": 4, "targetPortId": 186, - "travelTime": {"lock": true, "time": 13, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 55, "warning": null, "consecutiveTime": 115}, "sourceArrival": {"lock": false, "time": 5, "warning": null, "consecutiveTime": 185}, "targetDeparture": {"lock": false, "time": 52, "warning": null, "consecutiveTime": 172}, "targetArrival": {"lock": false, "time": 8, "warning": null, "consecutiveTime": 128}, + "travelTime": {"lock": true, "time": 13, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 13, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 28, "resourceId": 0, @@ -1717,7 +1876,8 @@ "3": {"x": 996, "y": 528}, "4": {"x": 996, "y": 462}, "5": {"x": 996, "y": 462}, - "6": {"x": 1020, "y": 462} + "6": {"x": 996, "y": 462}, + "7": {"x": 1020, "y": 462} } }, "warnings": null @@ -1728,11 +1888,14 @@ "sourcePortId": 189, "targetNodeId": 6, "targetPortId": 190, - "travelTime": {"lock": true, "time": 20, "warning": null, "consecutiveTime": 10}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 8, "warning": null, "consecutiveTime": 128}, "sourceArrival": {"lock": false, "time": 52, "warning": null, "consecutiveTime": 172}, "targetDeparture": {"lock": false, "time": 32, "warning": null, "consecutiveTime": 152}, "targetArrival": {"lock": false, "time": 28, "warning": null, "consecutiveTime": 148}, + "travelTime": {"lock": true, "time": 20, "warning": null, "consecutiveTime": 10}, + "backwardTravelTime": {"lock": true, "time": 20, "warning": null, "consecutiveTime": 10}, "numberOfStops": 0, "trainrunId": 28, "resourceId": 0, @@ -1751,7 +1914,8 @@ "3": {"x": 996, "y": 976}, "4": {"x": 996, "y": 832}, "5": {"x": 996, "y": 832}, - "6": {"x": 1020, "y": 832} + "6": {"x": 996, "y": 832}, + "7": {"x": 1020, "y": 832} } }, "warnings": null @@ -1762,11 +1926,14 @@ "sourcePortId": 204, "targetNodeId": 1, "targetPortId": 146, - "travelTime": {"lock": true, "time": 4, "warning": null, "consecutiveTime": 1}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 46, "warning": null, "consecutiveTime": 46}, "sourceArrival": {"lock": false, "time": 14, "warning": null, "consecutiveTime": 14}, "targetDeparture": {"lock": false, "time": 10, "warning": null, "consecutiveTime": 10}, "targetArrival": {"lock": false, "time": 50, "warning": null, "consecutiveTime": 50}, + "travelTime": {"lock": true, "time": 4, "warning": null, "consecutiveTime": 1}, + "backwardTravelTime": {"lock": true, "time": 4, "warning": null, "consecutiveTime": 1}, "numberOfStops": 0, "trainrunId": 21, "resourceId": 0, @@ -1785,7 +1952,8 @@ "3": {"x": 784, "y": 252}, "4": {"x": 592, "y": 228}, "5": {"x": 592, "y": 228}, - "6": {"x": 592, "y": 252} + "6": {"x": 592, "y": 252}, + "7": {"x": 592, "y": 252} } }, "warnings": null @@ -1796,11 +1964,14 @@ "sourcePortId": 206, "targetNodeId": 1, "targetPortId": 150, - "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 1}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 17, "warning": null, "consecutiveTime": 77}, "sourceArrival": {"lock": false, "time": 43, "warning": null, "consecutiveTime": 223}, "targetDeparture": {"lock": false, "time": 38, "warning": null, "consecutiveTime": 218}, "targetArrival": {"lock": false, "time": 22, "warning": null, "consecutiveTime": 82}, + "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 1}, + "backwardTravelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 1}, "numberOfStops": 0, "trainrunId": 22, "resourceId": 0, @@ -1819,7 +1990,8 @@ "3": {"x": 784, "y": 284}, "4": {"x": 592, "y": 260}, "5": {"x": 592, "y": 260}, - "6": {"x": 592, "y": 284} + "6": {"x": 592, "y": 284}, + "7": {"x": 592, "y": 284} } }, "warnings": null @@ -1830,11 +2002,14 @@ "sourcePortId": 208, "targetNodeId": 1, "targetPortId": 184, - "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 1}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 50, "warning": null, "consecutiveTime": 110}, "sourceArrival": {"lock": false, "time": 10, "warning": null, "consecutiveTime": 190}, "targetDeparture": {"lock": false, "time": 5, "warning": null, "consecutiveTime": 185}, "targetArrival": {"lock": false, "time": 55, "warning": null, "consecutiveTime": 115}, + "travelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 1}, + "backwardTravelTime": {"lock": true, "time": 5, "warning": null, "consecutiveTime": 1}, "numberOfStops": 0, "trainrunId": 28, "resourceId": 0, @@ -1853,7 +2028,8 @@ "3": {"x": 784, "y": 316}, "4": {"x": 592, "y": 292}, "5": {"x": 592, "y": 292}, - "6": {"x": 592, "y": 316} + "6": {"x": 592, "y": 316}, + "7": {"x": 592, "y": 316} } }, "warnings": null @@ -1864,11 +2040,14 @@ "sourcePortId": 209, "targetNodeId": 1, "targetPortId": 210, - "travelTime": {"lock": true, "time": 1, "warning": null, "consecutiveTime": 1}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 58, "warning": null, "consecutiveTime": 58}, "sourceArrival": {"lock": false, "time": 2, "warning": null, "consecutiveTime": 2}, "targetDeparture": {"lock": false, "time": 1, "warning": null, "consecutiveTime": 1}, "targetArrival": {"lock": false, "time": 59, "warning": null, "consecutiveTime": 59}, + "travelTime": {"lock": true, "time": 1, "warning": null, "consecutiveTime": 1}, + "backwardTravelTime": {"lock": true, "time": 1, "warning": null, "consecutiveTime": 1}, "numberOfStops": 0, "trainrunId": 29, "resourceId": 0, @@ -1887,7 +2066,8 @@ "3": {"x": 784, "y": 188}, "4": {"x": 592, "y": 164}, "5": {"x": 592, "y": 164}, - "6": {"x": 592, "y": 188} + "6": {"x": 592, "y": 188}, + "7": {"x": 592, "y": 188} } }, "warnings": null @@ -1898,11 +2078,14 @@ "sourcePortId": 212, "targetNodeId": 7, "targetPortId": 211, - "travelTime": {"lock": true, "time": 1, "warning": null, "consecutiveTime": 1}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 57, "warning": null, "consecutiveTime": 57}, "sourceArrival": {"lock": false, "time": 3, "warning": null, "consecutiveTime": 3}, "targetDeparture": {"lock": false, "time": 2, "warning": null, "consecutiveTime": 2}, "targetArrival": {"lock": false, "time": 58, "warning": null, "consecutiveTime": 58}, + "travelTime": {"lock": true, "time": 1, "warning": null, "consecutiveTime": 1}, + "backwardTravelTime": {"lock": true, "time": 1, "warning": null, "consecutiveTime": 1}, "numberOfStops": 0, "trainrunId": 29, "resourceId": 0, @@ -1921,7 +2104,8 @@ "3": {"x": 208, "y": 252}, "4": {"x": 16, "y": 228}, "5": {"x": 16, "y": 228}, - "6": {"x": 16, "y": 252} + "6": {"x": 16, "y": 252}, + "7": {"x": 16, "y": 252} } }, "warnings": null @@ -1932,11 +2116,14 @@ "sourcePortId": 214, "targetNodeId": 8, "targetPortId": 213, - "travelTime": {"lock": true, "time": 1, "warning": null, "consecutiveTime": 1}, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": {"lock": false, "time": 54, "warning": null, "consecutiveTime": 54}, "sourceArrival": {"lock": false, "time": 6, "warning": null, "consecutiveTime": 6}, "targetDeparture": {"lock": false, "time": 5, "warning": null, "consecutiveTime": 5}, "targetArrival": {"lock": false, "time": 55, "warning": null, "consecutiveTime": 55}, + "travelTime": {"lock": true, "time": 1, "warning": null, "consecutiveTime": 1}, + "backwardTravelTime": {"lock": true, "time": 1, "warning": null, "consecutiveTime": 1}, "numberOfStops": 0, "trainrunId": 29, "resourceId": 0, @@ -1955,7 +2142,8 @@ "3": {"x": -368, "y": 252}, "4": {"x": -592, "y": 228}, "5": {"x": -592, "y": 228}, - "6": {"x": -592, "y": 252} + "6": {"x": -592, "y": 252}, + "7": {"x": -592, "y": 252} } }, "warnings": null diff --git a/src/app/sample-netzgrafik/netzgrafik_demo_standalone_github.json b/src/app/sample-netzgrafik/netzgrafik_demo_standalone_github.json index 4b384c6b5..2c57881a3 100644 --- a/src/app/sample-netzgrafik/netzgrafik_demo_standalone_github.json +++ b/src/app/sample-netzgrafik/netzgrafik_demo_standalone_github.json @@ -1894,13 +1894,8 @@ "sourcePortId": 1033, "targetNodeId": 136, "targetPortId": 1034, - "travelTime": { - "lock": true, - "time": 14, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 2, @@ -1929,6 +1924,20 @@ "timeFormatter": null, "consecutiveTime": 196 }, + "travelTime": { + "lock": true, + "time": 14, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 14, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 75, "resourceId": 0, @@ -1947,7 +1956,8 @@ "3": {"x": 2652, "y": 3372}, "4": {"x": 2628, "y": 3518}, "5": {"x": 2628, "y": 3518}, - "6": {"x": 2652, "y": 3518} + "6": {"x": 2652, "y": 3518}, + "7": {"x": 2652, "y": 3518} } }, "warnings": null @@ -1958,13 +1968,8 @@ "sourcePortId": 1035, "targetNodeId": 158, "targetPortId": 1036, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 18, @@ -1993,6 +1998,20 @@ "timeFormatter": null, "consecutiveTime": 204 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 75, "resourceId": 0, @@ -2011,7 +2030,8 @@ "3": {"x": 2652, "y": 2800}, "4": {"x": 2628, "y": 2992}, "5": {"x": 2628, "y": 2992}, - "6": {"x": 2652, "y": 2992} + "6": {"x": 2652, "y": 2992}, + "7": {"x": 2652, "y": 2992} } }, "warnings": null @@ -2022,13 +2042,8 @@ "sourcePortId": 1037, "targetNodeId": 154, "targetPortId": 1038, - "travelTime": { - "lock": true, - "time": 19, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 52, @@ -2057,6 +2072,20 @@ "timeFormatter": null, "consecutiveTime": 251 }, + "travelTime": { + "lock": true, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 75, "resourceId": 0, @@ -2075,7 +2104,8 @@ "3": {"x": 2716, "y": 1932}, "4": {"x": 2692, "y": 2030}, "5": {"x": 2692, "y": 2030}, - "6": {"x": 2716, "y": 2030} + "6": {"x": 2716, "y": 2030}, + "7": {"x": 2716, "y": 2030} } }, "warnings": null @@ -2086,13 +2116,8 @@ "sourcePortId": 1039, "targetNodeId": 169, "targetPortId": 1040, - "travelTime": { - "lock": true, - "time": 18, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 15, @@ -2121,6 +2146,20 @@ "timeFormatter": null, "consecutiveTime": 273 }, + "travelTime": { + "lock": true, + "time": 18, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 18, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 75, "resourceId": 0, @@ -2139,7 +2178,8 @@ "3": {"x": 2000, "y": 1796}, "4": {"x": 2304, "y": 1796}, "5": {"x": 2304, "y": 1796}, - "6": {"x": 2304, "y": 1820} + "6": {"x": 2304, "y": 1796}, + "7": {"x": 2304, "y": 1820} } }, "warnings": null @@ -2150,13 +2190,8 @@ "sourcePortId": 1041, "targetNodeId": 141, "targetPortId": 1042, - "travelTime": { - "lock": true, - "time": 19, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 55, @@ -2185,6 +2220,20 @@ "timeFormatter": null, "consecutiveTime": 314 }, + "travelTime": { + "lock": true, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 75, "resourceId": 0, @@ -2203,7 +2252,8 @@ "3": {"x": 92, "y": 1296}, "4": {"x": 68, "y": 1488}, "5": {"x": 68, "y": 1488}, - "6": {"x": 92, "y": 1488} + "6": {"x": 92, "y": 1488}, + "7": {"x": 92, "y": 1488} } }, "warnings": null @@ -2214,13 +2264,8 @@ "sourcePortId": 1043, "targetNodeId": 143, "targetPortId": 1044, - "travelTime": { - "lock": true, - "time": 9, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 14, @@ -2249,6 +2294,20 @@ "timeFormatter": null, "consecutiveTime": 323 }, + "travelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 75, "resourceId": 0, @@ -2267,7 +2326,8 @@ "3": {"x": 92, "y": 848}, "4": {"x": 68, "y": 992}, "5": {"x": 68, "y": 992}, - "6": {"x": 92, "y": 992} + "6": {"x": 92, "y": 992}, + "7": {"x": 92, "y": 992} } }, "warnings": null @@ -2278,13 +2338,8 @@ "sourcePortId": 1045, "targetNodeId": 133, "targetPortId": 1046, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 23, @@ -2313,6 +2368,20 @@ "timeFormatter": null, "consecutiveTime": 330 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 75, "resourceId": 0, @@ -2331,7 +2400,8 @@ "3": {"x": 92, "y": 396}, "4": {"x": 68, "y": 542}, "5": {"x": 68, "y": 542}, - "6": {"x": 92, "y": 542} + "6": {"x": 92, "y": 542}, + "7": {"x": 92, "y": 542} } }, "warnings": null @@ -2342,13 +2412,8 @@ "sourcePortId": 1047, "targetNodeId": 144, "targetPortId": 1048, - "travelTime": { - "lock": true, - "time": 10, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 32, @@ -2377,6 +2442,20 @@ "timeFormatter": null, "consecutiveTime": 342 }, + "travelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 75, "resourceId": 0, @@ -2395,7 +2474,8 @@ "3": {"x": 92, "y": -308}, "4": {"x": 68, "y": -130}, "5": {"x": 68, "y": -130}, - "6": {"x": 92, "y": -130} + "6": {"x": 92, "y": -130}, + "7": {"x": 92, "y": -130} } }, "warnings": null @@ -2406,13 +2486,8 @@ "sourcePortId": 1049, "targetNodeId": 145, "targetPortId": 1050, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 42, @@ -2441,6 +2516,20 @@ "timeFormatter": null, "consecutiveTime": 347 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 75, "resourceId": 0, @@ -2459,7 +2548,8 @@ "3": {"x": 92, "y": -816}, "4": {"x": 68, "y": -656}, "5": {"x": 68, "y": -656}, - "6": {"x": 92, "y": -656} + "6": {"x": 92, "y": -656}, + "7": {"x": 92, "y": -656} } }, "warnings": null @@ -2470,13 +2560,8 @@ "sourcePortId": 1051, "targetNodeId": 146, "targetPortId": 1052, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 47, @@ -2505,6 +2590,20 @@ "timeFormatter": null, "consecutiveTime": 352 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 75, "resourceId": 0, @@ -2523,7 +2622,8 @@ "3": {"x": 92, "y": -1296}, "4": {"x": 68, "y": -1136}, "5": {"x": 68, "y": -1136}, - "6": {"x": 92, "y": -1136} + "6": {"x": 92, "y": -1136}, + "7": {"x": 92, "y": -1136} } }, "warnings": null @@ -2534,13 +2634,8 @@ "sourcePortId": 1053, "targetNodeId": 134, "targetPortId": 1054, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 52, @@ -2569,6 +2664,20 @@ "timeFormatter": null, "consecutiveTime": 357 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 75, "resourceId": 0, @@ -2587,7 +2696,8 @@ "3": {"x": 92, "y": -1776}, "4": {"x": 68, "y": -1616}, "5": {"x": 68, "y": -1616}, - "6": {"x": 92, "y": -1616} + "6": {"x": 92, "y": -1616}, + "7": {"x": 92, "y": -1616} } }, "warnings": null @@ -2598,13 +2708,8 @@ "sourcePortId": 1056, "targetNodeId": 155, "targetPortId": 1055, - "travelTime": { - "lock": true, - "time": 28, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 24, @@ -2633,6 +2738,20 @@ "timeFormatter": null, "consecutiveTime": 232 }, + "travelTime": { + "lock": true, + "time": 28, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 28, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 75, "resourceId": 0, @@ -2651,7 +2770,8 @@ "3": {"x": 2716, "y": 2316}, "4": {"x": 2692, "y": 2478}, "5": {"x": 2692, "y": 2478}, - "6": {"x": 2716, "y": 2478} + "6": {"x": 2716, "y": 2478}, + "7": {"x": 2716, "y": 2478} } }, "warnings": null @@ -2662,13 +2782,8 @@ "sourcePortId": 1057, "targetNodeId": 136, "targetPortId": 1058, - "travelTime": { - "lock": true, - "time": 14, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 2, @@ -2697,15 +2812,29 @@ "timeFormatter": null, "consecutiveTime": 16 }, - "numberOfStops": 0, - "trainrunId": 76, - "resourceId": 0, - "specificTrainrunSectionFrequencyId": null, - "path": { - "path": [ - {"x": 2608, "y": 3710}, - {"x": 2608, "y": 3646}, - {"x": 2608, "y": 3390}, + "travelTime": { + "lock": true, + "time": 14, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 14, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "numberOfStops": 0, + "trainrunId": 76, + "resourceId": 0, + "specificTrainrunSectionFrequencyId": null, + "path": { + "path": [ + {"x": 2608, "y": 3710}, + {"x": 2608, "y": 3646}, + {"x": 2608, "y": 3390}, {"x": 2608, "y": 3326} ], "textPositions": { @@ -2715,7 +2844,8 @@ "3": {"x": 2620, "y": 3372}, "4": {"x": 2596, "y": 3518}, "5": {"x": 2596, "y": 3518}, - "6": {"x": 2620, "y": 3518} + "6": {"x": 2620, "y": 3518}, + "7": {"x": 2620, "y": 3518} } }, "warnings": null @@ -2726,13 +2856,8 @@ "sourcePortId": 1059, "targetNodeId": 158, "targetPortId": 1060, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 18, @@ -2761,6 +2886,20 @@ "timeFormatter": null, "consecutiveTime": 24 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 76, "resourceId": 0, @@ -2779,7 +2918,8 @@ "3": {"x": 2620, "y": 2800}, "4": {"x": 2596, "y": 2992}, "5": {"x": 2596, "y": 2992}, - "6": {"x": 2620, "y": 2992} + "6": {"x": 2620, "y": 2992}, + "7": {"x": 2620, "y": 2992} } }, "warnings": null @@ -2790,13 +2930,8 @@ "sourcePortId": 1061, "targetNodeId": 155, "targetPortId": 1062, - "travelTime": { - "lock": true, - "time": 28, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 24, @@ -2825,6 +2960,20 @@ "timeFormatter": null, "consecutiveTime": 52 }, + "travelTime": { + "lock": true, + "time": 28, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 28, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 76, "resourceId": 0, @@ -2843,7 +2992,8 @@ "3": {"x": 2684, "y": 2316}, "4": {"x": 2660, "y": 2478}, "5": {"x": 2660, "y": 2478}, - "6": {"x": 2684, "y": 2478} + "6": {"x": 2684, "y": 2478}, + "7": {"x": 2684, "y": 2478} } }, "warnings": null @@ -2854,13 +3004,8 @@ "sourcePortId": 1063, "targetNodeId": 154, "targetPortId": 1064, - "travelTime": { - "lock": false, - "time": 19, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 52, @@ -2889,6 +3034,20 @@ "timeFormatter": null, "consecutiveTime": 71 }, + "travelTime": { + "lock": false, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 76, "resourceId": 0, @@ -2907,7 +3066,8 @@ "3": {"x": 2684, "y": 1932}, "4": {"x": 2660, "y": 2030}, "5": {"x": 2660, "y": 2030}, - "6": {"x": 2684, "y": 2030} + "6": {"x": 2684, "y": 2030}, + "7": {"x": 2684, "y": 2030} } }, "warnings": null @@ -2918,13 +3078,8 @@ "sourcePortId": 1065, "targetNodeId": 153, "targetPortId": 1066, - "travelTime": { - "lock": true, - "time": 15, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 15, @@ -2953,6 +3108,20 @@ "timeFormatter": null, "consecutiveTime": 90 }, + "travelTime": { + "lock": true, + "time": 15, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 15, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 76, "resourceId": 0, @@ -2971,7 +3140,8 @@ "3": {"x": 2684, "y": 1452}, "4": {"x": 2660, "y": 1598}, "5": {"x": 2660, "y": 1598}, - "6": {"x": 2684, "y": 1598} + "6": {"x": 2684, "y": 1598}, + "7": {"x": 2684, "y": 1598} } }, "warnings": null @@ -2982,13 +3152,8 @@ "sourcePortId": 1067, "targetNodeId": 170, "targetPortId": 1068, - "travelTime": { - "lock": true, - "time": 16, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 31, @@ -3017,6 +3182,20 @@ "timeFormatter": null, "consecutiveTime": 107 }, + "travelTime": { + "lock": true, + "time": 16, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 16, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 76, "resourceId": 0, @@ -3035,7 +3214,8 @@ "3": {"x": 2684, "y": 876}, "4": {"x": 2660, "y": 1070}, "5": {"x": 2660, "y": 1070}, - "6": {"x": 2684, "y": 1070} + "6": {"x": 2684, "y": 1070}, + "7": {"x": 2684, "y": 1070} } }, "warnings": null @@ -3046,13 +3226,8 @@ "sourcePortId": 1069, "targetNodeId": 136, "targetPortId": 1070, - "travelTime": { - "lock": true, - "time": 23, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 33, @@ -3081,6 +3256,20 @@ "timeFormatter": null, "consecutiveTime": 296 }, + "travelTime": { + "lock": true, + "time": 23, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 23, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 77, "resourceId": 0, @@ -3099,7 +3288,8 @@ "3": {"x": 2544, "y": 3260}, "4": {"x": 2448, "y": 3236}, "5": {"x": 2448, "y": 3236}, - "6": {"x": 2448, "y": 3260} + "6": {"x": 2448, "y": 3260}, + "7": {"x": 2448, "y": 3260} } }, "warnings": null @@ -3110,13 +3300,8 @@ "sourcePortId": 1071, "targetNodeId": 158, "targetPortId": 1072, - "travelTime": { - "lock": true, - "time": 15, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 0, @@ -3145,6 +3330,20 @@ "timeFormatter": null, "consecutiveTime": 315 }, + "travelTime": { + "lock": true, + "time": 15, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 15, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 77, "resourceId": 0, @@ -3163,7 +3362,8 @@ "3": {"x": 2684, "y": 2800}, "4": {"x": 2660, "y": 2992}, "5": {"x": 2660, "y": 2992}, - "6": {"x": 2684, "y": 2992} + "6": {"x": 2684, "y": 2992}, + "7": {"x": 2684, "y": 2992} } }, "warnings": null @@ -3174,13 +3374,8 @@ "sourcePortId": 1073, "targetNodeId": 159, "targetPortId": 1074, - "travelTime": { - "lock": true, - "time": 53, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 16, @@ -3209,6 +3404,20 @@ "timeFormatter": null, "consecutiveTime": 369 }, + "travelTime": { + "lock": true, + "time": 53, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 53, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 5, "trainrunId": 77, "resourceId": 0, @@ -3227,7 +3436,8 @@ "3": {"x": 2300, "y": 2380}, "4": {"x": 2460, "y": 2510}, "5": {"x": 2460, "y": 2510}, - "6": {"x": 2436, "y": 2510} + "6": {"x": 2460, "y": 2510}, + "7": {"x": 2436, "y": 2510} } }, "warnings": null @@ -3238,13 +3448,8 @@ "sourcePortId": 1075, "targetNodeId": 155, "targetPortId": 1076, - "travelTime": { - "lock": true, - "time": 32, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 10, @@ -3273,6 +3478,20 @@ "timeFormatter": null, "consecutiveTime": 402 }, + "travelTime": { + "lock": true, + "time": 32, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 32, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 1, "trainrunId": 77, "resourceId": 0, @@ -3291,7 +3510,8 @@ "3": {"x": 2608, "y": 2204}, "4": {"x": 2512, "y": 2212}, "5": {"x": 2512, "y": 2212}, - "6": {"x": 2512, "y": 2236} + "6": {"x": 2512, "y": 2236}, + "7": {"x": 2512, "y": 2236} } }, "warnings": null @@ -3302,13 +3522,8 @@ "sourcePortId": 1077, "targetNodeId": 154, "targetPortId": 1078, - "travelTime": { - "lock": true, - "time": 23, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 43, @@ -3337,6 +3552,20 @@ "timeFormatter": null, "consecutiveTime": 426 }, + "travelTime": { + "lock": true, + "time": 23, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 23, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 3, "trainrunId": 77, "resourceId": 0, @@ -3355,7 +3584,8 @@ "3": {"x": 2748, "y": 1932}, "4": {"x": 2724, "y": 2030}, "5": {"x": 2724, "y": 2030}, - "6": {"x": 2748, "y": 2030} + "6": {"x": 2748, "y": 2030}, + "7": {"x": 2748, "y": 2030} } }, "warnings": null @@ -3366,13 +3596,8 @@ "sourcePortId": 1079, "targetNodeId": 169, "targetPortId": 1080, - "travelTime": { - "lock": true, - "time": 18, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 15, @@ -3401,6 +3626,20 @@ "timeFormatter": null, "consecutiveTime": 453 }, + "travelTime": { + "lock": true, + "time": 18, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 18, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 77, "resourceId": 0, @@ -3419,7 +3658,8 @@ "3": {"x": 2000, "y": 1828}, "4": {"x": 2304, "y": 1828}, "5": {"x": 2304, "y": 1828}, - "6": {"x": 2304, "y": 1852} + "6": {"x": 2304, "y": 1828}, + "7": {"x": 2304, "y": 1852} } }, "warnings": null @@ -3430,13 +3670,8 @@ "sourcePortId": 1081, "targetNodeId": 136, "targetPortId": 1082, - "travelTime": { - "lock": true, - "time": 23, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 33, @@ -3465,6 +3700,20 @@ "timeFormatter": null, "consecutiveTime": 176 }, + "travelTime": { + "lock": true, + "time": 23, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 23, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 3, "trainrunId": 78, "resourceId": 0, @@ -3483,7 +3732,8 @@ "3": {"x": 2544, "y": 3292}, "4": {"x": 2448, "y": 3268}, "5": {"x": 2448, "y": 3268}, - "6": {"x": 2448, "y": 3292} + "6": {"x": 2448, "y": 3292}, + "7": {"x": 2448, "y": 3292} } }, "warnings": null @@ -3494,13 +3744,8 @@ "sourcePortId": 1083, "targetNodeId": 158, "targetPortId": 1084, - "travelTime": { - "lock": true, - "time": 15, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 0, @@ -3529,6 +3774,20 @@ "timeFormatter": null, "consecutiveTime": 195 }, + "travelTime": { + "lock": true, + "time": 15, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 15, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 1, "trainrunId": 78, "resourceId": 0, @@ -3547,7 +3806,8 @@ "3": {"x": 2716, "y": 2800}, "4": {"x": 2692, "y": 2992}, "5": {"x": 2692, "y": 2992}, - "6": {"x": 2716, "y": 2992} + "6": {"x": 2716, "y": 2992}, + "7": {"x": 2716, "y": 2992} } }, "warnings": null @@ -3558,13 +3818,8 @@ "sourcePortId": 1085, "targetNodeId": 159, "targetPortId": 1086, - "travelTime": { - "lock": true, - "time": 53, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 16, @@ -3593,6 +3848,20 @@ "timeFormatter": null, "consecutiveTime": 249 }, + "travelTime": { + "lock": true, + "time": 53, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 53, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 5, "trainrunId": 78, "resourceId": 0, @@ -3611,7 +3880,8 @@ "3": {"x": 2332, "y": 2380}, "4": {"x": 2492, "y": 2510}, "5": {"x": 2492, "y": 2510}, - "6": {"x": 2468, "y": 2510} + "6": {"x": 2492, "y": 2510}, + "7": {"x": 2468, "y": 2510} } }, "warnings": null @@ -3619,16 +3889,11 @@ { "id": 536, "sourceNodeId": 159, - "sourcePortId": 1087, - "targetNodeId": 155, - "targetPortId": 1088, - "travelTime": { - "lock": true, - "time": 32, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourcePortId": 1087, + "targetNodeId": 155, + "targetPortId": 1088, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 10, @@ -3657,6 +3922,20 @@ "timeFormatter": null, "consecutiveTime": 282 }, + "travelTime": { + "lock": true, + "time": 32, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 32, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 1, "trainrunId": 78, "resourceId": 0, @@ -3675,7 +3954,8 @@ "3": {"x": 2608, "y": 2236}, "4": {"x": 2512, "y": 2244}, "5": {"x": 2512, "y": 2244}, - "6": {"x": 2512, "y": 2268} + "6": {"x": 2512, "y": 2268}, + "7": {"x": 2512, "y": 2268} } }, "warnings": null @@ -3686,13 +3966,8 @@ "sourcePortId": 1089, "targetNodeId": 154, "targetPortId": 1090, - "travelTime": { - "lock": false, - "time": 23, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 43, @@ -3721,6 +3996,20 @@ "timeFormatter": null, "consecutiveTime": 306 }, + "travelTime": { + "lock": false, + "time": 23, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 23, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 3, "trainrunId": 78, "resourceId": 0, @@ -3739,7 +4028,8 @@ "3": {"x": 2780, "y": 1932}, "4": {"x": 2756, "y": 2030}, "5": {"x": 2756, "y": 2030}, - "6": {"x": 2780, "y": 2030} + "6": {"x": 2780, "y": 2030}, + "7": {"x": 2780, "y": 2030} } }, "warnings": null @@ -3750,13 +4040,8 @@ "sourcePortId": 1091, "targetNodeId": 153, "targetPortId": 1092, - "travelTime": { - "lock": true, - "time": 15, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 15, @@ -3785,6 +4070,20 @@ "timeFormatter": null, "consecutiveTime": 330 }, + "travelTime": { + "lock": true, + "time": 15, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 15, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 78, "resourceId": 0, @@ -3803,7 +4102,8 @@ "3": {"x": 2716, "y": 1452}, "4": {"x": 2692, "y": 1598}, "5": {"x": 2692, "y": 1598}, - "6": {"x": 2716, "y": 1598} + "6": {"x": 2716, "y": 1598}, + "7": {"x": 2716, "y": 1598} } }, "warnings": null @@ -3814,13 +4114,8 @@ "sourcePortId": 1093, "targetNodeId": 170, "targetPortId": 1094, - "travelTime": { - "lock": true, - "time": 16, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 31, @@ -3849,6 +4144,20 @@ "timeFormatter": null, "consecutiveTime": 347 }, + "travelTime": { + "lock": true, + "time": 16, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 16, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 78, "resourceId": 0, @@ -3867,7 +4176,8 @@ "3": {"x": 2716, "y": 876}, "4": {"x": 2692, "y": 1070}, "5": {"x": 2692, "y": 1070}, - "6": {"x": 2716, "y": 1070} + "6": {"x": 2716, "y": 1070}, + "7": {"x": 2716, "y": 1070} } }, "warnings": null @@ -3878,13 +4188,8 @@ "sourcePortId": 1095, "targetNodeId": 169, "targetPortId": 1096, - "travelTime": { - "lock": false, - "time": 12, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 35, @@ -3913,6 +4218,20 @@ "timeFormatter": null, "consecutiveTime": 47 }, + "travelTime": { + "lock": false, + "time": 12, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 12, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 79, "resourceId": 0, @@ -3931,7 +4250,8 @@ "3": {"x": 1808, "y": 1852}, "4": {"x": 1040, "y": 1828}, "5": {"x": 1040, "y": 1828}, - "6": {"x": 1040, "y": 1852} + "6": {"x": 1040, "y": 1852}, + "7": {"x": 1040, "y": 1852} } }, "warnings": null @@ -3942,13 +4262,8 @@ "sourcePortId": 1097, "targetNodeId": 170, "targetPortId": 1098, - "travelTime": { - "lock": false, - "time": 15, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 58, @@ -3977,6 +4292,20 @@ "timeFormatter": null, "consecutiveTime": 73 }, + "travelTime": { + "lock": false, + "time": 15, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 15, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 1, "trainrunId": 79, "resourceId": 0, @@ -3995,7 +4324,8 @@ "3": {"x": 2780, "y": 876}, "4": {"x": 2756, "y": 1070}, "5": {"x": 2756, "y": 1070}, - "6": {"x": 2780, "y": 1070} + "6": {"x": 2780, "y": 1070}, + "7": {"x": 2780, "y": 1070} } }, "warnings": null @@ -4006,13 +4336,8 @@ "sourcePortId": 1099, "targetNodeId": 169, "targetPortId": 1100, - "travelTime": { - "lock": true, - "time": 9, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 9, @@ -4041,6 +4366,20 @@ "timeFormatter": null, "consecutiveTime": 18 }, + "travelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 80, "resourceId": 0, @@ -4059,7 +4398,8 @@ "3": {"x": 1808, "y": 1820}, "4": {"x": 1040, "y": 1796}, "5": {"x": 1040, "y": 1796}, - "6": {"x": 1040, "y": 1820} + "6": {"x": 1040, "y": 1820}, + "7": {"x": 1040, "y": 1820} } }, "warnings": null @@ -4070,13 +4410,8 @@ "sourcePortId": 1101, "targetNodeId": 170, "targetPortId": 1102, - "travelTime": { - "lock": true, - "time": 14, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 29, @@ -4105,6 +4440,20 @@ "timeFormatter": null, "consecutiveTime": 43 }, + "travelTime": { + "lock": true, + "time": 14, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 14, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 80, "resourceId": 0, @@ -4123,7 +4472,8 @@ "3": {"x": 2748, "y": 876}, "4": {"x": 2724, "y": 1070}, "5": {"x": 2724, "y": 1070}, - "6": {"x": 2748, "y": 1070} + "6": {"x": 2748, "y": 1070}, + "7": {"x": 2748, "y": 1070} } }, "warnings": null @@ -4134,13 +4484,8 @@ "sourcePortId": 1103, "targetNodeId": 141, "targetPortId": 1104, - "travelTime": { - "lock": true, - "time": 19, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 59, @@ -4169,6 +4514,20 @@ "timeFormatter": null, "consecutiveTime": 318 }, + "travelTime": { + "lock": true, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 81, "resourceId": 0, @@ -4187,7 +4546,8 @@ "3": {"x": 124, "y": 1296}, "4": {"x": 100, "y": 1488}, "5": {"x": 100, "y": 1488}, - "6": {"x": 124, "y": 1488} + "6": {"x": 124, "y": 1488}, + "7": {"x": 124, "y": 1488} } }, "warnings": null @@ -4198,13 +4558,8 @@ "sourcePortId": 1105, "targetNodeId": 143, "targetPortId": 1106, - "travelTime": { - "lock": true, - "time": 12, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 19, @@ -4233,6 +4588,20 @@ "timeFormatter": null, "consecutiveTime": 331 }, + "travelTime": { + "lock": true, + "time": 12, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 12, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 81, "resourceId": 0, @@ -4251,7 +4620,8 @@ "3": {"x": 124, "y": 848}, "4": {"x": 100, "y": 992}, "5": {"x": 100, "y": 992}, - "6": {"x": 124, "y": 992} + "6": {"x": 124, "y": 992}, + "7": {"x": 124, "y": 992} } }, "warnings": null @@ -4262,13 +4632,8 @@ "sourcePortId": 1107, "targetNodeId": 172, "targetPortId": 1108, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 32, @@ -4297,6 +4662,20 @@ "timeFormatter": null, "consecutiveTime": 339 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 81, "resourceId": 0, @@ -4315,7 +4694,8 @@ "3": {"x": -464, "y": 324}, "4": {"x": -224, "y": 532}, "5": {"x": -224, "y": 532}, - "6": {"x": -224, "y": 556} + "6": {"x": -224, "y": 532}, + "7": {"x": -224, "y": 556} } }, "warnings": null @@ -4326,13 +4706,8 @@ "sourcePortId": 1109, "targetNodeId": 171, "targetPortId": 1110, - "travelTime": { - "lock": false, - "time": 22, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 4, @@ -4361,6 +4736,20 @@ "timeFormatter": null, "consecutiveTime": 386 }, + "travelTime": { + "lock": false, + "time": 22, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 22, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 81, "resourceId": 0, @@ -4379,7 +4768,8 @@ "3": {"x": -2416, "y": 324}, "4": {"x": -2304, "y": 244}, "5": {"x": -2304, "y": 244}, - "6": {"x": -2304, "y": 268} + "6": {"x": -2304, "y": 244}, + "7": {"x": -2304, "y": 268} } }, "warnings": null @@ -4390,13 +4780,8 @@ "sourcePortId": 1111, "targetNodeId": 141, "targetPortId": 1112, - "travelTime": { - "lock": true, - "time": 18, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 30, @@ -4418,12 +4803,26 @@ "timeFormatter": null, "consecutiveTime": 72 }, - "targetArrival": { + "targetArrival": { + "lock": true, + "time": 48, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 108 + }, + "travelTime": { + "lock": true, + "time": 18, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { "lock": true, - "time": 48, + "time": 18, "warning": null, "timeFormatter": null, - "consecutiveTime": 108 + "consecutiveTime": 1 }, "numberOfStops": 0, "trainrunId": 82, @@ -4443,7 +4842,8 @@ "3": {"x": 220, "y": 1296}, "4": {"x": 196, "y": 1488}, "5": {"x": 196, "y": 1488}, - "6": {"x": 220, "y": 1488} + "6": {"x": 220, "y": 1488}, + "7": {"x": 220, "y": 1488} } }, "warnings": null @@ -4454,13 +4854,8 @@ "sourcePortId": 1113, "targetNodeId": 143, "targetPortId": 1114, - "travelTime": { - "lock": true, - "time": 13, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 49, @@ -4489,6 +4884,20 @@ "timeFormatter": null, "consecutiveTime": 122 }, + "travelTime": { + "lock": true, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 82, "resourceId": 0, @@ -4507,7 +4916,8 @@ "3": {"x": 220, "y": 848}, "4": {"x": 196, "y": 992}, "5": {"x": 196, "y": 992}, - "6": {"x": 220, "y": 992} + "6": {"x": 220, "y": 992}, + "7": {"x": 220, "y": 992} } }, "warnings": null @@ -4518,13 +4928,8 @@ "sourcePortId": 1115, "targetNodeId": 133, "targetPortId": 1116, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 4, @@ -4553,6 +4958,20 @@ "timeFormatter": null, "consecutiveTime": 131 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 82, "resourceId": 0, @@ -4571,7 +4990,8 @@ "3": {"x": 188, "y": 396}, "4": {"x": 164, "y": 542}, "5": {"x": 164, "y": 542}, - "6": {"x": 188, "y": 542} + "6": {"x": 188, "y": 542}, + "7": {"x": 188, "y": 542} } }, "warnings": null @@ -4582,13 +5002,8 @@ "sourcePortId": 1117, "targetNodeId": 144, "targetPortId": 1118, - "travelTime": { - "lock": true, - "time": 10, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 12, @@ -4617,6 +5032,20 @@ "timeFormatter": null, "consecutiveTime": 142 }, + "travelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 82, "resourceId": 0, @@ -4635,7 +5064,8 @@ "3": {"x": 252, "y": -308}, "4": {"x": 228, "y": -130}, "5": {"x": 228, "y": -130}, - "6": {"x": 252, "y": -130} + "6": {"x": 252, "y": -130}, + "7": {"x": 252, "y": -130} } }, "warnings": null @@ -4646,13 +5076,8 @@ "sourcePortId": 1119, "targetNodeId": 145, "targetPortId": 1120, - "travelTime": { - "lock": true, - "time": 4, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 23, @@ -4681,6 +5106,20 @@ "timeFormatter": null, "consecutiveTime": 147 }, + "travelTime": { + "lock": true, + "time": 4, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 4, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 82, "resourceId": 0, @@ -4699,7 +5138,8 @@ "3": {"x": 316, "y": -816}, "4": {"x": 292, "y": -656}, "5": {"x": 292, "y": -656}, - "6": {"x": 316, "y": -656} + "6": {"x": 316, "y": -656}, + "7": {"x": 316, "y": -656} } }, "warnings": null @@ -4710,13 +5150,8 @@ "sourcePortId": 1121, "targetNodeId": 146, "targetPortId": 1122, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 28, @@ -4745,6 +5180,20 @@ "timeFormatter": null, "consecutiveTime": 153 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 82, "resourceId": 0, @@ -4763,7 +5212,8 @@ "3": {"x": 316, "y": -1296}, "4": {"x": 292, "y": -1136}, "5": {"x": 292, "y": -1136}, - "6": {"x": 316, "y": -1136} + "6": {"x": 316, "y": -1136}, + "7": {"x": 316, "y": -1136} } }, "warnings": null @@ -4774,13 +5224,8 @@ "sourcePortId": 1123, "targetNodeId": 134, "targetPortId": 1124, - "travelTime": { - "lock": true, - "time": 10, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 34, @@ -4809,6 +5254,20 @@ "timeFormatter": null, "consecutiveTime": 164 }, + "travelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 82, "resourceId": 0, @@ -4827,7 +5286,8 @@ "3": {"x": 316, "y": -1776}, "4": {"x": 292, "y": -1616}, "5": {"x": 292, "y": -1616}, - "6": {"x": 316, "y": -1616} + "6": {"x": 316, "y": -1616}, + "7": {"x": 316, "y": -1616} } }, "warnings": null @@ -4838,13 +5298,8 @@ "sourcePortId": 1125, "targetNodeId": 141, "targetPortId": 1126, - "travelTime": { - "lock": true, - "time": 19, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 55, @@ -4873,6 +5328,20 @@ "timeFormatter": null, "consecutiveTime": 134 }, + "travelTime": { + "lock": true, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 83, "resourceId": 0, @@ -4891,7 +5360,8 @@ "3": {"x": 188, "y": 1296}, "4": {"x": 164, "y": 1488}, "5": {"x": 164, "y": 1488}, - "6": {"x": 188, "y": 1488} + "6": {"x": 188, "y": 1488}, + "7": {"x": 188, "y": 1488} } }, "warnings": null @@ -4902,13 +5372,8 @@ "sourcePortId": 1127, "targetNodeId": 143, "targetPortId": 1128, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 14, @@ -4937,6 +5402,20 @@ "timeFormatter": null, "consecutiveTime": 142 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 83, "resourceId": 0, @@ -4955,7 +5434,8 @@ "3": {"x": 188, "y": 848}, "4": {"x": 164, "y": 992}, "5": {"x": 164, "y": 992}, - "6": {"x": 188, "y": 992} + "6": {"x": 188, "y": 992}, + "7": {"x": 188, "y": 992} } }, "warnings": null @@ -4966,13 +5446,8 @@ "sourcePortId": 1129, "targetNodeId": 133, "targetPortId": 1130, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 22, @@ -5001,6 +5476,20 @@ "timeFormatter": null, "consecutiveTime": 150 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 83, "resourceId": 0, @@ -5019,7 +5508,8 @@ "3": {"x": 156, "y": 396}, "4": {"x": 132, "y": 542}, "5": {"x": 132, "y": 542}, - "6": {"x": 156, "y": 542} + "6": {"x": 156, "y": 542}, + "7": {"x": 156, "y": 542} } }, "warnings": null @@ -5030,13 +5520,8 @@ "sourcePortId": 1131, "targetNodeId": 144, "targetPortId": 1132, - "travelTime": { - "lock": true, - "time": 10, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 32, @@ -5065,6 +5550,20 @@ "timeFormatter": null, "consecutiveTime": 162 }, + "travelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 83, "resourceId": 0, @@ -5083,7 +5582,8 @@ "3": {"x": 220, "y": -308}, "4": {"x": 196, "y": -130}, "5": {"x": 196, "y": -130}, - "6": {"x": 220, "y": -130} + "6": {"x": 220, "y": -130}, + "7": {"x": 220, "y": -130} } }, "warnings": null @@ -5094,13 +5594,8 @@ "sourcePortId": 1133, "targetNodeId": 145, "targetPortId": 1134, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 42, @@ -5129,6 +5624,20 @@ "timeFormatter": null, "consecutiveTime": 167 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 83, "resourceId": 0, @@ -5147,7 +5656,8 @@ "3": {"x": 284, "y": -816}, "4": {"x": 260, "y": -656}, "5": {"x": 260, "y": -656}, - "6": {"x": 284, "y": -656} + "6": {"x": 284, "y": -656}, + "7": {"x": 284, "y": -656} } }, "warnings": null @@ -5158,13 +5668,8 @@ "sourcePortId": 1135, "targetNodeId": 146, "targetPortId": 1136, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 47, @@ -5193,6 +5698,20 @@ "timeFormatter": null, "consecutiveTime": 172 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 83, "resourceId": 0, @@ -5211,7 +5730,8 @@ "3": {"x": 284, "y": -1296}, "4": {"x": 260, "y": -1136}, "5": {"x": 260, "y": -1136}, - "6": {"x": 284, "y": -1136} + "6": {"x": 284, "y": -1136}, + "7": {"x": 284, "y": -1136} } }, "warnings": null @@ -5219,16 +5739,11 @@ { "id": 561, "sourceNodeId": 146, - "sourcePortId": 1137, - "targetNodeId": 134, - "targetPortId": 1138, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourcePortId": 1137, + "targetNodeId": 134, + "targetPortId": 1138, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 52, @@ -5257,6 +5772,20 @@ "timeFormatter": null, "consecutiveTime": 177 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 83, "resourceId": 0, @@ -5275,7 +5804,8 @@ "3": {"x": 284, "y": -1776}, "4": {"x": 260, "y": -1616}, "5": {"x": 260, "y": -1616}, - "6": {"x": 284, "y": -1616} + "6": {"x": 284, "y": -1616}, + "7": {"x": 284, "y": -1616} } }, "warnings": null @@ -5286,13 +5816,8 @@ "sourcePortId": 1139, "targetNodeId": 150, "targetPortId": 1140, - "travelTime": { - "lock": true, - "time": 12, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 9, @@ -5321,6 +5846,20 @@ "timeFormatter": null, "consecutiveTime": 21 }, + "travelTime": { + "lock": true, + "time": 12, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 12, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 1, "trainrunId": 84, "resourceId": 0, @@ -5339,7 +5878,8 @@ "3": {"x": 3248, "y": 188}, "4": {"x": 3072, "y": 164}, "5": {"x": 3072, "y": 164}, - "6": {"x": 3072, "y": 188} + "6": {"x": 3072, "y": 188}, + "7": {"x": 3072, "y": 188} } }, "warnings": null @@ -5350,13 +5890,8 @@ "sourcePortId": 1141, "targetNodeId": 151, "targetPortId": 1142, - "travelTime": { - "lock": true, - "time": 13, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 23, @@ -5385,6 +5920,20 @@ "timeFormatter": null, "consecutiveTime": 36 }, + "travelTime": { + "lock": true, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 84, "resourceId": 0, @@ -5403,7 +5952,8 @@ "3": {"x": 3824, "y": 188}, "4": {"x": 3632, "y": 164}, "5": {"x": 3632, "y": 164}, - "6": {"x": 3632, "y": 188} + "6": {"x": 3632, "y": 188}, + "7": {"x": 3632, "y": 188} } }, "warnings": null @@ -5414,13 +5964,8 @@ "sourcePortId": 1143, "targetNodeId": 137, "targetPortId": 1144, - "travelTime": { - "lock": true, - "time": 44, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 38, @@ -5449,6 +5994,20 @@ "timeFormatter": null, "consecutiveTime": 82 }, + "travelTime": { + "lock": true, + "time": 44, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 44, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 4, "trainrunId": 84, "resourceId": 0, @@ -5467,7 +6026,8 @@ "3": {"x": 4592, "y": 188}, "4": {"x": 4304, "y": 164}, "5": {"x": 4304, "y": 164}, - "6": {"x": 4304, "y": 188} + "6": {"x": 4304, "y": 188}, + "7": {"x": 4304, "y": 188} } }, "warnings": null @@ -5478,13 +6038,8 @@ "sourcePortId": 1145, "targetNodeId": 140, "targetPortId": 1146, - "travelTime": { - "lock": true, - "time": 61, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 24, @@ -5513,6 +6068,20 @@ "timeFormatter": null, "consecutiveTime": 145 }, + "travelTime": { + "lock": true, + "time": 61, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 61, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 5, "trainrunId": 84, "resourceId": 0, @@ -5531,7 +6100,8 @@ "3": {"x": 4644, "y": 1136}, "4": {"x": 4644, "y": 702}, "5": {"x": 4644, "y": 702}, - "6": {"x": 4668, "y": 702} + "6": {"x": 4644, "y": 702}, + "7": {"x": 4668, "y": 702} } }, "warnings": null @@ -5542,13 +6112,8 @@ "sourcePortId": 1147, "targetNodeId": 152, "targetPortId": 1148, - "travelTime": { - "lock": true, - "time": 22, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 26, @@ -5577,6 +6142,20 @@ "timeFormatter": null, "consecutiveTime": 168 }, + "travelTime": { + "lock": true, + "time": 22, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 22, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 2, "trainrunId": 84, "resourceId": 0, @@ -5595,7 +6174,8 @@ "3": {"x": 4676, "y": 1840}, "4": {"x": 4676, "y": 1582}, "5": {"x": 4676, "y": 1582}, - "6": {"x": 4700, "y": 1582} + "6": {"x": 4676, "y": 1582}, + "7": {"x": 4700, "y": 1582} } }, "warnings": null @@ -5606,13 +6186,8 @@ "sourcePortId": 1149, "targetNodeId": 170, "targetPortId": 1150, - "travelTime": { - "lock": false, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 7, @@ -5641,6 +6216,20 @@ "timeFormatter": null, "consecutiveTime": 75 }, + "travelTime": { + "lock": false, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 85, "resourceId": 0, @@ -5659,7 +6248,8 @@ "3": {"x": 2692, "y": 688}, "4": {"x": 2692, "y": 542}, "5": {"x": 2692, "y": 542}, - "6": {"x": 2716, "y": 542} + "6": {"x": 2692, "y": 542}, + "7": {"x": 2716, "y": 542} } }, "warnings": null @@ -5670,13 +6260,8 @@ "sourcePortId": 1151, "targetNodeId": 152, "targetPortId": 1152, - "travelTime": { - "lock": true, - "time": 19, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 3, @@ -5705,6 +6290,20 @@ "timeFormatter": null, "consecutiveTime": 142 }, + "travelTime": { + "lock": true, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 1, "trainrunId": 85, "resourceId": 0, @@ -5723,7 +6322,8 @@ "3": {"x": 4644, "y": 1840}, "4": {"x": 4644, "y": 1582}, "5": {"x": 4644, "y": 1582}, - "6": {"x": 4668, "y": 1582} + "6": {"x": 4644, "y": 1582}, + "7": {"x": 4668, "y": 1582} } }, "warnings": null @@ -5734,13 +6334,8 @@ "sourcePortId": 1153, "targetNodeId": 170, "targetPortId": 1154, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 12, @@ -5769,6 +6364,20 @@ "timeFormatter": null, "consecutiveTime": 140 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 86, "resourceId": 0, @@ -5787,7 +6396,8 @@ "3": {"x": 2724, "y": 688}, "4": {"x": 2724, "y": 542}, "5": {"x": 2724, "y": 542}, - "6": {"x": 2748, "y": 542} + "6": {"x": 2724, "y": 542}, + "7": {"x": 2748, "y": 542} } }, "warnings": null @@ -5798,13 +6408,8 @@ "sourcePortId": 1155, "targetNodeId": 152, "targetPortId": 1156, - "travelTime": { - "lock": true, - "time": 20, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 23, @@ -5833,6 +6438,20 @@ "timeFormatter": null, "consecutiveTime": 223 }, + "travelTime": { + "lock": true, + "time": 20, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 20, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 1, "trainrunId": 86, "resourceId": 0, @@ -5851,7 +6470,8 @@ "3": {"x": 4708, "y": 1840}, "4": {"x": 4708, "y": 1582}, "5": {"x": 4708, "y": 1582}, - "6": {"x": 4732, "y": 1582} + "6": {"x": 4708, "y": 1582}, + "7": {"x": 4732, "y": 1582} } }, "warnings": null @@ -5862,13 +6482,8 @@ "sourcePortId": 1158, "targetNodeId": 135, "targetPortId": 1157, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 59, @@ -5897,6 +6512,20 @@ "timeFormatter": null, "consecutiveTime": 126 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 1, "trainrunId": 86, "resourceId": 0, @@ -5915,7 +6544,8 @@ "3": {"x": 2608, "y": 252}, "4": {"x": 2496, "y": 228}, "5": {"x": 2496, "y": 228}, - "6": {"x": 2496, "y": 252} + "6": {"x": 2496, "y": 252}, + "7": {"x": 2496, "y": 252} } }, "warnings": null @@ -5926,13 +6556,8 @@ "sourcePortId": 1160, "targetNodeId": 149, "targetPortId": 1159, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 52, @@ -5961,6 +6586,20 @@ "timeFormatter": null, "consecutiveTime": 119 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 86, "resourceId": 0, @@ -5979,7 +6618,8 @@ "3": {"x": 2192, "y": 252}, "4": {"x": 2064, "y": 228}, "5": {"x": 2064, "y": 228}, - "6": {"x": 2064, "y": 252} + "6": {"x": 2064, "y": 252}, + "7": {"x": 2064, "y": 252} } }, "warnings": null @@ -5990,13 +6630,8 @@ "sourcePortId": 1162, "targetNodeId": 148, "targetPortId": 1161, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 38, @@ -6025,6 +6660,20 @@ "timeFormatter": null, "consecutiveTime": 105 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 86, "resourceId": 0, @@ -6043,7 +6692,8 @@ "3": {"x": 1296, "y": 252}, "4": {"x": 1200, "y": 228}, "5": {"x": 1200, "y": 228}, - "6": {"x": 1200, "y": 252} + "6": {"x": 1200, "y": 252}, + "7": {"x": 1200, "y": 252} } }, "warnings": null @@ -6054,13 +6704,8 @@ "sourcePortId": 1164, "targetNodeId": 147, "targetPortId": 1163, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 30, @@ -6089,6 +6734,20 @@ "timeFormatter": null, "consecutiveTime": 98 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 86, "resourceId": 0, @@ -6107,7 +6766,8 @@ "3": {"x": 912, "y": 252}, "4": {"x": 608, "y": 228}, "5": {"x": 608, "y": 228}, - "6": {"x": 608, "y": 252} + "6": {"x": 608, "y": 252}, + "7": {"x": 608, "y": 252} } }, "warnings": null @@ -6118,13 +6778,8 @@ "sourcePortId": 1166, "targetNodeId": 133, "targetPortId": 1165, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 17, @@ -6153,6 +6808,20 @@ "timeFormatter": null, "consecutiveTime": 84 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 86, "resourceId": 0, @@ -6171,7 +6840,8 @@ "3": {"x": 16, "y": 316}, "4": {"x": -224, "y": 292}, "5": {"x": -224, "y": 292}, - "6": {"x": -224, "y": 316} + "6": {"x": -224, "y": 316}, + "7": {"x": -224, "y": 316} } }, "warnings": null @@ -6182,13 +6852,8 @@ "sourcePortId": 1167, "targetNodeId": 151, "targetPortId": 1168, - "travelTime": { - "lock": true, - "time": 33, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 58, @@ -6217,6 +6882,20 @@ "timeFormatter": null, "consecutiveTime": 331 }, + "travelTime": { + "lock": true, + "time": 33, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 33, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 87, "resourceId": 0, @@ -6235,7 +6914,8 @@ "3": {"x": 4016, "y": 132}, "4": {"x": 4304, "y": 132}, "5": {"x": 4304, "y": 132}, - "6": {"x": 4304, "y": 156} + "6": {"x": 4304, "y": 132}, + "7": {"x": 4304, "y": 156} } }, "warnings": null @@ -6246,13 +6926,8 @@ "sourcePortId": 1169, "targetNodeId": 150, "targetPortId": 1170, - "travelTime": { - "lock": true, - "time": 14, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 33, @@ -6281,6 +6956,20 @@ "timeFormatter": null, "consecutiveTime": 347 }, + "travelTime": { + "lock": true, + "time": 14, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 14, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 87, "resourceId": 0, @@ -6299,7 +6988,8 @@ "3": {"x": 3440, "y": 68}, "4": {"x": 3632, "y": 68}, "5": {"x": 3632, "y": 68}, - "6": {"x": 3632, "y": 92} + "6": {"x": 3632, "y": 68}, + "7": {"x": 3632, "y": 92} } }, "warnings": null @@ -6310,13 +7000,8 @@ "sourcePortId": 1171, "targetNodeId": 135, "targetPortId": 1172, - "travelTime": { - "lock": true, - "time": 9, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 48, @@ -6345,6 +7030,20 @@ "timeFormatter": null, "consecutiveTime": 357 }, + "travelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 87, "resourceId": 0, @@ -6363,7 +7062,8 @@ "3": {"x": 2896, "y": 68}, "4": {"x": 3072, "y": 68}, "5": {"x": 3072, "y": 68}, - "6": {"x": 3072, "y": 92} + "6": {"x": 3072, "y": 68}, + "7": {"x": 3072, "y": 92} } }, "warnings": null @@ -6374,13 +7074,8 @@ "sourcePortId": 1173, "targetNodeId": 149, "targetPortId": 1174, - "travelTime": { - "lock": true, - "time": 10, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 4, @@ -6415,6 +7110,20 @@ "timeFormatter": null, "consecutiveTime": 370 }, + "travelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 87, "resourceId": 0, @@ -6433,7 +7142,8 @@ "3": {"x": 2384, "y": 132}, "4": {"x": 2496, "y": 132}, "5": {"x": 2496, "y": 132}, - "6": {"x": 2496, "y": 156} + "6": {"x": 2496, "y": 132}, + "7": {"x": 2496, "y": 156} } }, "warnings": null @@ -6444,13 +7154,8 @@ "sourcePortId": 1175, "targetNodeId": 166, "targetPortId": 1176, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 10, @@ -6479,6 +7184,20 @@ "timeFormatter": null, "consecutiveTime": 377 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 87, "resourceId": 0, @@ -6497,7 +7216,8 @@ "3": {"x": 1936, "y": 132}, "4": {"x": 2064, "y": 132}, "5": {"x": 2064, "y": 132}, - "6": {"x": 2064, "y": 156} + "6": {"x": 2064, "y": 132}, + "7": {"x": 2064, "y": 156} } }, "warnings": null @@ -6508,13 +7228,8 @@ "sourcePortId": 1177, "targetNodeId": 147, "targetPortId": 1178, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 24, @@ -6543,6 +7258,20 @@ "timeFormatter": null, "consecutiveTime": 389 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 87, "resourceId": 0, @@ -6561,7 +7290,8 @@ "3": {"x": 1104, "y": 132}, "4": {"x": 1200, "y": 132}, "5": {"x": 1200, "y": 132}, - "6": {"x": 1200, "y": 156} + "6": {"x": 1200, "y": 132}, + "7": {"x": 1200, "y": 156} } }, "warnings": null @@ -6572,13 +7302,8 @@ "sourcePortId": 1179, "targetNodeId": 133, "targetPortId": 1180, - "travelTime": { - "lock": true, - "time": 9, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 31, @@ -6607,6 +7332,20 @@ "timeFormatter": null, "consecutiveTime": 400 }, + "travelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 87, "resourceId": 0, @@ -6625,7 +7364,8 @@ "3": {"x": 304, "y": 132}, "4": {"x": 608, "y": 132}, "5": {"x": 608, "y": 132}, - "6": {"x": 608, "y": 156} + "6": {"x": 608, "y": 132}, + "7": {"x": 608, "y": 156} } }, "warnings": null @@ -6636,13 +7376,8 @@ "sourcePortId": 1181, "targetNodeId": 175, "targetPortId": 1182, - "travelTime": { - "lock": true, - "time": 17, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 42, @@ -6671,6 +7406,20 @@ "timeFormatter": null, "consecutiveTime": 419 }, + "travelTime": { + "lock": true, + "time": 17, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 17, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 87, "resourceId": 0, @@ -6689,7 +7438,8 @@ "3": {"x": -1552, "y": -28}, "4": {"x": -768, "y": 36}, "5": {"x": -768, "y": 36}, - "6": {"x": -768, "y": 60} + "6": {"x": -768, "y": 36}, + "7": {"x": -768, "y": 60} } }, "warnings": null @@ -6700,13 +7450,8 @@ "sourcePortId": 1183, "targetNodeId": 177, "targetPortId": 1184, - "travelTime": { - "lock": false, - "time": 61, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 17, @@ -6735,6 +7480,20 @@ "timeFormatter": null, "consecutiveTime": 498 }, + "travelTime": { + "lock": false, + "time": 61, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 61, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 2, "trainrunId": 87, "resourceId": 0, @@ -6753,7 +7512,8 @@ "3": {"x": -3376, "y": 548}, "4": {"x": -2976, "y": 260}, "5": {"x": -2976, "y": 260}, - "6": {"x": -2976, "y": 284} + "6": {"x": -2976, "y": 260}, + "7": {"x": -2976, "y": 284} } }, "warnings": null @@ -6764,13 +7524,8 @@ "sourcePortId": 1185, "targetNodeId": 161, "targetPortId": 1186, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 48, @@ -6799,6 +7554,20 @@ "timeFormatter": null, "consecutiveTime": 536 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 87, "resourceId": 0, @@ -6817,7 +7586,8 @@ "3": {"x": -4208, "y": 644}, "4": {"x": -4096, "y": 644}, "5": {"x": -4096, "y": 644}, - "6": {"x": -4096, "y": 668} + "6": {"x": -4096, "y": 644}, + "7": {"x": -4096, "y": 668} } }, "warnings": null @@ -6828,13 +7598,8 @@ "sourcePortId": 1187, "targetNodeId": 177, "targetPortId": 1188, - "travelTime": { - "lock": false, - "time": 11, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 19, @@ -6861,7 +7626,21 @@ "time": 30, "warning": null, "timeFormatter": null, - "consecutiveTime": 450 + "consecutiveTime": 450 + }, + "travelTime": { + "lock": false, + "time": 11, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 11, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 }, "numberOfStops": 0, "trainrunId": 81, @@ -6881,7 +7660,8 @@ "3": {"x": -3376, "y": 612}, "4": {"x": -3248, "y": 596}, "5": {"x": -3248, "y": 596}, - "6": {"x": -3248, "y": 620} + "6": {"x": -3248, "y": 596}, + "7": {"x": -3248, "y": 620} } }, "warnings": null @@ -6892,13 +7672,8 @@ "sourcePortId": 1189, "targetNodeId": 161, "targetPortId": 1190, - "travelTime": { - "lock": false, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 4, @@ -6927,6 +7702,20 @@ "timeFormatter": null, "consecutiveTime": 492 }, + "travelTime": { + "lock": false, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 81, "resourceId": 0, @@ -6945,7 +7734,8 @@ "3": {"x": -4208, "y": 676}, "4": {"x": -4096, "y": 676}, "5": {"x": -4096, "y": 676}, - "6": {"x": -4096, "y": 700} + "6": {"x": -4096, "y": 676}, + "7": {"x": -4096, "y": 700} } }, "warnings": null @@ -6956,13 +7746,8 @@ "sourcePortId": 1192, "targetNodeId": 135, "targetPortId": 1191, - "travelTime": { - "lock": true, - "time": 12, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 9, @@ -6991,6 +7776,20 @@ "timeFormatter": null, "consecutiveTime": 321 }, + "travelTime": { + "lock": true, + "time": 12, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 12, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 1, "trainrunId": 88, "resourceId": 0, @@ -7009,7 +7808,8 @@ "3": {"x": 2896, "y": 36}, "4": {"x": 3072, "y": 36}, "5": {"x": 3072, "y": 36}, - "6": {"x": 3072, "y": 60} + "6": {"x": 3072, "y": 36}, + "7": {"x": 3072, "y": 60} } }, "warnings": null @@ -7020,13 +7820,8 @@ "sourcePortId": 1194, "targetNodeId": 150, "targetPortId": 1193, - "travelTime": { - "lock": true, - "time": 13, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 54, @@ -7055,6 +7850,20 @@ "timeFormatter": null, "consecutiveTime": 307 }, + "travelTime": { + "lock": true, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 88, "resourceId": 0, @@ -7073,7 +7882,8 @@ "3": {"x": 3440, "y": 36}, "4": {"x": 3632, "y": 36}, "5": {"x": 3632, "y": 36}, - "6": {"x": 3632, "y": 60} + "6": {"x": 3632, "y": 36}, + "7": {"x": 3632, "y": 60} } }, "warnings": null @@ -7084,13 +7894,8 @@ "sourcePortId": 1195, "targetNodeId": 149, "targetPortId": 1196, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 46, @@ -7119,6 +7924,20 @@ "timeFormatter": null, "consecutiveTime": 351 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 88, "resourceId": 0, @@ -7137,7 +7956,8 @@ "3": {"x": 2384, "y": 36}, "4": {"x": 2496, "y": 36}, "5": {"x": 2496, "y": 36}, - "6": {"x": 2496, "y": 60} + "6": {"x": 2496, "y": 36}, + "7": {"x": 2496, "y": 60} } }, "warnings": null @@ -7148,13 +7968,8 @@ "sourcePortId": 1197, "targetNodeId": 166, "targetPortId": 1198, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 51, @@ -7183,6 +7998,20 @@ "timeFormatter": null, "consecutiveTime": 356 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 88, "resourceId": 0, @@ -7201,7 +8030,8 @@ "3": {"x": 1936, "y": 36}, "4": {"x": 2064, "y": 36}, "5": {"x": 2064, "y": 36}, - "6": {"x": 2064, "y": 60} + "6": {"x": 2064, "y": 36}, + "7": {"x": 2064, "y": 60} } }, "warnings": null @@ -7212,13 +8042,8 @@ "sourcePortId": 1199, "targetNodeId": 147, "targetPortId": 1200, - "travelTime": { - "lock": true, - "time": 4, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 1, @@ -7247,6 +8072,20 @@ "timeFormatter": null, "consecutiveTime": 365 }, + "travelTime": { + "lock": true, + "time": 4, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 4, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 88, "resourceId": 0, @@ -7265,7 +8104,8 @@ "3": {"x": 1104, "y": 36}, "4": {"x": 1200, "y": 36}, "5": {"x": 1200, "y": 36}, - "6": {"x": 1200, "y": 60} + "6": {"x": 1200, "y": 36}, + "7": {"x": 1200, "y": 60} } }, "warnings": null @@ -7276,13 +8116,8 @@ "sourcePortId": 1201, "targetNodeId": 133, "targetPortId": 1202, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 5, @@ -7311,6 +8146,20 @@ "timeFormatter": null, "consecutiveTime": 370 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 88, "resourceId": 0, @@ -7329,7 +8178,8 @@ "3": {"x": 304, "y": 100}, "4": {"x": 608, "y": 100}, "5": {"x": 608, "y": 100}, - "6": {"x": 608, "y": 124} + "6": {"x": 608, "y": 100}, + "7": {"x": 608, "y": 124} } }, "warnings": null @@ -7340,13 +8190,8 @@ "sourcePortId": 1203, "targetNodeId": 172, "targetPortId": 1204, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 10, @@ -7375,6 +8220,20 @@ "timeFormatter": null, "consecutiveTime": 377 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 88, "resourceId": 0, @@ -7393,7 +8252,8 @@ "3": {"x": -464, "y": 132}, "4": {"x": -224, "y": 132}, "5": {"x": -224, "y": 132}, - "6": {"x": -224, "y": 156} + "6": {"x": -224, "y": 132}, + "7": {"x": -224, "y": 156} } }, "warnings": null @@ -7404,13 +8264,8 @@ "sourcePortId": 1205, "targetNodeId": 171, "targetPortId": 1206, - "travelTime": { - "lock": true, - "time": 22, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 30, @@ -7439,6 +8294,20 @@ "timeFormatter": null, "consecutiveTime": 412 }, + "travelTime": { + "lock": true, + "time": 22, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 22, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 88, "resourceId": 0, @@ -7457,7 +8326,8 @@ "3": {"x": -2416, "y": 292}, "4": {"x": -2304, "y": 212}, "5": {"x": -2304, "y": 212}, - "6": {"x": -2304, "y": 236} + "6": {"x": -2304, "y": 212}, + "7": {"x": -2304, "y": 236} } }, "warnings": null @@ -7468,13 +8338,8 @@ "sourcePortId": 1207, "targetNodeId": 177, "targetPortId": 1208, - "travelTime": { - "lock": true, - "time": 9, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 43, @@ -7503,6 +8368,20 @@ "timeFormatter": null, "consecutiveTime": 472 }, + "travelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 88, "resourceId": 0, @@ -7521,7 +8400,8 @@ "3": {"x": -3376, "y": 580}, "4": {"x": -3248, "y": 564}, "5": {"x": -3248, "y": 564}, - "6": {"x": -3248, "y": 588} + "6": {"x": -3248, "y": 564}, + "7": {"x": -3248, "y": 588} } }, "warnings": null @@ -7532,13 +8412,8 @@ "sourcePortId": 1209, "targetNodeId": 161, "targetPortId": 1210, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 21, @@ -7567,6 +8442,20 @@ "timeFormatter": null, "consecutiveTime": 508 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 88, "resourceId": 0, @@ -7585,7 +8474,8 @@ "3": {"x": -4208, "y": 612}, "4": {"x": -4096, "y": 612}, "5": {"x": -4096, "y": 612}, - "6": {"x": -4096, "y": 636} + "6": {"x": -4096, "y": 612}, + "7": {"x": -4096, "y": 636} } }, "warnings": null @@ -7596,13 +8486,8 @@ "sourcePortId": 1212, "targetNodeId": 151, "targetPortId": 1211, - "travelTime": { - "lock": false, - "time": 44, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 8, @@ -7631,6 +8516,20 @@ "timeFormatter": null, "consecutiveTime": 292 }, + "travelTime": { + "lock": false, + "time": 44, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 44, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 4, "trainrunId": 88, "resourceId": 0, @@ -7649,7 +8548,8 @@ "3": {"x": 4016, "y": 100}, "4": {"x": 4304, "y": 100}, "5": {"x": 4304, "y": 100}, - "6": {"x": 4304, "y": 124} + "6": {"x": 4304, "y": 100}, + "7": {"x": 4304, "y": 124} } }, "warnings": null @@ -7657,16 +8557,11 @@ { "id": 599, "sourceNodeId": 135, - "sourcePortId": 1213, - "targetNodeId": 150, - "targetPortId": 1214, - "travelTime": { - "lock": true, - "time": 9, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourcePortId": 1213, + "targetNodeId": 150, + "targetPortId": 1214, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 5, @@ -7695,6 +8590,20 @@ "timeFormatter": null, "consecutiveTime": 134 }, + "travelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 89, "resourceId": 0, @@ -7713,7 +8622,8 @@ "3": {"x": 3248, "y": 124}, "4": {"x": 3072, "y": 100}, "5": {"x": 3072, "y": 100}, - "6": {"x": 3072, "y": 124} + "6": {"x": 3072, "y": 124}, + "7": {"x": 3072, "y": 124} } }, "warnings": null @@ -7724,13 +8634,8 @@ "sourcePortId": 1215, "targetNodeId": 151, "targetPortId": 1216, - "travelTime": { - "lock": true, - "time": 13, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 16, @@ -7759,6 +8664,20 @@ "timeFormatter": null, "consecutiveTime": 149 }, + "travelTime": { + "lock": true, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 89, "resourceId": 0, @@ -7777,7 +8696,8 @@ "3": {"x": 3824, "y": 124}, "4": {"x": 3632, "y": 100}, "5": {"x": 3632, "y": 100}, - "6": {"x": 3632, "y": 124} + "6": {"x": 3632, "y": 124}, + "7": {"x": 3632, "y": 124} } }, "warnings": null @@ -7788,13 +8708,8 @@ "sourcePortId": 1218, "targetNodeId": 135, "targetPortId": 1217, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 52, @@ -7823,6 +8738,20 @@ "timeFormatter": null, "consecutiveTime": 118 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 89, "resourceId": 0, @@ -7841,7 +8770,8 @@ "3": {"x": 2608, "y": 188}, "4": {"x": 2496, "y": 164}, "5": {"x": 2496, "y": 164}, - "6": {"x": 2496, "y": 188} + "6": {"x": 2496, "y": 188}, + "7": {"x": 2496, "y": 188} } }, "warnings": null @@ -7852,13 +8782,8 @@ "sourcePortId": 1220, "targetNodeId": 149, "targetPortId": 1219, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 46, @@ -7887,6 +8812,20 @@ "timeFormatter": null, "consecutiveTime": 112 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 89, "resourceId": 0, @@ -7905,7 +8844,8 @@ "3": {"x": 2192, "y": 188}, "4": {"x": 2064, "y": 164}, "5": {"x": 2064, "y": 164}, - "6": {"x": 2064, "y": 188} + "6": {"x": 2064, "y": 188}, + "7": {"x": 2064, "y": 188} } }, "warnings": null @@ -7916,13 +8856,8 @@ "sourcePortId": 1222, "targetNodeId": 148, "targetPortId": 1221, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 35, @@ -7951,6 +8886,20 @@ "timeFormatter": null, "consecutiveTime": 100 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 89, "resourceId": 0, @@ -7969,7 +8918,8 @@ "3": {"x": 1296, "y": 188}, "4": {"x": 1200, "y": 164}, "5": {"x": 1200, "y": 164}, - "6": {"x": 1200, "y": 188} + "6": {"x": 1200, "y": 188}, + "7": {"x": 1200, "y": 188} } }, "warnings": null @@ -7980,13 +8930,8 @@ "sourcePortId": 1224, "targetNodeId": 147, "targetPortId": 1223, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 30, @@ -8015,6 +8960,20 @@ "timeFormatter": null, "consecutiveTime": 95 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 89, "resourceId": 0, @@ -8033,7 +8992,8 @@ "3": {"x": 912, "y": 188}, "4": {"x": 608, "y": 164}, "5": {"x": 608, "y": 164}, - "6": {"x": 608, "y": 188} + "6": {"x": 608, "y": 188}, + "7": {"x": 608, "y": 188} } }, "warnings": null @@ -8044,13 +9004,8 @@ "sourcePortId": 1226, "targetNodeId": 133, "targetPortId": 1225, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 23, @@ -8079,6 +9034,20 @@ "timeFormatter": null, "consecutiveTime": 90 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 89, "resourceId": 0, @@ -8097,7 +9066,8 @@ "3": {"x": 16, "y": 252}, "4": {"x": -224, "y": 228}, "5": {"x": -224, "y": 228}, - "6": {"x": -224, "y": 252} + "6": {"x": -224, "y": 252}, + "7": {"x": -224, "y": 252} } }, "warnings": null @@ -8108,13 +9078,8 @@ "sourcePortId": 1227, "targetNodeId": 162, "targetPortId": 1228, - "travelTime": { - "lock": true, - "time": 51, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 31, @@ -8143,6 +9108,20 @@ "timeFormatter": null, "consecutiveTime": 202 }, + "travelTime": { + "lock": true, + "time": 51, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 51, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 89, "resourceId": 0, @@ -8161,7 +9140,8 @@ "3": {"x": 4592, "y": -164}, "4": {"x": 4304, "y": -76}, "5": {"x": 4304, "y": -76}, - "6": {"x": 4304, "y": -52} + "6": {"x": 4304, "y": -52}, + "7": {"x": 4304, "y": -52} } }, "warnings": null @@ -8172,13 +9152,8 @@ "sourcePortId": 1229, "targetNodeId": 150, "targetPortId": 1230, - "travelTime": { - "lock": true, - "time": 9, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 5, @@ -8207,6 +9182,20 @@ "timeFormatter": null, "consecutiveTime": 134 }, + "travelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 90, "resourceId": 0, @@ -8225,7 +9214,8 @@ "3": {"x": 3248, "y": 156}, "4": {"x": 3072, "y": 132}, "5": {"x": 3072, "y": 132}, - "6": {"x": 3072, "y": 156} + "6": {"x": 3072, "y": 156}, + "7": {"x": 3072, "y": 156} } }, "warnings": null @@ -8236,13 +9226,8 @@ "sourcePortId": 1231, "targetNodeId": 151, "targetPortId": 1232, - "travelTime": { - "lock": true, - "time": 13, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 16, @@ -8271,6 +9256,20 @@ "timeFormatter": null, "consecutiveTime": 149 }, + "travelTime": { + "lock": true, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 90, "resourceId": 0, @@ -8289,7 +9288,8 @@ "3": {"x": 3824, "y": 156}, "4": {"x": 3632, "y": 132}, "5": {"x": 3632, "y": 132}, - "6": {"x": 3632, "y": 156} + "6": {"x": 3632, "y": 156}, + "7": {"x": 3632, "y": 156} } }, "warnings": null @@ -8300,13 +9300,8 @@ "sourcePortId": 1234, "targetNodeId": 135, "targetPortId": 1233, - "travelTime": { - "lock": true, - "time": 15, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 43, @@ -8335,6 +9330,20 @@ "timeFormatter": null, "consecutiveTime": 118 }, + "travelTime": { + "lock": true, + "time": 15, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 15, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 90, "resourceId": 0, @@ -8353,7 +9362,8 @@ "3": {"x": 2608, "y": 220}, "4": {"x": 2496, "y": 196}, "5": {"x": 2496, "y": 196}, - "6": {"x": 2496, "y": 220} + "6": {"x": 2496, "y": 220}, + "7": {"x": 2496, "y": 220} } }, "warnings": null @@ -8364,13 +9374,8 @@ "sourcePortId": 1236, "targetNodeId": 149, "targetPortId": 1235, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 37, @@ -8399,6 +9404,20 @@ "timeFormatter": null, "consecutiveTime": 103 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 90, "resourceId": 0, @@ -8417,7 +9436,8 @@ "3": {"x": 2192, "y": 220}, "4": {"x": 2064, "y": 196}, "5": {"x": 2064, "y": 196}, - "6": {"x": 2064, "y": 220} + "6": {"x": 2064, "y": 220}, + "7": {"x": 2064, "y": 220} } }, "warnings": null @@ -8428,13 +9448,8 @@ "sourcePortId": 1238, "targetNodeId": 148, "targetPortId": 1237, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 25, @@ -8463,6 +9478,20 @@ "timeFormatter": null, "consecutiveTime": 90 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 90, "resourceId": 0, @@ -8481,7 +9510,8 @@ "3": {"x": 1296, "y": 220}, "4": {"x": 1200, "y": 196}, "5": {"x": 1200, "y": 196}, - "6": {"x": 1200, "y": 220} + "6": {"x": 1200, "y": 220}, + "7": {"x": 1200, "y": 220} } }, "warnings": null @@ -8492,13 +9522,8 @@ "sourcePortId": 1240, "targetNodeId": 147, "targetPortId": 1239, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 20, @@ -8527,6 +9552,20 @@ "timeFormatter": null, "consecutiveTime": 85 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 90, "resourceId": 0, @@ -8545,7 +9584,8 @@ "3": {"x": 912, "y": 220}, "4": {"x": 608, "y": 196}, "5": {"x": 608, "y": 196}, - "6": {"x": 608, "y": 220} + "6": {"x": 608, "y": 220}, + "7": {"x": 608, "y": 220} } }, "warnings": null @@ -8556,13 +9596,8 @@ "sourcePortId": 1242, "targetNodeId": 133, "targetPortId": 1241, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 13, @@ -8591,6 +9626,20 @@ "timeFormatter": null, "consecutiveTime": 80 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 90, "resourceId": 0, @@ -8609,7 +9658,8 @@ "3": {"x": 16, "y": 284}, "4": {"x": -224, "y": 260}, "5": {"x": -224, "y": 260}, - "6": {"x": -224, "y": 284} + "6": {"x": -224, "y": 284}, + "7": {"x": -224, "y": 284} } }, "warnings": null @@ -8620,13 +9670,8 @@ "sourcePortId": 1243, "targetNodeId": 162, "targetPortId": 1244, - "travelTime": { - "lock": true, - "time": 41, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 31, @@ -8655,6 +9700,20 @@ "timeFormatter": null, "consecutiveTime": 192 }, + "travelTime": { + "lock": true, + "time": 41, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 41, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 90, "resourceId": 0, @@ -8673,7 +9732,8 @@ "3": {"x": 4592, "y": -132}, "4": {"x": 4304, "y": -44}, "5": {"x": 4304, "y": -44}, - "6": {"x": 4304, "y": -20} + "6": {"x": 4304, "y": -20}, + "7": {"x": 4304, "y": -20} } }, "warnings": null @@ -8684,13 +9744,8 @@ "sourcePortId": 1245, "targetNodeId": 150, "targetPortId": 1246, - "travelTime": { - "lock": true, - "time": 9, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 35, @@ -8719,6 +9774,20 @@ "timeFormatter": null, "consecutiveTime": 104 }, + "travelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 79, "resourceId": 0, @@ -8737,7 +9806,8 @@ "3": {"x": 3248, "y": 220}, "4": {"x": 3072, "y": 196}, "5": {"x": 3072, "y": 196}, - "6": {"x": 3072, "y": 220} + "6": {"x": 3072, "y": 220}, + "7": {"x": 3072, "y": 220} } }, "warnings": null @@ -8748,13 +9818,8 @@ "sourcePortId": 1247, "targetNodeId": 151, "targetPortId": 1248, - "travelTime": { - "lock": false, - "time": 13, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 46, @@ -8783,6 +9848,20 @@ "timeFormatter": null, "consecutiveTime": 119 }, + "travelTime": { + "lock": false, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 79, "resourceId": 0, @@ -8801,7 +9880,8 @@ "3": {"x": 3824, "y": 220}, "4": {"x": 3632, "y": 196}, "5": {"x": 3632, "y": 196}, - "6": {"x": 3632, "y": 220} + "6": {"x": 3632, "y": 220}, + "7": {"x": 3632, "y": 220} } }, "warnings": null @@ -8812,13 +9892,8 @@ "sourcePortId": 1249, "targetNodeId": 139, "targetPortId": 1250, - "travelTime": { - "lock": false, - "time": 49, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 1, @@ -8847,6 +9922,20 @@ "timeFormatter": null, "consecutiveTime": 170 }, + "travelTime": { + "lock": false, + "time": 49, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 49, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 2, "trainrunId": 79, "resourceId": 0, @@ -8865,7 +9954,8 @@ "3": {"x": 4284, "y": -304}, "4": {"x": 4068, "y": -160}, "5": {"x": 4068, "y": -160}, - "6": {"x": 4092, "y": -160} + "6": {"x": 4092, "y": -160}, + "7": {"x": 4092, "y": -160} } }, "warnings": null @@ -8876,13 +9966,8 @@ "sourcePortId": 1251, "targetNodeId": 163, "targetPortId": 1252, - "travelTime": { - "lock": true, - "time": 1, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 0, @@ -8911,6 +9996,20 @@ "timeFormatter": null, "consecutiveTime": 1 }, + "travelTime": { + "lock": true, + "time": 1, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 1, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 91, "resourceId": 0, @@ -8929,7 +10028,8 @@ "3": {"x": 2788, "y": -592}, "4": {"x": 2748, "y": -800}, "5": {"x": 2748, "y": -800}, - "6": {"x": 2724, "y": -800} + "6": {"x": 2724, "y": -800}, + "7": {"x": 2724, "y": -800} } }, "warnings": null @@ -8940,13 +10040,8 @@ "sourcePortId": 1253, "targetNodeId": 135, "targetPortId": 1254, - "travelTime": { - "lock": true, - "time": 1, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 3, @@ -8975,6 +10070,20 @@ "timeFormatter": null, "consecutiveTime": 4 }, + "travelTime": { + "lock": true, + "time": 1, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 1, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 91, "resourceId": 0, @@ -8993,7 +10102,8 @@ "3": {"x": 2692, "y": -16}, "4": {"x": 2740, "y": -224}, "5": {"x": 2740, "y": -224}, - "6": {"x": 2764, "y": -224} + "6": {"x": 2740, "y": -224}, + "7": {"x": 2764, "y": -224} } }, "warnings": null @@ -9004,13 +10114,8 @@ "sourcePortId": 1255, "targetNodeId": 138, "targetPortId": 1256, - "travelTime": { - "lock": true, - "time": 1, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 0, @@ -9039,6 +10144,20 @@ "timeFormatter": null, "consecutiveTime": 121 }, + "travelTime": { + "lock": true, + "time": 1, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 1, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 92, "resourceId": 0, @@ -9057,7 +10176,8 @@ "3": {"x": 2652, "y": -1008}, "4": {"x": 2668, "y": -512}, "5": {"x": 2668, "y": -512}, - "6": {"x": 2644, "y": -512} + "6": {"x": 2668, "y": -512}, + "7": {"x": 2644, "y": -512} } }, "warnings": null @@ -9068,13 +10188,8 @@ "sourcePortId": 1257, "targetNodeId": 148, "targetPortId": 1258, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 56, @@ -9103,6 +10218,20 @@ "timeFormatter": null, "consecutiveTime": 361 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 88, "resourceId": 0, @@ -9121,7 +10250,8 @@ "3": {"x": 1488, "y": 36}, "4": {"x": 1616, "y": 36}, "5": {"x": 1616, "y": 36}, - "6": {"x": 1616, "y": 60} + "6": {"x": 1616, "y": 36}, + "7": {"x": 1616, "y": 60} } }, "warnings": null @@ -9132,13 +10262,8 @@ "sourcePortId": 1259, "targetNodeId": 148, "targetPortId": 1260, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 17, @@ -9167,6 +10292,20 @@ "timeFormatter": null, "consecutiveTime": 384 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 87, "resourceId": 0, @@ -9185,7 +10324,8 @@ "3": {"x": 1488, "y": 132}, "4": {"x": 1616, "y": 132}, "5": {"x": 1616, "y": 132}, - "6": {"x": 1616, "y": 156} + "6": {"x": 1616, "y": 132}, + "7": {"x": 1616, "y": 156} } }, "warnings": null @@ -9196,13 +10336,8 @@ "sourcePortId": 1262, "targetNodeId": 166, "targetPortId": 1261, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 40, @@ -9231,6 +10366,20 @@ "timeFormatter": null, "consecutiveTime": 106 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 89, "resourceId": 0, @@ -9249,7 +10398,8 @@ "3": {"x": 1744, "y": 188}, "4": {"x": 1616, "y": 164}, "5": {"x": 1616, "y": 164}, - "6": {"x": 1616, "y": 188} + "6": {"x": 1616, "y": 188}, + "7": {"x": 1616, "y": 188} } }, "warnings": null @@ -9260,13 +10410,8 @@ "sourcePortId": 1264, "targetNodeId": 166, "targetPortId": 1263, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 30, @@ -9293,7 +10438,21 @@ "time": 35, "warning": null, "timeFormatter": null, - "consecutiveTime": 95 + "consecutiveTime": 95 + }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 }, "numberOfStops": 0, "trainrunId": 90, @@ -9313,7 +10472,8 @@ "3": {"x": 1744, "y": 220}, "4": {"x": 1616, "y": 196}, "5": {"x": 1616, "y": 196}, - "6": {"x": 1616, "y": 220} + "6": {"x": 1616, "y": 220}, + "7": {"x": 1616, "y": 220} } }, "warnings": null @@ -9324,13 +10484,8 @@ "sourcePortId": 1266, "targetNodeId": 166, "targetPortId": 1265, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 45, @@ -9359,6 +10514,20 @@ "timeFormatter": null, "consecutiveTime": 112 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 86, "resourceId": 0, @@ -9377,7 +10546,8 @@ "3": {"x": 1744, "y": 252}, "4": {"x": 1616, "y": 228}, "5": {"x": 1616, "y": 228}, - "6": {"x": 1616, "y": 252} + "6": {"x": 1616, "y": 252}, + "7": {"x": 1616, "y": 252} } }, "warnings": null @@ -9388,13 +10558,8 @@ "sourcePortId": 1267, "targetNodeId": 164, "targetPortId": 1268, - "travelTime": { - "lock": true, - "time": 13, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 11, @@ -9423,6 +10588,20 @@ "timeFormatter": null, "consecutiveTime": 24 }, + "travelTime": { + "lock": true, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 93, "resourceId": 0, @@ -9441,7 +10620,8 @@ "3": {"x": 1008, "y": -932}, "4": {"x": 688, "y": -1420}, "5": {"x": 688, "y": -1420}, - "6": {"x": 688, "y": -1396} + "6": {"x": 688, "y": -1396}, + "7": {"x": 688, "y": -1396} } }, "warnings": null @@ -9452,13 +10632,8 @@ "sourcePortId": 1269, "targetNodeId": 165, "targetPortId": 1270, - "travelTime": { - "lock": true, - "time": 9, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 25, @@ -9487,6 +10662,20 @@ "timeFormatter": null, "consecutiveTime": 34 }, + "travelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 93, "resourceId": 0, @@ -9505,7 +10694,8 @@ "3": {"x": 1744, "y": -644}, "4": {"x": 1472, "y": -812}, "5": {"x": 1472, "y": -812}, - "6": {"x": 1472, "y": -788} + "6": {"x": 1472, "y": -788}, + "7": {"x": 1472, "y": -788} } }, "warnings": null @@ -9516,13 +10706,8 @@ "sourcePortId": 1271, "targetNodeId": 166, "targetPortId": 1272, - "travelTime": { - "lock": true, - "time": 22, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 35, @@ -9551,6 +10736,20 @@ "timeFormatter": null, "consecutiveTime": 57 }, + "travelTime": { + "lock": true, + "time": 22, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 22, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 93, "resourceId": 0, @@ -9569,7 +10768,8 @@ "3": {"x": 1796, "y": -16}, "4": {"x": 1796, "y": -288}, "5": {"x": 1796, "y": -288}, - "6": {"x": 1820, "y": -288} + "6": {"x": 1796, "y": -288}, + "7": {"x": 1820, "y": -288} } }, "warnings": null @@ -9580,13 +10780,8 @@ "sourcePortId": 1273, "targetNodeId": 149, "targetPortId": 1274, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 0, @@ -9615,6 +10810,20 @@ "timeFormatter": null, "consecutiveTime": 67 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 93, "resourceId": 0, @@ -9633,7 +10842,8 @@ "3": {"x": 2192, "y": 284}, "4": {"x": 2064, "y": 260}, "5": {"x": 2064, "y": 260}, - "6": {"x": 2064, "y": 284} + "6": {"x": 2064, "y": 284}, + "7": {"x": 2064, "y": 284} } }, "warnings": null @@ -9644,13 +10854,8 @@ "sourcePortId": 1275, "targetNodeId": 135, "targetPortId": 1276, - "travelTime": { - "lock": true, - "time": 16, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 8, @@ -9679,6 +10884,20 @@ "timeFormatter": null, "consecutiveTime": 84 }, + "travelTime": { + "lock": true, + "time": 16, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 16, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 93, "resourceId": 0, @@ -9697,7 +10916,8 @@ "3": {"x": 2608, "y": 284}, "4": {"x": 2496, "y": 260}, "5": {"x": 2496, "y": 260}, - "6": {"x": 2496, "y": 284} + "6": {"x": 2496, "y": 284}, + "7": {"x": 2496, "y": 284} } }, "warnings": null @@ -9708,13 +10928,8 @@ "sourcePortId": 1277, "targetNodeId": 146, "targetPortId": 1278, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 6, @@ -9743,6 +10958,20 @@ "timeFormatter": null, "consecutiveTime": 11 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 94, "resourceId": 0, @@ -9761,7 +10990,8 @@ "3": {"x": 132, "y": -1456}, "4": {"x": 132, "y": -1616}, "5": {"x": 132, "y": -1616}, - "6": {"x": 156, "y": -1616} + "6": {"x": 132, "y": -1616}, + "7": {"x": 156, "y": -1616} } }, "warnings": null @@ -9772,13 +11002,8 @@ "sourcePortId": 1279, "targetNodeId": 145, "targetPortId": 1280, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 11, @@ -9807,6 +11032,20 @@ "timeFormatter": null, "consecutiveTime": 17 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 94, "resourceId": 0, @@ -9825,7 +11064,8 @@ "3": {"x": 132, "y": -976}, "4": {"x": 132, "y": -1136}, "5": {"x": 132, "y": -1136}, - "6": {"x": 156, "y": -1136} + "6": {"x": 132, "y": -1136}, + "7": {"x": 156, "y": -1136} } }, "warnings": null @@ -9836,13 +11076,8 @@ "sourcePortId": 1281, "targetNodeId": 144, "targetPortId": 1282, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 17, @@ -9871,6 +11106,20 @@ "timeFormatter": null, "consecutiveTime": 23 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 94, "resourceId": 0, @@ -9889,7 +11138,8 @@ "3": {"x": 132, "y": -496}, "4": {"x": 132, "y": -656}, "5": {"x": 132, "y": -656}, - "6": {"x": 156, "y": -656} + "6": {"x": 132, "y": -656}, + "7": {"x": 156, "y": -656} } }, "warnings": null @@ -9900,13 +11150,8 @@ "sourcePortId": 1283, "targetNodeId": 147, "targetPortId": 1284, - "travelTime": { - "lock": true, - "time": 10, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 23, @@ -9935,6 +11180,20 @@ "timeFormatter": null, "consecutiveTime": 33 }, + "travelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 94, "resourceId": 0, @@ -9953,7 +11212,8 @@ "3": {"x": 912, "y": 92}, "4": {"x": 640, "y": -172}, "5": {"x": 640, "y": -172}, - "6": {"x": 640, "y": -148} + "6": {"x": 640, "y": -148}, + "7": {"x": 640, "y": -148} } }, "warnings": null @@ -9964,13 +11224,8 @@ "sourcePortId": 1285, "targetNodeId": 148, "targetPortId": 1286, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 33, @@ -9999,6 +11254,20 @@ "timeFormatter": null, "consecutiveTime": 40 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 94, "resourceId": 0, @@ -10017,7 +11286,8 @@ "3": {"x": 1296, "y": 124}, "4": {"x": 1200, "y": 100}, "5": {"x": 1200, "y": 100}, - "6": {"x": 1200, "y": 124} + "6": {"x": 1200, "y": 124}, + "7": {"x": 1200, "y": 124} } }, "warnings": null @@ -10028,13 +11298,8 @@ "sourcePortId": 1287, "targetNodeId": 166, "targetPortId": 1288, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 40, @@ -10063,6 +11328,20 @@ "timeFormatter": null, "consecutiveTime": 46 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 94, "resourceId": 0, @@ -10081,7 +11360,8 @@ "3": {"x": 1744, "y": 124}, "4": {"x": 1616, "y": 100}, "5": {"x": 1616, "y": 100}, - "6": {"x": 1616, "y": 124} + "6": {"x": 1616, "y": 124}, + "7": {"x": 1616, "y": 124} } }, "warnings": null @@ -10089,16 +11369,11 @@ { "id": 637, "sourceNodeId": 166, - "sourcePortId": 1289, - "targetNodeId": 149, - "targetPortId": 1290, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourcePortId": 1289, + "targetNodeId": 149, + "targetPortId": 1290, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 46, @@ -10127,6 +11402,20 @@ "timeFormatter": null, "consecutiveTime": 52 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 94, "resourceId": 0, @@ -10145,7 +11434,8 @@ "3": {"x": 2192, "y": 124}, "4": {"x": 2064, "y": 100}, "5": {"x": 2064, "y": 100}, - "6": {"x": 2064, "y": 124} + "6": {"x": 2064, "y": 124}, + "7": {"x": 2064, "y": 124} } }, "warnings": null @@ -10156,13 +11446,8 @@ "sourcePortId": 1291, "targetNodeId": 135, "targetPortId": 1292, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 52, @@ -10191,6 +11476,20 @@ "timeFormatter": null, "consecutiveTime": 60 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 94, "resourceId": 0, @@ -10209,7 +11508,8 @@ "3": {"x": 2608, "y": 124}, "4": {"x": 2496, "y": 100}, "5": {"x": 2496, "y": 100}, - "6": {"x": 2496, "y": 124} + "6": {"x": 2496, "y": 124}, + "7": {"x": 2496, "y": 124} } }, "warnings": null @@ -10220,13 +11520,8 @@ "sourcePortId": 1293, "targetNodeId": 148, "targetPortId": 1294, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 54, @@ -10255,6 +11550,20 @@ "timeFormatter": null, "consecutiveTime": 60 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 97, "resourceId": 0, @@ -10273,7 +11582,8 @@ "3": {"x": 1296, "y": 284}, "4": {"x": 1200, "y": 260}, "5": {"x": 1200, "y": 260}, - "6": {"x": 1200, "y": 284} + "6": {"x": 1200, "y": 284}, + "7": {"x": 1200, "y": 284} } }, "warnings": null @@ -10284,13 +11594,8 @@ "sourcePortId": 1295, "targetNodeId": 166, "targetPortId": 1296, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 2, @@ -10319,6 +11624,20 @@ "timeFormatter": null, "consecutiveTime": 68 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 97, "resourceId": 0, @@ -10337,7 +11656,8 @@ "3": {"x": 1744, "y": 284}, "4": {"x": 1616, "y": 260}, "5": {"x": 1616, "y": 260}, - "6": {"x": 1616, "y": 284} + "6": {"x": 1616, "y": 284}, + "7": {"x": 1616, "y": 284} } }, "warnings": null @@ -10348,13 +11668,8 @@ "sourcePortId": 1297, "targetNodeId": 149, "targetPortId": 1298, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 8, @@ -10383,6 +11698,20 @@ "timeFormatter": null, "consecutiveTime": 75 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 97, "resourceId": 0, @@ -10401,7 +11730,8 @@ "3": {"x": 2192, "y": 316}, "4": {"x": 2064, "y": 292}, "5": {"x": 2064, "y": 292}, - "6": {"x": 2064, "y": 316} + "6": {"x": 2064, "y": 316}, + "7": {"x": 2064, "y": 316} } }, "warnings": null @@ -10412,13 +11742,8 @@ "sourcePortId": 1299, "targetNodeId": 135, "targetPortId": 1300, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 15, @@ -10447,6 +11772,20 @@ "timeFormatter": null, "consecutiveTime": 82 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 97, "resourceId": 0, @@ -10465,7 +11804,8 @@ "3": {"x": 2608, "y": 316}, "4": {"x": 2496, "y": 292}, "5": {"x": 2496, "y": 292}, - "6": {"x": 2496, "y": 316} + "6": {"x": 2496, "y": 316}, + "7": {"x": 2496, "y": 316} } }, "warnings": null @@ -10476,13 +11816,8 @@ "sourcePortId": 1301, "targetNodeId": 146, "targetPortId": 1302, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 28, @@ -10511,6 +11846,20 @@ "timeFormatter": null, "consecutiveTime": 35 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 95, "resourceId": 0, @@ -10529,7 +11878,8 @@ "3": {"x": 196, "y": -1456}, "4": {"x": 196, "y": -1616}, "5": {"x": 196, "y": -1616}, - "6": {"x": 220, "y": -1616} + "6": {"x": 196, "y": -1616}, + "7": {"x": 220, "y": -1616} } }, "warnings": null @@ -10540,13 +11890,8 @@ "sourcePortId": 1303, "targetNodeId": 145, "targetPortId": 1304, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 35, @@ -10575,6 +11920,20 @@ "timeFormatter": null, "consecutiveTime": 41 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 95, "resourceId": 0, @@ -10593,7 +11952,8 @@ "3": {"x": 196, "y": -976}, "4": {"x": 196, "y": -1136}, "5": {"x": 196, "y": -1136}, - "6": {"x": 220, "y": -1136} + "6": {"x": 196, "y": -1136}, + "7": {"x": 220, "y": -1136} } }, "warnings": null @@ -10604,13 +11964,8 @@ "sourcePortId": 1305, "targetNodeId": 144, "targetPortId": 1306, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 41, @@ -10639,6 +11994,20 @@ "timeFormatter": null, "consecutiveTime": 47 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 95, "resourceId": 0, @@ -10657,7 +12026,8 @@ "3": {"x": 196, "y": -496}, "4": {"x": 196, "y": -656}, "5": {"x": 196, "y": -656}, - "6": {"x": 220, "y": -656} + "6": {"x": 196, "y": -656}, + "7": {"x": 220, "y": -656} } }, "warnings": null @@ -10668,13 +12038,8 @@ "sourcePortId": 1307, "targetNodeId": 133, "targetPortId": 1308, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 47, @@ -10703,6 +12068,20 @@ "timeFormatter": null, "consecutiveTime": 55 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 95, "resourceId": 0, @@ -10721,7 +12100,8 @@ "3": {"x": 132, "y": 48}, "4": {"x": 132, "y": -130}, "5": {"x": 132, "y": -130}, - "6": {"x": 156, "y": -130} + "6": {"x": 132, "y": -130}, + "7": {"x": 156, "y": -130} } }, "warnings": null @@ -10732,13 +12112,8 @@ "sourcePortId": 1309, "targetNodeId": 172, "targetPortId": 1310, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 58, @@ -10767,6 +12142,20 @@ "timeFormatter": null, "consecutiveTime": 65 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 95, "resourceId": 0, @@ -10785,7 +12174,8 @@ "3": {"x": -464, "y": 196}, "4": {"x": -224, "y": 196}, "5": {"x": -224, "y": 196}, - "6": {"x": -224, "y": 220} + "6": {"x": -224, "y": 196}, + "7": {"x": -224, "y": 220} } }, "warnings": null @@ -10796,13 +12186,8 @@ "sourcePortId": 1311, "targetNodeId": 167, "targetPortId": 1312, - "travelTime": { - "lock": true, - "time": 18, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 34, @@ -10831,6 +12216,20 @@ "timeFormatter": null, "consecutiveTime": 112 }, + "travelTime": { + "lock": true, + "time": 18, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 18, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 95, "resourceId": 0, @@ -10849,7 +12248,8 @@ "3": {"x": -2108, "y": 592}, "4": {"x": -2108, "y": 510}, "5": {"x": -2108, "y": 510}, - "6": {"x": -2084, "y": 510} + "6": {"x": -2108, "y": 510}, + "7": {"x": -2084, "y": 510} } }, "warnings": null @@ -10860,13 +12260,8 @@ "sourcePortId": 1314, "targetNodeId": 129, "targetPortId": 1313, - "travelTime": { - "lock": true, - "time": 18, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 43, @@ -10895,6 +12290,20 @@ "timeFormatter": null, "consecutiveTime": 61 }, + "travelTime": { + "lock": true, + "time": 18, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 18, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 89, "resourceId": 0, @@ -10913,7 +12322,8 @@ "3": {"x": -2052, "y": 428}, "4": {"x": -2076, "y": 510}, "5": {"x": -2076, "y": 510}, - "6": {"x": -2052, "y": 510} + "6": {"x": -2052, "y": 510}, + "7": {"x": -2052, "y": 510} } }, "warnings": null @@ -10924,13 +12334,8 @@ "sourcePortId": 1315, "targetNodeId": 168, "targetPortId": 1316, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 54, @@ -10959,6 +12364,20 @@ "timeFormatter": null, "consecutiveTime": 122 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 95, "resourceId": 0, @@ -10977,7 +12396,8 @@ "3": {"x": -2108, "y": 880}, "4": {"x": -2108, "y": 816}, "5": {"x": -2108, "y": 816}, - "6": {"x": -2084, "y": 816} + "6": {"x": -2108, "y": 816}, + "7": {"x": -2084, "y": 816} } }, "warnings": null @@ -10988,13 +12408,8 @@ "sourcePortId": 1317, "targetNodeId": 131, "targetPortId": 1318, - "travelTime": { - "lock": true, - "time": 24, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 4, @@ -11023,6 +12438,20 @@ "timeFormatter": null, "consecutiveTime": 148 }, + "travelTime": { + "lock": true, + "time": 24, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 24, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 95, "resourceId": 0, @@ -11041,7 +12470,8 @@ "3": {"x": -1136, "y": 956}, "4": {"x": -1552, "y": 932}, "5": {"x": -1552, "y": 932}, - "6": {"x": -1552, "y": 956} + "6": {"x": -1552, "y": 956}, + "7": {"x": -1552, "y": 956} } }, "warnings": null @@ -11052,13 +12482,8 @@ "sourcePortId": 1320, "targetNodeId": 167, "targetPortId": 1319, - "travelTime": { - "lock": true, - "time": 10, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 31, @@ -11087,6 +12512,20 @@ "timeFormatter": null, "consecutiveTime": 41 }, + "travelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 89, "resourceId": 0, @@ -11105,7 +12544,8 @@ "3": {"x": -2052, "y": 752}, "4": {"x": -2076, "y": 816}, "5": {"x": -2076, "y": 816}, - "6": {"x": -2052, "y": 816} + "6": {"x": -2052, "y": 816}, + "7": {"x": -2052, "y": 816} } }, "warnings": null @@ -11116,13 +12556,8 @@ "sourcePortId": 1322, "targetNodeId": 168, "targetPortId": 1321, - "travelTime": { - "lock": true, - "time": 25, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 4, @@ -11151,6 +12586,20 @@ "timeFormatter": null, "consecutiveTime": 29 }, + "travelTime": { + "lock": true, + "time": 25, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 25, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 89, "resourceId": 0, @@ -11169,7 +12618,8 @@ "3": {"x": -2084, "y": 1068}, "4": {"x": -2108, "y": 1230}, "5": {"x": -2108, "y": 1230}, - "6": {"x": -2084, "y": 1230} + "6": {"x": -2084, "y": 1230}, + "7": {"x": -2084, "y": 1230} } }, "warnings": null @@ -11180,13 +12630,8 @@ "sourcePortId": 1323, "targetNodeId": 168, "targetPortId": 1324, - "travelTime": { - "lock": true, - "time": 26, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 29, @@ -11215,6 +12660,20 @@ "timeFormatter": null, "consecutiveTime": 175 }, + "travelTime": { + "lock": true, + "time": 26, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 26, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 96, "resourceId": 0, @@ -11233,7 +12692,8 @@ "3": {"x": -2116, "y": 1068}, "4": {"x": -2140, "y": 1230}, "5": {"x": -2140, "y": 1230}, - "6": {"x": -2116, "y": 1230} + "6": {"x": -2116, "y": 1230}, + "7": {"x": -2116, "y": 1230} } }, "warnings": null @@ -11244,13 +12704,8 @@ "sourcePortId": 1325, "targetNodeId": 167, "targetPortId": 1326, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 58, @@ -11279,6 +12734,20 @@ "timeFormatter": null, "consecutiveTime": 186 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 96, "resourceId": 0, @@ -11297,7 +12766,8 @@ "3": {"x": -2116, "y": 752}, "4": {"x": -2140, "y": 816}, "5": {"x": -2140, "y": 816}, - "6": {"x": -2116, "y": 816} + "6": {"x": -2116, "y": 816}, + "7": {"x": -2116, "y": 816} } }, "warnings": null @@ -11308,13 +12778,8 @@ "sourcePortId": 1327, "targetNodeId": 129, "targetPortId": 1328, - "travelTime": { - "lock": true, - "time": 18, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 8, @@ -11343,6 +12808,20 @@ "timeFormatter": null, "consecutiveTime": 206 }, + "travelTime": { + "lock": true, + "time": 18, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 18, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 96, "resourceId": 0, @@ -11361,7 +12840,8 @@ "3": {"x": -2116, "y": 428}, "4": {"x": -2140, "y": 510}, "5": {"x": -2140, "y": 510}, - "6": {"x": -2116, "y": 510} + "6": {"x": -2116, "y": 510}, + "7": {"x": -2116, "y": 510} } }, "warnings": null @@ -11372,13 +12852,8 @@ "sourcePortId": 1329, "targetNodeId": 178, "targetPortId": 1330, - "travelTime": { - "lock": true, - "time": 3, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 34, @@ -11407,6 +12882,20 @@ "timeFormatter": null, "consecutiveTime": 217 }, + "travelTime": { + "lock": true, + "time": 3, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 3, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 96, "resourceId": 0, @@ -11425,7 +12914,8 @@ "3": {"x": -1744, "y": 188}, "4": {"x": -1856, "y": 164}, "5": {"x": -1856, "y": 164}, - "6": {"x": -1856, "y": 188} + "6": {"x": -1856, "y": 188}, + "7": {"x": -1856, "y": 188} } }, "warnings": null @@ -11436,13 +12926,8 @@ "sourcePortId": 1331, "targetNodeId": 144, "targetPortId": 1332, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 5, @@ -11471,6 +12956,20 @@ "timeFormatter": null, "consecutiveTime": 253 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 96, "resourceId": 0, @@ -11489,7 +12988,8 @@ "3": {"x": 124, "y": -308}, "4": {"x": 100, "y": -130}, "5": {"x": 100, "y": -130}, - "6": {"x": 124, "y": -130} + "6": {"x": 124, "y": -130}, + "7": {"x": 124, "y": -130} } }, "warnings": null @@ -11500,13 +13000,8 @@ "sourcePortId": 1333, "targetNodeId": 145, "targetPortId": 1334, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 13, @@ -11535,6 +13030,20 @@ "timeFormatter": null, "consecutiveTime": 259 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 96, "resourceId": 0, @@ -11553,7 +13062,8 @@ "3": {"x": 188, "y": -816}, "4": {"x": 164, "y": -656}, "5": {"x": 164, "y": -656}, - "6": {"x": 188, "y": -656} + "6": {"x": 188, "y": -656}, + "7": {"x": 188, "y": -656} } }, "warnings": null @@ -11564,13 +13074,8 @@ "sourcePortId": 1335, "targetNodeId": 146, "targetPortId": 1336, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 19, @@ -11599,6 +13104,20 @@ "timeFormatter": null, "consecutiveTime": 265 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 96, "resourceId": 0, @@ -11617,7 +13136,8 @@ "3": {"x": 188, "y": -1296}, "4": {"x": 164, "y": -1136}, "5": {"x": 164, "y": -1136}, - "6": {"x": 188, "y": -1136} + "6": {"x": 188, "y": -1136}, + "7": {"x": 188, "y": -1136} } }, "warnings": null @@ -11628,13 +13148,8 @@ "sourcePortId": 1337, "targetNodeId": 134, "targetPortId": 1338, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 25, @@ -11663,6 +13178,20 @@ "timeFormatter": null, "consecutiveTime": 272 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 96, "resourceId": 0, @@ -11681,7 +13210,8 @@ "3": {"x": 188, "y": -1776}, "4": {"x": 164, "y": -1616}, "5": {"x": 164, "y": -1616}, - "6": {"x": 188, "y": -1616} + "6": {"x": 188, "y": -1616}, + "7": {"x": 188, "y": -1616} } }, "warnings": null @@ -11692,13 +13222,8 @@ "sourcePortId": 1340, "targetNodeId": 129, "targetPortId": 1339, - "travelTime": { - "lock": false, - "time": 19, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 33, @@ -11725,7 +13250,21 @@ "time": 52, "warning": null, "timeFormatter": null, - "consecutiveTime": 52 + "consecutiveTime": 52 + }, + "travelTime": { + "lock": false, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 }, "numberOfStops": 0, "trainrunId": 90, @@ -11745,7 +13284,8 @@ "3": {"x": -2020, "y": 428}, "4": {"x": -2044, "y": 510}, "5": {"x": -2044, "y": 510}, - "6": {"x": -2020, "y": 510} + "6": {"x": -2020, "y": 510}, + "7": {"x": -2020, "y": 510} } }, "warnings": null @@ -11756,13 +13296,8 @@ "sourcePortId": 1342, "targetNodeId": 167, "targetPortId": 1341, - "travelTime": { - "lock": true, - "time": 10, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 22, @@ -11791,6 +13326,20 @@ "timeFormatter": null, "consecutiveTime": 32 }, + "travelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 90, "resourceId": 0, @@ -11809,7 +13358,8 @@ "3": {"x": -2020, "y": 752}, "4": {"x": -2044, "y": 816}, "5": {"x": -2044, "y": 816}, - "6": {"x": -2020, "y": 816} + "6": {"x": -2020, "y": 816}, + "7": {"x": -2020, "y": 816} } }, "warnings": null @@ -11820,13 +13370,8 @@ "sourcePortId": 1344, "targetNodeId": 168, "targetPortId": 1343, - "travelTime": { - "lock": true, - "time": 21, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 0, @@ -11855,6 +13400,20 @@ "timeFormatter": null, "consecutiveTime": 21 }, + "travelTime": { + "lock": true, + "time": 21, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 21, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 90, "resourceId": 0, @@ -11873,7 +13432,8 @@ "3": {"x": -1968, "y": 964}, "4": {"x": -1552, "y": 964}, "5": {"x": -1552, "y": 964}, - "6": {"x": -1552, "y": 988} + "6": {"x": -1552, "y": 964}, + "7": {"x": -1552, "y": 988} } }, "warnings": null @@ -11884,13 +13444,8 @@ "sourcePortId": 1345, "targetNodeId": 153, "targetPortId": 1346, - "travelTime": { - "lock": true, - "time": 9, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 48, @@ -11919,6 +13474,20 @@ "timeFormatter": null, "consecutiveTime": 57 }, + "travelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 79, "resourceId": 0, @@ -11937,7 +13506,8 @@ "3": {"x": 2608, "y": 1372}, "4": {"x": 2304, "y": 1556}, "5": {"x": 2304, "y": 1556}, - "6": {"x": 2304, "y": 1580} + "6": {"x": 2304, "y": 1580}, + "7": {"x": 2304, "y": 1580} } }, "warnings": null @@ -11948,13 +13518,8 @@ "sourcePortId": 1347, "targetNodeId": 153, "targetPortId": 1348, - "travelTime": { - "lock": true, - "time": 10, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 18, @@ -11983,6 +13548,20 @@ "timeFormatter": null, "consecutiveTime": 28 }, + "travelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 80, "resourceId": 0, @@ -12001,7 +13580,8 @@ "3": {"x": 2608, "y": 1340}, "4": {"x": 2304, "y": 1524}, "5": {"x": 2304, "y": 1524}, - "6": {"x": 2304, "y": 1548} + "6": {"x": 2304, "y": 1548}, + "7": {"x": 2304, "y": 1548} } }, "warnings": null @@ -12012,13 +13592,8 @@ "sourcePortId": 1349, "targetNodeId": 142, "targetPortId": 1350, - "travelTime": { - "lock": true, - "time": 9, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 33, @@ -12047,6 +13622,20 @@ "timeFormatter": null, "consecutiveTime": 462 }, + "travelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 77, "resourceId": 0, @@ -12065,7 +13654,8 @@ "3": {"x": 272, "y": 1764}, "4": {"x": 1040, "y": 1764}, "5": {"x": 1040, "y": 1764}, - "6": {"x": 1040, "y": 1788} + "6": {"x": 1040, "y": 1764}, + "7": {"x": 1040, "y": 1788} } }, "warnings": null @@ -12076,13 +13666,8 @@ "sourcePortId": 1351, "targetNodeId": 142, "targetPortId": 1352, - "travelTime": { - "lock": true, - "time": 9, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 33, @@ -12111,6 +13696,20 @@ "timeFormatter": null, "consecutiveTime": 282 }, + "travelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 75, "resourceId": 0, @@ -12129,7 +13728,8 @@ "3": {"x": 272, "y": 1732}, "4": {"x": 1040, "y": 1732}, "5": {"x": 1040, "y": 1732}, - "6": {"x": 1040, "y": 1756} + "6": {"x": 1040, "y": 1732}, + "7": {"x": 1040, "y": 1756} } }, "warnings": null @@ -12140,13 +13740,8 @@ "sourcePortId": 1353, "targetNodeId": 135, "targetPortId": 1354, - "travelTime": { - "lock": true, - "time": 11, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 14, @@ -12175,6 +13770,20 @@ "timeFormatter": null, "consecutiveTime": 85 }, + "travelTime": { + "lock": true, + "time": 11, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 11, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 79, "resourceId": 0, @@ -12193,7 +13802,8 @@ "3": {"x": 2844, "y": 396}, "4": {"x": 2820, "y": 542}, "5": {"x": 2820, "y": 542}, - "6": {"x": 2844, "y": 542} + "6": {"x": 2844, "y": 542}, + "7": {"x": 2844, "y": 542} } }, "warnings": null @@ -12204,13 +13814,8 @@ "sourcePortId": 1355, "targetNodeId": 135, "targetPortId": 1356, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 43, @@ -12239,6 +13844,20 @@ "timeFormatter": null, "consecutiveTime": 50 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 80, "resourceId": 0, @@ -12257,7 +13876,8 @@ "3": {"x": 2812, "y": 396}, "4": {"x": 2788, "y": 542}, "5": {"x": 2788, "y": 542}, - "6": {"x": 2812, "y": 542} + "6": {"x": 2812, "y": 542}, + "7": {"x": 2812, "y": 542} } }, "warnings": null @@ -12268,13 +13888,8 @@ "sourcePortId": 1357, "targetNodeId": 135, "targetPortId": 1358, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 47, @@ -12303,6 +13918,20 @@ "timeFormatter": null, "consecutiveTime": 355 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 78, "resourceId": 0, @@ -12321,7 +13950,8 @@ "3": {"x": 2780, "y": 396}, "4": {"x": 2756, "y": 542}, "5": {"x": 2756, "y": 542}, - "6": {"x": 2780, "y": 542} + "6": {"x": 2780, "y": 542}, + "7": {"x": 2780, "y": 542} } }, "warnings": null @@ -12332,13 +13962,8 @@ "sourcePortId": 1359, "targetNodeId": 135, "targetPortId": 1360, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 47, @@ -12367,6 +13992,20 @@ "timeFormatter": null, "consecutiveTime": 115 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 76, "resourceId": 0, @@ -12385,7 +14024,8 @@ "3": {"x": 2684, "y": 396}, "4": {"x": 2660, "y": 542}, "5": {"x": 2660, "y": 542}, - "6": {"x": 2684, "y": 542} + "6": {"x": 2684, "y": 542}, + "7": {"x": 2684, "y": 542} } }, "warnings": null @@ -12396,13 +14036,8 @@ "sourcePortId": 1361, "targetNodeId": 140, "targetPortId": 1362, - "travelTime": { - "lock": true, - "time": 47, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 15, @@ -12431,6 +14066,20 @@ "timeFormatter": null, "consecutiveTime": 122 }, + "travelTime": { + "lock": true, + "time": 47, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 47, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 85, "resourceId": 0, @@ -12449,7 +14098,8 @@ "3": {"x": 4592, "y": 1212}, "4": {"x": 3744, "y": 964}, "5": {"x": 3744, "y": 964}, - "6": {"x": 3744, "y": 988} + "6": {"x": 3744, "y": 988}, + "7": {"x": 3744, "y": 988} } }, "warnings": null @@ -12460,13 +14110,8 @@ "sourcePortId": 1363, "targetNodeId": 140, "targetPortId": 1364, - "travelTime": { - "lock": false, - "time": 61, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 21, @@ -12495,6 +14140,20 @@ "timeFormatter": null, "consecutiveTime": 202 }, + "travelTime": { + "lock": false, + "time": 61, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 61, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 5, "trainrunId": 86, "resourceId": 0, @@ -12513,7 +14172,8 @@ "3": {"x": 4592, "y": 1244}, "4": {"x": 3744, "y": 996}, "5": {"x": 3744, "y": 996}, - "6": {"x": 3744, "y": 1020} + "6": {"x": 3744, "y": 1020}, + "7": {"x": 3744, "y": 1020} } }, "warnings": null @@ -12521,16 +14181,11 @@ { "id": 675, "sourceNodeId": 142, - "sourcePortId": 1365, - "targetNodeId": 141, - "targetPortId": 1366, - "travelTime": { - "lock": true, - "time": 19, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourcePortId": 1365, + "targetNodeId": 141, + "targetPortId": 1366, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 55, @@ -12559,6 +14214,20 @@ "timeFormatter": null, "consecutiveTime": 494 }, + "travelTime": { + "lock": true, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 19, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 77, "resourceId": 0, @@ -12577,7 +14246,8 @@ "3": {"x": 156, "y": 1296}, "4": {"x": 132, "y": 1488}, "5": {"x": 132, "y": 1488}, - "6": {"x": 156, "y": 1488} + "6": {"x": 156, "y": 1488}, + "7": {"x": 156, "y": 1488} } }, "warnings": null @@ -12588,13 +14258,8 @@ "sourcePortId": 1367, "targetNodeId": 143, "targetPortId": 1368, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 14, @@ -12623,6 +14288,20 @@ "timeFormatter": null, "consecutiveTime": 501 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 77, "resourceId": 0, @@ -12641,7 +14320,8 @@ "3": {"x": 156, "y": 848}, "4": {"x": 132, "y": 992}, "5": {"x": 132, "y": 992}, - "6": {"x": 156, "y": 992} + "6": {"x": 156, "y": 992}, + "7": {"x": 156, "y": 992} } }, "warnings": null @@ -12652,13 +14332,8 @@ "sourcePortId": 1369, "targetNodeId": 133, "targetPortId": 1370, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 23, @@ -12687,6 +14362,20 @@ "timeFormatter": null, "consecutiveTime": 510 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 77, "resourceId": 0, @@ -12705,7 +14394,8 @@ "3": {"x": 124, "y": 396}, "4": {"x": 100, "y": 542}, "5": {"x": 100, "y": 542}, - "6": {"x": 124, "y": 542} + "6": {"x": 124, "y": 542}, + "7": {"x": 124, "y": 542} } }, "warnings": null @@ -12716,13 +14406,8 @@ "sourcePortId": 1371, "targetNodeId": 144, "targetPortId": 1372, - "travelTime": { - "lock": true, - "time": 10, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 32, @@ -12751,6 +14436,20 @@ "timeFormatter": null, "consecutiveTime": 522 }, + "travelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 77, "resourceId": 0, @@ -12769,7 +14468,8 @@ "3": {"x": 188, "y": -308}, "4": {"x": 164, "y": -130}, "5": {"x": 164, "y": -130}, - "6": {"x": 188, "y": -130} + "6": {"x": 188, "y": -130}, + "7": {"x": 188, "y": -130} } }, "warnings": null @@ -12780,13 +14480,8 @@ "sourcePortId": 1373, "targetNodeId": 145, "targetPortId": 1374, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 42, @@ -12815,6 +14510,20 @@ "timeFormatter": null, "consecutiveTime": 527 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 77, "resourceId": 0, @@ -12833,7 +14542,8 @@ "3": {"x": 252, "y": -816}, "4": {"x": 228, "y": -656}, "5": {"x": 228, "y": -656}, - "6": {"x": 252, "y": -656} + "6": {"x": 252, "y": -656}, + "7": {"x": 252, "y": -656} } }, "warnings": null @@ -12844,13 +14554,8 @@ "sourcePortId": 1375, "targetNodeId": 146, "targetPortId": 1376, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 47, @@ -12879,6 +14584,20 @@ "timeFormatter": null, "consecutiveTime": 532 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 77, "resourceId": 0, @@ -12897,7 +14616,8 @@ "3": {"x": 252, "y": -1296}, "4": {"x": 228, "y": -1136}, "5": {"x": 228, "y": -1136}, - "6": {"x": 252, "y": -1136} + "6": {"x": 252, "y": -1136}, + "7": {"x": 252, "y": -1136} } }, "warnings": null @@ -12908,13 +14628,8 @@ "sourcePortId": 1377, "targetNodeId": 134, "targetPortId": 1378, - "travelTime": { - "lock": true, - "time": 5, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 52, @@ -12943,6 +14658,20 @@ "timeFormatter": null, "consecutiveTime": 537 }, + "travelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 5, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 77, "resourceId": 0, @@ -12961,7 +14690,8 @@ "3": {"x": 252, "y": -1776}, "4": {"x": 228, "y": -1616}, "5": {"x": 228, "y": -1616}, - "6": {"x": 252, "y": -1616} + "6": {"x": 252, "y": -1616}, + "7": {"x": 252, "y": -1616} } }, "warnings": null @@ -12972,13 +14702,8 @@ "sourcePortId": 1379, "targetNodeId": 128, "targetPortId": 1380, - "travelTime": { - "lock": false, - "time": 49, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 27, @@ -13007,6 +14732,20 @@ "timeFormatter": null, "consecutiveTime": 436 }, + "travelTime": { + "lock": false, + "time": 49, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 49, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 2, "trainrunId": 81, "resourceId": 0, @@ -13025,7 +14764,8 @@ "3": {"x": -2928, "y": 580}, "4": {"x": -2768, "y": 452}, "5": {"x": -2768, "y": 452}, - "6": {"x": -2768, "y": 476} + "6": {"x": -2768, "y": 452}, + "7": {"x": -2768, "y": 476} } }, "warnings": null @@ -13036,13 +14776,8 @@ "sourcePortId": 1381, "targetNodeId": 128, "targetPortId": 1382, - "travelTime": { - "lock": true, - "time": 44, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 54, @@ -13071,6 +14806,20 @@ "timeFormatter": null, "consecutiveTime": 458 }, + "travelTime": { + "lock": true, + "time": 44, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 44, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 88, "resourceId": 0, @@ -13089,7 +14838,8 @@ "3": {"x": -2928, "y": 548}, "4": {"x": -2768, "y": 420}, "5": {"x": -2768, "y": 420}, - "6": {"x": -2768, "y": 444} + "6": {"x": -2768, "y": 420}, + "7": {"x": -2768, "y": 444} } }, "warnings": null @@ -13100,13 +14850,8 @@ "sourcePortId": 1383, "targetNodeId": 178, "targetPortId": 1384, - "travelTime": { - "lock": true, - "time": 16, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 39, @@ -13135,6 +14880,20 @@ "timeFormatter": null, "consecutiveTime": 355 }, + "travelTime": { + "lock": true, + "time": 16, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 16, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 81, "resourceId": 0, @@ -13153,7 +14912,8 @@ "3": {"x": -1552, "y": 292}, "4": {"x": -1104, "y": 292}, "5": {"x": -1104, "y": 292}, - "6": {"x": -1104, "y": 316} + "6": {"x": -1104, "y": 292}, + "7": {"x": -1104, "y": 316} } }, "warnings": null @@ -13164,13 +14924,8 @@ "sourcePortId": 1386, "targetNodeId": 172, "targetPortId": 1385, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 9, @@ -13199,6 +14954,20 @@ "timeFormatter": null, "consecutiveTime": 77 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 86, "resourceId": 0, @@ -13217,7 +14986,8 @@ "3": {"x": -656, "y": 348}, "4": {"x": -752, "y": 340}, "5": {"x": -752, "y": 340}, - "6": {"x": -752, "y": 364} + "6": {"x": -752, "y": 364}, + "7": {"x": -752, "y": 364} } }, "warnings": null @@ -13228,13 +14998,8 @@ "sourcePortId": 1388, "targetNodeId": 172, "targetPortId": 1387, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 5, @@ -13263,6 +15028,20 @@ "timeFormatter": null, "consecutiveTime": 73 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 90, "resourceId": 0, @@ -13281,7 +15060,8 @@ "3": {"x": -656, "y": 284}, "4": {"x": -1104, "y": 260}, "5": {"x": -1104, "y": 260}, - "6": {"x": -1104, "y": 284} + "6": {"x": -1104, "y": 284}, + "7": {"x": -1104, "y": 284} } }, "warnings": null @@ -13292,13 +15072,8 @@ "sourcePortId": 1390, "targetNodeId": 172, "targetPortId": 1389, - "travelTime": { - "lock": false, - "time": 17, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 6, @@ -13320,12 +15095,26 @@ "timeFormatter": null, "consecutiveTime": 337 }, - "targetArrival": { + "targetArrival": { + "lock": false, + "time": 23, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 83 + }, + "travelTime": { + "lock": false, + "time": 17, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { "lock": false, - "time": 23, + "time": 17, "warning": null, "timeFormatter": null, - "consecutiveTime": 83 + "consecutiveTime": 1 }, "numberOfStops": 0, "trainrunId": 89, @@ -13345,7 +15134,8 @@ "3": {"x": -656, "y": 252}, "4": {"x": -1104, "y": 228}, "5": {"x": -1104, "y": 228}, - "6": {"x": -1104, "y": 252} + "6": {"x": -1104, "y": 252}, + "7": {"x": -1104, "y": 252} } }, "warnings": null @@ -13356,13 +15146,8 @@ "sourcePortId": 1391, "targetNodeId": 178, "targetPortId": 1392, - "travelTime": { - "lock": true, - "time": 18, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 5, @@ -13391,6 +15176,20 @@ "timeFormatter": null, "consecutiveTime": 83 }, + "travelTime": { + "lock": true, + "time": 18, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 18, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 95, "resourceId": 0, @@ -13409,7 +15208,8 @@ "3": {"x": -1552, "y": 196}, "4": {"x": -1104, "y": 196}, "5": {"x": -1104, "y": 196}, - "6": {"x": -1104, "y": 220} + "6": {"x": -1104, "y": 196}, + "7": {"x": -1104, "y": 220} } }, "warnings": null @@ -13420,13 +15220,8 @@ "sourcePortId": 1393, "targetNodeId": 133, "targetPortId": 1394, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 54, @@ -13455,6 +15250,20 @@ "timeFormatter": null, "consecutiveTime": 242 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 96, "resourceId": 0, @@ -13473,7 +15282,8 @@ "3": {"x": 16, "y": 188}, "4": {"x": -224, "y": 164}, "5": {"x": -224, "y": 164}, - "6": {"x": -224, "y": 188} + "6": {"x": -224, "y": 188}, + "7": {"x": -224, "y": 188} } }, "warnings": null @@ -13484,13 +15294,8 @@ "sourcePortId": 1395, "targetNodeId": 178, "targetPortId": 1396, - "travelTime": { - "lock": true, - "time": 9, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 17, @@ -13519,6 +15324,20 @@ "timeFormatter": null, "consecutiveTime": 386 }, + "travelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 9, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 88, "resourceId": 0, @@ -13537,7 +15356,8 @@ "3": {"x": -1552, "y": 132}, "4": {"x": -1104, "y": 132}, "5": {"x": -1104, "y": 132}, - "6": {"x": -1104, "y": 156} + "6": {"x": -1104, "y": 132}, + "7": {"x": -1104, "y": 156} } }, "warnings": null @@ -13548,13 +15368,8 @@ "sourcePortId": 1398, "targetNodeId": 173, "targetPortId": 1397, - "travelTime": { - "lock": true, - "time": 10, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 39, @@ -13583,6 +15398,20 @@ "timeFormatter": null, "consecutiveTime": 49 }, + "travelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 10, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 86, "resourceId": 0, @@ -13601,7 +15430,8 @@ "3": {"x": -1392, "y": 380}, "4": {"x": -1472, "y": 340}, "5": {"x": -1472, "y": 340}, - "6": {"x": -1472, "y": 364} + "6": {"x": -1472, "y": 364}, + "7": {"x": -1472, "y": 364} } }, "warnings": null @@ -13612,13 +15442,8 @@ "sourcePortId": 1400, "targetNodeId": 174, "targetPortId": 1399, - "travelTime": { - "lock": true, - "time": 17, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 51, @@ -13647,6 +15472,20 @@ "timeFormatter": null, "consecutiveTime": 68 }, + "travelTime": { + "lock": true, + "time": 17, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 17, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 1, "trainrunId": 86, "resourceId": 0, @@ -13665,7 +15504,8 @@ "3": {"x": -1040, "y": 380}, "4": {"x": -1120, "y": 356}, "5": {"x": -1120, "y": 356}, - "6": {"x": -1120, "y": 380} + "6": {"x": -1120, "y": 380}, + "7": {"x": -1120, "y": 380} } }, "warnings": null @@ -13676,13 +15516,8 @@ "sourcePortId": 1402, "targetNodeId": 135, "targetPortId": 1401, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 52, @@ -13711,6 +15546,20 @@ "timeFormatter": null, "consecutiveTime": 60 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 85, "resourceId": 0, @@ -13729,7 +15578,8 @@ "3": {"x": 2608, "y": 92}, "4": {"x": 2496, "y": 68}, "5": {"x": 2496, "y": 68}, - "6": {"x": 2496, "y": 92} + "6": {"x": 2496, "y": 92}, + "7": {"x": 2496, "y": 92} } }, "warnings": null @@ -13740,13 +15590,8 @@ "sourcePortId": 1404, "targetNodeId": 149, "targetPortId": 1403, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 46, @@ -13775,6 +15620,20 @@ "timeFormatter": null, "consecutiveTime": 52 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 85, "resourceId": 0, @@ -13793,7 +15652,8 @@ "3": {"x": 2192, "y": 92}, "4": {"x": 2064, "y": 68}, "5": {"x": 2064, "y": 68}, - "6": {"x": 2064, "y": 92} + "6": {"x": 2064, "y": 92}, + "7": {"x": 2064, "y": 92} } }, "warnings": null @@ -13804,13 +15664,8 @@ "sourcePortId": 1406, "targetNodeId": 166, "targetPortId": 1405, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 40, @@ -13839,6 +15694,20 @@ "timeFormatter": null, "consecutiveTime": 46 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 85, "resourceId": 0, @@ -13857,7 +15726,8 @@ "3": {"x": 1744, "y": 92}, "4": {"x": 1616, "y": 68}, "5": {"x": 1616, "y": 68}, - "6": {"x": 1616, "y": 92} + "6": {"x": 1616, "y": 92}, + "7": {"x": 1616, "y": 92} } }, "warnings": null @@ -13868,13 +15738,8 @@ "sourcePortId": 1408, "targetNodeId": 148, "targetPortId": 1407, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 34, @@ -13903,6 +15768,20 @@ "timeFormatter": null, "consecutiveTime": 40 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 85, "resourceId": 0, @@ -13921,7 +15800,8 @@ "3": {"x": 1296, "y": 92}, "4": {"x": 1200, "y": 68}, "5": {"x": 1200, "y": 68}, - "6": {"x": 1200, "y": 92} + "6": {"x": 1200, "y": 92}, + "7": {"x": 1200, "y": 92} } }, "warnings": null @@ -13932,13 +15812,8 @@ "sourcePortId": 1410, "targetNodeId": 147, "targetPortId": 1409, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 27, @@ -13967,6 +15842,20 @@ "timeFormatter": null, "consecutiveTime": 34 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 85, "resourceId": 0, @@ -13985,7 +15874,8 @@ "3": {"x": 912, "y": 60}, "4": {"x": 640, "y": -204}, "5": {"x": 640, "y": -204}, - "6": {"x": 640, "y": -180} + "6": {"x": 640, "y": -180}, + "7": {"x": 640, "y": -180} } }, "warnings": null @@ -13996,13 +15886,8 @@ "sourcePortId": 1412, "targetNodeId": 144, "targetPortId": 1411, - "travelTime": { - "lock": true, - "time": 6, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 21, @@ -14031,6 +15916,20 @@ "timeFormatter": null, "consecutiveTime": 27 }, + "travelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 6, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 85, "resourceId": 0, @@ -14049,7 +15948,8 @@ "3": {"x": 100, "y": -496}, "4": {"x": 100, "y": -656}, "5": {"x": 100, "y": -656}, - "6": {"x": 124, "y": -656} + "6": {"x": 100, "y": -656}, + "7": {"x": 124, "y": -656} } }, "warnings": null @@ -14060,13 +15960,8 @@ "sourcePortId": 1414, "targetNodeId": 145, "targetPortId": 1413, - "travelTime": { - "lock": true, - "time": 7, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 14, @@ -14095,6 +15990,20 @@ "timeFormatter": null, "consecutiveTime": 21 }, + "travelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 7, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 85, "resourceId": 0, @@ -14113,7 +16022,8 @@ "3": {"x": 100, "y": -976}, "4": {"x": 100, "y": -1136}, "5": {"x": 100, "y": -1136}, - "6": {"x": 124, "y": -1136} + "6": {"x": 100, "y": -1136}, + "7": {"x": 124, "y": -1136} } }, "warnings": null @@ -14121,16 +16031,11 @@ { "id": 700, "sourceNodeId": 134, - "sourcePortId": 1416, - "targetNodeId": 146, - "targetPortId": 1415, - "travelTime": { - "lock": true, - "time": 8, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourcePortId": 1416, + "targetNodeId": 146, + "targetPortId": 1415, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 6, @@ -14159,6 +16064,20 @@ "timeFormatter": null, "consecutiveTime": 14 }, + "travelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 8, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 85, "resourceId": 0, @@ -14177,7 +16096,8 @@ "3": {"x": 100, "y": -1456}, "4": {"x": 100, "y": -1616}, "5": {"x": 100, "y": -1616}, - "6": {"x": 124, "y": -1616} + "6": {"x": 100, "y": -1616}, + "7": {"x": 124, "y": -1616} } }, "warnings": null @@ -14188,13 +16108,8 @@ "sourcePortId": 1417, "targetNodeId": 130, "targetPortId": 1418, - "travelTime": { - "lock": true, - "time": 13, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 1, @@ -14223,6 +16138,20 @@ "timeFormatter": null, "consecutiveTime": 434 }, + "travelTime": { + "lock": true, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 13, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 87, "resourceId": 0, @@ -14241,7 +16170,8 @@ "3": {"x": -2384, "y": -28}, "4": {"x": -2064, "y": -28}, "5": {"x": -2064, "y": -28}, - "6": {"x": -2064, "y": -4} + "6": {"x": -2064, "y": -28}, + "7": {"x": -2064, "y": -4} } }, "warnings": null @@ -14252,13 +16182,8 @@ "sourcePortId": 1420, "targetNodeId": 137, "targetPortId": 1419, - "travelTime": { - "lock": true, - "time": 16, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 39, @@ -14287,6 +16212,20 @@ "timeFormatter": null, "consecutiveTime": 295 }, + "travelTime": { + "lock": true, + "time": 16, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 16, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 87, "resourceId": 0, @@ -14305,7 +16244,8 @@ "3": {"x": 4784, "y": 100}, "4": {"x": 5056, "y": 100}, "5": {"x": 5056, "y": 100}, - "6": {"x": 5056, "y": 124} + "6": {"x": 5056, "y": 100}, + "7": {"x": 5056, "y": 124} } }, "warnings": null @@ -14316,13 +16256,8 @@ "sourcePortId": 1421, "targetNodeId": 160, "targetPortId": 1422, - "travelTime": { - "lock": false, - "time": 30, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 31, @@ -14351,6 +16286,20 @@ "timeFormatter": null, "consecutiveTime": 481 }, + "travelTime": { + "lock": false, + "time": 30, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 30, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 1, "trainrunId": 81, "resourceId": 0, @@ -14369,7 +16318,8 @@ "3": {"x": -3792, "y": 676}, "4": {"x": -3680, "y": 644}, "5": {"x": -3680, "y": 644}, - "6": {"x": -3680, "y": 668} + "6": {"x": -3680, "y": 644}, + "7": {"x": -3680, "y": 668} } }, "warnings": null @@ -14380,13 +16330,8 @@ "sourcePortId": 1423, "targetNodeId": 160, "targetPortId": 1424, - "travelTime": { - "lock": true, - "time": 26, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 52, @@ -14415,6 +16360,20 @@ "timeFormatter": null, "consecutiveTime": 498 }, + "travelTime": { + "lock": true, + "time": 26, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 26, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 88, "resourceId": 0, @@ -14433,7 +16392,8 @@ "3": {"x": -3792, "y": 612}, "4": {"x": -3680, "y": 580}, "5": {"x": -3680, "y": 580}, - "6": {"x": -3680, "y": 604} + "6": {"x": -3680, "y": 580}, + "7": {"x": -3680, "y": 604} } }, "warnings": null @@ -14444,13 +16404,8 @@ "sourcePortId": 1425, "targetNodeId": 160, "targetPortId": 1426, - "travelTime": { - "lock": false, - "time": 26, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 19, @@ -14479,6 +16434,20 @@ "timeFormatter": null, "consecutiveTime": 525 }, + "travelTime": { + "lock": false, + "time": 26, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": false, + "time": 26, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 87, "resourceId": 0, @@ -14497,7 +16466,8 @@ "3": {"x": -3792, "y": 644}, "4": {"x": -3680, "y": 612}, "5": {"x": -3680, "y": 612}, - "6": {"x": -3680, "y": 636} + "6": {"x": -3680, "y": 612}, + "7": {"x": -3680, "y": 636} } }, "warnings": null @@ -14508,13 +16478,8 @@ "sourcePortId": 1428, "targetNodeId": 178, "targetPortId": 1427, - "travelTime": { - "lock": true, - "time": 3, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 36, @@ -14543,6 +16508,20 @@ "timeFormatter": null, "consecutiveTime": 39 }, + "travelTime": { + "lock": true, + "time": 3, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 3, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 86, "resourceId": 0, @@ -14561,7 +16540,8 @@ "3": {"x": -1744, "y": 348}, "4": {"x": -1856, "y": 324}, "5": {"x": -1856, "y": 324}, - "6": {"x": -1856, "y": 348} + "6": {"x": -1856, "y": 348}, + "7": {"x": -1856, "y": 348} } }, "warnings": null @@ -14572,13 +16552,8 @@ "sourcePortId": 1429, "targetNodeId": 129, "targetPortId": 1430, - "travelTime": { - "lock": true, - "time": 4, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 55, @@ -14613,6 +16588,20 @@ "timeFormatter": null, "consecutiveTime": 360 }, + "travelTime": { + "lock": true, + "time": 4, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 4, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 81, "resourceId": 0, @@ -14631,7 +16620,8 @@ "3": {"x": -1968, "y": 292}, "4": {"x": -1856, "y": 292}, "5": {"x": -1856, "y": 292}, - "6": {"x": -1856, "y": 316} + "6": {"x": -1856, "y": 292}, + "7": {"x": -1856, "y": 316} } }, "warnings": null @@ -14642,13 +16632,8 @@ "sourcePortId": 1432, "targetNodeId": 178, "targetPortId": 1431, - "travelTime": { - "lock": true, - "time": 3, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 2, @@ -14677,6 +16662,20 @@ "timeFormatter": null, "consecutiveTime": 65 }, + "travelTime": { + "lock": true, + "time": 3, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 3, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 90, "resourceId": 0, @@ -14695,7 +16694,8 @@ "3": {"x": -1744, "y": 284}, "4": {"x": -1856, "y": 260}, "5": {"x": -1856, "y": 260}, - "6": {"x": -1856, "y": 284} + "6": {"x": -1856, "y": 284}, + "7": {"x": -1856, "y": 284} } }, "warnings": null @@ -14706,13 +16706,8 @@ "sourcePortId": 1434, "targetNodeId": 178, "targetPortId": 1433, - "travelTime": { - "lock": true, - "time": 3, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": true, "time": 3, @@ -14741,6 +16736,20 @@ "timeFormatter": null, "consecutiveTime": 66 }, + "travelTime": { + "lock": true, + "time": 3, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 3, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 89, "resourceId": 0, @@ -14759,7 +16768,8 @@ "3": {"x": -1744, "y": 252}, "4": {"x": -1856, "y": 228}, "5": {"x": -1856, "y": 228}, - "6": {"x": -1856, "y": 252} + "6": {"x": -1856, "y": 252}, + "7": {"x": -1856, "y": 252} } }, "warnings": null @@ -14770,13 +16780,8 @@ "sourcePortId": 1435, "targetNodeId": 129, "targetPortId": 1436, - "travelTime": { - "lock": true, - "time": 3, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 23, @@ -14805,6 +16810,20 @@ "timeFormatter": null, "consecutiveTime": 86 }, + "travelTime": { + "lock": true, + "time": 3, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 3, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 95, "resourceId": 0, @@ -14823,7 +16842,8 @@ "3": {"x": -1968, "y": 196}, "4": {"x": -1856, "y": 196}, "5": {"x": -1856, "y": 196}, - "6": {"x": -1856, "y": 220} + "6": {"x": -1856, "y": 196}, + "7": {"x": -1856, "y": 220} } }, "warnings": null @@ -14834,13 +16854,8 @@ "sourcePortId": 1437, "targetNodeId": 172, "targetPortId": 1438, - "travelTime": { - "lock": true, - "time": 17, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 37, @@ -14869,6 +16884,20 @@ "timeFormatter": null, "consecutiveTime": 234 }, + "travelTime": { + "lock": true, + "time": 17, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 17, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 96, "resourceId": 0, @@ -14887,7 +16916,8 @@ "3": {"x": -656, "y": 188}, "4": {"x": -1104, "y": 164}, "5": {"x": -1104, "y": 164}, - "6": {"x": -1104, "y": 188} + "6": {"x": -1104, "y": 188}, + "7": {"x": -1104, "y": 188} } }, "warnings": null @@ -14898,13 +16928,8 @@ "sourcePortId": 1439, "targetNodeId": 129, "targetPortId": 1440, - "travelTime": { - "lock": true, - "time": 3, - "warning": null, - "timeFormatter": null, - "consecutiveTime": 1 - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "lock": false, "time": 26, @@ -14933,6 +16958,20 @@ "timeFormatter": null, "consecutiveTime": 389 }, + "travelTime": { + "lock": true, + "time": 3, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, + "backwardTravelTime": { + "lock": true, + "time": 3, + "warning": null, + "timeFormatter": null, + "consecutiveTime": 1 + }, "numberOfStops": 0, "trainrunId": 88, "resourceId": 0, @@ -14951,7 +16990,8 @@ "3": {"x": -1968, "y": 132}, "4": {"x": -1856, "y": 132}, "5": {"x": -1856, "y": 132}, - "6": {"x": -1856, "y": 156} + "6": {"x": -1856, "y": 132}, + "7": {"x": -1856, "y": 156} } }, "warnings": null diff --git a/src/app/services/data/data.service.ts b/src/app/services/data/data.service.ts index ff6d2df45..c02dfb0cc 100644 --- a/src/app/services/data/data.service.ts +++ b/src/app/services/data/data.service.ts @@ -197,6 +197,14 @@ export class DataService implements OnDestroy { return this.trainrunService.getTrainruns(); } + getTrainrunSections() { + return this.trainrunSectionService.getTrainrunSections(); + } + + getTrainrunSectionsByTrainrunId(trainrunId: number) { + return this.trainrunSectionService.getAllTrainrunSectionsForTrainrun(trainrunId); + } + getTrainrunCategory(categoryId: number): TrainrunCategory { const found = this.netzgrafikDtoStore.netzgrafikDto.metadata.trainrunCategories.find( (trainrunCategory) => trainrunCategory.id === categoryId, diff --git a/src/app/services/data/node.service.ts b/src/app/services/data/node.service.ts index 484d77b83..cf3736c07 100644 --- a/src/app/services/data/node.service.ts +++ b/src/app/services/data/node.service.ts @@ -424,19 +424,22 @@ export class NodeService implements OnDestroy { // update the time Locks if (isTargetNodeEqToNodeId) { - this.trainrunSectionService.updateTrainrunSectionTimeLock( + this.trainrunSectionService.updateTrainrunSectionSourceTargetTimeLocks( trainrunSection1.getId(), timeLock1, timeLock2, + enforceUpdate, + ); + this.trainrunSectionService.updateSectionsChainTravelTimeLocks( + trainrunSection1.getId(), trainrunSection1.getTravelTimeLock(), enforceUpdate, ); } else { - this.trainrunSectionService.updateTrainrunSectionTimeLock( + this.trainrunSectionService.updateTrainrunSectionSourceTargetTimeLocks( trainrunSection1.getId(), timeLock2, timeLock1, - trainrunSection1.getTravelTimeLock(), enforceUpdate, ); } @@ -479,71 +482,32 @@ export class NodeService implements OnDestroy { trainrunSection.setTargetPortId(targetPortId); } - hasPathAnyDepartureOrArrivalTimeLock(node: Node, trainrunSection: TrainrunSection): boolean { - const iterator = this.trainrunService.getIterator(node, trainrunSection); - while (iterator.hasNext()) { - iterator.next(); - const currentTrainrunSection = iterator.current().trainrunSection; - if ( - currentTrainrunSection.getSourceDepartureLock() || - currentTrainrunSection.getTargetArrivalLock() - ) { - return true; - } - } - return false; - } - toggleNonStop(nodeId: number, transitionId: number) { const node = this.getNodeFromId(nodeId); node.toggleNonStop(transitionId); - const trainrunSections = node.getTrainrunSections(transitionId); - const node1 = node.getOppositeNode(trainrunSections.trainrunSection1); - const node2 = node.getOppositeNode(trainrunSections.trainrunSection2); - const isForwardPathLocked = this.hasPathAnyDepartureOrArrivalTimeLock( - node1, - trainrunSections.trainrunSection1, - ); - const isBackwardPathLocked = this.hasPathAnyDepartureOrArrivalTimeLock( - node2, - trainrunSections.trainrunSection2, - ); - if (!isForwardPathLocked) { - this.trainrunSectionService.iterateAlongTrainrunUntilEndAndPropagateTime( - node1, - trainrunSections.trainrunSection1.getId(), - ); - } - if (!isBackwardPathLocked) { - this.trainrunSectionService.iterateAlongTrainrunUntilEndAndPropagateTime( - node2, - trainrunSections.trainrunSection2.getId(), - ); - } + const sections = node.getTrainrunSections(transitionId); - if (isForwardPathLocked && isBackwardPathLocked) { - const warningTitle = $localize`:@@app.services.data.node.transit-modified.title:Transition changed`; - const warningDescription = $localize`:@@app.services.data.node.transit-modified.description:Times cannot be adjusted, lock found on both sides`; - this.trainrunSectionService.setWarningOnNode( - trainrunSections.trainrunSection1.getId(), - node.getId(), - warningTitle, - warningDescription, - ); - this.trainrunSectionService.setWarningOnNode( - trainrunSections.trainrunSection2.getId(), - node.getId(), - warningTitle, - warningDescription, - ); - } + // propagate times in source to target direction until end of trainrun + this.trainrunSectionService.propagateTimes( + sections.trainrunSection1.getId(), + true, + node.getId(), + false, + ); + + // update locks using the source section as reference + this.trainrunSectionService.updateSectionsChainTravelTimeLocks( + sections.trainrunSection1.getId(), + sections.trainrunSection1.getTravelTimeLock(), + true, + ); TransitionValidator.validateTransition(node, transitionId); this.transitionsUpdated(); this.nodesUpdated(); this.operation.emit( - new TrainrunOperation(OperationType.update, trainrunSections.trainrunSection1.getTrainrun()), + new TrainrunOperation(OperationType.update, sections.trainrunSection1.getTrainrun()), ); } @@ -1176,4 +1140,15 @@ export class NodeService implements OnDestroy { }); return labelIDCauntMap; } + + private createTransitionWarning(trainrunSection: TrainrunSection, node: Node) { + const warningTitle = $localize`:@@app.services.data.node.transit-modified.title:Transition changed`; + const warningDescription = $localize`:@@app.services.data.node.transit-modified.description:Times cannot be adjusted, the departure time is locked.`; + this.trainrunSectionService.setWarningOnNode( + trainrunSection.getId(), + node.getId(), + warningTitle, + warningDescription, + ); + } } diff --git a/src/app/services/data/trainrun-section-times.service.ts b/src/app/services/data/trainrun-section-times.service.ts index 72918035b..fa738058d 100644 --- a/src/app/services/data/trainrun-section-times.service.ts +++ b/src/app/services/data/trainrun-section-times.service.ts @@ -11,12 +11,17 @@ import {FilterService} from "../ui/filter.service"; import {TrainrunSection} from "../../models/trainrunsection.model"; import {Node} from "../../models/node.model"; import {LoadPerlenketteService} from "../../perlenkette/service/load-perlenkette.service"; +import { + SymmetryOn, + SymmetryReference, +} from "../../view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component"; @Injectable({ providedIn: "root", }) export class TrainrunSectionTimesService { private trainrunSectionHelper: TrainrunsectionHelper; + private onPerlenkette: boolean; private selectedTrainrunSection: TrainrunSection; private timeStructure: LeftAndRightTimeStructure; @@ -26,6 +31,7 @@ export class TrainrunSectionTimesService { rightDepartureTime: 0, rightArrivalTime: 0, travelTime: 0, + bottomTravelTime: 0, }; private nodesOrdered: Node[] = []; @@ -42,6 +48,7 @@ export class TrainrunSectionTimesService { private offsetTransformationActive = false; private highlightTravelTimeElement: boolean; + private highlightBottomTravelTimeElement: boolean; private initialLeftAndRightElement: LeftAndRightElement = LeftAndRightElement.LeftArrival; @@ -54,11 +61,13 @@ export class TrainrunSectionTimesService { this.trainrunSectionHelper = new TrainrunsectionHelper(this.trainrunService); } - public setTrainrunSection(trainrunSection: TrainrunSection) { + public setTrainrunSection(trainrunSection: TrainrunSection, onPerlenkette: boolean = false) { + this.onPerlenkette = onPerlenkette; this.selectedTrainrunSection = trainrunSection; this.originalTimeStructure = this.trainrunSectionHelper.getLeftAndRightTimes( this.selectedTrainrunSection, this.nodesOrdered, + onPerlenkette, ); this.timeStructure = Object.assign({}, this.originalTimeStructure); } @@ -107,6 +116,14 @@ export class TrainrunSectionTimesService { this.highlightTravelTimeElement = highlightTravelTimeElement; } + public getHighlightBottomTravelTimeElement() { + return this.highlightBottomTravelTimeElement; + } + + public setHighlightBottomTravelTimeElement(highlightBottomTravelTimeElement: boolean) { + this.highlightBottomTravelTimeElement = highlightBottomTravelTimeElement; + } + public setInitialLeftAndRightElement(initialLeftAndRightElement: LeftAndRightElement) { this.initialLeftAndRightElement = initialLeftAndRightElement; } @@ -137,22 +154,47 @@ export class TrainrunSectionTimesService { this.roundAllTimes(); this.removeOffsetAndBackTransformTimeStructure(); - this.timeStructure.leftArrivalTime = TrainrunsectionHelper.getSymmetricTime( - this.timeStructure.leftDepartureTime, - ); if (!this.lockStructure.rightLock) { this.timeStructure.rightArrivalTime = this.timeStructure.leftDepartureTime + (this.timeStructure.travelTime % 60); this.timeStructure.rightArrivalTime %= 60; - this.timeStructure.rightDepartureTime = TrainrunsectionHelper.getSymmetricTime( + this.timeStructure.rightDepartureTime = TrainrunsectionHelper.getAdjustedTimeBasedOnSymmetry( + this.isRightNodeSymmetric(), + this.timeStructure.rightDepartureTime, this.timeStructure.rightArrivalTime, ); + if (this.isLeftNodeSymmetric()) { + this.timeStructure.leftArrivalTime = TrainrunsectionHelper.getSymmetricTime( + this.timeStructure.leftDepartureTime, + ); + } else if (this.isRightNodeSymmetric()) { + if (this.lockStructure.leftLock && !this.lockStructure.travelTimeLock) { + this.timeStructure.bottomTravelTime = + this.timeStructure.leftArrivalTime - this.timeStructure.rightDepartureTime; + this.timeStructure.bottomTravelTime += this.timeStructure.bottomTravelTime <= 0 ? 60 : 0; + } else { + this.timeStructure.leftArrivalTime = + this.timeStructure.rightDepartureTime + (this.timeStructure.bottomTravelTime % 60); + this.timeStructure.leftArrivalTime %= 60; + } + } + if (!this.isRightNodeSymmetric()) { + this.timeStructure.rightDepartureTime = + this.timeStructure.leftArrivalTime - (this.timeStructure.bottomTravelTime % 60); + this.timeStructure.rightDepartureTime += this.timeStructure.rightDepartureTime < 0 ? 60 : 0; + } } else if (!this.lockStructure.travelTimeLock && this.lockStructure.rightLock) { - const extraHour = this.timeStructure.travelTime - (this.timeStructure.travelTime % 60); + this.timeStructure.leftArrivalTime = TrainrunsectionHelper.getAdjustedTimeBasedOnSymmetry( + this.isLeftNodeSymmetric(), + this.timeStructure.leftArrivalTime, + this.timeStructure.leftDepartureTime, + ); this.timeStructure.travelTime = this.timeStructure.rightArrivalTime - this.timeStructure.leftDepartureTime; - this.timeStructure.travelTime += this.timeStructure.travelTime < 0 ? 60 : 0; - this.timeStructure.travelTime += extraHour; + this.timeStructure.travelTime += this.timeStructure.travelTime <= 0 ? 60 : 0; + this.timeStructure.bottomTravelTime = + this.timeStructure.leftArrivalTime - this.timeStructure.rightDepartureTime; + this.timeStructure.bottomTravelTime += this.timeStructure.bottomTravelTime <= 0 ? 60 : 0; } else { this.showWarningTwoLocks = true; } @@ -183,22 +225,47 @@ export class TrainrunSectionTimesService { this.roundAllTimes(); this.removeOffsetAndBackTransformTimeStructure(); - this.timeStructure.leftDepartureTime = TrainrunsectionHelper.getSymmetricTime( - this.timeStructure.leftArrivalTime, - ); if (!this.lockStructure.rightLock) { this.timeStructure.rightDepartureTime = - this.timeStructure.leftArrivalTime - (this.timeStructure.travelTime % 60); + this.timeStructure.leftArrivalTime - (this.timeStructure.bottomTravelTime % 60); this.timeStructure.rightDepartureTime += this.timeStructure.rightDepartureTime < 0 ? 60 : 0; - this.timeStructure.rightArrivalTime = TrainrunsectionHelper.getSymmetricTime( - this.timeStructure.rightDepartureTime, + this.timeStructure.leftDepartureTime = TrainrunsectionHelper.getAdjustedTimeBasedOnSymmetry( + this.isLeftNodeSymmetric(), + this.timeStructure.leftDepartureTime, + this.timeStructure.leftArrivalTime, ); + if (this.isRightNodeSymmetric()) { + this.timeStructure.rightArrivalTime = TrainrunsectionHelper.getSymmetricTime( + this.timeStructure.rightDepartureTime, + ); + } else { + this.timeStructure.rightArrivalTime = + this.timeStructure.leftDepartureTime + (this.timeStructure.travelTime % 60); + this.timeStructure.rightArrivalTime %= 60; + } + if (!this.isLeftNodeSymmetric()) { + if (this.lockStructure.leftLock) { + this.timeStructure.travelTime = + this.timeStructure.rightArrivalTime - this.timeStructure.leftDepartureTime; + this.timeStructure.travelTime += this.timeStructure.travelTime <= 0 ? 60 : 0; + } else { + this.timeStructure.leftDepartureTime = + this.timeStructure.rightArrivalTime - (this.timeStructure.travelTime % 60); + this.timeStructure.leftDepartureTime += this.timeStructure.leftDepartureTime < 0 ? 60 : 0; + } + } } else if (!this.lockStructure.travelTimeLock && this.lockStructure.rightLock) { - const extraHour = this.timeStructure.travelTime - (this.timeStructure.travelTime % 60); - this.timeStructure.travelTime = + this.timeStructure.leftDepartureTime = TrainrunsectionHelper.getAdjustedTimeBasedOnSymmetry( + this.isLeftNodeSymmetric(), + this.timeStructure.leftDepartureTime, + this.timeStructure.leftArrivalTime, + ); + this.timeStructure.bottomTravelTime = this.timeStructure.leftArrivalTime - this.timeStructure.rightDepartureTime; - this.timeStructure.travelTime += this.timeStructure.travelTime < 0 ? 60 : 0; - this.timeStructure.travelTime += extraHour; + this.timeStructure.bottomTravelTime += this.timeStructure.bottomTravelTime <= 0 ? 60 : 0; + this.timeStructure.travelTime = + this.timeStructure.rightArrivalTime - this.timeStructure.leftDepartureTime; + this.timeStructure.travelTime += this.timeStructure.travelTime <= 0 ? 60 : 0; } else { this.showWarningTwoLocks = true; } @@ -228,23 +295,49 @@ export class TrainrunSectionTimesService { this.showWarningTwoLocks = false; this.roundAllTimes(); this.removeOffsetAndBackTransformTimeStructure(); - this.timeStructure.rightDepartureTime = TrainrunsectionHelper.getSymmetricTime( - this.timeStructure.rightArrivalTime, - ); if (!this.lockStructure.leftLock) { this.timeStructure.leftDepartureTime = this.timeStructure.rightArrivalTime - (this.timeStructure.travelTime % 60); this.timeStructure.leftDepartureTime += this.timeStructure.leftDepartureTime < 0 ? 60 : 0; - this.timeStructure.leftArrivalTime = TrainrunsectionHelper.getSymmetricTime( - this.timeStructure.leftDepartureTime, + this.timeStructure.rightDepartureTime = TrainrunsectionHelper.getAdjustedTimeBasedOnSymmetry( + this.isRightNodeSymmetric(), + this.timeStructure.rightDepartureTime, + this.timeStructure.rightArrivalTime, ); + if (this.isLeftNodeSymmetric()) { + this.timeStructure.leftArrivalTime = TrainrunsectionHelper.getSymmetricTime( + this.timeStructure.leftDepartureTime, + ); + } else { + this.timeStructure.leftArrivalTime = + this.timeStructure.rightDepartureTime + (this.timeStructure.bottomTravelTime % 60); + this.timeStructure.leftArrivalTime %= 60; + } + if (!this.isRightNodeSymmetric()) { + if (this.lockStructure.rightLock) { + this.timeStructure.bottomTravelTime = + this.timeStructure.leftArrivalTime - this.timeStructure.rightDepartureTime; + this.timeStructure.bottomTravelTime += this.timeStructure.bottomTravelTime <= 0 ? 60 : 0; + } else { + this.timeStructure.rightDepartureTime = + this.timeStructure.leftArrivalTime - (this.timeStructure.bottomTravelTime % 60); + this.timeStructure.rightDepartureTime += + this.timeStructure.rightDepartureTime < 0 ? 60 : 0; + } + } } else if (!this.lockStructure.travelTimeLock && this.lockStructure.leftLock) { - const extraHour = this.timeStructure.travelTime - (this.timeStructure.travelTime % 60); + this.timeStructure.rightDepartureTime = TrainrunsectionHelper.getAdjustedTimeBasedOnSymmetry( + this.isRightNodeSymmetric(), + this.timeStructure.rightDepartureTime, + this.timeStructure.rightArrivalTime, + ); this.timeStructure.travelTime = this.timeStructure.rightArrivalTime - this.timeStructure.leftDepartureTime; - this.timeStructure.travelTime += this.timeStructure.travelTime < 0 ? 60 : 0; - this.timeStructure.travelTime += extraHour; + this.timeStructure.travelTime += this.timeStructure.travelTime <= 0 ? 60 : 0; + this.timeStructure.bottomTravelTime = + this.timeStructure.leftArrivalTime - this.timeStructure.rightDepartureTime; + this.timeStructure.bottomTravelTime += this.timeStructure.bottomTravelTime <= 0 ? 60 : 0; } else { this.showWarningTwoLocks = true; } @@ -275,22 +368,47 @@ export class TrainrunSectionTimesService { this.roundAllTimes(); this.removeOffsetAndBackTransformTimeStructure(); - this.timeStructure.rightArrivalTime = TrainrunsectionHelper.getSymmetricTime( - this.timeStructure.rightDepartureTime, - ); if (!this.lockStructure.leftLock) { this.timeStructure.leftArrivalTime = - this.timeStructure.rightDepartureTime + (this.timeStructure.travelTime % 60); + this.timeStructure.rightDepartureTime + (this.timeStructure.bottomTravelTime % 60); this.timeStructure.leftArrivalTime %= 60; - this.timeStructure.leftDepartureTime = TrainrunsectionHelper.getSymmetricTime( + this.timeStructure.leftDepartureTime = TrainrunsectionHelper.getAdjustedTimeBasedOnSymmetry( + this.isLeftNodeSymmetric(), + this.timeStructure.leftDepartureTime, this.timeStructure.leftArrivalTime, ); + if (this.isRightNodeSymmetric()) { + this.timeStructure.rightArrivalTime = TrainrunsectionHelper.getSymmetricTime( + this.timeStructure.rightDepartureTime, + ); + } else if (this.isLeftNodeSymmetric()) { + if (this.lockStructure.rightLock && !this.lockStructure.travelTimeLock) { + this.timeStructure.travelTime = + this.timeStructure.rightArrivalTime - this.timeStructure.leftDepartureTime; + this.timeStructure.travelTime += this.timeStructure.travelTime <= 0 ? 60 : 0; + } else { + this.timeStructure.rightArrivalTime = + this.timeStructure.leftDepartureTime + (this.timeStructure.travelTime % 60); + this.timeStructure.rightArrivalTime %= 60; + } + } + if (!this.isLeftNodeSymmetric()) { + this.timeStructure.leftDepartureTime = + this.timeStructure.rightArrivalTime - (this.timeStructure.travelTime % 60); + this.timeStructure.leftDepartureTime += this.timeStructure.leftDepartureTime < 0 ? 60 : 0; + } } else if (!this.lockStructure.travelTimeLock && this.lockStructure.leftLock) { - const extraHour = this.timeStructure.travelTime - (this.timeStructure.travelTime % 60); + this.timeStructure.rightArrivalTime = TrainrunsectionHelper.getAdjustedTimeBasedOnSymmetry( + this.isRightNodeSymmetric(), + this.timeStructure.rightArrivalTime, + this.timeStructure.rightDepartureTime, + ); this.timeStructure.travelTime = + this.timeStructure.rightArrivalTime - this.timeStructure.leftDepartureTime; + this.timeStructure.travelTime += this.timeStructure.travelTime <= 0 ? 60 : 0; + this.timeStructure.bottomTravelTime = this.timeStructure.leftArrivalTime - this.timeStructure.rightDepartureTime; - this.timeStructure.travelTime += this.timeStructure.travelTime < 0 ? 60 : 0; - this.timeStructure.travelTime += extraHour; + this.timeStructure.bottomTravelTime += this.timeStructure.bottomTravelTime <= 0 ? 60 : 0; } else { this.showWarningTwoLocks = true; } @@ -300,47 +418,133 @@ export class TrainrunSectionTimesService { } /* Travel Time */ - onInputTravelTimeElementButtonPlus() { + onTravelTimeButtonPlus() { this.timeStructure.travelTime += this.getTimeButtonPlusMinusStep(this.timeStructure.travelTime); this.highlightTravelTimeElement = false; - this.onInputTravelTimeChanged(); + this.onTravelTimeChanged(); } - onInputTravelTimeElementButtonMinus() { + onTravelTimeButtonMinus() { this.timeStructure.travelTime -= this.getTimeButtonPlusMinusStep(this.timeStructure.travelTime); this.timeStructure.travelTime = Math.max(1, this.timeStructure.travelTime); this.highlightTravelTimeElement = false; - this.onInputTravelTimeChanged(); + this.onTravelTimeChanged(); } - updateTravelTimeChanged() { + onTravelTimeChanged() { this.showWarningTwoLocks = false; this.roundAllTimes(); + this.removeOffsetAndBackTransformTimeStructure(); + + if (this.selectedTrainrunSection.isSymmetric()) { + this.timeStructure.bottomTravelTime = this.timeStructure.travelTime; + } if (!this.lockStructure.rightLock) { this.timeStructure.rightArrivalTime = this.timeStructure.leftDepartureTime + this.timeStructure.travelTime; this.timeStructure.rightArrivalTime += this.timeStructure.rightArrivalTime < 0 ? 60 : 0; this.timeStructure.rightArrivalTime %= 60; - this.timeStructure.rightDepartureTime = TrainrunsectionHelper.getSymmetricTime( + this.timeStructure.rightDepartureTime = TrainrunsectionHelper.getAdjustedTimeBasedOnSymmetry( + this.isRightNodeSymmetric(), + this.timeStructure.rightDepartureTime, this.timeStructure.rightArrivalTime, ); - } else if (!this.lockStructure.leftLock) { + if (!this.selectedTrainrunSection.isSymmetric()) { + if (this.lockStructure.leftLock) { + this.timeStructure.bottomTravelTime = + this.timeStructure.leftArrivalTime - this.timeStructure.rightDepartureTime; + this.timeStructure.bottomTravelTime += this.timeStructure.bottomTravelTime <= 0 ? 60 : 0; + } else { + this.timeStructure.leftArrivalTime = + this.timeStructure.rightDepartureTime + this.timeStructure.bottomTravelTime; + this.timeStructure.leftArrivalTime += this.timeStructure.leftArrivalTime < 0 ? 60 : 0; + this.timeStructure.leftArrivalTime %= 60; + } + } + } else if (!this.lockStructure.leftLock && this.lockStructure.rightLock) { + this.timeStructure.leftDepartureTime = + this.timeStructure.rightArrivalTime - this.timeStructure.travelTime; + this.timeStructure.leftDepartureTime += this.timeStructure.leftDepartureTime < 0 ? 60 : 0; + this.timeStructure.leftDepartureTime %= 60; + if (this.isLeftNodeSymmetric()) { + this.timeStructure.leftArrivalTime = TrainrunsectionHelper.getSymmetricTime( + this.timeStructure.leftDepartureTime, + ); + this.timeStructure.bottomTravelTime = + this.timeStructure.leftArrivalTime - this.timeStructure.rightDepartureTime; + this.timeStructure.bottomTravelTime += this.timeStructure.bottomTravelTime <= 0 ? 60 : 0; + } + } else { + this.showWarningTwoLocks = true; + } + + this.updateTrainrunSectionTime(); + this.applyOffsetAndTransformTimeStructure(); + } + + /* Bottom Travel Time */ + onBottomTravelTimeButtonPlus() { + this.timeStructure.bottomTravelTime += this.getTimeButtonPlusMinusStep( + this.timeStructure.bottomTravelTime, + ); + this.highlightBottomTravelTimeElement = false; + this.onBottomTravelTimeChanged(); + } + + onBottomTravelTimeButtonMinus() { + this.timeStructure.bottomTravelTime -= this.getTimeButtonPlusMinusStep( + this.timeStructure.bottomTravelTime, + ); + this.timeStructure.bottomTravelTime = Math.max(1, this.timeStructure.bottomTravelTime); + this.highlightBottomTravelTimeElement = false; + this.onBottomTravelTimeChanged(); + } + + onBottomTravelTimeChanged() { + this.showWarningTwoLocks = false; + this.roundAllTimes(); + this.removeOffsetAndBackTransformTimeStructure(); + + if (!this.lockStructure.leftLock) { this.timeStructure.leftArrivalTime = - this.timeStructure.rightDepartureTime + this.timeStructure.travelTime; + this.timeStructure.rightDepartureTime + this.timeStructure.bottomTravelTime; this.timeStructure.leftArrivalTime += this.timeStructure.leftArrivalTime < 0 ? 60 : 0; this.timeStructure.leftArrivalTime %= 60; - this.timeStructure.leftDepartureTime = TrainrunsectionHelper.getSymmetricTime( + this.timeStructure.leftDepartureTime = TrainrunsectionHelper.getAdjustedTimeBasedOnSymmetry( + this.isLeftNodeSymmetric(), + this.timeStructure.leftDepartureTime, this.timeStructure.leftArrivalTime, ); + if (!this.selectedTrainrunSection.isSymmetric()) { + if (this.lockStructure.rightLock) { + this.timeStructure.travelTime = + this.timeStructure.rightArrivalTime - this.timeStructure.leftDepartureTime; + this.timeStructure.travelTime += this.timeStructure.travelTime <= 0 ? 60 : 0; + } else { + this.timeStructure.rightArrivalTime = + this.timeStructure.leftDepartureTime + this.timeStructure.travelTime; + this.timeStructure.rightArrivalTime += this.timeStructure.rightArrivalTime < 0 ? 60 : 0; + this.timeStructure.rightArrivalTime %= 60; + } + } + } else if (this.lockStructure.leftLock && !this.lockStructure.rightLock) { + this.timeStructure.rightDepartureTime = + this.timeStructure.leftArrivalTime - this.timeStructure.bottomTravelTime; + this.timeStructure.rightDepartureTime += this.timeStructure.rightDepartureTime < 0 ? 60 : 0; + this.timeStructure.rightDepartureTime %= 60; + if (this.isRightNodeSymmetric()) { + this.timeStructure.rightArrivalTime = TrainrunsectionHelper.getSymmetricTime( + this.timeStructure.rightDepartureTime, + ); + this.timeStructure.travelTime = + this.timeStructure.rightArrivalTime - this.timeStructure.leftDepartureTime; + this.timeStructure.travelTime += this.timeStructure.travelTime <= 0 ? 60 : 0; + } } else { this.showWarningTwoLocks = true; } - } - onInputTravelTimeChanged() { - this.removeOffsetAndBackTransformTimeStructure(); - this.updateTravelTimeChanged(); this.updateTrainrunSectionTime(); this.applyOffsetAndTransformTimeStructure(); } @@ -366,54 +570,146 @@ export class TrainrunSectionTimesService { } updateTrainrunSectionTimeLock() { - const leftRight = this.trainrunSectionHelper.getLeftRightSections(this.selectedTrainrunSection); + const sections = this.trainrunService.getNonStopSectionsChain(this.selectedTrainrunSection); + const firstSection = sections[0]; + const lastSection = sections[sections.length - 1]; - this.trainrunSectionService.updateTrainrunSectionTimeLock( - leftRight.leftSection.getId(), - this.trainrunSectionHelper.getSourceLock(this.lockStructure, leftRight.leftSection), - this.trainrunSectionHelper.getTargetLock(this.lockStructure, leftRight.leftSection), - this.lockStructure.travelTimeLock, + this.trainrunSectionService.updateTrainrunSectionSourceTargetTimeLocks( + firstSection.getId(), + this.trainrunSectionHelper.getSourceLock(this.lockStructure, firstSection), + this.trainrunSectionHelper.getTargetLock(this.lockStructure, firstSection), true, ); - this.trainrunSectionService.updateTrainrunSectionTimeLock( - leftRight.rightSection.getId(), - this.trainrunSectionHelper.getSourceLock(this.lockStructure, leftRight.rightSection), - this.trainrunSectionHelper.getTargetLock(this.lockStructure, leftRight.rightSection), - undefined, + this.trainrunSectionService.updateSectionsChainTravelTimeLocks( + firstSection.getId(), + this.lockStructure.travelTimeLock, + ); + + this.trainrunSectionService.updateTrainrunSectionSourceTargetTimeLocks( + lastSection.getId(), + this.trainrunSectionHelper.getSourceLock(this.lockStructure, lastSection), + this.trainrunSectionHelper.getTargetLock(this.lockStructure, lastSection), true, ); } + /* Symmetry */ + onLeftNodeSymmetryChanged( + isLeftNodeSymmetric: boolean, + isPositionSwapped: boolean, + reference: SymmetryReference = null, + ) { + if (isPositionSwapped) { + this.trainrunSectionService.updateTargetSymmetry( + this.selectedTrainrunSection.getId(), + isLeftNodeSymmetric, + ); + } else { + this.trainrunSectionService.updateSourceSymmetry( + this.selectedTrainrunSection.getId(), + isLeftNodeSymmetric, + ); + } + + if (reference === null) return; + + this.removeOffsetAndBackTransformTimeStructure(); + this.timeStructure = this.calculateTimeStructureAfterSymmetrySelection( + SymmetryOn.LeftNode, + reference, + ); + this.updateTrainrunSectionTime(); + this.applyOffsetAndTransformTimeStructure(); + } + + onRightNodeSymmetryChanged( + isRightNodeSymmetric: boolean, + isPositionSwapped: boolean, + reference: SymmetryReference = null, + ) { + if (isPositionSwapped) { + this.trainrunSectionService.updateSourceSymmetry( + this.selectedTrainrunSection.getId(), + isRightNodeSymmetric, + ); + } else { + this.trainrunSectionService.updateTargetSymmetry( + this.selectedTrainrunSection.getId(), + isRightNodeSymmetric, + ); + } + + if (reference === null) return; + + this.removeOffsetAndBackTransformTimeStructure(); + this.timeStructure = this.calculateTimeStructureAfterSymmetrySelection( + SymmetryOn.RightNode, + reference, + ); + this.updateTrainrunSectionTime(); + this.applyOffsetAndTransformTimeStructure(); + } + + onTrainrunSymmetryChanged(trainrunId: number, reference: SymmetryReference = null) { + this.trainrunSectionService.getAllTrainrunSectionsForTrainrun(trainrunId).forEach((section) => { + if (!reference) { + // on/off case + section.resetSymmetry(); + } else { + this.removeOffsetAndBackTransformTimeStructure(); + section.resetSymmetry(); + this.updateTrainrunSectionTime( + section, + this.calculateTimeStructureAfterSymmetrySelectionForTrainrunSection(reference, section), + ); + this.applyOffsetAndTransformTimeStructure(); + } + }); + } + /* Buttons in Footer */ - onPropagateTimeLeft(trainrunSection: TrainrunSection) { + onPropagateTimeLeft(trainrunSection: TrainrunSection, fromPerlenkette: boolean = false) { const nextStopRightNodeId = this.trainrunSectionHelper .getNextStopRightNode(trainrunSection, this.nodesOrdered) .getId(); - this.trainrunSectionService.propagateTimeAlongTrainrun( + this.trainrunSectionService.propagateTimes( trainrunSection.getId(), + !TrainrunsectionHelper.isTargetRightOrBottom(trainrunSection), nextStopRightNodeId, + false, ); - this.loadPerlenketteService.render(); + if (fromPerlenkette) { + this.loadPerlenketteService.render(); + } } - onPropagateTimeRight(trainrunSection: TrainrunSection) { + onPropagateTimeRight(trainrunSection: TrainrunSection, fromPerlenkette: boolean = false) { const nextStopLeftNodeId = this.trainrunSectionHelper .getNextStopLeftNode(trainrunSection, this.nodesOrdered) .getId(); - this.trainrunSectionService.propagateTimeAlongTrainrun( + this.trainrunSectionService.propagateTimes( trainrunSection.getId(), + TrainrunsectionHelper.isTargetRightOrBottom(trainrunSection), nextStopLeftNodeId, + false, ); - this.loadPerlenketteService.render(); + if (fromPerlenkette) { + this.loadPerlenketteService.render(); + } } applyOffsetAndTransformTimeStructure() { this.originalTimeStructure = this.trainrunSectionHelper.getLeftAndRightTimes( this.selectedTrainrunSection, this.nodesOrdered, + this.onPerlenkette, ); - this.timeStructure = Object.assign({}, this.originalTimeStructure); + + // TODO: not sure if it's important to keep this, but it breaks the asymmetry + if (this.selectedTrainrunSection.isSymmetric()) { + this.timeStructure = Object.assign({}, this.originalTimeStructure); + } const maxMinutes = 7 * 24 * 60; if ( @@ -469,10 +765,248 @@ export class TrainrunSectionTimesService { this.originalTimeStructure = this.trainrunSectionHelper.getLeftAndRightTimes( this.selectedTrainrunSection, this.nodesOrdered, + this.onPerlenkette, ); this.offsetTransformationActive = false; } + getTrainrunLeftAndRightTimeStructure(): Omit< + LeftAndRightTimeStructure, + "travelTime" | "bottomTravelTime" + > { + const {firstTrainrunSection, lastTrainrunSection, swapped} = + this.trainrunService.getFirstAndLastTrainrunSections( + this.selectedTrainrunSection.getTrainrunId(), + ); + return { + leftDepartureTime: swapped + ? firstTrainrunSection.getTargetDeparture() + : firstTrainrunSection.getSourceDeparture(), + leftArrivalTime: swapped + ? firstTrainrunSection.getTargetArrival() + : firstTrainrunSection.getSourceArrival(), + rightDepartureTime: swapped + ? lastTrainrunSection.getSourceDeparture() + : lastTrainrunSection.getTargetDeparture(), + rightArrivalTime: swapped + ? lastTrainrunSection.getSourceArrival() + : lastTrainrunSection.getTargetArrival(), + }; + } + + calculateTimeStructureAfterSymmetrySelection( + symmetryOn: SymmetryOn, + reference: SymmetryReference, + ): LeftAndRightTimeStructure { + const timeStructure = Object.assign({}, this.timeStructure); + switch (symmetryOn) { + case SymmetryOn.LeftNode: { + if (reference === SymmetryReference.Top) { + timeStructure.leftArrivalTime = TrainrunsectionHelper.getSymmetricTime( + timeStructure.leftDepartureTime, + ); + } else { + timeStructure.leftDepartureTime = TrainrunsectionHelper.getSymmetricTime( + timeStructure.leftArrivalTime, + ); + } + if (this.isRightNodeSymmetric()) { + if (reference === SymmetryReference.Top) { + timeStructure.bottomTravelTime = timeStructure.travelTime; + } else { + timeStructure.travelTime = timeStructure.bottomTravelTime; + } + timeStructure.rightArrivalTime = + timeStructure.leftDepartureTime + timeStructure.travelTime; + timeStructure.rightArrivalTime %= 60; + timeStructure.rightDepartureTime = TrainrunsectionHelper.getSymmetricTime( + timeStructure.rightArrivalTime, + ); + } else { + if (!this.lockStructure.rightLock) { + timeStructure.rightDepartureTime = + timeStructure.leftArrivalTime - timeStructure.bottomTravelTime; + timeStructure.rightDepartureTime += timeStructure.rightDepartureTime < 0 ? 60 : 0; + timeStructure.rightDepartureTime %= 60; + timeStructure.rightArrivalTime = + timeStructure.leftDepartureTime + timeStructure.travelTime; + timeStructure.rightArrivalTime %= 60; + } else if (!this.lockStructure.travelTimeLock) { + timeStructure.travelTime = + timeStructure.rightArrivalTime - timeStructure.leftDepartureTime; + timeStructure.travelTime += timeStructure.travelTime <= 0 ? 60 : 0; + timeStructure.bottomTravelTime = + timeStructure.leftArrivalTime - timeStructure.rightDepartureTime; + timeStructure.bottomTravelTime += timeStructure.bottomTravelTime <= 0 ? 60 : 0; + } + } + return timeStructure; + } + + case SymmetryOn.RightNode: { + if (reference === SymmetryReference.Top) { + timeStructure.rightDepartureTime = TrainrunsectionHelper.getSymmetricTime( + timeStructure.rightArrivalTime, + ); + } else { + timeStructure.rightArrivalTime = TrainrunsectionHelper.getSymmetricTime( + timeStructure.rightDepartureTime, + ); + } + if (this.isLeftNodeSymmetric()) { + if (reference === SymmetryReference.Top) { + timeStructure.bottomTravelTime = timeStructure.travelTime; + } else { + timeStructure.travelTime = timeStructure.bottomTravelTime; + } + timeStructure.leftArrivalTime = + timeStructure.rightDepartureTime + timeStructure.bottomTravelTime; + timeStructure.leftArrivalTime %= 60; + timeStructure.leftDepartureTime = TrainrunsectionHelper.getSymmetricTime( + timeStructure.leftArrivalTime, + ); + } else { + if (!this.lockStructure.leftLock) { + timeStructure.leftDepartureTime = + timeStructure.rightArrivalTime - timeStructure.travelTime; + timeStructure.leftDepartureTime += timeStructure.leftDepartureTime < 0 ? 60 : 0; + timeStructure.leftDepartureTime %= 60; + timeStructure.leftArrivalTime = + timeStructure.rightDepartureTime + timeStructure.bottomTravelTime; + timeStructure.leftArrivalTime %= 60; + } else if (!this.lockStructure.travelTimeLock) { + timeStructure.travelTime = + timeStructure.rightArrivalTime - timeStructure.leftDepartureTime; + timeStructure.travelTime += timeStructure.travelTime <= 0 ? 60 : 0; + timeStructure.bottomTravelTime = + timeStructure.leftArrivalTime - timeStructure.rightDepartureTime; + timeStructure.bottomTravelTime += timeStructure.bottomTravelTime <= 0 ? 60 : 0; + } + } + return timeStructure; + } + + case SymmetryOn.Trainrun: { + // TODO faire pareil que trainrunSection + const {firstTrainrunSection, lastTrainrunSection, swapped} = + this.trainrunService.getFirstAndLastTrainrunSections( + this.selectedTrainrunSection.getTrainrunId(), + ); + + timeStructure.leftArrivalTime = swapped + ? firstTrainrunSection.getTargetArrival() + : firstTrainrunSection.getSourceArrival(); + timeStructure.leftDepartureTime = swapped + ? firstTrainrunSection.getTargetDeparture() + : firstTrainrunSection.getSourceDeparture(); + timeStructure.rightArrivalTime = swapped + ? lastTrainrunSection.getSourceArrival() + : lastTrainrunSection.getTargetArrival(); + timeStructure.rightDepartureTime = swapped + ? lastTrainrunSection.getSourceDeparture() + : lastTrainrunSection.getTargetDeparture(); + + if (reference === SymmetryReference.Top) { + timeStructure.leftArrivalTime = TrainrunsectionHelper.getSymmetricTime( + timeStructure.leftDepartureTime, + ); + timeStructure.rightDepartureTime = TrainrunsectionHelper.getSymmetricTime( + timeStructure.rightArrivalTime, + ); + } else { + timeStructure.leftDepartureTime = TrainrunsectionHelper.getSymmetricTime( + timeStructure.leftArrivalTime, + ); + timeStructure.rightArrivalTime = TrainrunsectionHelper.getSymmetricTime( + timeStructure.rightDepartureTime, + ); + } + + timeStructure.travelTime = null; // not used in this context + timeStructure.bottomTravelTime = null; // not used in this context + return timeStructure; + } + + default: + return timeStructure; + } + } + + calculateTimeStructureAfterSymmetrySelectionForTrainrunSection( + reference: SymmetryReference, + trainrunSection: TrainrunSection, + ): LeftAndRightTimeStructure { + if (reference === SymmetryReference.Top) { + return { + leftDepartureTime: trainrunSection.getSourceDeparture(), + travelTime: trainrunSection.getTravelTime(), + rightArrivalTime: trainrunSection.getTargetArrival(), + rightDepartureTime: TrainrunsectionHelper.getSymmetricTime( + trainrunSection.getTargetArrival(), + ), + bottomTravelTime: trainrunSection.getTravelTime(), + leftArrivalTime: TrainrunsectionHelper.getSymmetricTime( + trainrunSection.getSourceDeparture(), + ), + }; + } else { + return { + leftDepartureTime: TrainrunsectionHelper.getSymmetricTime( + trainrunSection.getSourceArrival(), + ), + travelTime: trainrunSection.getBackwardTravelTime(), + rightArrivalTime: TrainrunsectionHelper.getSymmetricTime( + trainrunSection.getTargetDeparture(), + ), + rightDepartureTime: trainrunSection.getTargetDeparture(), + bottomTravelTime: trainrunSection.getBackwardTravelTime(), + leftArrivalTime: trainrunSection.getSourceArrival(), + }; + } + } + + areLeftAndRightTimeStructuresEqual(symmetryOn: SymmetryOn) { + const top = this.calculateTimeStructureAfterSymmetrySelection( + symmetryOn, + SymmetryReference.Top, + ); + const bottom = this.calculateTimeStructureAfterSymmetrySelection( + symmetryOn, + SymmetryReference.Bottom, + ); + return ( + top.leftDepartureTime === bottom.leftDepartureTime && + top.leftArrivalTime === bottom.leftArrivalTime && + top.rightDepartureTime === bottom.rightDepartureTime && + top.rightArrivalTime === bottom.rightArrivalTime && + top.travelTime === bottom.travelTime && + top.bottomTravelTime === bottom.bottomTravelTime + ); + } + + areAllTimeStructuresEqual(trainrunId: number): boolean { + return this.trainrunSectionService + .getAllTrainrunSectionsForTrainrun(trainrunId) + .every((section) => { + const top = this.calculateTimeStructureAfterSymmetrySelectionForTrainrunSection( + SymmetryReference.Top, + section, + ); + const bottom = this.calculateTimeStructureAfterSymmetrySelectionForTrainrunSection( + SymmetryReference.Bottom, + section, + ); + return ( + top.leftDepartureTime === bottom.leftDepartureTime && + top.leftArrivalTime === bottom.leftArrivalTime && + top.rightDepartureTime === bottom.rightDepartureTime && + top.rightArrivalTime === bottom.rightArrivalTime && + top.travelTime === bottom.travelTime && + top.bottomTravelTime === bottom.bottomTravelTime + ); + }); + } + private roundAllTimes() { const timeDisplayPrecision = this.filterService.getTimeDisplayPrecision(); this.timeStructure.leftArrivalTime = MathUtils.round( @@ -495,6 +1029,10 @@ export class TrainrunSectionTimesService { this.timeStructure.travelTime, timeDisplayPrecision, ); + this.timeStructure.bottomTravelTime = MathUtils.round( + this.timeStructure.bottomTravelTime, + timeDisplayPrecision, + ); } private fixAllTimesPrecision() { @@ -511,17 +1049,34 @@ export class TrainrunSectionTimesService { timeDisplayPrecision; this.timeStructure.travelTime = Math.round(this.timeStructure.travelTime * timeDisplayPrecision) / timeDisplayPrecision; + this.timeStructure.bottomTravelTime = + Math.round(this.timeStructure.bottomTravelTime * timeDisplayPrecision) / timeDisplayPrecision; } - private updateTrainrunSectionTime() { - this.trainrunSectionService.setTimeStructureToTrainrunSections( - this.trainrunSectionHelper.mapLeftAndRightTimes( - this.selectedTrainrunSection, - this.nodesOrdered, - this.timeStructure, - ), - this.selectedTrainrunSection, - this.filterService.getTimeDisplayPrecision(), - ); + private updateTrainrunSectionTime( + trainrunSection: TrainrunSection = this.selectedTrainrunSection, + leftAndRightTimeStructure: LeftAndRightTimeStructure = this.timeStructure, + ) { + if (this.onPerlenkette) { + // non-stop trainruns in perlenkette: timeStructure is only for the section, not sections chain + this.trainrunSectionService.setTimeStructureToTrainrunSection( + leftAndRightTimeStructure, + trainrunSection, + ); + } else { + this.trainrunSectionService.setTimeStructureToTrainrunSections( + leftAndRightTimeStructure, + trainrunSection, + this.filterService.getTimeDisplayPrecision(), + ); + } + } + + private isLeftNodeSymmetric(): boolean { + return TrainrunsectionHelper.isLeftNodeSymmetric(this.selectedTrainrunSection); + } + + private isRightNodeSymmetric(): boolean { + return TrainrunsectionHelper.isRightNodeSymmetric(this.selectedTrainrunSection); } } diff --git a/src/app/services/data/trainrun.service.ts b/src/app/services/data/trainrun.service.ts index df30724ea..b2e5f1d02 100644 --- a/src/app/services/data/trainrun.service.ts +++ b/src/app/services/data/trainrun.service.ts @@ -221,6 +221,7 @@ export class TrainrunService { targetArrival, (60 - targetArrival) % 60, ts.getTravelTime(), + ts.getBackwardTravelTime(), false, // disable event emission since UpdateTrainrunOperation is emitted below ); }); @@ -265,6 +266,11 @@ export class TrainrunService { updateDirection(trainrun: Trainrun, direction: Direction) { const trainrunSection = this.getTrainrunFromId(trainrun.getId()); trainrunSection.setDirection(direction); + if (!trainrun.isRoundTrip()) { + this.trainrunSectionService + .getAllTrainrunSectionsForTrainrun(trainrun.getId()) + .forEach((ts: TrainrunSection) => ts.resetSymmetry()); + } this.trainrunsUpdated(); this.operation.emit(new TrainrunOperation(OperationType.update, trainrun)); } @@ -577,6 +583,7 @@ export class TrainrunService { return {endNode1, endNode2}; } + // TODO: refacto that using setTimeStructureToTrainrunSections code propagateConsecutiveTimesForTrainrun(trainrunSectionId: number) { const inTrainrunSection = this.trainrunSectionService.getTrainrunSectionFromId(trainrunSectionId); @@ -762,6 +769,69 @@ export class TrainrunService { ); } + // TODO: refactor travelTime and backwardTravelTime to use the same logic + // and use reverse iterator? + // TODO: wip + sumBackwardTravelTimeUpToLastNonStopNode(node: Node, trainrunSection: TrainrunSection): number { + let summedBackwardTravelTime = 0; + const iterator = this.getBackwardNonStopIterator(node, trainrunSection); + while (iterator.hasNext()) { + const nextPair = iterator.next(); + summedBackwardTravelTime += nextPair.trainrunSection.getBackwardTravelTime(); + } + return summedBackwardTravelTime; + } + + getCumulativeBackwardTravelTime(trainrunSection: TrainrunSection) { + const iterator = this.getBackwardNonStopIterator( + trainrunSection.getTargetNode(), + trainrunSection, + ); + while (iterator.hasNext()) { + iterator.next(); + } + return this.sumBackwardTravelTimeUpToLastNonStopNode( + iterator.current().node, + iterator.current().trainrunSection, + ); + } + + getCumSumBackwardTravelTimeNodePathToLastNonStopNode(n: Node, ts: TrainrunSection) { + const data = [ + { + node: n, + sumBackwardTravelTime: 0, + trainrunSection: ts, + }, + ]; + let summedBackwardTravelTime = 0; + const iterator = this.getBackwardNonStopIterator(n, ts); + while (iterator.hasNext()) { + const nextPair = iterator.next(); + summedBackwardTravelTime += nextPair.trainrunSection.getBackwardTravelTime(); + data.push({ + node: nextPair.node, + sumBackwardTravelTime: summedBackwardTravelTime, + trainrunSection: nextPair.trainrunSection, + }); + } + return data; + } + + getCumulativeBackwardTravelTimeAndNodePath(trainrunSection: TrainrunSection) { + const iterator = this.getBackwardNonStopIterator( + trainrunSection.getTargetNode(), + trainrunSection, + ); + while (iterator.hasNext()) { + iterator.next(); + } + return this.getCumSumBackwardTravelTimeNodePathToLastNonStopNode( + iterator.current().node, + iterator.current().trainrunSection, + ); + } + isStartEqualsEndNode(trainrunSectionId: number): boolean { const trainrunSection = this.trainrunSectionService.getTrainrunSectionFromId(trainrunSectionId); const startNode = this.getEndNode(trainrunSection.getSourceNode(), trainrunSection); @@ -777,6 +847,19 @@ export class TrainrunService { return new NonStopTrainrunIterator(this.logService, node, trainrunSection); } + public getNonStopSectionsChain(trainrunSection: TrainrunSection): TrainrunSection[] { + const firstTrainrunSection = this.getFirstNonStopTrainrunSection(trainrunSection); + const sectionsChain: TrainrunSection[] = []; + const iterator = this.getNonStopIterator( + firstTrainrunSection.getSourceNode(), + firstTrainrunSection, + ); + while (iterator.hasNext()) { + sectionsChain.push(iterator.next().trainrunSection); + } + return sectionsChain; + } + public getBackwardIterator(node: Node, trainrunSection: TrainrunSection) { return new BackwardTrainrunIterator(this.logService, node, trainrunSection); } @@ -809,6 +892,45 @@ export class TrainrunService { return this.getBothEndNodesFromTrainrunPart(trainrunSection); } + getFirstAndLastTrainrunSections(trainrunId: number): { + firstTrainrunSection: TrainrunSection; + lastTrainrunSection: TrainrunSection; + swapped: boolean; + } { + const trainrunSections = + this.trainrunSectionService.getAllTrainrunSectionsForTrainrun(trainrunId); + const [startNode, endNode] = [ + this.getStartNodeWithTrainrunId(trainrunId), + this.getEndNodeWithTrainrunId(trainrunId), + ]; + + // Try to find startNode → endNode + let firstTrainrunSection = trainrunSections.find( + (ts) => ts.getSourceNodeId() === startNode.getId(), + ); + let lastTrainrunSection = [...trainrunSections] + .reverse() + .find((ts) => ts.getTargetNodeId() === endNode.getId()); + + let swapped = false; + if (!firstTrainrunSection && !lastTrainrunSection) { + firstTrainrunSection = trainrunSections.find( + (ts) => ts.getSourceNodeId() === endNode.getId(), + ); + lastTrainrunSection = [...trainrunSections] + .reverse() + .find((ts) => ts.getTargetNodeId() === startNode.getId()); + [firstTrainrunSection, lastTrainrunSection] = [lastTrainrunSection, firstTrainrunSection]; + swapped = true; + } + + return { + firstTrainrunSection: firstTrainrunSection, + lastTrainrunSection: lastTrainrunSection, + swapped: swapped, + }; + } + private createNewTrainrunFromDto(trainrun: TrainrunDto): Trainrun { const newTrainrun = new Trainrun(); newTrainrun.setTrainrunCategory(this.dataService.getTrainrunCategory(trainrun.categoryId)); @@ -866,7 +988,9 @@ export class TrainrunService { if (!nextPair.node.isEndNode(nextPair.trainrunSection)) { const oldArrival = nextPair.node.getArrivalTime(nextPair.trainrunSection); const trs = nextPair.node.getNextTrainrunSection(nextPair.trainrunSection); - const nextDeparture = nextPair.node.getDepartureTime(trs); + const nextDeparture = nextPair.node.isNonStop(nextPair.trainrunSection) + ? oldArrival + : nextPair.node.getDepartureTime(trs); halteZeit = nextDeparture < oldArrival ? nextDeparture + 60 - oldArrival : nextDeparture - oldArrival; } diff --git a/src/app/services/data/trainrunsection.service.spec.ts b/src/app/services/data/trainrunsection.service.spec.ts index 72e27e105..8883fb5c6 100644 --- a/src/app/services/data/trainrunsection.service.spec.ts +++ b/src/app/services/data/trainrunsection.service.spec.ts @@ -113,7 +113,7 @@ describe("TrainrunSectionService", () => { expect(ts.getSourceDepartureConsecutiveTime()).toBe(12); expect(ts.getSourceArrivalConsecutiveTime()).toBe(48); // should not have any impact - trainrunSectionService.propagateTimesForNewTrainrunSection(ts); + trainrunSectionService.propagateTimesAtTrainrunSectionCreation(ts); expect(ts.getTargetDepartureConsecutiveTime()).toBe(38); expect(ts.getTargetArrivalConsecutiveTime()).toBe(22); expect(ts.getSourceDepartureConsecutiveTime()).toBe(12); diff --git a/src/app/services/data/trainrunsection.service.ts b/src/app/services/data/trainrunsection.service.ts index 3ed3a2453..9b519459d 100644 --- a/src/app/services/data/trainrunsection.service.ts +++ b/src/app/services/data/trainrunsection.service.ts @@ -12,7 +12,6 @@ import {NodeService} from "./node.service"; import {TrainrunSectionValidator} from "../util/trainrunsection.validator"; import {Trainrun} from "../../models/trainrun.model"; import {MathUtils} from "../../utils/math"; -import {GeneralViewFunctions} from "../../view/util/generalViewFunctions"; import {LeftAndRightTimeStructure} from "../../view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component"; import {TrainrunsectionHelper} from "../util/trainrunsection.helper"; import {LogService} from "../../logger/log.service"; @@ -34,6 +33,21 @@ export interface InformSelectedTrainrunClick { open: boolean; } +export interface TimeStructure { + sourceDepartureTime: number; + travelTime: number; + targetArrivalTime: number; + targetDepartureTime: number; + backwardTravelTime: number; + sourceArrivalTime: number; +} + +export interface PartialTimeStructure { + departureTime: number; + travelTime: number; + arrivalTime: number; +} + @Injectable({ providedIn: "root", }) @@ -69,8 +83,9 @@ export class TrainrunSectionService implements OnDestroy { static TIME_PRECISION = 10; + // TODO: refacto static computeArrivalAndDeparture( - nodeArrival: number, + previousNodeArrival: number, trainrunSection: TrainrunSection, nonStop: boolean, halteZeiten: TrainrunCategoryHaltezeit, @@ -79,7 +94,7 @@ export class TrainrunSectionService implements OnDestroy { let haltezeit = halteZeiten[trainrunSection.getTrainrun().getTrainrunCategory().fachCategory].haltezeit; haltezeit = nonStop ? 0 : haltezeit; - const fromDepartureTime = MathUtils.round((nodeArrival + haltezeit) % 60, precision); + const fromDepartureTime = MathUtils.round((previousNodeArrival + haltezeit) % 60, precision); const fromArrivalTime = MathUtils.round( TrainrunsectionHelper.getSymmetricTime(fromDepartureTime), precision, @@ -133,7 +148,7 @@ export class TrainrunSectionService implements OnDestroy { this.destroyed.complete(); } - propagateTimesForNewTrainrunSection(trainrunSection: TrainrunSection) { + propagateTimesAtTrainrunSectionCreation(trainrunSection: TrainrunSection) { let nodeFrom = trainrunSection.getSourceNode(); let previousTrainrunSection = nodeFrom.getNextTrainrunSection(trainrunSection); if (previousTrainrunSection === undefined) { @@ -150,7 +165,6 @@ export class TrainrunSectionService implements OnDestroy { halteZeit, TrainrunSectionService.TIME_PRECISION, ); - if (trainrunSection.getSourceNodeId() === nodeFrom.getId()) { trainrunSection.setSourceDeparture(arrivalDepartureTimes.nodeFromDepartureTime); trainrunSection.setSourceArrival(arrivalDepartureTimes.nodeFromArrivalTime); @@ -175,7 +189,6 @@ export class TrainrunSectionService implements OnDestroy { trainrunSection.setTargetDeparture(targetDepartureTime); trainrunSection.setTargetArrival(targetArrivalTime); } - this.trainrunService.propagateConsecutiveTimesForTrainrun(trainrunSection.getId()); } @@ -211,6 +224,12 @@ export class TrainrunSectionService implements OnDestroy { ); this.trainrunSectionsStore.trainrunSections.forEach((trainrunSection) => { + trainrunSection.setSourceNode( + this.nodeService.getNodeFromId(trainrunSection.getSourceNodeId()), + ); + trainrunSection.setTargetNode( + this.nodeService.getNodeFromId(trainrunSection.getTargetNodeId()), + ); TrainrunSectionValidator.validateOneSection(trainrunSection); TrainrunSectionValidator.validateTravelTime(trainrunSection); }); @@ -280,7 +299,7 @@ export class TrainrunSectionService implements OnDestroy { initializeTrainrunSectionRouting() { this.trainrunSectionsStore.trainrunSections.forEach((trainrunSection) => { - if (trainrunSection.isPathEmpty()) { + if (trainrunSection.isPathInvalid()) { trainrunSection.routeEdgeAndPlaceText(); } }); @@ -300,6 +319,7 @@ export class TrainrunSectionService implements OnDestroy { targetArrival: number, targetDeparture: number, travelTime: number, + backwardTravelTime: number, emit: boolean = true, ) { const trainrunSection = this.getTrainrunSectionFromId(trsId); @@ -308,6 +328,7 @@ export class TrainrunSectionService implements OnDestroy { trainrunSection.setTargetArrival(targetArrival); trainrunSection.setTargetDeparture(targetDeparture); trainrunSection.setTravelTime(travelTime); + trainrunSection.setBackwardTravelTime(backwardTravelTime); TrainrunSectionValidator.validateOneSection(trainrunSection); this.trainrunService.propagateConsecutiveTimesForTrainrun(trainrunSection.getId()); this.nodeService.validateConnections(trainrunSection.getSourceNode()); @@ -319,7 +340,21 @@ export class TrainrunSectionService implements OnDestroy { } } - private propagateTimeAlongTrainrunFixStartTrainrunSection( + updateSourceSymmetry(trainrunSectionId: number, isSourceNodeSymmetric: boolean) { + const trainrunSection = this.getTrainrunSectionFromId(trainrunSectionId); + trainrunSection.setSourceSymmetry(isSourceNodeSymmetric); + this.trainrunSectionsUpdated(); + this.operation.emit(new TrainrunOperation(OperationType.update, trainrunSection.getTrainrun())); + } + + updateTargetSymmetry(trainrunSectionId: number, isTargetNodeSymmetric: boolean) { + const trainrunSection = this.getTrainrunSectionFromId(trainrunSectionId); + trainrunSection.setTargetSymmetry(isTargetNodeSymmetric); + this.trainrunSectionsUpdated(); + this.operation.emit(new TrainrunOperation(OperationType.update, trainrunSection.getTrainrun())); + } + + private findTrainrunSectionForStopNode( trainrunSection: TrainrunSection, node: Node, stopNodeId: number, @@ -334,236 +369,270 @@ export class TrainrunSectionService implements OnDestroy { return undefined; } - propagateTimeAlongTrainrun(trainrunSectionId: number, fromNodeIdOn: number) { - const trainrunSection = this.getTrainrunSectionFromId(trainrunSectionId); - const fromNode = - fromNodeIdOn === trainrunSection.getSourceNodeId() - ? trainrunSection.getSourceNode() - : trainrunSection.getTargetNode(); - if (fromNode.getId() !== fromNodeIdOn) { - let trainrunSectionIdToStart = this.propagateTimeAlongTrainrunFixStartTrainrunSection( - trainrunSection, - trainrunSection.getSourceNode(), - fromNodeIdOn, + propagateTimes( + startTrainrunSectionId: number, + sourceToTarget: boolean, + nextStopNodeId: number, + nonStopIterator: boolean, + ) { + const startTrainrunSection = this.getTrainrunSectionFromId(startTrainrunSectionId); + const startNode = sourceToTarget + ? startTrainrunSection.getSourceNode() + : startTrainrunSection.getTargetNode(); + + let actualStartTrainrunSectionId = startTrainrunSectionId; + + // Non-stop chain case: if the start node is not the next stop node, + // we need to find the trainrun section that connects to the actual stop node + if (startNode.getId() !== nextStopNodeId) { + const foundTrainrunSectionId = this.findTrainrunSectionForStopNode( + startTrainrunSection, + startNode, + nextStopNodeId, ); - if (trainrunSectionIdToStart === undefined) { - trainrunSectionIdToStart = this.propagateTimeAlongTrainrunFixStartTrainrunSection( - trainrunSection, - trainrunSection.getTargetNode(), - fromNodeIdOn, - ); - } - if (trainrunSectionIdToStart !== undefined) { - this.iterateAlongTrainrunUntilEndAndPropagateTime( - this.nodeService.getNodeFromId(fromNodeIdOn), - trainrunSectionIdToStart, - ); - this.trainrunSectionsUpdated(); - return; + + if (foundTrainrunSectionId !== undefined) { + actualStartTrainrunSectionId = foundTrainrunSectionId; } } - this.iterateAlongTrainrunUntilEndAndPropagateTime(fromNode, trainrunSectionId); + + this.iterateAlongTrainrunAndPropagateTimes( + startNode, + actualStartTrainrunSectionId, + sourceToTarget, + nonStopIterator, + ); this.trainrunSectionsUpdated(); } - propagteTimeSourceToTarget( - previousPair: TrainrunSectionNodePair, + propagateTimesSourceToTarget( + previousPair: TrainrunSectionNodePair | null, pair: TrainrunSectionNodePair, - arrivalDepartureTimes: DepartureAndArrivalTimes, - isNonStop: boolean, + forward: boolean, ) { - // ------------------------------------------------------------------------------------------- - // Source to Target (pair) - // ------------------------------------------------------------------------------------------- - // retrieve haltezeit at node - const arrivalTimeAtSource = - previousPair.node.getId() === previousPair.trainrunSection.getTargetNodeId() - ? previousPair.trainrunSection.getTargetArrival() - : previousPair.trainrunSection.getSourceArrival(); - - let halteZeit = - previousPair.node.getTrainrunCategoryHaltezeit()[ - pair.trainrunSection.getTrainrun().getTrainrunCategory().fachCategory - ].haltezeit; - halteZeit = isNonStop ? 0 : halteZeit; - - // try to update the pair (based on previousPair) - if (pair.trainrunSection.getSourceDepartureLock()) { - // the source element is locked - no changes allowed! - return; + // Update source times + let newSourceDepartureTime; + if (previousPair) { + if (forward) { + newSourceDepartureTime = MathUtils.round( + (previousPair.trainrunSection.getTargetArrival() + + this.getPairsHaltezeit(previousPair, pair)) % + 60, + TrainrunSectionService.TIME_PRECISION, + ); + } else { + if (pair.trainrunSection.getSourceSymmetry()) { + newSourceDepartureTime = TrainrunsectionHelper.getSymmetricTime( + pair.trainrunSection.getSourceArrival(), + ); + } else { + if (pair.trainrunSection.getTargetSymmetry()) { + newSourceDepartureTime = MathUtils.round( + (TrainrunsectionHelper.getSymmetricTime(pair.trainrunSection.getTargetDeparture()) - + (pair.trainrunSection.getTravelTime() % 60) + + 60) % + 60, + TrainrunSectionService.TIME_PRECISION, + ); + } else { + newSourceDepartureTime = MathUtils.round( + (previousPair.trainrunSection.getTargetArrival() + + this.getPairsHaltezeit(previousPair, pair)) % + 60, + TrainrunSectionService.TIME_PRECISION, + ); + } + } + } + } else { + // start of trainrun case + newSourceDepartureTime = pair.trainrunSection.getSourceSymmetry() + ? TrainrunsectionHelper.getSymmetricTime(pair.trainrunSection.getSourceArrival()) + : pair.trainrunSection.getSourceDeparture(); } + pair.trainrunSection.setSourceDeparture(newSourceDepartureTime); - // ---------------------------------------------------------------------------------- - // update source arrival time - // ---------------------------------------------------------------------------------- - const depTimeAtSource = MathUtils.round( - (arrivalTimeAtSource + halteZeit) % 60, - TrainrunSectionService.TIME_PRECISION, - ); - const arrTimeAtSource = MathUtils.round( - TrainrunsectionHelper.getSymmetricTime(depTimeAtSource), - TrainrunSectionService.TIME_PRECISION, - ); - pair.trainrunSection.setSourceDeparture(depTimeAtSource); - pair.trainrunSection.setSourceArrival(arrTimeAtSource); - - // ---------------------------------------------------------------------------------- - // Use travel time to update the target times - if allowed - // ---------------------------------------------------------------------------------- + // Update target times if possible if (!pair.trainrunSection.getTargetArrivalLock()) { - // Target is not locked -> update the Target Arrival Time - const arrTimeAtTarget = MathUtils.round( - (depTimeAtSource + pair.trainrunSection.getTravelTime()) % 60, + const newTargetArrivalTime = MathUtils.round( + (newSourceDepartureTime + pair.trainrunSection.getTravelTime()) % 60, TrainrunSectionService.TIME_PRECISION, ); - const depTimeAtTarget = MathUtils.round( - TrainrunsectionHelper.getSymmetricTime(arrTimeAtTarget), - TrainrunSectionService.TIME_PRECISION, - ); - pair.trainrunSection.setTargetArrival(arrTimeAtTarget); - pair.trainrunSection.setTargetDeparture(depTimeAtTarget); - - return; - } - - // ---------------------------------------------------------------------------------- - // update travel time if possible - // ---------------------------------------------------------------------------------- - if (pair.trainrunSection.getTravelTimeLock()) { - return; + pair.trainrunSection.setTargetArrival(newTargetArrivalTime); } - let newTravelTime = pair.trainrunSection.getTargetArrival() - depTimeAtSource; - newTravelTime += Math.floor(pair.trainrunSection.getTravelTime() / 60) * 60; - while (newTravelTime < 0.0) { - newTravelTime += 60; + // Update travel times otherwise + if (!pair.trainrunSection.getTravelTimeLock()) { + let newTravelTime = pair.trainrunSection.getTargetArrival() - newSourceDepartureTime; + newTravelTime += Math.floor(pair.trainrunSection.getTravelTime() / 60) * 60; + while (newTravelTime < 0.0) { + newTravelTime += 60; + } + pair.trainrunSection.setTravelTime(newTravelTime); } - pair.trainrunSection.setTravelTime(newTravelTime); } - propagteTimeTargetToSource( - previousPair: TrainrunSectionNodePair, + propagateTimesTargetToSource( + previousPair: TrainrunSectionNodePair | null, pair: TrainrunSectionNodePair, - arrivalDepartureTimes: DepartureAndArrivalTimes, - isNonStop: boolean, + forward: boolean, ) { - // ------------------------------------------------------------------------------------------- - // Target to Source (pair) - // ------------------------------------------------------------------------------------------- - // retrieve haltezeit at node - const arrivalTimeAtTarget = - previousPair.node.getId() === previousPair.trainrunSection.getTargetNodeId() - ? previousPair.trainrunSection.getTargetArrival() - : previousPair.trainrunSection.getSourceArrival(); - - let halteZeit = - previousPair.node.getTrainrunCategoryHaltezeit()[ - pair.trainrunSection.getTrainrun().getTrainrunCategory().fachCategory - ].haltezeit; - halteZeit = isNonStop ? 0 : halteZeit; - - // try to update the pair (based on previousPair) - if (pair.trainrunSection.getTargetDepartureLock()) { - // the source element is locked - no changes allowed! - return; + // Update target times + let newTargetDepartureTime; + if (previousPair) { + if (forward) { + newTargetDepartureTime = MathUtils.round( + (previousPair.trainrunSection.getSourceArrival() + + this.getPairsHaltezeit(previousPair, pair)) % + 60, + TrainrunSectionService.TIME_PRECISION, + ); + } else { + if (pair.trainrunSection.getTargetSymmetry()) { + newTargetDepartureTime = TrainrunsectionHelper.getSymmetricTime( + pair.trainrunSection.getTargetArrival(), + ); + } else { + if (pair.trainrunSection.getSourceSymmetry()) { + newTargetDepartureTime = MathUtils.round( + (TrainrunsectionHelper.getSymmetricTime(pair.trainrunSection.getSourceDeparture()) - + (pair.trainrunSection.getBackwardTravelTime() % 60) + + 60) % + 60, + TrainrunSectionService.TIME_PRECISION, + ); + } else { + // section is fully non-symmetric + newTargetDepartureTime = MathUtils.round( + (previousPair.trainrunSection.getSourceArrival() + + this.getPairsHaltezeit(previousPair, pair)) % + 60, + TrainrunSectionService.TIME_PRECISION, + ); + } + } + } + } else { + // end of trainrun case + newTargetDepartureTime = pair.trainrunSection.getTargetSymmetry() + ? TrainrunsectionHelper.getSymmetricTime(pair.trainrunSection.getTargetArrival()) + : pair.trainrunSection.getTargetDeparture(); } + pair.trainrunSection.setTargetDeparture(newTargetDepartureTime); - // ---------------------------------------------------------------------------------- - // update source arrival time - // ---------------------------------------------------------------------------------- - const depTimeAtTarget = MathUtils.round( - (arrivalTimeAtTarget + halteZeit) % 60, - TrainrunSectionService.TIME_PRECISION, - ); - const arrTimeAtTarget = MathUtils.round( - TrainrunsectionHelper.getSymmetricTime(depTimeAtTarget), - TrainrunSectionService.TIME_PRECISION, - ); - pair.trainrunSection.setTargetDeparture(depTimeAtTarget); - pair.trainrunSection.setTargetArrival(arrTimeAtTarget); - - // ---------------------------------------------------------------------------------- - // Use travel time to update the target times - if allowed - // ---------------------------------------------------------------------------------- + // Update source times if possible if (!pair.trainrunSection.getSourceArrivalLock()) { - // Target is not locked -> update the Target Arrival Time - const arrTimeAtSource = MathUtils.round( - (depTimeAtTarget + pair.trainrunSection.getTravelTime()) % 60, + const newSourceArrivalTime = MathUtils.round( + (newTargetDepartureTime + pair.trainrunSection.getBackwardTravelTime()) % 60, TrainrunSectionService.TIME_PRECISION, ); - const depTimeAtSource = MathUtils.round( - TrainrunsectionHelper.getSymmetricTime(arrTimeAtSource), - TrainrunSectionService.TIME_PRECISION, - ); - pair.trainrunSection.setSourceArrival(arrTimeAtSource); - pair.trainrunSection.setSourceDeparture(depTimeAtSource); - - return; + pair.trainrunSection.setSourceArrival(newSourceArrivalTime); } - // ---------------------------------------------------------------------------------- - // update travel time if possible - // ---------------------------------------------------------------------------------- - if (pair.trainrunSection.getTravelTimeLock()) { - return; - } - - let newTravelTime = pair.trainrunSection.getSourceArrival() - depTimeAtTarget; - newTravelTime += Math.floor(pair.trainrunSection.getTravelTime() / 60) * 60; - while (newTravelTime < 0.0) { - newTravelTime += 60; + // Update travel times otherwise + if (!pair.trainrunSection.getTravelTimeLock()) { + let newBackwardTravelTime = pair.trainrunSection.getSourceArrival() - newTargetDepartureTime; + newBackwardTravelTime += Math.floor(pair.trainrunSection.getBackwardTravelTime() / 60) * 60; + while (newBackwardTravelTime < 0.0) { + newBackwardTravelTime += 60; + } + pair.trainrunSection.setBackwardTravelTime(newBackwardTravelTime); } - pair.trainrunSection.setTravelTime(newTravelTime); } - iterateAlongTrainrunUntilEndAndPropagateTime(nodeFrom: Node, trainrunSectionId: number) { - const trainrunSection = this.getTrainrunSectionFromId(trainrunSectionId); - - const iterator = this.trainrunService.getIterator(nodeFrom, trainrunSection); - let previousPair = iterator.next(); - - TrainrunSectionValidator.validateOneSection(previousPair.trainrunSection); + iterateAlongTrainrunAndPropagateTimes( + startNode: Node, + startTrainrunSectionId: number, + sourceToTarget: boolean, + nonStopIterator: boolean, + ) { + const startTrainrunSection = this.getTrainrunSectionFromId(startTrainrunSectionId); + + if (sourceToTarget) { + // Forward iteration: source to target direction + const forwardIterator = nonStopIterator + ? this.trainrunService.getNonStopIterator(startNode, startTrainrunSection) + : this.trainrunService.getIterator(startNode, startTrainrunSection); + const forwardSections: TrainrunSectionNodePair[] = []; + forwardSections.push(forwardIterator.next()); + while (forwardIterator.hasNext()) { + const pair = forwardIterator.next(); + forwardSections.push(pair); + } - while (iterator.hasNext()) { - const pair = iterator.next(); + // Forward propagation: source to target + // first section is not propagated, because it is the one that has been changed by the user + let previousForwardPair = forwardSections[0]; + TrainrunSectionValidator.validateOneSection(previousForwardPair.trainrunSection); + forwardSections.shift(); + for (const currentPair of forwardSections) { + if (currentPair.trainrunSection.getSourceDepartureLock()) { + break; // Stop propagation when lock is encountered + } + this.propagateTimesSourceToTarget(previousForwardPair, currentPair, true); + TrainrunSectionValidator.validateOneSection(currentPair.trainrunSection); + previousForwardPair = currentPair; + } - const isNonStop = previousPair.node.isNonStop(pair.trainrunSection); - const halteZeit = previousPair.node.getTrainrunCategoryHaltezeit(); - const previousNodeArrival = previousPair.node.getArrivalTime(previousPair.trainrunSection); - const arrivalDepartureTimes = TrainrunSectionService.computeArrivalAndDeparture( - previousNodeArrival, - pair.trainrunSection, - isNonStop, - halteZeit, - TrainrunSectionService.TIME_PRECISION, - ); + // Backward propagation: target to source + // first backward section is propagated, but has no previous section, special case + let previousBackwardPair: TrainrunSectionNodePair | null = null; + for (const currentPair of forwardSections.toReversed()) { + if (currentPair.trainrunSection.getTargetDepartureLock()) { + break; // Stop propagation when lock is encountered + } + this.propagateTimesTargetToSource(previousBackwardPair, currentPair, false); + TrainrunSectionValidator.validateOneSection(currentPair.trainrunSection); + previousBackwardPair = currentPair; + } + } else { + // Backward iteration: target to source direction + const backwardIterator = nonStopIterator + ? this.trainrunService.getBackwardNonStopIterator(startNode, startTrainrunSection) + : this.trainrunService.getBackwardIterator(startNode, startTrainrunSection); + const backwardSections: TrainrunSectionNodePair[] = []; + backwardSections.push(backwardIterator.next()); + while (backwardIterator.hasNext()) { + const pair = backwardIterator.next(); + backwardSections.push(pair); + } - if (pair.trainrunSection.getSourceNodeId() === previousPair.node.getId()) { - this.propagteTimeSourceToTarget(previousPair, pair, arrivalDepartureTimes, isNonStop); - } else { - this.propagteTimeTargetToSource(previousPair, pair, arrivalDepartureTimes, isNonStop); + // Forward propagation: target to source (in the context of backward iteration) + // first section is not propagated, because it is the one that has been changed by the user + let previousForwardPair = backwardSections[0]; + TrainrunSectionValidator.validateOneSection(previousForwardPair.trainrunSection); + backwardSections.shift(); + for (const currentPair of backwardSections) { + if (currentPair.trainrunSection.getTargetDepartureLock()) { + break; // Stop propagation when lock is encountered + } + this.propagateTimesTargetToSource(previousForwardPair, currentPair, true); + TrainrunSectionValidator.validateOneSection(currentPair.trainrunSection); + previousForwardPair = currentPair; } - TrainrunSectionValidator.validateOneSection(pair.trainrunSection); - if ( - pair.trainrunSection.getSourceDepartureLock() || - pair.trainrunSection.getTargetDepartureLock() - ) { - break; + // Backward propagation: source to target (in the context of backward iteration) + // first backward section is propagated, but has no previous section, special case + let previousBackwardPair: TrainrunSectionNodePair | null = null; + for (const currentPair of backwardSections.toReversed()) { + if (currentPair.trainrunSection.getSourceDepartureLock()) { + break; // Stop propagation when lock is encountered + } + this.propagateTimesSourceToTarget(previousBackwardPair, currentPair, false); + TrainrunSectionValidator.validateOneSection(currentPair.trainrunSection); + previousBackwardPair = currentPair; } - previousPair = pair; } - if (trainrunSection !== undefined) { - this.trainrunService.propagateConsecutiveTimesForTrainrun(trainrunSection.getId()); + if (startTrainrunSection !== undefined) { + this.trainrunService.propagateConsecutiveTimesForTrainrun(startTrainrunSection.getId()); } } - updateTrainrunSectionTimeLock( + updateTrainrunSectionSourceTargetTimeLocks( trsId: number, sourceLock: boolean, targetLock: boolean, - travelTimeLock: boolean, enforceUpdate = true, ) { const trainrunSection = this.getTrainrunSectionFromId(trsId); @@ -575,9 +644,23 @@ export class TrainrunSectionService implements OnDestroy { trainrunSection.setTargetArrivalLock(targetLock); trainrunSection.setTargetDepartureLock(targetLock); } - if (travelTimeLock !== undefined) { - trainrunSection.setTravelTimeLock(travelTimeLock); + if (enforceUpdate) { + this.trainrunSectionsUpdated(); } + } + + updateSectionsChainTravelTimeLocks( + trainrunSectionId: number, + lock: boolean, + enforceUpdate = true, + ) { + const sections = this.trainrunService.getNonStopSectionsChain( + this.getTrainrunSectionFromId(trainrunSectionId), + ); + sections.forEach((section) => { + section.setTravelTimeLock(lock); + section.setBackwardTravelTimeLock(lock); + }); if (enforceUpdate) { this.trainrunSectionsUpdated(); } @@ -647,11 +730,12 @@ export class TrainrunSectionService implements OnDestroy { this.handleNodeAndTrainrunSectionDetails(sourceNode, targetNode, trainrunSection); this.setTrainrunSectionAsSelected(trainrunSection.getId()); - this.propagateTimesForNewTrainrunSection(trainrunSection); // Ensure consistent section direction considering the previous ones this.enforceConsistentSectionDirection(trainrunSection.getTrainrunId()); + this.propagateTimesAtTrainrunSectionCreation(trainrunSection); + //this.trainrunSectionsUpdated(); this.trainrunService.trainrunsUpdated(); @@ -853,67 +937,151 @@ export class TrainrunSectionService implements OnDestroy { } setTimeStructureToTrainrunSections( - timeStructure: LeftAndRightTimeStructure, - trainrunSection: TrainrunSection, + chainLeftAndRightTimeStructure: LeftAndRightTimeStructure, + updatedTrainrunSection: TrainrunSection, precision = 0, ) { - const newTotalTravelTime = timeStructure.travelTime; - - const oldTotalTravelTime = this.trainrunService.getCumulativeTravelTime(trainrunSection); - const travelTimeFactor = newTotalTravelTime / oldTotalTravelTime; - - // prepare data structure for the first trainrunsection - const bothLastNonStopNodes = this.trainrunService.getBothLastNonStopNodes(trainrunSection); - const bothLastNonStopTrainrunSections = - this.trainrunService.getBothLastNonStopTrainrunSections(trainrunSection); - const leftNode = GeneralViewFunctions.getLeftOrTopNode( - bothLastNonStopNodes.lastNonStopNode1, - bothLastNonStopNodes.lastNonStopNode2, + // Get all pairs [ [node(stop) --ts--] [node(non-stop) --ts--] [...] node(stop) ] + // and initialize their time structures + const firstTrainrunSection = + this.trainrunService.getFirstNonStopTrainrunSection(updatedTrainrunSection); + const iterator = this.trainrunService.getNonStopIterator( + firstTrainrunSection.getSourceNode(), + firstTrainrunSection, ); - const trs = - leftNode.getId() === bothLastNonStopNodes.lastNonStopNode1.getId() - ? bothLastNonStopTrainrunSections.lastNonStopTrainrunSection1 - : bothLastNonStopTrainrunSections.lastNonStopTrainrunSection2; - - const trsTimeStructure = TrainrunsectionHelper.getDefaultTimeStructure(timeStructure); - let summedTravelTime = 0; - - const iterator = this.trainrunService.getNonStopIterator(leftNode, trs); + const pairs: TrainrunSectionNodePair[] = []; + const pairTimeStructures: Map = new Map(); while (iterator.hasNext()) { const nextPair = iterator.next(); + pairs.push(nextPair); + pairTimeStructures.set(nextPair, { + sourceDepartureTime: null, + travelTime: null, + targetArrivalTime: null, + targetDepartureTime: null, + backwardTravelTime: null, + sourceArrivalTime: null, + }); + } + + // Get rid of left/right paradigm + const chainTimeStructure = this.getTimeStructureFromLeftAndRightTimeStructure( + TrainrunsectionHelper.isChainTargetRightOrBottom( + firstTrainrunSection, + iterator.current().trainrunSection, + ), + chainLeftAndRightTimeStructure, + ); - const isRightNodeNonStop = nextPair.node.isNonStop(nextPair.trainrunSection); - trsTimeStructure.travelTime = TrainrunsectionHelper.getTravelTime( - newTotalTravelTime, + // Notes: + // - travelTimeFactor: get the sum of the travel times of all the sections from the non-stop sections chain + // and compare it to the total cumulative travel time to the end of the non-stop sections chain (from the start of the trainrun) + // - backwardTravelTimeFactor: get the sum of the backward travel times of all the sections from the non-stop sections chain + // and compare it to the total cumulative travel time to the end of the reversed non-stop sections chain (from the start of the reversed trainrun) + + // Source to target + const totalCumulativeTravelTime = + this.trainrunService.getCumulativeTravelTime(updatedTrainrunSection); + const travelTimeFactor = chainTimeStructure.travelTime / totalCumulativeTravelTime; + const tempTimeStructure: PartialTimeStructure = { + departureTime: chainTimeStructure.sourceDepartureTime, + travelTime: null, + arrivalTime: null, + }; + let summedTravelTime = 0; + pairs.forEach((pair) => { + const finalTimeStructure = pairTimeStructures.get(pair); + tempTimeStructure.travelTime = TrainrunsectionHelper.getDistributedTravelTime( + chainTimeStructure.travelTime, summedTravelTime, travelTimeFactor, - nextPair.trainrunSection.getTravelTime(), - isRightNodeNonStop, + pair.trainrunSection.getTravelTime(), + pair.node.isNonStop(pair.trainrunSection), precision, ); - trsTimeStructure.rightArrivalTime = TrainrunsectionHelper.getRightArrivalTime( - trsTimeStructure, + tempTimeStructure.arrivalTime = TrainrunsectionHelper.getArrivalTime( + tempTimeStructure, precision, ); - trsTimeStructure.rightDepartureTime = TrainrunsectionHelper.getRightDepartureTime( - trsTimeStructure, + finalTimeStructure.sourceDepartureTime = tempTimeStructure.departureTime; + finalTimeStructure.travelTime = tempTimeStructure.travelTime; + finalTimeStructure.targetArrivalTime = tempTimeStructure.arrivalTime; + // next section departure inherits from the previous arrival + tempTimeStructure.departureTime = tempTimeStructure.arrivalTime; + summedTravelTime += tempTimeStructure.travelTime; + }); + + // Target to source + const backwardPairs = pairs.toReversed(); + const totalCumulativeBackwardTravelTime = this.trainrunService.getCumulativeBackwardTravelTime( + backwardPairs[0].trainrunSection, + ); + const backwardTravelTimeFactor = + chainTimeStructure.backwardTravelTime / totalCumulativeBackwardTravelTime; + tempTimeStructure.departureTime = chainTimeStructure.targetDepartureTime; + let summedBackwardTravelTime = 0; + backwardPairs.forEach((pair) => { + const finalTimeStructure = pairTimeStructures.get(pair); + // check for opposite node stop instead since we iterate backward on a regular iterator + tempTimeStructure.travelTime = TrainrunsectionHelper.getDistributedTravelTime( + chainTimeStructure.backwardTravelTime, + summedBackwardTravelTime, + backwardTravelTimeFactor, + pair.trainrunSection.getBackwardTravelTime(), + pair.node.getOppositeNode(pair.trainrunSection).isNonStop(pair.trainrunSection), + precision, + ); + tempTimeStructure.arrivalTime = TrainrunsectionHelper.getArrivalTime( + tempTimeStructure, precision, ); - const rightIsTarget = - nextPair.node.getId() === nextPair.trainrunSection.getTargetNode().getId(); + finalTimeStructure.targetDepartureTime = tempTimeStructure.departureTime; + finalTimeStructure.backwardTravelTime = tempTimeStructure.travelTime; + finalTimeStructure.sourceArrivalTime = tempTimeStructure.arrivalTime; + // next section inherits from the previous arrival + tempTimeStructure.departureTime = tempTimeStructure.arrivalTime; + summedBackwardTravelTime += tempTimeStructure.travelTime; + }); + + // then when all time structures are filled, update all trainrun sections + pairs.forEach((pair) => { + const timeStructure = pairTimeStructures.get(pair); this.updateTrainrunSectionTime( - nextPair.trainrunSection.getId(), - rightIsTarget ? trsTimeStructure.leftArrivalTime : trsTimeStructure.rightArrivalTime, - rightIsTarget ? trsTimeStructure.leftDepartureTime : trsTimeStructure.rightDepartureTime, - rightIsTarget ? trsTimeStructure.rightArrivalTime : trsTimeStructure.leftArrivalTime, - rightIsTarget ? trsTimeStructure.rightDepartureTime : trsTimeStructure.leftDepartureTime, - trsTimeStructure.travelTime, + pair.trainrunSection.getId(), + timeStructure.sourceArrivalTime, + timeStructure.sourceDepartureTime, + timeStructure.targetArrivalTime, + timeStructure.targetDepartureTime, + timeStructure.travelTime, + timeStructure.backwardTravelTime, + false, ); + }); - trsTimeStructure.leftDepartureTime = trsTimeStructure.rightArrivalTime; - trsTimeStructure.leftArrivalTime = trsTimeStructure.rightDepartureTime; - summedTravelTime += trsTimeStructure.travelTime; - } + this.trainrunSectionsUpdated(); + this.nodeService.connectionsUpdated(); + } + + setTimeStructureToTrainrunSection( + leftAndRightTimeStructure: LeftAndRightTimeStructure, + updatedTrainrunSection: TrainrunSection, + ) { + // Get rid of left/right paradigm + const timeStructure = this.getTimeStructureFromLeftAndRightTimeStructure( + TrainrunsectionHelper.isTargetRightOrBottom(updatedTrainrunSection), + leftAndRightTimeStructure, + ); + + this.updateTrainrunSectionTime( + updatedTrainrunSection.getId(), + timeStructure.sourceArrivalTime, + timeStructure.sourceDepartureTime, + timeStructure.targetArrivalTime, + timeStructure.targetDepartureTime, + timeStructure.travelTime, + timeStructure.backwardTravelTime, + false, + ); this.trainrunSectionsUpdated(); this.nodeService.connectionsUpdated(); @@ -1076,6 +1244,12 @@ export class TrainrunSectionService implements OnDestroy { }); } + isTrainrunSymmetric(trainrunId: number): boolean { + return this.getAllTrainrunSectionsForTrainrun(trainrunId).every((section) => + section.isSymmetric(), + ); + } + private copyTrainrunSection( existingTrainrunSection: TrainrunSection, newTrainrunId: number, @@ -1085,6 +1259,15 @@ export class TrainrunSectionService implements OnDestroy { trainrunSection.setTravelTimeDto( JSON.parse(JSON.stringify(existingTrainrunSection.getTravelTimeDto())), ); + trainrunSection.setBackwardTravelTimeDto( + JSON.parse(JSON.stringify(existingTrainrunSection.getBackwardTravelTimeDto())), + ); + trainrunSection.setSourceSymmetry( + JSON.parse(JSON.stringify(existingTrainrunSection.getSourceSymmetry())), + ); + trainrunSection.setTargetSymmetry( + JSON.parse(JSON.stringify(existingTrainrunSection.getTargetSymmetry())), + ); trainrunSection.setSourceArrivalDto( JSON.parse(JSON.stringify(existingTrainrunSection.getSourceArrivalDto())), ); @@ -1301,11 +1484,14 @@ export class TrainrunSectionService implements OnDestroy { const targetNode = this.nodeService.getNodeFromId(targetNodeId); newTrainrunSection.setSourceAndTargetNodeReference(sourceNode, targetNode); + newTrainrunSection.setSourceSymmetry(trainrunSection.sourceSymmetry); + newTrainrunSection.setTargetSymmetry(trainrunSection.targetSymmetry); newTrainrunSection.setSourceArrivalDto(trainrunSection.sourceArrival); newTrainrunSection.setTargetArrivalDto(trainrunSection.targetArrival); newTrainrunSection.setSourceDepartureDto(trainrunSection.sourceDeparture); newTrainrunSection.setTargetDepartureDto(trainrunSection.targetDeparture); newTrainrunSection.setTravelTimeDto(trainrunSection.travelTime); + newTrainrunSection.setBackwardTravelTimeDto(trainrunSection.backwardTravelTime); newTrainrunSection.setNumberOfStops(trainrunSection.numberOfStops); this.trainrunSectionsStore.trainrunSections.push(newTrainrunSection); const sourceIsNonStop = this.getIsNonStop( @@ -1469,4 +1655,41 @@ export class TrainrunSectionService implements OnDestroy { trainrunSection.routeEdgeAndPlaceText(); trainrunSection.convertVec2DToPath(); } + + private getPairsHaltezeit( + previousPair: TrainrunSectionNodePair, + pair: TrainrunSectionNodePair, + ): number { + return previousPair.node.isNonStop(pair.trainrunSection) + ? 0 + : previousPair.node.getTrainrunCategoryHaltezeit()[ + pair.trainrunSection.getTrainrun().getTrainrunCategory().fachCategory + ].haltezeit; + } + + private getTimeStructureFromLeftAndRightTimeStructure( + isTargetRightOrBottom: boolean, + leftAndRightTimeStructure: LeftAndRightTimeStructure, + ): TimeStructure { + return { + sourceDepartureTime: isTargetRightOrBottom + ? leftAndRightTimeStructure.leftDepartureTime + : leftAndRightTimeStructure.rightDepartureTime, + travelTime: isTargetRightOrBottom + ? leftAndRightTimeStructure.travelTime + : leftAndRightTimeStructure.bottomTravelTime, + targetArrivalTime: isTargetRightOrBottom + ? leftAndRightTimeStructure.rightArrivalTime + : leftAndRightTimeStructure.leftArrivalTime, + targetDepartureTime: isTargetRightOrBottom + ? leftAndRightTimeStructure.rightDepartureTime + : leftAndRightTimeStructure.leftDepartureTime, + backwardTravelTime: isTargetRightOrBottom + ? leftAndRightTimeStructure.bottomTravelTime + : leftAndRightTimeStructure.travelTime, + sourceArrivalTime: isTargetRightOrBottom + ? leftAndRightTimeStructure.leftArrivalTime + : leftAndRightTimeStructure.rightArrivalTime, + }; + } } diff --git a/src/app/services/ui/filter.service.ts b/src/app/services/ui/filter.service.ts index e6d1971d7..188fb9191 100644 --- a/src/app/services/ui/filter.service.ts +++ b/src/app/services/ui/filter.service.ts @@ -370,12 +370,17 @@ export class FilterService implements OnDestroy { } /* Impelement user defined filtering */ const filterTrainrunSection = this.checkFilterTrainrunLabels(trainrun.getLabelIds()); + const trainrunSections = this.dataService.getTrainrunSectionsByTrainrunId(trainrun.getId()); + const hasAsymmetricalSection = trainrunSections.some( + (trainrunSection: TrainrunSection) => !trainrunSection.isSymmetric(), + ); return ( filterTrainrunSection && this.isFilterTrainrunFrequencyEnabled(trainrun.getTrainrunFrequency()) && this.isFilterTrainrunCategoryEnabled(trainrun.getTrainrunCategory()) && this.isFilterTrainrunTimeCategoryEnabled(trainrun.getTrainrunTimeCategory()) && - this.isFilterDirectionEnabled(trainrun.getDirection()) + this.isFilterDirectionEnabled(trainrun.getDirection()) && + this.isFilterSymmetryEnabled(!hasAsymmetricalSection) ); } @@ -540,6 +545,20 @@ export class FilterService implements OnDestroy { this.filterChanged(); } + isFilterAsymmetryArrowsEnabled(): boolean { + return this.activeFilterSetting.filterAsymmetryArrows; + } + + enableFilterAsymmetryArrows() { + this.activeFilterSetting.filterAsymmetryArrows = true; + this.filterChanged(); + } + + disableFilterAsymmetryArrows() { + this.activeFilterSetting.filterAsymmetryArrows = false; + this.filterChanged(); + } + isFilterArrivalDepartureTimeEnabled(): boolean { return this.activeFilterSetting.filterArrivalDepartureTime; } @@ -582,6 +601,20 @@ export class FilterService implements OnDestroy { this.filterChanged(); } + isFilterBackwardTravelTimeEnabled(): boolean { + return this.activeFilterSetting.filterBackwardTravelTime; + } + + enableFilterBackwardTravelTime() { + this.activeFilterSetting.filterBackwardTravelTime = true; + this.filterChanged(); + } + + disableFilterBackwardTravelTime() { + this.activeFilterSetting.filterBackwardTravelTime = false; + this.filterChanged(); + } + isFilterTrainrunNameEnabled(): boolean { return this.activeFilterSetting.filterTrainrunName; } @@ -713,6 +746,29 @@ export class FilterService implements OnDestroy { this.filterChanged(); } + isFilterSymmetryEnabled(symmetry: boolean): boolean { + return this.activeFilterSetting.filterSymmetry.includes(symmetry); + } + + enableFilterSymmetry(symmetry: boolean) { + if (!this.activeFilterSetting.filterSymmetry.includes(symmetry)) { + this.activeFilterSetting.filterSymmetry.push(symmetry); + this.filterChanged(); + } + } + + disableFilterSymmetry(symmetry: boolean) { + this.activeFilterSetting.filterSymmetry = this.activeFilterSetting.filterSymmetry.filter( + (sym) => sym !== symmetry, + ); + this.filterChanged(); + } + + resetFilterSymmetry() { + this.activeFilterSetting.filterSymmetry = [true, false]; + this.filterChanged(); + } + isAnyFilterActive(): boolean { return ( !this.isDisplayFilteringActive() || @@ -756,6 +812,13 @@ export class FilterService implements OnDestroy { return; } }); + [true, false].forEach((symmetry: boolean) => { + const isFilter = this.isFilterSymmetryEnabled(symmetry); + if (!isFilter) { + isActive = false; + return; + } + }); return isActive; } @@ -767,10 +830,12 @@ export class FilterService implements OnDestroy { return ( !this.isFilterNotesEnabled() && this.isFilterDirectionArrowsEnabled() && + this.isFilterAsymmetryArrowsEnabled() && this.isFilterArrivalDepartureTimeEnabled() && this.isFilterConnectionsEnabled() && this.isFilterTrainrunNameEnabled() && this.isFilterTravelTimeEnabled() && + this.isFilterBackwardTravelTimeEnabled() && this.isFilterShowNonStopTimeEnabled() ); } @@ -856,6 +921,7 @@ export class FilterService implements OnDestroy { if (filterSetting.filterDirection === null) { filterSetting.filterDirection = this.dataService.getDirections(); } + filterSetting.filterSymmetry = [true, false]; } } } diff --git a/src/app/services/ui/ui.interaction.service.ts b/src/app/services/ui/ui.interaction.service.ts index f9e19f464..3d1660c4e 100644 --- a/src/app/services/ui/ui.interaction.service.ts +++ b/src/app/services/ui/ui.interaction.service.ts @@ -5,6 +5,7 @@ import {Stammdaten} from "../../models/stammdaten.model"; import {TrainrunDialogParameter} from "../../view/dialogs/trainrun-and-section-dialog/trainrun-and-section-dialog.component"; import {ThemeBase} from "../../view/themes/theme-base"; import {ConfirmationDialogParameter} from "../../view/dialogs/confirmation-dialog/confirmation-dialog.component"; +import {SymmetrySelectionDialogParameter} from "../../view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component"; import {FilterService} from "./filter.service"; import {NodeService} from "../data/node.service"; import {StammdatenService} from "../data/stammdaten.service"; @@ -73,6 +74,9 @@ export class UiInteractionService implements OnDestroy { showConfirmationDiagramDialogSubject = new Subject(); readonly confirmationDiagramDialog = this.showConfirmationDiagramDialogSubject.asObservable(); + showSymmetrySelectionDialogSubject = new Subject(); + readonly symmetrySelectionDialog = this.showSymmetrySelectionDialogSubject.asObservable(); + showStammdatenEditDialogSubject = new Subject(); readonly stammdatenEditDialog = this.showStammdatenEditDialogSubject.asObservable(); @@ -379,6 +383,13 @@ export class UiInteractionService implements OnDestroy { return confirmationDiagramParameter.dialogFeedback; } + showSymmetrySelectionDialog( + symmetrySelectionParameter: SymmetrySelectionDialogParameter, + ): Observable { + this.showSymmetrySelectionDialogSubject.next(symmetrySelectionParameter); + return symmetrySelectionParameter.dialogFeedback; + } + showStammdatenEditDialog(stammdaten: Stammdaten[]) { this.showStammdatenEditDialogSubject.next(stammdaten); } diff --git a/src/app/services/util/symmetry-toggle.service.ts b/src/app/services/util/symmetry-toggle.service.ts new file mode 100644 index 000000000..0f088083f --- /dev/null +++ b/src/app/services/util/symmetry-toggle.service.ts @@ -0,0 +1,133 @@ +import {Injectable} from "@angular/core"; +import {TrainrunSection} from "../../models/trainrunsection.model"; +import {TrainrunSectionTimesService} from "../data/trainrun-section-times.service"; +import {TrainrunSectionService} from "../data/trainrunsection.service"; +import {UiInteractionService} from "../ui/ui.interaction.service"; +import {TrainrunService} from "../data/trainrun.service"; +import {TrainrunsectionHelper} from "./trainrunsection.helper"; +import { + SymmetryOn, + SymmetryReference, + SymmetrySelectionDialogParameter, +} from "../../view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component"; + +@Injectable({ + providedIn: "root", +}) +export class SymmetryToggleService { + constructor( + private trainrunService: TrainrunService, + private trainrunSectionService: TrainrunSectionService, + private uiInteractionService: UiInteractionService, + ) {} + + onLeftNodeSymmetryToggleChanged( + trainrunSection: TrainrunSection, + trainrunSectionTimesService: TrainrunSectionTimesService, + symmetry: boolean, + revertToggleCallback: () => void, + ) { + // Symmetry -> Asymmetry and on/off case + if ( + !symmetry || + trainrunSectionTimesService.areLeftAndRightTimeStructuresEqual(SymmetryOn.LeftNode) + ) { + trainrunSectionTimesService.onLeftNodeSymmetryChanged( + symmetry, + !TrainrunsectionHelper.isTargetRightOrBottom(trainrunSection), + ); + return; + } + + // Asymmetry -> Symmetry, show the dialog to choose symmetry reference + this.showSymmetrySelectionDialog(SymmetryOn.LeftNode, trainrunSectionTimesService).then( + (reference: SymmetryReference | null) => { + if (!(reference in SymmetryReference)) { + // User cancelled, need to revert toggle state + revertToggleCallback(); + return; + } + trainrunSectionTimesService.onLeftNodeSymmetryChanged( + symmetry, + !TrainrunsectionHelper.isTargetRightOrBottom(trainrunSection), + reference, + ); + }, + ); + } + + onRightNodeSymmetryToggleChanged( + trainrunSection: TrainrunSection, + trainrunSectionTimesService: TrainrunSectionTimesService, + symmetry: boolean, + revertToggleCallback: () => void, + ) { + // Symmetry -> Asymmetry and on/off case + if ( + !symmetry || + trainrunSectionTimesService.areLeftAndRightTimeStructuresEqual(SymmetryOn.RightNode) + ) { + trainrunSectionTimesService.onRightNodeSymmetryChanged( + symmetry, + !TrainrunsectionHelper.isTargetRightOrBottom(trainrunSection), + ); + return; + } + + // Asymmetry -> Symmetry, show the dialog to choose symmetry reference + this.showSymmetrySelectionDialog(SymmetryOn.RightNode, trainrunSectionTimesService).then( + (reference: SymmetryReference | null) => { + if (!(reference in SymmetryReference)) { + // User cancelled, need to revert toggle state + revertToggleCallback(); + return; + } + trainrunSectionTimesService.onRightNodeSymmetryChanged( + symmetry, + !TrainrunsectionHelper.isTargetRightOrBottom(trainrunSection), + reference, + ); + }, + ); + } + + onTrainrunSymmetryToggleChanged( + trainrunId: number, + trainrunSectionTimesService: TrainrunSectionTimesService, + revertToggleCallback: () => void, + ) { + if (trainrunSectionTimesService.areAllTimeStructuresEqual(trainrunId)) { + trainrunSectionTimesService.onTrainrunSymmetryChanged(trainrunId); + return; + } + this.showSymmetrySelectionDialog(SymmetryOn.Trainrun, trainrunSectionTimesService).then( + (reference: SymmetryReference | null) => { + if (!(reference in SymmetryReference)) { + // User cancelled (user clicks Cancel / X / outside the dialog), don't enable symmetry + revertToggleCallback(); + return; + } + trainrunSectionTimesService.onTrainrunSymmetryChanged(trainrunId, reference); + }, + ); + } + + private showSymmetrySelectionDialog( + symmetryOn: SymmetryOn, + trainrunSectionTimesService: TrainrunSectionTimesService, + ): Promise { + const parameter = new SymmetrySelectionDialogParameter( + symmetryOn, + this.trainrunService, + this.trainrunSectionService, + trainrunSectionTimesService, + ); + + return new Promise((resolve) => { + parameter.dialogFeedback.subscribe((result: SymmetryReference | null) => { + resolve(result); + }); + this.uiInteractionService.showSymmetrySelectionDialog(parameter); + }); + } +} diff --git a/src/app/services/util/trainrunsection.helper.spec.ts b/src/app/services/util/trainrunsection.helper.spec.ts index db2b82656..8e24f3898 100644 --- a/src/app/services/util/trainrunsection.helper.spec.ts +++ b/src/app/services/util/trainrunsection.helper.spec.ts @@ -89,32 +89,33 @@ describe("TrainrunsectionHelper", () => { rightDepartureTime: 20, rightArrivalTime: 40, travelTime: 10, + bottomTravelTime: 10, }; const d = TrainrunsectionHelper.getDefaultTimeStructure(larts); expect(d.travelTime).toBe(0); - expect(d.rightDepartureTime).toBe(0); - expect(d.rightArrivalTime).toBe(0); + expect(d.rightDepartureTime).toBe(20); + expect(d.rightArrivalTime).toBe(40); expect(d.leftDepartureTime).toBe(larts.leftDepartureTime); expect(d.leftArrivalTime).toBe(larts.leftArrivalTime); }); it("getTravelTime -- 001", () => { - const tt = TrainrunsectionHelper.getTravelTime(10, 10, 1, 12, false, 0); + const tt = TrainrunsectionHelper.getDistributedTravelTime(10, 10, 1, 12, false, 0); expect(tt).toBe(1); }); it("getTravelTime -- 002", () => { - const tt = TrainrunsectionHelper.getTravelTime(10, 10, 1, 12, true, 0); + const tt = TrainrunsectionHelper.getDistributedTravelTime(10, 10, 1, 12, true, 0); expect(tt).toBe(12); }); it("getTravelTime -- 003", () => { - const tt = TrainrunsectionHelper.getTravelTime(10, 10, 1, 12, false, 0); + const tt = TrainrunsectionHelper.getDistributedTravelTime(10, 10, 1, 12, false, 0); expect(tt).toBe(1); }); it("getTravelTime -- 004", () => { - const tt = TrainrunsectionHelper.getTravelTime(8, 10, 2, 12, false, 0); + const tt = TrainrunsectionHelper.getDistributedTravelTime(8, 10, 2, 12, false, 0); expect(tt).toBe(1); }); @@ -125,6 +126,7 @@ describe("TrainrunsectionHelper", () => { rightDepartureTime: 20, rightArrivalTime: 40, travelTime: 10, + bottomTravelTime: 10, }; const d = TrainrunsectionHelper.getDefaultTimeStructure(larts); const a = TrainrunsectionHelper.getRightArrivalTime(d); @@ -138,6 +140,7 @@ describe("TrainrunsectionHelper", () => { rightDepartureTime: 20, rightArrivalTime: 40, travelTime: 10, + bottomTravelTime: 10, }; const d = TrainrunsectionHelper.getDefaultTimeStructure(larts); d.leftArrivalTime = -10; @@ -152,6 +155,7 @@ describe("TrainrunsectionHelper", () => { rightDepartureTime: 20, rightArrivalTime: 40, travelTime: 10, + bottomTravelTime: 10, }; const d = TrainrunsectionHelper.getDefaultTimeStructure(larts); d.leftDepartureTime = undefined; @@ -166,10 +170,11 @@ describe("TrainrunsectionHelper", () => { rightDepartureTime: 20, rightArrivalTime: 40, travelTime: 10, + bottomTravelTime: 10, }; const d = TrainrunsectionHelper.getDefaultTimeStructure(larts); const a = TrainrunsectionHelper.getRightDepartureTime(d); - expect(a).toBe(0); + expect(a).toBe(20); }); it("getRightDepartureTime - 002", () => { @@ -179,6 +184,7 @@ describe("TrainrunsectionHelper", () => { rightDepartureTime: 20, rightArrivalTime: 40, travelTime: 10, + bottomTravelTime: 10, }; const d = TrainrunsectionHelper.getDefaultTimeStructure(larts); d.rightArrivalTime = -10; @@ -193,6 +199,7 @@ describe("TrainrunsectionHelper", () => { rightDepartureTime: 20, rightArrivalTime: 40, travelTime: 10, + bottomTravelTime: 10, }; const d = TrainrunsectionHelper.getDefaultTimeStructure(larts); d.rightArrivalTime = undefined; @@ -207,32 +214,33 @@ describe("TrainrunsectionHelper", () => { rightDepartureTime: 20, rightArrivalTime: 40, travelTime: 10, + bottomTravelTime: 10, }; const d = TrainrunsectionHelper.getDefaultTimeStructure(larts); expect(d.travelTime).toBe(0); - expect(d.rightDepartureTime).toBe(0); - expect(d.rightArrivalTime).toBe(0); + expect(d.rightDepartureTime).toBe(20); + expect(d.rightArrivalTime).toBe(40); expect(d.leftDepartureTime).toBe(larts.leftDepartureTime); expect(d.leftArrivalTime).toBe(larts.leftArrivalTime); }); it("getTravelTime -- 2 -- 001", () => { - const tt = TrainrunsectionHelper.getTravelTime(10, 10, 1, 12, false, 0); + const tt = TrainrunsectionHelper.getDistributedTravelTime(10, 10, 1, 12, false, 0); expect(tt).toBe(1); }); it("getTravelTime -- 2 -- 002", () => { - const tt = TrainrunsectionHelper.getTravelTime(10, 10, 1, 12, true, 0); + const tt = TrainrunsectionHelper.getDistributedTravelTime(10, 10, 1, 12, true, 0); expect(tt).toBe(12); }); it("getTravelTime -- 2 -- 003", () => { - const tt = TrainrunsectionHelper.getTravelTime(10, 10, 1, 12, false, 0); + const tt = TrainrunsectionHelper.getDistributedTravelTime(10, 10, 1, 12, false, 0); expect(tt).toBe(1); }); it("getTravelTime -- 2 -- 004", () => { - const tt = TrainrunsectionHelper.getTravelTime(8, 10, 2, 12, false, 0); + const tt = TrainrunsectionHelper.getDistributedTravelTime(8, 10, 2, 12, false, 0); expect(tt).toBe(1); }); @@ -243,6 +251,7 @@ describe("TrainrunsectionHelper", () => { rightDepartureTime: 20, rightArrivalTime: 40, travelTime: 10, + bottomTravelTime: 10, }; const d = TrainrunsectionHelper.getDefaultTimeStructure(larts); const a = TrainrunsectionHelper.getRightArrivalTime(d); @@ -256,6 +265,7 @@ describe("TrainrunsectionHelper", () => { rightDepartureTime: 20, rightArrivalTime: 40, travelTime: 10, + bottomTravelTime: 10, }; const d = TrainrunsectionHelper.getDefaultTimeStructure(larts); d.leftArrivalTime = -10; @@ -270,6 +280,7 @@ describe("TrainrunsectionHelper", () => { rightDepartureTime: 20, rightArrivalTime: 40, travelTime: 10, + bottomTravelTime: 10, }; const d = TrainrunsectionHelper.getDefaultTimeStructure(larts); d.leftDepartureTime = undefined; @@ -284,10 +295,11 @@ describe("TrainrunsectionHelper", () => { rightDepartureTime: 20, rightArrivalTime: 40, travelTime: 10, + bottomTravelTime: 10, }; const d = TrainrunsectionHelper.getDefaultTimeStructure(larts); const a = TrainrunsectionHelper.getRightDepartureTime(d); - expect(a).toBe(0); + expect(a).toBe(20); }); it("getRightDepartureTime - 002", () => { @@ -297,6 +309,7 @@ describe("TrainrunsectionHelper", () => { rightDepartureTime: 20, rightArrivalTime: 40, travelTime: 10, + bottomTravelTime: 10, }; const d = TrainrunsectionHelper.getDefaultTimeStructure(larts); d.rightArrivalTime = -10; @@ -311,6 +324,7 @@ describe("TrainrunsectionHelper", () => { rightDepartureTime: 20, rightArrivalTime: 40, travelTime: 10, + bottomTravelTime: 10, }; const d = TrainrunsectionHelper.getDefaultTimeStructure(larts); d.rightArrivalTime = undefined; diff --git a/src/app/services/util/trainrunsection.helper.ts b/src/app/services/util/trainrunsection.helper.ts index 219568a72..ede399f37 100644 --- a/src/app/services/util/trainrunsection.helper.ts +++ b/src/app/services/util/trainrunsection.helper.ts @@ -5,6 +5,7 @@ import { LeftAndRightLockStructure, LeftAndRightTimeStructure, } from "../../view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component"; +import {PartialTimeStructure} from "../data/trainrunsection.service"; import {MathUtils} from "../../utils/math"; import {TrainrunSectionText} from "../../data-structures/technical.data.structures"; import {TrainrunService} from "../data/trainrun.service"; @@ -16,6 +17,7 @@ export enum LeftAndRightElement { RightDeparture, RightArrival, TravelTime, + BottomTravelTime, LeftRightTrainrunName, RightLeftTrainrunName, } @@ -33,13 +35,14 @@ export class TrainrunsectionHelper { return { leftDepartureTime: timeStructure.leftDepartureTime, leftArrivalTime: timeStructure.leftArrivalTime, - rightDepartureTime: 0, - rightArrivalTime: 0, + rightDepartureTime: timeStructure.rightDepartureTime, + rightArrivalTime: timeStructure.rightArrivalTime, travelTime: 0, + bottomTravelTime: 0, }; } - static getTravelTime( + static getDistributedTravelTime( totalTravelTime: number, summedTravelTime: number, travelTimeFactor: number, @@ -60,6 +63,7 @@ export class TrainrunsectionHelper { } } + // TODO: remove this method static getRightArrivalTime( timeStructure: LeftAndRightTimeStructure, precision = TrainrunSectionService.TIME_PRECISION, @@ -70,6 +74,17 @@ export class TrainrunsectionHelper { ); } + static getLeftArrivalTime( + timeStructure: LeftAndRightTimeStructure, + precision = TrainrunSectionService.TIME_PRECISION, + ): number { + return MathUtils.round( + (timeStructure.rightDepartureTime + (timeStructure.bottomTravelTime % 60)) % 60, + precision, + ); + } + + // TODO: remove this method static getRightDepartureTime( timeStructure: LeftAndRightTimeStructure, precision = TrainrunSectionService.TIME_PRECISION, @@ -77,6 +92,16 @@ export class TrainrunsectionHelper { return MathUtils.round(this.getSymmetricTime(timeStructure.rightArrivalTime), precision); } + static getArrivalTime( + timeStructure: PartialTimeStructure, + precision = TrainrunSectionService.TIME_PRECISION, + ): number { + return MathUtils.round( + (timeStructure.departureTime + (timeStructure.travelTime % 60)) % 60, + precision, + ); + } + getLeftBetriebspunkt(trainrunSection: TrainrunSection, orderedNodes: Node[]): string[] { const nextStopLeftNode = this.getNextStopLeftNode(trainrunSection, orderedNodes); return [nextStopLeftNode.getBetriebspunktName(), "(" + nextStopLeftNode.getFullName() + ")"]; @@ -87,52 +112,15 @@ export class TrainrunsectionHelper { return [nextStopRightNode.getBetriebspunktName(), "(" + nextStopRightNode.getFullName() + ")"]; } - getLeftRightSections(trainrunSection: TrainrunSection) { - const bothLastNonStopTransitNodes = - this.trainrunService.getBothLastNonStopNodes(trainrunSection); - - const startForwardBackwardNode = GeneralViewFunctions.getStartForwardAndBackwardNode( - bothLastNonStopTransitNodes.lastNonStopNode1, - bothLastNonStopTransitNodes.lastNonStopNode2, - ); - const lastLeftNode = startForwardBackwardNode.startForwardNode; - const lastRightNode = startForwardBackwardNode.startBackwardNode; - - const towardsSource = this.trainrunService.getLastNonStopTrainrunSection( - trainrunSection.getSourceNode(), - trainrunSection, - ); - const towradsTarget = this.trainrunService.getLastNonStopTrainrunSection( - trainrunSection.getTargetNode(), - trainrunSection, - ); - - let leftSection = towradsTarget; - let rightSection = towardsSource; - if ( - towardsSource.getSourceNodeId() === lastLeftNode.getId() || - towardsSource.getTargetNodeId() === lastLeftNode.getId() - ) { - leftSection = towardsSource; - rightSection = towradsTarget; - } - return { - leftSection: leftSection, - rightSection: rightSection, - lastLeftNode: lastLeftNode, - lastRightNode: lastRightNode, - }; - } - getSourceLock( lockStructure: LeftAndRightLockStructure, trainrunSection: TrainrunSection, ): boolean { - const leftRight = this.getLeftRightSections(trainrunSection); - if (trainrunSection.getSourceNodeId() === leftRight.lastLeftNode.getId()) { + const sections = this.trainrunService.getNonStopSectionsChain(trainrunSection); + if (trainrunSection.getSourceNodeId() === sections[0].getSourceNodeId()) { return lockStructure.leftLock; } - if (trainrunSection.getSourceNodeId() === leftRight.lastRightNode.getId()) { + if (trainrunSection.getSourceNodeId() === sections[sections.length - 1].getTargetNodeId()) { return lockStructure.rightLock; } return undefined; @@ -142,11 +130,11 @@ export class TrainrunsectionHelper { lockStructure: LeftAndRightLockStructure, trainrunSection: TrainrunSection, ): boolean { - const leftRight = this.getLeftRightSections(trainrunSection); - if (trainrunSection.getTargetNodeId() === leftRight.lastLeftNode.getId()) { + const sections = this.trainrunService.getNonStopSectionsChain(trainrunSection); + if (trainrunSection.getTargetNodeId() === sections[0].getSourceNodeId()) { return lockStructure.leftLock; } - if (trainrunSection.getTargetNodeId() === leftRight.lastRightNode.getId()) { + if (trainrunSection.getTargetNodeId() === sections[sections.length - 1].getTargetNodeId()) { return lockStructure.rightLock; } return undefined; @@ -198,28 +186,28 @@ export class TrainrunsectionHelper { ): LeftAndRightElement | undefined { const nextStopLeftNode = this.getNextStopLeftNode(trainrunSection, orderedNodes); const sourceNodeid = trainrunSection.getSourceNode().getId(); - const targetNodeid = trainrunSection.getTargetNode().getId(); + const isNextStopNodeSource = sourceNodeid === nextStopLeftNode.getId(); switch (trainrunSectionSelectedText) { case TrainrunSectionText.SourceDeparture: - return sourceNodeid === nextStopLeftNode.getId() + return isNextStopNodeSource ? LeftAndRightElement.LeftDeparture : LeftAndRightElement.RightDeparture; case TrainrunSectionText.SourceArrival: - return sourceNodeid === nextStopLeftNode.getId() + return isNextStopNodeSource ? LeftAndRightElement.LeftArrival : LeftAndRightElement.RightArrival; case TrainrunSectionText.TargetDeparture: - return targetNodeid === nextStopLeftNode.getId() - ? LeftAndRightElement.LeftDeparture - : LeftAndRightElement.RightDeparture; + return isNextStopNodeSource + ? LeftAndRightElement.RightDeparture + : LeftAndRightElement.LeftDeparture; case TrainrunSectionText.TargetArrival: - return targetNodeid === nextStopLeftNode.getId() - ? LeftAndRightElement.LeftArrival - : LeftAndRightElement.RightArrival; + return isNextStopNodeSource + ? LeftAndRightElement.RightArrival + : LeftAndRightElement.LeftArrival; case TrainrunSectionText.TrainrunSectionName: if (forward === undefined) { @@ -236,38 +224,47 @@ export class TrainrunsectionHelper { : LeftAndRightElement.LeftRightTrainrunName; case TrainrunSectionText.TrainrunSectionTravelTime: - return LeftAndRightElement.TravelTime; - } - return undefined; - } + return LeftAndRightElement.TravelTime; // p-e - mapLeftAndRightTimes( - trainrunSection: TrainrunSection, - orderedNodes: Node[], - timeStructure: LeftAndRightTimeStructure, - ): LeftAndRightTimeStructure { - const bothLastNonStopNodes = this.trainrunService.getBothLastNonStopNodes(trainrunSection); - const leftNode = GeneralViewFunctions.getLeftOrTopNode( - bothLastNonStopNodes.lastNonStopNode1, - bothLastNonStopNodes.lastNonStopNode2, - ); - const localLeftNode = this.getNextStopLeftNode(trainrunSection, orderedNodes); - if (leftNode.getId() !== localLeftNode.getId()) { - const mappedTimeStructure = TrainrunsectionHelper.getDefaultTimeStructure(timeStructure); - mappedTimeStructure.rightArrivalTime = timeStructure.leftArrivalTime; - mappedTimeStructure.leftArrivalTime = timeStructure.rightArrivalTime; - mappedTimeStructure.rightDepartureTime = timeStructure.leftDepartureTime; - mappedTimeStructure.leftDepartureTime = timeStructure.rightDepartureTime; - mappedTimeStructure.travelTime = timeStructure.travelTime; - return mappedTimeStructure; + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + return LeftAndRightElement.BottomTravelTime; + + default: + return undefined; } - return timeStructure; } getLeftAndRightTimes( trainrunSection: TrainrunSection, orderedNodes: Node[], + onPerlenkette: boolean, ): LeftAndRightTimeStructure { + const targetIsRightOrBottom = TrainrunsectionHelper.isTargetRightOrBottom(trainrunSection); + + // Perlenkette component strictly displays the trainrunSection times, no matter if the trainrun stops at its source/target nodes + if (onPerlenkette) { + if (targetIsRightOrBottom) { + return { + leftDepartureTime: trainrunSection.getSourceNode().getDepartureTime(trainrunSection), + leftArrivalTime: trainrunSection.getSourceNode().getArrivalTime(trainrunSection), + rightDepartureTime: trainrunSection.getTargetNode().getDepartureTime(trainrunSection), + rightArrivalTime: trainrunSection.getTargetNode().getArrivalTime(trainrunSection), + travelTime: trainrunSection.getTravelTime(), + bottomTravelTime: trainrunSection.getBackwardTravelTime(), + }; + } else { + return { + leftDepartureTime: trainrunSection.getTargetNode().getDepartureTime(trainrunSection), + leftArrivalTime: trainrunSection.getTargetNode().getArrivalTime(trainrunSection), + rightDepartureTime: trainrunSection.getSourceNode().getDepartureTime(trainrunSection), + rightArrivalTime: trainrunSection.getSourceNode().getArrivalTime(trainrunSection), + travelTime: trainrunSection.getBackwardTravelTime(), + bottomTravelTime: trainrunSection.getTravelTime(), + }; + } + } + + // The other components display the times a the trainrunSections chain where first and last nodes are stops for this trainrun const bothLastNonStopNodes = this.trainrunService.getBothLastNonStopNodes(trainrunSection); const bothLastNonStopTrainrunSections = this.trainrunService.getBothLastNonStopTrainrunSections(trainrunSection); @@ -282,14 +279,21 @@ export class TrainrunsectionHelper { lastRightNode.getId() === bothLastNonStopNodes.lastNonStopNode1.getId() ? bothLastNonStopTrainrunSections.lastNonStopTrainrunSection1 : bothLastNonStopTrainrunSections.lastNonStopTrainrunSection2; - const cumulativeTravelTime = this.trainrunService.getCumulativeTravelTime(trainrunSection); + + const travelTime = targetIsRightOrBottom + ? this.trainrunService.getCumulativeTravelTime(trainrunSection) + : this.trainrunService.getCumulativeBackwardTravelTime(trainrunSection); + const bottomTravelTime = targetIsRightOrBottom + ? this.trainrunService.getCumulativeBackwardTravelTime(trainrunSection) + : this.trainrunService.getCumulativeTravelTime(trainrunSection); return { leftDepartureTime: lastLeftNode.getDepartureTime(leftTrainrunSection), leftArrivalTime: lastLeftNode.getArrivalTime(leftTrainrunSection), rightDepartureTime: lastRightNode.getDepartureTime(rightTrainrunSection), rightArrivalTime: lastRightNode.getArrivalTime(rightTrainrunSection), - travelTime: cumulativeTravelTime, + travelTime, + bottomTravelTime, }; } @@ -343,10 +347,149 @@ export class TrainrunsectionHelper { return rightNode; } + isLeftNextStopNodeSymmetric(trainrunSection: TrainrunSection, orderedNodes: Node[]): boolean { + const leftNode = this.getNextStopLeftNode(trainrunSection, orderedNodes); + + // find the trainrunSection where this left node is bound + const bothLastNonStopNodes = this.trainrunService.getBothLastNonStopNodes(trainrunSection); + const bothLastNonStopTrainrunSections = + this.trainrunService.getBothLastNonStopTrainrunSections(trainrunSection); + const leftTrainrunSection = + leftNode.getId() === bothLastNonStopNodes.lastNonStopNode1.getId() + ? bothLastNonStopTrainrunSections.lastNonStopTrainrunSection1 + : bothLastNonStopTrainrunSections.lastNonStopTrainrunSection2; + + if (leftTrainrunSection.getSourceNodeId() === leftNode.getId()) { + return leftTrainrunSection.getSourceSymmetry(); + } else if (leftTrainrunSection.getTargetNodeId() === leftNode.getId()) { + return leftTrainrunSection.getTargetSymmetry(); + } else { + throw new Error("Left node is neither source nor target of its trainrun section."); + } + } + + isRightNextStopNodeSymmetric(trainrunSection: TrainrunSection, orderedNodes: Node[]): boolean { + const rightNode = this.getNextStopRightNode(trainrunSection, orderedNodes); + + // find the trainrun section where this right node is bound + const bothLastNonStopNodes = this.trainrunService.getBothLastNonStopNodes(trainrunSection); + const bothLastNonStopTrainrunSections = + this.trainrunService.getBothLastNonStopTrainrunSections(trainrunSection); + const rightTrainrunSection = + rightNode.getId() === bothLastNonStopNodes.lastNonStopNode1.getId() + ? bothLastNonStopTrainrunSections.lastNonStopTrainrunSection1 + : bothLastNonStopTrainrunSections.lastNonStopTrainrunSection2; + + if (rightTrainrunSection.getSourceNodeId() === rightNode.getId()) { + return rightTrainrunSection.getSourceSymmetry(); + } else if (rightTrainrunSection.getTargetNodeId() === rightNode.getId()) { + return rightTrainrunSection.getTargetSymmetry(); + } else { + throw new Error("Right node is neither source nor target of its trainrun section."); + } + } + + isLeftToggleDisabled( + trainrunSection: TrainrunSection, + lockStructure: LeftAndRightLockStructure, + orderedNodes?: Node[], + ): boolean { + let isLeftSymmetric, isRightSymmetric; + if (orderedNodes) { + // for sbb-trainrunsection-tab component + isLeftSymmetric = this.isLeftNextStopNodeSymmetric(trainrunSection, orderedNodes); + isRightSymmetric = this.isRightNextStopNodeSymmetric(trainrunSection, orderedNodes); + } else { + // for sbb-perlenkette-section component + isLeftSymmetric = TrainrunsectionHelper.isLeftNodeSymmetric(trainrunSection); + isRightSymmetric = TrainrunsectionHelper.isRightNodeSymmetric(trainrunSection); + } + return ( + !isLeftSymmetric && + !trainrunSection.areTravelTimesEqual() && + ((lockStructure.travelTimeLock && lockStructure.rightLock) || + (isRightSymmetric && lockStructure.travelTimeLock)) + ); + } + + isRightToggleDisabled( + trainrunSection: TrainrunSection, + lockStructure: LeftAndRightLockStructure, + orderedNodes?: Node[], + ): boolean { + let isLeftSymmetric, isRightSymmetric; + if (orderedNodes) { + // for sbb-trainrunsection-tab component + isLeftSymmetric = this.isLeftNextStopNodeSymmetric(trainrunSection, orderedNodes); + isRightSymmetric = this.isRightNextStopNodeSymmetric(trainrunSection, orderedNodes); + } else { + // for sbb-perlenkette-section component + isLeftSymmetric = TrainrunsectionHelper.isLeftNodeSymmetric(trainrunSection); + isRightSymmetric = TrainrunsectionHelper.isRightNodeSymmetric(trainrunSection); + } + return ( + !isRightSymmetric && + !trainrunSection.areTravelTimesEqual() && + ((lockStructure.travelTimeLock && lockStructure.leftLock) || + (isLeftSymmetric && lockStructure.travelTimeLock)) + ); + } + static isTargetRightOrBottom(trainrunSection: TrainrunSection): boolean { const sourceNode = trainrunSection.getSourceNode(); const targetNode = trainrunSection.getTargetNode(); return GeneralViewFunctions.getRightOrBottomNode(sourceNode, targetNode) === targetNode; } + + static isChainTargetRightOrBottom( + firstTrainrunSection: TrainrunSection, + lastTrainrunSection: TrainrunSection, + ): boolean { + const sourceNode = firstTrainrunSection.getSourceNode(); + const targetNode = lastTrainrunSection.getTargetNode(); + + return GeneralViewFunctions.getRightOrBottomNode(sourceNode, targetNode) === targetNode; + } + + static isLeftSideDisplayed(trainrunSection: TrainrunSection): boolean { + return ( + trainrunSection.getTrainrun().isRoundTrip() || + !TrainrunsectionHelper.isTargetRightOrBottom(trainrunSection) + ); + } + + static isRightSideDisplayed(trainrunSection: TrainrunSection): boolean { + return ( + trainrunSection.getTrainrun().isRoundTrip() || + TrainrunsectionHelper.isTargetRightOrBottom(trainrunSection) + ); + } + + static getAdjustedTimeBasedOnSymmetry( + isSymmetricOnNode: boolean, + defaultTime: number, + symmetricTime: number, + ): number { + if (isSymmetricOnNode) { + return TrainrunsectionHelper.getSymmetricTime(symmetricTime); + } + return defaultTime; + } + + static isLeftNodeSymmetric(trainrunSection: TrainrunSection): boolean { + if (TrainrunsectionHelper.isTargetRightOrBottom(trainrunSection)) { + return trainrunSection.getSourceSymmetry(); + } else { + return trainrunSection.getTargetSymmetry(); + } + } + + static isRightNodeSymmetric(trainrunSection: TrainrunSection): boolean { + if (TrainrunsectionHelper.isTargetRightOrBottom(trainrunSection)) { + return trainrunSection.getTargetSymmetry(); + } else { + return trainrunSection.getSourceSymmetry(); + } + } } diff --git a/src/app/services/util/trainrunsection.routing.ts b/src/app/services/util/trainrunsection.routing.ts index af76f409e..5f1b17149 100644 --- a/src/app/services/util/trainrunsection.routing.ts +++ b/src/app/services/util/trainrunsection.routing.ts @@ -298,6 +298,7 @@ export class SimpleTrainrunSectionRouter { static placeTextOnTrainrunSection( lineWayPoints: Vec2D[], sourcePort: Port, + isBackwardTravelTimeDisplayed: boolean, ): TrainrunSectionTextPositions { const s = lineWayPoints[0]; const s1 = lineWayPoints[1]; @@ -402,6 +403,17 @@ export class SimpleTrainrunSectionRouter { namePosOffsetDirection, ); + const trainrunSectionTravelTimePos = isBackwardTravelTimeDisplayed + ? Vec2D.add( + Vec2D.scale(Vec2D.add(s1, t1), 0.5), + Vec2D.scale(rDeltaS, -TRAINRUN_SECTION_LINE_TEXT_HEIGHT / 2 + TRAINRUN_SECTION_TIME_TOP), + ) + : trainrunSectionNamePos; + const trainrunSectionBackwardTravelTimePos = Vec2D.add( + Vec2D.scale(Vec2D.add(s1, t1), 0.5), + Vec2D.scale(rDeltaS, TRAINRUN_SECTION_LINE_TEXT_HEIGHT / 2 + TRAINRUN_SECTION_TIME_BOTTOM), + ); + const trainrunSectionNumberOfStopsPos = Vec2D.add( Vec2D.scale(Vec2D.add(s1, t1), 0.5), nameNumberOfStopsOffsetDirection, @@ -413,7 +425,9 @@ export class SimpleTrainrunSectionRouter { [TrainrunSectionText.TargetArrival]: targetArrivalPos.toPointDto(), [TrainrunSectionText.TargetDeparture]: targetDeparturePos.toPointDto(), [TrainrunSectionText.TrainrunSectionName]: trainrunSectionNamePos.toPointDto(), - [TrainrunSectionText.TrainrunSectionTravelTime]: trainrunSectionNamePos.toPointDto(), + [TrainrunSectionText.TrainrunSectionTravelTime]: trainrunSectionTravelTimePos.toPointDto(), + [TrainrunSectionText.TrainrunSectionBackwardTravelTime]: + trainrunSectionBackwardTravelTimePos.toPointDto(), [TrainrunSectionText.TrainrunSectionNumberOfStops]: trainrunSectionNumberOfStopsPos.toPointDto(), }; diff --git a/src/app/services/util/trainrunsection.validator.ts b/src/app/services/util/trainrunsection.validator.ts index be656dcab..13da91060 100644 --- a/src/app/services/util/trainrunsection.validator.ts +++ b/src/app/services/util/trainrunsection.validator.ts @@ -11,6 +11,7 @@ export class TrainrunSectionValidator { } static validateTravelTimeOneSection(trainrunSection: TrainrunSection) { + // Source -> Target const calculatedTargetArrivalTime = (trainrunSection.getSourceDeparture() + trainrunSection.getTravelTime()) % 60; if (Math.abs(calculatedTargetArrivalTime - trainrunSection.getTargetArrival()) > 1 / 60) { @@ -22,8 +23,11 @@ export class TrainrunSectionValidator { trainrunSection.resetTargetArrivalWarning(); } - const calculatedSourceArrivalTime = - (trainrunSection.getTargetDeparture() + trainrunSection.getTravelTime()) % 60; + // Source <- Target + const travelTime = trainrunSection.isSymmetric() + ? trainrunSection.getTravelTime() + : trainrunSection.getBackwardTravelTime(); + const calculatedSourceArrivalTime = (trainrunSection.getTargetDeparture() + travelTime) % 60; if (Math.abs(calculatedSourceArrivalTime - trainrunSection.getSourceArrival()) > 1 / 60) { trainrunSection.setSourceArrivalWarning( $localize`:@@app.services.util.trainrunsection-validator.source-arrival-not-reacheable.title:Source Arrival Warning`, @@ -32,9 +36,32 @@ export class TrainrunSectionValidator { } else { trainrunSection.resetSourceArrivalWarning(); } + + // Non-stop time propagation with asymmetric times in the non-stop sections chain (Source <- Target context) + if ( + trainrunSection.isSymmetric() && + trainrunSection.getTravelTime() !== trainrunSection.getBackwardTravelTime() + ) { + trainrunSection.setTravelTimeWarning( + $localize`:@@app.services.util.trainrunsection-validator.travel-times-not-equal.title:Travel Times not equal`, + $localize`:@@app.services.util.trainrunsection-validator.travel-times-not-equal.description:Travel times are not compatible with return trip time schedules` + + " (" + + trainrunSection.getTargetDeparture() + + " + " + + trainrunSection.getTravelTime() + + " != " + + trainrunSection.getSourceArrival() + + ")", + ); + } else { + trainrunSection.resetTravelTimeWarning(); + } } static validateUnsymmetricTimesOneSection(trainrunSection: TrainrunSection) { + if (!trainrunSection.isSymmetric()) { + return; + } // check for broken symmetry (times) trainrunSection.resetSourceDepartureWarning(); trainrunSection.resetTargetDepartureWarning(); @@ -43,7 +70,12 @@ export class TrainrunSectionValidator { 4, ); const sourceSymmetricCheck = Math.abs(sourceSum % 60) < 1 / 60; - if (!sourceSymmetricCheck) { + if ( + !sourceSymmetricCheck && + trainrunSection.getSourceNode() && + !trainrunSection.getSourceNode().isNonStop(trainrunSection) + ) { + // display warning only if the target node is a stopping node trainrunSection.setSourceArrivalWarning( $localize`:@@app.services.util.trainrunsection-validator.broken-symmetry:Broken symmetry`, "" + @@ -64,7 +96,12 @@ export class TrainrunSectionValidator { 4, ); const targetSymmetricCheck = Math.abs(targetSum % 60) < 1 / 60; - if (!targetSymmetricCheck) { + if ( + !targetSymmetricCheck && + trainrunSection.getTargetNode() && + !trainrunSection.getTargetNode().isNonStop(trainrunSection) + ) { + // display warning only if the target node is a stopping node trainrunSection.setTargetArrivalWarning( $localize`:@@app.services.util.trainrunsection-validator.broken-symmetry:Broken symmetry`, "" + @@ -92,4 +129,15 @@ export class TrainrunSectionValidator { trainrunSection.resetTravelTimeWarning(); } } + + static validateBackwardTravelTime(trainrunSection: TrainrunSection) { + if (trainrunSection.getBackwardTravelTime() < 1) { + trainrunSection.setBackwardTravelTimeWarning( + $localize`:@@app.services.util.trainrunsection-validator.travel-time-less-than-1.title:Travel Time less than 1`, + $localize`:@@app.services.util.trainrunsection-validator.travel-time-less-than-1.description:Travel time must be greater than or equal to 1`, + ); + } else { + trainrunSection.resetBackwardTravelTimeWarning(); + } + } } diff --git a/src/app/services/util/transition.validator.spec.ts b/src/app/services/util/transition.validator.spec.ts index ca14af77a..a28e56b93 100644 --- a/src/app/services/util/transition.validator.spec.ts +++ b/src/app/services/util/transition.validator.spec.ts @@ -164,13 +164,13 @@ describe("TransitionValidator", () => { TransitionValidator.validateTransition(ts.getSourceNode(), transitionId); expect(trainrunSections.trainrunSection1.hasTargetArrivalWarning()).toBe(true); - expect(trainrunSections.trainrunSection1.hasTargetDepartureWarning()).toBe(true); + expect(trainrunSections.trainrunSection1.hasTargetDepartureWarning()).toBe(false); expect(trainrunSections.trainrunSection1.hasSourceArrivalWarning()).toBe(false); expect(trainrunSections.trainrunSection1.hasSourceDepartureWarning()).toBe(false); expect(trainrunSections.trainrunSection2.hasTargetArrivalWarning()).toBe(false); expect(trainrunSections.trainrunSection2.hasTargetDepartureWarning()).toBe(false); - expect(trainrunSections.trainrunSection2.hasSourceArrivalWarning()).toBe(true); + expect(trainrunSections.trainrunSection2.hasSourceArrivalWarning()).toBe(false); expect(trainrunSections.trainrunSection2.hasSourceDepartureWarning()).toBe(true); }); @@ -214,7 +214,7 @@ describe("TransitionValidator", () => { TransitionValidator.validateTransition(ts.getSourceNode(), transitionId); - expect(trainrunSections.trainrunSection1.hasTargetArrivalWarning()).toBe(true); + expect(trainrunSections.trainrunSection1.hasTargetArrivalWarning()).toBe(false); expect(trainrunSections.trainrunSection1.hasTargetDepartureWarning()).toBe(true); expect(trainrunSections.trainrunSection1.hasSourceArrivalWarning()).toBe(false); expect(trainrunSections.trainrunSection1.hasSourceDepartureWarning()).toBe(false); @@ -222,7 +222,7 @@ describe("TransitionValidator", () => { expect(trainrunSections.trainrunSection2.hasTargetArrivalWarning()).toBe(false); expect(trainrunSections.trainrunSection2.hasTargetDepartureWarning()).toBe(false); expect(trainrunSections.trainrunSection2.hasSourceArrivalWarning()).toBe(true); - expect(trainrunSections.trainrunSection2.hasSourceDepartureWarning()).toBe(true); + expect(trainrunSections.trainrunSection2.hasSourceDepartureWarning()).toBe(false); }); it("Validate Test - 004", () => { @@ -339,7 +339,7 @@ describe("TransitionValidator", () => { dataService.loadNetzgrafikDto(NetzgrafikUnitTesting.getUnitTestNetzgrafik()); const ts1 = trainrunSectionService.getTrainrunSectionFromId(4); const ts2 = trainrunSectionService.getTrainrunSectionFromId(5); - const trainrun = trainrunService.getSelectedOrNewTrainrun(); + trainrunService.getSelectedOrNewTrainrun(); trainrunSectionService.createTrainrunSection(ts1.getTargetNodeId(), ts1.getSourceNodeId()); trainrunSectionService.createTrainrunSection(ts2.getTargetNodeId(), ts2.getSourceNodeId()); const ts = trainrunSectionService.getSelectedTrainrunSection(); @@ -385,23 +385,35 @@ describe("TransitionValidator", () => { TransitionValidator.validateTransition(ts.getTargetNode(), transitionId); - expect(trainrunSections.trainrunSection1.hasTargetArrivalWarning()).toBe(false); + expect(trainrunSections.trainrunSection1.hasTargetArrivalWarning()).toBe(true); expect(trainrunSections.trainrunSection1.hasTargetDepartureWarning()).toBe(false); - expect(trainrunSections.trainrunSection1.hasSourceArrivalWarning()).toBe(true); - expect(trainrunSections.trainrunSection1.hasSourceDepartureWarning()).toBe(true); + expect(trainrunSections.trainrunSection1.hasSourceArrivalWarning()).toBe(false); + expect(trainrunSections.trainrunSection1.hasSourceDepartureWarning()).toBe(false); - expect(trainrunSections.trainrunSection2.hasTargetArrivalWarning()).toBe(true); - expect(trainrunSections.trainrunSection2.hasTargetDepartureWarning()).toBe(true); + expect(trainrunSections.trainrunSection2.hasTargetArrivalWarning()).toBe(false); + expect(trainrunSections.trainrunSection2.hasTargetDepartureWarning()).toBe(false); expect(trainrunSections.trainrunSection2.hasSourceArrivalWarning()).toBe(false); - expect(trainrunSections.trainrunSection2.hasSourceDepartureWarning()).toBe(false); + expect(trainrunSections.trainrunSection2.hasSourceDepartureWarning()).toBe(true); }); it("Validate Test - 007", () => { dataService.loadNetzgrafikDto(NetzgrafikUnitTesting.getUnitTestNetzgrafik()); - const ts1 = trainrunSectionService.getTrainrunSectionFromId(4); + // stop case + const ts1 = trainrunSectionService.getTrainrunSectionFromId(1); ts1.setSourceDeparture((ts1.getSourceDeparture() + 1) % 60); - const a = ts1.getSourceArrival(); - const b = ts1.getSourceDeparture(); - expect(ts1.getSourceArrivalWarning().description).toBe("" + a + " + " + b + " = " + (a + b)); + const a1 = ts1.getSourceArrival(); + const b1 = ts1.getSourceDeparture(); + expect(ts1.getSourceDepartureWarning().description).toBe( + "" + a1 + " + " + b1 + " = " + (a1 + b1), + ); + expect(ts1.getSourceArrivalWarning().description).toBe( + "" + a1 + " + " + b1 + " = " + (a1 + b1), + ); + expect(ts1.getTargetArrivalWarning().description).toBeDefined(); + + // non-stop case + const ts4 = trainrunSectionService.getTrainrunSectionFromId(4); + ts4.setSourceDeparture((ts1.getSourceDeparture() + 1) % 60); + expect(ts1.getTargetArrivalWarning().description).toBeDefined(); }); }); diff --git a/src/app/services/util/transition.validator.ts b/src/app/services/util/transition.validator.ts index ca762cce2..4f286d8f9 100644 --- a/src/app/services/util/transition.validator.ts +++ b/src/app/services/util/transition.validator.ts @@ -2,80 +2,86 @@ import {Node} from "../../models/node.model"; export class TransitionValidator { static validateTransition(node: Node, transitionId: number) { - if (!node.getIsNonStop(transitionId)) { - const trainrunSections = node.getTrainrunSections(transitionId); + const trainrunSections = node.getTrainrunSections(transitionId); + const sourceSection = trainrunSections.trainrunSection1; + const targetSection = trainrunSections.trainrunSection2; - const arrivalTime1 = node.getArrivalTime(trainrunSections.trainrunSection1); - const departureTime1 = node.getDepartureTime(trainrunSections.trainrunSection1); + if (!node.getIsNonStop(transitionId)) { + const arrivalTime1 = node.getArrivalTime(sourceSection); + const departureTime1 = node.getDepartureTime(sourceSection); - const arrivalTime2 = node.getArrivalTime(trainrunSections.trainrunSection2); - const departureTime2 = node.getDepartureTime(trainrunSections.trainrunSection2); + const arrivalTime2 = node.getArrivalTime(targetSection); + const departureTime2 = node.getDepartureTime(targetSection); const nodeHaltezeiten = node.getTrainrunCategoryHaltezeit(); const trainrunHaltezeit = - nodeHaltezeiten[ - trainrunSections.trainrunSection1.getTrainrun().getTrainrunCategory().fachCategory - ].haltezeit; + nodeHaltezeiten[sourceSection.getTrainrun().getTrainrunCategory().fachCategory].haltezeit; const calculatedDepartureTime2 = (arrivalTime1 + trainrunHaltezeit) % 60; const calculatedDepartureTime1 = (arrivalTime2 + trainrunHaltezeit) % 60; + + // Source -> Target check + if ( + calculatedDepartureTime2 !== departureTime2 && + sourceSection.getTargetSymmetry() && + targetSection.getSourceSymmetry() + ) { + sourceSection.setTargetArrivalWarning( + $localize`:@@app.services.util.transition-validator.target-arrival-not-reacheable.title:Target Arrival Warning`, + $localize`:@@app.services.util.transition-validator.target-arrival-not-reacheable.description:Target arrival time cannot be reached`, + ); + targetSection.setSourceDepartureWarning( + $localize`:@@app.services.util.transition-validator.source-departure-not-reacheable.title:Source Departure Warning`, + $localize`:@@app.services.util.transition-validator.source-departure-not-reacheable.description:Source departure time cannot be reached`, + ); + } else { + sourceSection.resetTargetArrivalWarning(); + targetSection.resetSourceDepartureWarning(); + } + + // Source <- Target check if ( - calculatedDepartureTime2 !== departureTime2 || - calculatedDepartureTime1 !== departureTime1 + calculatedDepartureTime1 !== departureTime1 && + sourceSection.getTargetSymmetry() && + targetSection.getSourceSymmetry() ) { - if (trainrunSections.trainrunSection1.getSourceNodeId() === node.getId()) { - trainrunSections.trainrunSection1.setSourceArrivalWarning( - $localize`:@@app.services.util.transition-validator.source-arrival-not-reacheable.title:Source Arrival Warning`, - $localize`:@@app.services.util.transition-validator.source-arrival-not-reacheable.description:Source arrival time cannot be reached`, - ); - trainrunSections.trainrunSection1.setSourceDepartureWarning( - $localize`:@@app.services.util.transition-validator.source-departure-not-reacheable.title:Source Departure Warning`, - $localize`:@@app.services.util.transition-validator.source-departure-not-reacheable.description:Source departure time cannot be reached`, - ); - } else { - trainrunSections.trainrunSection1.setTargetArrivalWarning( - $localize`:@@app.services.util.transition-validator.target-arrival-not-reacheable.title:Target Arrival Warning`, - $localize`:@@app.services.util.transition-validator.target-arrival-not-reacheable.description:Target arrival time cannot be reached`, - ); - trainrunSections.trainrunSection1.setTargetDepartureWarning( - $localize`:@@app.services.util.transition-validator.target-departure-not-reacheable.title:Target Departure Warning`, - $localize`:@@app.services.util.transition-validator.target-departure-not-reacheable.description:Target departure time cannot be reached`, - ); - } - if (trainrunSections.trainrunSection2.getSourceNodeId() === node.getId()) { - trainrunSections.trainrunSection2.setSourceArrivalWarning( - $localize`:@@app.services.util.transition-validator.source-arrival-not-reacheable.title:Source Arrival Warning`, - $localize`:@@app.services.util.transition-validator.source-arrival-not-reacheable.description:Source arrival time cannot be reached`, - ); - trainrunSections.trainrunSection2.setSourceDepartureWarning( - $localize`:@@app.services.util.transition-validator.source-departure-not-reacheable.title:Source Departure Warning`, - $localize`:@@app.services.util.transition-validator.source-departure-not-reacheable.description:Source departure time cannot be reached`, - ); - } else { - trainrunSections.trainrunSection2.setTargetArrivalWarning( - $localize`:@@app.services.util.transition-validator.target-arrival-not-reacheable.title:Target Arrival Warning`, - $localize`:@@app.services.util.transition-validator.target-arrival-not-reacheable.description:Target arrival time cannot be reached`, - ); - trainrunSections.trainrunSection2.setTargetDepartureWarning( - $localize`:@@app.services.util.transition-validator.target-departure-not-reacheable.title:Target Departure Warning`, - $localize`:@@app.services.util.transition-validator.target-departure-not-reacheable.description:Target departure time cannot be reached`, - ); - } + sourceSection.setTargetDepartureWarning( + $localize`:@@app.services.util.transition-validator.target-departure-not-reacheable.title:Target Departure Warning`, + $localize`:@@app.services.util.transition-validator.target-departure-not-reacheable.description:Target departure time cannot be reached`, + ); + targetSection.setSourceArrivalWarning( + $localize`:@@app.services.util.transition-validator.source-arrival-not-reacheable.title:Source Arrival Warning`, + $localize`:@@app.services.util.transition-validator.source-arrival-not-reacheable.description:Source arrival time cannot be reached`, + ); } else { - if (trainrunSections.trainrunSection1.getSourceNodeId() === node.getId()) { - trainrunSections.trainrunSection1.resetSourceArrivalWarning(); - trainrunSections.trainrunSection1.resetSourceDepartureWarning(); - } else { - trainrunSections.trainrunSection1.resetTargetArrivalWarning(); - trainrunSections.trainrunSection1.resetTargetDepartureWarning(); - } - if (trainrunSections.trainrunSection2.getSourceNodeId() === node.getId()) { - trainrunSections.trainrunSection2.resetSourceArrivalWarning(); - trainrunSections.trainrunSection2.resetSourceDepartureWarning(); - } else { - trainrunSections.trainrunSection2.resetTargetArrivalWarning(); - trainrunSections.trainrunSection2.resetTargetDepartureWarning(); - } + sourceSection.resetTargetDepartureWarning(); + targetSection.resetSourceArrivalWarning(); + } + } else { + // Source -> Target check + const expectedSourceDeparture2 = + (sourceSection.getSourceDeparture() + sourceSection.getTravelTime()) % 60; + if ( + !targetSection.getSourceSymmetry() && + expectedSourceDeparture2 !== targetSection.getSourceDeparture() + ) { + targetSection.setSourceDepartureWarning( + $localize`:@@app.services.util.transition-validator.source-departure-not-reacheable-asymmetry.title:Source Departure Warning`, + $localize`:@@app.services.util.transition-validator.source-departure-not-reacheable-asymmetry.description:Source departure time cannot be reached due to asymmetrical travel times`, + ); + } + + // Source <- Target check + const expectedTargetDeparture1 = + (targetSection.getTargetDeparture() + targetSection.getBackwardTravelTime()) % 60; + if ( + !sourceSection.getTargetSymmetry() && + expectedTargetDeparture1 !== sourceSection.getTargetDeparture() + ) { + sourceSection.setTargetDepartureWarning( + $localize`:@@app.services.util.transition-validator.target-departure-not-reacheable-asymmetry.title:Target Departure Warning`, + $localize`:@@app.services.util.transition-validator.target-departure-not-reacheable-asymmetry.description:Target departure time cannot be reached due to asymmetrical travel times`, + ); } } } diff --git a/src/app/streckengrafik/services/train-data-service.ts b/src/app/streckengrafik/services/train-data-service.ts index 94764bf32..a931b8838 100644 --- a/src/app/streckengrafik/services/train-data-service.ts +++ b/src/app/streckengrafik/services/train-data-service.ts @@ -87,6 +87,8 @@ export class TrainDataService implements OnDestroy { return trainrunSection.getTargetArrivalFormattedDisplayHtmlStyle(); case TrainrunSectionText.TrainrunSectionTravelTime: return trainrunSection.getTravelTimeFormattedDisplayHtmlStyle(); + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + return trainrunSection.getBackwardTravelTimeFormattedDisplayHtmlStyle(); default: return undefined; } @@ -112,6 +114,8 @@ export class TrainDataService implements OnDestroy { return trainrunSection.getTargetArrivalFormattedDisplayText(offset); case TrainrunSectionText.TrainrunSectionTravelTime: return trainrunSection.getTravelTimeFormattedDisplayText(offset); + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + return trainrunSection.getBackwardTravelTimeFormattedDisplayText(offset); default: return undefined; } @@ -133,6 +137,8 @@ export class TrainDataService implements OnDestroy { return trainrunSection.getTargetArrivalFormatterColorRef(); case TrainrunSectionText.TrainrunSectionTravelTime: return trainrunSection.getTravelTimeFormatterColorRef(); + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + return trainrunSection.getBackwardTravelTimeFormatterColorRef(); default: return undefined; } @@ -154,6 +160,8 @@ export class TrainDataService implements OnDestroy { return trainrunSection.getTargetArrivalFormattedDisplayTextWidth(); case TrainrunSectionText.TrainrunSectionTravelTime: return trainrunSection.getTravelTimeFormattedDisplayTextWidth(); + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + return trainrunSection.getBackwardTravelTimeFormattedDisplayTextWidth(); default: return undefined; } diff --git a/src/app/view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component.html b/src/app/view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component.html new file mode 100644 index 000000000..d970ab718 --- /dev/null +++ b/src/app/view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component.html @@ -0,0 +1,221 @@ + +
+ {{ "app.view.dialogs.symmetry-dialog.selection" | translate }} +
+ +
+
+ +
+
+
+ {{ startNode[1] }} ({{ startNode[0] }}) +
+
+ + + {{ topSymmetryTimeStructure.leftDepartureTime }} + + + {{ topSymmetryTimeStructure.leftArrivalTime }} + + + + + + + + + {{ topSymmetryTimeStructure.travelTime }} + + + {{ topSymmetryTimeStructure.travelTime }} + + + {{ topSymmetryTimeStructure.bottomTravelTime }} + + + + + {{ topSymmetryTimeStructure.rightArrivalTime }} + + + {{ topSymmetryTimeStructure.rightDepartureTime }} + + + + + + +
+
+ {{ endNode[1] }} ({{ endNode[0] }}) +
+
+
+ + +
+
+
+ {{ startNode[1] }} ({{ startNode[0] }}) +
+
+ + + {{ bottomSymmetryTimeStructure.leftDepartureTime }} + + + {{ bottomSymmetryTimeStructure.leftArrivalTime }} + + + + + + + + + {{ bottomSymmetryTimeStructure.travelTime }} + + + {{ bottomSymmetryTimeStructure.travelTime }} + + + {{ bottomSymmetryTimeStructure.bottomTravelTime }} + + + + + {{ bottomSymmetryTimeStructure.rightArrivalTime }} + + + {{ bottomSymmetryTimeStructure.rightDepartureTime }} + + + + + + +
+
+ {{ endNode[1] }} ({{ endNode[0] }}) +
+
+
+
+
+ +
+ + +
+
diff --git a/src/app/view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component.scss b/src/app/view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component.scss new file mode 100644 index 000000000..1b2d4b9de --- /dev/null +++ b/src/app/view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component.scss @@ -0,0 +1,70 @@ +@import "../../rastering/definitions"; + +// Style sbbDialogContent only within this component +:host ::ng-deep [sbbDialogContent] { + flex: inherit; +} + +.symmetry-selection-content { + padding: 0; + width: 100%; + min-width: 400px; + height: inherit; + min-height: inherit; + max-height: inherit; +} + +::ng-deep div.SymmetryCardBetriebspunkt { + max-width: 160px; + padding: 1px; + text-align: center; + align-content: center; + height: 40px; + font-family: "SBBWeb Light", "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +.TrainrunSection { + display: flex; + flex-direction: column; + justify-content: space-around; + row-gap: 6px; + padding-top: 6px; + padding-bottom: 6px; +} + +.SymmetryCard { + border-radius: 15px; + display: flex; + padding: 1rem 0; + justify-content: space-around; + align-items: center; + cursor: pointer; + * { + cursor: pointer; + } + + * > text.edge_text { + font-size: 10px; + } +} + +.SymmetryCard.muted { + border: 1px solid $COLOR_MUTED_SILVER; +} + +.SymmetryCard.selected { + border: 1px solid $COLOR_Focus; +} + +.SymmetryCard:hover { + background: var(--COLOR_TRANSITION_GRAYEDOUT); +} + +.SymmetryCard:active { + background-color: $COLOR_MUTED_SILVER; +} + +.TrainFreqContainer { + display: flex; + align-items: center; +} diff --git a/src/app/view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component.ts b/src/app/view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component.ts new file mode 100644 index 000000000..4e7b2d963 --- /dev/null +++ b/src/app/view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component.ts @@ -0,0 +1,233 @@ +import {Component, OnDestroy, TemplateRef, ViewChild} from "@angular/core"; +import {SbbDialog, SbbDialogConfig} from "@sbb-esta/angular/dialog"; +import {UiInteractionService} from "../../../services/ui/ui.interaction.service"; +import {Observable, Subject} from "rxjs"; +import {takeUntil} from "rxjs/operators"; +import {LeftAndRightTimeStructure} from "../trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component"; +import {StaticDomTags} from "../../editor-main-view/data-views/static.dom.tags"; +import {ColorRefType} from "src/app/data-structures/technical.data.structures"; +import {TrainrunSection} from "src/app/models/trainrunsection.model"; +import {TrainrunSectionService} from "src/app/services/data/trainrunsection.service"; +import {LinePatternRefs} from "src/app/data-structures/business.data.structures"; +import {TrainrunsectionHelper} from "../../../services/util/trainrunsection.helper"; +import {Node} from "src/app/models/node.model"; +import {TrainrunSectionTimesService} from "src/app/services/data/trainrun-section-times.service"; +import {TrainrunService} from "src/app/services/data/trainrun.service"; + +export enum SymmetryReference { + Top, + Bottom, +} + +export enum SymmetryOn { + LeftNode, + RightNode, + Trainrun, + TrainrunSection, +} + +export class SymmetrySelectionDialogParameter { + private trainrunSection: TrainrunSection; + public readonly symmetryOn: SymmetryOn; + public readonly topSymmetryTimeStructure: LeftAndRightTimeStructure; + public readonly bottomSymmetryTimeStructure: LeftAndRightTimeStructure; + public readonly startNode: string[]; + public readonly endNode: string[]; + public readonly subject: Subject; + public dialogFeedback: Observable; + + constructor( + symmetryOn: SymmetryOn, + private trainrunService: TrainrunService, + private trainrunSectionService: TrainrunSectionService, + public trainrunSectionTimesService: TrainrunSectionTimesService, + ) { + this.trainrunSection = this.trainrunSectionService.getSelectedTrainrunSection(); + if (this.trainrunSection === null) { + return; + } + this.trainrunSectionTimesService.setTrainrunSection(this.trainrunSection); + + // Calculate both symmetry alternatives for card preview + this.topSymmetryTimeStructure = + this.trainrunSectionTimesService.calculateTimeStructureAfterSymmetrySelection( + symmetryOn, + SymmetryReference.Top, + ); + this.bottomSymmetryTimeStructure = + this.trainrunSectionTimesService.calculateTimeStructureAfterSymmetrySelection( + symmetryOn, + SymmetryReference.Bottom, + ); + + // Determine start and end nodes based on symmetryOn + let nodes: {startNode: Node; endNode: Node}; + if (symmetryOn === SymmetryOn.Trainrun) { + nodes = { + startNode: this.trainrunService.getStartNodeWithTrainrunId( + this.trainrunSection.getTrainrunId(), + ), + endNode: this.trainrunService.getEndNodeWithTrainrunId( + this.trainrunSection.getTrainrunId(), + ), + }; + } else { + nodes = this.getNodesFromTrainrunSection(this.trainrunSection); + } + + this.startNode = [nodes.startNode.getFullName(), nodes.startNode.getBetriebspunktName()]; + this.endNode = [nodes.endNode.getFullName(), nodes.endNode.getBetriebspunktName()]; + + const dialogFeedbackSubject = new Subject(); + const dialogFeedback = dialogFeedbackSubject.asObservable(); + this.subject = dialogFeedbackSubject; + this.dialogFeedback = dialogFeedback; + } + + private getNodesFromTrainrunSection(trainrunSection: TrainrunSection): { + startNode: Node; + endNode: Node; + } { + // TODO: peut-être réutiliser de la logique de TrainrunSectionService + if (TrainrunsectionHelper.isTargetRightOrBottom(trainrunSection)) { + return { + startNode: trainrunSection.getSourceNode(), + endNode: trainrunSection.getTargetNode(), + }; + } else { + return { + startNode: trainrunSection.getTargetNode(), + endNode: trainrunSection.getSourceNode(), + }; + } + } +} + +@Component({ + selector: "sbb-symmetry-selection-dialog", + templateUrl: "./symmetry-selection-dialog.component.html", + styleUrls: ["./symmetry-selection-dialog.component.scss"], +}) +export class SymmetrySelectionDialogComponent implements OnDestroy { + @ViewChild("symmetrySelectionDialogTemplate", {static: true}) + symmetrySelectionDialogTemplate: TemplateRef; + + public selectedTrainrunSection: TrainrunSection; + public timeStructure: LeftAndRightTimeStructure; + public topSymmetryTimeStructure: LeftAndRightTimeStructure; + public bottomSymmetryTimeStructure: LeftAndRightTimeStructure; + public startNode: string[] = ["", ""]; + public endNode: string[] = ["", ""]; + public selectedSymmetryReference: SymmetryReference | null = null; + public frequencyLinePattern: LinePatternRefs; + public categoryColorRef: ColorRefType; + public timeCategoryLinePattern: LinePatternRefs; + public readonly SymmetryReference = SymmetryReference; + + private destroyed = new Subject(); + + constructor( + public dialog: SbbDialog, + private uiInteractionService: UiInteractionService, + private trainrunSectionService: TrainrunSectionService, + ) { + this.trainrunSectionService.trainrunSections + .pipe(takeUntil(this.destroyed)) + .subscribe(() => {}); + + this.uiInteractionService.symmetrySelectionDialog + .pipe(takeUntil(this.destroyed)) + .subscribe((parameter: SymmetrySelectionDialogParameter) => { + this.selectedTrainrunSection = this.trainrunSectionService.getSelectedTrainrunSection(); + if (this.selectedTrainrunSection === null) { + return; + } + + const selectedTrainrun = this.selectedTrainrunSection.getTrainrun(); + this.frequencyLinePattern = this.selectedTrainrunSection.getFrequencyLinePatternRef(); + this.categoryColorRef = selectedTrainrun.getCategoryColorRef(); + this.timeCategoryLinePattern = selectedTrainrun.getTimeCategoryLinePatternRef(); + this.startNode = parameter.startNode; + this.endNode = parameter.endNode; + this.selectedSymmetryReference = null; + this.topSymmetryTimeStructure = parameter.topSymmetryTimeStructure; + this.bottomSymmetryTimeStructure = parameter.bottomSymmetryTimeStructure; + + this.openDialog(parameter); + }); + } + + static getDialogConfig() { + const dialogConfig = new SbbDialogConfig(); + const width = 500; + dialogConfig.width = width + "px"; + dialogConfig.panelClass = "symmetry-selection-dialog"; + return dialogConfig; + } + + ngOnDestroy() { + this.destroyed.next(); + this.destroyed.complete(); + } + + onCardSelection(reference: SymmetryReference) { + this.selectedSymmetryReference = reference; + } + + isConfirmButtonDisabled() { + return !Object.values(SymmetryReference).includes(this.selectedSymmetryReference); + } + + onConfirm() { + this.dialog.openDialogs[this.dialog.openDialogs.length - 1].close( + this.selectedSymmetryReference, + ); + } + + onCancel() { + this.dialog.openDialogs[this.dialog.openDialogs.length - 1].close(null); + } + + openDialog(parameter: SymmetrySelectionDialogParameter) { + const dialogConfig = SymmetrySelectionDialogComponent.getDialogConfig(); + const dialogRef = this.dialog.open(this.symmetrySelectionDialogTemplate, dialogConfig); + dialogRef.afterClosed().subscribe((reference: SymmetryReference | null) => { + parameter.subject.next(reference); + }); + } + + getEdgeLineClassAttrString(layer: number, symmetryCard: SymmetryReference) { + return ( + StaticDomTags.EDGE_LINE_CLASS + + StaticDomTags.makeClassTag(StaticDomTags.LINE_LAYER, "" + layer) + + StaticDomTags.makeClassTag(StaticDomTags.FREQ_LINE_PATTERN, this.frequencyLinePattern) + + " " + + StaticDomTags.TAG_UI_DIALOG + + " " + + StaticDomTags.makeClassTag(StaticDomTags.TAG_COLOR_REF, this.getColorRefTag(symmetryCard)) + + StaticDomTags.makeClassTag(StaticDomTags.TAG_LINEPATTERN_REF, this.timeCategoryLinePattern) + ); + } + + getColorRefTag(symmetryCard: SymmetryReference) { + const colorRefTag = + symmetryCard === this.selectedSymmetryReference ? this.categoryColorRef : "NORMAL"; + return colorRefTag; + } + + getEdgeLineTextClass(symmetryCard: SymmetryReference) { + return ( + StaticDomTags.EDGE_LINE_TEXT_CLASS + + " " + + StaticDomTags.makeClassTag(StaticDomTags.TAG_COLOR_REF, this.getColorRefTag(symmetryCard)) + ); + } + + getEdgeLineArrowClass(symmetryCard: SymmetryReference) { + return ( + StaticDomTags.EDGE_LINE_ARROW_CLASS + + " " + + StaticDomTags.makeClassTag(StaticDomTags.TAG_COLOR_REF, this.getColorRefTag(symmetryCard)) + ); + } +} diff --git a/src/app/view/dialogs/trainrun-and-section-dialog/trainrun-tab/trainrun-tab.component.html b/src/app/view/dialogs/trainrun-and-section-dialog/trainrun-tab/trainrun-tab.component.html index 975aacdd6..14220b84d 100644 --- a/src/app/view/dialogs/trainrun-and-section-dialog/trainrun-tab/trainrun-tab.component.html +++ b/src/app/view/dialogs/trainrun-and-section-dialog/trainrun-tab/trainrun-tab.component.html @@ -69,6 +69,14 @@
+ +
-
+
- -
+ + +
-
+
-
+
-
+
- -
+ + +
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+ +
+ +
+ +
+
+ + + +
+
-
+
(); - public get isTopTrainrunSectionInfoDisplayed(): boolean { - if (this.selectedTrainrunSection === null) { - return false; - } - const isTargetRightOrBottom = TrainrunsectionHelper.isTargetRightOrBottom( + public get isSymmetric(): boolean { + const firstTrainrunSection = this.trainrunService.getFirstNonStopTrainrunSection( this.selectedTrainrunSection, ); - return this.isRoundTrip() || isTargetRightOrBottom; - } - - public get isBottomTrainrunSectionInfoDisplayed(): boolean { - if (this.selectedTrainrunSection === null) { - return false; - } - const isTargetRightOrBottom = TrainrunsectionHelper.isTargetRightOrBottom( - this.selectedTrainrunSection, + const iterator = this.trainrunService.getNonStopIterator( + firstTrainrunSection.getSourceNode(), + firstTrainrunSection, ); - return this.isRoundTrip() || !isTargetRightOrBottom; + while (iterator.hasNext()) { + const nextPair = iterator.next(); + if (!nextPair.trainrunSection.isSymmetric()) { + return false; + } + } + return true; } constructor( private dataService: DataService, private filterService: FilterService, - private trainrunService: TrainrunService, + public trainrunService: TrainrunService, private trainrunSectionService: TrainrunSectionService, - private changeDetection: ChangeDetectorRef, + private changeDetectionRef: ChangeDetectorRef, public trainrunSectionTimesService: TrainrunSectionTimesService, private versionControlService: VersionControlService, + private symmetryToggleService: SymmetryToggleService, ) { this.trainrunSectionHelper = new TrainrunsectionHelper(this.trainrunService); @@ -137,6 +143,7 @@ export class TrainrunSectionTabComponent implements AfterViewInit, OnDestroy { .getTrainrun() .getTimeCategoryLinePatternRef(); this.trainrunSectionTimesService.setHighlightTravelTimeElement(false); + this.trainrunSectionTimesService.setHighlightBottomTravelTimeElement(false); this.numberOfStops = this.selectedTrainrunSection.getNumberOfStops(); this.trainrunSectionTimesService.applyOffsetAndTransformTimeStructure(); @@ -180,7 +187,7 @@ export class TrainrunSectionTabComponent implements AfterViewInit, OnDestroy { this.setFocusToUIElement(focusElement); this.updateAllValues(); - this.changeDetection.detectChanges(); + this.changeDetectionRef.detectChanges(); } getContentClassTag(): string { @@ -216,6 +223,9 @@ export class TrainrunSectionTabComponent implements AfterViewInit, OnDestroy { case LeftAndRightElement.TravelTime: this.setFocusAndSelectInputElement(this.travelTimeInputElement.nativeElement); break; + case LeftAndRightElement.BottomTravelTime: + this.setFocusAndSelectInputElement(this.bottomTravelTimeInputElement.nativeElement); + break; } } @@ -223,7 +233,7 @@ export class TrainrunSectionTabComponent implements AfterViewInit, OnDestroy { setTimeout(() => { element.focus(); element.select(); - }, 800); + }, 100); } getEdgeLineClassAttrString(layer: number) { @@ -251,12 +261,15 @@ export class TrainrunSectionTabComponent implements AfterViewInit, OnDestroy { ); } - getArrowTranslateAndRotate() { - if (this.isTopTrainrunSectionInfoDisplayed && !this.isBottomTrainrunSectionInfoDisplayed) { + getDirectionArrowTranslateAndRotate() { + if ( + !TrainrunsectionHelper.isLeftSideDisplayed(this.selectedTrainrunSection) && + TrainrunsectionHelper.isRightSideDisplayed(this.selectedTrainrunSection) + ) { return "translate(60, 16) rotate(0)"; } else if ( - !this.isTopTrainrunSectionInfoDisplayed && - this.isBottomTrainrunSectionInfoDisplayed + TrainrunsectionHelper.isLeftSideDisplayed(this.selectedTrainrunSection) && + !TrainrunsectionHelper.isRightSideDisplayed(this.selectedTrainrunSection) ) { return "translate(60, 16) rotate(180)"; } @@ -286,6 +299,7 @@ export class TrainrunSectionTabComponent implements AfterViewInit, OnDestroy { onInputNumberOfStopsElementButtonPlus() { this.numberOfStops += 1; this.trainrunSectionTimesService.setHighlightTravelTimeElement(false); + this.trainrunSectionTimesService.setHighlightBottomTravelTimeElement(false); this.onNumberOfStopsChanged(); } @@ -311,6 +325,60 @@ export class TrainrunSectionTabComponent implements AfterViewInit, OnDestroy { return "NumberOfStopsInputElement" + activeTag; } + getTravelTimeScssClass(): string { + if (this.isSymmetric) { + // If symmetric, travel time is displayed at the center + return ""; + } + // If not symmetric, travel time is displayed at the top + // (and bottom travel time at the bottom) + return "Top"; + } + + onLeftNodeSymmetryToggleChanged(symmetry: boolean) { + const originalState = this.trainrunSectionHelper.isLeftNextStopNodeSymmetric( + this.selectedTrainrunSection, + this.trainrunSectionTimesService.getNodesOrdered(), + ); + this.symmetryToggleService.onLeftNodeSymmetryToggleChanged( + this.selectedTrainrunSection, + this.trainrunSectionTimesService, + symmetry, + () => { + // Revert the toggle state + if (this.leftSymmetryToggle) { + this.leftSymmetryToggle.checked = !originalState; + } + this.changeDetectionRef.detectChanges(); + }, + ); + } + + onRightNodeSymmetryToggleChanged(symmetry: boolean) { + const originalState = this.trainrunSectionHelper.isRightNextStopNodeSymmetric( + this.selectedTrainrunSection, + this.trainrunSectionTimesService.getNodesOrdered(), + ); + this.symmetryToggleService.onRightNodeSymmetryToggleChanged( + this.selectedTrainrunSection, + this.trainrunSectionTimesService, + symmetry, + () => { + // Revert the toggle state + if (this.rightSymmetryToggle) { + this.rightSymmetryToggle.checked = !originalState; + } + this.changeDetectionRef.detectChanges(); + }, + ); + } + + isTrainrunSymmetric() { + return this.trainrunSectionService.isTrainrunSymmetric( + this.selectedTrainrunSection.getTrainrunId(), + ); + } + private resetOffsetAfterTrainrunChanged() { if (this.trainrunSectionTimesService.getOffsetTransformationActive()) { this.trainrunSectionTimesService.removeOffsetAndBackTransformTimeStructure(); @@ -337,8 +405,4 @@ export class TrainrunSectionTabComponent implements AfterViewInit, OnDestroy { this.trainrunSectionTimesService.setOffset(this.trainrunDialogParameter.offset); } } - - private isRoundTrip() { - return this.selectedTrainrunSection.getTrainrun().isRoundTrip(); - } } diff --git a/src/app/view/editor-filter-view/editor-filter-view.component.html b/src/app/view/editor-filter-view/editor-filter-view.component.html index 462f9c4af..7cc88aa54 100644 --- a/src/app/view/editor-filter-view/editor-filter-view.component.html +++ b/src/app/view/editor-filter-view/editor-filter-view.component.html @@ -54,20 +54,33 @@

{{ "app.view.editor-filter-view.filter" | translate }}<

-
+
{{ "app.view.editor-filter-view.symmetry" | translate }}
- + + + + + +
@@ -158,6 +171,14 @@

{{ "app.view.editor-filter-view.filter" | translate }}< {{ "app.view.editor-filter-view.display-direction-arrows" | translate }} + {{ "app.view.editor-filter-view.display-asymmetry-arrows" | translate }} + + {{ "app.view.editor-filter-view.display-backward-travel-times" | translate }} +


diff --git a/src/app/view/editor-filter-view/editor-filter-view.component.ts b/src/app/view/editor-filter-view/editor-filter-view.component.ts index 29b4e891f..c35e8a746 100644 --- a/src/app/view/editor-filter-view/editor-filter-view.component.ts +++ b/src/app/view/editor-filter-view/editor-filter-view.component.ts @@ -25,9 +25,11 @@ export class EditorFilterViewComponent implements OnInit, OnDestroy { filterNotes: boolean; filterAllNonStopNodes: boolean; filterDirectionArrows: boolean; + filterAsymmetryArrows: boolean; filterArrivalDepartureTime: boolean; filterShowNonStopTime: boolean; filterTravelTime: boolean; + filterBackwardTravelTime: boolean; filterTrainrunName: boolean; filterConnections: boolean; timeDisplayPrecision: number; @@ -68,9 +70,11 @@ export class EditorFilterViewComponent implements OnInit, OnDestroy { updateFilterData() { this.filterDirectionArrows = this.filterService.isFilterDirectionArrowsEnabled(); + this.filterAsymmetryArrows = this.filterService.isFilterAsymmetryArrowsEnabled(); this.filterArrivalDepartureTime = this.filterService.isFilterArrivalDepartureTimeEnabled(); this.filterShowNonStopTime = this.filterService.isFilterShowNonStopTimeEnabled(); this.filterTravelTime = this.filterService.isFilterTravelTimeEnabled(); + this.filterBackwardTravelTime = this.filterService.isFilterBackwardTravelTimeEnabled(); this.filterTrainrunName = this.filterService.isFilterTrainrunNameEnabled(); this.filterConnections = this.filterService.isFilterConnectionsEnabled(); this.filterNotes = !this.filterService.isFilterNotesEnabled(); @@ -210,6 +214,14 @@ export class EditorFilterViewComponent implements OnInit, OnDestroy { } } + filterAsymmetryArrowsChanged() { + if (this.filterAsymmetryArrows) { + this.filterService.enableFilterAsymmetryArrows(); + } else { + this.filterService.disableFilterAsymmetryArrows(); + } + } + filterArrivalDepartureTimeChanged() { if (this.filterArrivalDepartureTime) { this.filterService.enableFilterArrivalDepartureTime(); @@ -234,6 +246,14 @@ export class EditorFilterViewComponent implements OnInit, OnDestroy { } } + filterBackwardTravelTimeChanged() { + if (this.filterBackwardTravelTime) { + this.filterService.enableFilterBackwardTravelTime(); + } else { + this.filterService.disableFilterBackwardTravelTime(); + } + } + filterTrainrunNameChanged() { if (this.filterTrainrunName) { this.filterService.enableFilterTrainrunName(); @@ -293,6 +313,13 @@ export class EditorFilterViewComponent implements OnInit, OnDestroy { return "TrainrunDialog Direction "; } + getSymmetryClassname(symmetry: boolean): string { + if (this.filterService.isFilterSymmetryEnabled(symmetry)) { + return "TrainrunDialog Symmetry " + StaticDomTags.TAG_SELECTED; + } + return "TrainrunDialog Symmetry "; + } + hasOneWayTrainruns(): boolean { for (const trainrun of this.dataService.getTrainruns()) { if (!trainrun.isRoundTrip()) return true; @@ -300,6 +327,13 @@ export class EditorFilterViewComponent implements OnInit, OnDestroy { return false; } + isAsymmetryActive(): boolean { + for (const section of this.dataService.getTrainrunSections()) { + if (!section.isSymmetric()) return true; + } + return false; + } + getCategoryTooltip(trainrunCategory: TrainrunCategory): string { if (!this.filterService.isFilterTrainrunCategoryEnabled(trainrunCategory)) { return $localize`:@@app.view.editor-filter-view.show-trainrun-category:Show ${trainrunCategory.name}:trainrunCategory:`; @@ -335,6 +369,13 @@ export class EditorFilterViewComponent implements OnInit, OnDestroy { return $localize`:@@app.view.editor-filter-view.hide-direction:Hide ${directionTranslation}:direction:`; } + getSymmetryTooltip(symmetry: boolean): string { + if (!this.filterService.isFilterSymmetryEnabled(symmetry)) { + return $localize`:@@app.view.editor-filter-view.show-asymmetric-trainruns:Show asymmetric trainruns`; + } + return $localize`:@@app.view.editor-filter-view.hide-asymmetric-trainruns:Hide asymmetric trainruns`; + } + makeCategoryButtonLabel(trainrunCategory: TrainrunCategory): string { const label = trainrunCategory.shortName.toUpperCase(); if (label.length > 4) { @@ -359,6 +400,14 @@ export class EditorFilterViewComponent implements OnInit, OnDestroy { } } + makeSymmetryButtonLabel(symmetry: boolean): string { + if (symmetry) { + return $localize`:@@app.view.editor-filter-view.symmetric-short:Sym.`; + } else { + return $localize`:@@app.view.editor-filter-view.asymmetric-short:Asym.`; + } + } + onCategoryChanged(trainrunCategory: TrainrunCategory) { if (!this.filterService.isFilterTrainrunCategoryEnabled(trainrunCategory)) { this.filterService.enableFilterTrainrunCategory(trainrunCategory); @@ -383,6 +432,14 @@ export class EditorFilterViewComponent implements OnInit, OnDestroy { } } + onSymmetryChanged(symmetry: boolean) { + if (!this.filterService.isFilterSymmetryEnabled(symmetry)) { + this.filterService.enableFilterSymmetry(symmetry); + } else { + this.filterService.disableFilterSymmetry(symmetry); + } + } + isFilterFunctionOrEnabled(labelGroupObject: LabelGroup): boolean { return labelGroupObject.getLogicalFilterOperator() === LogicalFilterOperator.OR; } @@ -427,6 +484,7 @@ export class EditorFilterViewComponent implements OnInit, OnDestroy { this.filterService.resetFilterTrainrunFrequency(); this.filterService.resetFilterTrainrunTimeCategory(); this.filterService.resetFilterDirection(); + this.filterService.resetFilterSymmetry(); } onResetNodeFilter() { @@ -445,14 +503,18 @@ export class EditorFilterViewComponent implements OnInit, OnDestroy { this.onResetNodeFilter(); this.onResetNoteFilter(); this.filterService.enableFilterDirectionArrows(); + this.filterService.enableFilterAsymmetryArrows(); this.filterService.enableFilterArrivalDepartureTime(); this.filterService.enableFilterTravelTime(); + this.filterService.enableFilterBackwardTravelTime(); this.filterService.enableFilterTrainrunName(); this.filterService.enableFilterShowNonStopTime(); this.filterService.enableFilterConnections(); this.filterDirectionArrows = this.filterService.isFilterDirectionArrowsEnabled(); + this.filterAsymmetryArrows = this.filterService.isFilterAsymmetryArrowsEnabled(); this.filterArrivalDepartureTime = this.filterService.isFilterArrivalDepartureTimeEnabled(); this.filterTravelTime = this.filterService.isFilterTravelTimeEnabled(); + this.filterBackwardTravelTime = this.filterService.isFilterBackwardTravelTimeEnabled(); this.filterTrainrunName = this.filterService.isFilterTrainrunNameEnabled(); this.filterConnections = this.filterService.isFilterConnectionsEnabled(); this.filterShowNonStopTime = this.filterService.isFilterShowNonStopTimeEnabled(); diff --git a/src/app/view/editor-main-view/data-views/data.view.spec.ts b/src/app/view/editor-main-view/data-views/data.view.spec.ts index 4d3579884..736dce26a 100644 --- a/src/app/view/editor-main-view/data-views/data.view.spec.ts +++ b/src/app/view/editor-main-view/data-views/data.view.spec.ts @@ -226,9 +226,11 @@ describe("Editor-DataView", () => { false, false, false, + false, + false, ); expect(cvo1.key).toBe( - "#3@1234_false_0_39_49_1_21_39_0_39_141_39_0_39_0_20_0_S_20_7/24_4_1_0_S_20_7/24_20_0_round_trip_false_false_false_false_false_false_false_false_false_true_true_true_false_false_true_true_true_0_false_2_true_true_true_1_false_true_true_0_false_true_true(130,80)(194,80)(254,80)(318,80)", + "#3@1234_false_0_39_49_39_undefined_1_21_39_0_39_141_39_0_39_0_20_0_S_20_7/24_4_1_0_S_20_7/24_20_0_round_trip_false_false_false_false_false_false_false_false_false_false_false_true_true_true_false_false_true_true_true_0_false_2_true_true_true_1_false_true_true_0_false_true_true_0_false_true_true_1_false_true_true_2_true_true_true(130,80)(194,80)(254,80)(318,80)", ); }); diff --git a/src/app/view/editor-main-view/data-views/editor.view.ts b/src/app/view/editor-main-view/data-views/editor.view.ts index 3ec5b1835..a36cb9632 100644 --- a/src/app/view/editor-main-view/data-views/editor.view.ts +++ b/src/app/view/editor-main-view/data-views/editor.view.ts @@ -67,6 +67,8 @@ export class EditorView implements SVGMouseControllerObserver { getSelectedTrainrun = null; getCumulativeTravelTime = null; getCumulativeTravelTimeAndNodePath = null; + getCumulativeBackwardTravelTime = null; + getCumulativeBackwardTravelTimeAndNodePath = null; unselectAllTrainruns = null; isAnyTrainSelected = null; getConnectedTrainrunIds = null; @@ -76,8 +78,10 @@ export class EditorView implements SVGMouseControllerObserver { combineTwoTrainruns = null; getNodeFromConnection = null; isFilterTravelTimeEnabled = null; + isFilterBackwardTravelTimeEnabled = null; isFilterTrainrunNameEnabled = null; isFilterDirectionArrowsEnabled = null; + isFilterAsymmetryArrowsEnabled = null; isFilterArrivalDepartureTimeEnabled = null; isFilterShowNonStopTimeEnabled = null; isFilterTrainrunCategoryEnabled = null; @@ -240,10 +244,18 @@ export class EditorView implements SVGMouseControllerObserver { this.getCumulativeTravelTime = callback; } + bindGetCumulativeBackwardTravelTime(callback) { + this.getCumulativeBackwardTravelTime = callback; + } + bindGetCumulativeTravelTimeAndNodePath(callback) { this.getCumulativeTravelTimeAndNodePath = callback; } + bindGetCumulativeBackwardTravelTimeAndNodePath(callback) { + this.getCumulativeBackwardTravelTimeAndNodePath = callback; + } + bindUnselectAllTrainruns(callback) { this.unselectAllTrainruns = callback; } @@ -280,6 +292,10 @@ export class EditorView implements SVGMouseControllerObserver { this.isFilterTravelTimeEnabled = callback; } + bindIsFilterBackwardTravelTimeEnabled(callback) { + this.isFilterBackwardTravelTimeEnabled = callback; + } + bindIsfilterTrainrunNameEnabled(callback) { this.isFilterTrainrunNameEnabled = callback; } @@ -288,6 +304,10 @@ export class EditorView implements SVGMouseControllerObserver { this.isFilterDirectionArrowsEnabled = callback; } + bindIsFilterAsymmetryArrowsEnabled(callback) { + this.isFilterAsymmetryArrowsEnabled = callback; + } + bindIsfilterArrivalDepartureTimeEnabled(callback) { this.isFilterArrivalDepartureTimeEnabled = callback; } diff --git a/src/app/view/editor-main-view/data-views/trainrunSectionViewObject.ts b/src/app/view/editor-main-view/data-views/trainrunSectionViewObject.ts index 73e221407..cd7035623 100644 --- a/src/app/view/editor-main-view/data-views/trainrunSectionViewObject.ts +++ b/src/app/view/editor-main-view/data-views/trainrunSectionViewObject.ts @@ -12,9 +12,11 @@ export class TrainrunSectionViewObject { isMuted: boolean, hiddenTagSource: boolean, hiddenTagTarget: boolean, - hiddenTagTraveltime: boolean, + hiddenTagTravelTime: boolean, + hiddenTagBackwardTravelTime: boolean, hiddenTagTrainrunName: boolean, hiddenTagDirectionArrows: boolean, + hiddenTagAsymmetryArrows: boolean, ) { this.key = TrainrunSectionViewObject.generateKey( editorView, @@ -24,9 +26,11 @@ export class TrainrunSectionViewObject { isMuted, hiddenTagSource, hiddenTagTarget, - hiddenTagTraveltime, + hiddenTagTravelTime, + hiddenTagBackwardTravelTime, hiddenTagTrainrunName, hiddenTagDirectionArrows, + hiddenTagAsymmetryArrows, ); } @@ -38,13 +42,19 @@ export class TrainrunSectionViewObject { isMuted: boolean, hiddenTagSource: boolean, hiddenTagTarget: boolean, - hiddenTagTraveltime: boolean, + hiddenTagTravelTime: boolean, + hiddenTagBackwardTravelTime: boolean, hiddenTagTrainrunName: boolean, hiddenTagDirectionArrows: boolean, + hiddenTagAsymmetryArrows: boolean, ): string { const cumulativeTravelTimeData = editorView.getCumulativeTravelTimeAndNodePath(d); const cumulativeTravelTime = cumulativeTravelTimeData[cumulativeTravelTimeData.length - 1].sumTravelTime; + const cumulativeBackwardTravelTimeData = + editorView.getCumulativeBackwardTravelTimeAndNodePath(d); + const cumulativeBackwardTravelTime = + cumulativeBackwardTravelTimeData[cumulativeBackwardTravelTimeData.length - 1].sumTravelTime; let key = "#" + @@ -60,6 +70,10 @@ export class TrainrunSectionViewObject { "_" + cumulativeTravelTime + "_" + + d.getBackwardTravelTime() + + "_" + + cumulativeBackwardTravelTime + + "_" + editorView.getTimeDisplayPrecision() + "_" + d.getTargetDeparture() + @@ -118,12 +132,16 @@ export class TrainrunSectionViewObject { "_" + hiddenTagTarget + "_" + - hiddenTagTraveltime + + hiddenTagTravelTime + + "_" + + hiddenTagBackwardTravelTime + "_" + hiddenTagTrainrunName + "_" + hiddenTagDirectionArrows + "_" + + hiddenTagAsymmetryArrows + + "_" + editorView.isTemporaryDisableFilteringOfItemsInViewEnabled() + "_" + editorView.isFilterShowNonStopTimeEnabled() + @@ -153,6 +171,13 @@ export class TrainrunSectionViewObject { key += "_" + editorView.checkFilterNode(data.node); }); + cumulativeBackwardTravelTimeData.forEach((data) => { + key += "_" + data.node.getId(); + key += "_" + editorView.isJunctionNode(data.node); + key += "_" + editorView.checkFilterNonStopNode(data.node); + key += "_" + editorView.checkFilterNode(data.node); + }); + d.getPath().forEach((p) => { key += p.toString(); }); diff --git a/src/app/view/editor-main-view/data-views/trainrunsections.view.scss b/src/app/view/editor-main-view/data-views/trainrunsections.view.scss index 8a76b45f7..513ae8740 100644 --- a/src/app/view/editor-main-view/data-views/trainrunsections.view.scss +++ b/src/app/view/editor-main-view/data-views/trainrunsections.view.scss @@ -38,6 +38,11 @@ text-align: left; } +::ng-deep text.edge_text.TrainrunSectionBackwardTravelTime { + text-anchor: start; + text-align: left; +} + ::ng-deep text.edge_text.warning { stroke: $COLOR_Warning; fill: $COLOR_Warning; diff --git a/src/app/view/editor-main-view/data-views/trainrunsections.view.spec.ts b/src/app/view/editor-main-view/data-views/trainrunsections.view.spec.ts index b55dc3409..1d522377e 100644 --- a/src/app/view/editor-main-view/data-views/trainrunsections.view.spec.ts +++ b/src/app/view/editor-main-view/data-views/trainrunsections.view.spec.ts @@ -1241,48 +1241,56 @@ describe("TrainrunSection-View", () => { const v0 = TrainrunSectionsView.extractTravelTime( trainrunSectionService.getTrainrunSectionFromId(0), editorView, + false, ); expect(v0).toBe("10'"); const v1 = TrainrunSectionsView.extractTravelTime( trainrunSectionService.getTrainrunSectionFromId(1), editorView, + false, ); expect(v1).toBe("10'"); const v2 = TrainrunSectionsView.extractTravelTime( trainrunSectionService.getTrainrunSectionFromId(2), editorView, + false, ); expect(v2).toBe("20'"); const v3 = TrainrunSectionsView.extractTravelTime( trainrunSectionService.getTrainrunSectionFromId(3), editorView, + false, ); expect(v3).toBe("49' (39')"); const v4 = TrainrunSectionsView.extractTravelTime( trainrunSectionService.getTrainrunSectionFromId(4), editorView, + false, ); expect(v4).toBe("49' (10')"); const v5 = TrainrunSectionsView.extractTravelTime( trainrunSectionService.getTrainrunSectionFromId(5), editorView, + false, ); expect(v5).toBe("51'"); const v6 = TrainrunSectionsView.extractTravelTime( trainrunSectionService.getTrainrunSectionFromId(6), editorView, + false, ); expect(v6).toBe("10'"); const v7 = TrainrunSectionsView.extractTravelTime( trainrunSectionService.getTrainrunSectionFromId(7), editorView, + false, ); expect(v7).toBe("10'"); }); @@ -1296,7 +1304,7 @@ describe("TrainrunSection-View", () => { const t2 = n2.getTransition(ts.getId()); t1.setIsNonStopTransit(true); t2.setIsNonStopTransit(true); - const v0 = TrainrunSectionsView.extractTravelTime(ts, editorView); + const v0 = TrainrunSectionsView.extractTravelTime(ts, editorView, false); expect(v0).toBe("(10')"); }); diff --git a/src/app/view/editor-main-view/data-views/trainrunsections.view.ts b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts index 6b09c99b3..9e129d709 100644 --- a/src/app/view/editor-main-view/data-views/trainrunsections.view.ts +++ b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts @@ -160,6 +160,8 @@ export class TrainrunSectionsView { return trainrunSection.hasTargetArrivalWarning(); case TrainrunSectionText.TrainrunSectionTravelTime: return trainrunSection.hasTravelTimeWarning(); + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + return trainrunSection.hasBackwardTravelTimeWarning(); case TrainrunSectionText.TrainrunSectionName: default: return false; @@ -201,11 +203,16 @@ export class TrainrunSectionsView { ": " + trainrunSection.getTravelTimeWarning().description ); + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + return ( + trainrunSection.getBackwardTravelTimeWarning().title + + ": " + + trainrunSection.getBackwardTravelTimeWarning().description + ); case TrainrunSectionText.TrainrunSectionName: default: return ""; } - return ""; } static getTime(trainrunSection: TrainrunSection, textElement: TrainrunSectionText): number { @@ -220,6 +227,8 @@ export class TrainrunSectionsView { return trainrunSection.getTargetArrival(); case TrainrunSectionText.TrainrunSectionTravelTime: return trainrunSection.getTravelTime(); + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + return trainrunSection.getBackwardTravelTime(); default: return 0; } @@ -240,6 +249,8 @@ export class TrainrunSectionsView { return trainrunSection.getTargetArrivalFormattedDisplayText(); case TrainrunSectionText.TrainrunSectionTravelTime: return trainrunSection.getTravelTimeFormattedDisplayText(); + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + return trainrunSection.getBackwardTravelTimeFormattedDisplayText(); default: return undefined; } @@ -260,6 +271,8 @@ export class TrainrunSectionsView { return trainrunSection.getTargetArrivalFormattedDisplayTextWidth(); case TrainrunSectionText.TrainrunSectionTravelTime: return trainrunSection.getTravelTimeFormattedDisplayTextWidth(); + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + return trainrunSection.getBackwardTravelTimeFormattedDisplayTextWidth(); default: return undefined; } @@ -318,6 +331,7 @@ export class TrainrunSectionsView { case TrainrunSectionText.TargetArrival: return trainrunSection.getTextPositionX(textElement); case TrainrunSectionText.TrainrunSectionTravelTime: + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: return RASTERING_BASIC_GRID_SIZE / 4; case TrainrunSectionText.TrainrunSectionName: return -RASTERING_BASIC_GRID_SIZE / 4; @@ -333,9 +347,6 @@ export class TrainrunSectionsView { case TrainrunSectionText.TargetDeparture: case TrainrunSectionText.TargetArrival: return trainrunSection.getTextPositionY(textElement); - case TrainrunSectionText.TrainrunSectionTravelTime: - case TrainrunSectionText.TrainrunSectionName: - return 0.0; default: return 0; } @@ -349,6 +360,7 @@ export class TrainrunSectionsView { case TrainrunSectionText.TargetArrival: return "dy"; case TrainrunSectionText.TrainrunSectionTravelTime: + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: case TrainrunSectionText.TrainrunSectionName: return "transform"; default: @@ -367,6 +379,7 @@ export class TrainrunSectionsView { case TrainrunSectionText.TargetArrival: return 1.5; case TrainrunSectionText.TrainrunSectionTravelTime: + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: case TrainrunSectionText.TrainrunSectionName: return TrainrunSectionsView.translateAndRotateText(trainrunSection, textElement); default: @@ -438,6 +451,7 @@ export class TrainrunSectionsView { ) ); case TrainrunSectionText.TrainrunSectionTravelTime: + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: return timeTag; case TrainrunSectionText.TrainrunSectionName: return ( @@ -454,8 +468,9 @@ export class TrainrunSectionsView { trainrunSection.getTrainrun().getCategoryColorRef(), ) ); + default: + return undefined; } - return undefined; } static formatTime(value: number, precision: number): number { @@ -476,21 +491,34 @@ export class TrainrunSectionsView { ); } - static extractTravelTime(trainrunSection: TrainrunSection, editorView: EditorView): string { - const cumTravelTimeData = editorView.getCumulativeTravelTimeAndNodePath(trainrunSection); - const cumulativeTravelTime = cumTravelTimeData[cumTravelTimeData.length - 1].sumTravelTime; + static extractTravelTime( + trainrunSection: TrainrunSection, + editorView: EditorView, + isBackwardTravel: boolean, + ): string { + // invert travel times display since departures and arrivals + // are also inverted if target is left or top + isBackwardTravel = TrainrunsectionHelper.isTargetRightOrBottom(trainrunSection) + ? isBackwardTravel + : !isBackwardTravel; + const travelTime = isBackwardTravel + ? trainrunSection.getBackwardTravelTime() + : trainrunSection.getTravelTime(); + const cumTravelTimeData = isBackwardTravel + ? editorView.getCumulativeBackwardTravelTimeAndNodePath(trainrunSection) + : editorView.getCumulativeTravelTimeAndNodePath(trainrunSection); + const cumulativeTravelTime = isBackwardTravel + ? cumTravelTimeData[cumTravelTimeData.length - 1].sumBackwardTravelTime + : cumTravelTimeData[cumTravelTimeData.length - 1].sumTravelTime; if ( trainrunSection.getTrainrun().selected() === true || editorView.isFilterShowNonStopTimeEnabled() || editorView.isTemporaryDisableFilteringOfItemsInViewEnabled() ) { - if (cumulativeTravelTime === trainrunSection.getTravelTime()) { + if (cumulativeTravelTime === travelTime) { // default case return ( - TrainrunSectionsView.formatTime( - trainrunSection.getTravelTime(), - editorView.getTimeDisplayPrecision(), - ) + "'" + TrainrunSectionsView.formatTime(travelTime, editorView.getTimeDisplayPrecision()) + "'" ); } else { // special case - with non stops @@ -631,7 +659,7 @@ export class TrainrunSectionsView { } if (TrainrunSectionsView.isBothSideNonStop(trainrunSection)) { - return "(" + TrainrunSectionsView.formatTime(trainrunSection.getTravelTime(), 1) + "')"; + return "(" + TrainrunSectionsView.formatTime(travelTime, 1) + "')"; } // default case for non stops return ( @@ -640,7 +668,7 @@ export class TrainrunSectionsView { editorView.getTimeDisplayPrecision(), ) + "' (" + - TrainrunSectionsView.formatTime(trainrunSection.getTravelTime(), 1) + + TrainrunSectionsView.formatTime(travelTime, 1) + "')" ); } @@ -751,17 +779,24 @@ export class TrainrunSectionsView { editorView.getTimeDisplayPrecision(), ); } - case TrainrunSectionText.TrainrunSectionTravelTime: { + case TrainrunSectionText.TrainrunSectionTravelTime: + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: { const data = TrainrunSectionsView.getFormattedDisplayText(trainrunSection, textElement); if (data !== undefined) { + console.log("textElement", textElement, "data", data); return data; } - return TrainrunSectionsView.extractTravelTime(trainrunSection, editorView); + return TrainrunSectionsView.extractTravelTime( + trainrunSection, + editorView, + textElement === TrainrunSectionText.TrainrunSectionBackwardTravelTime, + ); } case TrainrunSectionText.TrainrunSectionName: return TrainrunSectionsView.extractTrainrunName(trainrunSection); + default: + return undefined; } - return undefined; } static getTrainrunSectionValueTextWidth( @@ -773,7 +808,8 @@ export class TrainrunSectionsView { case TrainrunSectionText.SourceArrival: case TrainrunSectionText.TargetDeparture: case TrainrunSectionText.TargetArrival: - case TrainrunSectionText.TrainrunSectionTravelTime: { + case TrainrunSectionText.TrainrunSectionTravelTime: + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: { const data = TrainrunSectionsView.getFormattedDisplayTextWidth( trainrunSection, textElement, @@ -783,8 +819,9 @@ export class TrainrunSectionsView { } return TRAINRUN_SECTION_TEXT_AREA_WIDTH; } + default: + return TRAINRUN_SECTION_TEXT_AREA_WIDTH; } - return TRAINRUN_SECTION_TEXT_AREA_WIDTH; } static getTrainrunSectionValueHtmlStyle( @@ -802,10 +839,11 @@ export class TrainrunSectionsView { return trainrunSection.getTargetArrivalFormattedDisplayHtmlStyle(); case TrainrunSectionText.TrainrunSectionTravelTime: return trainrunSection.getTravelTimeFormattedDisplayHtmlStyle(); + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + return trainrunSection.getBackwardTravelTimeFormattedDisplayHtmlStyle(); default: return undefined; } - return undefined; } static getTrainrunSectionNextAndDestinationNodeToShow( @@ -845,6 +883,8 @@ export class TrainrunSectionsView { return trainrunSection.getTargetArrivalFormatterColorRef(); case TrainrunSectionText.TrainrunSectionTravelTime: return trainrunSection.getTravelTimeFormatterColorRef(); + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + return trainrunSection.getBackwardTravelTimeFormatterColorRef(); default: return undefined; } @@ -899,6 +939,17 @@ export class TrainrunSectionsView { !trainrunSection.getTrainrun().selected() && TrainrunSectionsView.isBothSideNonStop(trainrunSection) ); + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + if (!trainrunSection.getTrainrun().isRoundTrip() || trainrunSection.isSymmetric()) { + return true; + } + if (this.editorView.isFilterShowNonStopTimeEnabled()) { + return false; + } + return ( + !trainrunSection.getTrainrun().selected() && + TrainrunSectionsView.isBothSideNonStop(trainrunSection) + ); case TrainrunSectionText.TrainrunSectionName: { if (!this.editorView.isFilterTrainrunNameEnabled()) { @@ -1005,7 +1056,8 @@ export class TrainrunSectionsView { translateAndRotateArrow( trainrunSection: TrainrunSection, - arrowType: "BEGINNING_ARROW" | "ENDING_ARROW", + arrowLocation: "BEGINNING_ARROW" | "ENDING_ARROW", + arrowType: "DIRECTION_ARROW" | "SYMMETRY_ARROW", ) { const positions = trainrunSection.getPath(); const isTargetRightOrBottom = TrainrunsectionHelper.isTargetRightOrBottom(trainrunSection); @@ -1024,9 +1076,14 @@ export class TrainrunSectionsView { // Set arrow offset values : positions[1] and positions[2] are // the 2 intermediate points where the sections change direction - const arrowOffset = isTargetRightOrBottom ? [-44, 20] : [44, -20]; + let arrowOffset: [number, number]; + if (isTargetRightOrBottom) { + arrowOffset = arrowType === "DIRECTION_ARROW" ? [-44, 20] : [-32, 32]; + } else { + arrowOffset = arrowType === "DIRECTION_ARROW" ? [44, -20] : [32, -32]; + } let x, y: number; - if (arrowType === "BEGINNING_ARROW") { + if (arrowLocation === "BEGINNING_ARROW") { x = positions[1].getX() + (xDiff === 0 ? 0 : arrowOffset[0]); y = positions[1].getY() + (xDiff === 0 ? arrowOffset[0] : 0); } else { @@ -1060,7 +1117,7 @@ export class TrainrunSectionsView { return d.trainrunSection.getTrainrun().isRoundTrip() ? "" : "M-4,-5L2,0L-4,5Z"; }) .attr("transform", (d: TrainrunSectionViewObject) => - this.translateAndRotateArrow(d.trainrunSection, arrowType), + this.translateAndRotateArrow(d.trainrunSection, arrowType, "DIRECTION_ARROW"), ) .attr( "class", @@ -1106,6 +1163,87 @@ export class TrainrunSectionsView { }); } + createAsymmetryArrows( + groupLinesEnter: d3.Selection, + selectedTrainrun: Trainrun, + connectedTrainIds: any, + enableEvents = true, + ) { + (["BEGINNING_ARROW", "ENDING_ARROW"] as const).forEach((arrowType) => { + groupLinesEnter + .append(StaticDomTags.EDGE_LINE_ARROW_SVG) + .attr(StaticDomTags.TAG_HIDDEN, (d: TrainrunSectionViewObject) => + // Hide arrow + // - if asymmetry arrows are filtered out or + // - if the node on this side is filtered out + // - if the node on this side is non-stop + !this.editorView.isFilterAsymmetryArrowsEnabled() || + !this.filterTrainrunsectionAtNode(d.trainrunSection, arrowType === "BEGINNING_ARROW") || + TrainrunSectionsView.getNode( + d.trainrunSection, + arrowType === "BEGINNING_ARROW", + ).isNonStop(d.trainrunSection) + ? "" + : null, + ) + .attr("d", (d: TrainrunSectionViewObject) => { + if (arrowType === "BEGINNING_ARROW") { + return d.trainrunSection.isSourceSymmetricOrTimesSymmetric() + ? "" + : "M-1,-6 V0 H-8 L1,6 V0 H8 Z"; + } else { + return d.trainrunSection.isTargetSymmetricOrTimesSymmetric() + ? "" + : "M-1,-6 V0 H-8 L1,6 V0 H8 Z"; + } + }) + .attr("transform", (d: TrainrunSectionViewObject) => + this.translateAndRotateArrow(d.trainrunSection, arrowType, "SYMMETRY_ARROW"), + ) + .attr( + "class", + (d: TrainrunSectionViewObject) => + StaticDomTags.EDGE_LINE_ARROW_CLASS + + TrainrunSectionsView.createTrainrunSectionFrequencyClassAttribute( + d.trainrunSection, + selectedTrainrun, + connectedTrainIds, + ), + ) + .classed( + StaticDomTags.TAG_HIDDEN, + (d: TrainrunSectionViewObject) => + !this.editorView.isTemporaryDisableFilteringOfItemsInViewEnabled() && + (!this.editorView.isFilterAsymmetryArrowsEnabled() || + !this.filterTrainrunsectionAtNode( + d.trainrunSection, + arrowType === "BEGINNING_ARROW", + )), + ) + .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) + .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => + d.trainrunSection.getTrainrun().getId(), + ) + .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => + d.trainrunSection.getTrainrun().selected(), + ) + .classed(StaticDomTags.TAG_LINE_ARROW_EDITOR, true) + .classed(StaticDomTags.TAG_MUTED, (d: TrainrunSectionViewObject) => + TrainrunSectionsView.isMuted(d.trainrunSection, selectedTrainrun, connectedTrainIds), + ) + .classed(StaticDomTags.TAG_EVENT_DISABLED, !enableEvents) + .on("mouseup", (d: TrainrunSectionViewObject, i, a) => { + this.onTrainrunAsymmetryArrowMouseUp(d.trainrunSection, a[i]); + }) + .on("mouseover", (d: TrainrunSectionViewObject, i, a) => { + this.onTrainrunSectionMouseoverPath(d.trainrunSection, a[i]); + }) + .on("mouseout", (d: TrainrunSectionViewObject, i, a) => { + this.onTrainrunSectionMouseoutPath(d.trainrunSection, a[i]); + }); + }); + } + createTrainrunSection( groupEnter: d3.Selector, classRef, @@ -1347,7 +1485,8 @@ export class TrainrunSectionsView { ) { const isDefaultText = textElement === TrainrunSectionText.TrainrunSectionName || - textElement === TrainrunSectionText.TrainrunSectionTravelTime; + textElement === TrainrunSectionText.TrainrunSectionTravelTime || + textElement === TrainrunSectionText.TrainrunSectionBackwardTravelTime; const atSource = textElement === TrainrunSectionText.SourceArrival || textElement === TrainrunSectionText.SourceDeparture; @@ -1667,9 +1806,11 @@ export class TrainrunSectionsView { this.getHiddenTagForTime(d, TrainrunSectionText.SourceDeparture), this.getHiddenTagForTime(d, TrainrunSectionText.TargetDeparture), this.getHiddenTagForTime(d, TrainrunSectionText.TrainrunSectionTravelTime), + this.getHiddenTagForTime(d, TrainrunSectionText.TrainrunSectionBackwardTravelTime), this.getHiddenTagForTime(d, TrainrunSectionText.TrainrunSectionName), !this.editorView.isTemporaryDisableFilteringOfItemsInViewEnabled() && !this.editorView.isFilterDirectionArrowsEnabled(), + !this.editorView.isFilterAsymmetryArrowsEnabled(), ), ); }); @@ -1840,6 +1981,17 @@ export class TrainrunSectionsView { this.editorView.showTrainrunOneWayInformation(trainrunSection, clickPosition); } + onTrainrunAsymmetryArrowMouseUp(trainrunSection: TrainrunSection, domObj: any) { + d3.event.stopPropagation(); + const rect: DOMRect = d3.select(domObj).node().getBoundingClientRect(); + const clickPosition = new Vec2D(rect.x + rect.width / 2, rect.y + rect.height / 2); + + if (this.editorView.editorMode === EditorMode.Analytics) { + return; + } + this.editorView.showTrainrunSectionInformation(trainrunSection, clickPosition); + } + onTrainrunSectionMouseUp(trainrunSection: TrainrunSection, domObj: any) { d3.event.stopPropagation(); const ts = this.editorView.getSelectedTrainrun(); @@ -1964,6 +2116,8 @@ export class TrainrunSectionsView { node = trainrunSection.getTargetNode(); minute = trainrunSection.getTargetDeparture(); break; + default: + break; } this.editorView.unselectAllNodes(); this.editorView.calculateShortestDistanceNodesFromStartingTrainrunSection( @@ -1983,11 +2137,15 @@ export class TrainrunSectionsView { case TrainrunSectionText.TargetDeparture: case TrainrunSectionText.TargetArrival: case TrainrunSectionText.TrainrunSectionTravelTime: + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: case TrainrunSectionText.TrainrunSectionNumberOfStops: this.editorView.showTrainrunSectionInformation(trainrunSection, clickPos, textElement); break; case TrainrunSectionText.TrainrunSectionName: this.editorView.showTrainrunInformation(trainrunSection, clickPos); + break; + default: + break; } } @@ -2394,6 +2552,13 @@ export class TrainrunSectionsView { connectedTrainIds, TrainrunSectionText.TrainrunSectionTravelTime, ); + this.createTrainrunSectionElement( + // LevelOfDetail.LEVEL3 + groupLabels, + selectedTrainrun, + connectedTrainIds, + TrainrunSectionText.TrainrunSectionBackwardTravelTime, + ); } if ( @@ -2473,6 +2638,7 @@ export class TrainrunSectionsView { ); this.createDirectionArrows(groupLines, selectedTrainrun, connectedTrainIds, enableEvents); + this.createAsymmetryArrows(groupLines, selectedTrainrun, connectedTrainIds, enableEvents); } private createSingleStopElement( diff --git a/src/app/view/editor-main-view/editor-main-view.component.ts b/src/app/view/editor-main-view/editor-main-view.component.ts index cdf9983d6..4ec266ecf 100644 --- a/src/app/view/editor-main-view/editor-main-view.component.ts +++ b/src/app/view/editor-main-view/editor-main-view.component.ts @@ -245,6 +245,15 @@ export class EditorMainViewComponent implements AfterViewInit, OnDestroy { this.trainrunService.getCumulativeTravelTimeAndNodePath(trainrunSection), ); + this.editorView.bindGetCumulativeBackwardTravelTime((trainrunSection: TrainrunSection) => + this.trainrunService.getCumulativeBackwardTravelTime(trainrunSection), + ); + + this.editorView.bindGetCumulativeBackwardTravelTimeAndNodePath( + (trainrunSection: TrainrunSection) => + this.trainrunService.getCumulativeBackwardTravelTimeAndNodePath(trainrunSection), + ); + this.editorView.bindAddConnectionToNode( (node: Node, trainrunSectionFrom: TrainrunSection, trainrunSectionTo: TrainrunSection) => { this.nodeService.addConnectionToNode( @@ -348,6 +357,10 @@ export class EditorMainViewComponent implements AfterViewInit, OnDestroy { this.filterService.isFilterTravelTimeEnabled(), ); + this.editorView.bindIsFilterBackwardTravelTimeEnabled(() => + this.filterService.isFilterBackwardTravelTimeEnabled(), + ); + this.editorView.bindIsfilterTrainrunNameEnabled(() => this.filterService.isFilterTrainrunNameEnabled(), ); @@ -356,6 +369,10 @@ export class EditorMainViewComponent implements AfterViewInit, OnDestroy { this.filterService.isFilterDirectionArrowsEnabled(), ); + this.editorView.bindIsFilterAsymmetryArrowsEnabled(() => + this.filterService.isFilterAsymmetryArrowsEnabled(), + ); + this.editorView.bindIsfilterArrivalDepartureTimeEnabled(() => this.filterService.isFilterArrivalDepartureTimeEnabled(), ); diff --git a/src/app/view/filter-main-side-view/filter-main-side-view.component.html b/src/app/view/filter-main-side-view/filter-main-side-view.component.html index 8d08ba4f5..d5aed2d1b 100644 --- a/src/app/view/filter-main-side-view/filter-main-side-view.component.html +++ b/src/app/view/filter-main-side-view/filter-main-side-view.component.html @@ -34,6 +34,7 @@ +
diff --git a/src/app/view/toggle-switch-button/toggle-switch-button.component.html b/src/app/view/toggle-switch-button/toggle-switch-button.component.html index e421e0409..971285a7b 100644 --- a/src/app/view/toggle-switch-button/toggle-switch-button.component.html +++ b/src/app/view/toggle-switch-button/toggle-switch-button.component.html @@ -1,7 +1,11 @@ -
- {{ - labelFalse - }} +
+ {{ labelFalse }} - {{ - labelTrue - }} + {{ labelTrue }}
diff --git a/src/app/view/toggle-switch-button/toggle-switch-button.component.scss b/src/app/view/toggle-switch-button/toggle-switch-button.component.scss index 01befb76f..06f8241a7 100644 --- a/src/app/view/toggle-switch-button/toggle-switch-button.component.scss +++ b/src/app/view/toggle-switch-button/toggle-switch-button.component.scss @@ -101,4 +101,9 @@ input.non-default + .slider:before { background: $COLOR_SBB_RED; } + + &.disabled { + opacity: 0.6; + pointer-events: none; + } } diff --git a/src/app/view/toggle-switch-button/toggle-switch-button.component.ts b/src/app/view/toggle-switch-button/toggle-switch-button.component.ts index f23d82f09..2bed08623 100644 --- a/src/app/view/toggle-switch-button/toggle-switch-button.component.ts +++ b/src/app/view/toggle-switch-button/toggle-switch-button.component.ts @@ -8,11 +8,12 @@ import {Component, EventEmitter, Input, Output} from "@angular/core"; export class ToggleSwitchButtonComponent { @Output() checkedChanged = new EventEmitter(); @Input() checked = false; - @Input() labelFalse: string = ""; - @Input() labelTrue: string = ""; - @Input() tagNonDefault: boolean = false; + @Input() labelFalse = ""; + @Input() labelTrue = ""; + @Input() tagNonDefault = false; + @Input() disabled = false; - onToggle(check: boolean) { + onToggle(check: boolean): void { if (!this.labelTrue || !this.labelFalse) { this.onChange(!this.checked); return; @@ -20,7 +21,7 @@ export class ToggleSwitchButtonComponent { this.onChange(check); } - onChange(isChecked: boolean) { + onChange(isChecked: boolean): void { if (this.checked !== isChecked) { this.checked = isChecked; this.checkedChanged.next(this.checked); diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index 0f4287bd0..48fc43c4f 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -60,7 +60,7 @@ "node": { "transit-modified": { "title": "Durchfahrt geändert", - "description": "Zeiten können nicht angepasst werden, beidseitger Lock gefunden" + "description": "Zeiten können nicht angepasst werden, die Startzeit ist fest vorgegeben." } }, "trainrunsection": { @@ -95,6 +95,10 @@ "title": "Quelle Ankunft Warnung", "description": "Quellankunftszeit kann nicht erreicht werden" }, + "travel-times-not-equal": { + "title": "Reisezeiten nicht symmetrisch", + "description": "Reisezeiten sind nicht kompatibel mit Rückreise-Zeitplänen" + }, "travel-time-less-than-1": { "title": "Reisezeit weniger als 1", "description": "Die Reisezeit muss größer oder gleich 1 sein." @@ -116,6 +120,14 @@ "target-departure-not-reacheable": { "title": "Ziel Abfahrt Warnung", "description": "Zielabfahrtszeit kann nicht erreicht werden" + }, + "source-departure-not-reacheable-asymmetry": { + "title": "Quelle Abfahrt Warnung", + "description": "Quellabfahrtszeit kann nicht erreicht werden aufgrund asymmetrischer Reisezeiten" + }, + "target-departure-not-reacheable-asymmetry": { + "title": "Ziel Abfahrt Warnung", + "description": "Zielabfahrtszeit kann nicht erreicht werden aufgrund asymmetrischer Reisezeiten" } } } @@ -267,6 +279,11 @@ "position": "Position", "close": "Schliessen" }, + "symmetry-dialog": { + "apply-symmetry": "Symmetrie anwenden", + "cancel": "Abbrechen", + "selection": "Symmetrie-Auswahl" + }, "trainrun-and-section-dialog": { "filterableLabels": "Filterbare Labels", "trainrun-filter-tab": { @@ -355,6 +372,8 @@ "round-trips": "Rundreisen", "one-ways": "Einzelfahrten", "display-direction-arrows": "Zugfahrt-Richtungs-Pfeile anzeigen", + "display-asymmetry-arrows": "Zugfahrt-Knoten-Asymmetrie-Pfeile anzeigen", + "display-backward-travel-times": "Rückwärtsfahrzeiten anzeigen (Asymmetrie)", "times": "Zeiten", "decimal-displayed": "Anzahl Nachkommastellenanzeigen", "display-arrival-departure-times": "Abfahrt- und Ankuftszeiten anzeigen", @@ -383,6 +402,10 @@ "symmetry": "Symmetrie", "show-direction": "{$direction} einblenden", "hide-direction": "{$direction} ausblenden", + "show-asymmetric-trainruns": "Asymmetrische Zugfahrten einblenden", + "hide-asymmetric-trainruns": "Asymmetrische Zugfahrten ausblenden", + "symmetric": "Sym.", + "asymmetric": "Asym.", "filterable-label-filter": { "no-labels-available": "Keine Labels vorhanden", "or": "Oder", diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 12223bbc5..f01b1150e 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -60,7 +60,7 @@ "node": { "transit-modified": { "title": "Transition changed", - "description": "Times cannot be adjusted, lock found on both sides" + "description": "Times cannot be adjusted, the departure time is locked." } }, "trainrunsection": { @@ -95,6 +95,10 @@ "title": "Source Arrival Warning", "description": "Source arrival time cannot be reached" }, + "travel-times-not-equal": { + "title": "Travel Times not equal", + "description": "Travel times are not compatible with return trip time schedules" + }, "travel-time-less-than-1": { "title": "Travel Time less than 1", "description": "Travel time must be greater than or equal to 1" @@ -116,6 +120,14 @@ "target-departure-not-reacheable": { "title": "Target Departure Warning", "description": "Target departure time cannot be reached" + }, + "source-departure-not-reacheable-asymmetry": { + "title": "Source Departure Warning", + "description": "Source departure time cannot be reached due to asymmetric travel times" + }, + "target-departure-not-reacheable-asymmetry": { + "title": "Target Departure Warning", + "description": "Target departure time cannot be reached due to asymmetric travel times" } } } @@ -267,6 +279,11 @@ "position": "Position", "close": "Close" }, + "symmetry-dialog": { + "apply-symmetry": "Apply symmetry", + "cancel": "Cancel", + "selection": "Symmetry selection" + }, "trainrun-and-section-dialog": { "filterableLabels": "Filterable Labels", "trainrun-filter-tab": { @@ -355,6 +372,8 @@ "round-trips": "round trips", "one-ways": "one-ways", "display-direction-arrows": "Display trainrun direction arrows", + "display-asymmetry-arrows": "Display trainrun section asymmetry arrows at nodes", + "display-backward-travel-times": "Display backward travel times (asymmetry)", "times": "Times", "decimal-displayed": "Number of decimal place displayed", "display-arrival-departure-times": "Display departure and arrival times", @@ -383,6 +402,10 @@ "symmetry": "Symmetry", "show-direction": "Show {$direction}", "hide-direction": "Hide {$direction}", + "show-asymmetric-trainruns": "Show asymmetric trainruns", + "hide-asymmetric-trainruns": "Hide asymmetric trainruns", + "symmetric-short": "Sym.", + "asymmetric-short": "Asym.", "filterable-label-filter": { "no-labels-available": "No labels available", "or": "Or", diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json index b6d1979be..502e09655 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -60,7 +60,7 @@ "node": { "transit-modified": { "title": "Transition modifiée", - "description": "Les temps ne peuvent pas être ajustés, le verrou se trouve des deux côtés." + "description": "Les temps ne peuvent pas être ajustés, le temps au départ est verrouillé." } }, "trainrunsection": { @@ -95,6 +95,10 @@ "title": "Avertissement d'arrivée à l'origine", "description": "L'heure d'arrivée à l'origine ne peut être atteinte" }, + "travel-times-not-equal": { + "title": "Temps de parcours non symétriques", + "description": "Le temps de parcours n'est pas compatible avec les horaires du trajet retour" + }, "travel-time-less-than-1": { "title": "Temps de trajet inférieur à 1", "description": "Le temps de trajet doit être supérieur ou égal à 1" @@ -116,6 +120,14 @@ "target-departure-not-reacheable": { "title": "Avertissement de départ à destination", "description": "L'heure de départ à destination ne peut être atteinte" + }, + "source-departure-not-reacheable-asymmetry": { + "title": "Avertissement de départ à l'origine", + "description": "L'heure de départ à l'origine ne peut être atteinte à cause de temps de parcours asymétriques" + }, + "target-departure-not-reacheable-asymmetry": { + "title": "Avertissement de départ à destination", + "description": "L'heure de départ à destination ne peut être atteinte à cause de temps de parcours asymétriques" } } } @@ -266,6 +278,11 @@ "position": "Position", "close": "Fermer" }, + "symmetry-dialog": { + "apply-symmetry": "Appliquer la symétrie", + "cancel": "Annuler", + "selection": "Sélection de la symétrie" + }, "trainrun-and-section-dialog": { "filterableLabels": "Labels filtrables", "trainrun-filter-tab": { @@ -354,6 +371,8 @@ "round-trips": "aller-retours", "one-ways": "allers simples", "display-direction-arrows": "Afficher les flèches de direction des trains", + "display-asymmetry-arrows": "Afficher les flèches d'asymétrie au niveau des noeuds des trains", + "display-backward-travel-times": "Afficher les temps de parcours retour (asymmétrie)", "times": "Temps", "decimal-displayed": "Nombre de décimales affichées", "display-arrival-departure-times": "Afficher les heures de départ et d'arrivée", @@ -382,6 +401,10 @@ "symmetry": "Symétrie", "show-direction": "Afficher les {$direction}", "hide-direction": "Masquer les {$direction}", + "show-asymmetric-trainruns": "Afficher les trains asymétriques", + "hide-asymmetric-trainruns": "Masquer les trains asymétriques", + "symmetric-short": "Sym.", + "asymmetric-short": "Asym.", "filterable-label-filter": { "no-labels-available": "Aucun label disponible", "or": "Ou", diff --git a/src/assets/i18n/it.json b/src/assets/i18n/it.json index c67c3a0c5..e697faf3d 100644 --- a/src/assets/i18n/it.json +++ b/src/assets/i18n/it.json @@ -60,7 +60,7 @@ "node": { "transit-modified": { "title": "Transition changed", - "description": "Times cannot be adjusted, lock found on both sides" + "description": "Times cannot be adjusted, the departure time is locked." } }, "trainrunsection": { @@ -95,6 +95,10 @@ "title": "Source Arrival Warning", "description": "Source arrival time cannot be reached" }, + "travel-times-not-equal": { + "title": "Travel Times not equal", + "description": "Travel times are not compatible with return trip time schedules" + }, "travel-time-less-than-1": { "title": "Travel Time less than 1", "description": "Travel time must be greater than or equal to 1" @@ -116,6 +120,14 @@ "target-departure-not-reacheable": { "title": "Target Departure Warning", "description": "Target departure time cannot be reached" + }, + "source-departure-not-reacheable-asymmetry": { + "title": "Source Departure Warning", + "description": "Source departure time cannot be reached due to asymmetric travel times" + }, + "target-departure-not-reacheable-asymmetry": { + "title": "Target Departure Warning", + "description": "Target departure time cannot be reached due to asymmetric travel times" } } } @@ -266,6 +278,11 @@ "position": "Position", "close": "Close" }, + "symmetry-dialog": { + "apply-symmetry": "Apply symmetry", + "cancel": "Cancel", + "selection": "Symmetry selection" + }, "trainrun-and-section-dialog": { "filterableLabels": "Filterable Labels", "trainrun-filter-tab": { @@ -354,6 +371,8 @@ "round-trips": "round trips", "one-ways": "one-ways", "display-direction-arrows": "Display trainrun direction arrows", + "display-asymmetry-arrows": "Display trainrun section asymmetry arrows at nodes", + "display-backward-travel-times": "Display backward travel times (asymmetry)", "times": "Times", "decimal-displayed": "Number of decimal place displayed", "display-arrival-departure-times": "Display departure and arrival times", @@ -382,6 +401,10 @@ "symmetry": "Symmetry", "show-direction": "Show {$direction}", "hide-direction": "Hide {$direction}", + "show-asymmetric-trainruns": "Show asymmetric trainruns", + "hide-asymmetric-trainruns": "Hide asymmetric trainruns", + "symmetric": "Sym.", + "asymmetric": "Asym.", "filterable-label-filter": { "no-labels-available": "No labels available", "or": "Or", diff --git a/src/integration-testing/reconnect.trainrunsections.test.spec.ts b/src/integration-testing/reconnect.trainrunsections.test.spec.ts index 38279deb2..ee0076cbe 100644 --- a/src/integration-testing/reconnect.trainrunsections.test.spec.ts +++ b/src/integration-testing/reconnect.trainrunsections.test.spec.ts @@ -66,10 +66,10 @@ describe("Reconnect TrainrunSection Test", () => { dataService.loadNetzgrafikDto( NetzgrafikUnitTestingReconnectTrainrunSection.getUnitTestReconnectTrainrunSectionNetzgrafik(), ); - const trainrunSectionOfInterest1 = trainrunSectionService.getTrainrunSectionFromId(6); + const trainrunSectionOfInterest1 = trainrunSectionService.getTrainrunSectionFromId(1); trainrunSectionService.reconnectTrainrunSection( - 12, + 1, 7, trainrunSectionOfInterest1.getId(), trainrunSectionOfInterest1.getTargetNodeId(), @@ -80,12 +80,12 @@ describe("Reconnect TrainrunSection Test", () => { trainrunSectionOfInterest1.getSourceNode(), trainrunSectionOfInterest1, ); - expect(endNode1.getId()).toBe(11); + expect(endNode1.getId()).toBe(8); - const trainrunSectionOfInterest2 = trainrunSectionService.getTrainrunSectionFromId(7); + const trainrunSectionOfInterest2 = trainrunSectionService.getTrainrunSectionFromId(2); trainrunSectionService.reconnectTrainrunSection( - 12, - 11, + 1, + 8, trainrunSectionOfInterest2.getId(), trainrunSectionOfInterest2.getTargetNodeId(), trainrunSectionOfInterest2.getSourceNodeId(), @@ -95,12 +95,12 @@ describe("Reconnect TrainrunSection Test", () => { trainrunSectionOfInterest2.getSourceNode(), trainrunSectionOfInterest2, ); - expect(endNode2.getId()).toBe(11); + expect(endNode2.getId()).toBe(1); - const trainrunSectionOfInterest4 = trainrunSectionService.getTrainrunSectionFromId(8); + const trainrunSectionOfInterest4 = trainrunSectionService.getTrainrunSectionFromId(4); trainrunSectionService.reconnectTrainrunSection( - 11, - 14, + 1, + 8, trainrunSectionOfInterest4.getId(), trainrunSectionOfInterest4.getTargetNodeId(), trainrunSectionOfInterest4.getSourceNodeId(), @@ -110,26 +110,26 @@ describe("Reconnect TrainrunSection Test", () => { trainrunSectionOfInterest4.getSourceNode(), trainrunSectionOfInterest4, ); - expect(endNode4.getId()).toBe(14); + expect(endNode4.getId()).toBe(7); trainrunSectionService.reconnectTrainrunSection( 7, - 12, + 1, trainrunSectionOfInterest1.getId(), trainrunSectionOfInterest1.getTargetNodeId(), trainrunSectionOfInterest1.getSourceNodeId(), ); - const nLTH = nodeService.getNodeFromId(11); + const nLTH = nodeService.getNodeFromId(8); expect(nLTH.getTransitions().length).toBe(1); const nRTR = nodeService.getNodeFromId(7); expect(nRTR.getTransitions().length).toBe(0); - const nBN = nodeService.getNodeFromId(14); + const nBN = nodeService.getNodeFromId(0); expect(nBN.getTransitions().length).toBe(0); - const nOL = nodeService.getNodeFromId(12); + const nOL = nodeService.getNodeFromId(1); expect(nOL.getTransitions().length).toBe(1); }); }); diff --git a/src/integration-testing/test-data/testNetzgrafik.json b/src/integration-testing/test-data/testNetzgrafik.json index 67b6af798..8756f1925 100644 --- a/src/integration-testing/test-data/testNetzgrafik.json +++ b/src/integration-testing/test-data/testNetzgrafik.json @@ -12,7 +12,7 @@ ], "transitions": [], "connections": [], - "resourceId": 83, + "resourceId": 370, "perronkanten": 10, "connectionTime": 5, "trainrunCategoryHaltezeiten": { @@ -45,7 +45,7 @@ {"id": 1, "port1Id": 7, "port2Id": 8, "isNonStopTransit": true} ], "connections": [], - "resourceId": 84, + "resourceId": 371, "perronkanten": 10, "connectionTime": 5, "trainrunCategoryHaltezeiten": { @@ -79,7 +79,7 @@ {"id": 1, "port1Id": 13, "port2Id": 9}, {"id": 2, "port1Id": 15, "port2Id": 9} ], - "resourceId": 85, + "resourceId": 372, "perronkanten": 10, "connectionTime": 5, "trainrunCategoryHaltezeiten": { @@ -103,7 +103,7 @@ "ports": [{"id": 11, "trainrunSectionId": 5, "positionIndex": 0, "positionAlignment": 2}], "transitions": [], "connections": [], - "resourceId": 86, + "resourceId": 373, "perronkanten": 5, "connectionTime": 3, "trainrunCategoryHaltezeiten": { @@ -130,7 +130,7 @@ ], "transitions": [], "connections": [], - "resourceId": 87, + "resourceId": 374, "perronkanten": 5, "connectionTime": 4, "trainrunCategoryHaltezeiten": { @@ -153,13 +153,8 @@ "sourcePortId": 0, "targetNodeId": 1, "targetPortId": 1, - "travelTime": { - "time": 10, - "consecutiveTime": 0, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 0, @@ -188,6 +183,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 10, + "consecutiveTime": 0, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 10, + "consecutiveTime": 0, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 0, "resourceId": 0, @@ -206,7 +215,8 @@ "3": {"x": 272, "y": 60}, "4": {"x": 224, "y": 36}, "5": {"x": 224, "y": 36}, - "6": {"x": 224, "y": 60} + "6": {"x": 224, "y": 60}, + "7": {"x": 224, "y": 60} } }, "warnings": null @@ -217,13 +227,8 @@ "sourcePortId": 2, "targetNodeId": 2, "targetPortId": 3, - "travelTime": { - "time": 10, - "consecutiveTime": 0, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 12, "consecutiveTime": 12, @@ -252,6 +257,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 10, + "consecutiveTime": 0, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 10, + "consecutiveTime": 0, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 0, "resourceId": 0, @@ -270,7 +289,8 @@ "3": {"x": 688, "y": 92}, "4": {"x": 576, "y": 52}, "5": {"x": 576, "y": 52}, - "6": {"x": 576, "y": 76} + "6": {"x": 576, "y": 76}, + "7": {"x": 576, "y": 76} } }, "warnings": null @@ -281,13 +301,8 @@ "sourcePortId": 4, "targetNodeId": 2, "targetPortId": 5, - "travelTime": { - "time": 20, - "consecutiveTime": 0, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 15, "consecutiveTime": 15, @@ -316,6 +331,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 20, + "consecutiveTime": 0, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 20, + "consecutiveTime": 0, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 1, "resourceId": 0, @@ -334,7 +363,8 @@ "3": {"x": 688, "y": 124}, "4": {"x": 576, "y": 84}, "5": {"x": 576, "y": 84}, - "6": {"x": 576, "y": 108} + "6": {"x": 576, "y": 108}, + "7": {"x": 576, "y": 108} } }, "warnings": null @@ -345,13 +375,8 @@ "sourcePortId": 6, "targetNodeId": 1, "targetPortId": 7, - "travelTime": { - "time": 39, - "consecutiveTime": 10, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 0, @@ -380,6 +405,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 39, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 39, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 2, "resourceId": 0, @@ -398,7 +437,8 @@ "3": {"x": 272, "y": 92}, "4": {"x": 224, "y": 68}, "5": {"x": 224, "y": 68}, - "6": {"x": 224, "y": 92} + "6": {"x": 224, "y": 92}, + "7": {"x": 224, "y": 92} } }, "warnings": null @@ -409,13 +449,8 @@ "sourcePortId": 8, "targetNodeId": 2, "targetPortId": 9, - "travelTime": { - "time": 10, - "consecutiveTime": 10, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 39, "consecutiveTime": 39, @@ -444,6 +479,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 2, "resourceId": 0, @@ -462,7 +511,8 @@ "3": {"x": 688, "y": 156}, "4": {"x": 576, "y": 116}, "5": {"x": 576, "y": 116}, - "6": {"x": 576, "y": 140} + "6": {"x": 576, "y": 140}, + "7": {"x": 576, "y": 140} } }, "warnings": null @@ -473,13 +523,8 @@ "sourcePortId": 10, "targetNodeId": 3, "targetPortId": 11, - "travelTime": { - "time": 51, - "consecutiveTime": 10, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 50, "consecutiveTime": 50, @@ -508,6 +553,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 51, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 51, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 2, "resourceId": 0, @@ -526,7 +585,8 @@ "3": {"x": 1136, "y": 92}, "4": {"x": 1008, "y": 68}, "5": {"x": 1008, "y": 68}, - "6": {"x": 1008, "y": 92} + "6": {"x": 1008, "y": 92}, + "7": {"x": 1008, "y": 92} } }, "warnings": null @@ -537,13 +597,8 @@ "sourcePortId": 12, "targetNodeId": 2, "targetPortId": 13, - "travelTime": { - "time": 10, - "consecutiveTime": 10, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 55, "consecutiveTime": 115, @@ -572,6 +627,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 3, "resourceId": 0, @@ -590,7 +659,8 @@ "3": {"x": 880, "y": 100}, "4": {"x": 944, "y": 180}, "5": {"x": 944, "y": 180}, - "6": {"x": 944, "y": 204} + "6": {"x": 944, "y": 204}, + "7": {"x": 944, "y": 204} } }, "warnings": null @@ -601,13 +671,8 @@ "sourcePortId": 14, "targetNodeId": 2, "targetPortId": 15, - "travelTime": { - "time": 10, - "consecutiveTime": 10, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 120, @@ -636,6 +701,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 4, "resourceId": 0, @@ -654,7 +733,8 @@ "3": {"x": 880, "y": 132}, "4": {"x": 944, "y": 212}, "5": {"x": 944, "y": 212}, - "6": {"x": 944, "y": 236} + "6": {"x": 944, "y": 236}, + "7": {"x": 944, "y": 236} } }, "warnings": null @@ -708,11 +788,11 @@ } ], "resources": [ - {"id": 83, "capacity": 2}, - {"id": 84, "capacity": 2}, - {"id": 85, "capacity": 2}, - {"id": 86, "capacity": 2}, - {"id": 87, "capacity": 2} + {"id": 370, "capacity": 2}, + {"id": 371, "capacity": 2}, + {"id": 372, "capacity": 2}, + {"id": 373, "capacity": 2}, + {"id": 374, "capacity": 2} ], "metadata": { "analyticsSettings": {"originDestinationSettings": {"connectionPenalty": 5}}, @@ -883,7 +963,7 @@ ], "netzgrafikColors": [ { - "id": 7, + "id": 70, "colorRef": "NORMAL", "color": "#767676", "colorFocus": "#000000", diff --git a/src/integration-testing/test-data/testNetzgrafikOdMatrix.json b/src/integration-testing/test-data/testNetzgrafikOdMatrix.json index 3a3d24e28..37c57e2fd 100644 --- a/src/integration-testing/test-data/testNetzgrafikOdMatrix.json +++ b/src/integration-testing/test-data/testNetzgrafikOdMatrix.json @@ -7,30 +7,10 @@ "positionX": 1536, "positionY": 864, "ports": [ - { - "id": 14, - "trainrunSectionId": 7, - "positionIndex": 0, - "positionAlignment": 2 - }, - { - "id": 20, - "trainrunSectionId": 10, - "positionIndex": 1, - "positionAlignment": 2 - }, - { - "id": 15, - "trainrunSectionId": 8, - "positionIndex": 2, - "positionAlignment": 2 - }, - { - "id": 21, - "trainrunSectionId": 11, - "positionIndex": 3, - "positionAlignment": 2 - } + {"id": 14, "trainrunSectionId": 7, "positionIndex": 0, "positionAlignment": 2}, + {"id": 20, "trainrunSectionId": 10, "positionIndex": 1, "positionAlignment": 2}, + {"id": 15, "trainrunSectionId": 8, "positionIndex": 2, "positionAlignment": 2}, + {"id": 21, "trainrunSectionId": 11, "positionIndex": 3, "positionAlignment": 2} ], "transitions": [{"id": 4, "port1Id": 20, "port2Id": 21, "isNonStopTransit": true}], "connections": [], @@ -56,30 +36,10 @@ "positionX": 1120, "positionY": 672, "ports": [ - { - "id": 17, - "trainrunSectionId": 9, - "positionIndex": 0, - "positionAlignment": 1 - }, - { - "id": 12, - "trainrunSectionId": 6, - "positionIndex": 0, - "positionAlignment": 2 - }, - { - "id": 13, - "trainrunSectionId": 7, - "positionIndex": 0, - "positionAlignment": 3 - }, - { - "id": 19, - "trainrunSectionId": 10, - "positionIndex": 1, - "positionAlignment": 3 - } + {"id": 17, "trainrunSectionId": 9, "positionIndex": 0, "positionAlignment": 1}, + {"id": 12, "trainrunSectionId": 6, "positionIndex": 0, "positionAlignment": 2}, + {"id": 13, "trainrunSectionId": 7, "positionIndex": 0, "positionAlignment": 3}, + {"id": 19, "trainrunSectionId": 10, "positionIndex": 1, "positionAlignment": 3} ], "transitions": [{"id": 3, "port1Id": 12, "port2Id": 13, "isNonStopTransit": false}], "connections": [], @@ -105,18 +65,8 @@ "positionX": 1088, "positionY": 1088, "ports": [ - { - "id": 18, - "trainrunSectionId": 9, - "positionIndex": 0, - "positionAlignment": 0 - }, - { - "id": 22, - "trainrunSectionId": 11, - "positionIndex": 0, - "positionAlignment": 3 - } + {"id": 18, "trainrunSectionId": 9, "positionIndex": 0, "positionAlignment": 0}, + {"id": 22, "trainrunSectionId": 11, "positionIndex": 0, "positionAlignment": 3} ], "transitions": [], "connections": [], @@ -142,18 +92,8 @@ "positionX": 800, "positionY": 864, "ports": [ - { - "id": 11, - "trainrunSectionId": 6, - "positionIndex": 0, - "positionAlignment": 3 - }, - { - "id": 16, - "trainrunSectionId": 8, - "positionIndex": 1, - "positionAlignment": 3 - } + {"id": 11, "trainrunSectionId": 6, "positionIndex": 0, "positionAlignment": 3}, + {"id": 16, "trainrunSectionId": 8, "positionIndex": 1, "positionAlignment": 3} ], "transitions": [], "connections": [], @@ -178,14 +118,7 @@ "fullName": "New node", "positionX": 1472, "positionY": 1248, - "ports": [ - { - "id": 24, - "trainrunSectionId": 12, - "positionIndex": 0, - "positionAlignment": 3 - } - ], + "ports": [{"id": 24, "trainrunSectionId": 12, "positionIndex": 0, "positionAlignment": 3}], "transitions": [], "connections": [], "resourceId": 16, @@ -210,18 +143,8 @@ "positionX": 1696, "positionY": 1248, "ports": [ - { - "id": 23, - "trainrunSectionId": 12, - "positionIndex": 0, - "positionAlignment": 2 - }, - { - "id": 25, - "trainrunSectionId": 13, - "positionIndex": 0, - "positionAlignment": 3 - } + {"id": 23, "trainrunSectionId": 12, "positionIndex": 0, "positionAlignment": 2}, + {"id": 25, "trainrunSectionId": 13, "positionIndex": 0, "positionAlignment": 3} ], "transitions": [{"id": 5, "port1Id": 23, "port2Id": 25, "isNonStopTransit": false}], "connections": [], @@ -246,14 +169,7 @@ "fullName": "New node", "positionX": 1920, "positionY": 1248, - "ports": [ - { - "id": 26, - "trainrunSectionId": 13, - "positionIndex": 0, - "positionAlignment": 2 - } - ], + "ports": [{"id": 26, "trainrunSectionId": 13, "positionIndex": 0, "positionAlignment": 2}], "transitions": [], "connections": [], "resourceId": 18, @@ -278,30 +194,10 @@ "positionX": 832, "positionY": 32, "ports": [ - { - "id": 29, - "trainrunSectionId": 19, - "positionIndex": 0, - "positionAlignment": 1 - }, - { - "id": 32, - "trainrunSectionId": 20, - "positionIndex": 1, - "positionAlignment": 1 - }, - { - "id": 28, - "trainrunSectionId": 18, - "positionIndex": 0, - "positionAlignment": 2 - }, - { - "id": 33, - "trainrunSectionId": 21, - "positionIndex": 0, - "positionAlignment": 3 - } + {"id": 29, "trainrunSectionId": 19, "positionIndex": 0, "positionAlignment": 1}, + {"id": 32, "trainrunSectionId": 20, "positionIndex": 1, "positionAlignment": 1}, + {"id": 28, "trainrunSectionId": 18, "positionIndex": 0, "positionAlignment": 2}, + {"id": 33, "trainrunSectionId": 21, "positionIndex": 0, "positionAlignment": 3} ], "transitions": [ {"id": 7, "port1Id": 29, "port2Id": 28, "isNonStopTransit": false}, @@ -329,14 +225,7 @@ "fullName": "K", "positionX": 1632, "positionY": 32, - "ports": [ - { - "id": 34, - "trainrunSectionId": 21, - "positionIndex": 0, - "positionAlignment": 2 - } - ], + "ports": [{"id": 34, "trainrunSectionId": 21, "positionIndex": 0, "positionAlignment": 2}], "transitions": [], "connections": [], "resourceId": 3, @@ -361,18 +250,8 @@ "positionX": 832, "positionY": 448, "ports": [ - { - "id": 30, - "trainrunSectionId": 19, - "positionIndex": 0, - "positionAlignment": 0 - }, - { - "id": 31, - "trainrunSectionId": 20, - "positionIndex": 1, - "positionAlignment": 0 - } + {"id": 30, "trainrunSectionId": 19, "positionIndex": 0, "positionAlignment": 0}, + {"id": 31, "trainrunSectionId": 20, "positionIndex": 1, "positionAlignment": 0} ], "transitions": [{"id": 8, "port1Id": 30, "port2Id": 31, "isNonStopTransit": false}], "connections": [], @@ -397,14 +276,7 @@ "fullName": "H", "positionX": 320, "positionY": 32, - "ports": [ - { - "id": 27, - "trainrunSectionId": 18, - "positionIndex": 0, - "positionAlignment": 3 - } - ], + "ports": [{"id": 27, "trainrunSectionId": 18, "positionIndex": 0, "positionAlignment": 3}], "transitions": [], "connections": [], "resourceId": 8, @@ -428,14 +300,7 @@ "fullName": "L1", "positionX": 1504, "positionY": 192, - "ports": [ - { - "id": 35, - "trainrunSectionId": 22, - "positionIndex": 0, - "positionAlignment": 1 - } - ], + "ports": [{"id": 35, "trainrunSectionId": 22, "positionIndex": 0, "positionAlignment": 1}], "transitions": [], "connections": [], "resourceId": 19, @@ -460,18 +325,8 @@ "positionX": 1504, "positionY": 512, "ports": [ - { - "id": 36, - "trainrunSectionId": 22, - "positionIndex": 0, - "positionAlignment": 0 - }, - { - "id": 37, - "trainrunSectionId": 23, - "positionIndex": 0, - "positionAlignment": 3 - } + {"id": 36, "trainrunSectionId": 22, "positionIndex": 0, "positionAlignment": 0}, + {"id": 37, "trainrunSectionId": 23, "positionIndex": 0, "positionAlignment": 3} ], "transitions": [], "connections": [], @@ -496,14 +351,7 @@ "fullName": "N1", "positionX": 1888, "positionY": 512, - "ports": [ - { - "id": 38, - "trainrunSectionId": 23, - "positionIndex": 0, - "positionAlignment": 2 - } - ], + "ports": [{"id": 38, "trainrunSectionId": 23, "positionIndex": 0, "positionAlignment": 2}], "transitions": [], "connections": [], "resourceId": 21, @@ -527,14 +375,7 @@ "fullName": "L2", "positionX": 2080, "positionY": 192, - "ports": [ - { - "id": 44, - "trainrunSectionId": 24, - "positionIndex": 0, - "positionAlignment": 1 - } - ], + "ports": [{"id": 44, "trainrunSectionId": 24, "positionIndex": 0, "positionAlignment": 1}], "transitions": [], "connections": [], "resourceId": 22, @@ -559,18 +400,8 @@ "positionX": 2080, "positionY": 512, "ports": [ - { - "id": 43, - "trainrunSectionId": 24, - "positionIndex": 0, - "positionAlignment": 0 - }, - { - "id": 46, - "trainrunSectionId": 25, - "positionIndex": 0, - "positionAlignment": 3 - } + {"id": 43, "trainrunSectionId": 24, "positionIndex": 0, "positionAlignment": 0}, + {"id": 46, "trainrunSectionId": 25, "positionIndex": 0, "positionAlignment": 3} ], "transitions": [], "connections": [], @@ -595,14 +426,7 @@ "fullName": "N2", "positionX": 2464, "positionY": 512, - "ports": [ - { - "id": 45, - "trainrunSectionId": 25, - "positionIndex": 0, - "positionAlignment": 2 - } - ], + "ports": [{"id": 45, "trainrunSectionId": 25, "positionIndex": 0, "positionAlignment": 2}], "transitions": [], "connections": [], "resourceId": 24, @@ -626,14 +450,7 @@ "fullName": "L3", "positionX": 2656, "positionY": 192, - "ports": [ - { - "id": 52, - "trainrunSectionId": 26, - "positionIndex": 0, - "positionAlignment": 1 - } - ], + "ports": [{"id": 52, "trainrunSectionId": 26, "positionIndex": 0, "positionAlignment": 1}], "transitions": [], "connections": [], "resourceId": 25, @@ -658,18 +475,8 @@ "positionX": 2656, "positionY": 512, "ports": [ - { - "id": 51, - "trainrunSectionId": 26, - "positionIndex": 0, - "positionAlignment": 0 - }, - { - "id": 54, - "trainrunSectionId": 27, - "positionIndex": 0, - "positionAlignment": 3 - } + {"id": 51, "trainrunSectionId": 26, "positionIndex": 0, "positionAlignment": 0}, + {"id": 54, "trainrunSectionId": 27, "positionIndex": 0, "positionAlignment": 3} ], "transitions": [], "connections": [], @@ -694,14 +501,7 @@ "fullName": "N3", "positionX": 3040, "positionY": 512, - "ports": [ - { - "id": 53, - "trainrunSectionId": 27, - "positionIndex": 0, - "positionAlignment": 2 - } - ], + "ports": [{"id": 53, "trainrunSectionId": 27, "positionIndex": 0, "positionAlignment": 2}], "transitions": [], "connections": [], "resourceId": 27, @@ -727,13 +527,8 @@ "sourcePortId": 11, "targetNodeId": 12, "targetPortId": 12, - "travelTime": { - "time": 2, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 0, @@ -762,6 +557,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 2, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 2, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 4, "resourceId": 0, @@ -780,7 +589,8 @@ "3": {"x": 1072, "y": 700}, "4": {"x": 1008, "y": 772}, "5": {"x": 1008, "y": 772}, - "6": {"x": 1008, "y": 796} + "6": {"x": 1008, "y": 796}, + "7": {"x": 1008, "y": 796} } }, "warnings": null @@ -791,13 +601,8 @@ "sourcePortId": 13, "targetNodeId": 11, "targetPortId": 14, - "travelTime": { - "time": 4, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 3, "consecutiveTime": 3, @@ -826,6 +631,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 4, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 4, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 4, "resourceId": 0, @@ -844,7 +663,8 @@ "3": {"x": 1488, "y": 892}, "4": {"x": 1376, "y": 772}, "5": {"x": 1376, "y": 772}, - "6": {"x": 1376, "y": 796} + "6": {"x": 1376, "y": 796}, + "7": {"x": 1376, "y": 796} } }, "warnings": null @@ -855,13 +675,8 @@ "sourcePortId": 15, "targetNodeId": 14, "targetPortId": 16, - "travelTime": { - "time": 6, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 60, @@ -890,6 +705,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 6, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 6, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 5, "resourceId": 0, @@ -908,7 +737,8 @@ "3": {"x": 944, "y": 900}, "4": {"x": 1216, "y": 916}, "5": {"x": 1216, "y": 916}, - "6": {"x": 1216, "y": 940} + "6": {"x": 1216, "y": 940}, + "7": {"x": 1216, "y": 940} } }, "warnings": null @@ -919,13 +749,8 @@ "sourcePortId": 17, "targetNodeId": 13, "targetPortId": 18, - "travelTime": { - "time": 2, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 8, "consecutiveTime": 8, @@ -954,6 +779,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 2, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 2, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 6, "resourceId": 0, @@ -972,7 +811,8 @@ "3": {"x": 1092, "y": 1040}, "4": {"x": 1108, "y": 926}, "5": {"x": 1108, "y": 926}, - "6": {"x": 1132, "y": 926} + "6": {"x": 1132, "y": 926}, + "7": {"x": 1132, "y": 926} } }, "warnings": null @@ -983,13 +823,8 @@ "sourcePortId": 19, "targetNodeId": 11, "targetPortId": 20, - "travelTime": { - "time": 5, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 0, @@ -1018,6 +853,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 5, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 5, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 7, "resourceId": 0, @@ -1036,7 +885,8 @@ "3": {"x": 1488, "y": 924}, "4": {"x": 1376, "y": 804}, "5": {"x": 1376, "y": 804}, - "6": {"x": 1376, "y": 828} + "6": {"x": 1376, "y": 828}, + "7": {"x": 1376, "y": 828} } }, "warnings": null @@ -1047,13 +897,8 @@ "sourcePortId": 21, "targetNodeId": 13, "targetPortId": 22, - "travelTime": { - "time": 4, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 5, "consecutiveTime": 5, @@ -1082,6 +927,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 4, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 4, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 7, "resourceId": 0, @@ -1100,7 +959,8 @@ "3": {"x": 1232, "y": 1092}, "4": {"x": 1360, "y": 1028}, "5": {"x": 1360, "y": 1028}, - "6": {"x": 1360, "y": 1052} + "6": {"x": 1360, "y": 1052}, + "7": {"x": 1360, "y": 1052} } }, "warnings": null @@ -1111,13 +971,8 @@ "sourcePortId": 23, "targetNodeId": 15, "targetPortId": 24, - "travelTime": { - "time": 1, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 120, @@ -1146,6 +1001,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 8, "resourceId": 0, @@ -1164,7 +1033,8 @@ "3": {"x": 1616, "y": 1252}, "4": {"x": 1632, "y": 1252}, "5": {"x": 1632, "y": 1252}, - "6": {"x": 1632, "y": 1276} + "6": {"x": 1632, "y": 1276}, + "7": {"x": 1632, "y": 1276} } }, "warnings": null @@ -1175,13 +1045,8 @@ "sourcePortId": 26, "targetNodeId": 16, "targetPortId": 25, - "travelTime": { - "time": 1, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 57, "consecutiveTime": 117, @@ -1210,6 +1075,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 8, "resourceId": 0, @@ -1228,7 +1107,8 @@ "3": {"x": 1840, "y": 1252}, "4": {"x": 1856, "y": 1252}, "5": {"x": 1856, "y": 1252}, - "6": {"x": 1856, "y": 1276} + "6": {"x": 1856, "y": 1276}, + "7": {"x": 1856, "y": 1276} } }, "warnings": null @@ -1239,13 +1119,8 @@ "sourcePortId": 27, "targetNodeId": 1, "targetPortId": 28, - "travelTime": { - "time": 1, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 0, @@ -1274,6 +1149,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 9, "resourceId": 0, @@ -1292,7 +1181,8 @@ "3": {"x": 784, "y": 60}, "4": {"x": 624, "y": 36}, "5": {"x": 624, "y": 36}, - "6": {"x": 624, "y": 60} + "6": {"x": 624, "y": 60}, + "7": {"x": 624, "y": 60} } }, "warnings": null @@ -1303,13 +1193,8 @@ "sourcePortId": 29, "targetNodeId": 4, "targetPortId": 30, - "travelTime": { - "time": 5, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 3, "consecutiveTime": 3, @@ -1338,6 +1223,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 5, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 5, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 9, "resourceId": 0, @@ -1356,7 +1255,8 @@ "3": {"x": 836, "y": 400}, "4": {"x": 836, "y": 272}, "5": {"x": 836, "y": 272}, - "6": {"x": 860, "y": 272} + "6": {"x": 860, "y": 272}, + "7": {"x": 860, "y": 272} } }, "warnings": null @@ -1367,13 +1267,8 @@ "sourcePortId": 31, "targetNodeId": 1, "targetPortId": 32, - "travelTime": { - "time": 1, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 6, "consecutiveTime": 66, @@ -1402,6 +1297,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 9, "resourceId": 0, @@ -1420,7 +1329,8 @@ "3": {"x": 892, "y": 144}, "4": {"x": 868, "y": 272}, "5": {"x": 868, "y": 272}, - "6": {"x": 892, "y": 272} + "6": {"x": 892, "y": 272}, + "7": {"x": 892, "y": 272} } }, "warnings": null @@ -1431,13 +1341,8 @@ "sourcePortId": 33, "targetNodeId": 2, "targetPortId": 34, - "travelTime": { - "time": 1, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 9, "consecutiveTime": 69, @@ -1466,6 +1371,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 9, "resourceId": 0, @@ -1484,7 +1403,8 @@ "3": {"x": 1584, "y": 60}, "4": {"x": 1280, "y": 36}, "5": {"x": 1280, "y": 36}, - "6": {"x": 1280, "y": 60} + "6": {"x": 1280, "y": 60}, + "7": {"x": 1280, "y": 60} } }, "warnings": null @@ -1495,13 +1415,8 @@ "sourcePortId": 35, "targetNodeId": 19, "targetPortId": 36, - "travelTime": { - "time": 5, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 0, @@ -1530,6 +1445,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 5, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 5, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 10, "resourceId": 0, @@ -1548,7 +1477,8 @@ "3": {"x": 1508, "y": 464}, "4": {"x": 1508, "y": 384}, "5": {"x": 1508, "y": 384}, - "6": {"x": 1532, "y": 384} + "6": {"x": 1508, "y": 384}, + "7": {"x": 1532, "y": 384} } }, "warnings": null @@ -1559,13 +1489,8 @@ "sourcePortId": 37, "targetNodeId": 20, "targetPortId": 38, - "travelTime": { - "time": 1, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 0, @@ -1594,6 +1519,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 11, "resourceId": 0, @@ -1612,7 +1551,8 @@ "3": {"x": 1840, "y": 540}, "4": {"x": 1744, "y": 516}, "5": {"x": 1744, "y": 516}, - "6": {"x": 1744, "y": 540} + "6": {"x": 1744, "y": 540}, + "7": {"x": 1744, "y": 540} } }, "warnings": null @@ -1623,13 +1563,8 @@ "sourcePortId": 44, "targetNodeId": 22, "targetPortId": 43, - "travelTime": { - "time": 5, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 0, @@ -1658,6 +1593,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 5, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 5, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 12, "resourceId": 0, @@ -1676,7 +1625,8 @@ "3": {"x": 2084, "y": 464}, "4": {"x": 2084, "y": 384}, "5": {"x": 2084, "y": 384}, - "6": {"x": 2108, "y": 384} + "6": {"x": 2084, "y": 384}, + "7": {"x": 2108, "y": 384} } }, "warnings": null @@ -1687,13 +1637,8 @@ "sourcePortId": 46, "targetNodeId": 23, "targetPortId": 45, - "travelTime": { - "time": 1, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 0, @@ -1722,6 +1667,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 13, "resourceId": 0, @@ -1740,7 +1699,8 @@ "3": {"x": 2416, "y": 540}, "4": {"x": 2320, "y": 516}, "5": {"x": 2320, "y": 516}, - "6": {"x": 2320, "y": 540} + "6": {"x": 2320, "y": 540}, + "7": {"x": 2320, "y": 540} } }, "warnings": null @@ -1751,13 +1711,8 @@ "sourcePortId": 52, "targetNodeId": 25, "targetPortId": 51, - "travelTime": { - "time": 5, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 0, @@ -1786,6 +1741,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 5, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 5, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 14, "resourceId": 0, @@ -1804,7 +1773,8 @@ "3": {"x": 2660, "y": 464}, "4": {"x": 2660, "y": 384}, "5": {"x": 2660, "y": 384}, - "6": {"x": 2684, "y": 384} + "6": {"x": 2660, "y": 384}, + "7": {"x": 2684, "y": 384} } }, "warnings": null @@ -1815,13 +1785,8 @@ "sourcePortId": 53, "targetNodeId": 25, "targetPortId": 54, - "travelTime": { - "time": 1, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 59, "consecutiveTime": 59, @@ -1850,6 +1815,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 1, + "consecutiveTime": 1, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 15, "resourceId": 0, @@ -1868,7 +1847,8 @@ "3": {"x": 2800, "y": 516}, "4": {"x": 2896, "y": 516}, "5": {"x": 2896, "y": 516}, - "6": {"x": 2896, "y": 540} + "6": {"x": 2896, "y": 516}, + "7": {"x": 2896, "y": 540} } }, "warnings": null @@ -1985,17 +1965,10 @@ } ], "resources": [ - {"id": 1, "capacity": 2}, {"id": 2, "capacity": 2}, {"id": 3, "capacity": 2}, - {"id": 4, "capacity": 2}, {"id": 5, "capacity": 2}, - {"id": 6, "capacity": 2}, - {"id": 7, "capacity": 2}, {"id": 8, "capacity": 2}, - {"id": 9, "capacity": 2}, - {"id": 10, "capacity": 2}, - {"id": 11, "capacity": 2}, {"id": 12, "capacity": 2}, {"id": 13, "capacity": 2}, {"id": 14, "capacity": 2}, @@ -2202,9 +2175,7 @@ "colorDarkModeRelated": "#767676" } ], - "analyticsSettings": { - "originDestinationSettings": {"connectionPenalty": 5} - } + "analyticsSettings": {"originDestinationSettings": {"connectionPenalty": 5}} }, "freeFloatingTexts": [], "labels": [], diff --git a/src/integration-testing/test-data/testReconnectTrainrunSectionNetzgrafik.json b/src/integration-testing/test-data/testReconnectTrainrunSectionNetzgrafik.json index 46f13051d..bc5034cfe 100644 --- a/src/integration-testing/test-data/testReconnectTrainrunSectionNetzgrafik.json +++ b/src/integration-testing/test-data/testReconnectTrainrunSectionNetzgrafik.json @@ -1,217 +1,49 @@ { "nodes": [ { - "id": 11, - "betriebspunktName": "C", - "fullName": "Neuer Knoten", - "positionX": 1536, - "positionY": 864, - "ports": [ - {"id": 14, "trainrunSectionId": 7, "positionIndex": 0, "positionAlignment": 2}, - {"id": 20, "trainrunSectionId": 10, "positionIndex": 1, "positionAlignment": 2}, - {"id": 15, "trainrunSectionId": 8, "positionIndex": 2, "positionAlignment": 2}, - {"id": 21, "trainrunSectionId": 11, "positionIndex": 3, "positionAlignment": 2} - ], - "transitions": [{"id": 4, "port1Id": 20, "port2Id": 21, "isNonStopTransit": true}], - "connections": [], - "resourceId": 12, - "perronkanten": 5, - "connectionTime": 3, - "trainrunCategoryHaltezeiten": { - "HaltezeitIPV": {"haltezeit": 3, "no_halt": false}, - "HaltezeitA": {"haltezeit": 2, "no_halt": false}, - "HaltezeitB": {"haltezeit": 2, "no_halt": false}, - "HaltezeitC": {"haltezeit": 1, "no_halt": false}, - "HaltezeitD": {"haltezeit": 1, "no_halt": false}, - "HaltezeitUncategorized": {"haltezeit": 0, "no_halt": true} - }, - "symmetryAxis": null, - "warnings": null, - "labelIds": [] - }, - { - "id": 12, - "betriebspunktName": "A", - "fullName": "Neuer Knoten", - "positionX": 1120, - "positionY": 672, - "ports": [ - {"id": 17, "trainrunSectionId": 9, "positionIndex": 0, "positionAlignment": 1}, - {"id": 12, "trainrunSectionId": 6, "positionIndex": 0, "positionAlignment": 2}, - {"id": 13, "trainrunSectionId": 7, "positionIndex": 0, "positionAlignment": 3}, - {"id": 19, "trainrunSectionId": 10, "positionIndex": 1, "positionAlignment": 3} - ], - "transitions": [{"id": 3, "port1Id": 12, "port2Id": 13, "isNonStopTransit": false}], - "connections": [], - "resourceId": 13, - "perronkanten": 5, - "connectionTime": 8, - "trainrunCategoryHaltezeiten": { - "HaltezeitIPV": {"haltezeit": 3, "no_halt": false}, - "HaltezeitA": {"haltezeit": 2, "no_halt": false}, - "HaltezeitB": {"haltezeit": 2, "no_halt": false}, - "HaltezeitC": {"haltezeit": 1, "no_halt": false}, - "HaltezeitD": {"haltezeit": 1, "no_halt": false}, - "HaltezeitUncategorized": {"haltezeit": 0, "no_halt": true} - }, - "symmetryAxis": null, - "warnings": null, - "labelIds": [] - }, - { - "id": 13, - "betriebspunktName": "D", - "fullName": "Neuer Knoten", - "positionX": 1088, - "positionY": 1088, - "ports": [ - {"id": 18, "trainrunSectionId": 9, "positionIndex": 0, "positionAlignment": 0}, - {"id": 22, "trainrunSectionId": 11, "positionIndex": 0, "positionAlignment": 3} - ], - "transitions": [], - "connections": [], - "resourceId": 14, - "perronkanten": 5, - "connectionTime": 3, - "trainrunCategoryHaltezeiten": { - "HaltezeitIPV": {"haltezeit": 3, "no_halt": false}, - "HaltezeitA": {"haltezeit": 2, "no_halt": false}, - "HaltezeitB": {"haltezeit": 2, "no_halt": false}, - "HaltezeitC": {"haltezeit": 1, "no_halt": false}, - "HaltezeitD": {"haltezeit": 1, "no_halt": false}, - "HaltezeitUncategorized": {"haltezeit": 0, "no_halt": true} - }, - "symmetryAxis": null, - "warnings": null, - "labelIds": [] - }, - { - "id": 14, - "betriebspunktName": "B", - "fullName": "Neuer Knoten", - "positionX": 800, - "positionY": 864, - "ports": [ - {"id": 11, "trainrunSectionId": 6, "positionIndex": 0, "positionAlignment": 3}, - {"id": 16, "trainrunSectionId": 8, "positionIndex": 1, "positionAlignment": 3} - ], - "transitions": [], - "connections": [], - "resourceId": 15, - "perronkanten": 5, - "connectionTime": 3, - "trainrunCategoryHaltezeiten": { - "HaltezeitIPV": {"haltezeit": 3, "no_halt": false}, - "HaltezeitA": {"haltezeit": 2, "no_halt": false}, - "HaltezeitB": {"haltezeit": 2, "no_halt": false}, - "HaltezeitC": {"haltezeit": 1, "no_halt": false}, - "HaltezeitD": {"haltezeit": 1, "no_halt": false}, - "HaltezeitUncategorized": {"haltezeit": 0, "no_halt": true} - }, - "symmetryAxis": null, - "warnings": null, - "labelIds": [] - }, - { - "id": 15, - "betriebspunktName": "E", - "fullName": "New node", - "positionX": 1472, - "positionY": 1248, - "ports": [{"id": 24, "trainrunSectionId": 12, "positionIndex": 0, "positionAlignment": 3}], - "transitions": [], - "connections": [], - "resourceId": 16, - "perronkanten": 5, - "connectionTime": 3, - "trainrunCategoryHaltezeiten": { - "HaltezeitIPV": {"haltezeit": 3, "no_halt": false}, - "HaltezeitA": {"haltezeit": 2, "no_halt": false}, - "HaltezeitB": {"haltezeit": 2, "no_halt": false}, - "HaltezeitC": {"haltezeit": 1, "no_halt": false}, - "HaltezeitD": {"haltezeit": 1, "no_halt": false}, - "HaltezeitUncategorized": {"haltezeit": 0, "no_halt": true} - }, - "symmetryAxis": null, - "warnings": null, - "labelIds": [] - }, - { - "id": 16, - "betriebspunktName": "F", - "fullName": "New node", - "positionX": 1696, - "positionY": 1248, + "id": 0, + "betriebspunktName": "BN", + "fullName": "Bern", + "positionX": -192, + "positionY": 32, "ports": [ - {"id": 23, "trainrunSectionId": 12, "positionIndex": 0, "positionAlignment": 2}, - {"id": 25, "trainrunSectionId": 13, "positionIndex": 0, "positionAlignment": 3} + {"id": 4, "trainrunSectionId": 2, "positionIndex": 0, "positionAlignment": 3}, + {"id": 5, "trainrunSectionId": 3, "positionIndex": 1, "positionAlignment": 3} ], - "transitions": [{"id": 5, "port1Id": 23, "port2Id": 25, "isNonStopTransit": false}], - "connections": [], - "resourceId": 17, - "perronkanten": 5, - "connectionTime": 3, - "trainrunCategoryHaltezeiten": { - "HaltezeitIPV": {"haltezeit": 3, "no_halt": false}, - "HaltezeitA": {"haltezeit": 2, "no_halt": false}, - "HaltezeitB": {"haltezeit": 2, "no_halt": false}, - "HaltezeitC": {"haltezeit": 1, "no_halt": false}, - "HaltezeitD": {"haltezeit": 1, "no_halt": false}, - "HaltezeitUncategorized": {"haltezeit": 0, "no_halt": true} - }, - "symmetryAxis": null, - "warnings": null, - "labelIds": [] - }, - { - "id": 17, - "betriebspunktName": "G", - "fullName": "New node", - "positionX": 1920, - "positionY": 1248, - "ports": [{"id": 26, "trainrunSectionId": 13, "positionIndex": 0, "positionAlignment": 2}], - "transitions": [], + "transitions": [{"id": 1, "port1Id": 4, "port2Id": 5, "isNonStopTransit": false}], "connections": [], - "resourceId": 18, - "perronkanten": 5, - "connectionTime": 3, + "resourceId": 1, + "perronkanten": 10, + "connectionTime": 5, "trainrunCategoryHaltezeiten": { - "HaltezeitIPV": {"haltezeit": 3, "no_halt": false}, + "HaltezeitIPV": {"haltezeit": 2, "no_halt": false}, "HaltezeitA": {"haltezeit": 2, "no_halt": false}, "HaltezeitB": {"haltezeit": 2, "no_halt": false}, - "HaltezeitC": {"haltezeit": 1, "no_halt": false}, + "HaltezeitC": {"haltezeit": 1.5, "no_halt": false}, "HaltezeitD": {"haltezeit": 1, "no_halt": false}, "HaltezeitUncategorized": {"haltezeit": 0, "no_halt": true} }, - "symmetryAxis": null, + "symmetryAxis": 0, "warnings": null, "labelIds": [] }, { "id": 1, - "betriebspunktName": "I", - "fullName": "I", + "betriebspunktName": "OL", + "fullName": "Olten", "positionX": 832, "positionY": 32, - "ports": [ - {"id": 11, "trainrunSectionId": 15, "positionIndex": 0, "positionAlignment": 1}, - {"id": 14, "trainrunSectionId": 16, "positionIndex": 1, "positionAlignment": 1}, - {"id": 10, "trainrunSectionId": 14, "positionIndex": 0, "positionAlignment": 2}, - {"id": 15, "trainrunSectionId": 17, "positionIndex": 0, "positionAlignment": 3} - ], - "transitions": [ - {"id": 4, "port1Id": 11, "port2Id": 10, "isNonStopTransit": false}, - {"id": 6, "port1Id": 14, "port2Id": 15, "isNonStopTransit": false} - ], + "ports": [{"id": 8, "trainrunSectionId": 4, "positionIndex": 0, "positionAlignment": 2}], + "transitions": [], "connections": [], "resourceId": 2, "perronkanten": 10, "connectionTime": 5, "trainrunCategoryHaltezeiten": { - "HaltezeitIPV": {"haltezeit": 3, "no_halt": false}, + "HaltezeitIPV": {"haltezeit": 2, "no_halt": false}, "HaltezeitA": {"haltezeit": 2, "no_halt": false}, "HaltezeitB": {"haltezeit": 2, "no_halt": false}, - "HaltezeitC": {"haltezeit": 1, "no_halt": false}, + "HaltezeitC": {"haltezeit": 1.5, "no_halt": false}, "HaltezeitD": {"haltezeit": 1, "no_halt": false}, "HaltezeitUncategorized": {"haltezeit": 0, "no_halt": true} }, @@ -220,22 +52,22 @@ "labelIds": [] }, { - "id": 2, - "betriebspunktName": "K", - "fullName": "K", - "positionX": 1632, + "id": 7, + "betriebspunktName": "RTR", + "fullName": "Rothrist", + "positionX": 320, "positionY": 32, - "ports": [{"id": 16, "trainrunSectionId": 17, "positionIndex": 0, "positionAlignment": 2}], + "ports": [{"id": 11, "trainrunSectionId": 1, "positionIndex": 0, "positionAlignment": 1}], "transitions": [], "connections": [], - "resourceId": 3, - "perronkanten": 10, + "resourceId": 8, + "perronkanten": 5, "connectionTime": 5, "trainrunCategoryHaltezeiten": { - "HaltezeitIPV": {"haltezeit": 3, "no_halt": false}, + "HaltezeitIPV": {"haltezeit": 2, "no_halt": false}, "HaltezeitA": {"haltezeit": 2, "no_halt": false}, "HaltezeitB": {"haltezeit": 2, "no_halt": false}, - "HaltezeitC": {"haltezeit": 1, "no_halt": false}, + "HaltezeitC": {"haltezeit": 1.5, "no_halt": false}, "HaltezeitD": {"haltezeit": 1, "no_halt": false}, "HaltezeitUncategorized": {"haltezeit": 0, "no_halt": true} }, @@ -244,49 +76,27 @@ "labelIds": [] }, { - "id": 4, - "betriebspunktName": "J", - "fullName": "J", - "positionX": 832, - "positionY": 448, + "id": 8, + "betriebspunktName": "LTH", + "fullName": "Langenthal", + "positionX": 320, + "positionY": 192, "ports": [ - {"id": 12, "trainrunSectionId": 15, "positionIndex": 0, "positionAlignment": 0}, - {"id": 13, "trainrunSectionId": 16, "positionIndex": 1, "positionAlignment": 0} + {"id": 9, "trainrunSectionId": 1, "positionIndex": 0, "positionAlignment": 0}, + {"id": 3, "trainrunSectionId": 2, "positionIndex": 0, "positionAlignment": 2}, + {"id": 6, "trainrunSectionId": 3, "positionIndex": 1, "positionAlignment": 2}, + {"id": 10, "trainrunSectionId": 4, "positionIndex": 0, "positionAlignment": 3} ], - "transitions": [{"id": 5, "port1Id": 12, "port2Id": 13, "isNonStopTransit": false}], - "connections": [], - "resourceId": 5, - "perronkanten": 5, - "connectionTime": 3, - "trainrunCategoryHaltezeiten": { - "HaltezeitIPV": {"haltezeit": 3, "no_halt": false}, - "HaltezeitA": {"haltezeit": 2, "no_halt": false}, - "HaltezeitB": {"haltezeit": 2, "no_halt": false}, - "HaltezeitC": {"haltezeit": 1, "no_halt": false}, - "HaltezeitD": {"haltezeit": 1, "no_halt": false}, - "HaltezeitUncategorized": {"haltezeit": 0, "no_halt": true} - }, - "symmetryAxis": null, - "warnings": null, - "labelIds": [] - }, - { - "id": 7, - "betriebspunktName": "H", - "fullName": "H", - "positionX": 320, - "positionY": 32, - "ports": [{"id": 9, "trainrunSectionId": 14, "positionIndex": 0, "positionAlignment": 3}], - "transitions": [], + "transitions": [{"id": 3, "port1Id": 3, "port2Id": 9, "isNonStopTransit": false}], "connections": [], - "resourceId": 8, + "resourceId": 9, "perronkanten": 5, "connectionTime": 5, "trainrunCategoryHaltezeiten": { - "HaltezeitIPV": {"haltezeit": 3, "no_halt": false}, + "HaltezeitIPV": {"haltezeit": 2, "no_halt": false}, "HaltezeitA": {"haltezeit": 2, "no_halt": false}, "HaltezeitB": {"haltezeit": 2, "no_halt": false}, - "HaltezeitC": {"haltezeit": 1, "no_halt": false}, + "HaltezeitC": {"haltezeit": 1.5, "no_halt": false}, "HaltezeitD": {"haltezeit": 1, "no_halt": false}, "HaltezeitUncategorized": {"haltezeit": 0, "no_halt": true} }, @@ -297,18 +107,13 @@ ], "trainrunSections": [ { - "id": 6, - "sourceNodeId": 14, + "id": 1, + "sourceNodeId": 7, "sourcePortId": 11, - "targetNodeId": 12, - "targetPortId": 12, - "travelTime": { - "time": 2, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "targetNodeId": 8, + "targetPortId": 9, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 0, @@ -324,119 +129,65 @@ "timeFormatter": null }, "targetDeparture": { - "time": 58, - "consecutiveTime": 58, + "time": 50, + "consecutiveTime": 50, "lock": false, "warning": null, "timeFormatter": null }, "targetArrival": { - "time": 2, - "consecutiveTime": 2, + "time": 10, + "consecutiveTime": 10, "lock": false, "warning": null, "timeFormatter": null }, - "numberOfStops": 0, - "trainrunId": 4, - "resourceId": 0, - "specificTrainrunSectionFrequencyId": null, - "path": { - "path": [ - {"x": 898, "y": 880}, - {"x": 962, "y": 880}, - {"x": 1054, "y": 688}, - {"x": 1118, "y": 688} - ], - "textPositions": { - "0": {"x": 916, "y": 892}, - "1": {"x": 944, "y": 868}, - "2": {"x": 1100, "y": 676}, - "3": {"x": 1072, "y": 700}, - "4": {"x": 1008, "y": 772}, - "5": {"x": 1008, "y": 772}, - "6": {"x": 1008, "y": 796} - } - }, - "warnings": null - }, - { - "id": 7, - "sourceNodeId": 12, - "sourcePortId": 13, - "targetNodeId": 11, - "targetPortId": 14, "travelTime": { - "time": 4, - "consecutiveTime": 1, + "time": 10, + "consecutiveTime": 10, "lock": true, "warning": null, "timeFormatter": null }, - "sourceDeparture": { - "time": 3, - "consecutiveTime": 3, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "sourceArrival": { - "time": 57, - "consecutiveTime": 57, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetDeparture": { - "time": 53, - "consecutiveTime": 53, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetArrival": { - "time": 7, - "consecutiveTime": 7, - "lock": false, + "backwardTravelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, "warning": null, "timeFormatter": null }, "numberOfStops": 0, - "trainrunId": 4, + "trainrunId": 1, "resourceId": 0, "specificTrainrunSectionFrequencyId": null, "path": { "path": [ - {"x": 1218, "y": 688}, - {"x": 1282, "y": 688}, - {"x": 1470, "y": 880}, - {"x": 1534, "y": 880} + {"x": 336, "y": 98}, + {"x": 336, "y": 162}, + {"x": 336, "y": 126}, + {"x": 336, "y": 190} ], "textPositions": { - "0": {"x": 1236, "y": 700}, - "1": {"x": 1264, "y": 676}, - "2": {"x": 1516, "y": 868}, - "3": {"x": 1488, "y": 892}, - "4": {"x": 1376, "y": 772}, - "5": {"x": 1376, "y": 772}, - "6": {"x": 1376, "y": 796} + "0": {"x": 324, "y": 116}, + "1": {"x": 348, "y": 144}, + "2": {"x": 348, "y": 172}, + "3": {"x": 324, "y": 144}, + "4": {"x": 324, "y": 144}, + "5": {"x": 324, "y": 144}, + "6": {"x": 348, "y": 144}, + "7": {"x": 348, "y": 144} } }, "warnings": null }, { - "id": 8, - "sourceNodeId": 11, - "sourcePortId": 15, - "targetNodeId": 14, - "targetPortId": 16, - "travelTime": { - "time": 6, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "id": 2, + "sourceNodeId": 8, + "sourcePortId": 3, + "targetNodeId": 0, + "targetPortId": 4, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 60, @@ -451,70 +202,6 @@ "warning": null, "timeFormatter": null }, - "targetDeparture": { - "time": 54, - "consecutiveTime": 54, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetArrival": { - "time": 6, - "consecutiveTime": 66, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "numberOfStops": 0, - "trainrunId": 5, - "resourceId": 0, - "specificTrainrunSectionFrequencyId": null, - "path": { - "path": [ - {"x": 1534, "y": 944}, - {"x": 1470, "y": 944}, - {"x": 962, "y": 912}, - {"x": 898, "y": 912} - ], - "textPositions": { - "0": {"x": 1516, "y": 932}, - "1": {"x": 1488, "y": 956}, - "2": {"x": 916, "y": 924}, - "3": {"x": 944, "y": 900}, - "4": {"x": 1216, "y": 916}, - "5": {"x": 1216, "y": 916}, - "6": {"x": 1216, "y": 940} - } - }, - "warnings": null - }, - { - "id": 9, - "sourceNodeId": 12, - "sourcePortId": 17, - "targetNodeId": 13, - "targetPortId": 18, - "travelTime": { - "time": 2, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, - "sourceDeparture": { - "time": 8, - "consecutiveTime": 8, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "sourceArrival": { - "time": 52, - "consecutiveTime": 52, - "lock": false, - "warning": null, - "timeFormatter": null - }, "targetDeparture": { "time": 50, "consecutiveTime": 50, @@ -524,542 +211,193 @@ }, "targetArrival": { "time": 10, - "consecutiveTime": 10, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "numberOfStops": 0, - "trainrunId": 6, - "resourceId": 0, - "specificTrainrunSectionFrequencyId": null, - "path": { - "path": [ - {"x": 1136, "y": 766}, - {"x": 1136, "y": 830}, - {"x": 1104, "y": 1022}, - {"x": 1104, "y": 1086} - ], - "textPositions": { - "0": {"x": 1124, "y": 784}, - "1": {"x": 1148, "y": 812}, - "2": {"x": 1116, "y": 1068}, - "3": {"x": 1092, "y": 1040}, - "4": {"x": 1108, "y": 926}, - "5": {"x": 1108, "y": 926}, - "6": {"x": 1132, "y": 926} - } - }, - "warnings": null - }, - { - "id": 10, - "sourceNodeId": 12, - "sourcePortId": 19, - "targetNodeId": 11, - "targetPortId": 20, - "travelTime": { - "time": 5, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, - "sourceDeparture": { - "time": 0, - "consecutiveTime": 0, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "sourceArrival": { - "time": 0, - "consecutiveTime": 60, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetDeparture": { - "time": 55, - "consecutiveTime": 55, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetArrival": { - "time": 5, - "consecutiveTime": 5, + "consecutiveTime": 70, "lock": false, "warning": null, "timeFormatter": null }, - "numberOfStops": 0, - "trainrunId": 7, - "resourceId": 0, - "specificTrainrunSectionFrequencyId": null, - "path": { - "path": [ - {"x": 1218, "y": 720}, - {"x": 1282, "y": 720}, - {"x": 1470, "y": 912}, - {"x": 1534, "y": 912} - ], - "textPositions": { - "0": {"x": 1236, "y": 732}, - "1": {"x": 1264, "y": 708}, - "2": {"x": 1516, "y": 900}, - "3": {"x": 1488, "y": 924}, - "4": {"x": 1376, "y": 804}, - "5": {"x": 1376, "y": 804}, - "6": {"x": 1376, "y": 828} - } - }, - "warnings": null - }, - { - "id": 11, - "sourceNodeId": 11, - "sourcePortId": 21, - "targetNodeId": 13, - "targetPortId": 22, "travelTime": { - "time": 4, - "consecutiveTime": 1, + "time": 10, + "consecutiveTime": 10, "lock": true, "warning": null, "timeFormatter": null }, - "sourceDeparture": { - "time": 5, - "consecutiveTime": 5, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "sourceArrival": { - "time": 55, - "consecutiveTime": 55, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetDeparture": { - "time": 51, - "consecutiveTime": 51, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetArrival": { - "time": 9, - "consecutiveTime": 9, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "numberOfStops": 0, - "trainrunId": 7, - "resourceId": 0, - "specificTrainrunSectionFrequencyId": null, - "path": { - "path": [ - {"x": 1534, "y": 976}, - {"x": 1470, "y": 976}, - {"x": 1250, "y": 1104}, - {"x": 1186, "y": 1104} - ], - "textPositions": { - "0": {"x": 1516, "y": 964}, - "1": {"x": 1488, "y": 988}, - "2": {"x": 1204, "y": 1116}, - "3": {"x": 1232, "y": 1092}, - "4": {"x": 1360, "y": 1028}, - "5": {"x": 1360, "y": 1028}, - "6": {"x": 1360, "y": 1052} - } - }, - "warnings": null - }, - { - "id": 12, - "sourceNodeId": 16, - "sourcePortId": 23, - "targetNodeId": 15, - "targetPortId": 24, - "travelTime": { - "time": 1, - "consecutiveTime": 1, + "backwardTravelTime": { + "time": 10, + "consecutiveTime": 10, "lock": true, "warning": null, "timeFormatter": null }, - "sourceDeparture": { - "time": 0, - "consecutiveTime": 120, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "sourceArrival": { - "time": 0, - "consecutiveTime": 60, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetDeparture": { - "time": 59, - "consecutiveTime": 59, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetArrival": { - "time": 1, - "consecutiveTime": 121, - "lock": false, - "warning": null, - "timeFormatter": null - }, "numberOfStops": 0, - "trainrunId": 8, + "trainrunId": 1, "resourceId": 0, "specificTrainrunSectionFrequencyId": null, "path": { "path": [ - {"x": 1694, "y": 1264}, - {"x": 1630, "y": 1264}, - {"x": 1634, "y": 1264}, - {"x": 1570, "y": 1264} + {"x": 318, "y": 208}, + {"x": 254, "y": 208}, + {"x": -30, "y": 48}, + {"x": -94, "y": 48} ], "textPositions": { - "0": {"x": 1676, "y": 1252}, - "1": {"x": 1648, "y": 1276}, - "2": {"x": 1588, "y": 1276}, - "3": {"x": 1616, "y": 1252}, - "4": {"x": 1632, "y": 1252}, - "5": {"x": 1632, "y": 1252}, - "6": {"x": 1632, "y": 1276} + "0": {"x": 300, "y": 196}, + "1": {"x": 272, "y": 220}, + "2": {"x": -76, "y": 60}, + "3": {"x": -48, "y": 36}, + "4": {"x": 112, "y": 116}, + "5": {"x": 112, "y": 116}, + "6": {"x": 112, "y": 140}, + "7": {"x": 112, "y": 140} } }, "warnings": null }, { - "id": 13, - "sourceNodeId": 17, - "sourcePortId": 26, - "targetNodeId": 16, - "targetPortId": 25, - "travelTime": { - "time": 1, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "id": 3, + "sourceNodeId": 0, + "sourcePortId": 5, + "targetNodeId": 8, + "targetPortId": 6, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { - "time": 57, - "consecutiveTime": 117, + "time": 12, + "consecutiveTime": 72, "lock": false, "warning": null, "timeFormatter": null }, "sourceArrival": { - "time": 3, - "consecutiveTime": 63, + "time": 48, + "consecutiveTime": 48, "lock": false, "warning": null, "timeFormatter": null }, "targetDeparture": { - "time": 2, - "consecutiveTime": 62, + "time": 38, + "consecutiveTime": 38, "lock": false, "warning": null, "timeFormatter": null }, "targetArrival": { - "time": 58, - "consecutiveTime": 118, + "time": 22, + "consecutiveTime": 82, "lock": false, "warning": null, "timeFormatter": null }, - "numberOfStops": 0, - "trainrunId": 8, - "resourceId": 0, - "specificTrainrunSectionFrequencyId": null, - "path": { - "path": [ - {"x": 1918, "y": 1264}, - {"x": 1854, "y": 1264}, - {"x": 1858, "y": 1264}, - {"x": 1794, "y": 1264} - ], - "textPositions": { - "0": {"x": 1900, "y": 1252}, - "1": {"x": 1872, "y": 1276}, - "2": {"x": 1812, "y": 1276}, - "3": {"x": 1840, "y": 1252}, - "4": {"x": 1856, "y": 1252}, - "5": {"x": 1856, "y": 1252}, - "6": {"x": 1856, "y": 1276} - } - }, - "warnings": null - }, - { - "id": 14, - "sourceNodeId": 7, - "sourcePortId": 9, - "targetNodeId": 1, - "targetPortId": 10, "travelTime": { - "time": 1, - "consecutiveTime": 1, + "time": 10, + "consecutiveTime": 10, "lock": true, "warning": null, "timeFormatter": null }, - "sourceDeparture": { - "time": 0, - "consecutiveTime": 0, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "sourceArrival": { - "time": 0, - "consecutiveTime": 180, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetDeparture": { - "time": 59, - "consecutiveTime": 179, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetArrival": { - "time": 1, - "consecutiveTime": 1, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "numberOfStops": 0, - "trainrunId": 2, - "resourceId": 0, - "specificTrainrunSectionFrequencyId": null, - "path": { - "path": [ - {"x": 418, "y": 48}, - {"x": 482, "y": 48}, - {"x": 766, "y": 48}, - {"x": 830, "y": 48} - ], - "textPositions": { - "0": {"x": 436, "y": 60}, - "1": {"x": 464, "y": 36}, - "2": {"x": 812, "y": 36}, - "3": {"x": 784, "y": 60}, - "4": {"x": 624, "y": 36}, - "5": {"x": 624, "y": 36}, - "6": {"x": 624, "y": 60} - } - }, - "warnings": null - }, - { - "id": 15, - "sourceNodeId": 1, - "sourcePortId": 11, - "targetNodeId": 4, - "targetPortId": 12, - "travelTime": { - "time": 5, - "consecutiveTime": 1, + "backwardTravelTime": { + "time": 10, + "consecutiveTime": 10, "lock": true, "warning": null, "timeFormatter": null }, - "sourceDeparture": { - "time": 3, - "consecutiveTime": 3, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "sourceArrival": { - "time": 57, - "consecutiveTime": 177, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetDeparture": { - "time": 52, - "consecutiveTime": 172, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetArrival": { - "time": 8, - "consecutiveTime": 8, - "lock": false, - "warning": null, - "timeFormatter": null - }, "numberOfStops": 0, - "trainrunId": 2, + "trainrunId": 1, "resourceId": 0, "specificTrainrunSectionFrequencyId": null, "path": { "path": [ - {"x": 848, "y": 98}, - {"x": 848, "y": 162}, - {"x": 848, "y": 382}, - {"x": 848, "y": 446} + {"x": -94, "y": 80}, + {"x": -30, "y": 80}, + {"x": 254, "y": 240}, + {"x": 318, "y": 240} ], "textPositions": { - "0": {"x": 836, "y": 116}, - "1": {"x": 860, "y": 144}, - "2": {"x": 860, "y": 428}, - "3": {"x": 836, "y": 400}, - "4": {"x": 836, "y": 272}, - "5": {"x": 836, "y": 272}, - "6": {"x": 860, "y": 272} + "0": {"x": -76, "y": 92}, + "1": {"x": -48, "y": 68}, + "2": {"x": 300, "y": 228}, + "3": {"x": 272, "y": 252}, + "4": {"x": 112, "y": 148}, + "5": {"x": 112, "y": 148}, + "6": {"x": 112, "y": 172}, + "7": {"x": 112, "y": 172} } }, "warnings": null }, { - "id": 16, - "sourceNodeId": 4, - "sourcePortId": 13, + "id": 4, + "sourceNodeId": 8, + "sourcePortId": 10, "targetNodeId": 1, - "targetPortId": 14, - "travelTime": { - "time": 1, - "consecutiveTime": 1, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "targetPortId": 8, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { - "time": 6, - "consecutiveTime": 66, + "time": 2, + "consecutiveTime": 62, "lock": false, "warning": null, "timeFormatter": null }, "sourceArrival": { - "time": 54, - "consecutiveTime": 114, + "time": 58, + "consecutiveTime": 118, "lock": false, "warning": null, "timeFormatter": null }, "targetDeparture": { - "time": 53, - "consecutiveTime": 113, + "time": 48, + "consecutiveTime": 108, "lock": false, "warning": null, "timeFormatter": null }, "targetArrival": { - "time": 7, - "consecutiveTime": 67, + "time": 12, + "consecutiveTime": 72, "lock": false, "warning": null, "timeFormatter": null }, - "numberOfStops": 0, - "trainrunId": 2, - "resourceId": 0, - "specificTrainrunSectionFrequencyId": null, - "path": { - "path": [ - {"x": 880, "y": 446}, - {"x": 880, "y": 382}, - {"x": 880, "y": 162}, - {"x": 880, "y": 98} - ], - "textPositions": { - "0": {"x": 892, "y": 428}, - "1": {"x": 868, "y": 400}, - "2": {"x": 868, "y": 116}, - "3": {"x": 892, "y": 144}, - "4": {"x": 868, "y": 272}, - "5": {"x": 868, "y": 272}, - "6": {"x": 892, "y": 272} - } - }, - "warnings": null - }, - { - "id": 17, - "sourceNodeId": 1, - "sourcePortId": 15, - "targetNodeId": 2, - "targetPortId": 16, "travelTime": { - "time": 1, - "consecutiveTime": 1, + "time": 10, + "consecutiveTime": 10, "lock": true, "warning": null, "timeFormatter": null }, - "sourceDeparture": { - "time": 9, - "consecutiveTime": 69, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "sourceArrival": { - "time": 51, - "consecutiveTime": 111, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetDeparture": { - "time": 50, - "consecutiveTime": 110, - "lock": false, - "warning": null, - "timeFormatter": null - }, - "targetArrival": { + "backwardTravelTime": { "time": 10, - "consecutiveTime": 70, - "lock": false, + "consecutiveTime": 10, + "lock": true, "warning": null, "timeFormatter": null }, "numberOfStops": 0, - "trainrunId": 2, + "trainrunId": 1, "resourceId": 0, "specificTrainrunSectionFrequencyId": null, "path": { "path": [ - {"x": 930, "y": 48}, - {"x": 994, "y": 48}, - {"x": 1566, "y": 48}, - {"x": 1630, "y": 48} + {"x": 418, "y": 240}, + {"x": 482, "y": 240}, + {"x": 766, "y": 80}, + {"x": 830, "y": 80} ], "textPositions": { - "0": {"x": 948, "y": 60}, - "1": {"x": 976, "y": 36}, - "2": {"x": 1612, "y": 36}, - "3": {"x": 1584, "y": 60}, - "4": {"x": 1280, "y": 36}, - "5": {"x": 1280, "y": 36}, - "6": {"x": 1280, "y": 60} + "0": {"x": 436, "y": 252}, + "1": {"x": 464, "y": 228}, + "2": {"x": 812, "y": 68}, + "3": {"x": 784, "y": 92}, + "4": {"x": 624, "y": 148}, + "5": {"x": 624, "y": 148}, + "6": {"x": 624, "y": 172}, + "7": {"x": 624, "y": 172} } }, "warnings": null @@ -1067,52 +405,7 @@ ], "trainruns": [ { - "id": 4, - "name": "1", - "categoryId": 1, - "frequencyId": 3, - "trainrunTimeCategoryId": 0, - "labelIds": [], - "direction": "round_trip" - }, - { - "id": 5, - "name": "2", - "categoryId": 3, - "frequencyId": 2, - "trainrunTimeCategoryId": 0, - "labelIds": [], - "direction": "round_trip" - }, - { - "id": 6, - "name": "4", - "categoryId": 6, - "frequencyId": 3, - "trainrunTimeCategoryId": 0, - "labelIds": [], - "direction": "round_trip" - }, - { - "id": 7, - "name": "3", - "categoryId": 5, - "frequencyId": 0, - "trainrunTimeCategoryId": 0, - "labelIds": [], - "direction": "round_trip" - }, - { - "id": 8, - "name": "X", - "categoryId": 1, - "frequencyId": 3, - "trainrunTimeCategoryId": 0, - "labelIds": [], - "direction": "round_trip" - }, - { - "id": 2, + "id": 1, "name": "X", "categoryId": 1, "frequencyId": 3, @@ -1124,24 +417,11 @@ "resources": [ {"id": 1, "capacity": 2}, {"id": 2, "capacity": 2}, - {"id": 3, "capacity": 2}, - {"id": 4, "capacity": 2}, - {"id": 5, "capacity": 2}, - {"id": 6, "capacity": 2}, - {"id": 7, "capacity": 2}, {"id": 8, "capacity": 2}, - {"id": 9, "capacity": 2}, - {"id": 10, "capacity": 2}, - {"id": 11, "capacity": 2}, - {"id": 12, "capacity": 2}, - {"id": 13, "capacity": 2}, - {"id": 14, "capacity": 2}, - {"id": 15, "capacity": 2}, - {"id": 16, "capacity": 2}, - {"id": 17, "capacity": 2}, - {"id": 18, "capacity": 2} + {"id": 9, "capacity": 2} ], "metadata": { + "analyticsSettings": {"originDestinationSettings": {"connectionPenalty": 5}}, "trainrunCategories": [ { "id": 0, @@ -1271,16 +551,7 @@ "frequency": 120, "offset": 0, "shortName": "120", - "name": "verkehrt zweistündlich (gerade)", - "linePatternRef": "120" - }, - { - "id": 5, - "order": 0, - "frequency": 120, - "offset": 60, - "shortName": "120+", - "name": "verkehrt zweistündlich (ungerade)", + "name": "verkehrt zweistündlich", "linePatternRef": "120" } ], @@ -1318,7 +589,7 @@ ], "netzgrafikColors": [ { - "id": 8, + "id": 5, "colorRef": "NORMAL", "color": "#767676", "colorFocus": "#000000", @@ -1329,8 +600,7 @@ "colorDarkModeMuted": "#000000", "colorDarkModeRelated": "#767676" } - ], - "analyticsSettings": {"originDestinationSettings": {"connectionPenalty": 5}} + ] }, "freeFloatingTexts": [], "labels": [], diff --git a/src/integration-testing/test-data/testTransitionNetzgrafik.json b/src/integration-testing/test-data/testTransitionNetzgrafik.json index 1a2239fea..288e5785c 100644 --- a/src/integration-testing/test-data/testTransitionNetzgrafik.json +++ b/src/integration-testing/test-data/testTransitionNetzgrafik.json @@ -128,13 +128,8 @@ "sourcePortId": 97, "targetNodeId": 1, "targetPortId": 188, - "travelTime": { - "time": 10, - "consecutiveTime": 10, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 48, "consecutiveTime": 48, @@ -163,6 +158,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 6, "resourceId": 0, @@ -181,7 +190,8 @@ "3": {"x": 816, "y": 476}, "4": {"x": 640, "y": 372}, "5": {"x": 640, "y": 372}, - "6": {"x": 640, "y": 396} + "6": {"x": 640, "y": 396}, + "7": {"x": 640, "y": 396} } }, "warnings": null @@ -192,13 +202,8 @@ "sourcePortId": 70, "targetNodeId": 1, "targetPortId": 155, - "travelTime": { - "time": 10, - "consecutiveTime": 10, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 0, @@ -230,6 +235,20 @@ "warning": {"title": "Symétrie brisée", "description": "10 + 51 = 61"}, "timeFormatter": null }, + "travelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 7, "resourceId": 0, @@ -248,7 +267,8 @@ "3": {"x": 816, "y": 508}, "4": {"x": 640, "y": 404}, "5": {"x": 640, "y": 404}, - "6": {"x": 640, "y": 428} + "6": {"x": 640, "y": 428}, + "7": {"x": 640, "y": 428} } }, "warnings": null @@ -259,13 +279,8 @@ "sourcePortId": 99, "targetNodeId": 1, "targetPortId": 147, - "travelTime": { - "time": 9, - "consecutiveTime": 10, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 49, "consecutiveTime": 109, @@ -297,6 +312,20 @@ "warning": {"title": "Symétrie brisée", "description": "58 + 3 = 61"}, "timeFormatter": null }, + "travelTime": { + "time": 9, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 9, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 8, "resourceId": 0, @@ -315,7 +344,8 @@ "3": {"x": 1008, "y": 548}, "4": {"x": 1200, "y": 452}, "5": {"x": 1200, "y": 452}, - "6": {"x": 1200, "y": 476} + "6": {"x": 1200, "y": 452}, + "7": {"x": 1200, "y": 476} } }, "warnings": null @@ -326,13 +356,8 @@ "sourcePortId": 82, "targetNodeId": 1, "targetPortId": 151, - "travelTime": { - "time": 10, - "consecutiveTime": 10, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 120, @@ -364,6 +389,20 @@ "warning": {"title": "Symétrie brisée", "description": "10 + 51 = 61"}, "timeFormatter": null }, + "travelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 10, "resourceId": 0, @@ -382,7 +421,8 @@ "3": {"x": 1008, "y": 516}, "4": {"x": 1200, "y": 420}, "5": {"x": 1200, "y": 420}, - "6": {"x": 1200, "y": 444} + "6": {"x": 1200, "y": 444}, + "7": {"x": 1200, "y": 444} } }, "warnings": null @@ -393,13 +433,8 @@ "sourcePortId": 148, "targetNodeId": 5, "targetPortId": 146, - "travelTime": { - "time": 8, - "consecutiveTime": 10, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 120, @@ -428,6 +463,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 8, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 8, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 8, "resourceId": 0, @@ -446,7 +495,8 @@ "3": {"x": 464, "y": 388}, "4": {"x": 640, "y": 468}, "5": {"x": 640, "y": 468}, - "6": {"x": 640, "y": 492} + "6": {"x": 640, "y": 492}, + "7": {"x": 640, "y": 492} } }, "warnings": null @@ -457,13 +507,8 @@ "sourcePortId": 152, "targetNodeId": 5, "targetPortId": 150, - "travelTime": { - "time": 9, - "consecutiveTime": 10, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 13, "consecutiveTime": 133, @@ -492,6 +537,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 9, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 9, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 10, "resourceId": 0, @@ -510,7 +569,8 @@ "3": {"x": 464, "y": 356}, "4": {"x": 640, "y": 436}, "5": {"x": 640, "y": 436}, - "6": {"x": 640, "y": 460} + "6": {"x": 640, "y": 460}, + "7": {"x": 640, "y": 460} } }, "warnings": null @@ -521,13 +581,8 @@ "sourcePortId": 156, "targetNodeId": 4, "targetPortId": 154, - "travelTime": { - "time": 9, - "consecutiveTime": 10, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 13, "consecutiveTime": 13, @@ -556,6 +611,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 9, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 9, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 7, "resourceId": 0, @@ -574,7 +643,8 @@ "3": {"x": 1392, "y": 316}, "4": {"x": 1200, "y": 388}, "5": {"x": 1200, "y": 388}, - "6": {"x": 1200, "y": 412} + "6": {"x": 1200, "y": 412}, + "7": {"x": 1200, "y": 412} } }, "warnings": null @@ -585,13 +655,8 @@ "sourcePortId": 189, "targetNodeId": 4, "targetPortId": 185, - "travelTime": { - "time": 10, - "consecutiveTime": 10, - "lock": true, - "warning": null, - "timeFormatter": null - }, + "sourceSymmetry": true, + "targetSymmetry": true, "sourceDeparture": { "time": 0, "consecutiveTime": 60, @@ -620,6 +685,20 @@ "warning": null, "timeFormatter": null }, + "travelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, + "backwardTravelTime": { + "time": 10, + "consecutiveTime": 10, + "lock": true, + "warning": null, + "timeFormatter": null + }, "numberOfStops": 0, "trainrunId": 6, "resourceId": 0, @@ -638,7 +717,8 @@ "3": {"x": 1392, "y": 284}, "4": {"x": 1200, "y": 356}, "5": {"x": 1200, "y": 356}, - "6": {"x": 1200, "y": 380} + "6": {"x": 1200, "y": 380}, + "7": {"x": 1200, "y": 380} } }, "warnings": null @@ -683,19 +763,10 @@ } ], "resources": [ - {"id": 1, "capacity": 2}, {"id": 2, "capacity": 2}, - {"id": 3, "capacity": 2}, - {"id": 4, "capacity": 2}, {"id": 5, "capacity": 2}, {"id": 6, "capacity": 2}, - {"id": 7, "capacity": 2}, - {"id": 8, "capacity": 2}, - {"id": 9, "capacity": 2}, - {"id": 10, "capacity": 2}, - {"id": 11, "capacity": 2}, - {"id": 12, "capacity": 2}, - {"id": 13, "capacity": 2} + {"id": 12, "capacity": 2} ], "metadata": { "analyticsSettings": {"originDestinationSettings": {"connectionPenalty": 5}}, diff --git a/src/integration-testing/trainrunsection.service.test.spec.ts b/src/integration-testing/trainrunsection.service.test.spec.ts index 21e4aa94f..78a700f3c 100644 --- a/src/integration-testing/trainrunsection.service.test.spec.ts +++ b/src/integration-testing/trainrunsection.service.test.spec.ts @@ -203,7 +203,7 @@ describe("TrainrunSection Service Test", () => { it("update trainrunSection time test", () => { dataService.loadNetzgrafikDto(NetzgrafikUnitTesting.getUnitTestNetzgrafik()); - trainrunSectionService.updateTrainrunSectionTime(0, 58, 2, 12, 48, 10); + trainrunSectionService.updateTrainrunSectionTime(0, 58, 2, 12, 48, 10, 10); const trainrunSection = trainrunSectionService.getTrainrunSectionFromId(0); expect(trainrunSection.getSourceArrival()).toBe(58); @@ -215,9 +215,9 @@ describe("TrainrunSection Service Test", () => { it("propagate time test", () => { dataService.loadNetzgrafikDto(NetzgrafikUnitTesting.getUnitTestNetzgrafik()); - trainrunSectionService.updateTrainrunSectionTime(0, 58, 2, 12, 48, 10); - trainrunSectionService.propagateTimeAlongTrainrun(0, 0); - trainrunSectionService.propagateTimeAlongTrainrun(0, 1); + trainrunSectionService.updateTrainrunSectionTime(0, 58, 2, 12, 48, 10, 10); + trainrunSectionService.propagateTimes(0, true, 0, false); + trainrunSectionService.propagateTimes(0, true, 1, false); // TODO: fix const trainrunSection = trainrunSectionService.getTrainrunSectionFromId(1); expect(trainrunSection.getSourceArrival()).toBe(46);