@@ -860,119 +860,130 @@ export class TrainrunSectionService implements OnDestroy {
860860 // 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)
861861 replaceIntermediateStopWithNode (
862862 trainrunSectionId : number ,
863- nodeId : number ,
864- stopDuration ?: number ,
865- ) {
866- const trainrunSection1 = this . getTrainrunSectionFromId ( trainrunSectionId ) ;
863+ intermediateNodeId : number ,
864+ initialStopDuration ?: number ,
865+ ) : TrainrunSection | null {
866+ // Before:
867+ // initialSourceNode ◄─[port]──[port]─► initialTargetNode
868+ // initialSection
869+ //
870+ // After:
871+ // initialSourceNode ◄-[port]──[port]─► intermediateNode ◄─[port]──[port]─► initialTargetNode
872+ // initialSection newSection
873+
874+ const initialSection = this . getTrainrunSectionFromId ( trainrunSectionId ) ;
867875 if (
868- trainrunSection1 . getSourceNodeId ( ) === nodeId ||
869- trainrunSection1 . getTargetNodeId ( ) === nodeId
876+ initialSection . getSourceNodeId ( ) === intermediateNodeId ||
877+ initialSection . getTargetNodeId ( ) === intermediateNodeId
870878 ) {
871- return { } ;
879+ // Early return if the intermediate node is already part of the trainrun section
880+ return null ;
872881 }
873- const origTravelTime = trainrunSection1 . getTravelTime ( ) ;
874- const trainrunSection2 = this . copyTrainrunSection (
875- trainrunSection1 ,
876- trainrunSection1 . getTrainrunId ( ) ,
877- ) ;
878- const node1 = trainrunSection1 . getSourceNode ( ) ;
879- const node2 = trainrunSection1 . getTargetNode ( ) ;
880- const nodeIntermediate = this . nodeService . getNodeFromId ( nodeId ) ;
881- const transition1 : Transition = node1 . getTransition ( trainrunSection1 . getId ( ) ) ;
882- const nonStop1 = transition1 !== undefined ? transition1 . getIsNonStopTransit ( ) : false ;
883- const transition2 : Transition = node2 . getTransition ( trainrunSection1 . getId ( ) ) ;
884- const nonStop2 = transition2 !== undefined ? transition2 . getIsNonStopTransit ( ) : false ;
885-
886- node2 . replaceTrainrunSectionOnPort ( trainrunSection1 , trainrunSection2 ) ;
887-
888- trainrunSection1 . setTargetNode ( nodeIntermediate ) ;
889- nodeIntermediate . addPortWithRespectToOppositeNode ( node1 , trainrunSection1 ) ;
890- node1 . reAlignPortWithRespectToOppositeNode ( nodeIntermediate , trainrunSection1 ) ;
891-
892- trainrunSection2 . setSourceNode ( nodeIntermediate ) ;
893- trainrunSection2 . setTargetNode ( node2 ) ;
894- nodeIntermediate . addPortWithRespectToOppositeNode ( node2 , trainrunSection2 ) ;
895- node2 . reAlignPortWithRespectToOppositeNode ( nodeIntermediate , trainrunSection2 ) ;
896-
882+ // Create new section with same properties as initial section
883+ const newSection = this . copyTrainrunSection ( initialSection , initialSection . getTrainrunId ( ) ) ;
884+
885+ // Store initial values for later validation
886+ const initialTravelTime = initialSection . getTravelTime ( ) ;
887+ const initialSourceNode = initialSection . getSourceNode ( ) ;
888+ const initialTargetNode = initialSection . getTargetNode ( ) ;
889+
890+ // Store initial transition properties for later validation
891+ const initialTargetNodeTransition = initialTargetNode . getTransition ( initialSection . getId ( ) ) ;
892+ const isInitialTargetNodeNonStop = initialTargetNodeTransition ?. getIsNonStopTransit ( ) ;
893+
894+ // Update initial target node port to use new section instead of initial section
895+ initialTargetNode . replaceTrainrunSectionOnPort ( initialSection , newSection ) ;
896+
897+ // Update initial section to point from intermediate node to initial target node
898+ const intermediateNode = this . nodeService . getNodeFromId ( intermediateNodeId ) ;
899+ initialSection . setTargetNode ( intermediateNode ) ;
900+ intermediateNode . addPortWithRespectToOppositeNode ( initialSourceNode , initialSection ) ;
901+ initialSourceNode . reAlignPortWithRespectToOppositeNode ( intermediateNode , initialSection ) ;
902+
903+ // Update new section to point from intermediate node to initial target node
904+ newSection . setSourceNode ( intermediateNode ) ;
905+ newSection . setTargetNode ( initialTargetNode ) ;
906+ intermediateNode . addPortWithRespectToOppositeNode ( initialTargetNode , newSection ) ;
907+ initialTargetNode . reAlignPortWithRespectToOppositeNode ( intermediateNode , newSection ) ;
908+
909+ // Add transitions and connections for new section
897910 this . nodeService . addTransitionToNodeForTrainrunSections (
898- nodeIntermediate . getId ( ) ,
899- trainrunSection1 ,
900- trainrunSection2 ,
911+ intermediateNode . getId ( ) ,
912+ initialSection ,
913+ newSection ,
901914 ) ;
902- this . trainrunService . propagateConsecutiveTimesForTrainrun ( trainrunSection1 . getId ( ) ) ;
915+ const initialSectionNewTargetTransition = initialTargetNode . getTransition ( newSection . getId ( ) ) ;
916+ if ( initialSectionNewTargetTransition !== undefined ) {
917+ initialSectionNewTargetTransition . setIsNonStopTransit ( isInitialTargetNodeNonStop ) ;
918+ }
903919
904- const minHalteZeitFromNode = this . nodeService . getHaltezeit (
905- nodeId ,
906- trainrunSection1 . getTrainrun ( ) . getTrainrunCategory ( ) ,
920+ // Propagate times to ensure that the new section gets correct times based on the initial section
921+ this . trainrunService . propagateConsecutiveTimesForTrainrun ( initialSection . getId ( ) ) ;
922+
923+ // Calculate travel time using consecutive times in both directions
924+ let forwardTravelTime =
925+ initialSection . getTargetArrivalConsecutiveTime ( ) -
926+ initialSection . getSourceDepartureConsecutiveTime ( ) ;
927+ let backwardTravelTime =
928+ initialSection . getSourceArrivalConsecutiveTime ( ) -
929+ initialSection . getTargetDepartureConsecutiveTime ( ) ;
930+ forwardTravelTime = forwardTravelTime < 0 ? backwardTravelTime : forwardTravelTime ;
931+ backwardTravelTime = backwardTravelTime < 0 ? forwardTravelTime : backwardTravelTime ;
932+ const minimumCalculatedTravelTime = Math . min ( forwardTravelTime , backwardTravelTime ) ;
933+ const travelTimeIssue = ! forwardTravelTime || ! backwardTravelTime ;
934+
935+ // Determine stop duration at intermediate node based on calculated travel time
936+ // and minimum haltezeit for the trainrun category at the intermediate node
937+ const minimumHalteZeitAtIntermediateNode = this . nodeService . getHaltezeit (
938+ intermediateNodeId ,
939+ initialSection . getTrainrun ( ) . getTrainrunCategory ( ) ,
907940 ) ;
908- let travelTime1 =
909- trainrunSection1 . getTargetArrivalConsecutiveTime ( ) -
910- trainrunSection1 . getSourceDepartureConsecutiveTime ( ) ;
911- let travelTime2 =
912- trainrunSection1 . getSourceArrivalConsecutiveTime ( ) -
913- trainrunSection1 . getTargetDepartureConsecutiveTime ( ) ;
914- travelTime1 = travelTime1 < 0 ? travelTime2 : travelTime1 ;
915- travelTime2 = travelTime2 < 0 ? travelTime1 : travelTime2 ;
916- const calculatedTravelTime = Math . min ( travelTime1 , travelTime2 ) ;
917- const halteZeit =
918- stopDuration ?? Math . min ( minHalteZeitFromNode , Math . max ( 0 , calculatedTravelTime - 2 ) ) ;
919- const travelTimeIssue = ! travelTime1 || ! travelTime2 ;
920- const halteZeitIssue = minHalteZeitFromNode < halteZeit ;
921- const travelTime = Math . max ( trainrunSection1 . getTravelTime ( ) - halteZeit , 0 ) ;
922- const halfTravelTime = travelTime / 2 ;
923- trainrunSection1 . setTravelTime ( travelTime - halfTravelTime ) ;
924- trainrunSection2 . setTravelTime ( halfTravelTime ) ;
925-
926- trainrunSection1 . setTargetArrival (
941+ const stopDuration =
942+ initialStopDuration ??
943+ Math . min ( minimumHalteZeitAtIntermediateNode , Math . max ( 0 , minimumCalculatedTravelTime - 2 ) ) ;
944+ const halteZeitIssue = minimumHalteZeitAtIntermediateNode < stopDuration ;
945+
946+ // Finally, set the times for both sections (order of setting times is important)
947+ const travelTime = Math . max ( initialSection . getTravelTime ( ) - stopDuration , 0 ) ;
948+ initialSection . setTravelTime ( travelTime / 2 ) ;
949+ newSection . setTravelTime ( travelTime / 2 ) ;
950+ initialSection . setTargetArrival (
927951 TrainrunSectionService . boundMinutesToOneHour (
928- trainrunSection1 . getSourceDeparture ( ) + trainrunSection1 . getTravelTime ( ) ,
952+ initialSection . getSourceDeparture ( ) + initialSection . getTravelTime ( ) ,
929953 ) ,
930954 ) ;
931- trainrunSection2 . setSourceArrival (
955+ newSection . setSourceArrival (
932956 TrainrunSectionService . boundMinutesToOneHour (
933- trainrunSection1 . getTargetDeparture ( ) + trainrunSection2 . getTravelTime ( ) ,
957+ initialSection . getTargetDeparture ( ) + newSection . getTravelTime ( ) ,
934958 ) ,
935959 ) ;
936- trainrunSection1 . setTargetDeparture (
937- TrainrunSectionService . boundMinutesToOneHour ( halteZeit + trainrunSection2 . getSourceArrival ( ) ) ,
960+ initialSection . setTargetDeparture (
961+ TrainrunSectionService . boundMinutesToOneHour ( stopDuration + newSection . getSourceArrival ( ) ) ,
938962 ) ;
939- trainrunSection2 . setSourceDeparture (
940- TrainrunSectionService . boundMinutesToOneHour ( halteZeit + trainrunSection1 . getTargetArrival ( ) ) ,
963+ newSection . setSourceDeparture (
964+ TrainrunSectionService . boundMinutesToOneHour (
965+ stopDuration + initialSection . getTargetArrival ( ) ,
966+ ) ,
941967 ) ;
942968
943- if (
944- halteZeitIssue ||
945- trainrunSection1 . getTravelTime ( ) + trainrunSection2 . getTravelTime ( ) + halteZeit !==
946- origTravelTime ||
947- travelTimeIssue
948- ) {
969+ // Validate that the changes did not lead to inconsistencies in the times
970+ const finalTravelTimeIssue =
971+ initialSection . getTravelTime ( ) + newSection . getTravelTime ( ) + stopDuration !==
972+ initialTravelTime ;
973+ if ( travelTimeIssue || halteZeitIssue || finalTravelTimeIssue ) {
949974 const title = $localize `:@@app.services.data.trainrunsection.intermediate-stop-replacement.title:Intermediate stop replacement` ;
950975 const description = $localize `:@@app.services.data.trainrunsection.intermediate-stop-replacement.description:Intermediate stop replacement led to inconsistencies in the allocation of times!` ;
951- trainrunSection1 . setTargetArrivalWarning ( title , description ) ;
952- trainrunSection1 . setTargetDepartureWarning ( title , description ) ;
953- trainrunSection2 . setSourceArrivalWarning ( title , description ) ;
954- trainrunSection2 . setSourceDepartureWarning ( title , description ) ;
976+ initialSection . setTargetArrivalWarning ( title , description ) ;
977+ initialSection . setTargetDepartureWarning ( title , description ) ;
978+ newSection . setSourceArrivalWarning ( title , description ) ;
979+ newSection . setSourceDepartureWarning ( title , description ) ;
955980 }
956981
957- const transitionNew1 = node1 . getTransition ( trainrunSection1 . getId ( ) ) ;
958- if ( transitionNew1 !== undefined ) {
959- transitionNew1 . setIsNonStopTransit ( nonStop1 ) ;
960- }
961- const transitionNew2 = node2 . getTransition ( trainrunSection2 . getId ( ) ) ;
962- if ( transitionNew2 !== undefined ) {
963- transitionNew2 . setIsNonStopTransit ( nonStop2 ) ;
964- }
965-
966- this . trainrunService . propagateConsecutiveTimesForTrainrun ( trainrunSection1 . getId ( ) ) ;
967-
968982 this . nodeService . transitionsUpdated ( ) ;
969983 this . nodeService . connectionsUpdated ( ) ;
970984 this . nodeService . nodesUpdated ( ) ;
971985 this . trainrunSectionsUpdated ( ) ;
972- return {
973- existingTrainrunSection : trainrunSection1 ,
974- newTrainrunSection : trainrunSection2 ,
975- } ;
986+ return newSection ;
976987 }
977988
978989 addIntermediateStopOnTrainrunSection ( trainrunSection : TrainrunSection ) {
0 commit comments