openskidata-format 5.1.0 → 5.3.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SlopeGradingScale.js","sourceRoot":"","sources":["../src/SlopeGradingScale.ts"],"names":[],"mappings":";;AAoBA,oDAyBC;AAWD,8DASC;AAjED,+BAA0D;AAY1D;;;;;;;GAOG;AACH,SAAgB,oBAAoB,CAAC,OAAmB;IACtD,IACE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAM,CAAC,QAAQ,CAAC;QACjD,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAM,CAAC,OAAO,CAAC,EAChD,CAAC;QACD,OAAO;YACL,KAAK,EAAE;gBACL,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,yBAAyB;gBACnE,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,mBAAa,CAAC,IAAI,EAAE;gBACtD,EAAE,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,mBAAa,CAAC,YAAY,EAAE;gBAC7D,EAAE,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,mBAAa,CAAC,QAAQ,EAAE,EAAE,qBAAqB;gBAChF,EAAE,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,mBAAa,CAAC,MAAM,EAAE,EAAE,oBAAoB;aAC9E;SACF,CAAC;IACJ,CAAC;SAAM,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3D,OAAO;YACL,KAAK,EAAE;gBACL,EAAE,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,mBAAa,CAAC,IAAI,EAAE;gBACrD,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,mBAAa,CAAC,YAAY,EAAE;gBAC9D,EAAE,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,mBAAa,CAAC,QAAQ,EAAE;aAC1D;SACF,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACvB,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,yBAAyB,CACvC,SAAiB,EACjB,KAAwB;IAExB,MAAM,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC9C,OAAO,CACL,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,GAAG,iBAAiB,CAAC;QAC/D,EAAE,UAAU,IAAI,IAAI,CACvB,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -4,6 +4,8 @@ export * from './Lift';
4
4
  export * from './LiftNameFormatter';
5
5
  export * from './Location';
6
6
  export * from './Run';
7
+ export * from './RunDifficultyConvention';
8
+ export * from './SlopeGradingScale';
7
9
  export * from './SkiArea';
8
10
  export * from './SnowCoverHistory';
9
11
  export * from './Source';
package/dist/index.js CHANGED
@@ -7,6 +7,8 @@ tslib_1.__exportStar(require("./Lift"), exports);
7
7
  tslib_1.__exportStar(require("./LiftNameFormatter"), exports);
8
8
  tslib_1.__exportStar(require("./Location"), exports);
9
9
  tslib_1.__exportStar(require("./Run"), exports);
10
+ tslib_1.__exportStar(require("./RunDifficultyConvention"), exports);
11
+ tslib_1.__exportStar(require("./SlopeGradingScale"), exports);
10
12
  tslib_1.__exportStar(require("./SkiArea"), exports);
11
13
  tslib_1.__exportStar(require("./SnowCoverHistory"), exports);
12
14
  tslib_1.__exportStar(require("./Source"), exports);
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,qDAA0B;AAC1B,gDAAqB;AACrB,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,qDAA0B;AAC1B,gDAAqB;AACrB,oEAAyC;AACzC,8DAAmC;AACnC,oDAAyB;AACzB,6DAAkC;AAClC,mDAAwB;AACxB,mDAAwB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openskidata-format",
3
- "version": "5.1.0",
3
+ "version": "5.3.0",
4
4
  "description": "Data format for OpenSkiMap.org",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -33,7 +33,10 @@
33
33
  "typescript": "^5"
34
34
  },
35
35
  "dependencies": {
36
+ "@turf/boolean-point-in-polygon": "^7.2.0",
37
+ "@turf/center": "^7.2.0",
36
38
  "@turf/distance": "^7.2.0",
39
+ "@turf/helpers": "^7.2.0",
37
40
  "@turf/length": "^7.2.0",
38
41
  "@turf/line-chunk": "^7.2.0",
39
42
  "@turf/meta": "^7.2.0",
@@ -8,10 +8,10 @@ import { getLiftElevationData, LiftFeature, LiftType } from './Lift'
8
8
  import {
9
9
  getRunElevationData,
10
10
  RunDifficulty,
11
- RunDifficultyConvention,
12
11
  RunFeature,
13
12
  RunUse,
14
13
  } from './Run'
14
+ import { RunDifficultyConvention } from './RunDifficultyConvention'
15
15
  import { Status } from './Status'
16
16
 
17
17
  describe('ElevationProfile', () => {
package/src/Run.ts CHANGED
@@ -6,7 +6,9 @@ import {
6
6
  getProfileGeometry,
7
7
  } from './ElevationProfile'
8
8
  import { FeatureType } from './FeatureType'
9
+ import { RunDifficultyConvention } from './RunDifficultyConvention'
9
10
  import { SkiAreaSummaryFeature } from './SkiArea'
11
+ import { SnowCoverHistory } from './SnowCoverHistory'
10
12
  import { Source } from './Source'
11
13
  import { Status } from './Status'
12
14
  import { exhaustiveMatchingGuard } from './util/exhaustiveMatchingGuard'
@@ -54,6 +56,7 @@ export type RunFeature = GeoJSON.Feature<RunGeometry, RunProperties>
54
56
  * @property {Source[]} sources - Data sources for this run's information
55
57
  * @property {string[]} websites - Websites associated with this run, derived from the OpenStreetMap website tag
56
58
  * @property {string | null} wikidata_id - Wikidata identifier, if available, derived from the OpenStreetMap wikidata tag
59
+ * @property {SnowCoverHistory} [snowCoverHistory] - Historical snow cover data for this run, if available
57
60
  */
58
61
  export type RunProperties = {
59
62
  type: FeatureType.Run
@@ -75,6 +78,7 @@ export type RunProperties = {
75
78
  sources: Source[]
76
79
  websites: string[]
77
80
  wikidata_id: string | null
81
+ snowCoverHistory?: SnowCoverHistory
78
82
  }
79
83
 
80
84
  export enum RunUse {
@@ -128,39 +132,6 @@ export enum RunColorValue {
128
132
  GREY = 'hsl(0, 0%, 35%)',
129
133
  }
130
134
 
131
- /**
132
- * Run difficulty colors vary by region. This enum defines the color convention used for runs at a ski area.
133
- * @enum {string}
134
- */
135
- export enum RunDifficultyConvention {
136
- /**
137
- * European color convention:
138
- * - Green: Novice
139
- * - Blue: Easy
140
- * - Red: Intermediate
141
- * - Black: Advanced/Expert
142
- * - Orange: Freeride/Extreme
143
- */
144
- EUROPE = 'europe',
145
-
146
- /**
147
- * Japanese color convention:
148
- * - Green: Novice/Easy
149
- * - Red: Intermediate
150
- * - Black: Advanced/Expert
151
- * - Orange: Freeride/Extreme
152
- */
153
- JAPAN = 'japan',
154
-
155
- /**
156
- * North American color convention:
157
- * - Green: Novice/Easy
158
- * - Blue: Intermediate
159
- * - Black: Advanced/Expert
160
- * - Orange: Freeride/Extreme
161
- */
162
- NORTH_AMERICA = 'north_america',
163
- }
164
135
 
165
136
  export function getRunElevationData(feature: RunFeature): ElevationData | null {
166
137
  const geometry = feature.geometry
@@ -0,0 +1,79 @@
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
+ });
@@ -0,0 +1,335 @@
1
+ import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
2
+ import turfCenter from "@turf/center";
3
+ import * as turf from "@turf/helpers";
4
+ import { AllGeoJSON } from "@turf/helpers";
5
+
6
+ /**
7
+ * Run difficulty colors vary by region. This enum defines the color convention used for runs at a ski area.
8
+ * @enum {string}
9
+ */
10
+ export enum RunDifficultyConvention {
11
+ /**
12
+ * European color convention:
13
+ * - Green: Novice
14
+ * - Blue: Easy
15
+ * - Red: Intermediate
16
+ * - Black: Advanced/Expert
17
+ * - Orange: Freeride/Extreme
18
+ */
19
+ EUROPE = 'europe',
20
+
21
+ /**
22
+ * Japanese color convention:
23
+ * - Green: Novice/Easy
24
+ * - Red: Intermediate
25
+ * - Black: Advanced/Expert
26
+ * - Orange: Freeride/Extreme
27
+ */
28
+ JAPAN = 'japan',
29
+
30
+ /**
31
+ * North American color convention:
32
+ * - Green: Novice/Easy
33
+ * - Blue: Intermediate
34
+ * - Black: Advanced/Expert
35
+ * - Orange: Freeride/Extreme
36
+ */
37
+ NORTH_AMERICA = 'north_america',
38
+ }
39
+
40
+ const northAmericanConventionGeometry = turf.multiPolygon([
41
+ [
42
+ [
43
+ [66.89889168301036, 22.98946421817959],
44
+ [76.79011657384558, 4.2607118936878265],
45
+ [112.5459757578734, -40.008871147786486],
46
+ [166.64372809287335, -58.19200446079054],
47
+ [191.91699393212554, -33.377687858720755],
48
+ [192.65370948033006, -8.971607939355977],
49
+ [140.68354997294796, 5.451024881476499],
50
+ [123.38582294700518, 21.801329456101513],
51
+ [122.25942048875993, 24.243081370534554],
52
+ [123.02414890399393, 26.354744126525432],
53
+ [129.68307711216244, 35.3374262814546],
54
+ [131.36509887116028, 39.1827837685222],
55
+ [130.5715844381864, 42.515964349309684],
56
+ [130.62108313985783, 42.63370843853855],
57
+ [130.39263902117034, 42.73714858581644],
58
+ [130.8150956808529, 42.87954610777132],
59
+ [131.04334909066392, 42.88226217082041],
60
+ [131.33954328617205, 43.445079879213296],
61
+ [131.191137752773, 43.53879786242706],
62
+ [131.2860140618261, 44.06115319070142],
63
+ [131.1086866768622, 44.71097030226514],
64
+ [130.95332209785204, 44.84377389211244],
65
+ [131.56223386930952, 45.01998391706314],
66
+ [131.87876159757576, 45.342467064732745],
67
+ [131.9445424786545, 45.26381674117374],
68
+ [132.89886314033083, 45.04768363738535],
69
+ [132.9409663928247, 45.020634782943716],
70
+ [133.12560828825156, 45.14828761444474],
71
+ [133.11406817721956, 45.23774574998686],
72
+ [133.1686920707706, 45.49559658174417],
73
+ [133.4044528436404, 45.59600211321589],
74
+ [133.49367119277423, 45.87840483196845],
75
+ [133.57649823904808, 45.88061866181769],
76
+ [133.7230811284722, 46.06662995573109],
77
+ [133.68166349871666, 46.137321119014274],
78
+ [133.9014556853037, 46.24315756590036],
79
+ [134.29060710292293, 47.44981009549741],
80
+ [134.53603145724082, 47.47580868032259],
81
+ [134.80050117570937, 47.73143995381383],
82
+ [134.54808493637842, 48.00270638588145],
83
+ [134.7902354911858, 48.38077517538687],
84
+ [134.53852703049813, 48.414602674179406],
85
+ [134.05426284432252, 48.33207866806839],
86
+ [133.44255382292891, 48.11130941788082],
87
+ [133.06661598961256, 48.102793716410616],
88
+ [132.65561957214425, 47.92377254119751],
89
+ [132.57597035647728, 47.73126763647102],
90
+ [131.5872859174675, 47.669086096155525],
91
+ [130.978760673039, 47.70552624852317],
92
+ [130.8927298265839, 47.92147467660291],
93
+ [130.69208001471225, 48.07898424194457],
94
+ [130.8424973965307, 48.32747681044523],
95
+ [130.53333624266037, 48.638203333369944],
96
+ [130.69902773150022, 48.86294984494779],
97
+ [130.4313260036679, 48.91144552665949],
98
+ [130.2336273608912, 48.877796693265594],
99
+ [129.49472335519903, 49.445146325369194],
100
+ [128.6404925727599, 49.6395594299683],
101
+ [127.95892224407356, 49.62425806475295],
102
+ [127.56973394676123, 49.842755131278835],
103
+ [127.6749910879272, 50.240140628289964],
104
+ [127.45368458653832, 50.26847480259133],
105
+ [127.37394005798404, 50.29288471184299],
106
+ [127.32612719828853, 50.34379944487219],
107
+ [127.37997900840315, 50.60653687131031],
108
+ [127.16325020595207, 50.933036917572906],
109
+ [126.99177818739395, 51.326954509452236],
110
+ [126.33131963313707, 52.493153867333206],
111
+ [126.09655832692533, 52.86710580508279],
112
+ [125.18461572471739, 53.21778527809076],
113
+ [123.62905555865535, 53.56957077991163],
114
+ [122.14662682326076, 53.507610554797225],
115
+ [120.81940759451805, 53.31174251524433],
116
+ [119.95478692741125, 52.77983494498105],
117
+ [120.02183577608542, 52.55624852160162],
118
+ [120.59821023820314, 52.5562523256705],
119
+ [120.65182146309388, 52.027454302929755],
120
+ [120.00845804883363, 51.63400833664596],
121
+ [119.10923570584242, 50.3653464992334],
122
+ [119.33042992474253, 50.30545934524457],
123
+ [119.21648675850292, 50.099528593865784],
124
+ [118.93783039700338, 49.98458223887849],
125
+ [118.54626899510839, 49.94616013995508],
126
+ [117.80663959739081, 49.53647108800752],
127
+ [117.484738258086, 49.624317990557614],
128
+ [117.26607476489426, 49.63477188589076],
129
+ [116.96468681768641, 49.73160402967815],
130
+ [116.62825050755794, 49.944503706705376],
131
+ [116.2287910451044, 50.03623236447976],
132
+ [115.97912115005505, 49.97893073129566],
133
+ [115.72585372832015, 49.87560524136032],
134
+ [115.38340104847777, 49.935338883138456],
135
+ [115.15157871232401, 50.03624558574222],
136
+ [114.96972180858182, 50.18262812854161],
137
+ [114.32823723216535, 50.27374466694857],
138
+ [113.21615782676918, 49.84014337192383],
139
+ [113.06279976594055, 49.60262851502978],
140
+ [112.75961978011298, 49.50544853175836],
141
+ [112.4528903096238, 49.51941937053812],
142
+ [111.93911320274538, 49.37324774723086],
143
+ [111.69083700584588, 49.38804243172055],
144
+ [110.68965090965844, 49.16705432804406],
145
+ [108.61062678042163, 49.33457873762259],
146
+ [107.90316280555385, 49.97532248790398],
147
+ [106.49948671672877, 50.3809827302172],
148
+ [105.51746011619525, 50.48702476586922],
149
+ [103.97795584841299, 50.133831277984996],
150
+ [102.69196601175406, 50.37681484681099],
151
+ [102.27144249887641, 50.87948727040293],
152
+ [102.17444849785716, 51.35640391793228],
153
+ [100.63003834780625, 51.738599556839574],
154
+ [98.92412930445079, 52.152271807237554],
155
+ [98.0263146497278, 51.38702212297895],
156
+ [97.83223938583137, 50.91503753447586],
157
+ [98.30141292582249, 50.51549014567553],
158
+ [98.03452228766315, 50.01401927081076],
159
+ [97.21087912958029, 49.75344974439781],
160
+ [96.59617521697089, 49.92558626439808],
161
+ [94.58073504473032, 50.071206832869876],
162
+ [94.44884921665886, 50.25288523325358],
163
+ [94.28227879098631, 50.59029357818193],
164
+ [93.06055432240078, 50.6108167038102],
165
+ [92.95500531764452, 50.764378755264715],
166
+ [92.38044935493656, 50.81536176617482],
167
+ [89.61447548394369, 49.896510834163024],
168
+ [89.41209157088667, 49.593951299041436],
169
+ [87.21941106111126, 49.136371106937105],
170
+ [86.47691458036888, 48.52706996107682],
171
+ [85.66792655187515, 48.41217050021373],
172
+ [85.61001315938637, 47.097608820611185],
173
+ [83.06577876367635, 47.1684932958469],
174
+ [82.19603900970611, 45.39598594758252],
175
+ [79.94680702146206, 44.995940936938524],
176
+ [80.74758671786947, 43.25101970631087],
177
+ [80.16296382083789, 42.42004311892032],
178
+ [79.08808560905646, 42.80565581050615],
179
+ [77.46543003728954, 42.93866114713731],
180
+ [77.30266016034727, 42.91577009179525],
181
+ [77.06944317811468, 42.98941184436538],
182
+ [76.83954492079482, 42.95784584611252],
183
+ [76.66706605000616, 42.91054018927406],
184
+ [76.35054751194656, 42.86314251596045],
185
+ [76.22106905960021, 42.92109675548289],
186
+ [75.8499512176796, 42.944841027684475],
187
+ [75.69647619703395, 42.79434701877443],
188
+ [75.20518050373951, 42.86058166470994],
189
+ [74.86716288299183, 42.99486162795807],
190
+ [74.21214208437436, 43.26799034589942],
191
+ [73.54918053004673, 43.03445951036437],
192
+ [73.43569691290458, 42.59058989745361],
193
+ [73.50713573720739, 42.42885549027292],
194
+ [73.32430827244477, 42.43964242187812],
195
+ [73.28138720704561, 42.524654623049486],
196
+ [72.89688006931604, 42.53825798475941],
197
+ [72.7028920768594, 42.65445195418786],
198
+ [71.8205490156389, 42.84297257066001],
199
+ [71.24172502287257, 42.76218198674192],
200
+ [70.96542642702568, 42.45295945325228],
201
+ [70.87574064610243, 42.288978943546994],
202
+ [70.93667564676599, 42.25956939262474],
203
+ [71.0522698554054, 42.28801700409892],
204
+ [71.26892670629547, 42.19664779423837],
205
+ [70.22467025584973, 41.6109136918285],
206
+ [70.1871419707528, 41.52357559397731],
207
+ [70.29521282660394, 41.5196557335768],
208
+ [70.4885172051716, 41.39563567019803],
209
+ [70.6908234400903, 41.47973822440426],
210
+ [70.78334977579652, 41.37596799777336],
211
+ [70.7936135992125, 41.23200478517444],
212
+ [71.40193377758987, 41.189890843929476],
213
+ [71.72132931443616, 41.463007098837124],
214
+ [72.25976659039807, 41.036213505586716],
215
+ [73.12473655458163, 40.821214468109844],
216
+ [71.8274169831183, 40.219535506292345],
217
+ [71.2093915709481, 40.35194316359275],
218
+ [70.70839519610914, 40.047767583705706],
219
+ [70.00814064760502, 40.19597188360018],
220
+ [69.3238929275289, 39.96163997362652],
221
+ [69.25288425833449, 39.8365015771121],
222
+ [69.36807176732333, 39.53622995828479],
223
+ [70.5656905159378, 39.611522993563625],
224
+ [70.81017094805003, 39.40296443017286],
225
+ [71.05478901580443, 39.42623263483682],
226
+ [71.09537841230028, 39.521081174175976],
227
+ [71.48723105871241, 39.61179598590786],
228
+ [71.80293870931277, 39.289369010362776],
229
+ [72.03176071465103, 39.344791211184486],
230
+ [72.22037536907436, 39.19478948035075],
231
+ [72.34794908849406, 39.34434407454637],
232
+ [73.15397827282933, 39.35800161267082],
233
+ [73.41580743762637, 39.46694232025965],
234
+ [73.60494023346439, 39.469004217709056],
235
+ [73.53306087489301, 39.24817612724672],
236
+ [73.8401473956308, 38.955283153545196],
237
+ [73.7178756559239, 38.88418224181672],
238
+ [73.84575285445322, 38.5733588129749],
239
+ [74.19825648155071, 38.625225936216],
240
+ [74.73465165940527, 38.39729684471283],
241
+ [74.94429646804616, 37.74563365375093],
242
+ [75.09730124153691, 37.34874288728962],
243
+ [74.47556092367677, 37.22736548435755],
244
+ [74.52571774786139, 37.04804932382365],
245
+ [72.64281263069017, 36.9965169904729],
246
+ [71.27151437563325, 36.14385342653641],
247
+ [71.70051938813555, 35.31553980310994],
248
+ [70.91367870839377, 34.02947262017156],
249
+ [69.8657881549984, 33.97753268150575],
250
+ [70.19479291508452, 33.38872790844742],
251
+ [69.48427263502771, 32.94309627730759],
252
+ [69.17043362955638, 31.802649394624297],
253
+ [66.5660130962763, 31.1468844695182],
254
+ [66.39058495939196, 29.902900359253024],
255
+ [64.20728972399988, 29.470320322411112],
256
+ [62.39830055544061, 29.433474533828033],
257
+ [60.82809795436239, 29.876493049104326],
258
+ [61.819412883544715, 28.5413645023537],
259
+ [62.838210084807116, 28.1758941784838],
260
+ [62.87712480493187, 26.710220153319582],
261
+ [61.95649723937791, 26.202543172995433],
262
+ [61.64164473778666, 25.062349569223997],
263
+ [66.89889168301036, 22.98946421817959],
264
+ ],
265
+ ],
266
+ [
267
+ [
268
+ [-79.49790751939359, 8.895517276865164],
269
+ [-80.09116426661198, 9.489400626216977],
270
+ [-71.5226805789838, 14.570830502555324],
271
+ [-64.296660455746, 16.87497218957077],
272
+ [-63.50670575144407, 19.468079078229948],
273
+ [-46.04319359052067, 49.81687541607755],
274
+ [-57.24573007399778, 67.81957009723368],
275
+ [-74.74198803509906, 76.55978940288878],
276
+ [-73.60375960527375, 78.39636019182609],
277
+ [-67.92218140574312, 80.61698801540712],
278
+ [-59.076220860081435, 82.41962573871615],
279
+ [-68.9778162806643, 85.05112877980659],
280
+ [-169.10721706859002, 69.87119013352208],
281
+ [-168.82669211383998, 64.59846733544799],
282
+ [-172.31141325730604, 63.991833108168834],
283
+ [-192.1254235906623, 52.646873605362146],
284
+ [-166.3003429543922, 12.967564352770154],
285
+ [-79.6692367415715, 4.562414945897046],
286
+ [-79.49790751939359, 8.895517276865164],
287
+ ],
288
+ ],
289
+ ]);
290
+
291
+ const japanConventionGeometry = turf.polygon([
292
+ [
293
+ [122.40443764161375, 24.25555191895947],
294
+ [123.22422482046358, 22.664415921202675],
295
+ [131.6668409404955, 27.1734104531445],
296
+ [141.6724497786463, 33.41882632781292],
297
+ [152.21247459573226, 45.19087135255526],
298
+ [154.7040665173107, 48.05238412051253],
299
+ [149.47388354609916, 49.86405083649407],
300
+ [144.62198341555745, 55.122855332829886],
301
+ [141.85000003174838, 54.453056889632535],
302
+ [141.56865023975553, 53.237305271866575],
303
+ [141.5658284519161, 52.12730212591498],
304
+ [140.86177532698593, 47.83608043534858],
305
+ [129.38176008175282, 34.88162789041118],
306
+ [122.40443764161375, 24.25555191895947],
307
+ ],
308
+ ]);
309
+
310
+ /**
311
+ * Determines the run difficulty convention for a given geographic location.
312
+ * Based on the center point of the geometry, returns the appropriate regional
313
+ * convention for ski run difficulty ratings.
314
+ *
315
+ * @param geojson - GeoJSON geometry to determine the center location from
316
+ * @returns The appropriate run difficulty convention for the location
317
+ * @throws Error if the center of geometry cannot be determined
318
+ */
319
+ export function getRunDifficultyConvention(
320
+ geojson: AllGeoJSON,
321
+ ): RunDifficultyConvention {
322
+ const point = turfCenter(geojson).geometry;
323
+ if (!point) {
324
+ throw "Cannot determine center of geometry";
325
+ }
326
+
327
+ if (booleanPointInPolygon(point, japanConventionGeometry)) {
328
+ return RunDifficultyConvention.JAPAN;
329
+ } else if (booleanPointInPolygon(point, northAmericanConventionGeometry)) {
330
+ return RunDifficultyConvention.NORTH_AMERICA;
331
+ } else {
332
+ return RunDifficultyConvention.EUROPE;
333
+ }
334
+ }
335
+
package/src/SkiArea.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { FeatureType } from './FeatureType'
2
2
  import { LiftType } from './Lift'
3
3
  import { Location } from './Location'
4
- import { RunDifficulty, RunDifficultyConvention } from './Run'
4
+ import { RunDifficulty } from './Run'
5
+ import { RunDifficultyConvention } from './RunDifficultyConvention'
5
6
  import { SnowCoverHistory } from './SnowCoverHistory'
6
7
  import { Source } from './Source'
7
8
  import { Status } from './Status'
@@ -0,0 +1,129 @@
1
+ import { RunDifficulty, RunUse } from "./Run";
2
+ import { getEstimatedRunDifficulty, getSlopeGradingScale } from "./SlopeGradingScale";
3
+
4
+ describe("getEstimatedRunDifficulty", () => {
5
+ it("should return null for steepness below minimum threshold", () => {
6
+ const downhillScale = getSlopeGradingScale({
7
+ type: "Feature",
8
+ geometry: { type: "LineString", coordinates: [] },
9
+ properties: {
10
+ type: "Run" as any,
11
+ uses: [RunUse.Downhill],
12
+ id: "test",
13
+ name: null,
14
+ ref: null,
15
+ status: "operating" as any,
16
+ description: null,
17
+ difficulty: null,
18
+ difficultyConvention: "europe" as any,
19
+ oneway: null,
20
+ lit: null,
21
+ gladed: null,
22
+ patrolled: null,
23
+ grooming: null,
24
+ skiAreas: [],
25
+ elevationProfile: null,
26
+ sources: [],
27
+ websites: [],
28
+ wikidata_id: null,
29
+ },
30
+ });
31
+
32
+ expect(getEstimatedRunDifficulty(0.03, downhillScale)).toBeNull(); // 3% steepness
33
+ });
34
+
35
+ it("should return correct difficulty for downhill slopes", () => {
36
+ const downhillScale = getSlopeGradingScale({
37
+ type: "Feature",
38
+ geometry: { type: "LineString", coordinates: [] },
39
+ properties: {
40
+ type: "Run" as any,
41
+ uses: [RunUse.Downhill],
42
+ id: "test",
43
+ name: null,
44
+ ref: null,
45
+ status: "operating" as any,
46
+ description: null,
47
+ difficulty: null,
48
+ difficultyConvention: "europe" as any,
49
+ oneway: null,
50
+ lit: null,
51
+ gladed: null,
52
+ patrolled: null,
53
+ grooming: null,
54
+ skiAreas: [],
55
+ elevationProfile: null,
56
+ sources: [],
57
+ websites: [],
58
+ wikidata_id: null,
59
+ },
60
+ });
61
+
62
+ expect(getEstimatedRunDifficulty(0.1, downhillScale)).toBe(RunDifficulty.EASY); // 10%
63
+ expect(getEstimatedRunDifficulty(0.3, downhillScale)).toBe(RunDifficulty.INTERMEDIATE); // 30%
64
+ expect(getEstimatedRunDifficulty(0.6, downhillScale)).toBe(RunDifficulty.ADVANCED); // 60%
65
+ expect(getEstimatedRunDifficulty(1.0, downhillScale)).toBe(RunDifficulty.EXPERT); // 100%
66
+ });
67
+
68
+ it("should return correct difficulty for nordic slopes", () => {
69
+ const nordicScale = getSlopeGradingScale({
70
+ type: "Feature",
71
+ geometry: { type: "LineString", coordinates: [] },
72
+ properties: {
73
+ type: "Run" as any,
74
+ uses: [RunUse.Nordic],
75
+ id: "test",
76
+ name: null,
77
+ ref: null,
78
+ status: "operating" as any,
79
+ description: null,
80
+ difficulty: null,
81
+ difficultyConvention: "europe" as any,
82
+ oneway: null,
83
+ lit: null,
84
+ gladed: null,
85
+ patrolled: null,
86
+ grooming: null,
87
+ skiAreas: [],
88
+ elevationProfile: null,
89
+ sources: [],
90
+ websites: [],
91
+ wikidata_id: null,
92
+ },
93
+ });
94
+
95
+ expect(getEstimatedRunDifficulty(0.05, nordicScale)).toBe(RunDifficulty.EASY); // 5%
96
+ expect(getEstimatedRunDifficulty(0.12, nordicScale)).toBe(RunDifficulty.INTERMEDIATE); // 12%
97
+ expect(getEstimatedRunDifficulty(0.25, nordicScale)).toBe(RunDifficulty.ADVANCED); // 25%
98
+ });
99
+
100
+ it("should handle negative steepness (uphill)", () => {
101
+ const downhillScale = getSlopeGradingScale({
102
+ type: "Feature",
103
+ geometry: { type: "LineString", coordinates: [] },
104
+ properties: {
105
+ type: "Run" as any,
106
+ uses: [RunUse.Downhill],
107
+ id: "test",
108
+ name: null,
109
+ ref: null,
110
+ status: "operating" as any,
111
+ description: null,
112
+ difficulty: null,
113
+ difficultyConvention: "europe" as any,
114
+ oneway: null,
115
+ lit: null,
116
+ gladed: null,
117
+ patrolled: null,
118
+ grooming: null,
119
+ skiAreas: [],
120
+ elevationProfile: null,
121
+ sources: [],
122
+ websites: [],
123
+ wikidata_id: null,
124
+ },
125
+ });
126
+
127
+ expect(getEstimatedRunDifficulty(-0.1, downhillScale)).toBe(RunDifficulty.EASY); // -10%
128
+ });
129
+ });