@@ -861,128 +861,147 @@ export class TrainrunSectionService implements OnDestroy {
861861 // 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)
862862 replaceIntermediateStopWithNode (
863863 trainrunSectionId : number ,
864- nodeId : number ,
865- stopDuration ?: number ,
866- ) {
867- const trainrunSection1 = this . getTrainrunSectionFromId ( trainrunSectionId ) ;
864+ intermediateNodeId : number ,
865+ initialStopDuration ?: number ,
866+ ) : TrainrunSection | null {
867+ // Before:
868+ // initialSourceNode ◄─[port]──[port]─► initialTargetNode
869+ // initialSection
870+ //
871+ // After:
872+ // initialSourceNode ◄-[port]──[port]─► intermediateNode ◄─[port]──[port]─► initialTargetNode
873+ // initialSection newSection
874+
875+ const initialSection = this . getTrainrunSectionFromId ( trainrunSectionId ) ;
868876 if (
869- trainrunSection1 . getSourceNodeId ( ) === nodeId ||
870- trainrunSection1 . getTargetNodeId ( ) === nodeId
877+ initialSection . getSourceNodeId ( ) === intermediateNodeId ||
878+ initialSection . getTargetNodeId ( ) === intermediateNodeId
871879 ) {
872- return { } ;
880+ // Early return if the intermediate node is already part of the trainrun section
881+ return null ;
873882 }
874- const origTravelTime = trainrunSection1 . getTravelTime ( ) ;
875- const trainrunSection2 = this . copyTrainrunSection (
876- trainrunSection1 ,
877- trainrunSection1 . getTrainrunId ( ) ,
878- ) ;
879- const node1 = trainrunSection1 . getSourceNode ( ) ;
880- const node2 = trainrunSection1 . getTargetNode ( ) ;
881- const nodeIntermediate = this . nodeService . getNodeFromId ( nodeId ) ;
882- const transition1 : Transition = node1 . getTransition ( trainrunSection1 . getId ( ) ) ;
883- const nonStop1 = transition1 !== undefined ? transition1 . getIsNonStopTransit ( ) : false ;
884- const transition2 : Transition = node2 . getTransition ( trainrunSection1 . getId ( ) ) ;
885- const nonStop2 = transition2 !== undefined ? transition2 . getIsNonStopTransit ( ) : false ;
883+ // Create new section with same properties as initial section
884+ const newSection = this . copyTrainrunSection ( initialSection , initialSection . getTrainrunId ( ) ) ;
885+
886+ // Store initial values for later validation
887+ const initialTravelTime = initialSection . getTravelTime ( ) ;
888+ const initialSourceNode = initialSection . getSourceNode ( ) ;
889+ const initialTargetNode = initialSection . getTargetNode ( ) ;
890+
891+ // Store initial transition properties for later validation
892+ const initialTargetNodeTransition = initialTargetNode . getTransition ( initialSection . getId ( ) ) ;
893+ const isInitialTargetNodeNonStop = initialTargetNodeTransition ?. getIsNonStopTransit ( ) ;
886894
887- node2 . replaceTrainrunSectionOnPort ( trainrunSection1 , trainrunSection2 ) ;
895+ // Update initial target node port to use new section instead of initial section
896+ initialTargetNode . replaceTrainrunSectionOnPort ( initialSection , newSection ) ;
888897
898+ // Update initial section to point from intermediate node to initial target node
889899 const portOrderingType = this . nodeService . getCurrentOrderingAlgorithm ( ) ;
890- trainrunSection1 . setTargetNode ( nodeIntermediate ) ;
891- nodeIntermediate . addPortWithRespectToOppositeNode ( node1 , trainrunSection1 , portOrderingType ) ;
892- node1 . reAlignPortWithRespectToOppositeNode (
893- nodeIntermediate ,
894- trainrunSection1 ,
900+ const intermediateNode = this . nodeService . getNodeFromId ( intermediateNodeId ) ;
901+ initialSection . setTargetNode ( intermediateNode ) ;
902+ intermediateNode . addPortWithRespectToOppositeNode (
903+ initialSourceNode ,
904+ initialSection ,
905+ portOrderingType ,
906+ ) ;
907+ initialSourceNode . reAlignPortWithRespectToOppositeNode (
908+ intermediateNode ,
909+ initialSection ,
895910 portOrderingType ,
896911 ) ;
897912
898- trainrunSection2 . setSourceNode ( nodeIntermediate ) ;
899- trainrunSection2 . setTargetNode ( node2 ) ;
900- nodeIntermediate . addPortWithRespectToOppositeNode ( node2 , trainrunSection2 , portOrderingType ) ;
901- node2 . reAlignPortWithRespectToOppositeNode (
902- nodeIntermediate ,
903- trainrunSection2 ,
913+ // Update new section to point from intermediate node to initial target node
914+ newSection . setSourceNode ( intermediateNode ) ;
915+ newSection . setTargetNode ( initialTargetNode ) ;
916+ intermediateNode . addPortWithRespectToOppositeNode (
917+ initialTargetNode ,
918+ newSection ,
919+ portOrderingType ,
920+ ) ;
921+ initialTargetNode . reAlignPortWithRespectToOppositeNode (
922+ intermediateNode ,
923+ newSection ,
904924 portOrderingType ,
905925 ) ;
906926
927+ // Add transitions and connections for new section
907928 this . nodeService . addTransitionToNodeForTrainrunSections (
908- nodeIntermediate . getId ( ) ,
909- trainrunSection1 ,
910- trainrunSection2 ,
929+ intermediateNode . getId ( ) ,
930+ initialSection ,
931+ newSection ,
911932 ) ;
912- this . trainrunService . propagateConsecutiveTimesForTrainrun ( trainrunSection1 . getId ( ) ) ;
933+ const initialSectionNewTargetTransition = initialTargetNode . getTransition ( newSection . getId ( ) ) ;
934+ if ( initialSectionNewTargetTransition !== undefined ) {
935+ initialSectionNewTargetTransition . setIsNonStopTransit ( isInitialTargetNodeNonStop ) ;
936+ }
913937
914- const minHalteZeitFromNode = this . nodeService . getHaltezeit (
915- nodeId ,
916- trainrunSection1 . getTrainrun ( ) . getTrainrunCategory ( ) ,
938+ // Propagate times to ensure that the new section gets correct times based on the initial section
939+ this . trainrunService . propagateConsecutiveTimesForTrainrun ( initialSection . getId ( ) ) ;
940+
941+ // Calculate travel time using consecutive times in both directions
942+ let forwardTravelTime =
943+ initialSection . getTargetArrivalConsecutiveTime ( ) -
944+ initialSection . getSourceDepartureConsecutiveTime ( ) ;
945+ let backwardTravelTime =
946+ initialSection . getSourceArrivalConsecutiveTime ( ) -
947+ initialSection . getTargetDepartureConsecutiveTime ( ) ;
948+ forwardTravelTime = forwardTravelTime < 0 ? backwardTravelTime : forwardTravelTime ;
949+ backwardTravelTime = backwardTravelTime < 0 ? forwardTravelTime : backwardTravelTime ;
950+ const minimumCalculatedTravelTime = Math . min ( forwardTravelTime , backwardTravelTime ) ;
951+ const travelTimeIssue = ! forwardTravelTime || ! backwardTravelTime ;
952+
953+ // Determine stop duration at intermediate node based on calculated travel time
954+ // and minimum haltezeit for the trainrun category at the intermediate node
955+ const minimumHalteZeitAtIntermediateNode = this . nodeService . getHaltezeit (
956+ intermediateNodeId ,
957+ initialSection . getTrainrun ( ) . getTrainrunCategory ( ) ,
917958 ) ;
918- let travelTime1 =
919- trainrunSection1 . getTargetArrivalConsecutiveTime ( ) -
920- trainrunSection1 . getSourceDepartureConsecutiveTime ( ) ;
921- let travelTime2 =
922- trainrunSection1 . getSourceArrivalConsecutiveTime ( ) -
923- trainrunSection1 . getTargetDepartureConsecutiveTime ( ) ;
924- travelTime1 = travelTime1 < 0 ? travelTime2 : travelTime1 ;
925- travelTime2 = travelTime2 < 0 ? travelTime1 : travelTime2 ;
926- const calculatedTravelTime = Math . min ( travelTime1 , travelTime2 ) ;
927- const halteZeit =
928- stopDuration ?? Math . min ( minHalteZeitFromNode , Math . max ( 0 , calculatedTravelTime - 2 ) ) ;
929- const travelTimeIssue = ! travelTime1 || ! travelTime2 ;
930- const halteZeitIssue = minHalteZeitFromNode < halteZeit ;
931- const travelTime = Math . max ( trainrunSection1 . getTravelTime ( ) - halteZeit , 0 ) ;
932- const halfTravelTime = travelTime / 2 ;
933- trainrunSection1 . setTravelTime ( travelTime - halfTravelTime ) ;
934- trainrunSection2 . setTravelTime ( halfTravelTime ) ;
935-
936- trainrunSection1 . setTargetArrival (
959+ const stopDuration =
960+ initialStopDuration ??
961+ Math . min ( minimumHalteZeitAtIntermediateNode , Math . max ( 0 , minimumCalculatedTravelTime - 2 ) ) ;
962+ const halteZeitIssue = minimumHalteZeitAtIntermediateNode < stopDuration ;
963+
964+ // Finally, set the times for both sections (order of setting times is important)
965+ const travelTime = Math . max ( initialSection . getTravelTime ( ) - stopDuration , 0 ) ;
966+ initialSection . setTravelTime ( travelTime / 2 ) ;
967+ newSection . setTravelTime ( travelTime / 2 ) ;
968+ initialSection . setTargetArrival (
937969 TrainrunSectionService . boundMinutesToOneHour (
938- trainrunSection1 . getSourceDeparture ( ) + trainrunSection1 . getTravelTime ( ) ,
970+ initialSection . getSourceDeparture ( ) + initialSection . getTravelTime ( ) ,
939971 ) ,
940972 ) ;
941- trainrunSection2 . setSourceArrival (
973+ newSection . setSourceArrival (
942974 TrainrunSectionService . boundMinutesToOneHour (
943- trainrunSection1 . getTargetDeparture ( ) + trainrunSection2 . getTravelTime ( ) ,
975+ initialSection . getTargetDeparture ( ) + newSection . getTravelTime ( ) ,
944976 ) ,
945977 ) ;
946- trainrunSection1 . setTargetDeparture (
947- TrainrunSectionService . boundMinutesToOneHour ( halteZeit + trainrunSection2 . getSourceArrival ( ) ) ,
978+ initialSection . setTargetDeparture (
979+ TrainrunSectionService . boundMinutesToOneHour ( stopDuration + newSection . getSourceArrival ( ) ) ,
948980 ) ;
949- trainrunSection2 . setSourceDeparture (
950- TrainrunSectionService . boundMinutesToOneHour ( halteZeit + trainrunSection1 . getTargetArrival ( ) ) ,
981+ newSection . setSourceDeparture (
982+ TrainrunSectionService . boundMinutesToOneHour (
983+ stopDuration + initialSection . getTargetArrival ( ) ,
984+ ) ,
951985 ) ;
952986
953- if (
954- halteZeitIssue ||
955- trainrunSection1 . getTravelTime ( ) + trainrunSection2 . getTravelTime ( ) + halteZeit !==
956- origTravelTime ||
957- travelTimeIssue
958- ) {
987+ // Validate that the changes did not lead to inconsistencies in the times
988+ const finalTravelTimeIssue =
989+ initialSection . getTravelTime ( ) + newSection . getTravelTime ( ) + stopDuration !==
990+ initialTravelTime ;
991+ if ( travelTimeIssue || halteZeitIssue || finalTravelTimeIssue ) {
959992 const title = $localize `:@@app.services.data.trainrunsection.intermediate-stop-replacement.title:Intermediate stop replacement` ;
960993 const description = $localize `:@@app.services.data.trainrunsection.intermediate-stop-replacement.description:Intermediate stop replacement led to inconsistencies in the allocation of times!` ;
961- trainrunSection1 . setTargetArrivalWarning ( title , description ) ;
962- trainrunSection1 . setTargetDepartureWarning ( title , description ) ;
963- trainrunSection2 . setSourceArrivalWarning ( title , description ) ;
964- trainrunSection2 . setSourceDepartureWarning ( title , description ) ;
965- }
966-
967- const transitionNew1 = node1 . getTransition ( trainrunSection1 . getId ( ) ) ;
968- if ( transitionNew1 !== undefined ) {
969- transitionNew1 . setIsNonStopTransit ( nonStop1 ) ;
970- }
971- const transitionNew2 = node2 . getTransition ( trainrunSection2 . getId ( ) ) ;
972- if ( transitionNew2 !== undefined ) {
973- transitionNew2 . setIsNonStopTransit ( nonStop2 ) ;
994+ initialSection . setTargetArrivalWarning ( title , description ) ;
995+ initialSection . setTargetDepartureWarning ( title , description ) ;
996+ newSection . setSourceArrivalWarning ( title , description ) ;
997+ newSection . setSourceDepartureWarning ( title , description ) ;
974998 }
975999
976- this . trainrunService . propagateConsecutiveTimesForTrainrun ( trainrunSection1 . getId ( ) ) ;
977-
9781000 this . nodeService . transitionsUpdated ( ) ;
9791001 this . nodeService . connectionsUpdated ( ) ;
9801002 this . nodeService . nodesUpdated ( ) ;
9811003 this . trainrunSectionsUpdated ( ) ;
982- return {
983- existingTrainrunSection : trainrunSection1 ,
984- newTrainrunSection : trainrunSection2 ,
985- } ;
1004+ return newSection ;
9861005 }
9871006
9881007 addIntermediateStopOnTrainrunSection ( trainrunSection : TrainrunSection ) {
0 commit comments