openskidata-format 11.0.0 → 11.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Lift.js +26 -2
- package/dist/Lift.js.map +1 -1
- package/package.json +1 -1
- package/src/Lift.test.ts +170 -2
- package/src/Lift.ts +45 -3
package/dist/Lift.js
CHANGED
|
@@ -4,7 +4,10 @@ exports.LiftType = void 0;
|
|
|
4
4
|
exports.getLiftElevationData = getLiftElevationData;
|
|
5
5
|
exports.getFormattedLiftType = getFormattedLiftType;
|
|
6
6
|
exports.getLiftColor = getLiftColor;
|
|
7
|
+
const tslib_1 = require("tslib");
|
|
8
|
+
const distance_1 = tslib_1.__importDefault(require("@turf/distance"));
|
|
7
9
|
const ElevationProfile_1 = require("./ElevationProfile");
|
|
10
|
+
const Spot_1 = require("./Spot");
|
|
8
11
|
const Status_1 = require("./Status");
|
|
9
12
|
const exhaustiveMatchingGuard_1 = require("./util/exhaustiveMatchingGuard");
|
|
10
13
|
var LiftType;
|
|
@@ -31,16 +34,37 @@ function getLiftElevationData(feature) {
|
|
|
31
34
|
}
|
|
32
35
|
const elevationData = (0, ElevationProfile_1.getElevationData)(geometry);
|
|
33
36
|
const durationInSeconds = feature.properties.duration;
|
|
37
|
+
const terminalDistances = getTerminalStationDistances(feature);
|
|
38
|
+
const inclinedLength = terminalDistances?.inclinedLengthInMeters ??
|
|
39
|
+
elevationData.inclinedLengthInMeters;
|
|
40
|
+
const verticalLength = terminalDistances?.verticalInMeters ?? elevationData.verticalInMeters;
|
|
34
41
|
return {
|
|
35
42
|
...elevationData,
|
|
36
43
|
speedInMetersPerSecond: durationInSeconds
|
|
37
|
-
?
|
|
44
|
+
? inclinedLength / durationInSeconds
|
|
38
45
|
: null,
|
|
39
46
|
verticalSpeedInMetersPerSecond: durationInSeconds
|
|
40
|
-
?
|
|
47
|
+
? verticalLength / durationInSeconds
|
|
41
48
|
: null,
|
|
42
49
|
};
|
|
43
50
|
}
|
|
51
|
+
function getTerminalStationDistances(feature) {
|
|
52
|
+
const stations = feature.properties.stations;
|
|
53
|
+
const topStation = stations.find((s) => s.properties.position === Spot_1.LiftStationPosition.Top);
|
|
54
|
+
const bottomStation = stations.find((s) => s.properties.position === Spot_1.LiftStationPosition.Bottom);
|
|
55
|
+
if (!topStation || !bottomStation) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const topCoords = topStation.geometry.coordinates;
|
|
59
|
+
const bottomCoords = bottomStation.geometry.coordinates;
|
|
60
|
+
if (topCoords.length < 3 || bottomCoords.length < 3) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const horizontalDistanceInMeters = (0, distance_1.default)(topStation.geometry, bottomStation.geometry, { units: 'meters' });
|
|
64
|
+
const verticalInMeters = Math.abs(topCoords[2] - bottomCoords[2]);
|
|
65
|
+
const inclinedLengthInMeters = Math.sqrt(Math.pow(horizontalDistanceInMeters, 2) + Math.pow(verticalInMeters, 2));
|
|
66
|
+
return { inclinedLengthInMeters, verticalInMeters };
|
|
67
|
+
}
|
|
44
68
|
function getFormattedLiftType(liftType) {
|
|
45
69
|
switch (liftType) {
|
|
46
70
|
case LiftType.CableCar:
|
package/dist/Lift.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Lift.js","sourceRoot":"","sources":["../src/Lift.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"Lift.js","sourceRoot":"","sources":["../src/Lift.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/Lift.test.ts
CHANGED
|
@@ -1,7 +1,175 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FeatureType } from './FeatureType';
|
|
2
|
+
import { getLiftElevationData, LiftFeature, LiftType, getFormattedLiftType, getLiftColor } from './Lift';
|
|
3
|
+
import { LiftStationPosition, LiftStationSpotFeature, SpotType } from './Spot';
|
|
2
4
|
import { Status } from './Status';
|
|
3
5
|
|
|
6
|
+
function makeLiftFeature(overrides: {
|
|
7
|
+
coordinates?: GeoJSON.Position[];
|
|
8
|
+
duration?: number | null;
|
|
9
|
+
stations?: LiftStationSpotFeature[];
|
|
10
|
+
}): LiftFeature {
|
|
11
|
+
return {
|
|
12
|
+
type: 'Feature',
|
|
13
|
+
geometry: {
|
|
14
|
+
type: 'LineString',
|
|
15
|
+
coordinates: overrides.coordinates ?? [
|
|
16
|
+
[8.0, 46.0, 1000],
|
|
17
|
+
[8.01, 46.05, 1500],
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
properties: {
|
|
21
|
+
type: FeatureType.Lift,
|
|
22
|
+
id: 'test',
|
|
23
|
+
liftType: LiftType.ChairLift,
|
|
24
|
+
status: Status.Operating,
|
|
25
|
+
access: null,
|
|
26
|
+
name: null,
|
|
27
|
+
ref: null,
|
|
28
|
+
refFRCAIRN: null,
|
|
29
|
+
description: null,
|
|
30
|
+
oneway: null,
|
|
31
|
+
occupancy: null,
|
|
32
|
+
capacity: null,
|
|
33
|
+
duration: overrides.duration !== undefined ? overrides.duration : 600,
|
|
34
|
+
detachable: null,
|
|
35
|
+
bubble: null,
|
|
36
|
+
heating: null,
|
|
37
|
+
tunnel: null,
|
|
38
|
+
stations: overrides.stations ?? [],
|
|
39
|
+
skiAreas: [],
|
|
40
|
+
sources: [],
|
|
41
|
+
websites: [],
|
|
42
|
+
wikidataID: null,
|
|
43
|
+
places: [],
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function makeStation(
|
|
49
|
+
position: LiftStationPosition,
|
|
50
|
+
coordinates: GeoJSON.Position,
|
|
51
|
+
): LiftStationSpotFeature {
|
|
52
|
+
return {
|
|
53
|
+
type: 'Feature',
|
|
54
|
+
geometry: { type: 'Point', coordinates },
|
|
55
|
+
properties: {
|
|
56
|
+
type: FeatureType.Spot,
|
|
57
|
+
id: `station-${position}`,
|
|
58
|
+
spotType: SpotType.LiftStation,
|
|
59
|
+
name: null,
|
|
60
|
+
position,
|
|
61
|
+
entry: null,
|
|
62
|
+
exit: null,
|
|
63
|
+
liftId: 'test',
|
|
64
|
+
skiAreas: [],
|
|
65
|
+
sources: [],
|
|
66
|
+
places: [],
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
4
71
|
describe('Lift', () => {
|
|
72
|
+
describe('getLiftElevationData', () => {
|
|
73
|
+
it('returns null for non-LineString geometry', () => {
|
|
74
|
+
const feature: LiftFeature = {
|
|
75
|
+
...makeLiftFeature({}),
|
|
76
|
+
geometry: { type: 'MultiLineString', coordinates: [] },
|
|
77
|
+
}
|
|
78
|
+
expect(getLiftElevationData(feature)).toBeNull()
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('returns null when coordinates have no elevation', () => {
|
|
82
|
+
const feature = makeLiftFeature({
|
|
83
|
+
coordinates: [[8.0, 46.0], [8.01, 46.05]],
|
|
84
|
+
})
|
|
85
|
+
expect(getLiftElevationData(feature)).toBeNull()
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('returns null speed when duration is null', () => {
|
|
89
|
+
const result = getLiftElevationData(makeLiftFeature({ duration: null }))
|
|
90
|
+
expect(result?.speedInMetersPerSecond).toBeNull()
|
|
91
|
+
expect(result?.verticalSpeedInMetersPerSecond).toBeNull()
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('uses full geometry length when no stations', () => {
|
|
95
|
+
const feature = makeLiftFeature({ stations: [] })
|
|
96
|
+
const result = getLiftElevationData(feature)!
|
|
97
|
+
expect(result.speedInMetersPerSecond).toBeGreaterThan(0)
|
|
98
|
+
// Speed should be inclinedLength / duration from geometry
|
|
99
|
+
const expectedSpeed = result.inclinedLengthInMeters / 600
|
|
100
|
+
expect(result.speedInMetersPerSecond).toBeCloseTo(expectedSpeed)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('uses full geometry length when only one terminal station is present', () => {
|
|
104
|
+
const noStations = makeLiftFeature({ stations: [] })
|
|
105
|
+
const oneStation = makeLiftFeature({
|
|
106
|
+
stations: [makeStation(LiftStationPosition.Bottom, [8.0, 46.0, 1000])],
|
|
107
|
+
})
|
|
108
|
+
const resultNoStations = getLiftElevationData(noStations)!
|
|
109
|
+
const resultOneStation = getLiftElevationData(oneStation)!
|
|
110
|
+
expect(resultOneStation.speedInMetersPerSecond).toBeCloseTo(
|
|
111
|
+
resultNoStations.speedInMetersPerSecond!,
|
|
112
|
+
)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('uses station-based distance when top and bottom stations have elevation', () => {
|
|
116
|
+
// Geometry extends beyond the stations (extra approach at each end)
|
|
117
|
+
const feature = makeLiftFeature({
|
|
118
|
+
coordinates: [
|
|
119
|
+
[8.0, 46.0, 900], // approach before bottom station
|
|
120
|
+
[8.005, 46.01, 1000], // bottom station location
|
|
121
|
+
[8.015, 46.04, 1500], // top station location
|
|
122
|
+
[8.02, 46.05, 1600], // approach after top station
|
|
123
|
+
],
|
|
124
|
+
duration: 600,
|
|
125
|
+
stations: [
|
|
126
|
+
makeStation(LiftStationPosition.Bottom, [8.005, 46.01, 1000]),
|
|
127
|
+
makeStation(LiftStationPosition.Top, [8.015, 46.04, 1500]),
|
|
128
|
+
],
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
const resultWithStations = getLiftElevationData(feature)!
|
|
132
|
+
|
|
133
|
+
// Without stations, use full geometry (which is longer)
|
|
134
|
+
const featureNoStations = makeLiftFeature({
|
|
135
|
+
coordinates: [
|
|
136
|
+
[8.0, 46.0, 900],
|
|
137
|
+
[8.005, 46.01, 1000],
|
|
138
|
+
[8.015, 46.04, 1500],
|
|
139
|
+
[8.02, 46.05, 1600],
|
|
140
|
+
],
|
|
141
|
+
duration: 600,
|
|
142
|
+
stations: [],
|
|
143
|
+
})
|
|
144
|
+
const resultNoStations = getLiftElevationData(featureNoStations)!
|
|
145
|
+
|
|
146
|
+
// Station-based distance is shorter → lower speed
|
|
147
|
+
expect(resultWithStations.speedInMetersPerSecond).toBeLessThan(
|
|
148
|
+
resultNoStations.speedInMetersPerSecond!,
|
|
149
|
+
)
|
|
150
|
+
expect(resultWithStations.verticalSpeedInMetersPerSecond).toBeLessThan(
|
|
151
|
+
resultNoStations.verticalSpeedInMetersPerSecond!,
|
|
152
|
+
)
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('falls back to geometry when stations have no elevation', () => {
|
|
156
|
+
const featureWithStations = makeLiftFeature({
|
|
157
|
+
stations: [
|
|
158
|
+
makeStation(LiftStationPosition.Bottom, [8.0, 46.0]), // no Z
|
|
159
|
+
makeStation(LiftStationPosition.Top, [8.01, 46.05]), // no Z
|
|
160
|
+
],
|
|
161
|
+
})
|
|
162
|
+
const featureNoStations = makeLiftFeature({ stations: [] })
|
|
163
|
+
|
|
164
|
+
const resultWithStations = getLiftElevationData(featureWithStations)!
|
|
165
|
+
const resultNoStations = getLiftElevationData(featureNoStations)!
|
|
166
|
+
|
|
167
|
+
expect(resultWithStations.speedInMetersPerSecond).toBeCloseTo(
|
|
168
|
+
resultNoStations.speedInMetersPerSecond!,
|
|
169
|
+
)
|
|
170
|
+
})
|
|
171
|
+
})
|
|
172
|
+
|
|
5
173
|
describe('getFormattedLiftType', () => {
|
|
6
174
|
it('should format lift types correctly', () => {
|
|
7
175
|
expect(getFormattedLiftType(LiftType.ChairLift)).toBe('Chairlift');
|
|
@@ -21,4 +189,4 @@ describe('Lift', () => {
|
|
|
21
189
|
expect(getLiftColor(Status.Construction)).toBe('hsl(0, 82%, 42%)');
|
|
22
190
|
});
|
|
23
191
|
});
|
|
24
|
-
});
|
|
192
|
+
});
|
package/src/Lift.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import distance from '@turf/distance'
|
|
1
2
|
import { ElevationData, getElevationData } from './ElevationProfile'
|
|
2
3
|
import { FeatureType } from './FeatureType'
|
|
3
4
|
import { Place } from './Place'
|
|
4
5
|
import { SkiAreaSummaryFeature } from './SkiArea'
|
|
5
6
|
import { Source } from './Source'
|
|
6
|
-
import { LiftStationSpotFeature } from './Spot'
|
|
7
|
+
import { LiftStationPosition, LiftStationSpotFeature } from './Spot'
|
|
7
8
|
import { Status } from './Status'
|
|
8
9
|
import { exhaustiveMatchingGuard } from './util/exhaustiveMatchingGuard'
|
|
9
10
|
|
|
@@ -113,18 +114,59 @@ export function getLiftElevationData(
|
|
|
113
114
|
|
|
114
115
|
const elevationData = getElevationData(geometry)
|
|
115
116
|
const durationInSeconds = feature.properties.duration
|
|
117
|
+
const terminalDistances = getTerminalStationDistances(feature)
|
|
118
|
+
const inclinedLength =
|
|
119
|
+
terminalDistances?.inclinedLengthInMeters ??
|
|
120
|
+
elevationData.inclinedLengthInMeters
|
|
121
|
+
const verticalLength =
|
|
122
|
+
terminalDistances?.verticalInMeters ?? elevationData.verticalInMeters
|
|
116
123
|
|
|
117
124
|
return {
|
|
118
125
|
...elevationData,
|
|
119
126
|
speedInMetersPerSecond: durationInSeconds
|
|
120
|
-
?
|
|
127
|
+
? inclinedLength / durationInSeconds
|
|
121
128
|
: null,
|
|
122
129
|
verticalSpeedInMetersPerSecond: durationInSeconds
|
|
123
|
-
?
|
|
130
|
+
? verticalLength / durationInSeconds
|
|
124
131
|
: null,
|
|
125
132
|
}
|
|
126
133
|
}
|
|
127
134
|
|
|
135
|
+
function getTerminalStationDistances(
|
|
136
|
+
feature: LiftFeature,
|
|
137
|
+
): { inclinedLengthInMeters: number; verticalInMeters: number } | null {
|
|
138
|
+
const stations = feature.properties.stations
|
|
139
|
+
const topStation = stations.find(
|
|
140
|
+
(s) => s.properties.position === LiftStationPosition.Top,
|
|
141
|
+
)
|
|
142
|
+
const bottomStation = stations.find(
|
|
143
|
+
(s) => s.properties.position === LiftStationPosition.Bottom,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
if (!topStation || !bottomStation) {
|
|
147
|
+
return null
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const topCoords = topStation.geometry.coordinates
|
|
151
|
+
const bottomCoords = bottomStation.geometry.coordinates
|
|
152
|
+
|
|
153
|
+
if (topCoords.length < 3 || bottomCoords.length < 3) {
|
|
154
|
+
return null
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const horizontalDistanceInMeters = distance(
|
|
158
|
+
topStation.geometry,
|
|
159
|
+
bottomStation.geometry,
|
|
160
|
+
{ units: 'meters' },
|
|
161
|
+
)
|
|
162
|
+
const verticalInMeters = Math.abs(topCoords[2] - bottomCoords[2])
|
|
163
|
+
const inclinedLengthInMeters = Math.sqrt(
|
|
164
|
+
Math.pow(horizontalDistanceInMeters, 2) + Math.pow(verticalInMeters, 2),
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
return { inclinedLengthInMeters, verticalInMeters }
|
|
168
|
+
}
|
|
169
|
+
|
|
128
170
|
export function getFormattedLiftType(liftType: LiftType): string {
|
|
129
171
|
switch (liftType) {
|
|
130
172
|
case LiftType.CableCar:
|