openskidata-format 10.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.d.ts CHANGED
@@ -40,6 +40,7 @@ export type Access = 'private' | null;
40
40
  * @property {boolean | null} detachable - Whether the lift has detachable grips. Derived from the OpenStreetMap aerialway:detachable tag.
41
41
  * @property {boolean | null} bubble - Whether the lift has bubbles/covers to protect from weather. Derived from the OpenStreetMap aerialway:bubble tag.
42
42
  * @property {boolean | null} heating - Whether the lift has heated carriers/seats. Derived from the OpenStreetMap aerialway:heating tag.
43
+ * @property {boolean | null} tunnel - Whether the lift passes through a tunnel, derived from the OpenStreetMap "tunnel" tag. True for any tunnel value (e.g. "yes", "avalanche_protector", "building_passage"), null if untagged.
43
44
  * @property {LiftStationSpotFeature[]} stations - Lift station spot features associated with this lift.
44
45
  * @property {SkiAreaSummaryFeature[]} skiAreas - Ski areas this lift is a part of.
45
46
  * @property {Source[]} sources - Data sources for the feature.
@@ -64,6 +65,7 @@ export type LiftProperties = {
64
65
  detachable: boolean | null;
65
66
  bubble: boolean | null;
66
67
  heating: boolean | null;
68
+ tunnel: boolean | null;
67
69
  stations: LiftStationSpotFeature[];
68
70
  skiAreas: SkiAreaSummaryFeature[];
69
71
  sources: Source[];
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
- ? elevationData.inclinedLengthInMeters / durationInSeconds
44
+ ? inclinedLength / durationInSeconds
38
45
  : null,
39
46
  verticalSpeedInMetersPerSecond: durationInSeconds
40
- ? elevationData.verticalInMeters / durationInSeconds
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":"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"}
1
+ {"version":3,"file":"Lift.js","sourceRoot":"","sources":["../src/Lift.ts"],"names":[],"mappings":"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"}
package/dist/Run.d.ts CHANGED
@@ -44,6 +44,7 @@ export type RunFeature = GeoJSON.Feature<RunGeometry, RunProperties>;
44
44
  * @property {boolean | null} patrolled - Whether the run is patrolled by ski patrol, derived from the OpenStreetMap "piste:patrolled" or "patrolled" tag.
45
45
  * @property {boolean | null} snowmaking - Whether the run has its operation secured through snowmaking, derived from the OpenStreetMap "piste:snowmaking" tag.
46
46
  * @property {boolean | null} snowfarming - Whether the run has its early season operation secured through snowfarming (storing snow from previous season), derived from the OpenStreetMap "piste:snowfarming" tag.
47
+ * @property {boolean | null} tunnel - Whether the run passes through a tunnel, derived from the OpenStreetMap "tunnel" tag. True for any tunnel value (e.g. "yes", "avalanche_protector", "building_passage"), null if untagged.
47
48
  * @property {RunGrooming | null} grooming - Grooming status/type of the run, derived from the OpenStreetMap "piste:grooming" tag. If not specified explicitly, for difficulties "expert", "freeride", and "extreme", grooming is assumed to be "backcountry".
48
49
  * @property {SkiAreaSummaryFeature[]} skiAreas - Ski areas this run belongs to. Derived from the OpenStreetMap site=piste relation or landuse=winter_sports area and proximity to ski area features. Runs with "backcountry" grooming are not associated with ski areas unless they have a "piste:patrolled=yes" or "patrolled=yes" OpenStreetMap tag, or are part of a "site=piste" ski area relation.
49
50
  * @property {ElevationProfile | null} elevationProfile - Elevation profile of the run, only available for runs with LineString geometry.
@@ -69,6 +70,7 @@ export type RunProperties = {
69
70
  patrolled: boolean | null;
70
71
  snowmaking: boolean | null;
71
72
  snowfarming: boolean | null;
73
+ tunnel: boolean | null;
72
74
  grooming: RunGrooming | null;
73
75
  skiAreas: SkiAreaSummaryFeature[];
74
76
  elevationProfile: ElevationProfile | null;
package/dist/Run.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Run.js","sourceRoot":"","sources":["../src/Run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Run.js","sourceRoot":"","sources":["../src/Run.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openskidata-format",
3
- "version": "10.0.0",
3
+ "version": "11.1.0",
4
4
  "description": "Data format for OpenSkiMap.org",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -10,6 +10,7 @@
10
10
  ],
11
11
  "scripts": {
12
12
  "build": "rm -rf dist/ && tsc",
13
+ "prepare": "npm run build",
13
14
  "release": "npm run-script build && npm publish",
14
15
  "test": "jest",
15
16
  "test:watch": "jest --watch",
@@ -275,6 +275,7 @@ describe('ElevationProfile', () => {
275
275
  grooming: null,
276
276
  websites: [],
277
277
  wikidataID: null,
278
+ tunnel: null,
278
279
  places: [],
279
280
  },
280
281
  }
@@ -314,6 +315,7 @@ describe('ElevationProfile', () => {
314
315
  grooming: null,
315
316
  websites: [],
316
317
  wikidataID: null,
318
+ tunnel: null,
317
319
  places: [],
318
320
  },
319
321
  }
@@ -357,6 +359,7 @@ describe('ElevationProfile', () => {
357
359
  stations: [],
358
360
  websites: [],
359
361
  wikidataID: null,
362
+ tunnel: null,
360
363
  places: [],
361
364
  },
362
365
  }
@@ -403,6 +406,7 @@ describe('ElevationProfile', () => {
403
406
  sources: [],
404
407
  websites: [],
405
408
  wikidataID: null,
409
+ tunnel: null,
406
410
  places: [],
407
411
  },
408
412
  geometry: {
package/src/Lift.test.ts CHANGED
@@ -1,7 +1,175 @@
1
- import { LiftType, getFormattedLiftType, getLiftColor } from './Lift';
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
 
@@ -45,6 +46,7 @@ export type Access = 'private' | null
45
46
  * @property {boolean | null} detachable - Whether the lift has detachable grips. Derived from the OpenStreetMap aerialway:detachable tag.
46
47
  * @property {boolean | null} bubble - Whether the lift has bubbles/covers to protect from weather. Derived from the OpenStreetMap aerialway:bubble tag.
47
48
  * @property {boolean | null} heating - Whether the lift has heated carriers/seats. Derived from the OpenStreetMap aerialway:heating tag.
49
+ * @property {boolean | null} tunnel - Whether the lift passes through a tunnel, derived from the OpenStreetMap "tunnel" tag. True for any tunnel value (e.g. "yes", "avalanche_protector", "building_passage"), null if untagged.
48
50
  * @property {LiftStationSpotFeature[]} stations - Lift station spot features associated with this lift.
49
51
  * @property {SkiAreaSummaryFeature[]} skiAreas - Ski areas this lift is a part of.
50
52
  * @property {Source[]} sources - Data sources for the feature.
@@ -69,6 +71,7 @@ export type LiftProperties = {
69
71
  detachable: boolean | null
70
72
  bubble: boolean | null
71
73
  heating: boolean | null
74
+ tunnel: boolean | null
72
75
  stations: LiftStationSpotFeature[]
73
76
  skiAreas: SkiAreaSummaryFeature[]
74
77
  sources: Source[]
@@ -111,18 +114,59 @@ export function getLiftElevationData(
111
114
 
112
115
  const elevationData = getElevationData(geometry)
113
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
114
123
 
115
124
  return {
116
125
  ...elevationData,
117
126
  speedInMetersPerSecond: durationInSeconds
118
- ? elevationData.inclinedLengthInMeters / durationInSeconds
127
+ ? inclinedLength / durationInSeconds
119
128
  : null,
120
129
  verticalSpeedInMetersPerSecond: durationInSeconds
121
- ? elevationData.verticalInMeters / durationInSeconds
130
+ ? verticalLength / durationInSeconds
122
131
  : null,
123
132
  }
124
133
  }
125
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
+
126
170
  export function getFormattedLiftType(liftType: LiftType): string {
127
171
  switch (liftType) {
128
172
  case LiftType.CableCar:
package/src/Run.ts CHANGED
@@ -53,6 +53,7 @@ export type RunFeature = GeoJSON.Feature<RunGeometry, RunProperties>
53
53
  * @property {boolean | null} patrolled - Whether the run is patrolled by ski patrol, derived from the OpenStreetMap "piste:patrolled" or "patrolled" tag.
54
54
  * @property {boolean | null} snowmaking - Whether the run has its operation secured through snowmaking, derived from the OpenStreetMap "piste:snowmaking" tag.
55
55
  * @property {boolean | null} snowfarming - Whether the run has its early season operation secured through snowfarming (storing snow from previous season), derived from the OpenStreetMap "piste:snowfarming" tag.
56
+ * @property {boolean | null} tunnel - Whether the run passes through a tunnel, derived from the OpenStreetMap "tunnel" tag. True for any tunnel value (e.g. "yes", "avalanche_protector", "building_passage"), null if untagged.
56
57
  * @property {RunGrooming | null} grooming - Grooming status/type of the run, derived from the OpenStreetMap "piste:grooming" tag. If not specified explicitly, for difficulties "expert", "freeride", and "extreme", grooming is assumed to be "backcountry".
57
58
  * @property {SkiAreaSummaryFeature[]} skiAreas - Ski areas this run belongs to. Derived from the OpenStreetMap site=piste relation or landuse=winter_sports area and proximity to ski area features. Runs with "backcountry" grooming are not associated with ski areas unless they have a "piste:patrolled=yes" or "patrolled=yes" OpenStreetMap tag, or are part of a "site=piste" ski area relation.
58
59
  * @property {ElevationProfile | null} elevationProfile - Elevation profile of the run, only available for runs with LineString geometry.
@@ -78,6 +79,7 @@ export type RunProperties = {
78
79
  patrolled: boolean | null
79
80
  snowmaking: boolean | null
80
81
  snowfarming: boolean | null
82
+ tunnel: boolean | null
81
83
  grooming: RunGrooming | null
82
84
  skiAreas: SkiAreaSummaryFeature[]
83
85
  elevationProfile: ElevationProfile | null
@@ -28,6 +28,7 @@ describe("getEstimatedRunDifficulty", () => {
28
28
  sources: [],
29
29
  websites: [],
30
30
  wikidataID: null,
31
+ tunnel: null,
31
32
  places: [],
32
33
  },
33
34
  });
@@ -61,6 +62,7 @@ describe("getEstimatedRunDifficulty", () => {
61
62
  sources: [],
62
63
  websites: [],
63
64
  wikidataID: null,
65
+ tunnel: null,
64
66
  places: [],
65
67
  },
66
68
  });
@@ -98,6 +100,7 @@ describe("getEstimatedRunDifficulty", () => {
98
100
  sources: [],
99
101
  websites: [],
100
102
  wikidataID: null,
103
+ tunnel: null,
101
104
  places: [],
102
105
  },
103
106
  });
@@ -133,6 +136,7 @@ describe("getEstimatedRunDifficulty", () => {
133
136
  sources: [],
134
137
  websites: [],
135
138
  wikidataID: null,
139
+ tunnel: null,
136
140
  places: [],
137
141
  },
138
142
  });