diff --git a/front/src/modules/simulationResult/SimulationResultExport/__tests__/utils.spec.ts b/front/src/modules/simulationResult/SimulationResultExport/__tests__/utils.spec.ts index 74b0ac661cc..ad5811b3941 100644 --- a/front/src/modules/simulationResult/SimulationResultExport/__tests__/utils.spec.ts +++ b/front/src/modules/simulationResult/SimulationResultExport/__tests__/utils.spec.ts @@ -1,32 +1,32 @@ import { describe, it, expect } from 'vitest'; -import { findActualVmax } from '../utils'; +import { findActualVmaxs } from '../utils'; describe('findActualVmax', () => { const vMax = { internalBoundaries: [2000, 3400, 5300, 6000], speeds: [10, 100, 200, 100, 150] }; - it('should return the correct Vmax', () => { - const result = findActualVmax(2500, vMax); - expect(result).toEqual(100); + it('should return the correct Vmax when the givenPosition is in an intermediary interval', () => { + const result = findActualVmaxs(2500, vMax); + expect(result).toEqual([100]); }); it('should return the correct Vmax when the givenPosition is in the last interval', () => { - const result = findActualVmax(7000, vMax); - expect(result).toEqual(150); + const result = findActualVmaxs(7000, vMax); + expect(result).toEqual([150]); }); it('should return the correct Vmax when the givenPosition is in thefirst interval', () => { - const result = findActualVmax(1000, vMax); - expect(result).toEqual(10); + const result = findActualVmaxs(1000, vMax); + expect(result).toEqual([10]); }); - it('should return the min Vmax when givenPosition is equal to a boundary (min before)', () => { - const result = findActualVmax(3400, vMax); - expect(result).toEqual(100); + it('should return both Vmax before and after when givenPosition is equal to a boundary (min before)', () => { + const result = findActualVmaxs(3400, vMax); + expect(result).toEqual([100, 200]); }); - it('should return the min Vmax when givenPosition is equal to a boundary (min after)', () => { - const result = findActualVmax(5300, vMax); - expect(result).toEqual(100); + it('should return both Vmax before and after when givenPosition is equal to a boundary (min after)', () => { + const result = findActualVmaxs(5300, vMax); + expect(result).toEqual([200, 100]); }); }); diff --git a/front/src/modules/simulationResult/SimulationResultExport/exportTrainCSV.ts b/front/src/modules/simulationResult/SimulationResultExport/exportTrainCSV.ts index 453c2cd6b54..32389f4334a 100644 --- a/front/src/modules/simulationResult/SimulationResultExport/exportTrainCSV.ts +++ b/front/src/modules/simulationResult/SimulationResultExport/exportTrainCSV.ts @@ -222,20 +222,37 @@ export default function exportTrainCSV( simulatedTrain.electrical_profiles ); - const steps = speedsWithOPsAndSpeedLimits.map((speed) => ({ - op: speed.op || '', - ch: speed.ch || '', - trackName: speed.trackName, - time: timestampToHHMMSS(speed.time), - seconds: pointToComma(+speed.time.toFixed(1)), - position: pointToComma(+(speed.position / 1000).toFixed(3)), - speed: pointToComma(+(speed.speed * 3.6).toFixed(3)), - speedLimit: pointToComma(getActualVmax(speed.position, formattedMrsp)), - lineCode: speed.lineCode, - electrificationType: speed.electrificationType, - electrificationMode: speed.electrificationMode, - electrificationProfile: speed.electrificationProfile, - })); + const steps: CSVData[] = []; + speedsWithOPsAndSpeedLimits.forEach((speed, index) => { + const actualVmaxs = getActualVmax(speed.position, formattedMrsp); + const newStep = { + op: speed.op || '', + ch: speed.ch || '', + trackName: speed.trackName, + time: timestampToHHMMSS(speed.time), + seconds: pointToComma(+speed.time.toFixed(1)), + position: pointToComma(+(speed.position / 1000).toFixed(3)), + speed: pointToComma(+(speed.speed * 3.6).toFixed(3)), + speedLimit: pointToComma(actualVmaxs[0]), + lineCode: speed.lineCode, + electrificationType: speed.electrificationType, + electrificationMode: speed.electrificationMode, + electrificationProfile: speed.electrificationProfile, + }; + steps.push(newStep); + + // If there's a second speed limit (meaning we are at a boundary) + // and it's the last step at this position, we add a copy of the step with the new limit + const isLastStepAtPosition = + index === speedsWithOPsAndSpeedLimits.length - 1 || + speed.position !== speedsWithOPsAndSpeedLimits[index + 1].position; + if (actualVmaxs.length > 1 && isLastStepAtPosition) { + steps.push({ + ...newStep, + speedLimit: pointToComma(actualVmaxs[1]), + }); + } + }); if (steps) createFakeLinkWithData(train.train_name, spreadDataBetweenSteps(steps)); } diff --git a/front/src/modules/simulationResult/SimulationResultExport/utils.ts b/front/src/modules/simulationResult/SimulationResultExport/utils.ts index 56df4c56329..aaa736dd9cc 100644 --- a/front/src/modules/simulationResult/SimulationResultExport/utils.ts +++ b/front/src/modules/simulationResult/SimulationResultExport/utils.ts @@ -24,22 +24,18 @@ export function massWithOneDecimal(number: number) { // to prevent a white screen when datas are computing and synchronizing when switching the selected train /** - * Get the Vmax at a givenPosition (in meters), using vmax (MRSP in m/s) - * Returns the current Vmax if in the middle of an interval, or - * the min of the Vmax before and after if exactly at a bound. + * Get the Vmax values at a givenPosition (in meters), using vmax (MRSP in m/s) + * Returns a list containing only the current Vmax if in the middle of an interval, + * or the Vmax values before and after if exactly at a bound. */ -export function findActualVmax(givenPosition: number, vmax: SpeedRanges): number { +export function findActualVmaxs(givenPosition: number, vmax: SpeedRanges): number[] { // givenPosition is in meters const vmaxUpperBoundIndex = d3.bisectRight(vmax.internalBoundaries, givenPosition); // Error case: vmax doesn't respect the SpeedRanges specifications on the lists' lengths - if (vmaxUpperBoundIndex > vmax.speeds.length - 1) return 0; - // If exactly on a speed-limit change, use the minimal value of both side - const actualVmaxMetersPerSecond = - vmaxUpperBoundIndex > 0 && vmax.internalBoundaries[vmaxUpperBoundIndex - 1] === givenPosition - ? Math.min(vmax.speeds[vmaxUpperBoundIndex], vmax.speeds[vmaxUpperBoundIndex - 1]) - : vmax.speeds[vmaxUpperBoundIndex]; - - return actualVmaxMetersPerSecond; + if (vmaxUpperBoundIndex > vmax.speeds.length - 1) return [0]; + if (vmaxUpperBoundIndex > 0 && vmax.internalBoundaries[vmaxUpperBoundIndex - 1] === givenPosition) + return [vmax.speeds[vmaxUpperBoundIndex - 1], vmax.speeds[vmaxUpperBoundIndex]]; + return [vmax.speeds[vmaxUpperBoundIndex]]; } /** @@ -47,8 +43,8 @@ export function findActualVmax(givenPosition: number, vmax: SpeedRanges): number * return the actual vmax at the givenPosition in km/h */ export function getActualVmax(givenPosition: number, vmax: SpeedRanges) { - const actualVMax = findActualVmax(givenPosition, vmax); - return msToKmhRounded(actualVMax); + const actualVMaxs = findActualVmaxs(givenPosition, vmax); + return actualVMaxs.map((actualVMax) => msToKmhRounded(actualVMax)); } /**