-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathhelpers.ts
107 lines (95 loc) · 3.76 KB
/
helpers.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import { feature, point } from '@turf/helpers';
import { compact, last, pick } from 'lodash';
import { v4 as uuidV4 } from 'uuid';
import { calculateDistanceAlongTrack } from 'applications/editor/tools/utils';
import type { ManageTrainSchedulePathProperties } from 'applications/operationalStudies/types';
import type { OperationalPointReference } from 'common/api/osrdEditoastApi';
import { pathStepMatchesOp } from 'modules/pathfinding/utils';
import type { SuggestedOP } from 'modules/trainschedule/components/ManageTrainSchedule/types';
import { addElementAtIndex } from 'utils/array';
import type { OperationalStudiesConfState } from './operationalStudiesConf';
import type { PathStep } from './types';
export const insertViaFromMap = (
pathSteps: OperationalStudiesConfState['pathSteps'],
// newVia comes from a map click either on a track section or an operational point
newVia: PathStep,
pathProperties: ManageTrainSchedulePathProperties
): OperationalStudiesConfState['pathSteps'] => {
// If one of these is missing, via is not valid (it hasn't been added via click on map) and we return the same array
if (!newVia.coordinates) return pathSteps;
const origin = pathSteps[0];
const destination = last(pathSteps);
const newStep = {
id: newVia.id,
coordinates: newVia.coordinates,
...('track' in newVia
? {
track: newVia.track,
offset: newVia.offset,
}
: {
...newVia,
track_reference: newVia.track_reference,
}),
};
let newViaIndex = -1;
if (origin && destination && pathSteps.length > 2) {
// If origin and destination have already been selected and there is at least a via,
// we project the new via on the current path and add it at the most relevant index
const newViaPoint = point(newStep.coordinates);
const positionOnPath = calculateDistanceAlongTrack(
feature(pathProperties.geometry, { length: pathProperties.length }),
newViaPoint.geometry,
'millimeters'
);
newViaIndex = pathSteps.findIndex(
(pathStep) => pathStep?.positionOnPath && pathStep.positionOnPath >= positionOnPath
);
}
return addElementAtIndex(pathSteps, newViaIndex, newStep);
};
/**
* Modifies the array statePathSteps in place in the reducer
*/
export function upsertPathStep(statePathSteps: (PathStep | null)[], op: SuggestedOP) {
// We know that, at this point, origin and destination are defined because pathfinding has been done
const cleanPathSteps = compact(statePathSteps);
let newVia: PathStep = {
...pick(op, [
'coordinates',
'positionOnPath',
'name',
'kp',
'arrival',
'locked',
'deleted',
'receptionSignal',
'theoreticalMargin',
'stopFor',
]),
id: uuidV4(),
...(op.uic
? { uic: op.uic, secondary_code: op.ch }
: {
track: op.track,
offset: op.offsetOnTrack,
}),
};
const stepIndex = cleanPathSteps.findIndex((step) => pathStepMatchesOp(step, op));
if (stepIndex >= 0) {
// Because of import issues, there can be multiple ops with same position on path
// To avoid updating the wrong one, we need to find the one that matches the payload
newVia = {
...newVia,
id: cleanPathSteps[stepIndex].id,
track_reference:
(cleanPathSteps[stepIndex] as OperationalPointReference).track_reference || undefined,
}; // We don't need to change the id of the updated via
statePathSteps[stepIndex] = newVia;
} else {
// Because of import issues, there can be multiple ops at position 0
// To avoid inserting a new via before the origin we need to check if the index is 0
const index = cleanPathSteps.findIndex((step) => step.positionOnPath! >= op.positionOnPath);
statePathSteps.splice(index || 1, 0, newVia);
}
}