From d35c68ff8b11b96a2b14c97ec0ad70bdc41a7cca Mon Sep 17 00:00:00 2001 From: Louis Greiner Date: Fri, 29 Aug 2025 16:35:13 +0200 Subject: [PATCH 01/40] asymmetry: introduce TrainrunSection asymmetric attributes Getters and setters will be usefull later. Also fixed the associated tests, which updated other fields (like resources) that have been forgotten to be updated by 'fix: Resource deletion when node gets deleted'. Signed-off-by: Louis Greiner --- .../business.data.structures.ts | 5 +- src/app/models/trainrun.model.ts | 2 +- src/app/models/trainrunsection.model.spec.ts | 13 + src/app/models/trainrunsection.model.ts | 129 +- src/app/sample-netzgrafik/Demo_OL_LZ.json | 235 +- .../netzgrafik_demo_standalone_github.json | 4764 ++++++++++++----- .../services/data/trainrunsection.service.ts | 12 + .../data-views/data.view.spec.ts | 4 +- .../reconnect.trainrunsections.test.spec.ts | 30 +- .../test-data/testNetzgrafik.json | 206 +- .../test-data/testNetzgrafikOdMatrix.json | 283 +- ...estReconnectTrainrunSectionNetzgrafik.json | 1062 +--- .../test-data/testTransitionNetzgrafik.json | 195 +- .../trainrunsection.service.test.spec.ts | 4 +- 14 files changed, 4290 insertions(+), 2654 deletions(-) diff --git a/src/app/data-structures/business.data.structures.ts b/src/app/data-structures/business.data.structures.ts index 665a51f38..fc47211b1 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) 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..42ea533a1 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,40 @@ 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 { + return this.travelTime.time === this.backwardTravelTime.time; + } + getSourceArrivalDto(): TimeLockDto { return this.sourceArrival; } @@ -277,6 +345,10 @@ export class TrainrunSection { return this.travelTime; } + getBackwardTravelTimeDto(): TimeLockDto { + return this.backwardTravelTime; + } + getId(): number { return this.id; } @@ -285,6 +357,10 @@ export class TrainrunSection { return this.travelTime.time; } + getBackwardTravelTime(): number { + return this.backwardTravelTime.time; + } + getSourceDeparture(): number { return this.sourceDeparture.time; } @@ -305,6 +381,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 +405,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 +429,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 +453,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 +482,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 +511,10 @@ export class TrainrunSection { return this.travelTime.lock; } + getBackwardTravelTimeLock(): boolean { + return this.backwardTravelTime.lock; + } + getSourceDepartureLock(): boolean { return this.sourceDeparture.lock; } @@ -434,6 +535,10 @@ export class TrainrunSection { this.travelTime.lock = lock; } + setBackwardTravelTimeLock(lock: boolean) { + this.backwardTravelTime.lock = lock; + } + setSourceDepartureLock(lock: boolean) { this.sourceDeparture.lock = lock; } @@ -458,6 +563,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 +618,13 @@ export class TrainrunSection { }; } + setBackwardTravelTimeWarning(warningTitle: string, warningDescription: string) { + this.backwardTravelTime.warning = { + title: warningTitle, + description: warningDescription, + }; + } + getTargetArrivalWarning() { return this.targetArrival.warning; } @@ -529,6 +645,10 @@ export class TrainrunSection { return this.travelTime.warning; } + getBackwardTravelTimeWarning() { + return this.backwardTravelTime.warning; + } + resetTargetArrivalWarning() { this.targetArrival.warning = null; } @@ -549,6 +669,10 @@ export class TrainrunSection { this.travelTime.warning = null; } + resetBackwardTravelTimeWarning() { + this.backwardTravelTime.warning = null; + } + getTrainrunId(): number { return this.trainrunId; } @@ -651,12 +775,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/sample-netzgrafik/Demo_OL_LZ.json b/src/app/sample-netzgrafik/Demo_OL_LZ.json index 43896df87..47253ce3a 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, @@ -402,11 +405,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, @@ -436,11 +442,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, @@ -470,11 +479,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, @@ -504,11 +516,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, @@ -538,11 +553,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, @@ -572,11 +590,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, @@ -606,11 +627,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, @@ -640,11 +664,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, @@ -674,11 +701,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, @@ -708,11 +738,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, @@ -742,11 +775,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, @@ -776,11 +812,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, @@ -810,11 +849,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, @@ -844,11 +886,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, @@ -878,11 +923,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, @@ -912,11 +960,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, @@ -946,11 +997,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, @@ -980,11 +1034,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, @@ -1014,11 +1071,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, @@ -1048,11 +1108,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, @@ -1082,11 +1145,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, @@ -1116,11 +1182,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, @@ -1150,11 +1219,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, @@ -1184,11 +1256,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, @@ -1218,11 +1293,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, @@ -1252,11 +1330,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, @@ -1286,11 +1367,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, @@ -1320,11 +1404,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, @@ -1354,11 +1441,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, @@ -1388,11 +1478,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, @@ -1422,11 +1515,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, @@ -1456,11 +1552,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, @@ -1490,11 +1589,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, @@ -1524,11 +1626,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, @@ -1558,11 +1663,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, @@ -1592,11 +1700,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, @@ -1626,11 +1737,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, @@ -1660,11 +1774,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, @@ -1694,11 +1811,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, @@ -1728,11 +1848,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, @@ -1762,11 +1885,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, @@ -1796,11 +1922,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, @@ -1830,11 +1959,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, @@ -1864,11 +1996,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, @@ -1898,11 +2033,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, @@ -1932,11 +2070,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, diff --git a/src/app/sample-netzgrafik/netzgrafik_demo_standalone_github.json b/src/app/sample-netzgrafik/netzgrafik_demo_standalone_github.json index 4b384c6b5..69a7fce7c 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, @@ -1958,13 +1967,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 +1997,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, @@ -2022,13 +2040,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 +2070,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, @@ -2086,13 +2113,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 +2143,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, @@ -2150,13 +2186,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 +2216,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, @@ -2214,13 +2259,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 +2289,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, @@ -2278,13 +2332,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 +2362,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, @@ -2342,13 +2405,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 +2435,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, @@ -2406,13 +2478,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 +2508,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, @@ -2470,13 +2551,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 +2581,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, @@ -2534,13 +2624,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 +2654,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, @@ -2598,13 +2697,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 +2727,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, @@ -2662,13 +2770,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 +2800,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": { @@ -2726,13 +2843,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 +2873,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, @@ -2790,13 +2916,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 +2946,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, @@ -2854,13 +2989,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 +3019,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, @@ -2918,13 +3062,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 +3092,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, @@ -2982,13 +3135,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 +3165,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, @@ -3046,13 +3208,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 +3238,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, @@ -3110,13 +3281,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 +3311,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, @@ -3174,13 +3354,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 +3384,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, @@ -3238,13 +3427,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 +3457,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, @@ -3302,13 +3500,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 +3530,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, @@ -3366,13 +3573,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 +3603,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, @@ -3430,13 +3646,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 +3676,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, @@ -3494,13 +3719,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 +3749,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, @@ -3558,13 +3792,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 +3822,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, @@ -3619,16 +3862,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 +3895,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, @@ -3686,13 +3938,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 +3968,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, @@ -3750,13 +4011,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 +4041,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, @@ -3814,13 +4084,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 +4114,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, @@ -3878,13 +4157,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 +4187,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, @@ -3942,13 +4230,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 +4260,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, @@ -4006,13 +4303,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 +4333,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, @@ -4070,13 +4376,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 +4406,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, @@ -4134,13 +4449,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 +4479,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, @@ -4198,13 +4522,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 +4552,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, @@ -4262,13 +4595,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 +4625,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, @@ -4326,13 +4668,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 +4698,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, @@ -4390,13 +4741,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 +4764,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, @@ -4454,13 +4814,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 +4844,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, @@ -4518,13 +4887,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 +4917,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, @@ -4582,13 +4960,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 +4990,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, @@ -4646,13 +5033,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 +5063,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, @@ -4710,13 +5106,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 +5136,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, @@ -4774,13 +5179,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 +5209,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, @@ -4838,13 +5252,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 +5282,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, @@ -4902,13 +5325,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 +5355,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, @@ -4966,13 +5398,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 +5428,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, @@ -5030,13 +5471,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 +5501,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, @@ -5094,13 +5544,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 +5574,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, @@ -5158,13 +5617,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 +5647,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, @@ -5219,16 +5687,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 +5720,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, @@ -5286,13 +5763,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 +5793,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, @@ -5350,13 +5836,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 +5866,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, @@ -5414,13 +5909,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 +5939,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, @@ -5478,13 +5982,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 +6012,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, @@ -5542,13 +6055,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 +6085,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, @@ -5606,13 +6128,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 +6158,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, @@ -5670,13 +6201,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 +6231,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, @@ -5734,13 +6274,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 +6304,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, @@ -5798,13 +6347,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 +6377,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, @@ -5862,13 +6420,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 +6450,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, @@ -5926,13 +6493,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 +6523,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, @@ -5990,13 +6566,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 +6596,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, @@ -6054,13 +6639,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 +6669,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, @@ -6118,13 +6712,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 +6742,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, @@ -6182,13 +6785,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 +6815,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, @@ -6246,13 +6858,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 +6888,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, @@ -6310,13 +6931,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 +6961,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, @@ -6374,13 +7004,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 +7040,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, @@ -6444,13 +7083,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 +7113,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, @@ -6508,13 +7156,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 +7186,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, @@ -6572,13 +7229,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 +7259,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, @@ -6636,13 +7302,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 +7332,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, @@ -6700,13 +7375,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 +7405,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, @@ -6764,13 +7448,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 +7478,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, @@ -6828,13 +7521,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 +7549,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, @@ -6892,13 +7594,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 +7624,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, @@ -6956,13 +7667,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 +7697,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, @@ -7020,13 +7740,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 +7770,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, @@ -7084,13 +7813,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 +7843,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, @@ -7148,13 +7886,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 +7916,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, @@ -7212,13 +7959,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 +7989,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, @@ -7276,13 +8032,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 +8062,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, @@ -7340,13 +8105,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 +8135,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, @@ -7404,13 +8178,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 +8208,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, @@ -7468,13 +8251,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 +8281,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, @@ -7532,13 +8324,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 +8354,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, @@ -7596,13 +8397,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 +8427,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, @@ -7657,16 +8467,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 +8500,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, @@ -7724,13 +8543,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 +8573,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, @@ -7788,13 +8616,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 +8646,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, @@ -7852,13 +8689,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 +8719,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, @@ -7916,13 +8762,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 +8792,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, @@ -7980,13 +8835,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 +8865,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, @@ -8044,13 +8908,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 +8938,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, @@ -8108,13 +8981,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 +9011,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, @@ -8172,13 +9054,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 +9084,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, @@ -8236,13 +9127,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 +9157,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, @@ -8300,13 +9200,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 +9230,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, @@ -8364,13 +9273,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 +9303,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, @@ -8428,13 +9346,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 +9376,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, @@ -8492,13 +9419,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 +9449,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, @@ -8556,13 +9492,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 +9522,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, @@ -8620,13 +9565,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 +9595,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, @@ -8684,13 +9638,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 +9668,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, @@ -8748,13 +9711,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 +9741,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, @@ -8812,13 +9784,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 +9814,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, @@ -8876,13 +9857,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 +9887,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, @@ -8940,13 +9930,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 +9960,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, @@ -9004,13 +10003,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 +10033,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, @@ -9068,13 +10076,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 +10106,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, @@ -9132,13 +10149,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 +10179,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, @@ -9196,13 +10222,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 +10252,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, @@ -9260,13 +10295,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 +10323,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, @@ -9324,13 +10368,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 +10398,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, @@ -9388,13 +10441,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 +10471,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, @@ -9452,13 +10514,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 +10544,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, @@ -9516,13 +10587,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 +10617,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, @@ -9580,13 +10660,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 +10690,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, @@ -9644,13 +10733,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 +10763,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, @@ -9708,13 +10806,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 +10836,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, @@ -9772,13 +10879,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 +10909,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, @@ -9836,13 +10952,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 +10982,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, @@ -9900,13 +11025,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 +11055,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, @@ -9964,13 +11098,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 +11128,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, @@ -10028,13 +11171,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 +11201,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, @@ -10089,16 +11241,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 +11274,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, @@ -10156,13 +11317,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 +11347,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, @@ -10220,13 +11390,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 +11420,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, @@ -10284,13 +11463,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 +11493,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, @@ -10348,13 +11536,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 +11566,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, @@ -10412,13 +11609,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 +11639,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, @@ -10476,13 +11682,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 +11712,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, @@ -10540,13 +11755,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 +11785,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, @@ -10604,13 +11828,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 +11858,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, @@ -10668,13 +11901,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 +11931,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, @@ -10732,13 +11974,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 +12004,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, @@ -10796,13 +12047,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 +12077,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, @@ -10860,13 +12120,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 +12150,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, @@ -10924,13 +12193,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 +12223,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, @@ -10988,13 +12266,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 +12296,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, @@ -11052,13 +12339,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 +12369,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, @@ -11116,13 +12412,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 +12442,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, @@ -11180,13 +12485,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 +12515,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, @@ -11244,13 +12558,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 +12588,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, @@ -11308,13 +12631,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 +12661,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, @@ -11372,13 +12704,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 +12734,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, @@ -11436,13 +12777,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 +12807,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, @@ -11500,13 +12850,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 +12880,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, @@ -11564,13 +12923,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 +12953,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, @@ -11628,13 +12996,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 +13026,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, @@ -11692,13 +13069,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 +13097,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, @@ -11756,13 +13142,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 +13172,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, @@ -11820,13 +13215,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 +13245,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, @@ -11884,13 +13288,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 +13318,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, @@ -11948,13 +13361,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 +13391,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, @@ -12012,13 +13434,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 +13464,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, @@ -12076,13 +13507,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 +13537,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, @@ -12140,13 +13580,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 +13610,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, @@ -12204,13 +13653,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 +13683,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, @@ -12268,13 +13726,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 +13756,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, @@ -12332,13 +13799,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 +13829,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, @@ -12396,13 +13872,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 +13902,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, @@ -12460,13 +13945,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 +13975,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, @@ -12521,16 +14015,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 +14048,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, @@ -12588,13 +14091,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 +14121,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, @@ -12652,13 +14164,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 +14194,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, @@ -12716,13 +14237,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 +14267,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, @@ -12780,13 +14310,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 +14340,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, @@ -12844,13 +14383,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 +14413,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, @@ -12908,13 +14456,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 +14486,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, @@ -12972,13 +14529,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 +14559,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, @@ -13036,13 +14602,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 +14632,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, @@ -13100,13 +14675,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 +14705,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, @@ -13164,13 +14748,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 +14778,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, @@ -13228,13 +14821,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 +14851,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, @@ -13292,13 +14894,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 +14917,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, @@ -13356,13 +14967,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 +14997,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, @@ -13420,13 +15040,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 +15070,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, @@ -13484,13 +15113,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 +15143,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, @@ -13548,13 +15186,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 +15216,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, @@ -13612,13 +15259,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 +15289,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, @@ -13676,13 +15332,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 +15362,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, @@ -13740,13 +15405,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 +15435,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, @@ -13804,13 +15478,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 +15508,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, @@ -13868,13 +15551,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 +15581,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, @@ -13932,13 +15624,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 +15654,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, @@ -13996,13 +15697,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 +15727,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, @@ -14060,13 +15770,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 +15800,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, @@ -14121,16 +15840,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 +15873,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, @@ -14188,13 +15916,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 +15946,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, @@ -14252,13 +15989,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 +16019,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, @@ -14316,13 +16062,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 +16092,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, @@ -14380,13 +16135,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 +16165,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, @@ -14444,13 +16208,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 +16238,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, @@ -14508,13 +16281,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 +16311,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, @@ -14572,13 +16354,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 +16390,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, @@ -14642,13 +16433,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 +16463,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, @@ -14706,13 +16506,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 +16536,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, @@ -14770,13 +16579,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 +16609,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, @@ -14834,13 +16652,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 +16682,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, @@ -14898,13 +16725,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 +16755,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, diff --git a/src/app/services/data/trainrunsection.service.ts b/src/app/services/data/trainrunsection.service.ts index 3ed3a2453..699f0d56b 100644 --- a/src/app/services/data/trainrunsection.service.ts +++ b/src/app/services/data/trainrunsection.service.ts @@ -1085,6 +1085,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 +1310,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( 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/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..b8094cbfc 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, @@ -217,13 +226,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 +256,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, @@ -281,13 +299,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 +329,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, @@ -345,13 +372,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 +402,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, @@ -409,13 +445,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 +475,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, @@ -473,13 +518,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 +548,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, @@ -537,13 +591,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 +621,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, @@ -601,13 +664,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 +694,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, @@ -708,11 +780,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 +955,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..c38ba450f 100644 --- a/src/integration-testing/test-data/testNetzgrafikOdMatrix.json +++ b/src/integration-testing/test-data/testNetzgrafikOdMatrix.json @@ -727,13 +727,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 +757,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, @@ -791,13 +800,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 +830,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, @@ -855,13 +873,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 +903,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, @@ -919,13 +946,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 +976,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, @@ -983,13 +1019,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 +1049,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, @@ -1047,13 +1092,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 +1122,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, @@ -1111,13 +1165,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 +1195,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, @@ -1175,13 +1238,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 +1268,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, @@ -1239,13 +1311,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 +1341,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, @@ -1303,13 +1384,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 +1414,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, @@ -1367,13 +1457,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 +1487,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, @@ -1431,13 +1530,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 +1560,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, @@ -1985,17 +2093,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}, diff --git a/src/integration-testing/test-data/testReconnectTrainrunSectionNetzgrafik.json b/src/integration-testing/test-data/testReconnectTrainrunSectionNetzgrafik.json index 46f13051d..e4a84164c 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,64 @@ "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} } }, "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 +201,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 +210,190 @@ }, "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} } }, "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} } }, "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} } }, "warnings": null @@ -1067,52 +401,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 +413,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 +547,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 +585,7 @@ ], "netzgrafikColors": [ { - "id": 8, + "id": 5, "colorRef": "NORMAL", "color": "#767676", "colorFocus": "#000000", @@ -1329,8 +596,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..f5cc69b62 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, @@ -192,13 +201,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 +234,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, @@ -259,13 +277,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 +310,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, @@ -326,13 +353,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 +386,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, @@ -393,13 +429,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 +459,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, @@ -457,13 +502,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 +532,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, @@ -521,13 +575,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 +605,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, @@ -585,13 +648,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 +678,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, @@ -683,19 +755,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..62f5672dc 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,7 +215,7 @@ describe("TrainrunSection Service Test", () => { it("propagate time test", () => { dataService.loadNetzgrafikDto(NetzgrafikUnitTesting.getUnitTestNetzgrafik()); - trainrunSectionService.updateTrainrunSectionTime(0, 58, 2, 12, 48, 10); + trainrunSectionService.updateTrainrunSectionTime(0, 58, 2, 12, 48, 10, 10); trainrunSectionService.propagateTimeAlongTrainrun(0, 0); trainrunSectionService.propagateTimeAlongTrainrun(0, 1); From 8de21523d09b9d1b41b0aa0bac681a2bc49f910a Mon Sep 17 00:00:00 2001 From: Louis Greiner Date: Fri, 29 Aug 2025 17:49:34 +0200 Subject: [PATCH 02/40] asymmetry: display asymmetry on reticular Signed-off-by: Louis Greiner --- .../technical.data.structures.ts | 2 + src/app/models/trainrunsection.model.ts | 19 +++- src/app/services/data/trainrun.service.ts | 66 +++++++++++ .../services/data/trainrunsection.service.ts | 2 +- .../services/util/trainrunsection.routing.ts | 7 ++ .../util/trainrunsection.validator.ts | 20 +++- .../services/train-data-service.ts | 8 ++ .../data-views/editor.view.ts | 10 ++ .../data-views/trainrunsections.view.scss | 5 + .../data-views/trainrunsections.view.ts | 106 ++++++++++++++---- .../editor-main-view.component.ts | 9 ++ .../test-data/testNetzgrafik.json | 24 ++-- .../test-data/testNetzgrafikOdMatrix.json | 36 ++++-- ...estReconnectTrainrunSectionNetzgrafik.json | 12 +- .../test-data/testTransitionNetzgrafik.json | 24 ++-- 15 files changed, 293 insertions(+), 57 deletions(-) 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/trainrunsection.model.ts b/src/app/models/trainrunsection.model.ts index 42ea533a1..916ee1d3e 100644 --- a/src/app/models/trainrunsection.model.ts +++ b/src/app/models/trainrunsection.model.ts @@ -741,8 +741,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() { diff --git a/src/app/services/data/trainrun.service.ts b/src/app/services/data/trainrun.service.ts index df30724ea..a5658ab61 100644 --- a/src/app/services/data/trainrun.service.ts +++ b/src/app/services/data/trainrun.service.ts @@ -762,6 +762,72 @@ 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.getNonStopIterator(node, trainrunSection); // TODO: reverse iterator + while (iterator.hasNext()) { + const nextPair = iterator.next(); + summedBackwardTravelTime += nextPair.trainrunSection.getBackwardTravelTime(); + } + return summedBackwardTravelTime; + } + + getCumulativeBackwardTravelTime(trainrunSection: TrainrunSection) { + const iterator = this.getNonStopIterator( + // get reverse iterator instead + trainrunSection.getTargetNode(), // ??? + trainrunSection, + ); + while (iterator.hasNext()) { + // p-e le faire avant + 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.getNonStopIterator(n, ts); // TODO: reverse iterator + 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.getNonStopIterator( + // TODO: reverse iterator + trainrunSection.getTargetNode(), // not sure for that + 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); diff --git a/src/app/services/data/trainrunsection.service.ts b/src/app/services/data/trainrunsection.service.ts index 699f0d56b..d7677fa1e 100644 --- a/src/app/services/data/trainrunsection.service.ts +++ b/src/app/services/data/trainrunsection.service.ts @@ -280,7 +280,7 @@ export class TrainrunSectionService implements OnDestroy { initializeTrainrunSectionRouting() { this.trainrunSectionsStore.trainrunSections.forEach((trainrunSection) => { - if (trainrunSection.isPathEmpty()) { + if (trainrunSection.isPathInvalid()) { trainrunSection.routeEdgeAndPlaceText(); } }); diff --git a/src/app/services/util/trainrunsection.routing.ts b/src/app/services/util/trainrunsection.routing.ts index af76f409e..107153779 100644 --- a/src/app/services/util/trainrunsection.routing.ts +++ b/src/app/services/util/trainrunsection.routing.ts @@ -402,6 +402,11 @@ export class SimpleTrainrunSectionRouter { namePosOffsetDirection, ); + const trainrunSectionBackwardTravelTimePos = Vec2D.add( + Vec2D.scale(Vec2D.add(s1, t1), 0.5), + nameNumberOfStopsOffsetDirection, + ); + const trainrunSectionNumberOfStopsPos = Vec2D.add( Vec2D.scale(Vec2D.add(s1, t1), 0.5), nameNumberOfStopsOffsetDirection, @@ -414,6 +419,8 @@ export class SimpleTrainrunSectionRouter { [TrainrunSectionText.TargetDeparture]: targetDeparturePos.toPointDto(), [TrainrunSectionText.TrainrunSectionName]: trainrunSectionNamePos.toPointDto(), [TrainrunSectionText.TrainrunSectionTravelTime]: trainrunSectionNamePos.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..6415e3530 100644 --- a/src/app/services/util/trainrunsection.validator.ts +++ b/src/app/services/util/trainrunsection.validator.ts @@ -22,8 +22,10 @@ export class TrainrunSectionValidator { trainrunSection.resetTargetArrivalWarning(); } - const calculatedSourceArrivalTime = - (trainrunSection.getTargetDeparture() + trainrunSection.getTravelTime()) % 60; + 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`, @@ -35,6 +37,9 @@ export class TrainrunSectionValidator { } static validateUnsymmetricTimesOneSection(trainrunSection: TrainrunSection) { + if (!trainrunSection.isSymmetric()) { + return; + } // check for broken symmetry (times) trainrunSection.resetSourceDepartureWarning(); trainrunSection.resetTargetDepartureWarning(); @@ -92,4 +97,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/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/editor-main-view/data-views/editor.view.ts b/src/app/view/editor-main-view/data-views/editor.view.ts index 3ec5b1835..e869d0816 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; @@ -240,10 +242,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; } 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.ts b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts index 6b09c99b3..484efec25 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 = false, + ): 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) + "')" ); } @@ -758,10 +786,18 @@ export class TrainrunSectionsView { } return TrainrunSectionsView.extractTravelTime(trainrunSection, editorView); } + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: { + const data = TrainrunSectionsView.getFormattedDisplayText(trainrunSection, textElement); + if (data !== undefined) { + return data; + } + return TrainrunSectionsView.extractTravelTime(trainrunSection, editorView, true); + } case TrainrunSectionText.TrainrunSectionName: return TrainrunSectionsView.extractTrainrunName(trainrunSection); + default: + return undefined; } - return undefined; } static getTrainrunSectionValueTextWidth( @@ -773,7 +809,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 +820,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 +840,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 +884,8 @@ export class TrainrunSectionsView { return trainrunSection.getTargetArrivalFormatterColorRef(); case TrainrunSectionText.TrainrunSectionTravelTime: return trainrunSection.getTravelTimeFormatterColorRef(); + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + return trainrunSection.getBackwardTravelTimeFormatterColorRef(); default: return undefined; } @@ -899,6 +940,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()) { @@ -1347,7 +1399,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; @@ -1964,6 +2017,8 @@ export class TrainrunSectionsView { node = trainrunSection.getTargetNode(); minute = trainrunSection.getTargetDeparture(); break; + default: + break; } this.editorView.unselectAllNodes(); this.editorView.calculateShortestDistanceNodesFromStartingTrainrunSection( @@ -1983,11 +2038,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 +2453,13 @@ export class TrainrunSectionsView { connectedTrainIds, TrainrunSectionText.TrainrunSectionTravelTime, ); + this.createTrainrunSectionElement( + // LevelOfDetail.LEVEL3 + groupLabels, + selectedTrainrun, + connectedTrainIds, + TrainrunSectionText.TrainrunSectionBackwardTravelTime, + ); } if ( 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..b8e44e43b 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( diff --git a/src/integration-testing/test-data/testNetzgrafik.json b/src/integration-testing/test-data/testNetzgrafik.json index b8094cbfc..8756f1925 100644 --- a/src/integration-testing/test-data/testNetzgrafik.json +++ b/src/integration-testing/test-data/testNetzgrafik.json @@ -215,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 @@ -288,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 @@ -361,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 @@ -434,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 @@ -507,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 @@ -580,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 @@ -653,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 @@ -726,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 diff --git a/src/integration-testing/test-data/testNetzgrafikOdMatrix.json b/src/integration-testing/test-data/testNetzgrafikOdMatrix.json index c38ba450f..89d4bf8a9 100644 --- a/src/integration-testing/test-data/testNetzgrafikOdMatrix.json +++ b/src/integration-testing/test-data/testNetzgrafikOdMatrix.json @@ -789,7 +789,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 @@ -862,7 +863,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 @@ -935,7 +937,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 @@ -1008,7 +1011,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 @@ -1081,7 +1085,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 @@ -1154,7 +1159,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 @@ -1227,7 +1233,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 @@ -1300,7 +1307,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 @@ -1373,7 +1381,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 @@ -1446,7 +1455,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 @@ -1519,7 +1529,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 @@ -1592,7 +1603,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 diff --git a/src/integration-testing/test-data/testReconnectTrainrunSectionNetzgrafik.json b/src/integration-testing/test-data/testReconnectTrainrunSectionNetzgrafik.json index e4a84164c..bc5034cfe 100644 --- a/src/integration-testing/test-data/testReconnectTrainrunSectionNetzgrafik.json +++ b/src/integration-testing/test-data/testReconnectTrainrunSectionNetzgrafik.json @@ -174,7 +174,8 @@ "3": {"x": 324, "y": 144}, "4": {"x": 324, "y": 144}, "5": {"x": 324, "y": 144}, - "6": {"x": 348, "y": 144} + "6": {"x": 348, "y": 144}, + "7": {"x": 348, "y": 144} } }, "warnings": null @@ -247,7 +248,8 @@ "3": {"x": -48, "y": 36}, "4": {"x": 112, "y": 116}, "5": {"x": 112, "y": 116}, - "6": {"x": 112, "y": 140} + "6": {"x": 112, "y": 140}, + "7": {"x": 112, "y": 140} } }, "warnings": null @@ -320,7 +322,8 @@ "3": {"x": 272, "y": 252}, "4": {"x": 112, "y": 148}, "5": {"x": 112, "y": 148}, - "6": {"x": 112, "y": 172} + "6": {"x": 112, "y": 172}, + "7": {"x": 112, "y": 172} } }, "warnings": null @@ -393,7 +396,8 @@ "3": {"x": 784, "y": 92}, "4": {"x": 624, "y": 148}, "5": {"x": 624, "y": 148}, - "6": {"x": 624, "y": 172} + "6": {"x": 624, "y": 172}, + "7": {"x": 624, "y": 172} } }, "warnings": null diff --git a/src/integration-testing/test-data/testTransitionNetzgrafik.json b/src/integration-testing/test-data/testTransitionNetzgrafik.json index f5cc69b62..fe14e5395 100644 --- a/src/integration-testing/test-data/testTransitionNetzgrafik.json +++ b/src/integration-testing/test-data/testTransitionNetzgrafik.json @@ -190,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 @@ -266,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 @@ -342,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": 476}, + "": {"x": 1200, "y": 476} } }, "warnings": null @@ -418,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 @@ -491,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 @@ -564,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 @@ -637,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 @@ -710,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 From 0ec87f1b2e49912a3dfc1e26ca175519e9e9f32e Mon Sep 17 00:00:00 2001 From: Louis Greiner Date: Fri, 29 Aug 2025 18:00:21 +0200 Subject: [PATCH 03/40] asymmetry: enable filtering Signed-off-by: Louis Greiner --- .../business.data.structures.ts | 3 + src/app/models/filterSettings.model.ts | 22 +++++- src/app/services/data/data.service.ts | 8 +++ .../services/data/trainrunsection.service.ts | 6 ++ src/app/services/ui/filter.service.ts | 69 ++++++++++++++++++- .../editor-filter-view.component.html | 41 ++++++++--- .../editor-filter-view.component.ts | 62 +++++++++++++++++ .../data-views/editor.view.ts | 10 +++ .../data-views/trainrunSectionViewObject.ts | 33 +++++++-- .../data-views/trainrunsections.view.ts | 2 + .../editor-main-view.component.ts | 8 +++ src/assets/i18n/de.json | 4 ++ src/assets/i18n/en.json | 6 ++ src/assets/i18n/fr.json | 4 ++ src/assets/i18n/it.json | 4 ++ 15 files changed, 265 insertions(+), 17 deletions(-) diff --git a/src/app/data-structures/business.data.structures.ts b/src/app/data-structures/business.data.structures.ts index fc47211b1..389a318c7 100644 --- a/src/app/data-structures/business.data.structures.ts +++ b/src/app/data-structures/business.data.structures.ts @@ -293,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) @@ -302,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/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/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/trainrunsection.service.ts b/src/app/services/data/trainrunsection.service.ts index d7677fa1e..8431560a2 100644 --- a/src/app/services/data/trainrunsection.service.ts +++ b/src/app/services/data/trainrunsection.service.ts @@ -1076,6 +1076,12 @@ export class TrainrunSectionService implements OnDestroy { }); } + isTrainrunSymmetric(trainrunId: number): boolean { + return this.getAllTrainrunSectionsForTrainrun(trainrunId).every((section) => + section.isSymmetric(), + ); + } + private copyTrainrunSection( existingTrainrunSection: TrainrunSection, newTrainrunId: number, diff --git a/src/app/services/ui/filter.service.ts b/src/app/services/ui/filter.service.ts index e6d1971d7..d25e685a6 100644 --- a/src/app/services/ui/filter.service.ts +++ b/src/app/services/ui/filter.service.ts @@ -370,12 +370,18 @@ export class FilterService implements OnDestroy { } /* Impelement user defined filtering */ const filterTrainrunSection = this.checkFilterTrainrunLabels(trainrun.getLabelIds()); + const asymmetry = this.dataService + .getTrainrunSectionsByTrainrunId(trainrun.getId()) + .some((trainrunSection: TrainrunSection) => + this.isFilterSymmetryEnabled(trainrunSection.isSymmetric()), + ); return ( filterTrainrunSection && this.isFilterTrainrunFrequencyEnabled(trainrun.getTrainrunFrequency()) && this.isFilterTrainrunCategoryEnabled(trainrun.getTrainrunCategory()) && this.isFilterTrainrunTimeCategoryEnabled(trainrun.getTrainrunTimeCategory()) && - this.isFilterDirectionEnabled(trainrun.getDirection()) + this.isFilterDirectionEnabled(trainrun.getDirection()) && + asymmetry ); } @@ -540,6 +546,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 +602,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 +747,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 +813,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 +831,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 +922,7 @@ export class FilterService implements OnDestroy { if (filterSetting.filterDirection === null) { filterSetting.filterDirection = this.dataService.getDirections(); } + filterSetting.filterSymmetry = [true, false]; } } } 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..0185cd37f 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:Symm.`; + } else { + return $localize`:@@app.view.editor-filter-view.asymmetric-short:Asymm.`; + } + } + 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/editor.view.ts b/src/app/view/editor-main-view/data-views/editor.view.ts index e869d0816..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 @@ -78,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; @@ -290,6 +292,10 @@ export class EditorView implements SVGMouseControllerObserver { this.isFilterTravelTimeEnabled = callback; } + bindIsFilterBackwardTravelTimeEnabled(callback) { + this.isFilterBackwardTravelTimeEnabled = callback; + } + bindIsfilterTrainrunNameEnabled(callback) { this.isFilterTrainrunNameEnabled = callback; } @@ -298,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.ts b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts index 484efec25..d4d45c0f6 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 @@ -1720,9 +1720,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(), ), ); }); 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 b8e44e43b..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 @@ -357,6 +357,10 @@ export class EditorMainViewComponent implements AfterViewInit, OnDestroy { this.filterService.isFilterTravelTimeEnabled(), ); + this.editorView.bindIsFilterBackwardTravelTimeEnabled(() => + this.filterService.isFilterBackwardTravelTimeEnabled(), + ); + this.editorView.bindIsfilterTrainrunNameEnabled(() => this.filterService.isFilterTrainrunNameEnabled(), ); @@ -365,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/assets/i18n/de.json b/src/assets/i18n/de.json index 0f4287bd0..e0474a7ad 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -383,6 +383,10 @@ "symmetry": "Symmetrie", "show-direction": "{$direction} einblenden", "hide-direction": "{$direction} ausblenden", + "show-asymmetric-trainruns": "Asymmetrische Zugfahrten einblenden", + "hide-asymmetric-trainruns": "Asymmetrische Zugfahrten ausblenden", + "symmetric": "Symm.", + "asymmetric": "Asymm.", "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..29afe2ab5 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -355,6 +355,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", @@ -381,6 +383,10 @@ "show-trainrun-frequency": "Show {$trainrunFrequency}", "hide-trainrun-frequency": "Hide {$trainrunFrequency}", "symmetry": "Symmetry", + "show-asymmetric-trainruns": "Show asymmetric trainruns", + "hide-asymmetric-trainruns": "Hide asymmetric trainruns", + "symmetric-short": "Symm.", + "asymmetric-short": "Asymm.", "show-direction": "Show {$direction}", "hide-direction": "Hide {$direction}", "filterable-label-filter": { diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json index b6d1979be..a4fe8b4c6 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -382,6 +382,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..81c8f52ec 100644 --- a/src/assets/i18n/it.json +++ b/src/assets/i18n/it.json @@ -382,6 +382,10 @@ "symmetry": "Symmetry", "show-direction": "Show {$direction}", "hide-direction": "Hide {$direction}", + "show-asymmetric-trainruns": "Show asymmetric trainruns", + "hide-asymmetric-trainruns": "Hide asymmetric trainruns", + "symmetric": "Symm.", + "asymmetric": "Asymm.", "filterable-label-filter": { "no-labels-available": "No labels available", "or": "Or", From 15c7303b0c654c603f0b9ffa44f7860a361ac866 Mon Sep 17 00:00:00 2001 From: Louis Greiner Date: Fri, 29 Aug 2025 18:09:48 +0200 Subject: [PATCH 04/40] asymmetry: add asymmetry arrows Signed-off-by: Louis Greiner --- .../trainrun-section-tab.component.html | 4 +- .../trainrun-section-tab.component.ts | 3 +- .../data-views/trainrunsections.view.ts | 88 ++++++++++++++++++- src/assets/i18n/de.json | 2 + src/assets/i18n/en.json | 4 +- src/assets/i18n/fr.json | 2 + src/assets/i18n/it.json | 2 + 7 files changed, 95 insertions(+), 10 deletions(-) diff --git a/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.html b/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.html index 4cc193e1a..47be1c345 100644 --- a/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.html +++ b/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.html @@ -78,7 +78,7 @@ @@ -91,7 +91,7 @@ diff --git a/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.ts b/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.ts index 9675cd0a4..7414cd9a7 100644 --- a/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.ts +++ b/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.ts @@ -251,8 +251,7 @@ export class TrainrunSectionTabComponent implements AfterViewInit, OnDestroy { ); } - getArrowTranslateAndRotate() { - if (this.isTopTrainrunSectionInfoDisplayed && !this.isBottomTrainrunSectionInfoDisplayed) { + getDirectionArrowTranslateAndRotate() { return "translate(60, 16) rotate(0)"; } else if ( !this.isTopTrainrunSectionInfoDisplayed && 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 d4d45c0f6..6c054897f 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 @@ -1057,7 +1057,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); @@ -1076,9 +1077,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 { @@ -1112,7 +1118,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", @@ -1141,6 +1147,79 @@ export class TrainrunSectionsView { .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => d.trainrunSection.getTrainrun().selected(), ) + .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.onTrainrunSectionMouseUp(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]); + }); + }); + } + + 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 + !this.editorView.isFilterAsymmetryArrowsEnabled() || + !this.filterTrainrunsectionAtNode(d.trainrunSection, arrowType === "BEGINNING_ARROW") + ? "" + : null, + ) + .attr("d", (d: TrainrunSectionViewObject) => { + if (arrowType === "BEGINNING_ARROW") { + return d.trainrunSection.isSourceSymmetricOrTimesSymmetric() + ? "" + : "M-1,-8 V0 H-10 L1,8 V0 H10 Z"; + } else { + return d.trainrunSection.isTargetSymmetricOrTimesSymmetric() + ? "" + : "M-1,-8 V0 H-10 L1,8 V0 H10 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), @@ -2541,6 +2620,7 @@ export class TrainrunSectionsView { ); this.createDirectionArrows(groupLines, selectedTrainrun, connectedTrainIds, enableEvents); + this.createAsymmetryArrows(groupLines, selectedTrainrun, connectedTrainIds, enableEvents); } private createSingleStopElement( diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index e0474a7ad..95e026ccd 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -355,6 +355,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", diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 29afe2ab5..aff903f36 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -383,12 +383,12 @@ "show-trainrun-frequency": "Show {$trainrunFrequency}", "hide-trainrun-frequency": "Hide {$trainrunFrequency}", "symmetry": "Symmetry", + "show-direction": "Show {$direction}", + "hide-direction": "Hide {$direction}", "show-asymmetric-trainruns": "Show asymmetric trainruns", "hide-asymmetric-trainruns": "Hide asymmetric trainruns", "symmetric-short": "Symm.", "asymmetric-short": "Asymm.", - "show-direction": "Show {$direction}", - "hide-direction": "Hide {$direction}", "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 a4fe8b4c6..a6e200849 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -354,6 +354,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", diff --git a/src/assets/i18n/it.json b/src/assets/i18n/it.json index 81c8f52ec..5111d84ac 100644 --- a/src/assets/i18n/it.json +++ b/src/assets/i18n/it.json @@ -354,6 +354,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", From e9c74c5c5a6771a5245d94f23a081fe0bf72c5d2 Mon Sep 17 00:00:00 2001 From: Louis Greiner Date: Fri, 29 Aug 2025 18:07:54 +0200 Subject: [PATCH 05/40] asymmetry: enable asymmetric values update from trainrun-section-tab component Signed-off-by: Louis Greiner --- .../data/trainrun-section-times.service.ts | 320 +++++++++++++++--- src/app/services/data/trainrun.service.ts | 6 + .../services/data/trainrunsection.service.ts | 49 ++- .../util/trainrunsection.helper.spec.ts | 26 +- .../services/util/trainrunsection.helper.ts | 95 +++++- .../trainrun-section-card.component.ts | 1 + .../trainrun-section-tab.component.html | 143 ++++++-- .../trainrun-section-tab.component.scss | 82 +++++ .../trainrun-section-tab.component.ts | 61 ++-- 9 files changed, 660 insertions(+), 123 deletions(-) diff --git a/src/app/services/data/trainrun-section-times.service.ts b/src/app/services/data/trainrun-section-times.service.ts index 72918035b..0c52fef7a 100644 --- a/src/app/services/data/trainrun-section-times.service.ts +++ b/src/app/services/data/trainrun-section-times.service.ts @@ -26,6 +26,7 @@ export class TrainrunSectionTimesService { rightDepartureTime: 0, rightArrivalTime: 0, travelTime: 0, + bottomTravelTime: 0, }; private nodesOrdered: Node[] = []; @@ -42,6 +43,7 @@ export class TrainrunSectionTimesService { private offsetTransformationActive = false; private highlightTravelTimeElement: boolean; + private highlightBottomTravelTimeElement: boolean; private initialLeftAndRightElement: LeftAndRightElement = LeftAndRightElement.LeftArrival; @@ -107,6 +109,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 +147,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 +218,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 +288,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 +361,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 +411,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(); } @@ -413,7 +610,11 @@ export class TrainrunSectionTimesService { this.selectedTrainrunSection, this.nodesOrdered, ); - 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 ( @@ -495,6 +696,10 @@ export class TrainrunSectionTimesService { this.timeStructure.travelTime, timeDisplayPrecision, ); + this.timeStructure.bottomTravelTime = MathUtils.round( + this.timeStructure.bottomTravelTime, + timeDisplayPrecision, + ); } private fixAllTimesPrecision() { @@ -511,17 +716,30 @@ 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() { + private updateTrainrunSectionTime( + trainrunSection: TrainrunSection = this.selectedTrainrunSection, + timeStructure: LeftAndRightTimeStructure = this.timeStructure, + ) { this.trainrunSectionService.setTimeStructureToTrainrunSections( this.trainrunSectionHelper.mapLeftAndRightTimes( - this.selectedTrainrunSection, + trainrunSection, this.nodesOrdered, - this.timeStructure, + timeStructure, ), - this.selectedTrainrunSection, + 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 a5658ab61..c1c11a1cc 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)); } diff --git a/src/app/services/data/trainrunsection.service.ts b/src/app/services/data/trainrunsection.service.ts index 8431560a2..7b191949c 100644 --- a/src/app/services/data/trainrunsection.service.ts +++ b/src/app/services/data/trainrunsection.service.ts @@ -300,6 +300,7 @@ export class TrainrunSectionService implements OnDestroy { targetArrival: number, targetDeparture: number, travelTime: number, + backwardTravelTime: number, emit: boolean = true, ) { const trainrunSection = this.getTrainrunSectionFromId(trsId); @@ -308,6 +309,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,6 +321,20 @@ export class TrainrunSectionService implements OnDestroy { } } + 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 propagateTimeAlongTrainrunFixStartTrainrunSection( trainrunSection: TrainrunSection, node: Node, @@ -577,6 +593,7 @@ export class TrainrunSectionService implements OnDestroy { } if (travelTimeLock !== undefined) { trainrunSection.setTravelTimeLock(travelTimeLock); + trainrunSection.setBackwardTravelTimeLock(travelTimeLock); } if (enforceUpdate) { this.trainrunSectionsUpdated(); @@ -858,10 +875,14 @@ export class TrainrunSectionService implements OnDestroy { precision = 0, ) { const newTotalTravelTime = timeStructure.travelTime; - const oldTotalTravelTime = this.trainrunService.getCumulativeTravelTime(trainrunSection); const travelTimeFactor = newTotalTravelTime / oldTotalTravelTime; + const newTotalBottomTravelTime = timeStructure.bottomTravelTime; + const oldTotalBackwardTravelTime = + this.trainrunService.getCumulativeBackwardTravelTime(trainrunSection); + const backwardTravelTimeFactor = newTotalBottomTravelTime / oldTotalBackwardTravelTime; + // prepare data structure for the first trainrunsection const bothLastNonStopNodes = this.trainrunService.getBothLastNonStopNodes(trainrunSection); const bothLastNonStopTrainrunSections = @@ -877,6 +898,7 @@ export class TrainrunSectionService implements OnDestroy { const trsTimeStructure = TrainrunsectionHelper.getDefaultTimeStructure(timeStructure); let summedTravelTime = 0; + let summedBottomTravelTime = 0; const iterator = this.trainrunService.getNonStopIterator(leftNode, trs); while (iterator.hasNext()) { @@ -891,14 +913,23 @@ export class TrainrunSectionService implements OnDestroy { isRightNodeNonStop, precision, ); - trsTimeStructure.rightArrivalTime = TrainrunsectionHelper.getRightArrivalTime( - trsTimeStructure, - precision, - ); - trsTimeStructure.rightDepartureTime = TrainrunsectionHelper.getRightDepartureTime( - trsTimeStructure, + trsTimeStructure.bottomTravelTime = TrainrunsectionHelper.getTravelTime( + newTotalBottomTravelTime, + summedBottomTravelTime, + backwardTravelTimeFactor, + nextPair.trainrunSection.getBackwardTravelTime(), + isRightNodeNonStop, precision, ); + // TODO: delete the commented area below but potential bug around here for asymmetry + // check for non-stops + // trsTimeStructure.rightArrivalTime = TrainrunsectionHelper.getRightArrivalTime(trsTimeStructure, precision); + // trsTimeStructure.rightDepartureTime = + // TrainrunsectionHelper.getAdjustedTimeBasedOnSymmetry( + // trainrunSection.getTargetSymmetry(), + // trsTimeStructure.rightDepartureTime, + // trsTimeStructure.rightArrivalTime, + // ); const rightIsTarget = nextPair.node.getId() === nextPair.trainrunSection.getTargetNode().getId(); this.updateTrainrunSectionTime( @@ -907,12 +938,14 @@ export class TrainrunSectionService implements OnDestroy { rightIsTarget ? trsTimeStructure.leftDepartureTime : trsTimeStructure.rightDepartureTime, rightIsTarget ? trsTimeStructure.rightArrivalTime : trsTimeStructure.leftArrivalTime, rightIsTarget ? trsTimeStructure.rightDepartureTime : trsTimeStructure.leftDepartureTime, - trsTimeStructure.travelTime, + rightIsTarget ? trsTimeStructure.travelTime : trsTimeStructure.bottomTravelTime, + rightIsTarget ? trsTimeStructure.bottomTravelTime : trsTimeStructure.travelTime, ); trsTimeStructure.leftDepartureTime = trsTimeStructure.rightArrivalTime; trsTimeStructure.leftArrivalTime = trsTimeStructure.rightDepartureTime; summedTravelTime += trsTimeStructure.travelTime; + summedBottomTravelTime += trsTimeStructure.bottomTravelTime; } this.trainrunSectionsUpdated(); diff --git a/src/app/services/util/trainrunsection.helper.spec.ts b/src/app/services/util/trainrunsection.helper.spec.ts index db2b82656..0f71ce8b0 100644 --- a/src/app/services/util/trainrunsection.helper.spec.ts +++ b/src/app/services/util/trainrunsection.helper.spec.ts @@ -89,11 +89,12 @@ 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); }); @@ -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,11 +214,12 @@ 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); }); @@ -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..2611cc158 100644 --- a/src/app/services/util/trainrunsection.helper.ts +++ b/src/app/services/util/trainrunsection.helper.ts @@ -16,6 +16,7 @@ export enum LeftAndRightElement { RightDeparture, RightArrival, TravelTime, + BottomTravelTime, LeftRightTrainrunName, RightLeftTrainrunName, } @@ -33,9 +34,10 @@ export class TrainrunsectionHelper { return { leftDepartureTime: timeStructure.leftDepartureTime, leftArrivalTime: timeStructure.leftArrivalTime, - rightDepartureTime: 0, - rightArrivalTime: 0, + rightDepartureTime: timeStructure.rightDepartureTime, + rightArrivalTime: timeStructure.rightArrivalTime, travelTime: 0, + bottomTravelTime: 0, }; } @@ -60,6 +62,7 @@ export class TrainrunsectionHelper { } } + // TODO: remove this method static getRightArrivalTime( timeStructure: LeftAndRightTimeStructure, precision = TrainrunSectionService.TIME_PRECISION, @@ -70,6 +73,7 @@ export class TrainrunsectionHelper { ); } + // TODO: remove this method static getRightDepartureTime( timeStructure: LeftAndRightTimeStructure, precision = TrainrunSectionService.TIME_PRECISION, @@ -237,8 +241,13 @@ export class TrainrunsectionHelper { case TrainrunSectionText.TrainrunSectionTravelTime: return LeftAndRightElement.TravelTime; + + case TrainrunSectionText.TrainrunSectionBackwardTravelTime: + return LeftAndRightElement.BottomTravelTime; + + default: + return undefined; } - return undefined; } mapLeftAndRightTimes( @@ -258,7 +267,8 @@ export class TrainrunsectionHelper { mappedTimeStructure.leftArrivalTime = timeStructure.rightArrivalTime; mappedTimeStructure.rightDepartureTime = timeStructure.leftDepartureTime; mappedTimeStructure.leftDepartureTime = timeStructure.rightDepartureTime; - mappedTimeStructure.travelTime = timeStructure.travelTime; + mappedTimeStructure.travelTime = timeStructure.bottomTravelTime; + mappedTimeStructure.bottomTravelTime = timeStructure.travelTime; return mappedTimeStructure; } return timeStructure; @@ -282,14 +292,22 @@ export class TrainrunsectionHelper { lastRightNode.getId() === bothLastNonStopNodes.lastNonStopNode1.getId() ? bothLastNonStopTrainrunSections.lastNonStopTrainrunSection1 : bothLastNonStopTrainrunSections.lastNonStopTrainrunSection2; - const cumulativeTravelTime = this.trainrunService.getCumulativeTravelTime(trainrunSection); + + const targetIsRightOrBottom = TrainrunsectionHelper.isTargetRightOrBottom(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, }; } @@ -349,4 +367,69 @@ export class TrainrunsectionHelper { 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(); + } + } + + static isLeftToggleDisabled( + trainrunSection: TrainrunSection, + lockStructure: LeftAndRightLockStructure, + ): boolean { + return ( + !TrainrunsectionHelper.isLeftNodeSymmetric(trainrunSection) && + ((lockStructure.travelTimeLock && lockStructure.rightLock) || + (TrainrunsectionHelper.isRightNodeSymmetric(trainrunSection) && + lockStructure.travelTimeLock)) + ); + } + + static isRightToggleDisabled( + trainrunSection: TrainrunSection, + lockStructure: LeftAndRightLockStructure, + ): boolean { + return ( + !TrainrunsectionHelper.isRightNodeSymmetric(trainrunSection) && + ((lockStructure.travelTimeLock && lockStructure.leftLock) || + (TrainrunsectionHelper.isLeftNodeSymmetric(trainrunSection) && + lockStructure.travelTimeLock)) + ); + } } diff --git a/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-card/trainrun-section-card.component.ts b/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-card/trainrun-section-card.component.ts index ab379148d..01037361b 100644 --- a/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-card/trainrun-section-card.component.ts +++ b/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-card/trainrun-section-card.component.ts @@ -76,6 +76,7 @@ export class TrainrunSectionCardComponent implements AfterViewInit, OnDestroy { this.categoryColorRef = selectedTrainrun.getCategoryColorRef(); this.timeCategoryLinePattern = selectedTrainrun.getTimeCategoryLinePatternRef(); this.trainrunSectionTimesService.setHighlightTravelTimeElement(false); + this.trainrunSectionTimesService.setHighlightBottomTravelTimeElement(false); this.trainrunSectionTimesService.applyOffsetAndTransformTimeStructure(); const startNode = this.trainrunService.getStartNodeWithTrainrunId( diff --git a/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.html b/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.html index 47be1c345..38b1692c2 100644 --- a/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.html +++ b/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.html @@ -96,11 +96,24 @@ -
-
-
-
-
+
+
+
+
+
+
-
+
-
+
- -
+
-
+
-
+
-
+
- -
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+ +
+ +
+ +
+
+ + + +
+
-
+
(); - public get isTopTrainrunSectionInfoDisplayed(): boolean { - if (this.selectedTrainrunSection === null) { - return false; - } - const isTargetRightOrBottom = TrainrunsectionHelper.isTargetRightOrBottom( - this.selectedTrainrunSection, - ); - return this.isRoundTrip() || isTargetRightOrBottom; - } - - public get isBottomTrainrunSectionInfoDisplayed(): boolean { - if (this.selectedTrainrunSection === null) { - return false; - } - const isTargetRightOrBottom = TrainrunsectionHelper.isTargetRightOrBottom( - this.selectedTrainrunSection, - ); - return this.isRoundTrip() || !isTargetRightOrBottom; + public get isSymmetric(): boolean { + return this.selectedTrainrunSection.isSymmetric(); } constructor( @@ -137,6 +125,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(); @@ -216,6 +205,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 +215,7 @@ export class TrainrunSectionTabComponent implements AfterViewInit, OnDestroy { setTimeout(() => { element.focus(); element.select(); - }, 800); + }, 100); } getEdgeLineClassAttrString(layer: number) { @@ -252,10 +244,14 @@ export class TrainrunSectionTabComponent implements AfterViewInit, OnDestroy { } 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)"; } @@ -285,6 +281,7 @@ export class TrainrunSectionTabComponent implements AfterViewInit, OnDestroy { onInputNumberOfStopsElementButtonPlus() { this.numberOfStops += 1; this.trainrunSectionTimesService.setHighlightTravelTimeElement(false); + this.trainrunSectionTimesService.setHighlightBottomTravelTimeElement(false); this.onNumberOfStopsChanged(); } @@ -310,6 +307,22 @@ 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"; + } + + isTrainrunSymmetric() { + return this.trainrunSectionService.isTrainrunSymmetric( + this.selectedTrainrunSection.getTrainrunId(), + ); + } + private resetOffsetAfterTrainrunChanged() { if (this.trainrunSectionTimesService.getOffsetTransformationActive()) { this.trainrunSectionTimesService.removeOffsetAndBackTransformTimeStructure(); @@ -336,8 +349,4 @@ export class TrainrunSectionTabComponent implements AfterViewInit, OnDestroy { this.trainrunSectionTimesService.setOffset(this.trainrunDialogParameter.offset); } } - - private isRoundTrip() { - return this.selectedTrainrunSection.getTrainrun().isRoundTrip(); - } } From 720ae26203898f58877f43774d32ed6956dc0a15 Mon Sep 17 00:00:00 2001 From: Louis Greiner Date: Fri, 29 Aug 2025 18:24:52 +0200 Subject: [PATCH 06/40] asymmetry: move getTrainrunLeftAndRightTimeStructure outside of one-way card Will be useful later for reuse. Signed-off-by: Louis Greiner --- .../data/trainrun-section-times.service.ts | 24 ++++++++++ .../trainrun-section-card.component.html | 12 +++-- .../trainrun-section-card.component.ts | 46 ------------------- 3 files changed, 32 insertions(+), 50 deletions(-) diff --git a/src/app/services/data/trainrun-section-times.service.ts b/src/app/services/data/trainrun-section-times.service.ts index 0c52fef7a..c7c8986b7 100644 --- a/src/app/services/data/trainrun-section-times.service.ts +++ b/src/app/services/data/trainrun-section-times.service.ts @@ -674,6 +674,30 @@ export class TrainrunSectionTimesService { 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(), + }; + } + private roundAllTimes() { const timeDisplayPrecision = this.filterService.getTimeDisplayPrecision(); this.timeStructure.leftArrivalTime = MathUtils.round( diff --git a/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-card/trainrun-section-card.component.html b/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-card/trainrun-section-card.component.html index f90a12a55..158c79681 100644 --- a/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-card/trainrun-section-card.component.html +++ b/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-card/trainrun-section-card.component.html @@ -10,7 +10,9 @@
- {{ getTrainrunTimeStructure()?.leftDepartureTime }} + {{ + trainrunSectionTimesService.getTrainrunLeftAndRightTimeStructure()?.leftDepartureTime + }} @@ -22,7 +24,7 @@ - {{ getTrainrunTimeStructure()?.rightArrivalTime }} + {{ trainrunSectionTimesService.getTrainrunLeftAndRightTimeStructure()?.rightArrivalTime }} @@ -46,7 +48,7 @@
- {{ getTrainrunTimeStructure()?.leftArrivalTime }} + {{ trainrunSectionTimesService.getTrainrunLeftAndRightTimeStructure()?.leftArrivalTime }} @@ -58,7 +60,9 @@ - {{ getTrainrunTimeStructure()?.rightDepartureTime }} + {{ + trainrunSectionTimesService.getTrainrunLeftAndRightTimeStructure()?.rightDepartureTime + }} diff --git a/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-card/trainrun-section-card.component.ts b/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-card/trainrun-section-card.component.ts index 01037361b..1e8db5388 100644 --- a/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-card/trainrun-section-card.component.ts +++ b/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-card/trainrun-section-card.component.ts @@ -187,50 +187,4 @@ export class TrainrunSectionCardComponent implements AfterViewInit, OnDestroy { Direction.ONE_WAY, ); } - - getTrainrunTimeStructure(): Omit { - const selectedTrainrun = this.trainrunService.getSelectedTrainrun(); - if (!selectedTrainrun) { - return undefined; - } - const selectedTrainrunId = selectedTrainrun.getId(); - const trainrunSections = - this.trainrunSectionService.getAllTrainrunSectionsForTrainrun(selectedTrainrunId); - const [startNode, endNode] = [ - this.trainrunService.getStartNodeWithTrainrunId(selectedTrainrunId), - this.trainrunService.getEndNodeWithTrainrunId(selectedTrainrunId), - ]; - - // Try to find startNode → endNode - let firstTrainrunSection = trainrunSections.find( - (ts) => ts.getSourceNodeId() === startNode.getId(), - ); - let lastTrainrunSection = [...trainrunSections] - .reverse() - .find((ts) => ts.getTargetNodeId() === endNode.getId()); - - // If not found, swap first and last sections (and source and target nodes) - if (!firstTrainrunSection && !lastTrainrunSection) { - firstTrainrunSection = trainrunSections.find( - (ts) => ts.getSourceNodeId() === endNode.getId(), - ); - lastTrainrunSection = [...trainrunSections] - .reverse() - .find((ts) => ts.getTargetNodeId() === startNode.getId()); - [firstTrainrunSection, lastTrainrunSection] = [lastTrainrunSection, firstTrainrunSection]; - return { - leftDepartureTime: firstTrainrunSection.getTargetDeparture(), - leftArrivalTime: firstTrainrunSection.getTargetArrival(), - rightDepartureTime: lastTrainrunSection.getSourceDeparture(), - rightArrivalTime: lastTrainrunSection.getSourceArrival(), - }; - } - - return { - leftDepartureTime: firstTrainrunSection.getSourceDeparture(), - leftArrivalTime: firstTrainrunSection.getSourceArrival(), - rightDepartureTime: lastTrainrunSection.getTargetDeparture(), - rightArrivalTime: lastTrainrunSection.getTargetArrival(), - }; - } } From 53f255463bbae3b6ec773722eebf587628a52ac5 Mon Sep 17 00:00:00 2001 From: Louis Greiner Date: Fri, 29 Aug 2025 18:27:21 +0200 Subject: [PATCH 07/40] asymmetry: introduce symmetry selection dialog component Signed-off-by: Louis Greiner --- src/app/app.module.ts | 2 + .../services/util/symmetry-toggle.service.ts | 123 +++++++++ .../symmetry-selection-dialog.component.html | 221 +++++++++++++++++ .../symmetry-selection-dialog.component.scss | 70 ++++++ .../symmetry-selection-dialog.component.ts | 233 ++++++++++++++++++ src/assets/i18n/de.json | 5 + src/assets/i18n/en.json | 5 + src/assets/i18n/fr.json | 5 + src/assets/i18n/it.json | 5 + 9 files changed, 669 insertions(+) create mode 100644 src/app/services/util/symmetry-toggle.service.ts create mode 100644 src/app/view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component.html create mode 100644 src/app/view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component.scss create mode 100644 src/app/view/dialogs/symmetry-selection-dialog/symmetry-selection-dialog.component.ts 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/services/util/symmetry-toggle.service.ts b/src/app/services/util/symmetry-toggle.service.ts new file mode 100644 index 000000000..7604b16cf --- /dev/null +++ b/src/app/services/util/symmetry-toggle.service.ts @@ -0,0 +1,123 @@ +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 + if (!symmetry) { + 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 + if (!symmetry) { + 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, + ) { + 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/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..d361df7e4 --- /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/assets/i18n/de.json b/src/assets/i18n/de.json index 95e026ccd..a459b313c 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -267,6 +267,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": { diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index aff903f36..db32fe3de 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -267,6 +267,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": { diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json index a6e200849..df0cd5187 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -266,6 +266,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": { diff --git a/src/assets/i18n/it.json b/src/assets/i18n/it.json index 5111d84ac..54eb7e698 100644 --- a/src/assets/i18n/it.json +++ b/src/assets/i18n/it.json @@ -266,6 +266,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": { From 3f56e351d99337df63d37c3e1b05dbabaf493969 Mon Sep 17 00:00:00 2001 From: Louis Greiner Date: Fri, 29 Aug 2025 18:27:54 +0200 Subject: [PATCH 08/40] asymmetry: enable toggle component to be disabled Signed-off-by: Louis Greiner --- .../toggle-switch-button.component.html | 22 +++++++++++++------ .../toggle-switch-button.component.scss | 5 +++++ .../toggle-switch-button.component.ts | 11 +++++----- 3 files changed, 26 insertions(+), 12 deletions(-) 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); From 4aa4979c6c7016d986d81fd2c52d31129a7c5412 Mon Sep 17 00:00:00 2001 From: Louis Greiner Date: Fri, 29 Aug 2025 18:34:32 +0200 Subject: [PATCH 09/40] asymmetry: add symmetry toggle + enable to reset the symmetry on trainrun-section-tab component Signed-off-by: Louis Greiner --- .../data/trainrun-section-times.service.ts | 159 ++++++++++++++++++ src/app/services/ui/ui.interaction.service.ts | 11 ++ .../trainrun-section-tab.component.html | 28 +++ .../trainrun-section-tab.component.scss | 20 +++ .../trainrun-section-tab.component.ts | 41 ++++- .../filter-main-side-view.component.html | 1 + 6 files changed, 258 insertions(+), 2 deletions(-) diff --git a/src/app/services/data/trainrun-section-times.service.ts b/src/app/services/data/trainrun-section-times.service.ts index c7c8986b7..02035cbd4 100644 --- a/src/app/services/data/trainrun-section-times.service.ts +++ b/src/app/services/data/trainrun-section-times.service.ts @@ -11,6 +11,10 @@ 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", @@ -582,6 +586,63 @@ export class TrainrunSectionTimesService { ); } + /* 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(); + } + /* Buttons in Footer */ onPropagateTimeLeft(trainrunSection: TrainrunSection) { const nextStopRightNodeId = this.trainrunSectionHelper @@ -698,6 +759,104 @@ export class TrainrunSectionTimesService { }; } + 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; + } + + default: + return timeStructure; + } + } + + private roundAllTimes() { const timeDisplayPrecision = this.filterService.getTimeDisplayPrecision(); this.timeStructure.leftArrivalTime = MathUtils.round( 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/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.html b/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.html index 38b1692c2..bcdf32fd7 100644 --- a/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.html +++ b/src/app/view/dialogs/trainrun-and-section-dialog/trainrunsection-tab/trainrun-section-tab.component.html @@ -158,6 +158,20 @@ #leftArrivalTimeInputElement />
+ +
+ +
{ + // Revert the toggle state + if (this.leftSymmetryToggle) { + this.leftSymmetryToggle.checked = !originalState; + } + this.changeDetectionRef.detectChanges(); + }, + ); + } + + onRightNodeSymmetryToggleChanged(symmetry: boolean) { + const originalState = TrainrunsectionHelper.isRightNodeSymmetric(this.selectedTrainrunSection); + 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(), 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 @@ +
From 9ff8b1533df43a28dfc38c3baf2c6a02ac5c94d8 Mon Sep 17 00:00:00 2001 From: Louis Greiner Date: Fri, 29 Aug 2025 18:36:25 +0200 Subject: [PATCH 10/40] asymmetry: add symmetry Trainrun toggle + enable to reset the symmetry on trainrun-tab component Enables to reset the symmetry on the whole trainrun at once. Signed-off-by: Louis Greiner --- .../data/trainrun-section-times.service.ts | 85 +++++++++++++++++++ src/app/services/data/trainrun.service.ts | 39 +++++++++ .../trainrun-tab/trainrun-tab.component.html | 8 ++ .../trainrun-tab/trainrun-tab.component.ts | 40 ++++++++- 4 files changed, 171 insertions(+), 1 deletion(-) diff --git a/src/app/services/data/trainrun-section-times.service.ts b/src/app/services/data/trainrun-section-times.service.ts index 02035cbd4..86c30fe75 100644 --- a/src/app/services/data/trainrun-section-times.service.ts +++ b/src/app/services/data/trainrun-section-times.service.ts @@ -643,6 +643,18 @@ export class TrainrunSectionTimesService { this.applyOffsetAndTransformTimeStructure(); } + onTrainrunSymmetryChanged(trainrunId: number, reference: SymmetryReference) { + this.trainrunSectionService.getAllTrainrunSectionsForTrainrun(trainrunId).forEach((section) => { + this.removeOffsetAndBackTransformTimeStructure(); + section.resetSymmetry(); + this.updateTrainrunSectionTime( + section, + this.calculateTimeStructureAfterSymmetrySelectionForTrainrunSection(reference, section), + ); + this.applyOffsetAndTransformTimeStructure(); + }); + } + /* Buttons in Footer */ onPropagateTimeLeft(trainrunSection: TrainrunSection) { const nextStopRightNodeId = this.trainrunSectionHelper @@ -851,11 +863,84 @@ export class TrainrunSectionTimesService { 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(), + }; + } + } private roundAllTimes() { const timeDisplayPrecision = this.filterService.getTimeDisplayPrecision(); diff --git a/src/app/services/data/trainrun.service.ts b/src/app/services/data/trainrun.service.ts index c1c11a1cc..1f9c454e8 100644 --- a/src/app/services/data/trainrun.service.ts +++ b/src/app/services/data/trainrun.service.ts @@ -881,6 +881,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)); 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 @@
+ +