@@ -872,128 +872,147 @@ export class TrainrunSectionService implements OnDestroy {
872872 // this function is no longer used for its original purpose (drag a node that only existed inside numberOfStops and create it inside the real graph)
873873 replaceIntermediateStopWithNode (
874874 trainrunSectionId : number ,
875- nodeId : number ,
876- stopDuration ?: number ,
877- ) {
878- const trainrunSection1 = this . getTrainrunSectionFromId ( trainrunSectionId ) ;
875+ intermediateNodeId : number ,
876+ initialStopDuration ?: number ,
877+ ) : TrainrunSection | null {
878+ // Before:
879+ // initialSourceNode ◄─[port]──[port]─► initialTargetNode
880+ // initialSection
881+ //
882+ // After:
883+ // initialSourceNode ◄-[port]──[port]─► intermediateNode ◄─[port]──[port]─► initialTargetNode
884+ // initialSection newSection
885+
886+ const initialSection = this . getTrainrunSectionFromId ( trainrunSectionId ) ;
879887 if (
880- trainrunSection1 . getSourceNodeId ( ) === nodeId ||
881- trainrunSection1 . getTargetNodeId ( ) === nodeId
888+ initialSection . getSourceNodeId ( ) === intermediateNodeId ||
889+ initialSection . getTargetNodeId ( ) === intermediateNodeId
882890 ) {
883- return { } ;
891+ // Early return if the intermediate node is already part of the trainrun section
892+ return null ;
884893 }
885- const origTravelTime = trainrunSection1 . getTravelTime ( ) ;
886- const trainrunSection2 = this . copyTrainrunSection (
887- trainrunSection1 ,
888- trainrunSection1 . getTrainrunId ( ) ,
889- ) ;
890- const node1 = trainrunSection1 . getSourceNode ( ) ;
891- const node2 = trainrunSection1 . getTargetNode ( ) ;
892- const nodeIntermediate = this . nodeService . getNodeFromId ( nodeId ) ;
893- const transition1 : Transition = node1 . getTransition ( trainrunSection1 . getId ( ) ) ;
894- const nonStop1 = transition1 !== undefined ? transition1 . getIsNonStopTransit ( ) : false ;
895- const transition2 : Transition = node2 . getTransition ( trainrunSection1 . getId ( ) ) ;
896- const nonStop2 = transition2 !== undefined ? transition2 . getIsNonStopTransit ( ) : false ;
894+ // Create new section with same properties as initial section
895+ const newSection = this . copyTrainrunSection ( initialSection , initialSection . getTrainrunId ( ) ) ;
896+
897+ // Store initial values for later validation
898+ const initialTravelTime = initialSection . getTravelTime ( ) ;
899+ const initialSourceNode = initialSection . getSourceNode ( ) ;
900+ const initialTargetNode = initialSection . getTargetNode ( ) ;
901+
902+ // Store initial transition properties for later validation
903+ const initialTargetNodeTransition = initialTargetNode . getTransition ( initialSection . getId ( ) ) ;
904+ const isInitialTargetNodeNonStop = initialTargetNodeTransition ?. getIsNonStopTransit ( ) ;
897905
898- node2 . replaceTrainrunSectionOnPort ( trainrunSection1 , trainrunSection2 ) ;
906+ // Update initial target node port to use new section instead of initial section
907+ initialTargetNode . replaceTrainrunSectionOnPort ( initialSection , newSection ) ;
899908
909+ // Update initial section to point from intermediate node to initial target node
900910 const portOrderingType = this . nodeService . getCurrentOrderingAlgorithm ( ) ;
901- trainrunSection1 . setTargetNode ( nodeIntermediate ) ;
902- nodeIntermediate . addPortWithRespectToOppositeNode ( node1 , trainrunSection1 , portOrderingType ) ;
903- node1 . reAlignPortWithRespectToOppositeNode (
904- nodeIntermediate ,
905- trainrunSection1 ,
911+ const intermediateNode = this . nodeService . getNodeFromId ( intermediateNodeId ) ;
912+ initialSection . setTargetNode ( intermediateNode ) ;
913+ intermediateNode . addPortWithRespectToOppositeNode (
914+ initialSourceNode ,
915+ initialSection ,
916+ portOrderingType ,
917+ ) ;
918+ initialSourceNode . reAlignPortWithRespectToOppositeNode (
919+ intermediateNode ,
920+ initialSection ,
906921 portOrderingType ,
907922 ) ;
908923
909- trainrunSection2 . setSourceNode ( nodeIntermediate ) ;
910- trainrunSection2 . setTargetNode ( node2 ) ;
911- nodeIntermediate . addPortWithRespectToOppositeNode ( node2 , trainrunSection2 , portOrderingType ) ;
912- node2 . reAlignPortWithRespectToOppositeNode (
913- nodeIntermediate ,
914- trainrunSection2 ,
924+ // Update new section to point from intermediate node to initial target node
925+ newSection . setSourceNode ( intermediateNode ) ;
926+ newSection . setTargetNode ( initialTargetNode ) ;
927+ intermediateNode . addPortWithRespectToOppositeNode (
928+ initialTargetNode ,
929+ newSection ,
930+ portOrderingType ,
931+ ) ;
932+ initialTargetNode . reAlignPortWithRespectToOppositeNode (
933+ intermediateNode ,
934+ newSection ,
915935 portOrderingType ,
916936 ) ;
917937
938+ // Add transitions and connections for new section
918939 this . nodeService . addTransitionToNodeForTrainrunSections (
919- nodeIntermediate . getId ( ) ,
920- trainrunSection1 ,
921- trainrunSection2 ,
940+ intermediateNode . getId ( ) ,
941+ initialSection ,
942+ newSection ,
922943 ) ;
923- this . trainrunService . propagateConsecutiveTimesForTrainrun ( trainrunSection1 . getId ( ) ) ;
944+ const initialSectionNewTargetTransition = initialTargetNode . getTransition ( newSection . getId ( ) ) ;
945+ if ( initialSectionNewTargetTransition !== undefined ) {
946+ initialSectionNewTargetTransition . setIsNonStopTransit ( isInitialTargetNodeNonStop ) ;
947+ }
924948
925- const minHalteZeitFromNode = this . nodeService . getHaltezeit (
926- nodeId ,
927- trainrunSection1 . getTrainrun ( ) . getTrainrunCategory ( ) ,
949+ // Propagate times to ensure that the new section gets correct times based on the initial section
950+ this . trainrunService . propagateConsecutiveTimesForTrainrun ( initialSection . getId ( ) ) ;
951+
952+ // Calculate travel time using consecutive times in both directions
953+ let forwardTravelTime =
954+ initialSection . getTargetArrivalConsecutiveTime ( ) -
955+ initialSection . getSourceDepartureConsecutiveTime ( ) ;
956+ let backwardTravelTime =
957+ initialSection . getSourceArrivalConsecutiveTime ( ) -
958+ initialSection . getTargetDepartureConsecutiveTime ( ) ;
959+ forwardTravelTime = forwardTravelTime < 0 ? backwardTravelTime : forwardTravelTime ;
960+ backwardTravelTime = backwardTravelTime < 0 ? forwardTravelTime : backwardTravelTime ;
961+ const minimumCalculatedTravelTime = Math . min ( forwardTravelTime , backwardTravelTime ) ;
962+ const travelTimeIssue = ! forwardTravelTime || ! backwardTravelTime ;
963+
964+ // Determine stop duration at intermediate node based on calculated travel time
965+ // and minimum haltezeit for the trainrun category at the intermediate node
966+ const minimumHalteZeitAtIntermediateNode = this . nodeService . getHaltezeit (
967+ intermediateNodeId ,
968+ initialSection . getTrainrun ( ) . getTrainrunCategory ( ) ,
928969 ) ;
929- let travelTime1 =
930- trainrunSection1 . getTargetArrivalConsecutiveTime ( ) -
931- trainrunSection1 . getSourceDepartureConsecutiveTime ( ) ;
932- let travelTime2 =
933- trainrunSection1 . getSourceArrivalConsecutiveTime ( ) -
934- trainrunSection1 . getTargetDepartureConsecutiveTime ( ) ;
935- travelTime1 = travelTime1 < 0 ? travelTime2 : travelTime1 ;
936- travelTime2 = travelTime2 < 0 ? travelTime1 : travelTime2 ;
937- const calculatedTravelTime = Math . min ( travelTime1 , travelTime2 ) ;
938- const halteZeit =
939- stopDuration ?? Math . min ( minHalteZeitFromNode , Math . max ( 0 , calculatedTravelTime - 2 ) ) ;
940- const travelTimeIssue = ! travelTime1 || ! travelTime2 ;
941- const halteZeitIssue = minHalteZeitFromNode < halteZeit ;
942- const travelTime = Math . max ( trainrunSection1 . getTravelTime ( ) - halteZeit , 0 ) ;
943- const halfTravelTime = travelTime / 2 ;
944- trainrunSection1 . setTravelTime ( travelTime - halfTravelTime ) ;
945- trainrunSection2 . setTravelTime ( halfTravelTime ) ;
946-
947- trainrunSection1 . setTargetArrival (
970+ const stopDuration =
971+ initialStopDuration ??
972+ Math . min ( minimumHalteZeitAtIntermediateNode , Math . max ( 0 , minimumCalculatedTravelTime - 2 ) ) ;
973+ const halteZeitIssue = minimumHalteZeitAtIntermediateNode < stopDuration ;
974+
975+ // Finally, set the times for both sections (order of setting times is important)
976+ const travelTime = Math . max ( initialSection . getTravelTime ( ) - stopDuration , 0 ) ;
977+ initialSection . setTravelTime ( travelTime / 2 ) ;
978+ newSection . setTravelTime ( travelTime / 2 ) ;
979+ initialSection . setTargetArrival (
948980 TrainrunSectionService . boundMinutesToOneHour (
949- trainrunSection1 . getSourceDeparture ( ) + trainrunSection1 . getTravelTime ( ) ,
981+ initialSection . getSourceDeparture ( ) + initialSection . getTravelTime ( ) ,
950982 ) ,
951983 ) ;
952- trainrunSection2 . setSourceArrival (
984+ newSection . setSourceArrival (
953985 TrainrunSectionService . boundMinutesToOneHour (
954- trainrunSection1 . getTargetDeparture ( ) + trainrunSection2 . getTravelTime ( ) ,
986+ initialSection . getTargetDeparture ( ) + newSection . getTravelTime ( ) ,
955987 ) ,
956988 ) ;
957- trainrunSection1 . setTargetDeparture (
958- TrainrunSectionService . boundMinutesToOneHour ( halteZeit + trainrunSection2 . getSourceArrival ( ) ) ,
989+ initialSection . setTargetDeparture (
990+ TrainrunSectionService . boundMinutesToOneHour ( stopDuration + newSection . getSourceArrival ( ) ) ,
959991 ) ;
960- trainrunSection2 . setSourceDeparture (
961- TrainrunSectionService . boundMinutesToOneHour ( halteZeit + trainrunSection1 . getTargetArrival ( ) ) ,
992+ newSection . setSourceDeparture (
993+ TrainrunSectionService . boundMinutesToOneHour (
994+ stopDuration + initialSection . getTargetArrival ( ) ,
995+ ) ,
962996 ) ;
963997
964- if (
965- halteZeitIssue ||
966- trainrunSection1 . getTravelTime ( ) + trainrunSection2 . getTravelTime ( ) + halteZeit !==
967- origTravelTime ||
968- travelTimeIssue
969- ) {
998+ // Validate that the changes did not lead to inconsistencies in the times
999+ const finalTravelTimeIssue =
1000+ initialSection . getTravelTime ( ) + newSection . getTravelTime ( ) + stopDuration !==
1001+ initialTravelTime ;
1002+ if ( travelTimeIssue || halteZeitIssue || finalTravelTimeIssue ) {
9701003 const title = $localize `:@@app.services.data.trainrunsection.intermediate-stop-replacement.title:Intermediate stop replacement` ;
9711004 const description = $localize `:@@app.services.data.trainrunsection.intermediate-stop-replacement.description:Intermediate stop replacement led to inconsistencies in the allocation of times!` ;
972- trainrunSection1 . setTargetArrivalWarning ( title , description ) ;
973- trainrunSection1 . setTargetDepartureWarning ( title , description ) ;
974- trainrunSection2 . setSourceArrivalWarning ( title , description ) ;
975- trainrunSection2 . setSourceDepartureWarning ( title , description ) ;
976- }
977-
978- const transitionNew1 = node1 . getTransition ( trainrunSection1 . getId ( ) ) ;
979- if ( transitionNew1 !== undefined ) {
980- transitionNew1 . setIsNonStopTransit ( nonStop1 ) ;
981- }
982- const transitionNew2 = node2 . getTransition ( trainrunSection2 . getId ( ) ) ;
983- if ( transitionNew2 !== undefined ) {
984- transitionNew2 . setIsNonStopTransit ( nonStop2 ) ;
1005+ initialSection . setTargetArrivalWarning ( title , description ) ;
1006+ initialSection . setTargetDepartureWarning ( title , description ) ;
1007+ newSection . setSourceArrivalWarning ( title , description ) ;
1008+ newSection . setSourceDepartureWarning ( title , description ) ;
9851009 }
9861010
987- this . trainrunService . propagateConsecutiveTimesForTrainrun ( trainrunSection1 . getId ( ) ) ;
988-
9891011 this . nodeService . transitionsUpdated ( ) ;
9901012 this . nodeService . connectionsUpdated ( ) ;
9911013 this . nodeService . nodesUpdated ( ) ;
9921014 this . trainrunSectionsUpdated ( ) ;
993- return {
994- existingTrainrunSection : trainrunSection1 ,
995- newTrainrunSection : trainrunSection2 ,
996- } ;
1015+ return newSection ;
9971016 }
9981017
9991018 addIntermediateStopOnTrainrunSection ( trainrunSection : TrainrunSection ) {
0 commit comments