openskidata-format 7.0.0 → 9.0.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.
@@ -29,6 +29,7 @@ type PitchData = {
29
29
  maxPitchInPercent: number | null;
30
30
  inclinedLengthInMeters: number;
31
31
  overallPitchInPercent: number | null;
32
+ pitchCalculationResolutionInMeters: number;
32
33
  };
33
34
  export declare function getElevationData(profileGeometry: GeoJSON.LineString): ElevationData;
34
35
  export declare function getPitchData(profileGeometry: GeoJSON.LineString, resolutionInMeters?: number): PitchData;
@@ -44,94 +44,82 @@ function getPitchData(profileGeometry, resolutionInMeters = 25) {
44
44
  totalInclinedLength += Math.sqrt(Math.pow(lengthInMeters, 2) + Math.pow(elevation, 2));
45
45
  totalElevationChange += Math.abs(elevation);
46
46
  }
47
- // Chunk the line into fixed-length segments for max pitch calculation
48
- const chunkedGeometries = (0, line_chunk_1.lineChunk)(profileGeometry, resolutionInMeters, {
47
+ // If the line is too short relative to the resolution, pitch calculations are unreliable
48
+ // due to elevation data resolution. A 1m elevation change over 1m distance would be a 45 degree slope,
49
+ // which can easily happen due to elevation data precision issues.
50
+ if (totalLength < resolutionInMeters / 2) {
51
+ return {
52
+ averagePitchInPercent: null,
53
+ maxPitchInPercent: null,
54
+ inclinedLengthInMeters: totalInclinedLength,
55
+ overallPitchInPercent: null,
56
+ pitchCalculationResolutionInMeters: totalLength,
57
+ };
58
+ }
59
+ // Calculate a resolution that divides the distance evenly, with the constraint that it must be <= resolutionInMeters
60
+ const numSegments = Math.ceil(totalLength / resolutionInMeters);
61
+ const actualResolution = totalLength / numSegments;
62
+ // Chunk the line into segments using the calculated resolution for max pitch calculation
63
+ const chunkedGeometries = (0, line_chunk_1.lineChunk)(profileGeometry, actualResolution, {
49
64
  units: 'meters',
50
65
  }).features.map((feature) => feature.geometry);
66
+ // turf 7.3+ adds Z coordinates to newly created points using segment-end elevation,
67
+ // but we need distance-based interpolation. Strip Z from non-original vertices so
68
+ // interpolateElevation can add them correctly.
69
+ // https://github.com/Turfjs/turf/issues/3007
70
+ stripNonOriginalElevations(chunkedGeometries, coordinates);
51
71
  // Mutates the geometries in place to add elevation data
52
72
  interpolateElevation(chunkedGeometries);
53
- // Initialize max pitch values
54
- let maxPitchValue = null;
55
- // Calculate max pitch over the fixed-length chunks
73
+ // Calculate max pitch over the evenly-divided chunks
74
+ let maxPitchValue = 0;
56
75
  for (const chunk of chunkedGeometries) {
57
76
  const chunkCoords = chunk.coordinates;
58
77
  const startPoint = chunkCoords[0];
59
78
  const endPoint = chunkCoords[chunkCoords.length - 1];
60
79
  const elevationChange = endPoint[2] - startPoint[2];
61
80
  const chunkLengthInMeters = (0, length_1.default)({ type: 'Feature', geometry: chunk, properties: {} }, { units: 'meters' });
62
- // Skip chunks that are too close together to calculate pitch reliably (can happen for the last chunk)
63
- if (chunkLengthInMeters < resolutionInMeters / 2)
64
- continue;
65
81
  const chunkPitch = Math.abs(elevationChange / chunkLengthInMeters);
66
- if (maxPitchValue === null || chunkPitch > maxPitchValue) {
82
+ if (chunkPitch > maxPitchValue) {
67
83
  maxPitchValue = chunkPitch;
68
84
  }
69
85
  }
70
86
  const averagePitch = totalElevationChange / totalLength;
71
87
  const overallElevationChange = Math.abs(coordinates[coordinates.length - 1][2] - coordinates[0][2]);
72
- // null maxPitchValue indicates the line is shorter than half the resolution, in which case the accuracy of pitch calculations
73
- // is questionable as a 1m change in elevation over
74
- // 1m of distance would be a 45 degree slope, this can happen due to resolution of the elevation data.
75
- if (maxPitchValue === null) {
76
- return {
77
- averagePitchInPercent: null,
78
- maxPitchInPercent: null,
79
- inclinedLengthInMeters: totalInclinedLength,
80
- overallPitchInPercent: null,
81
- };
82
- }
83
88
  return {
84
89
  averagePitchInPercent: averagePitch,
85
90
  maxPitchInPercent: maxPitchValue,
86
91
  inclinedLengthInMeters: totalInclinedLength,
87
92
  overallPitchInPercent: overallElevationChange / totalLength,
93
+ pitchCalculationResolutionInMeters: actualResolution,
88
94
  };
89
95
  }
90
96
  function getProfileGeometry(geometry, elevationProfile) {
91
- const geometries = lineChunksForElevationProfile(geometry, elevationProfile.resolution);
92
- var index = 0;
93
- for (let subline of geometries) {
94
- const firstPoint = subline.coordinates[0];
95
- if (firstPoint.length === 2) {
96
- firstPoint.push(elevationProfile.heights[index]);
97
- }
98
- index++;
99
- if (index === elevationProfile.heights.length) {
100
- throw 'Mismatch of points & elevation profile.';
101
- }
102
- const lastPoint = subline.coordinates[subline.coordinates.length - 1];
103
- if (lastPoint.length === 2) {
104
- lastPoint.push(elevationProfile.heights[index]);
105
- }
106
- }
107
- if (index !== elevationProfile.heights.length - 1) {
97
+ const profileLine = extractPointsForElevationProfile(geometry, elevationProfile.resolution);
98
+ if (profileLine.coordinates.length !== elevationProfile.heights.length) {
108
99
  throw `Mismatch of points & elevation profile`;
109
100
  }
110
- // Check all coordinates have a height
111
- for (let subline of geometries) {
112
- for (let point of subline.coordinates) {
113
- if (point.length < 3) {
114
- throw 'All points should have an elevation at this point.';
115
- }
116
- }
101
+ for (let i = 0; i < profileLine.coordinates.length; i++) {
102
+ const point = profileLine.coordinates[i];
103
+ const height = elevationProfile.heights[i];
104
+ point.push(height);
117
105
  }
118
- return {
119
- type: 'LineString',
120
- coordinates: geometries.flatMap((geometry) => geometry.coordinates),
121
- };
106
+ return profileLine;
122
107
  }
123
108
  /**
124
109
  * Determines the points to use for an elevation profile.
125
110
  */
126
111
  function extractPointsForElevationProfile(geometry, resolution) {
127
- const geometries = lineChunksForElevationProfile(geometry, resolution);
112
+ // Important: Z coordinates in the output of lineChunk may be incorrect, ignore them (https://github.com/Turfjs/turf/issues/3007)
113
+ const lineChunks = (0, line_chunk_1.lineChunk)(geometry, resolution, {
114
+ units: 'meters',
115
+ }).features.map((feature) => feature.geometry);
128
116
  const points = [];
129
- for (let subline of geometries) {
117
+ for (let subline of lineChunks) {
130
118
  const point = subline.coordinates[0];
131
119
  points.push([point[0], point[1]]);
132
120
  }
133
- if (geometries.length > 0) {
134
- const geometry = geometries[geometries.length - 1];
121
+ if (lineChunks.length > 0) {
122
+ const geometry = lineChunks[lineChunks.length - 1];
135
123
  const coords = geometry.coordinates;
136
124
  if (coords.length > 1) {
137
125
  const point = coords[coords.length - 1];
@@ -143,11 +131,6 @@ function extractPointsForElevationProfile(geometry, resolution) {
143
131
  coordinates: points,
144
132
  };
145
133
  }
146
- function lineChunksForElevationProfile(geometry, resolution) {
147
- return (0, line_chunk_1.lineChunk)(geometry, resolution, {
148
- units: 'meters',
149
- }).features.map((feature) => feature.geometry);
150
- }
151
134
  function getAscentAndDescent(profileGeometry) {
152
135
  const coordinates = profileGeometry.coordinates;
153
136
  if (coordinates.length === 0) {
@@ -186,6 +169,22 @@ function getAscentAndDescent(profileGeometry) {
186
169
  verticalInMeters: result.maxElevation - result.minElevation,
187
170
  };
188
171
  }
172
+ /**
173
+ * Strip Z coordinates from points that were created by lineChunk (not original vertices).
174
+ * Original vertices are identified by matching lon/lat coordinates.
175
+ * Mutates the geometries in place.
176
+ */
177
+ function stripNonOriginalElevations(geometries, originalCoordinates) {
178
+ const originalSet = new Set(originalCoordinates.map((c) => `${c[0]},${c[1]}`));
179
+ for (const geometry of geometries) {
180
+ for (const point of geometry.coordinates) {
181
+ const key = `${point[0]},${point[1]}`;
182
+ if (!originalSet.has(key) && point.length >= 3) {
183
+ point.length = 2;
184
+ }
185
+ }
186
+ }
187
+ }
189
188
  /**
190
189
  * Interpolate elevation for points along a list of linestrings that don't already have elevation.
191
190
  * Uses geographic distances for proper interpolation.
@@ -1 +1 @@
1
- {"version":3,"file":"ElevationProfile.js","sourceRoot":"","sources":["../src/ElevationProfile.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ElevationProfile.js","sourceRoot":"","sources":["../src/ElevationProfile.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  export declare enum FeatureType {
2
2
  Run = "run",
3
3
  Lift = "lift",
4
- SkiArea = "skiArea"
4
+ SkiArea = "skiArea",
5
+ Spot = "spot"
5
6
  }
@@ -6,5 +6,6 @@ var FeatureType;
6
6
  FeatureType["Run"] = "run";
7
7
  FeatureType["Lift"] = "lift";
8
8
  FeatureType["SkiArea"] = "skiArea";
9
+ FeatureType["Spot"] = "spot";
9
10
  })(FeatureType || (exports.FeatureType = FeatureType = {}));
10
11
  //# sourceMappingURL=FeatureType.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FeatureType.js","sourceRoot":"","sources":["../src/FeatureType.ts"],"names":[],"mappings":";;;AAAA,IAAY,WAIX;AAJD,WAAY,WAAW;IACrB,0BAAW,CAAA;IACX,4BAAa,CAAA;IACb,kCAAmB,CAAA;AACrB,CAAC,EAJW,WAAW,2BAAX,WAAW,QAItB"}
1
+ {"version":3,"file":"FeatureType.js","sourceRoot":"","sources":["../src/FeatureType.ts"],"names":[],"mappings":";;;AAAA,IAAY,WAKX;AALD,WAAY,WAAW;IACrB,0BAAW,CAAA;IACX,4BAAa,CAAA;IACb,kCAAmB,CAAA;IACnB,4BAAa,CAAA;AACf,CAAC,EALW,WAAW,2BAAX,WAAW,QAKtB"}
package/dist/Lift.d.ts CHANGED
@@ -3,16 +3,22 @@ import { FeatureType } from './FeatureType';
3
3
  import { Place } from './Place';
4
4
  import { SkiAreaSummaryFeature } from './SkiArea';
5
5
  import { Source } from './Source';
6
+ import { LiftStationSpotFeature } from './Spot';
6
7
  import { Status } from './Status';
7
8
  export type LiftFeature = GeoJSON.Feature<LiftGeometry, LiftProperties>;
8
9
  export type LiftGeometry = GeoJSON.LineString | GeoJSON.MultiLineString;
10
+ /**
11
+ * Access restriction for a lift feature.
12
+ * - 'private': The lift has restricted access (derived from OSM access=private tag)
13
+ * - null: No access restriction or access information not available
14
+ */
15
+ export type Access = 'private' | null;
9
16
  /**
10
17
  * A feature representing a ski lift.
11
18
  *
12
19
  * Lifts are derived from OpenStreetMap aerialway/railway features that are commonly used for winter sports.
13
20
  *
14
21
  * Note:
15
- * - Private lifts are not included in this dataset.
16
22
  * - Railways (except funiculars) are included only if they are part of a site=piste relation.
17
23
  * - Railway parts are not merged together so a single railway line may be represented as multiple features.
18
24
  * - Some lifts included in the dataset may be for other purposes (amusement parks, etc).
@@ -22,6 +28,7 @@ export type LiftGeometry = GeoJSON.LineString | GeoJSON.MultiLineString;
22
28
  * @property {string} id - Unique identifier for the lift. The ID is just a hash of the feature, so will change if the feature changes in any way.
23
29
  * @property {LiftType} liftType - Type of lift (e.g. chair_lift, gondola). Derived from OpenStreetMap aerialway/railway tags.
24
30
  * @property {Status} status - Operational status of the lift. Derived from OpenStreetMap lifecycle tags.
31
+ * @property {Access} access - Access restriction for the lift. Set to "private" when derived from OpenStreetMap access=private tag, otherwise null.
25
32
  * @property {string | null} name - Name of the lift. Derived from the OpenStreetMap name tag.
26
33
  * @property {string | null} ref - Reference code/number for the lift. Derived from the OpenStreetMap ref tag.
27
34
  * @property {string | null} refFRCAIRN - French CAIRN reference identifier. Derived from the OpenStreetMap ref:FR:CAIRN tag.
@@ -33,6 +40,7 @@ export type LiftGeometry = GeoJSON.LineString | GeoJSON.MultiLineString;
33
40
  * @property {boolean | null} detachable - Whether the lift has detachable grips. Derived from the OpenStreetMap aerialway:detachable tag.
34
41
  * @property {boolean | null} bubble - Whether the lift has bubbles/covers to protect from weather. Derived from the OpenStreetMap aerialway:bubble tag.
35
42
  * @property {boolean | null} heating - Whether the lift has heated carriers/seats. Derived from the OpenStreetMap aerialway:heating tag.
43
+ * @property {LiftStationSpotFeature[]} stations - Lift station spot features associated with this lift.
36
44
  * @property {SkiAreaSummaryFeature[]} skiAreas - Ski areas this lift is a part of.
37
45
  * @property {Source[]} sources - Data sources for the feature.
38
46
  * @property {string[]} websites - Websites associated with this lift. Derived from the OpenStreetMap website tag.
@@ -44,6 +52,7 @@ export type LiftProperties = {
44
52
  id: string;
45
53
  liftType: LiftType;
46
54
  status: Status;
55
+ access: Access;
47
56
  name: string | null;
48
57
  ref: string | null;
49
58
  refFRCAIRN: string | null;
@@ -55,6 +64,7 @@ export type LiftProperties = {
55
64
  detachable: boolean | null;
56
65
  bubble: boolean | null;
57
66
  heating: boolean | null;
67
+ stations: LiftStationSpotFeature[];
58
68
  skiAreas: SkiAreaSummaryFeature[];
59
69
  sources: Source[];
60
70
  websites: string[];
package/dist/Lift.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Lift.js","sourceRoot":"","sources":["../src/Lift.ts"],"names":[],"mappings":";;;AAwFA,oDAwBC;AAED,oDA6BC;AAED,oCAgBC;AAjKD,yDAAoE;AAKpE,qCAAiC;AACjC,4EAAwE;AA8DxE,IAAY,QAaX;AAbD,WAAY,QAAQ;IAClB,kCAAsB,CAAA;IACtB,+BAAmB,CAAA;IACnB,oCAAwB,CAAA;IACxB,oCAAwB,CAAA;IACxB,kCAAsB,CAAA;IACtB,0BAAc,CAAA;IACd,0BAAc,CAAA;IACd,+BAAmB,CAAA;IACnB,gCAAoB,CAAA;IACpB,wCAA4B,CAAA;IAC5B,mCAAuB,CAAA;IACvB,+BAAmB,CAAA;AACrB,CAAC,EAbW,QAAQ,wBAAR,QAAQ,QAanB;AAOD,SAAgB,oBAAoB,CAClC,OAAoB;IAEpB,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAA;IACjC,IACE,CAAC,QAAQ;QACT,QAAQ,CAAC,IAAI,KAAK,YAAY;QAC9B,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EAClC,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,MAAM,aAAa,GAAG,IAAA,mCAAgB,EAAC,QAAQ,CAAC,CAAA;IAChD,MAAM,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAA;IAErD,OAAO;QACL,GAAG,aAAa;QAChB,sBAAsB,EAAE,iBAAiB;YACvC,CAAC,CAAC,aAAa,CAAC,sBAAsB,GAAG,iBAAiB;YAC1D,CAAC,CAAC,IAAI;QACR,8BAA8B,EAAE,iBAAiB;YAC/C,CAAC,CAAC,aAAa,CAAC,gBAAgB,GAAG,iBAAiB;YACpD,CAAC,CAAC,IAAI;KACT,CAAA;AACH,CAAC;AAED,SAAgB,oBAAoB,CAAC,QAAkB;IACrD,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,QAAQ,CAAC,QAAQ;YACpB,OAAO,WAAW,CAAA;QACpB,KAAK,QAAQ,CAAC,OAAO;YACnB,OAAO,SAAS,CAAA;QAClB,KAAK,QAAQ,CAAC,SAAS;YACrB,OAAO,WAAW,CAAA;QACpB,KAAK,QAAQ,CAAC,SAAS;YACrB,OAAO,QAAQ,CAAA;QACjB,KAAK,QAAQ,CAAC,QAAQ;YACpB,OAAO,WAAW,CAAA;QACpB,KAAK,QAAQ,CAAC,IAAI;YAChB,OAAO,OAAO,CAAA;QAChB,KAAK,QAAQ,CAAC,IAAI;YAChB,OAAO,OAAO,CAAA;QAChB,KAAK,QAAQ,CAAC,OAAO;YACnB,OAAO,SAAS,CAAA;QAClB,KAAK,QAAQ,CAAC,OAAO;YACnB,OAAO,SAAS,CAAA;QAClB,KAAK,QAAQ,CAAC,WAAW;YACvB,OAAO,cAAc,CAAA;QACvB,KAAK,QAAQ,CAAC,SAAS;YACrB,OAAO,WAAW,CAAA;QACpB,KAAK,QAAQ,CAAC,OAAO;YACnB,OAAO,SAAS,CAAA;QAClB;YACE,OAAO,IAAA,iDAAuB,EAAC,QAAQ,CAAC,CAAA;IAC5C,CAAC;AACH,CAAC;AAED,SAAgB,YAAY,CAAC,MAAc;IACzC,MAAM,gBAAgB,GAAG,kBAAkB,CAAA;IAC3C,MAAM,aAAa,GAAG,kBAAkB,CAAA;IAExC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,eAAM,CAAC,OAAO,CAAC;QACpB,KAAK,eAAM,CAAC,SAAS;YACnB,OAAO,aAAa,CAAA;QACtB,KAAK,eAAM,CAAC,QAAQ,CAAC;QACrB,KAAK,eAAM,CAAC,OAAO,CAAC;QACpB,KAAK,eAAM,CAAC,YAAY,CAAC;QACzB,KAAK,eAAM,CAAC,SAAS;YACnB,OAAO,gBAAgB,CAAA;QACzB;YACE,OAAO,IAAA,iDAAuB,EAAC,MAAM,CAAC,CAAA;IAC1C,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"Lift.js","sourceRoot":"","sources":["../src/Lift.ts"],"names":[],"mappings":"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"}
package/dist/Run.d.ts CHANGED
@@ -42,6 +42,8 @@ export type RunFeature = GeoJSON.Feature<RunGeometry, RunProperties>;
42
42
  * @property {boolean | null} lit - Whether the run has lighting for night skiing, derived from the OpenStreetMap "piste:lit" or "lit" tag.
43
43
  * @property {boolean | null} gladed - Whether the run is through gladed/tree terrain, derived from the OpenStreetMap "piste:gladed" or "gladed" tag.
44
44
  * @property {boolean | null} patrolled - Whether the run is patrolled by ski patrol, derived from the OpenStreetMap "piste:patrolled" or "patrolled" tag.
45
+ * @property {boolean | null} snowmaking - Whether the run has its operation secured through snowmaking, derived from the OpenStreetMap "piste:snowmaking" tag.
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.
45
47
  * @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".
46
48
  * @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.
47
49
  * @property {ElevationProfile | null} elevationProfile - Elevation profile of the run, only available for runs with LineString geometry.
@@ -65,6 +67,8 @@ export type RunProperties = {
65
67
  lit: boolean | null;
66
68
  gladed: boolean | null;
67
69
  patrolled: boolean | null;
70
+ snowmaking: boolean | null;
71
+ snowfarming: boolean | null;
68
72
  grooming: RunGrooming | null;
69
73
  skiAreas: SkiAreaSummaryFeature[];
70
74
  elevationProfile: ElevationProfile | null;
package/dist/Run.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Run.js","sourceRoot":"","sources":["../src/Run.ts"],"names":[],"mappings":";;;AA0IA,kDAUC;AAED,kCAKC;AAED,kDAiBC;AAED,0CAyDC;AAxOD,yDAK2B;AAG3B,uEAAmE;AAKnE,4EAAwE;AAwExE,IAAY,MAYX;AAZD,WAAY,MAAM;IAChB,+BAAqB,CAAA;IACrB,2BAAiB,CAAA;IACjB,6BAAmB,CAAA;IACnB,uBAAa,CAAA;IACb,uBAAa,CAAA;IACb,2BAAiB,CAAA;IACjB,gCAAsB,CAAA;IACtB,gCAAsB,CAAA;IACtB,mCAAyB,CAAA;IACzB,mCAAyB,CAAA;IACzB,6BAAmB,CAAA;AACrB,CAAC,EAZW,MAAM,sBAAN,MAAM,QAYjB;AAED,IAAY,WAOX;AAPD,WAAY,WAAW;IACrB,kCAAmB,CAAA;IACnB,8BAAe,CAAA;IACf,oDAAqC,CAAA;IACrC,kCAAmB,CAAA;IACnB,kCAAmB,CAAA;IACnB,0CAA2B,CAAA;AAC7B,CAAC,EAPW,WAAW,2BAAX,WAAW,QAOtB;AAED,IAAY,aAQX;AARD,WAAY,aAAa;IACvB,kCAAiB,CAAA;IACjB,8BAAa,CAAA;IACb,8CAA6B,CAAA;IAC7B,sCAAqB,CAAA;IACrB,kCAAiB,CAAA;IACjB,sCAAqB,CAAA;IACrB,oCAAmB,CAAA;AACrB,CAAC,EARW,aAAa,6BAAb,aAAa,QAQxB;AAED,IAAY,YAOX;AAPD,WAAY,YAAY;IACtB,+BAAe,CAAA;IACf,6BAAa,CAAA;IACb,2BAAW,CAAA;IACX,+BAAe,CAAA;IACf,iCAAiB,CAAA;IACjB,6BAAa,CAAA;AACf,CAAC,EAPW,YAAY,4BAAZ,YAAY,QAOvB;AAED,IAAY,aAOX;AAPD,WAAY,aAAa;IACvB,8CAA6B,CAAA;IAC7B,6CAA4B,CAAA;IAC5B,2CAA0B,CAAA;IAC1B,yCAAwB,CAAA;IACxB,8CAA6B,CAAA;IAC7B,yCAAwB,CAAA;AAC1B,CAAC,EAPW,aAAa,6BAAb,aAAa,QAOxB;AAGD,SAAgB,mBAAmB,CAAC,OAAmB;IACrD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAA;IACjC,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAA;IACnD,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAC5D,OAAO,IAAI,CAAA;IACb,CAAC;IAED,+EAA+E;IAC/E,MAAM,eAAe,GAAG,IAAA,qCAAkB,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAC7D,OAAO,IAAA,mCAAgB,EAAC,eAAe,CAAC,CAAA;AAC1C,CAAC;AAED,SAAgB,WAAW,CACzB,UAAmC,EACnC,UAAgC;IAEhC,OAAO,mBAAmB,CAAC,eAAe,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAA;AACrE,CAAC;AAED,SAAgB,mBAAmB,CAAC,KAAmB;IACrD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,YAAY,CAAC,KAAK;YACrB,OAAO,aAAa,CAAC,KAAK,CAAA;QAC5B,KAAK,YAAY,CAAC,IAAI;YACpB,OAAO,aAAa,CAAC,IAAI,CAAA;QAC3B,KAAK,YAAY,CAAC,GAAG;YACnB,OAAO,aAAa,CAAC,GAAG,CAAA;QAC1B,KAAK,YAAY,CAAC,KAAK;YACrB,OAAO,aAAa,CAAC,KAAK,CAAA;QAC5B,KAAK,YAAY,CAAC,MAAM;YACtB,OAAO,aAAa,CAAC,MAAM,CAAA;QAC7B,KAAK,YAAY,CAAC,IAAI;YACpB,OAAO,aAAa,CAAC,IAAI,CAAA;QAC3B;YACE,MAAM,eAAe,CAAA;IACzB,CAAC;AACH,CAAC;AAED,SAAgB,eAAe,CAC7B,UAAmC,EACnC,UAAgC;IAEhC,QAAQ,UAAU,EAAE,CAAC;QACnB,KAAK,iDAAuB,CAAC,MAAM;YACjC,QAAQ,UAAU,EAAE,CAAC;gBACnB,KAAK,aAAa,CAAC,MAAM;oBACvB,OAAO,YAAY,CAAC,KAAK,CAAA;gBAC3B,KAAK,aAAa,CAAC,IAAI;oBACrB,OAAO,YAAY,CAAC,IAAI,CAAA;gBAC1B,KAAK,aAAa,CAAC,YAAY;oBAC7B,OAAO,YAAY,CAAC,GAAG,CAAA;gBACzB,KAAK,aAAa,CAAC,QAAQ,CAAC;gBAC5B,KAAK,aAAa,CAAC,MAAM;oBACvB,OAAO,YAAY,CAAC,KAAK,CAAA;gBAC3B,KAAK,aAAa,CAAC,QAAQ,CAAC;gBAC5B,KAAK,aAAa,CAAC,OAAO;oBACxB,OAAO,YAAY,CAAC,MAAM,CAAA;gBAC5B;oBACE,OAAO,YAAY,CAAC,IAAI,CAAA;YAC5B,CAAC;QACH,KAAK,iDAAuB,CAAC,KAAK;YAChC,QAAQ,UAAU,EAAE,CAAC;gBACnB,KAAK,aAAa,CAAC,MAAM,CAAC;gBAC1B,KAAK,aAAa,CAAC,IAAI;oBACrB,OAAO,YAAY,CAAC,KAAK,CAAA;gBAC3B,KAAK,aAAa,CAAC,YAAY;oBAC7B,OAAO,YAAY,CAAC,GAAG,CAAA;gBACzB,KAAK,aAAa,CAAC,QAAQ,CAAC;gBAC5B,KAAK,aAAa,CAAC,MAAM;oBACvB,OAAO,YAAY,CAAC,KAAK,CAAA;gBAC3B,KAAK,aAAa,CAAC,QAAQ,CAAC;gBAC5B,KAAK,aAAa,CAAC,OAAO;oBACxB,OAAO,YAAY,CAAC,MAAM,CAAA;gBAC5B;oBACE,OAAO,YAAY,CAAC,IAAI,CAAA;YAC5B,CAAC;QACH,KAAK,iDAAuB,CAAC,aAAa;YACxC,QAAQ,UAAU,EAAE,CAAC;gBACnB,KAAK,aAAa,CAAC,MAAM,CAAC;gBAC1B,KAAK,aAAa,CAAC,IAAI;oBACrB,OAAO,YAAY,CAAC,KAAK,CAAA;gBAC3B,KAAK,aAAa,CAAC,YAAY;oBAC7B,OAAO,YAAY,CAAC,IAAI,CAAA;gBAC1B,KAAK,aAAa,CAAC,QAAQ,CAAC;gBAC5B,KAAK,aAAa,CAAC,MAAM;oBACvB,OAAO,YAAY,CAAC,KAAK,CAAA;gBAC3B,KAAK,aAAa,CAAC,QAAQ,CAAC;gBAC5B,KAAK,aAAa,CAAC,OAAO;oBACxB,OAAO,YAAY,CAAC,MAAM,CAAA;gBAC5B;oBACE,OAAO,YAAY,CAAC,IAAI,CAAA;YAC5B,CAAC;QACH;YACE,OAAO,IAAA,iDAAuB,EAAC,UAAU,CAAC,CAAA;IAC9C,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"Run.js","sourceRoot":"","sources":["../src/Run.ts"],"names":[],"mappings":"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"}
package/dist/SkiArea.d.ts CHANGED
@@ -90,6 +90,8 @@ export type RunStatisticsByDifficulty = {
90
90
  [key in RunDifficulty | 'other']?: {
91
91
  count: number;
92
92
  lengthInKm: number;
93
+ snowmakingLengthInKm?: number;
94
+ snowfarmingLengthInKm?: number;
93
95
  };
94
96
  };
95
97
  export type LiftStatistics = {
package/dist/Spot.d.ts ADDED
@@ -0,0 +1,116 @@
1
+ import * as GeoJSON from 'geojson';
2
+ import { FeatureType } from './FeatureType';
3
+ import { Place } from './Place';
4
+ import { SkiAreaSummaryFeature } from './SkiArea';
5
+ import { Source } from './Source';
6
+ /**
7
+ * A GeoJSON feature representing a spot (point of interest) in or around a ski area.
8
+ *
9
+ * Spots are used to represent lift stations, road crossings, or certain terrain features.
10
+ */
11
+ export type SpotFeature = GeoJSON.Feature<SpotGeometry, SpotProperties>;
12
+ /**
13
+ * A GeoJSON feature representing a lift station spot.
14
+ */
15
+ export type LiftStationSpotFeature = GeoJSON.Feature<SpotGeometry, LiftStationSpotProperties>;
16
+ /**
17
+ * Geometry type for spots - always a point.
18
+ */
19
+ export type SpotGeometry = GeoJSON.Point;
20
+ /**
21
+ * Union of all spot property types.
22
+ */
23
+ export type SpotProperties = CrossingSpotProperties | LiftStationSpotProperties | AvalancheTransceiverTrainingSpotProperties | AvalancheTransceiverCheckpointSpotProperties | HalfpipeSpotProperties;
24
+ /**
25
+ * Base properties shared by all spot types.
26
+ */
27
+ export type SpotBaseProperties = {
28
+ type: FeatureType.Spot;
29
+ id: string;
30
+ skiAreas: SkiAreaSummaryFeature[];
31
+ sources: Source[];
32
+ places: Place[];
33
+ };
34
+ /**
35
+ * Types of spots that can be found in or around ski areas.
36
+ */
37
+ export declare enum SpotType {
38
+ Crossing = "crossing",
39
+ LiftStation = "lift_station",
40
+ AvalancheTransceiverTraining = "avalanche_transceiver_training",
41
+ AvalancheTransceiverCheckpoint = "avalanche_transceiver_checkpoint",
42
+ Halfpipe = "halfpipe"
43
+ }
44
+ /**
45
+ * A crossing is a point where a ski run intersects with a road or path,
46
+ * potentially requiring skiers to remove their skis.
47
+ *
48
+ * From OpenStreetMap node with tag `piste:dismount=yes|no|sometimes`.
49
+ */
50
+ export type CrossingSpotProperties = SpotBaseProperties & {
51
+ spotType: SpotType.Crossing;
52
+ dismount: DismountRequirement;
53
+ };
54
+ /**
55
+ * Whether dismounting from skis is required at a crossing.
56
+ */
57
+ export declare enum DismountRequirement {
58
+ Yes = "yes",
59
+ No = "no",
60
+ Sometimes = "sometimes"
61
+ }
62
+ /**
63
+ * A lift station is a boarding or alighting point for a ski lift.
64
+ *
65
+ * From OpenStreetMap node or area with tag `aerialway=station`.
66
+ * Areas are represented as a point (centroid).
67
+ *
68
+ * @property {string | null} name - Name of the station, from OpenStreetMap tag `name`.
69
+ * @property {LiftStationPosition | null} position - From OpenStreetMap tag `aerialway:station=bottom|mid|top`.
70
+ * @property {boolean | null} entry - Whether passengers can board here. From OpenStreetMap tag `aerialway:access=entry|both|no`.
71
+ * @property {boolean | null} exit - Whether passengers can alight here. From OpenStreetMap tag `aerialway:access=exit|both|no`.
72
+ * @property {string} liftId - ID of the lift feature associated with this station.
73
+ */
74
+ export type LiftStationSpotProperties = SpotBaseProperties & {
75
+ spotType: SpotType.LiftStation;
76
+ name: string | null;
77
+ position: LiftStationPosition | null;
78
+ entry: boolean | null;
79
+ exit: boolean | null;
80
+ liftId: string;
81
+ };
82
+ /**
83
+ * Position of a lift station along the lift line.
84
+ */
85
+ export declare enum LiftStationPosition {
86
+ Top = "top",
87
+ Mid = "mid",
88
+ Bottom = "bottom"
89
+ }
90
+ /**
91
+ * A designated area where skiers can practice using avalanche transceivers.
92
+ *
93
+ * From OpenStreetMap node or area with tags `amenity=avalanche_transceiver` and `avalanche_transceiver=training`.
94
+ * Areas are represented as a point (centroid).
95
+ */
96
+ export type AvalancheTransceiverTrainingSpotProperties = SpotBaseProperties & {
97
+ spotType: SpotType.AvalancheTransceiverTraining;
98
+ };
99
+ /**
100
+ * A checkpoint where skiers can verify their avalanche transceiver is functioning.
101
+ *
102
+ * From OpenStreetMap node or area with tags `amenity=avalanche_transceiver` and `avalanche_transceiver=checkpoint`.
103
+ * Areas are represented as a point (centroid).
104
+ */
105
+ export type AvalancheTransceiverCheckpointSpotProperties = SpotBaseProperties & {
106
+ spotType: SpotType.AvalancheTransceiverCheckpoint;
107
+ };
108
+ /**
109
+ * A halfpipe structure for freestyle skiing or snowboarding.
110
+ *
111
+ * From OpenStreetMap node/way/area with tag `man_made=piste:halfpipe`.
112
+ * Areas are represented as a point (centroid).
113
+ */
114
+ export type HalfpipeSpotProperties = SpotBaseProperties & {
115
+ spotType: SpotType.Halfpipe;
116
+ };
package/dist/Spot.js ADDED
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LiftStationPosition = exports.DismountRequirement = exports.SpotType = void 0;
4
+ /**
5
+ * Types of spots that can be found in or around ski areas.
6
+ */
7
+ var SpotType;
8
+ (function (SpotType) {
9
+ SpotType["Crossing"] = "crossing";
10
+ SpotType["LiftStation"] = "lift_station";
11
+ SpotType["AvalancheTransceiverTraining"] = "avalanche_transceiver_training";
12
+ SpotType["AvalancheTransceiverCheckpoint"] = "avalanche_transceiver_checkpoint";
13
+ SpotType["Halfpipe"] = "halfpipe";
14
+ })(SpotType || (exports.SpotType = SpotType = {}));
15
+ /**
16
+ * Whether dismounting from skis is required at a crossing.
17
+ */
18
+ var DismountRequirement;
19
+ (function (DismountRequirement) {
20
+ DismountRequirement["Yes"] = "yes";
21
+ DismountRequirement["No"] = "no";
22
+ DismountRequirement["Sometimes"] = "sometimes";
23
+ })(DismountRequirement || (exports.DismountRequirement = DismountRequirement = {}));
24
+ /**
25
+ * Position of a lift station along the lift line.
26
+ */
27
+ var LiftStationPosition;
28
+ (function (LiftStationPosition) {
29
+ LiftStationPosition["Top"] = "top";
30
+ LiftStationPosition["Mid"] = "mid";
31
+ LiftStationPosition["Bottom"] = "bottom";
32
+ })(LiftStationPosition || (exports.LiftStationPosition = LiftStationPosition = {}));
33
+ //# sourceMappingURL=Spot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Spot.js","sourceRoot":"","sources":["../src/Spot.ts"],"names":[],"mappings":";;;AA+CA;;GAEG;AACH,IAAY,QAMX;AAND,WAAY,QAAQ;IAClB,iCAAqB,CAAA;IACrB,wCAA4B,CAAA;IAC5B,2EAA+D,CAAA;IAC/D,+EAAmE,CAAA;IACnE,iCAAqB,CAAA;AACvB,CAAC,EANW,QAAQ,wBAAR,QAAQ,QAMnB;AAaD;;GAEG;AACH,IAAY,mBAIX;AAJD,WAAY,mBAAmB;IAC7B,kCAAW,CAAA;IACX,gCAAS,CAAA;IACT,8CAAuB,CAAA;AACzB,CAAC,EAJW,mBAAmB,mCAAnB,mBAAmB,QAI9B;AAuBD;;GAEG;AACH,IAAY,mBAIX;AAJD,WAAY,mBAAmB;IAC7B,kCAAW,CAAA;IACX,kCAAW,CAAA;IACX,wCAAiB,CAAA;AACnB,CAAC,EAJW,mBAAmB,mCAAnB,mBAAmB,QAI9B"}
package/dist/index.d.ts CHANGED
@@ -9,4 +9,5 @@ export * from './SlopeGradingScale';
9
9
  export * from './SkiArea';
10
10
  export * from './SnowCoverHistory';
11
11
  export * from './Source';
12
+ export * from './Spot';
12
13
  export * from './Status';
package/dist/index.js CHANGED
@@ -12,5 +12,6 @@ tslib_1.__exportStar(require("./SlopeGradingScale"), exports);
12
12
  tslib_1.__exportStar(require("./SkiArea"), exports);
13
13
  tslib_1.__exportStar(require("./SnowCoverHistory"), exports);
14
14
  tslib_1.__exportStar(require("./Source"), exports);
15
+ tslib_1.__exportStar(require("./Spot"), exports);
15
16
  tslib_1.__exportStar(require("./Status"), exports);
16
17
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,6DAAkC;AAClC,wDAA6B;AAC7B,iDAAsB;AACtB,8DAAmC;AACnC,kDAAuB;AACvB,gDAAqB;AACrB,oEAAyC;AACzC,8DAAmC;AACnC,oDAAyB;AACzB,6DAAkC;AAClC,mDAAwB;AACxB,mDAAwB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,6DAAkC;AAClC,wDAA6B;AAC7B,iDAAsB;AACtB,8DAAmC;AACnC,kDAAuB;AACvB,gDAAqB;AACrB,oEAAyC;AACzC,8DAAmC;AACnC,oDAAyB;AACzB,6DAAkC;AAClC,mDAAwB;AACxB,iDAAsB;AACtB,mDAAwB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openskidata-format",
3
- "version": "7.0.0",
3
+ "version": "9.0.0",
4
4
  "description": "Data format for OpenSkiMap.org",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -26,19 +26,19 @@
26
26
  },
27
27
  "homepage": "https://github.com/russellporter/openskidata-format#readme",
28
28
  "devDependencies": {
29
- "@types/geojson": "^7946.0.7",
30
- "@types/jest": "^29.5.14",
31
- "jest": "^29.7.0",
32
- "ts-jest": "^29.2.6",
33
- "typescript": "^5"
29
+ "@types/geojson": "^7946.0.16",
30
+ "@types/jest": "^30.0.0",
31
+ "jest": "^30.2.0",
32
+ "ts-jest": "^29.4.6",
33
+ "typescript": "^5.9.3"
34
34
  },
35
35
  "dependencies": {
36
- "@turf/boolean-point-in-polygon": "^7.2.0",
37
- "@turf/center": "^7.2.0",
38
- "@turf/distance": "^7.2.0",
39
- "@turf/helpers": "^7.2.0",
40
- "@turf/length": "^7.2.0",
41
- "@turf/line-chunk": "^7.2.0",
42
- "tslib": "^2"
36
+ "@turf/boolean-point-in-polygon": "^7.3.2",
37
+ "@turf/center": "^7.3.2",
38
+ "@turf/distance": "^7.3.2",
39
+ "@turf/helpers": "^7.3.2",
40
+ "@turf/length": "^7.3.2",
41
+ "@turf/line-chunk": "^7.3.2",
42
+ "tslib": "^2.8.1"
43
43
  }
44
44
  }
@@ -74,7 +74,11 @@ describe('ElevationProfile', () => {
74
74
 
75
75
  const result = getPitchData(profileGeometry)
76
76
 
77
- expect(result.maxPitchInPercent).toBeCloseTo(0.377)
77
+ // With the new resolution calculation, the actual resolution divides the distance evenly
78
+ // Total length is ~60.44m, with default resolution of 25m: numSegments = ceil(60.44/25) = 3, actualResolution = 60.44/3 ≈ 20.15m
79
+ expect(result.pitchCalculationResolutionInMeters).toBeCloseTo(20.15, 1)
80
+ expect(result.pitchCalculationResolutionInMeters).toBeLessThanOrEqual(25)
81
+ expect(result.maxPitchInPercent).toBeCloseTo(0.489, 2)
78
82
  expect(result.averagePitchInPercent).toBeCloseTo(0.2482)
79
83
  expect(result.inclinedLengthInMeters).toBeCloseTo(63.0597)
80
84
  })
@@ -97,6 +101,101 @@ describe('ElevationProfile', () => {
97
101
  // The overall change should be more reasonable when calculated over fixed distances
98
102
  expect(result.maxPitchInPercent).toBeLessThan(0.5) // Should be much less than the individual segment pitch
99
103
  })
104
+
105
+ it('calculates resolution that divides distance evenly', () => {
106
+ const profileGeometry: GeoJSON.LineString = {
107
+ type: 'LineString',
108
+ coordinates: [
109
+ [0, 0, 100],
110
+ [0, 0.001, 110], // ~111m distance
111
+ [0, 0.002, 105], // ~111m distance
112
+ ],
113
+ }
114
+
115
+ const result = getPitchData(profileGeometry, 50)
116
+
117
+ // Resolution should be <= 50
118
+ expect(result.pitchCalculationResolutionInMeters).toBeLessThanOrEqual(50)
119
+
120
+ // With ~222m total length and 50m input resolution:
121
+ // numSegments = ceil(222/50) = 5
122
+ // actualResolution = 222/5 = 44.4m
123
+ expect(result.pitchCalculationResolutionInMeters).toBeCloseTo(44.4, 0)
124
+ })
125
+
126
+ it('uses total length as resolution when line is shorter than input resolution', () => {
127
+ const profileGeometry: GeoJSON.LineString = {
128
+ type: 'LineString',
129
+ coordinates: [
130
+ [0, 0, 100],
131
+ [0, 0.0001, 110], // ~11m distance
132
+ ],
133
+ }
134
+
135
+ const result = getPitchData(profileGeometry, 50)
136
+
137
+ // Resolution should equal the total length since numSegments = ceil(11/50) = 1
138
+ // actualResolution = 11/1 = 11m
139
+ expect(result.pitchCalculationResolutionInMeters).toBeCloseTo(11.1, 0)
140
+ expect(result.pitchCalculationResolutionInMeters).toBeLessThanOrEqual(50)
141
+ })
142
+
143
+ it('ensures all chunks are processed without skipping short chunks', () => {
144
+ // Create a line that would previously have a short final chunk
145
+ const profileGeometry: GeoJSON.LineString = {
146
+ type: 'LineString',
147
+ coordinates: [
148
+ [11.177425600412874, 47.31265682344346, 100],
149
+ [11.177224899122194, 47.312533118812354, 120], // ~20m, steep
150
+ [11.176823496540862, 47.31229807921545, 105], // ~40m, gentle descent
151
+ ],
152
+ }
153
+
154
+ const result = getPitchData(profileGeometry, 25)
155
+
156
+ // With evenly divided chunks, no chunks should be skipped
157
+ // The max pitch should be calculated from all segments
158
+ expect(result.maxPitchInPercent).toBeGreaterThan(0)
159
+ expect(result.pitchCalculationResolutionInMeters).toBeCloseTo(20.15, 1)
160
+ })
161
+
162
+ it('returns null pitch data for very short lines', () => {
163
+ const profileGeometry: GeoJSON.LineString = {
164
+ type: 'LineString',
165
+ coordinates: [
166
+ [0, 0, 100],
167
+ [0, 0.00001, 101], // ~1.11m distance
168
+ ],
169
+ }
170
+
171
+ const result = getPitchData(profileGeometry, 25)
172
+
173
+ // Lines shorter than half the resolution should return null pitch data
174
+ // because elevation data resolution makes pitch calculations unreliable
175
+ expect(result.pitchCalculationResolutionInMeters).toBeCloseTo(1.11, 1)
176
+ expect(result.maxPitchInPercent).toBeNull()
177
+ expect(result.averagePitchInPercent).toBeNull()
178
+ expect(result.overallPitchInPercent).toBeNull()
179
+ expect(result.inclinedLengthInMeters).toBeGreaterThan(0) // This should still be calculated
180
+ })
181
+
182
+ it('calculates pitch data for lines just above the minimum threshold', () => {
183
+ const profileGeometry: GeoJSON.LineString = {
184
+ type: 'LineString',
185
+ coordinates: [
186
+ [0, 0, 100],
187
+ [0, 0.00015, 105], // ~16.7m distance, just above half of 25m
188
+ ],
189
+ }
190
+
191
+ const result = getPitchData(profileGeometry, 25)
192
+
193
+ // Lines at or above half the resolution should calculate pitch data
194
+ expect(result.pitchCalculationResolutionInMeters).toBeCloseTo(16.7, 0)
195
+ expect(result.maxPitchInPercent).not.toBeNull()
196
+ expect(result.averagePitchInPercent).not.toBeNull()
197
+ expect(result.overallPitchInPercent).not.toBeNull()
198
+ })
100
199
  })
101
200
 
102
201
  describe('extractPointsForElevationProfile', () => {
@@ -174,6 +273,8 @@ describe('ElevationProfile', () => {
174
273
  lit: null,
175
274
  gladed: null,
176
275
  patrolled: null,
276
+ snowmaking: null,
277
+ snowfarming: null,
177
278
  grooming: null,
178
279
  websites: [],
179
280
  wikidataID: null,
@@ -211,6 +312,8 @@ describe('ElevationProfile', () => {
211
312
  lit: null,
212
313
  gladed: null,
213
314
  patrolled: null,
315
+ snowmaking: null,
316
+ snowfarming: null,
214
317
  grooming: null,
215
318
  websites: [],
216
319
  wikidataID: null,
@@ -235,6 +338,7 @@ describe('ElevationProfile', () => {
235
338
  id: '123',
236
339
  liftType: LiftType.ChairLift,
237
340
  status: Status.Operating,
341
+ access: null,
238
342
  name: 'Test Lift',
239
343
  skiAreas: [],
240
344
  sources: [],
@@ -248,6 +352,7 @@ describe('ElevationProfile', () => {
248
352
  detachable: null,
249
353
  bubble: null,
250
354
  heating: null,
355
+ stations: [],
251
356
  websites: [],
252
357
  wikidataID: null,
253
358
  places: [],
@@ -274,6 +379,8 @@ describe('ElevationProfile', () => {
274
379
  lit: null,
275
380
  gladed: null,
276
381
  patrolled: null,
382
+ snowmaking: null,
383
+ snowfarming: null,
277
384
  grooming: 'classic+skating',
278
385
  skiAreas: [],
279
386
  elevationProfile: {
@@ -37,6 +37,7 @@ type PitchData = {
37
37
  maxPitchInPercent: number | null
38
38
  inclinedLengthInMeters: number
39
39
  overallPitchInPercent: number | null
40
+ pitchCalculationResolutionInMeters: number
40
41
  }
41
42
 
42
43
  export function getElevationData(
@@ -86,18 +87,39 @@ export function getPitchData(
86
87
  totalElevationChange += Math.abs(elevation)
87
88
  }
88
89
 
89
- // Chunk the line into fixed-length segments for max pitch calculation
90
- const chunkedGeometries = lineChunk(profileGeometry, resolutionInMeters, {
90
+ // If the line is too short relative to the resolution, pitch calculations are unreliable
91
+ // due to elevation data resolution. A 1m elevation change over 1m distance would be a 45 degree slope,
92
+ // which can easily happen due to elevation data precision issues.
93
+ if (totalLength < resolutionInMeters / 2) {
94
+ return {
95
+ averagePitchInPercent: null,
96
+ maxPitchInPercent: null,
97
+ inclinedLengthInMeters: totalInclinedLength,
98
+ overallPitchInPercent: null,
99
+ pitchCalculationResolutionInMeters: totalLength,
100
+ }
101
+ }
102
+
103
+ // Calculate a resolution that divides the distance evenly, with the constraint that it must be <= resolutionInMeters
104
+ const numSegments = Math.ceil(totalLength / resolutionInMeters)
105
+ const actualResolution = totalLength / numSegments
106
+
107
+ // Chunk the line into segments using the calculated resolution for max pitch calculation
108
+ const chunkedGeometries = lineChunk(profileGeometry, actualResolution, {
91
109
  units: 'meters',
92
110
  }).features.map((feature) => feature.geometry)
93
111
 
112
+ // turf 7.3+ adds Z coordinates to newly created points using segment-end elevation,
113
+ // but we need distance-based interpolation. Strip Z from non-original vertices so
114
+ // interpolateElevation can add them correctly.
115
+ // https://github.com/Turfjs/turf/issues/3007
116
+ stripNonOriginalElevations(chunkedGeometries, coordinates)
117
+
94
118
  // Mutates the geometries in place to add elevation data
95
119
  interpolateElevation(chunkedGeometries)
96
120
 
97
- // Initialize max pitch values
98
- let maxPitchValue: number | null = null
99
-
100
- // Calculate max pitch over the fixed-length chunks
121
+ // Calculate max pitch over the evenly-divided chunks
122
+ let maxPitchValue = 0
101
123
  for (const chunk of chunkedGeometries) {
102
124
  const chunkCoords = chunk.coordinates
103
125
 
@@ -110,11 +132,8 @@ export function getPitchData(
110
132
  { units: 'meters' },
111
133
  )
112
134
 
113
- // Skip chunks that are too close together to calculate pitch reliably (can happen for the last chunk)
114
- if (chunkLengthInMeters < resolutionInMeters / 2) continue
115
-
116
135
  const chunkPitch = Math.abs(elevationChange / chunkLengthInMeters)
117
- if (maxPitchValue === null || chunkPitch > maxPitchValue) {
136
+ if (chunkPitch > maxPitchValue) {
118
137
  maxPitchValue = chunkPitch
119
138
  }
120
139
  }
@@ -124,23 +143,12 @@ export function getPitchData(
124
143
  coordinates[coordinates.length - 1][2] - coordinates[0][2],
125
144
  )
126
145
 
127
- // null maxPitchValue indicates the line is shorter than half the resolution, in which case the accuracy of pitch calculations
128
- // is questionable as a 1m change in elevation over
129
- // 1m of distance would be a 45 degree slope, this can happen due to resolution of the elevation data.
130
- if (maxPitchValue === null) {
131
- return {
132
- averagePitchInPercent: null,
133
- maxPitchInPercent: null,
134
- inclinedLengthInMeters: totalInclinedLength,
135
- overallPitchInPercent: null,
136
- }
137
- }
138
-
139
146
  return {
140
147
  averagePitchInPercent: averagePitch,
141
148
  maxPitchInPercent: maxPitchValue,
142
149
  inclinedLengthInMeters: totalInclinedLength,
143
150
  overallPitchInPercent: overallElevationChange / totalLength,
151
+ pitchCalculationResolutionInMeters: actualResolution,
144
152
  }
145
153
  }
146
154
 
@@ -148,46 +156,21 @@ export function getProfileGeometry(
148
156
  geometry: GeoJSON.LineString,
149
157
  elevationProfile: ElevationProfile,
150
158
  ): GeoJSON.LineString {
151
- const geometries = lineChunksForElevationProfile(
159
+ const profileLine = extractPointsForElevationProfile(
152
160
  geometry,
153
161
  elevationProfile.resolution,
154
162
  )
155
- var index = 0
156
- for (let subline of geometries) {
157
- const firstPoint = subline.coordinates[0]
158
- if (firstPoint.length === 2) {
159
- firstPoint.push(elevationProfile.heights[index])
160
- }
161
-
162
- index++
163
-
164
- if (index === elevationProfile.heights.length) {
165
- throw 'Mismatch of points & elevation profile.'
166
- }
167
-
168
- const lastPoint = subline.coordinates[subline.coordinates.length - 1]
169
- if (lastPoint.length === 2) {
170
- lastPoint.push(elevationProfile.heights[index])
171
- }
172
- }
173
-
174
- if (index !== elevationProfile.heights.length - 1) {
163
+ if (profileLine.coordinates.length !== elevationProfile.heights.length) {
175
164
  throw `Mismatch of points & elevation profile`
176
165
  }
177
166
 
178
- // Check all coordinates have a height
179
- for (let subline of geometries) {
180
- for (let point of subline.coordinates) {
181
- if (point.length < 3) {
182
- throw 'All points should have an elevation at this point.'
183
- }
184
- }
167
+ for (let i = 0; i < profileLine.coordinates.length; i++) {
168
+ const point = profileLine.coordinates[i]
169
+ const height = elevationProfile.heights[i]
170
+ point.push(height)
185
171
  }
186
172
 
187
- return {
188
- type: 'LineString',
189
- coordinates: geometries.flatMap((geometry) => geometry.coordinates),
190
- }
173
+ return profileLine
191
174
  }
192
175
 
193
176
  /**
@@ -197,14 +180,18 @@ export function extractPointsForElevationProfile(
197
180
  geometry: LineString,
198
181
  resolution: number,
199
182
  ): GeoJSON.LineString {
200
- const geometries = lineChunksForElevationProfile(geometry, resolution)
183
+ // Important: Z coordinates in the output of lineChunk may be incorrect, ignore them (https://github.com/Turfjs/turf/issues/3007)
184
+ const lineChunks = lineChunk(geometry, resolution, {
185
+ units: 'meters',
186
+ }).features.map((feature) => feature.geometry)
187
+
201
188
  const points: GeoJSON.Position[] = []
202
- for (let subline of geometries) {
189
+ for (let subline of lineChunks) {
203
190
  const point = subline.coordinates[0]
204
191
  points.push([point[0], point[1]])
205
192
  }
206
- if (geometries.length > 0) {
207
- const geometry = geometries[geometries.length - 1]
193
+ if (lineChunks.length > 0) {
194
+ const geometry = lineChunks[lineChunks.length - 1]
208
195
  const coords = geometry.coordinates
209
196
  if (coords.length > 1) {
210
197
  const point = coords[coords.length - 1]
@@ -218,15 +205,6 @@ export function extractPointsForElevationProfile(
218
205
  }
219
206
  }
220
207
 
221
- function lineChunksForElevationProfile(
222
- geometry: LineString,
223
- resolution: number,
224
- ): GeoJSON.LineString[] {
225
- return lineChunk(geometry, resolution, {
226
- units: 'meters',
227
- }).features.map((feature) => feature.geometry)
228
- }
229
-
230
208
  export function getAscentAndDescent(
231
209
  profileGeometry: GeoJSON.LineString,
232
210
  ): AscentDescentData {
@@ -278,6 +256,27 @@ export function getAscentAndDescent(
278
256
  }
279
257
  }
280
258
 
259
+ /**
260
+ * Strip Z coordinates from points that were created by lineChunk (not original vertices).
261
+ * Original vertices are identified by matching lon/lat coordinates.
262
+ * Mutates the geometries in place.
263
+ */
264
+ function stripNonOriginalElevations(
265
+ geometries: GeoJSON.LineString[],
266
+ originalCoordinates: GeoJSON.Position[],
267
+ ) {
268
+ const originalSet = new Set(originalCoordinates.map((c) => `${c[0]},${c[1]}`))
269
+
270
+ for (const geometry of geometries) {
271
+ for (const point of geometry.coordinates) {
272
+ const key = `${point[0]},${point[1]}`
273
+ if (!originalSet.has(key) && point.length >= 3) {
274
+ point.length = 2
275
+ }
276
+ }
277
+ }
278
+ }
279
+
281
280
  /**
282
281
  * Interpolate elevation for points along a list of linestrings that don't already have elevation.
283
282
  * Uses geographic distances for proper interpolation.
@@ -2,4 +2,5 @@ export enum FeatureType {
2
2
  Run = 'run',
3
3
  Lift = 'lift',
4
4
  SkiArea = 'skiArea',
5
+ Spot = 'spot',
5
6
  }
package/src/Lift.ts CHANGED
@@ -3,6 +3,7 @@ import { FeatureType } from './FeatureType'
3
3
  import { Place } from './Place'
4
4
  import { SkiAreaSummaryFeature } from './SkiArea'
5
5
  import { Source } from './Source'
6
+ import { LiftStationSpotFeature } from './Spot'
6
7
  import { Status } from './Status'
7
8
  import { exhaustiveMatchingGuard } from './util/exhaustiveMatchingGuard'
8
9
 
@@ -10,13 +11,19 @@ export type LiftFeature = GeoJSON.Feature<LiftGeometry, LiftProperties>
10
11
 
11
12
  export type LiftGeometry = GeoJSON.LineString | GeoJSON.MultiLineString
12
13
 
14
+ /**
15
+ * Access restriction for a lift feature.
16
+ * - 'private': The lift has restricted access (derived from OSM access=private tag)
17
+ * - null: No access restriction or access information not available
18
+ */
19
+ export type Access = 'private' | null
20
+
13
21
  /**
14
22
  * A feature representing a ski lift.
15
23
  *
16
24
  * Lifts are derived from OpenStreetMap aerialway/railway features that are commonly used for winter sports.
17
25
  *
18
26
  * Note:
19
- * - Private lifts are not included in this dataset.
20
27
  * - Railways (except funiculars) are included only if they are part of a site=piste relation.
21
28
  * - Railway parts are not merged together so a single railway line may be represented as multiple features.
22
29
  * - Some lifts included in the dataset may be for other purposes (amusement parks, etc).
@@ -26,6 +33,7 @@ export type LiftGeometry = GeoJSON.LineString | GeoJSON.MultiLineString
26
33
  * @property {string} id - Unique identifier for the lift. The ID is just a hash of the feature, so will change if the feature changes in any way.
27
34
  * @property {LiftType} liftType - Type of lift (e.g. chair_lift, gondola). Derived from OpenStreetMap aerialway/railway tags.
28
35
  * @property {Status} status - Operational status of the lift. Derived from OpenStreetMap lifecycle tags.
36
+ * @property {Access} access - Access restriction for the lift. Set to "private" when derived from OpenStreetMap access=private tag, otherwise null.
29
37
  * @property {string | null} name - Name of the lift. Derived from the OpenStreetMap name tag.
30
38
  * @property {string | null} ref - Reference code/number for the lift. Derived from the OpenStreetMap ref tag.
31
39
  * @property {string | null} refFRCAIRN - French CAIRN reference identifier. Derived from the OpenStreetMap ref:FR:CAIRN tag.
@@ -37,6 +45,7 @@ export type LiftGeometry = GeoJSON.LineString | GeoJSON.MultiLineString
37
45
  * @property {boolean | null} detachable - Whether the lift has detachable grips. Derived from the OpenStreetMap aerialway:detachable tag.
38
46
  * @property {boolean | null} bubble - Whether the lift has bubbles/covers to protect from weather. Derived from the OpenStreetMap aerialway:bubble tag.
39
47
  * @property {boolean | null} heating - Whether the lift has heated carriers/seats. Derived from the OpenStreetMap aerialway:heating tag.
48
+ * @property {LiftStationSpotFeature[]} stations - Lift station spot features associated with this lift.
40
49
  * @property {SkiAreaSummaryFeature[]} skiAreas - Ski areas this lift is a part of.
41
50
  * @property {Source[]} sources - Data sources for the feature.
42
51
  * @property {string[]} websites - Websites associated with this lift. Derived from the OpenStreetMap website tag.
@@ -48,6 +57,7 @@ export type LiftProperties = {
48
57
  id: string
49
58
  liftType: LiftType
50
59
  status: Status
60
+ access: Access
51
61
  name: string | null
52
62
  ref: string | null
53
63
  refFRCAIRN: string | null
@@ -59,6 +69,7 @@ export type LiftProperties = {
59
69
  detachable: boolean | null
60
70
  bubble: boolean | null
61
71
  heating: boolean | null
72
+ stations: LiftStationSpotFeature[]
62
73
  skiAreas: SkiAreaSummaryFeature[]
63
74
  sources: Source[]
64
75
  websites: string[]
package/src/Run.ts CHANGED
@@ -51,6 +51,8 @@ export type RunFeature = GeoJSON.Feature<RunGeometry, RunProperties>
51
51
  * @property {boolean | null} lit - Whether the run has lighting for night skiing, derived from the OpenStreetMap "piste:lit" or "lit" tag.
52
52
  * @property {boolean | null} gladed - Whether the run is through gladed/tree terrain, derived from the OpenStreetMap "piste:gladed" or "gladed" tag.
53
53
  * @property {boolean | null} patrolled - Whether the run is patrolled by ski patrol, derived from the OpenStreetMap "piste:patrolled" or "patrolled" tag.
54
+ * @property {boolean | null} snowmaking - Whether the run has its operation secured through snowmaking, derived from the OpenStreetMap "piste:snowmaking" tag.
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.
54
56
  * @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".
55
57
  * @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.
56
58
  * @property {ElevationProfile | null} elevationProfile - Elevation profile of the run, only available for runs with LineString geometry.
@@ -74,6 +76,8 @@ export type RunProperties = {
74
76
  lit: boolean | null
75
77
  gladed: boolean | null
76
78
  patrolled: boolean | null
79
+ snowmaking: boolean | null
80
+ snowfarming: boolean | null
77
81
  grooming: RunGrooming | null
78
82
  skiAreas: SkiAreaSummaryFeature[]
79
83
  elevationProfile: ElevationProfile | null
package/src/SkiArea.ts CHANGED
@@ -102,7 +102,12 @@ export type RunStatisticsByActivityAndDifficulty = {
102
102
  }
103
103
 
104
104
  export type RunStatisticsByDifficulty = {
105
- [key in RunDifficulty | 'other']?: { count: number; lengthInKm: number }
105
+ [key in RunDifficulty | 'other']?: {
106
+ count: number
107
+ lengthInKm: number
108
+ snowmakingLengthInKm?: number
109
+ snowfarmingLengthInKm?: number
110
+ }
106
111
  }
107
112
 
108
113
  export type LiftStatistics = {
@@ -20,6 +20,8 @@ describe("getEstimatedRunDifficulty", () => {
20
20
  lit: null,
21
21
  gladed: null,
22
22
  patrolled: null,
23
+ snowmaking: null,
24
+ snowfarming: null,
23
25
  grooming: null,
24
26
  skiAreas: [],
25
27
  elevationProfile: null,
@@ -51,6 +53,8 @@ describe("getEstimatedRunDifficulty", () => {
51
53
  lit: null,
52
54
  gladed: null,
53
55
  patrolled: null,
56
+ snowmaking: null,
57
+ snowfarming: null,
54
58
  grooming: null,
55
59
  skiAreas: [],
56
60
  elevationProfile: null,
@@ -86,6 +90,8 @@ describe("getEstimatedRunDifficulty", () => {
86
90
  lit: null,
87
91
  gladed: null,
88
92
  patrolled: null,
93
+ snowmaking: null,
94
+ snowfarming: null,
89
95
  grooming: null,
90
96
  skiAreas: [],
91
97
  elevationProfile: null,
@@ -119,6 +125,8 @@ describe("getEstimatedRunDifficulty", () => {
119
125
  lit: null,
120
126
  gladed: null,
121
127
  patrolled: null,
128
+ snowmaking: null,
129
+ snowfarming: null,
122
130
  grooming: null,
123
131
  skiAreas: [],
124
132
  elevationProfile: null,
package/src/Spot.ts ADDED
@@ -0,0 +1,138 @@
1
+ import * as GeoJSON from 'geojson'
2
+ import { FeatureType } from './FeatureType'
3
+ import { Place } from './Place'
4
+ import { SkiAreaSummaryFeature } from './SkiArea'
5
+ import { Source } from './Source'
6
+
7
+ /**
8
+ * A GeoJSON feature representing a spot (point of interest) in or around a ski area.
9
+ *
10
+ * Spots are used to represent lift stations, road crossings, or certain terrain features.
11
+ */
12
+ export type SpotFeature = GeoJSON.Feature<SpotGeometry, SpotProperties>
13
+
14
+ /**
15
+ * A GeoJSON feature representing a lift station spot.
16
+ */
17
+ export type LiftStationSpotFeature = GeoJSON.Feature<
18
+ SpotGeometry,
19
+ LiftStationSpotProperties
20
+ >
21
+
22
+ /**
23
+ * Geometry type for spots - always a point.
24
+ */
25
+ export type SpotGeometry = GeoJSON.Point
26
+
27
+ /**
28
+ * Union of all spot property types.
29
+ */
30
+ export type SpotProperties =
31
+ | CrossingSpotProperties
32
+ | LiftStationSpotProperties
33
+ | AvalancheTransceiverTrainingSpotProperties
34
+ | AvalancheTransceiverCheckpointSpotProperties
35
+ | HalfpipeSpotProperties
36
+
37
+ /**
38
+ * Base properties shared by all spot types.
39
+ */
40
+ export type SpotBaseProperties = {
41
+ type: FeatureType.Spot
42
+ id: string
43
+ skiAreas: SkiAreaSummaryFeature[]
44
+ sources: Source[]
45
+ places: Place[]
46
+ }
47
+
48
+ /**
49
+ * Types of spots that can be found in or around ski areas.
50
+ */
51
+ export enum SpotType {
52
+ Crossing = 'crossing',
53
+ LiftStation = 'lift_station',
54
+ AvalancheTransceiverTraining = 'avalanche_transceiver_training',
55
+ AvalancheTransceiverCheckpoint = 'avalanche_transceiver_checkpoint',
56
+ Halfpipe = 'halfpipe',
57
+ }
58
+
59
+ /**
60
+ * A crossing is a point where a ski run intersects with a road or path,
61
+ * potentially requiring skiers to remove their skis.
62
+ *
63
+ * From OpenStreetMap node with tag `piste:dismount=yes|no|sometimes`.
64
+ */
65
+ export type CrossingSpotProperties = SpotBaseProperties & {
66
+ spotType: SpotType.Crossing
67
+ dismount: DismountRequirement
68
+ }
69
+
70
+ /**
71
+ * Whether dismounting from skis is required at a crossing.
72
+ */
73
+ export enum DismountRequirement {
74
+ Yes = 'yes',
75
+ No = 'no',
76
+ Sometimes = 'sometimes',
77
+ }
78
+
79
+ /**
80
+ * A lift station is a boarding or alighting point for a ski lift.
81
+ *
82
+ * From OpenStreetMap node or area with tag `aerialway=station`.
83
+ * Areas are represented as a point (centroid).
84
+ *
85
+ * @property {string | null} name - Name of the station, from OpenStreetMap tag `name`.
86
+ * @property {LiftStationPosition | null} position - From OpenStreetMap tag `aerialway:station=bottom|mid|top`.
87
+ * @property {boolean | null} entry - Whether passengers can board here. From OpenStreetMap tag `aerialway:access=entry|both|no`.
88
+ * @property {boolean | null} exit - Whether passengers can alight here. From OpenStreetMap tag `aerialway:access=exit|both|no`.
89
+ * @property {string} liftId - ID of the lift feature associated with this station.
90
+ */
91
+ export type LiftStationSpotProperties = SpotBaseProperties & {
92
+ spotType: SpotType.LiftStation
93
+ name: string | null
94
+ position: LiftStationPosition | null
95
+ entry: boolean | null
96
+ exit: boolean | null
97
+ liftId: string
98
+ }
99
+
100
+ /**
101
+ * Position of a lift station along the lift line.
102
+ */
103
+ export enum LiftStationPosition {
104
+ Top = 'top',
105
+ Mid = 'mid',
106
+ Bottom = 'bottom',
107
+ }
108
+
109
+ /**
110
+ * A designated area where skiers can practice using avalanche transceivers.
111
+ *
112
+ * From OpenStreetMap node or area with tags `amenity=avalanche_transceiver` and `avalanche_transceiver=training`.
113
+ * Areas are represented as a point (centroid).
114
+ */
115
+ export type AvalancheTransceiverTrainingSpotProperties = SpotBaseProperties & {
116
+ spotType: SpotType.AvalancheTransceiverTraining
117
+ }
118
+
119
+ /**
120
+ * A checkpoint where skiers can verify their avalanche transceiver is functioning.
121
+ *
122
+ * From OpenStreetMap node or area with tags `amenity=avalanche_transceiver` and `avalanche_transceiver=checkpoint`.
123
+ * Areas are represented as a point (centroid).
124
+ */
125
+ export type AvalancheTransceiverCheckpointSpotProperties =
126
+ SpotBaseProperties & {
127
+ spotType: SpotType.AvalancheTransceiverCheckpoint
128
+ }
129
+
130
+ /**
131
+ * A halfpipe structure for freestyle skiing or snowboarding.
132
+ *
133
+ * From OpenStreetMap node/way/area with tag `man_made=piste:halfpipe`.
134
+ * Areas are represented as a point (centroid).
135
+ */
136
+ export type HalfpipeSpotProperties = SpotBaseProperties & {
137
+ spotType: SpotType.Halfpipe
138
+ }
package/src/index.ts CHANGED
@@ -9,4 +9,5 @@ export * from './SlopeGradingScale'
9
9
  export * from './SkiArea'
10
10
  export * from './SnowCoverHistory'
11
11
  export * from './Source'
12
+ export * from './Spot'
12
13
  export * from './Status'