openskidata-format 14.0.0 → 16.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.
Files changed (94) hide show
  1. package/dist/ElevationProfile.d.ts +1 -0
  2. package/dist/ElevationProfile.d.ts.map +1 -0
  3. package/dist/ElevationProfile.js +15 -24
  4. package/dist/ElevationProfile.js.map +1 -1
  5. package/dist/FeatureType.d.ts +1 -0
  6. package/dist/FeatureType.d.ts.map +1 -0
  7. package/dist/FeatureType.js +2 -5
  8. package/dist/FeatureType.js.map +1 -1
  9. package/dist/Lift.d.ts +10 -8
  10. package/dist/Lift.d.ts.map +1 -0
  11. package/dist/Lift.js +22 -29
  12. package/dist/Lift.js.map +1 -1
  13. package/dist/LiftNameFormatter.d.ts +2 -1
  14. package/dist/LiftNameFormatter.d.ts.map +1 -0
  15. package/dist/LiftNameFormatter.js +11 -14
  16. package/dist/LiftNameFormatter.js.map +1 -1
  17. package/dist/Place.d.ts +1 -0
  18. package/dist/Place.d.ts.map +1 -0
  19. package/dist/Place.js +1 -2
  20. package/dist/Run.d.ts +10 -9
  21. package/dist/Run.d.ts.map +1 -0
  22. package/dist/Run.js +23 -30
  23. package/dist/Run.js.map +1 -1
  24. package/dist/RunDifficultyConvention.d.ts +2 -1
  25. package/dist/RunDifficultyConvention.d.ts.map +1 -0
  26. package/dist/RunDifficultyConvention.js +10 -15
  27. package/dist/RunDifficultyConvention.js.map +1 -1
  28. package/dist/SkiArea.d.ts +11 -12
  29. package/dist/SkiArea.d.ts.map +1 -0
  30. package/dist/SkiArea.js +2 -5
  31. package/dist/SkiArea.js.map +1 -1
  32. package/dist/SlopeGradingScale.d.ts +3 -2
  33. package/dist/SlopeGradingScale.d.ts.map +1 -0
  34. package/dist/SlopeGradingScale.js +21 -26
  35. package/dist/SlopeGradingScale.js.map +1 -1
  36. package/dist/SnowCoverHistory.d.ts +1 -0
  37. package/dist/SnowCoverHistory.d.ts.map +1 -0
  38. package/dist/SnowCoverHistory.js +9 -8
  39. package/dist/SnowCoverHistory.js.map +1 -1
  40. package/dist/Source.d.ts +2 -14
  41. package/dist/Source.d.ts.map +1 -0
  42. package/dist/Source.js +7 -43
  43. package/dist/Source.js.map +1 -1
  44. package/dist/Spot.d.ts +6 -5
  45. package/dist/Spot.d.ts.map +1 -0
  46. package/dist/Spot.js +6 -9
  47. package/dist/Spot.js.map +1 -1
  48. package/dist/Status.d.ts +1 -0
  49. package/dist/Status.d.ts.map +1 -0
  50. package/dist/Status.js +2 -5
  51. package/dist/Status.js.map +1 -1
  52. package/dist/ViewportHint.d.ts +1 -0
  53. package/dist/ViewportHint.d.ts.map +1 -0
  54. package/dist/ViewportHint.js +4 -10
  55. package/dist/ViewportHint.js.map +1 -1
  56. package/dist/index.d.ts +15 -15
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +14 -18
  59. package/dist/index.js.map +1 -1
  60. package/dist/util/exhaustiveMatchingGuard.d.ts +1 -0
  61. package/dist/util/exhaustiveMatchingGuard.d.ts.map +1 -0
  62. package/dist/util/exhaustiveMatchingGuard.js +1 -5
  63. package/dist/util/exhaustiveMatchingGuard.js.map +1 -1
  64. package/package.json +35 -23
  65. package/dist/SkiPass.d.ts +0 -82
  66. package/dist/SkiPass.js +0 -3
  67. package/dist/SkiPass.js.map +0 -1
  68. package/dist/testUtils.d.ts +0 -2
  69. package/dist/testUtils.js +0 -7
  70. package/dist/testUtils.js.map +0 -1
  71. package/src/ElevationProfile.test.ts +0 -738
  72. package/src/ElevationProfile.ts +0 -452
  73. package/src/FeatureType.ts +0 -6
  74. package/src/Lift.test.ts +0 -195
  75. package/src/Lift.ts +0 -219
  76. package/src/LiftNameFormatter.ts +0 -116
  77. package/src/Place.ts +0 -11
  78. package/src/Run.ts +0 -242
  79. package/src/RunDifficultyConvention.test.ts +0 -79
  80. package/src/RunDifficultyConvention.ts +0 -335
  81. package/src/SkiArea.ts +0 -128
  82. package/src/SkiPass.ts +0 -89
  83. package/src/SlopeGradingScale.test.ts +0 -151
  84. package/src/SlopeGradingScale.ts +0 -96
  85. package/src/SnowCoverHistory.test.ts +0 -103
  86. package/src/SnowCoverHistory.ts +0 -107
  87. package/src/Source.test.ts +0 -50
  88. package/src/Source.ts +0 -72
  89. package/src/Spot.ts +0 -140
  90. package/src/Status.ts +0 -20
  91. package/src/ViewportHint.ts +0 -208
  92. package/src/index.ts +0 -15
  93. package/src/testUtils.ts +0 -5
  94. package/src/util/exhaustiveMatchingGuard.ts +0 -3
package/src/Lift.ts DELETED
@@ -1,219 +0,0 @@
1
- import distance from '@turf/distance'
2
- import { ElevationData, getElevationData } from './ElevationProfile'
3
- import { FeatureType } from './FeatureType'
4
- import { Place } from './Place'
5
- import { SkiAreaSummaryFeature } from './SkiArea'
6
- import { Source } from './Source'
7
- import { LiftStationPosition, LiftStationSpotFeature } from './Spot'
8
- import { Status } from './Status'
9
- import { exhaustiveMatchingGuard } from './util/exhaustiveMatchingGuard'
10
- import { ViewportHint } from './ViewportHint'
11
-
12
- export type LiftFeature = GeoJSON.Feature<LiftGeometry, LiftProperties>
13
-
14
- export type LiftGeometry = GeoJSON.LineString | GeoJSON.MultiLineString
15
-
16
- /**
17
- * Access restriction for a lift feature.
18
- * - 'private': The lift has restricted access (derived from OSM access=private tag)
19
- * - null: No access restriction or access information not available
20
- */
21
- export type Access = 'private' | null
22
-
23
- /**
24
- * A feature representing a ski lift.
25
- *
26
- * Lifts are derived from OpenStreetMap aerialway/railway features that are commonly used for winter sports.
27
- *
28
- * Note:
29
- * - Railways (except funiculars) are included only if they are part of a site=piste relation.
30
- * - Railway parts are not merged together so a single railway line may be represented as multiple features.
31
- * - Some lifts included in the dataset may be for other purposes (amusement parks, etc).
32
- *
33
- * Properties:
34
- * @property {FeatureType.Lift} type - The feature type, which is always 'Lift'.
35
- * @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.
36
- * @property {LiftType} liftType - Type of lift (e.g. chair_lift, gondola). Derived from OpenStreetMap aerialway/railway tags.
37
- * @property {Status} status - Operational status of the lift. Derived from OpenStreetMap lifecycle tags.
38
- * @property {Access} access - Access restriction for the lift. Set to "private" when derived from OpenStreetMap access=private tag, otherwise null.
39
- * @property {string | null} name - Name of the lift. Derived from the OpenStreetMap name tag.
40
- * @property {string | null} ref - Reference code/number for the lift. Derived from the OpenStreetMap ref tag.
41
- * @property {string | null} refFRCAIRN - French CAIRN reference identifier. Derived from the OpenStreetMap ref:FR:CAIRN tag.
42
- * @property {string | null} description - Description of the lift. Derived from the OpenStreetMap description tag.
43
- * @property {boolean | null} oneway - Whether the lift allows riding only in one direction. Derived from the OpenStreetMap oneway tag.
44
- * @property {number | null} occupancy - Number of people each carrier can transport. Derived from the OpenStreetMap aerialway:occupancy tag.
45
- * @property {number | null} capacity - Transport capacity in persons/hour. Derived from the OpenStreetMap aerialway:capacity tag.
46
- * @property {number | null} duration - Duration of lift ride in seconds. Derived from the OpenStreetMap aerialway:duration tag.
47
- * @property {boolean | null} detachable - Whether the lift has detachable grips. Derived from the OpenStreetMap aerialway:detachable tag.
48
- * @property {boolean | null} bubble - Whether the lift has bubbles/covers to protect from weather. Derived from the OpenStreetMap aerialway:bubble tag.
49
- * @property {boolean | null} heating - Whether the lift has heated carriers/seats. Derived from the OpenStreetMap aerialway:heating tag.
50
- * @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.
51
- * @property {LiftStationSpotFeature[]} stations - Lift station spot features associated with this lift.
52
- * @property {SkiAreaSummaryFeature[]} skiAreas - Ski areas this lift is a part of.
53
- * @property {Source[]} sources - Data sources for the feature.
54
- * @property {string[]} websites - Websites associated with this lift. Derived from the OpenStreetMap website tag.
55
- * @property {string | null} wikidataID - Wikidata identifier. Derived from the OpenStreetMap wikidata tag.
56
- * @property {Place[]} places - Geographic places this lift is within (e.g., city, region, country). Derived from reverse geocoding.
57
- */
58
- export type LiftProperties = {
59
- type: FeatureType.Lift
60
- id: string
61
- liftType: LiftType
62
- status: Status
63
- access: Access
64
- name: string | null
65
- ref: string | null
66
- refFRCAIRN: string | null
67
- description: string | null
68
- oneway: boolean | null
69
- occupancy: number | null
70
- capacity: number | null
71
- duration: number | null
72
- detachable: boolean | null
73
- bubble: boolean | null
74
- heating: boolean | null
75
- tunnel: boolean | null
76
- stations: LiftStationSpotFeature[]
77
- skiAreas: SkiAreaSummaryFeature[]
78
- sources: Source[]
79
- websites: string[]
80
- wikidataID: string | null
81
- places: Place[]
82
- viewportHint: ViewportHint
83
- }
84
-
85
- export enum LiftType {
86
- CableCar = 'cable_car',
87
- Gondola = 'gondola',
88
- ChairLift = 'chair_lift',
89
- MixedLift = 'mixed_lift',
90
- DragLift = 'drag_lift',
91
- TBar = 't-bar',
92
- JBar = 'j-bar',
93
- Platter = 'platter',
94
- RopeTow = 'rope_tow',
95
- MagicCarpet = 'magic_carpet',
96
- Funicular = 'funicular',
97
- Railway = 'railway',
98
- }
99
-
100
- export type LiftElevationData = ElevationData & {
101
- speedInMetersPerSecond: number | null
102
- verticalSpeedInMetersPerSecond: number | null
103
- }
104
-
105
- export function getLiftElevationData(
106
- feature: LiftFeature,
107
- ): LiftElevationData | null {
108
- const geometry = feature.geometry
109
- if (
110
- !geometry ||
111
- geometry.type !== 'LineString' ||
112
- geometry.coordinates[0].length < 3
113
- ) {
114
- return null
115
- }
116
-
117
- const elevationData = getElevationData(geometry)
118
- const durationInSeconds = feature.properties.duration
119
- const terminalDistances = getTerminalStationDistances(feature)
120
- const inclinedLength =
121
- terminalDistances?.inclinedLengthInMeters ??
122
- elevationData.inclinedLengthInMeters
123
- const verticalLength =
124
- terminalDistances?.verticalInMeters ?? elevationData.verticalInMeters
125
-
126
- return {
127
- ...elevationData,
128
- speedInMetersPerSecond: durationInSeconds
129
- ? inclinedLength / durationInSeconds
130
- : null,
131
- verticalSpeedInMetersPerSecond: durationInSeconds
132
- ? verticalLength / durationInSeconds
133
- : null,
134
- }
135
- }
136
-
137
- function getTerminalStationDistances(
138
- feature: LiftFeature,
139
- ): { inclinedLengthInMeters: number; verticalInMeters: number } | null {
140
- const stations = feature.properties.stations
141
- const topStation = stations.find(
142
- (s) => s.properties.position === LiftStationPosition.Top,
143
- )
144
- const bottomStation = stations.find(
145
- (s) => s.properties.position === LiftStationPosition.Bottom,
146
- )
147
-
148
- if (!topStation || !bottomStation) {
149
- return null
150
- }
151
-
152
- const topCoords = topStation.geometry.coordinates
153
- const bottomCoords = bottomStation.geometry.coordinates
154
-
155
- if (topCoords.length < 3 || bottomCoords.length < 3) {
156
- return null
157
- }
158
-
159
- const horizontalDistanceInMeters = distance(
160
- topStation.geometry,
161
- bottomStation.geometry,
162
- { units: 'meters' },
163
- )
164
- const verticalInMeters = Math.abs(topCoords[2] - bottomCoords[2])
165
- const inclinedLengthInMeters = Math.sqrt(
166
- Math.pow(horizontalDistanceInMeters, 2) + Math.pow(verticalInMeters, 2),
167
- )
168
-
169
- return { inclinedLengthInMeters, verticalInMeters }
170
- }
171
-
172
- export function getFormattedLiftType(liftType: LiftType): string {
173
- switch (liftType) {
174
- case LiftType.CableCar:
175
- return 'Cable Car'
176
- case LiftType.Gondola:
177
- return 'Gondola'
178
- case LiftType.ChairLift:
179
- return 'Chairlift'
180
- case LiftType.MixedLift:
181
- return 'Hybrid'
182
- case LiftType.DragLift:
183
- return 'Drag lift'
184
- case LiftType.TBar:
185
- return 'T-bar'
186
- case LiftType.JBar:
187
- return 'J-bar'
188
- case LiftType.Platter:
189
- return 'Platter'
190
- case LiftType.RopeTow:
191
- return 'Ropetow'
192
- case LiftType.MagicCarpet:
193
- return 'Magic Carpet'
194
- case LiftType.Funicular:
195
- return 'Funicular'
196
- case LiftType.Railway:
197
- return 'Railway'
198
- default:
199
- return exhaustiveMatchingGuard(liftType)
200
- }
201
- }
202
-
203
- export function getLiftColor(status: Status): string {
204
- const brightRedColor = 'hsl(0, 82%, 42%)'
205
- const dimRedColor = 'hsl(0, 53%, 42%)'
206
-
207
- switch (status) {
208
- case Status.Disused:
209
- case Status.Abandoned:
210
- return dimRedColor
211
- case Status.Proposed:
212
- case Status.Planned:
213
- case Status.Construction:
214
- case Status.Operating:
215
- return brightRedColor
216
- default:
217
- return exhaustiveMatchingGuard(status)
218
- }
219
- }
@@ -1,116 +0,0 @@
1
- import { LiftProperties, LiftType, getFormattedLiftType } from './Lift'
2
-
3
- export function getLiftNameAndType(properties: LiftProperties) {
4
- const name = properties.name
5
-
6
- const liftType = getAugmentedLiftType(properties)
7
-
8
- if (name && liftType) {
9
- return `${name} (${liftType})`
10
- } else if (name) {
11
- return name
12
- } else {
13
- return liftType
14
- }
15
- }
16
-
17
- function getAugmentedLiftType(properties: LiftProperties): string | null {
18
- const components = []
19
-
20
- const heated = properties.heating
21
- const bubble = properties.bubble
22
- if (heated === true) {
23
- components.push('Heated')
24
- }
25
-
26
- if (
27
- bubble === true &&
28
- properties.liftType !== LiftType.CableCar &&
29
- properties.liftType !== LiftType.Gondola
30
- ) {
31
- components.push('Bubble')
32
- }
33
-
34
- if (!isOccupancyImplicit(properties) && properties.occupancy) {
35
- components.push(properties.occupancy + 'p')
36
- }
37
-
38
- const liftType =
39
- implicitOccupancyLiftType(properties) ||
40
- getFormattedLiftType(properties.liftType)
41
- if (liftType !== null) {
42
- components.push(liftType)
43
- }
44
-
45
- return components.join(' ')
46
- }
47
-
48
- function implicitOccupancyLiftType(properties: LiftProperties): string | null {
49
- const occupancy = properties.occupancy
50
- if (properties.liftType === LiftType.ChairLift) {
51
- switch (occupancy) {
52
- case 1:
53
- return 'Single'
54
- case 2:
55
- return 'Double'
56
- case 3:
57
- return 'Triple'
58
- case 4:
59
- return 'Quad'
60
- default:
61
- return null
62
- }
63
- }
64
-
65
- switch (properties.liftType) {
66
- case LiftType.TBar:
67
- return 'T-bar'
68
- case LiftType.JBar:
69
- return 'J-bar'
70
- case LiftType.Platter:
71
- return 'Platter'
72
- case LiftType.RopeTow:
73
- return 'Ropetow'
74
- case LiftType.MagicCarpet:
75
- return 'Magic Carpet'
76
- }
77
- return null
78
- }
79
-
80
- function isOccupancyImplicit(properties: LiftProperties) {
81
- const implicitLiftType = implicitOccupancyLiftType(properties)
82
- if (implicitLiftType) {
83
- return true
84
- }
85
-
86
- return containsAny(properties.name, [
87
- 't-bar',
88
- 'j-bar',
89
- 'platter',
90
- 'rope tow',
91
- 'ropetow',
92
- 'rope-tow',
93
- 'carpet',
94
- 'single',
95
- 'double',
96
- 'triple',
97
- 'quad',
98
- '1er',
99
- '2er',
100
- '3er',
101
- '4er',
102
- '6er',
103
- '8er',
104
- ])
105
- }
106
-
107
- function containsAny(input: string | null, lowerCaseSearchList: string[]) {
108
- if (input === null) {
109
- return false
110
- }
111
-
112
- const lowerCaseInput = input.toLowerCase()
113
- return lowerCaseSearchList.some((searchItem) => {
114
- return lowerCaseInput.includes(searchItem)
115
- })
116
- }
package/src/Place.ts DELETED
@@ -1,11 +0,0 @@
1
- export type Place = {
2
- iso3166_1Alpha2: string
3
- iso3166_2: string | null
4
- localized: {
5
- en: {
6
- country: string
7
- region: string | null
8
- locality: string | null
9
- }
10
- }
11
- }
package/src/Run.ts DELETED
@@ -1,242 +0,0 @@
1
- import * as GeoJSON from 'geojson'
2
- import {
3
- ElevationData,
4
- ElevationProfile,
5
- getElevationData,
6
- getProfileGeometry,
7
- } from './ElevationProfile'
8
- import { FeatureType } from './FeatureType'
9
- import { Place } from './Place'
10
- import { RunDifficultyConvention } from './RunDifficultyConvention'
11
- import { SkiAreaSummaryFeature } from './SkiArea'
12
- import { SnowCoverHistory } from './SnowCoverHistory'
13
- import { Source } from './Source'
14
- import { Status } from './Status'
15
- import { exhaustiveMatchingGuard } from './util/exhaustiveMatchingGuard'
16
- import { ViewportHint } from './ViewportHint'
17
-
18
- export type RunGeometry = GeoJSON.LineString | GeoJSON.Polygon
19
-
20
- /**
21
- * Represents a segment of a ski run/trail.
22
- *
23
- * Runs are derived from OpenStreetMap pistes, which are defined as all ways/areas/relations containing a "piste:type" tag.
24
- * Piste relations support is limited, it is only used to enhance the data of its member ways. There is no way to access the relation itself in the output data.
25
- *
26
- * A single run as marked on the mountain may be broken up into several run features, especially if the run has branches, or changes in tags (e.g. difficulty, use).
27
- *
28
- * In the future, there might be a "Route" entity introduced to represent a whole run, which would be composed of multiple run features.
29
- *
30
- * Note: winter hiking trails and trails of other winter sports disciplines are also included in this dataset.
31
- *
32
- * In postprocessing:
33
- * - overlapping ways are merged into a single run feature with multiple uses.
34
- * - connected run segments with the same properties are merged into a single run feature.
35
- */
36
- export type RunFeature = GeoJSON.Feature<RunGeometry, RunProperties>
37
-
38
- /**
39
- * Represents the properties of a ski run.
40
- *
41
- * Properties:
42
- * @property {FeatureType.Run} type - The feature type, which is always 'Run'.
43
- * @property {RunUse[]} uses - Use types for the run (e.g. downhill, nordic), derived from OpenStreetMap "piste:type" tags.
44
- * @property {string} id - Unique identifier for the run. The ID is just a hash of the feature, so will change if the feature changes in any way.
45
- * @property {string | null} name - Name of the run, if available
46
- * @property {string | null} ref - Reference code/number for the run. Derived from the OpenStreetMap piste:ref and ref tags.
47
- * @property {Status} status - Operational status. Note: as only operational runs are included in this dataset, this will always be 'operating'.
48
- * @property {string | null} description - Description of the run, derived from the OpenStreetMap "piste:description" or "description" tag.
49
- * @property {RunDifficulty | null} difficulty - Difficulty rating of the run, derived from the OpenStreetMap "piste:difficulty" tag
50
- * @property {RunDifficultyConvention} difficultyConvention - Regional convention used for representing run difficulty. Derived from location.
51
- * @property {boolean | null} oneway - Whether the run is one-way only, derived from the OpenStreetMap "piste:oneway" or "oneway" tag, in addition to defaults based on run use.
52
- * @property {boolean | null} lit - Whether the run has lighting for night skiing, derived from the OpenStreetMap "piste:lit" or "lit" tag.
53
- * @property {boolean | null} gladed - Whether the run is through gladed/tree terrain, derived from the OpenStreetMap "piste:gladed" or "gladed" tag.
54
- * @property {boolean | null} patrolled - Whether the run is patrolled by ski patrol, derived from the OpenStreetMap "piste:patrolled" or "patrolled" tag.
55
- * @property {boolean | null} snowmaking - Whether the run has its operation secured through snowmaking, derived from the OpenStreetMap "piste:snowmaking" tag.
56
- * @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.
57
- * @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.
58
- * @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".
59
- * @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.
60
- * @property {ElevationProfile | null} elevationProfile - Elevation profile of the run, only available for runs with LineString geometry.
61
- * @property {Source[]} sources - Data sources for this run's information
62
- * @property {string[]} websites - Websites associated with this run, derived from the OpenStreetMap website tag
63
- * @property {string | null} wikidataID - Wikidata identifier, if available, derived from the OpenStreetMap wikidata tag
64
- * @property {Place[]} places - Geographic places this run is within (e.g., city, region, country). Derived from reverse geocoding.
65
- * @property {SnowCoverHistory} [snowCoverHistory] - Historical snow cover data for this run, if available
66
- */
67
- export type RunProperties = {
68
- type: FeatureType.Run
69
- uses: RunUse[]
70
- id: string
71
- name: string | null
72
- ref: string | null
73
- status: Status
74
- description: string | null
75
- difficulty: RunDifficulty | null
76
- difficultyConvention: RunDifficultyConvention
77
- oneway: boolean | null
78
- lit: boolean | null
79
- gladed: boolean | null
80
- patrolled: boolean | null
81
- snowmaking: boolean | null
82
- snowfarming: boolean | null
83
- tunnel: boolean | null
84
- grooming: RunGrooming | null
85
- skiAreas: SkiAreaSummaryFeature[]
86
- elevationProfile: ElevationProfile | null
87
- sources: Source[]
88
- websites: string[]
89
- wikidataID: string | null
90
- places: Place[]
91
- snowCoverHistory?: SnowCoverHistory
92
- viewportHint: ViewportHint
93
- }
94
-
95
- export enum RunUse {
96
- Downhill = 'downhill',
97
- Nordic = 'nordic',
98
- Skitour = 'skitour',
99
- Sled = 'sled',
100
- Hike = 'hike',
101
- Sleigh = 'sleigh',
102
- IceSkate = 'ice_skate',
103
- SnowPark = 'snow_park',
104
- Playground = 'playground',
105
- Connection = 'connection',
106
- Fatbike = 'fatbike',
107
- }
108
-
109
- export enum RunGrooming {
110
- Classic = 'classic',
111
- Mogul = 'mogul',
112
- ClassicAndSkating = 'classic+skating',
113
- Skating = 'skating',
114
- Scooter = 'scooter',
115
- Backcountry = 'backcountry',
116
- }
117
-
118
- export enum RunDifficulty {
119
- NOVICE = 'novice',
120
- EASY = 'easy',
121
- INTERMEDIATE = 'intermediate',
122
- ADVANCED = 'advanced',
123
- EXPERT = 'expert',
124
- FREERIDE = 'freeride',
125
- EXTREME = 'extreme',
126
- }
127
-
128
- export enum RunColorName {
129
- GREEN = 'green',
130
- BLUE = 'blue',
131
- RED = 'red',
132
- BLACK = 'black',
133
- ORANGE = 'orange',
134
- GREY = 'grey',
135
- }
136
-
137
- export enum RunColorValue {
138
- GREEN = 'hsl(125, 100%, 33%)',
139
- BLUE = 'hsl(208, 100%, 33%)',
140
- RED = 'hsl(359, 94%, 53%)',
141
- BLACK = 'hsl(0, 0%, 0%)',
142
- ORANGE = 'hsl(34, 100%, 50%)',
143
- GREY = 'hsl(0, 0%, 35%)',
144
- }
145
-
146
-
147
- export function getRunElevationData(feature: RunFeature): ElevationData | null {
148
- const geometry = feature.geometry
149
- const profile = feature.properties.elevationProfile
150
- if (!profile || !geometry || geometry.type !== 'LineString') {
151
- return null
152
- }
153
-
154
- // Get a geometry that includes elevation data at an even spacing along the run
155
- const profileGeometry = getProfileGeometry(geometry, profile)
156
- return getElevationData(profileGeometry)
157
- }
158
-
159
- export function getRunColor(
160
- convention: RunDifficultyConvention,
161
- difficulty: RunDifficulty | null,
162
- ): RunColorValue {
163
- return runColorNameToValue(getRunColorName(convention, difficulty))
164
- }
165
-
166
- export function runColorNameToValue(color: RunColorName): RunColorValue {
167
- switch (color) {
168
- case RunColorName.GREEN:
169
- return RunColorValue.GREEN
170
- case RunColorName.BLUE:
171
- return RunColorValue.BLUE
172
- case RunColorName.RED:
173
- return RunColorValue.RED
174
- case RunColorName.BLACK:
175
- return RunColorValue.BLACK
176
- case RunColorName.ORANGE:
177
- return RunColorValue.ORANGE
178
- case RunColorName.GREY:
179
- return RunColorValue.GREY
180
- default:
181
- throw 'invalid color'
182
- }
183
- }
184
-
185
- export function getRunColorName(
186
- convention: RunDifficultyConvention,
187
- difficulty: RunDifficulty | null,
188
- ): RunColorName {
189
- switch (convention) {
190
- case RunDifficultyConvention.EUROPE:
191
- switch (difficulty) {
192
- case RunDifficulty.NOVICE:
193
- return RunColorName.GREEN
194
- case RunDifficulty.EASY:
195
- return RunColorName.BLUE
196
- case RunDifficulty.INTERMEDIATE:
197
- return RunColorName.RED
198
- case RunDifficulty.ADVANCED:
199
- case RunDifficulty.EXPERT:
200
- return RunColorName.BLACK
201
- case RunDifficulty.FREERIDE:
202
- case RunDifficulty.EXTREME:
203
- return RunColorName.ORANGE
204
- default:
205
- return RunColorName.GREY
206
- }
207
- case RunDifficultyConvention.JAPAN:
208
- switch (difficulty) {
209
- case RunDifficulty.NOVICE:
210
- case RunDifficulty.EASY:
211
- return RunColorName.GREEN
212
- case RunDifficulty.INTERMEDIATE:
213
- return RunColorName.RED
214
- case RunDifficulty.ADVANCED:
215
- case RunDifficulty.EXPERT:
216
- return RunColorName.BLACK
217
- case RunDifficulty.FREERIDE:
218
- case RunDifficulty.EXTREME:
219
- return RunColorName.ORANGE
220
- default:
221
- return RunColorName.GREY
222
- }
223
- case RunDifficultyConvention.NORTH_AMERICA:
224
- switch (difficulty) {
225
- case RunDifficulty.NOVICE:
226
- case RunDifficulty.EASY:
227
- return RunColorName.GREEN
228
- case RunDifficulty.INTERMEDIATE:
229
- return RunColorName.BLUE
230
- case RunDifficulty.ADVANCED:
231
- case RunDifficulty.EXPERT:
232
- return RunColorName.BLACK
233
- case RunDifficulty.FREERIDE:
234
- case RunDifficulty.EXTREME:
235
- return RunColorName.ORANGE
236
- default:
237
- return RunColorName.GREY
238
- }
239
- default:
240
- return exhaustiveMatchingGuard(convention)
241
- }
242
- }
@@ -1,79 +0,0 @@
1
- import { getRunDifficultyConvention, RunDifficultyConvention } from "./RunDifficultyConvention";
2
-
3
- describe("getRunDifficultyConvention", () => {
4
- it("should return JAPAN for locations in Japan", () => {
5
- // Point in Japan (Tokyo)
6
- const tokyoGeometry = {
7
- type: "Point" as const,
8
- coordinates: [139.6917, 35.6895]
9
- };
10
-
11
- expect(getRunDifficultyConvention(tokyoGeometry)).toBe(RunDifficultyConvention.JAPAN);
12
- });
13
-
14
- it("should return NORTH_AMERICA for locations in North America", () => {
15
- // Point in Colorado, USA
16
- const coloradoGeometry = {
17
- type: "Point" as const,
18
- coordinates: [-106.3731, 39.1911]
19
- };
20
-
21
- expect(getRunDifficultyConvention(coloradoGeometry)).toBe(RunDifficultyConvention.NORTH_AMERICA);
22
-
23
- // Point in British Columbia, Canada
24
- const bcGeometry = {
25
- type: "Point" as const,
26
- coordinates: [-123.1207, 49.2827]
27
- };
28
-
29
- expect(getRunDifficultyConvention(bcGeometry)).toBe(RunDifficultyConvention.NORTH_AMERICA);
30
- });
31
-
32
- it("should return EUROPE for locations in Europe", () => {
33
- // Point in the Alps (Chamonix, France)
34
- const chamonixGeometry = {
35
- type: "Point" as const,
36
- coordinates: [6.8694, 45.9237]
37
- };
38
-
39
- expect(getRunDifficultyConvention(chamonixGeometry)).toBe(RunDifficultyConvention.EUROPE);
40
-
41
- // Point in Austria
42
- const austriaGeometry = {
43
- type: "Point" as const,
44
- coordinates: [13.7558, 47.8095]
45
- };
46
-
47
- expect(getRunDifficultyConvention(austriaGeometry)).toBe(RunDifficultyConvention.EUROPE);
48
- });
49
-
50
- it("should return EUROPE as default for other locations", () => {
51
- // Point in South America (should default to Europe)
52
- const southAmericaGeometry = {
53
- type: "Point" as const,
54
- coordinates: [-58.3816, -34.6037] // Buenos Aires, Argentina
55
- };
56
-
57
- expect(getRunDifficultyConvention(southAmericaGeometry)).toBe(RunDifficultyConvention.EUROPE);
58
- });
59
-
60
- it("should work with LineString geometry", () => {
61
- // LineString crossing through Europe
62
- const lineGeometry = {
63
- type: "LineString" as const,
64
- coordinates: [[6.8, 45.9], [6.9, 46.0]]
65
- };
66
-
67
- expect(getRunDifficultyConvention(lineGeometry)).toBe(RunDifficultyConvention.EUROPE);
68
- });
69
-
70
- it("should work with Polygon geometry", () => {
71
- // Polygon in North America
72
- const polygonGeometry = {
73
- type: "Polygon" as const,
74
- coordinates: [[[-106.4, 39.1], [-106.3, 39.1], [-106.3, 39.2], [-106.4, 39.2], [-106.4, 39.1]]]
75
- };
76
-
77
- expect(getRunDifficultyConvention(polygonGeometry)).toBe(RunDifficultyConvention.NORTH_AMERICA);
78
- });
79
- });