@hybridcore/ui 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/dist/Button-BZR43NHz.js +2025 -0
  2. package/dist/ButtonBase-B6WYZgVU.js +967 -0
  3. package/dist/CardContent-C8PxkJz4.js +73 -0
  4. package/dist/Checkbox-CxbQ9tJ5.js +673 -0
  5. package/dist/FormControl-C4PmH1vh.js +1491 -0
  6. package/dist/IconButton-CKHPuOyh.js +183 -0
  7. package/dist/Input-CH_JyT5B.js +324 -0
  8. package/dist/List-BX_5LP1i.js +132 -0
  9. package/dist/Object-DBPgar-D.js +688 -0
  10. package/dist/OutlinedInput-gnp48tDo.js +452 -0
  11. package/dist/Paper-CaiWdndQ.js +162 -0
  12. package/dist/Select-DOyHt8I_.js +2526 -0
  13. package/dist/Source-Bo1Eq6y-.js +4374 -0
  14. package/dist/Text-DVP2PrYM.js +2192 -0
  15. package/dist/Typography-XIiVCSto.js +178 -0
  16. package/dist/assertThisInitialized-BUtkG-md.js +13 -0
  17. package/dist/assets/index.css +1 -0
  18. package/dist/assets/index2.css +1 -0
  19. package/dist/chainPropTypes-DtBfUj5o.js +96 -0
  20. package/dist/components/access/helpers.js +32 -0
  21. package/dist/components/access/index.js +15 -0
  22. package/dist/components/card/index.js +159 -469
  23. package/dist/components/card/styled.js +75 -7
  24. package/dist/components/conditional-wrapper/index.js +9 -0
  25. package/dist/components/confirm/dialog.js +151 -0
  26. package/dist/components/confirm/index.js +23 -0
  27. package/dist/components/container/index.js +270 -0
  28. package/dist/components/context-menu/index.js +973 -0
  29. package/dist/components/data-management/instance-form/components/composite-list/index.js +12 -0
  30. package/dist/components/data-management/instance-form/components/composite-list/styled.js +64 -0
  31. package/dist/components/data-management/instance-form/components/policy-list/index.js +86 -0
  32. package/dist/components/data-management/instance-form/components/variable/index.js +15 -0
  33. package/dist/components/data-management/instance-form/components/variables/index.js +39 -0
  34. package/dist/components/data-management/instance-form/index.js +437 -0
  35. package/dist/components/data-security-selectors/dissemination-list/index.js +3201 -0
  36. package/dist/components/data-security-selectors/security-level/index.js +81 -0
  37. package/dist/components/date-time-picker/index.js +103 -0
  38. package/dist/components/geometry-picker/coordinate/index.js +93 -0
  39. package/dist/components/geometry-picker/edit/index.js +71 -0
  40. package/dist/components/geometry-picker/geometry/index.js +160 -0
  41. package/dist/components/geometry-picker/geometry/map-overlay.js +22 -0
  42. package/dist/components/geometry-picker/index.js +140 -0
  43. package/dist/components/geometry-picker/kml/index.js +62 -0
  44. package/dist/components/geometry-picker/kml/select-input-method.js +75 -0
  45. package/dist/components/geometry-picker/logic.js +69 -0
  46. package/dist/components/geometry-picker/map/index.js +42 -0
  47. package/dist/components/geometry-picker/map/logic.js +2360 -0
  48. package/dist/components/geometry-picker/map/style.js +88 -0
  49. package/dist/components/geometry-picker/parser/coordinate-input/index.js +78 -0
  50. package/dist/components/geometry-picker/parser/coordinate-input/logic.js +1305 -0
  51. package/dist/components/geometry-picker/parser/index.js +179 -0
  52. package/dist/components/geometry-picker/parser/logic.js +84 -0
  53. package/dist/components/geometry-picker/parser/styled.js +25 -0
  54. package/dist/components/geometry-picker/styled.js +48 -0
  55. package/dist/components/geometry-picker/wkt/index.js +59 -0
  56. package/dist/components/geometry-picker/wkt/select-input-method.js +75 -0
  57. package/dist/components/icon-button/index.js +18 -0
  58. package/dist/components/icon-button/styled.js +51 -0
  59. package/dist/components/key-protection/index.js +4 -0
  60. package/dist/components/key-protection/menu.js +85 -0
  61. package/dist/components/key-protection/utils.js +10 -0
  62. package/dist/components/loading/index.js +7 -0
  63. package/dist/components/loading/styled.js +16 -0
  64. package/dist/components/map/helpers/kml.js +45 -0
  65. package/dist/components/map/helpers/mapbox.js +48 -0
  66. package/dist/components/map/helpers/ol.js +25 -0
  67. package/dist/components/map/helpers/wkt.js +29 -0
  68. package/dist/components/map/index.js +30 -0
  69. package/dist/components/map/logic.js +140 -0
  70. package/dist/components/map/styled.js +8 -0
  71. package/dist/components/phone-input/index.js +25 -0
  72. package/dist/components/phone-input/styled.js +26 -0
  73. package/dist/components/search-input/index.js +76 -0
  74. package/dist/components/tree-select/index.js +70 -0
  75. package/dist/components/tree-select/styled.js +64 -0
  76. package/dist/components/treeview-filter/index.js +621 -0
  77. package/dist/components/treeview-filter/item/index.js +7 -0
  78. package/dist/components/treeview-filter/item-label/index.js +44 -0
  79. package/dist/createTheme-agWfFD64.js +2392 -0
  80. package/dist/exactProp-CI8dagM-.js +36 -0
  81. package/dist/extends-C3382pL0.js +22 -0
  82. package/dist/hooks/useMenuLogic.js +21 -0
  83. package/dist/hooks/useToggle.js +23 -0
  84. package/dist/index-BQE8B4sc.js +957 -0
  85. package/dist/index-DHFb1Qpn.js +1105 -0
  86. package/dist/isHostComponent-kiaBvYVo.js +6 -0
  87. package/dist/isMuiElement-CxT3_ACP.js +13 -0
  88. package/dist/main.d.ts +646 -0
  89. package/dist/ol-CMEkXXLJ.js +15041 -0
  90. package/dist/ownerDocument-CUrv0DIK.js +6 -0
  91. package/dist/ownerWindow-niciwP7I.js +7 -0
  92. package/dist/styled-B22KrhDR.js +229 -0
  93. package/dist/styled-Iq9jsO4F.js +1033 -0
  94. package/dist/useFormControl-CatNKXAi.js +10 -0
  95. package/dist/useId-BHG98T5I.js +26 -0
  96. package/dist/useTheme-C0Dky5rV.js +17 -0
  97. package/dist/useTheme-CeyGVuQP.js +10 -0
  98. package/dist/useThemeProps-CzAjOL6F.js +26 -0
  99. package/dist/utils/ontology.js +37 -0
  100. package/dist/utils-Bq0ye5vf.js +115 -0
  101. package/dist/utils-C13eMoWa.js +365 -0
  102. package/package.json +26 -5
  103. package/dist/styled-BG5UIpPU.js +0 -3459
@@ -0,0 +1,1305 @@
1
+ import { useState as it, useEffect as ct } from "react";
2
+ let ut = " ";
3
+ class h {
4
+ // note Unicode Degree = U+00B0. Prime = U+2032, Double prime = U+2033
5
+ /**
6
+ * Separator character to be used to separate degrees, minutes, seconds, and cardinal directions.
7
+ *
8
+ * Default separator is U+202F ‘narrow no-break space’.
9
+ *
10
+ * To change this (e.g. to empty string or full space), set Dms.separator prior to invoking
11
+ * formatting.
12
+ *
13
+ * @example
14
+ * import LatLon, { Dms } from '/js/geodesy/latlon-spherical.js';
15
+ * const p = new LatLon(51.2, 0.33).toString('dms'); // 51° 12′ 00″ N, 000° 19′ 48″ E
16
+ * Dms.separator = ''; // no separator
17
+ * const pʹ = new LatLon(51.2, 0.33).toString('dms'); // 51°12′00″N, 000°19′48″E
18
+ */
19
+ static get separator() {
20
+ return ut;
21
+ }
22
+ static set separator(t) {
23
+ ut = t;
24
+ }
25
+ /**
26
+ * Parses string representing degrees/minutes/seconds into numeric degrees.
27
+ *
28
+ * This is very flexible on formats, allowing signed decimal degrees, or deg-min-sec optionally
29
+ * suffixed by compass direction (NSEW); a variety of separators are accepted. Examples -3.62,
30
+ * '3 37 12W', '3°37′12″W'.
31
+ *
32
+ * Thousands/decimal separators must be comma/dot; use Dms.fromLocale to convert locale-specific
33
+ * thousands/decimal separators.
34
+ *
35
+ * @param {string|number} dms - Degrees or deg/min/sec in variety of formats.
36
+ * @returns {number} Degrees as decimal number.
37
+ *
38
+ * @example
39
+ * const lat = Dms.parse('51° 28′ 40.37″ N');
40
+ * const lon = Dms.parse('000° 00′ 05.29″ W');
41
+ * const p1 = new LatLon(lat, lon); // 51.4779°N, 000.0015°W
42
+ */
43
+ static parse(t) {
44
+ if (!isNaN(parseFloat(t)) && isFinite(t)) return Number(t);
45
+ const n = String(t).trim().replace(/^-/, "").replace(/[NSEW]$/i, "").split(/[^0-9.,]+/);
46
+ if (n[n.length - 1] == "" && n.splice(n.length - 1), n == "") return NaN;
47
+ let s = null;
48
+ switch (n.length) {
49
+ case 3:
50
+ s = n[0] / 1 + n[1] / 60 + n[2] / 3600;
51
+ break;
52
+ case 2:
53
+ s = n[0] / 1 + n[1] / 60;
54
+ break;
55
+ case 1:
56
+ s = n[0];
57
+ break;
58
+ default:
59
+ return NaN;
60
+ }
61
+ return /^-|[WS]$/i.test(t.trim()) && (s = -s), Number(s);
62
+ }
63
+ /**
64
+ * Converts decimal degrees to deg/min/sec format
65
+ * - degree, prime, double-prime symbols are added, but sign is discarded, though no compass
66
+ * direction is added.
67
+ * - degrees are zero-padded to 3 digits; for degrees latitude, use .slice(1) to remove leading
68
+ * zero.
69
+ *
70
+ * @private
71
+ * @param {number} deg - Degrees to be formatted as specified.
72
+ * @param {string} [format=d] - Return value as 'd', 'dm', 'dms' for deg, deg+min, deg+min+sec.
73
+ * @param {number} [dp=4|2|0] - Number of decimal places to use – default 4 for d, 2 for dm, 0 for dms.
74
+ * @returns {string} Degrees formatted as deg/min/secs according to specified format.
75
+ */
76
+ static toDms(t, n = "d", s = void 0) {
77
+ if (isNaN(t) || typeof t == "string" && t.trim() == "" || typeof t == "boolean" || t == 1 / 0 || t == null) return null;
78
+ if (s === void 0)
79
+ switch (n) {
80
+ case "d":
81
+ case "deg":
82
+ s = 4;
83
+ break;
84
+ case "dm":
85
+ case "deg+min":
86
+ s = 2;
87
+ break;
88
+ case "dms":
89
+ case "deg+min+sec":
90
+ s = 0;
91
+ break;
92
+ default:
93
+ n = "d", s = 4;
94
+ break;
95
+ }
96
+ t = Math.abs(t);
97
+ let e = null, i = null, r = null, a = null;
98
+ switch (n) {
99
+ default:
100
+ case "d":
101
+ case "deg":
102
+ i = t.toFixed(s), i < 100 && (i = "0" + i), i < 10 && (i = "0" + i), e = i + "°";
103
+ break;
104
+ case "dm":
105
+ case "deg+min":
106
+ i = Math.floor(t), r = (t * 60 % 60).toFixed(s), r == 60 && (r = 0 .toFixed(s), i++), i = ("000" + i).slice(-3), r < 10 && (r = "0" + r), e = i + "°" + h.separator + r + "′";
107
+ break;
108
+ case "dms":
109
+ case "deg+min+sec":
110
+ i = Math.floor(t), r = Math.floor(t * 3600 / 60) % 60, a = (t * 3600 % 60).toFixed(s), a == 60 && (a = 0 .toFixed(s), r++), r == 60 && (r = 0, i++), i = ("000" + i).slice(-3), r = ("00" + r).slice(-2), a < 10 && (a = "0" + a), e = i + "°" + h.separator + r + "′" + h.separator + a + "″";
111
+ break;
112
+ }
113
+ return e;
114
+ }
115
+ /**
116
+ * Converts numeric degrees to deg/min/sec latitude (2-digit degrees, suffixed with N/S).
117
+ *
118
+ * @param {number} deg - Degrees to be formatted as specified.
119
+ * @param {string} [format=d] - Return value as 'd', 'dm', 'dms' for deg, deg+min, deg+min+sec.
120
+ * @param {number} [dp=4|2|0] - Number of decimal places to use – default 4 for d, 2 for dm, 0 for dms.
121
+ * @returns {string} Degrees formatted as deg/min/secs according to specified format.
122
+ *
123
+ * @example
124
+ * const lat = Dms.toLat(-3.62, 'dms'); // 3°37′12″S
125
+ */
126
+ static toLat(t, n, s) {
127
+ const e = h.toDms(h.wrap90(t), n, s);
128
+ return e === null ? "–" : e.slice(1) + h.separator + (t < 0 ? "S" : "N");
129
+ }
130
+ /**
131
+ * Convert numeric degrees to deg/min/sec longitude (3-digit degrees, suffixed with E/W).
132
+ *
133
+ * @param {number} deg - Degrees to be formatted as specified.
134
+ * @param {string} [format=d] - Return value as 'd', 'dm', 'dms' for deg, deg+min, deg+min+sec.
135
+ * @param {number} [dp=4|2|0] - Number of decimal places to use – default 4 for d, 2 for dm, 0 for dms.
136
+ * @returns {string} Degrees formatted as deg/min/secs according to specified format.
137
+ *
138
+ * @example
139
+ * const lon = Dms.toLon(-3.62, 'dms'); // 3°37′12″W
140
+ */
141
+ static toLon(t, n, s) {
142
+ const e = h.toDms(h.wrap180(t), n, s);
143
+ return e === null ? "–" : e + h.separator + (t < 0 ? "W" : "E");
144
+ }
145
+ /**
146
+ * Converts numeric degrees to deg/min/sec as a bearing (0°..360°).
147
+ *
148
+ * @param {number} deg - Degrees to be formatted as specified.
149
+ * @param {string} [format=d] - Return value as 'd', 'dm', 'dms' for deg, deg+min, deg+min+sec.
150
+ * @param {number} [dp=4|2|0] - Number of decimal places to use – default 4 for d, 2 for dm, 0 for dms.
151
+ * @returns {string} Degrees formatted as deg/min/secs according to specified format.
152
+ *
153
+ * @example
154
+ * const lon = Dms.toBrng(-3.62, 'dms'); // 356°22′48″
155
+ */
156
+ static toBrng(t, n, s) {
157
+ const e = h.toDms(h.wrap360(t), n, s);
158
+ return e === null ? "–" : e.replace("360", "0");
159
+ }
160
+ /**
161
+ * Converts DMS string from locale thousands/decimal separators to JavaScript comma/dot separators
162
+ * for subsequent parsing.
163
+ *
164
+ * Both thousands and decimal separators must be followed by a numeric character, to facilitate
165
+ * parsing of single lat/long string (in which whitespace must be left after the comma separator).
166
+ *
167
+ * @param {string} str - Degrees/minutes/seconds formatted with locale separators.
168
+ * @returns {string} Degrees/minutes/seconds formatted with standard Javascript separators.
169
+ *
170
+ * @example
171
+ * const lat = Dms.fromLocale('51°28′40,12″N'); // '51°28′40.12″N' in France
172
+ * const p = new LatLon(Dms.fromLocale('51°28′40,37″N, 000°00′05,29″W'); // '51.4779°N, 000.0015°W' in France
173
+ */
174
+ static fromLocale(t) {
175
+ const n = 123456.789.toLocaleString(), s = { thousands: n.slice(3, 4), decimal: n.slice(7, 8) };
176
+ return t.replace(s.thousands, "⁜").replace(s.decimal, ".").replace("⁜", ",");
177
+ }
178
+ /**
179
+ * Converts DMS string from JavaScript comma/dot thousands/decimal separators to locale separators.
180
+ *
181
+ * Can also be used to format standard numbers such as distances.
182
+ *
183
+ * @param {string} str - Degrees/minutes/seconds formatted with standard Javascript separators.
184
+ * @returns {string} Degrees/minutes/seconds formatted with locale separators.
185
+ *
186
+ * @example
187
+ * const Dms.toLocale('123,456.789'); // '123.456,789' in France
188
+ * const Dms.toLocale('51°28′40.12″N, 000°00′05.31″W'); // '51°28′40,12″N, 000°00′05,31″W' in France
189
+ */
190
+ static toLocale(t) {
191
+ const n = 123456.789.toLocaleString(), s = { thousands: n.slice(3, 4), decimal: n.slice(7, 8) };
192
+ return t.replace(/,([0-9])/, "⁜$1").replace(".", s.decimal).replace("⁜", s.thousands);
193
+ }
194
+ /**
195
+ * Returns compass point (to given precision) for supplied bearing.
196
+ *
197
+ * @param {number} bearing - Bearing in degrees from north.
198
+ * @param {number} [precision=3] - Precision (1:cardinal / 2:intercardinal / 3:secondary-intercardinal).
199
+ * @returns {string} Compass point for supplied bearing.
200
+ *
201
+ * @example
202
+ * const point = Dms.compassPoint(24); // point = 'NNE'
203
+ * const point = Dms.compassPoint(24, 1); // point = 'N'
204
+ */
205
+ static compassPoint(t, n = 3) {
206
+ if (![1, 2, 3].includes(Number(n))) throw new RangeError(`invalid precision ‘${n}’`);
207
+ t = h.wrap360(t);
208
+ const s = [
209
+ "N",
210
+ "NNE",
211
+ "NE",
212
+ "ENE",
213
+ "E",
214
+ "ESE",
215
+ "SE",
216
+ "SSE",
217
+ "S",
218
+ "SSW",
219
+ "SW",
220
+ "WSW",
221
+ "W",
222
+ "WNW",
223
+ "NW",
224
+ "NNW"
225
+ ], e = 4 * 2 ** (n - 1);
226
+ return s[Math.round(t * e / 360) % e * 16 / e];
227
+ }
228
+ /**
229
+ * Constrain degrees to range -90..+90 (for latitude); e.g. -91 => -89, 91 => 89.
230
+ *
231
+ * @private
232
+ * @param {number} degrees
233
+ * @returns degrees within range -90..+90.
234
+ */
235
+ static wrap90(t) {
236
+ if (-90 <= t && t <= 90) return t;
237
+ const n = t, s = 90, e = 360;
238
+ return 4 * s / e * Math.abs(((n - e / 4) % e + e) % e - e / 2) - s;
239
+ }
240
+ /**
241
+ * Constrain degrees to range -180..+180 (for longitude); e.g. -181 => 179, 181 => -179.
242
+ *
243
+ * @private
244
+ * @param {number} degrees
245
+ * @returns degrees within range -180..+180.
246
+ */
247
+ static wrap180(t) {
248
+ if (-180 <= t && t <= 180) return t;
249
+ const n = t, s = 180, e = 360;
250
+ return ((2 * s * n / e - e / 2) % e + e) % e - s;
251
+ }
252
+ /**
253
+ * Constrain degrees to range 0..360 (for bearings); e.g. -1 => 359, 361 => 1.
254
+ *
255
+ * @private
256
+ * @param {number} degrees
257
+ * @returns degrees within range 0..360.
258
+ */
259
+ static wrap360(t) {
260
+ if (0 <= t && t < 360) return t;
261
+ const n = t, s = 180, e = 360;
262
+ return (2 * s * n / e % e + e) % e;
263
+ }
264
+ }
265
+ Number.prototype.toRadians = function() {
266
+ return this * Math.PI / 180;
267
+ };
268
+ Number.prototype.toDegrees = function() {
269
+ return this * 180 / Math.PI;
270
+ };
271
+ class $ {
272
+ /**
273
+ * Creates a 3-d vector.
274
+ *
275
+ * @param {number} x - X component of vector.
276
+ * @param {number} y - Y component of vector.
277
+ * @param {number} z - Z component of vector.
278
+ *
279
+ * @example
280
+ * import Vector3d from '/js/geodesy/vector3d.js';
281
+ * const v = new Vector3d(0.267, 0.535, 0.802);
282
+ */
283
+ constructor(t, n, s) {
284
+ if (isNaN(t) || isNaN(n) || isNaN(s)) throw new TypeError(`invalid vector [${t},${n},${s}]`);
285
+ this.x = Number(t), this.y = Number(n), this.z = Number(s);
286
+ }
287
+ /**
288
+ * Length (magnitude or norm) of ‘this’ vector.
289
+ *
290
+ * @returns {number} Magnitude of this vector.
291
+ */
292
+ get length() {
293
+ return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
294
+ }
295
+ /**
296
+ * Adds supplied vector to ‘this’ vector.
297
+ *
298
+ * @param {Vector3d} v - Vector to be added to this vector.
299
+ * @returns {Vector3d} Vector representing sum of this and v.
300
+ */
301
+ plus(t) {
302
+ if (!(t instanceof $)) throw new TypeError("v is not Vector3d object");
303
+ return new $(this.x + t.x, this.y + t.y, this.z + t.z);
304
+ }
305
+ /**
306
+ * Subtracts supplied vector from ‘this’ vector.
307
+ *
308
+ * @param {Vector3d} v - Vector to be subtracted from this vector.
309
+ * @returns {Vector3d} Vector representing difference between this and v.
310
+ */
311
+ minus(t) {
312
+ if (!(t instanceof $)) throw new TypeError("v is not Vector3d object");
313
+ return new $(this.x - t.x, this.y - t.y, this.z - t.z);
314
+ }
315
+ /**
316
+ * Multiplies ‘this’ vector by a scalar value.
317
+ *
318
+ * @param {number} x - Factor to multiply this vector by.
319
+ * @returns {Vector3d} Vector scaled by x.
320
+ */
321
+ times(t) {
322
+ if (isNaN(t)) throw new TypeError(`invalid scalar value ‘${t}’`);
323
+ return new $(this.x * t, this.y * t, this.z * t);
324
+ }
325
+ /**
326
+ * Divides ‘this’ vector by a scalar value.
327
+ *
328
+ * @param {number} x - Factor to divide this vector by.
329
+ * @returns {Vector3d} Vector divided by x.
330
+ */
331
+ dividedBy(t) {
332
+ if (isNaN(t)) throw new TypeError(`invalid scalar value ‘${t}’`);
333
+ return new $(this.x / t, this.y / t, this.z / t);
334
+ }
335
+ /**
336
+ * Multiplies ‘this’ vector by the supplied vector using dot (scalar) product.
337
+ *
338
+ * @param {Vector3d} v - Vector to be dotted with this vector.
339
+ * @returns {number} Dot product of ‘this’ and v.
340
+ */
341
+ dot(t) {
342
+ if (!(t instanceof $)) throw new TypeError("v is not Vector3d object");
343
+ return this.x * t.x + this.y * t.y + this.z * t.z;
344
+ }
345
+ /**
346
+ * Multiplies ‘this’ vector by the supplied vector using cross (vector) product.
347
+ *
348
+ * @param {Vector3d} v - Vector to be crossed with this vector.
349
+ * @returns {Vector3d} Cross product of ‘this’ and v.
350
+ */
351
+ cross(t) {
352
+ if (!(t instanceof $)) throw new TypeError("v is not Vector3d object");
353
+ const n = this.y * t.z - this.z * t.y, s = this.z * t.x - this.x * t.z, e = this.x * t.y - this.y * t.x;
354
+ return new $(n, s, e);
355
+ }
356
+ /**
357
+ * Negates a vector to point in the opposite direction.
358
+ *
359
+ * @returns {Vector3d} Negated vector.
360
+ */
361
+ negate() {
362
+ return new $(-this.x, -this.y, -this.z);
363
+ }
364
+ /**
365
+ * Normalizes a vector to its unit vector
366
+ * – if the vector is already unit or is zero magnitude, this is a no-op.
367
+ *
368
+ * @returns {Vector3d} Normalised version of this vector.
369
+ */
370
+ unit() {
371
+ const t = this.length;
372
+ if (t == 1) return this;
373
+ if (t == 0) return this;
374
+ const n = this.x / t, s = this.y / t, e = this.z / t;
375
+ return new $(n, s, e);
376
+ }
377
+ /**
378
+ * Calculates the angle between ‘this’ vector and supplied vector atan2(|p₁×p₂|, p₁·p₂) (or if
379
+ * (extra-planar) ‘n’ supplied then atan2(n·p₁×p₂, p₁·p₂).
380
+ *
381
+ * @param {Vector3d} v - Vector whose angle is to be determined from ‘this’ vector.
382
+ * @param {Vector3d} [n] - Plane normal: if supplied, angle is signed +ve if this->v is
383
+ * clockwise looking along n, -ve in opposite direction.
384
+ * @returns {number} Angle (in radians) between this vector and supplied vector (in range 0..π
385
+ * if n not supplied, range -π..+π if n supplied).
386
+ */
387
+ angleTo(t, n = void 0) {
388
+ if (!(t instanceof $)) throw new TypeError("v is not Vector3d object");
389
+ if (!(n instanceof $ || n == null)) throw new TypeError("n is not Vector3d object");
390
+ const s = n == null || this.cross(t).dot(n) >= 0 ? 1 : -1, e = this.cross(t).length * s, i = this.dot(t);
391
+ return Math.atan2(e, i);
392
+ }
393
+ /**
394
+ * Rotates ‘this’ point around an axis by a specified angle.
395
+ *
396
+ * @param {Vector3d} axis - The axis being rotated around.
397
+ * @param {number} angle - The angle of rotation (in degrees).
398
+ * @returns {Vector3d} The rotated point.
399
+ */
400
+ rotateAround(t, n) {
401
+ if (!(t instanceof $)) throw new TypeError("axis is not Vector3d object");
402
+ const s = n.toRadians(), e = this.unit(), i = t.unit(), r = Math.sin(s), a = Math.cos(s), o = 1 - a, f = i.x, c = i.y, u = i.z, w = [
403
+ // rotation matrix for rotation about supplied axis
404
+ [o * f * f + a, o * f * c - r * u, o * f * u + r * c],
405
+ [o * f * c + r * u, o * c * c + a, o * c * u - r * f],
406
+ [o * f * u - r * c, o * c * u + r * f, o * u * u + a]
407
+ ], N = [
408
+ w[0][0] * e.x + w[0][1] * e.y + w[0][2] * e.z,
409
+ w[1][0] * e.x + w[1][1] * e.y + w[1][2] * e.z,
410
+ w[2][0] * e.x + w[2][1] * e.y + w[2][2] * e.z
411
+ ];
412
+ return new $(N[0], N[1], N[2]);
413
+ }
414
+ /**
415
+ * String representation of vector.
416
+ *
417
+ * @param {number} [dp=3] - Number of decimal places to be used.
418
+ * @returns {string} Vector represented as [x,y,z].
419
+ */
420
+ toString(t = 3) {
421
+ return `[${this.x.toFixed(t)},${this.y.toFixed(t)},${this.z.toFixed(t)}]`;
422
+ }
423
+ }
424
+ Number.prototype.toRadians = function() {
425
+ return this * Math.PI / 180;
426
+ };
427
+ Number.prototype.toDegrees = function() {
428
+ return this * 180 / Math.PI;
429
+ };
430
+ const B = {
431
+ WGS84: { a: 6378137, b: 6356752314245e-6, f: 1 / 298.257223563 }
432
+ }, dt = {
433
+ WGS84: { ellipsoid: B.WGS84 }
434
+ };
435
+ Object.freeze(B.WGS84);
436
+ Object.freeze(dt.WGS84);
437
+ class Q {
438
+ /**
439
+ * Creates a geodetic latitude/longitude point on a (WGS84) ellipsoidal model earth.
440
+ *
441
+ * @param {number} lat - Latitude (in degrees).
442
+ * @param {number} lon - Longitude (in degrees).
443
+ * @param {number} [height=0] - Height above ellipsoid in metres.
444
+ * @throws {TypeError} Invalid lat/lon/height.
445
+ *
446
+ * @example
447
+ * import LatLon from '/js/geodesy/latlon-ellipsoidal.js';
448
+ * const p = new LatLon(51.47788, -0.00147, 17);
449
+ */
450
+ constructor(t, n, s = 0) {
451
+ if (isNaN(t) || t == null) throw new TypeError(`invalid lat ‘${t}’`);
452
+ if (isNaN(n) || n == null) throw new TypeError(`invalid lon ‘${n}’`);
453
+ if (isNaN(s) || s == null) throw new TypeError(`invalid height ‘${s}’`);
454
+ this._lat = h.wrap90(Number(t)), this._lon = h.wrap180(Number(n)), this._height = Number(s);
455
+ }
456
+ /**
457
+ * Latitude in degrees north from equator (including aliases lat, latitude): can be set as
458
+ * numeric or hexagesimal (deg-min-sec); returned as numeric.
459
+ */
460
+ get lat() {
461
+ return this._lat;
462
+ }
463
+ get latitude() {
464
+ return this._lat;
465
+ }
466
+ set lat(t) {
467
+ if (this._lat = isNaN(t) ? h.wrap90(h.parse(t)) : h.wrap90(Number(t)), isNaN(this._lat)) throw new TypeError(`invalid lat ‘${t}’`);
468
+ }
469
+ set latitude(t) {
470
+ if (this._lat = isNaN(t) ? h.wrap90(h.parse(t)) : h.wrap90(Number(t)), isNaN(this._lat)) throw new TypeError(`invalid latitude ‘${t}’`);
471
+ }
472
+ /**
473
+ * Longitude in degrees east from international reference meridian (including aliases lon, lng,
474
+ * longitude): can be set as numeric or hexagesimal (deg-min-sec); returned as numeric.
475
+ */
476
+ get lon() {
477
+ return this._lon;
478
+ }
479
+ get lng() {
480
+ return this._lon;
481
+ }
482
+ get longitude() {
483
+ return this._lon;
484
+ }
485
+ set lon(t) {
486
+ if (this._lon = isNaN(t) ? h.wrap180(h.parse(t)) : h.wrap180(Number(t)), isNaN(this._lon)) throw new TypeError(`invalid lon ‘${t}’`);
487
+ }
488
+ set lng(t) {
489
+ if (this._lon = isNaN(t) ? h.wrap180(h.parse(t)) : h.wrap180(Number(t)), isNaN(this._lon)) throw new TypeError(`invalid lng ‘${t}’`);
490
+ }
491
+ set longitude(t) {
492
+ if (this._lon = isNaN(t) ? h.wrap180(h.parse(t)) : h.wrap180(Number(t)), isNaN(this._lon)) throw new TypeError(`invalid longitude ‘${t}’`);
493
+ }
494
+ /**
495
+ * Height in metres above ellipsoid.
496
+ */
497
+ get height() {
498
+ return this._height;
499
+ }
500
+ set height(t) {
501
+ if (this._height = Number(t), isNaN(this._height)) throw new TypeError(`invalid height ‘${t}’`);
502
+ }
503
+ /**
504
+ * Datum.
505
+ *
506
+ * Note this is replicated within LatLonEllipsoidal in order that a LatLonEllipsoidal object can
507
+ * be monkey-patched to look like a LatLonEllipsoidal_Datum, for Vincenty calculations on
508
+ * different ellipsoids.
509
+ *
510
+ * @private
511
+ */
512
+ get datum() {
513
+ return this._datum;
514
+ }
515
+ set datum(t) {
516
+ this._datum = t;
517
+ }
518
+ /**
519
+ * Ellipsoids with their parameters; this module only defines WGS84 parameters a = 6378137, b =
520
+ * 6356752.314245, f = 1/298.257223563.
521
+ *
522
+ * @example
523
+ * const a = LatLon.ellipsoids.WGS84.a; // 6378137
524
+ */
525
+ static get ellipsoids() {
526
+ return B;
527
+ }
528
+ /**
529
+ * Datums; this module only defines WGS84 datum, hence no datum transformations.
530
+ *
531
+ * @example
532
+ * const a = LatLon.datums.WGS84.ellipsoid.a; // 6377563.396
533
+ */
534
+ static get datums() {
535
+ return dt;
536
+ }
537
+ /**
538
+ * Parses a latitude/longitude point from a variety of formats.
539
+ *
540
+ * Latitude & longitude (in degrees) can be supplied as two separate parameters, as a single
541
+ * comma-separated lat/lon string, or as a single object with { lat, lon } or GeoJSON properties.
542
+ *
543
+ * The latitude/longitude values may be numeric or strings; they may be signed decimal or
544
+ * deg-min-sec (hexagesimal) suffixed by compass direction (NSEW); a variety of separators are
545
+ * accepted. Examples -3.62, '3 37 12W', '3°37′12″W'.
546
+ *
547
+ * Thousands/decimal separators must be comma/dot; use Dms.fromLocale to convert locale-specific
548
+ * thousands/decimal separators.
549
+ *
550
+ * @param {number|string|Object} lat|latlon - Latitude (in degrees), or comma-separated lat/lon, or lat/lon object.
551
+ * @param {number} [lon] - Longitude (in degrees).
552
+ * @param {number} [height=0] - Height above ellipsoid in metres.
553
+ * @returns {LatLon} Latitude/longitude point on WGS84 ellipsoidal model earth.
554
+ * @throws {TypeError} Invalid coordinate.
555
+ *
556
+ * @example
557
+ * const p1 = LatLon.parse(51.47788, -0.00147); // numeric pair
558
+ * const p2 = LatLon.parse('51°28′40″N, 000°00′05″W', 17); // dms string + height
559
+ * const p3 = LatLon.parse({ lat: 52.205, lon: 0.119 }, 17); // { lat, lon } object numeric + height
560
+ */
561
+ static parse(...t) {
562
+ if (t.length == 0) throw new TypeError("invalid (empty) point");
563
+ let n, s, e;
564
+ if (typeof t[0] == "object" && (t.length == 1 || !isNaN(parseFloat(t[1])))) {
565
+ const i = t[0];
566
+ if (i.type == "Point" && Array.isArray(i.coordinates) ? ([s, n, e] = i.coordinates, e = e || 0) : (i.latitude != null && (n = i.latitude), i.lat != null && (n = i.lat), i.longitude != null && (s = i.longitude), i.lng != null && (s = i.lng), i.lon != null && (s = i.lon), i.height != null && (e = i.height), n = h.wrap90(h.parse(n)), s = h.wrap180(h.parse(s))), t[1] != null && (e = t[1]), isNaN(n) || isNaN(s)) throw new TypeError(`invalid point ‘${JSON.stringify(t[0])}’`);
567
+ }
568
+ if (typeof t[0] == "string" && t[0].split(",").length == 2 && ([n, s] = t[0].split(","), n = h.wrap90(h.parse(n)), s = h.wrap180(h.parse(s)), e = t[1] || 0, isNaN(n) || isNaN(s)))
569
+ throw new TypeError(`invalid point ‘${t[0]}’`);
570
+ if (n == null && s == null && ([n, s] = t, n = h.wrap90(h.parse(n)), s = h.wrap180(h.parse(s)), e = t[2] || 0, isNaN(n) || isNaN(s)))
571
+ throw new TypeError(`invalid point ‘${t.toString()}’`);
572
+ return new this(n, s, e);
573
+ }
574
+ /**
575
+ * Converts ‘this’ point from (geodetic) latitude/longitude coordinates to (geocentric)
576
+ * cartesian (x/y/z) coordinates.
577
+ *
578
+ * @returns {Cartesian} Cartesian point equivalent to lat/lon point, with x, y, z in metres from
579
+ * earth centre.
580
+ */
581
+ toCartesian() {
582
+ const t = this.datum ? this.datum.ellipsoid : this.referenceFrame ? this.referenceFrame.ellipsoid : B.WGS84, n = this.lat.toRadians(), s = this.lon.toRadians(), e = this.height, { a: i, f: r } = t, a = Math.sin(n), o = Math.cos(n), f = Math.sin(s), c = Math.cos(s), u = 2 * r - r * r, w = i / Math.sqrt(1 - u * a * a), N = (w + e) * o * c, g = (w + e) * o * f, d = (w * (1 - u) + e) * a;
583
+ return new ft(N, g, d);
584
+ }
585
+ /**
586
+ * Checks if another point is equal to ‘this’ point.
587
+ *
588
+ * @param {LatLon} point - Point to be compared against this point.
589
+ * @returns {bool} True if points have identical latitude, longitude, height, and datum/referenceFrame.
590
+ * @throws {TypeError} Invalid point.
591
+ *
592
+ * @example
593
+ * const p1 = new LatLon(52.205, 0.119);
594
+ * const p2 = new LatLon(52.205, 0.119);
595
+ * const equal = p1.equals(p2); // true
596
+ */
597
+ equals(t) {
598
+ if (!(t instanceof Q)) throw new TypeError(`invalid point ‘${t}’`);
599
+ return !(Math.abs(this.lat - t.lat) > Number.EPSILON || Math.abs(this.lon - t.lon) > Number.EPSILON || Math.abs(this.height - t.height) > Number.EPSILON || this.datum != t.datum || this.referenceFrame != t.referenceFrame || this.epoch != t.epoch);
600
+ }
601
+ /**
602
+ * Returns a string representation of ‘this’ point, formatted as degrees, degrees+minutes, or
603
+ * degrees+minutes+seconds.
604
+ *
605
+ * @param {string} [format=d] - Format point as 'd', 'dm', 'dms', or 'n' for signed numeric.
606
+ * @param {number} [dp=4|2|0] - Number of decimal places to use: default 4 for d, 2 for dm, 0 for dms.
607
+ * @param {number} [dpHeight=null] - Number of decimal places to use for height; default is no height display.
608
+ * @returns {string} Comma-separated formatted latitude/longitude.
609
+ * @throws {RangeError} Invalid format.
610
+ *
611
+ * @example
612
+ * const greenwich = new LatLon(51.47788, -0.00147, 46);
613
+ * const d = greenwich.toString(); // 51.4779°N, 000.0015°W
614
+ * const dms = greenwich.toString('dms', 2); // 51°28′40″N, 000°00′05″W
615
+ * const [lat, lon] = greenwich.toString('n').split(','); // 51.4779, -0.0015
616
+ * const dmsh = greenwich.toString('dms', 0, 0); // 51°28′40″N, 000°00′06″W +46m
617
+ */
618
+ toString(t = "d", n = void 0, s = null) {
619
+ if (!["d", "dm", "dms", "n"].includes(t)) throw new RangeError(`invalid format ‘${t}’`);
620
+ const e = (this.height >= 0 ? " +" : " ") + this.height.toFixed(s) + "m";
621
+ if (t == "n") {
622
+ n == null && (n = 4);
623
+ const a = this.lat.toFixed(n), o = this.lon.toFixed(n);
624
+ return `${a}, ${o}${s == null ? "" : e}`;
625
+ }
626
+ const i = h.toLat(this.lat, t, n), r = h.toLon(this.lon, t, n);
627
+ return `${i}, ${r}${s == null ? "" : e}`;
628
+ }
629
+ }
630
+ class ft extends $ {
631
+ /**
632
+ * Creates cartesian coordinate representing ECEF (earth-centric earth-fixed) point.
633
+ *
634
+ * @param {number} x - X coordinate in metres (=> 0°N,0°E).
635
+ * @param {number} y - Y coordinate in metres (=> 0°N,90°E).
636
+ * @param {number} z - Z coordinate in metres (=> 90°N).
637
+ *
638
+ * @example
639
+ * import { Cartesian } from '/js/geodesy/latlon-ellipsoidal.js';
640
+ * const coord = new Cartesian(3980581.210, -111.159, 4966824.522);
641
+ */
642
+ constructor(t, n, s) {
643
+ super(t, n, s);
644
+ }
645
+ /**
646
+ * Converts ‘this’ (geocentric) cartesian (x/y/z) coordinate to (geodetic) latitude/longitude
647
+ * point on specified ellipsoid.
648
+ *
649
+ * Uses Bowring’s (1985) formulation for μm precision in concise form; ‘The accuracy of geodetic
650
+ * latitude and height equations’, B R Bowring, Survey Review vol 28, 218, Oct 1985.
651
+ *
652
+ * @param {LatLon.ellipsoids} [ellipsoid=WGS84] - Ellipsoid to use when converting point.
653
+ * @returns {LatLon} Latitude/longitude point defined by cartesian coordinates, on given ellipsoid.
654
+ * @throws {TypeError} Invalid ellipsoid.
655
+ *
656
+ * @example
657
+ * const c = new Cartesian(4027893.924, 307041.993, 4919474.294);
658
+ * const p = c.toLatLon(); // 50.7978°N, 004.3592°E
659
+ */
660
+ toLatLon(t = B.WGS84) {
661
+ if (!t || !t.a) throw new TypeError(`invalid ellipsoid ‘${t}’`);
662
+ const { x: n, y: s, z: e } = this, { a: i, b: r, f: a } = t, o = 2 * a - a * a, f = o / (1 - o), c = Math.sqrt(n * n + s * s), u = Math.sqrt(c * c + e * e), w = r * e / (i * c) * (1 + f * r / u), N = w / Math.sqrt(1 + w * w), g = N / w, d = isNaN(g) ? 0 : Math.atan2(e + f * r * N * N * N, c - o * i * g * g * g), p = Math.atan2(s, n), m = Math.sin(d), y = Math.cos(d), b = i / Math.sqrt(1 - o * m * m), S = c * y + e * m - i * i / b;
663
+ return new Q(d.toDegrees(), p.toDegrees(), S);
664
+ }
665
+ /**
666
+ * Returns a string representation of ‘this’ cartesian point.
667
+ *
668
+ * @param {number} [dp=0] - Number of decimal places to use.
669
+ * @returns {string} Comma-separated latitude/longitude.
670
+ */
671
+ toString(t = 0) {
672
+ const n = this.x.toFixed(t), s = this.y.toFixed(t), e = this.z.toFixed(t);
673
+ return `[${n},${s},${e}]`;
674
+ }
675
+ }
676
+ const x = {
677
+ WGS84: { a: 6378137, b: 6356752314245e-6, f: 1 / 298.257223563 },
678
+ Airy1830: { a: 6377563396e-3, b: 6356256909e-3, f: 1 / 299.3249646 },
679
+ AiryModified: { a: 6377340189e-3, b: 6356034448e-3, f: 1 / 299.3249646 },
680
+ Bessel1841: { a: 6377397155e-3, b: 6356078962818e-6, f: 1 / 299.1528128 },
681
+ Clarke1866: { a: 63782064e-1, b: 63565838e-1, f: 1 / 294.978698214 },
682
+ Clarke1880IGN: { a: 63782492e-1, b: 6356515, f: 1 / 293.466021294 },
683
+ GRS80: { a: 6378137, b: 635675231414e-5, f: 1 / 298.257222101 },
684
+ Intl1924: { a: 6378388, b: 6356911946e-3, f: 1 / 297 },
685
+ // aka Hayford
686
+ WGS72: { a: 6378135, b: 63567505e-1, f: 1 / 298.26 }
687
+ }, R = {
688
+ // transforms: t in metres, s in ppm, r in arcseconds tx ty tz s rx ry rz
689
+ ED50: { ellipsoid: x.Intl1924, transform: [89.5, 93.8, 123.1, -1.2, 0, 0, 0.156] },
690
+ // epsg.io/1311
691
+ ETRS89: { ellipsoid: x.GRS80, transform: [0, 0, 0, 0, 0, 0, 0] },
692
+ // epsg.io/1149; @ 1-metre level
693
+ Irl1975: { ellipsoid: x.AiryModified, transform: [-482.53, 130.596, -564.557, -8.15, 1.042, 0.214, 0.631] },
694
+ // epsg.io/1954
695
+ NAD27: { ellipsoid: x.Clarke1866, transform: [8, -160, -176, 0, 0, 0, 0] },
696
+ NAD83: { ellipsoid: x.GRS80, transform: [0.9956, -1.9103, -0.5215, -62e-5, 0.025915, 9426e-6, 0.011599] },
697
+ NTF: { ellipsoid: x.Clarke1880IGN, transform: [168, 60, -320, 0, 0, 0, 0] },
698
+ OSGB36: { ellipsoid: x.Airy1830, transform: [-446.448, 125.157, -542.06, 20.4894, -0.1502, -0.247, -0.8421] },
699
+ // epsg.io/1314
700
+ Potsdam: { ellipsoid: x.Bessel1841, transform: [-582, -105, -414, -8.3, 1.04, 0.35, -3.08] },
701
+ TokyoJapan: { ellipsoid: x.Bessel1841, transform: [148, -507, -685, 0, 0, 0, 0] },
702
+ WGS72: { ellipsoid: x.WGS72, transform: [0, 0, -4.5, -0.22, 0, 0, 0.554] },
703
+ WGS84: { ellipsoid: x.WGS84, transform: [0, 0, 0, 0, 0, 0, 0] }
704
+ };
705
+ Object.keys(x).forEach((M) => Object.freeze(x[M]));
706
+ Object.keys(R).forEach((M) => {
707
+ Object.freeze(R[M]), Object.freeze(R[M].transform);
708
+ });
709
+ class D extends Q {
710
+ /**
711
+ * Creates a geodetic latitude/longitude point on an ellipsoidal model earth using given datum.
712
+ *
713
+ * @param {number} lat - Latitude (in degrees).
714
+ * @param {number} lon - Longitude (in degrees).
715
+ * @param {number} [height=0] - Height above ellipsoid in metres.
716
+ * @param {LatLon.datums} datum - Datum this point is defined within.
717
+ *
718
+ * @example
719
+ * import LatLon from '/js/geodesy/latlon-ellipsoidal-datum.js';
720
+ * const p = new LatLon(53.3444, -6.2577, 17, LatLon.datums.Irl1975);
721
+ */
722
+ constructor(t, n, s = 0, e = R.WGS84) {
723
+ if (!e || e.ellipsoid == null) throw new TypeError(`unrecognised datum ‘${e}’`);
724
+ super(t, n, s), this._datum = e;
725
+ }
726
+ /**
727
+ * Datum this point is defined within.
728
+ */
729
+ get datum() {
730
+ return this._datum;
731
+ }
732
+ /**
733
+ * Ellipsoids with their parameters; semi-major axis (a), semi-minor axis (b), and flattening (f).
734
+ *
735
+ * Flattening f = (a−b)/a; at least one of these parameters is derived from defining constants.
736
+ *
737
+ * @example
738
+ * const a = LatLon.ellipsoids.Airy1830.a; // 6377563.396
739
+ */
740
+ static get ellipsoids() {
741
+ return x;
742
+ }
743
+ /**
744
+ * Datums; with associated ellipsoid, and Helmert transform parameters to convert from WGS-84
745
+ * into given datum.
746
+ *
747
+ * Note that precision of various datums will vary, and WGS-84 (original) is not defined to be
748
+ * accurate to better than ±1 metre. No transformation should be assumed to be accurate to
749
+ * better than a metre, for many datums somewhat less.
750
+ *
751
+ * This is a small sample of commoner datums from a large set of historical datums. I will add
752
+ * new datums on request.
753
+ *
754
+ * @example
755
+ * const a = LatLon.datums.OSGB36.ellipsoid.a; // 6377563.396
756
+ * const tx = LatLon.datums.OSGB36.transform; // [ tx, ty, tz, s, rx, ry, rz ]
757
+ * const availableDatums = Object.keys(LatLon.datums).join(', '); // ED50, Irl1975, NAD27, ...
758
+ */
759
+ static get datums() {
760
+ return R;
761
+ }
762
+ // note instance datum getter/setters are in LatLonEllipsoidal
763
+ /**
764
+ * Parses a latitude/longitude point from a variety of formats.
765
+ *
766
+ * Latitude & longitude (in degrees) can be supplied as two separate parameters, as a single
767
+ * comma-separated lat/lon string, or as a single object with { lat, lon } or GeoJSON properties.
768
+ *
769
+ * The latitude/longitude values may be numeric or strings; they may be signed decimal or
770
+ * deg-min-sec (hexagesimal) suffixed by compass direction (NSEW); a variety of separators are
771
+ * accepted. Examples -3.62, '3 37 12W', '3°37′12″W'.
772
+ *
773
+ * Thousands/decimal separators must be comma/dot; use Dms.fromLocale to convert locale-specific
774
+ * thousands/decimal separators.
775
+ *
776
+ * @param {number|string|Object} lat|latlon - Geodetic Latitude (in degrees) or comma-separated lat/lon or lat/lon object.
777
+ * @param {number} [lon] - Longitude in degrees.
778
+ * @param {number} [height=0] - Height above ellipsoid in metres.
779
+ * @param {LatLon.datums} [datum=WGS84] - Datum this point is defined within.
780
+ * @returns {LatLon} Latitude/longitude point on ellipsoidal model earth using given datum.
781
+ * @throws {TypeError} Unrecognised datum.
782
+ *
783
+ * @example
784
+ * const p = LatLon.parse('51.47736, 0.0000', 0, LatLon.datums.OSGB36);
785
+ */
786
+ static parse(...t) {
787
+ let n = R.WGS84;
788
+ if ((t.length == 4 || t.length == 3 && typeof t[2] == "object") && (n = t.pop()), !n || n.ellipsoid == null) throw new TypeError(`unrecognised datum ‘${n}’`);
789
+ const s = super.parse(...t);
790
+ return s._datum = n, s;
791
+ }
792
+ /**
793
+ * Converts ‘this’ lat/lon coordinate to new coordinate system.
794
+ *
795
+ * @param {LatLon.datums} toDatum - Datum this coordinate is to be converted to.
796
+ * @returns {LatLon} This point converted to new datum.
797
+ * @throws {TypeError} Unrecognised datum.
798
+ *
799
+ * @example
800
+ * const pWGS84 = new LatLon(51.47788, -0.00147, 0, LatLon.datums.WGS84);
801
+ * const pOSGB = pWGS84.convertDatum(LatLon.datums.OSGB36); // 51.4773°N, 000.0001°E
802
+ */
803
+ convertDatum(t) {
804
+ if (!t || t.ellipsoid == null) throw new TypeError(`unrecognised datum ‘${t}’`);
805
+ return this.toCartesian().convertDatum(t).toLatLon();
806
+ }
807
+ /**
808
+ * Converts ‘this’ point from (geodetic) latitude/longitude coordinates to (geocentric) cartesian
809
+ * (x/y/z) coordinates, based on the same datum.
810
+ *
811
+ * Shadow of LatLonEllipsoidal.toCartesian(), returning Cartesian augmented with
812
+ * LatLonEllipsoidal_Datum methods/properties.
813
+ *
814
+ * @returns {Cartesian} Cartesian point equivalent to lat/lon point, with x, y, z in metres from
815
+ * earth centre, augmented with reference frame conversion methods and properties.
816
+ */
817
+ toCartesian() {
818
+ const t = super.toCartesian();
819
+ return new lt(t.x, t.y, t.z, this.datum);
820
+ }
821
+ }
822
+ class lt extends ft {
823
+ /**
824
+ * Creates cartesian coordinate representing ECEF (earth-centric earth-fixed) point, on a given
825
+ * datum. The datum will identify the primary meridian (for the x-coordinate), and is also
826
+ * useful in transforming to/from geodetic (lat/lon) coordinates.
827
+ *
828
+ * @param {number} x - X coordinate in metres (=> 0°N,0°E).
829
+ * @param {number} y - Y coordinate in metres (=> 0°N,90°E).
830
+ * @param {number} z - Z coordinate in metres (=> 90°N).
831
+ * @param {LatLon.datums} [datum] - Datum this coordinate is defined within.
832
+ * @throws {TypeError} Unrecognised datum.
833
+ *
834
+ * @example
835
+ * import { Cartesian } from '/js/geodesy/latlon-ellipsoidal-datum.js';
836
+ * const coord = new Cartesian(3980581.210, -111.159, 4966824.522);
837
+ */
838
+ constructor(t, n, s, e = void 0) {
839
+ if (e && e.ellipsoid == null) throw new TypeError(`unrecognised datum ‘${e}’`);
840
+ super(t, n, s), e && (this._datum = e);
841
+ }
842
+ /**
843
+ * Datum this point is defined within.
844
+ */
845
+ get datum() {
846
+ return this._datum;
847
+ }
848
+ set datum(t) {
849
+ if (!t || t.ellipsoid == null) throw new TypeError(`unrecognised datum ‘${t}’`);
850
+ this._datum = t;
851
+ }
852
+ /**
853
+ * Converts ‘this’ (geocentric) cartesian (x/y/z) coordinate to (geodetic) latitude/longitude
854
+ * point (based on the same datum, or WGS84 if unset).
855
+ *
856
+ * Shadow of Cartesian.toLatLon(), returning LatLon augmented with LatLonEllipsoidal_Datum
857
+ * methods convertDatum, toCartesian, etc.
858
+ *
859
+ * @returns {LatLon} Latitude/longitude point defined by cartesian coordinates.
860
+ * @throws {TypeError} Unrecognised datum
861
+ *
862
+ * @example
863
+ * const c = new Cartesian(4027893.924, 307041.993, 4919474.294);
864
+ * const p = c.toLatLon(); // 50.7978°N, 004.3592°E
865
+ */
866
+ toLatLon(t = void 0) {
867
+ t && (console.info("datum parameter to Cartesian_Datum.toLatLon is deprecated: set datum before calling toLatLon()"), this.datum = t);
868
+ const n = this.datum || R.WGS84;
869
+ if (!n || n.ellipsoid == null) throw new TypeError(`unrecognised datum ‘${n}’`);
870
+ const s = super.toLatLon(n.ellipsoid);
871
+ return new D(s.lat, s.lon, s.height, this.datum);
872
+ }
873
+ /**
874
+ * Converts ‘this’ cartesian coordinate to new datum using Helmert 7-parameter transformation.
875
+ *
876
+ * @param {LatLon.datums} toDatum - Datum this coordinate is to be converted to.
877
+ * @returns {Cartesian} This point converted to new datum.
878
+ * @throws {Error} Undefined datum.
879
+ *
880
+ * @example
881
+ * const c = new Cartesian(3980574.247, -102.127, 4966830.065, LatLon.datums.OSGB36);
882
+ * c.convertDatum(LatLon.datums.Irl1975); // [??,??,??]
883
+ */
884
+ convertDatum(t) {
885
+ if (!t || t.ellipsoid == null) throw new TypeError(`unrecognised datum ‘${t}’`);
886
+ if (!this.datum) throw new TypeError("cartesian coordinate has no datum");
887
+ let n = null, s = null;
888
+ (this.datum == null || this.datum == R.WGS84) && (n = this, s = t.transform), t == R.WGS84 && (n = this, s = this.datum.transform.map((i) => -i)), s == null && (n = this.convertDatum(R.WGS84), s = t.transform);
889
+ const e = n.applyTransform(s);
890
+ return e.datum = t, e;
891
+ }
892
+ /**
893
+ * Applies Helmert 7-parameter transformation to ‘this’ coordinate using transform parameters t.
894
+ *
895
+ * This is used in converting datums (geodetic->cartesian, apply transform, cartesian->geodetic).
896
+ *
897
+ * @private
898
+ * @param {number[]} t - Transformation to apply to this coordinate.
899
+ * @returns {Cartesian} Transformed point.
900
+ */
901
+ applyTransform(t) {
902
+ const { x: n, y: s, z: e } = this, i = t[0], r = t[1], a = t[2], o = t[3] / 1e6 + 1, f = (t[4] / 3600).toRadians(), c = (t[5] / 3600).toRadians(), u = (t[6] / 3600).toRadians(), w = i + n * o - s * u + e * c, N = r + n * u + s * o - e * f, g = a - n * c + s * f + e * o;
903
+ return new lt(w, N, g);
904
+ }
905
+ }
906
+ class pt {
907
+ /**
908
+ * Creates a Utm coordinate object comprising zone, hemisphere, easting, northing on a given
909
+ * datum (normally WGS84).
910
+ *
911
+ * @param {number} zone - UTM 6° longitudinal zone (1..60 covering 180°W..180°E).
912
+ * @param {string} hemisphere - N for northern hemisphere, S for southern hemisphere.
913
+ * @param {number} easting - Easting in metres from false easting (-500km from central meridian).
914
+ * @param {number} northing - Northing in metres from equator (N) or from false northing -10,000km (S).
915
+ * @param {LatLon.datums} [datum=WGS84] - Datum UTM coordinate is based on.
916
+ * @param {number} [convergence=null] - Meridian convergence (bearing of grid north
917
+ * clockwise from true north), in degrees.
918
+ * @param {number} [scale=null] - Grid scale factor.
919
+ * @params {boolean=true} verifyEN - Check easting/northing is within 'normal' values (may be
920
+ * suppressed for extended coherent coordinates or alternative datums
921
+ * e.g. ED50 (epsg.io/23029).
922
+ * @throws {TypeError} Invalid UTM coordinate.
923
+ *
924
+ * @example
925
+ * import Utm from '/js/geodesy/utm.js';
926
+ * const utmCoord = new Utm(31, 'N', 448251, 5411932);
927
+ */
928
+ constructor(t, n, s, e, i = D.datums.WGS84, r = null, a = null, o = !0) {
929
+ if (!(1 <= t && t <= 60)) throw new RangeError(`invalid UTM zone ‘${t}’`);
930
+ if (t != parseInt(t)) throw new RangeError(`invalid UTM zone ‘${t}’`);
931
+ if (typeof n != "string" || !n.match(/[NS]/i)) throw new RangeError(`invalid UTM hemisphere ‘${n}’`);
932
+ if (o) {
933
+ if (!(0 <= s && s <= 1e6)) throw new RangeError(`invalid UTM easting ‘${s}’`);
934
+ if (n.toUpperCase() == "N" && !(0 <= e && e < 9328094)) throw new RangeError(`invalid UTM northing ‘${e}’`);
935
+ if (n.toUpperCase() == "S" && !(1118414 < e && e <= 1e7)) throw new RangeError(`invalid UTM northing ‘${e}’`);
936
+ }
937
+ if (!i || i.ellipsoid == null) throw new TypeError(`unrecognised datum ‘${i}’`);
938
+ this.zone = Number(t), this.hemisphere = n.toUpperCase(), this.easting = Number(s), this.northing = Number(e), this.datum = i, this.convergence = r === null ? null : Number(r), this.scale = a === null ? null : Number(a);
939
+ }
940
+ /**
941
+ * Converts UTM zone/easting/northing coordinate to latitude/longitude.
942
+ *
943
+ * Implements Karney’s method, using Krüger series to order n⁶, giving results accurate to 5nm
944
+ * for distances up to 3900km from the central meridian.
945
+ *
946
+ * @param {Utm} utmCoord - UTM coordinate to be converted to latitude/longitude.
947
+ * @returns {LatLon} Latitude/longitude of supplied grid reference.
948
+ *
949
+ * @example
950
+ * const grid = new Utm(31, 'N', 448251.795, 5411932.678);
951
+ * const latlong = grid.toLatLon(); // 48°51′29.52″N, 002°17′40.20″E
952
+ */
953
+ toLatLon() {
954
+ const { zone: t, hemisphere: n } = this, s = 5e5, e = 1e7, { a: i, f: r } = this.datum.ellipsoid, a = 0.9996, o = this.easting - s, f = n == "S" ? this.northing - e : this.northing, c = Math.sqrt(r * (2 - r)), u = r / (2 - r), w = u * u, N = u * w, g = u * N, d = u * g, p = u * d, m = i / (1 + u) * (1 + 1 / 4 * w + 1 / 64 * g + 1 / 256 * p), y = o / (a * m), b = f / (a * m), S = [
955
+ null,
956
+ // note β is one-based array (6th order Krüger expressions)
957
+ 1 / 2 * u - 2 / 3 * w + 37 / 96 * N - 1 / 360 * g - 81 / 512 * d + 96199 / 604800 * p,
958
+ 1 / 48 * w + 1 / 15 * N - 437 / 1440 * g + 46 / 105 * d - 1118711 / 3870720 * p,
959
+ 17 / 480 * N - 37 / 840 * g - 209 / 4480 * d + 5569 / 90720 * p,
960
+ 4397 / 161280 * g - 11 / 504 * d - 830251 / 7257600 * p,
961
+ 4583 / 161280 * d - 108847 / 3991680 * p,
962
+ 20648693 / 638668800 * p
963
+ ];
964
+ let L = b;
965
+ for (let l = 1; l <= 6; l++) L -= S[l] * Math.sin(2 * l * b) * Math.cosh(2 * l * y);
966
+ let P = y;
967
+ for (let l = 1; l <= 6; l++) P -= S[l] * Math.cos(2 * l * b) * Math.sinh(2 * l * y);
968
+ const G = Math.sinh(P), v = Math.sin(L), F = Math.cos(L), T = v / Math.sqrt(G * G + F * F);
969
+ let W = null, E = T;
970
+ do {
971
+ const l = Math.sinh(c * Math.atanh(c * E / Math.sqrt(1 + E * E))), st = E * Math.sqrt(1 + l * l) - l * Math.sqrt(1 + E * E);
972
+ W = (T - st) / Math.sqrt(1 + st * st) * (1 + (1 - c * c) * E * E) / ((1 - c * c) * Math.sqrt(1 + E * E)), E += W;
973
+ } while (Math.abs(W) > 1e-12);
974
+ const q = E, U = Math.atan(q);
975
+ let O = Math.atan2(G, F), C = 1;
976
+ for (let l = 1; l <= 6; l++) C -= 2 * l * S[l] * Math.cos(2 * l * b) * Math.cosh(2 * l * y);
977
+ let z = 0;
978
+ for (let l = 1; l <= 6; l++) z += 2 * l * S[l] * Math.sin(2 * l * b) * Math.sinh(2 * l * y);
979
+ const k = Math.atan(Math.tan(L) * Math.tanh(P)), j = Math.atan2(z, C), A = k + j, X = Math.sin(U), H = Math.sqrt(1 - c * c * X * X) * Math.sqrt(1 + q * q) * Math.sqrt(G * G + F * F), Y = m / i / Math.sqrt(C * C + z * z), J = a * H * Y, Z = ((t - 1) * 6 - 180 + 3).toRadians();
980
+ O += Z;
981
+ const V = Number(U.toDegrees().toFixed(14)), tt = Number(O.toDegrees().toFixed(14)), nt = Number(A.toDegrees().toFixed(9)), et = Number(J.toFixed(12)), I = new K(V, tt, 0, this.datum);
982
+ return I.convergence = nt, I.scale = et, I;
983
+ }
984
+ /**
985
+ * Parses string representation of UTM coordinate.
986
+ *
987
+ * A UTM coordinate comprises (space-separated)
988
+ * - zone
989
+ * - hemisphere
990
+ * - easting
991
+ * - northing.
992
+ *
993
+ * @param {string} utmCoord - UTM coordinate (WGS 84).
994
+ * @param {Datum} [datum=WGS84] - Datum coordinate is defined in (default WGS 84).
995
+ * @returns {Utm} Parsed UTM coordinate.
996
+ * @throws {TypeError} Invalid UTM coordinate.
997
+ *
998
+ * @example
999
+ * const utmCoord = Utm.parse('31 N 448251 5411932');
1000
+ * // utmCoord: {zone: 31, hemisphere: 'N', easting: 448251, northing: 5411932 }
1001
+ */
1002
+ static parse(t, n = D.datums.WGS84) {
1003
+ if (t = t.trim().match(/\S+/g), t == null || t.length != 4) throw new Error(`invalid UTM coordinate ‘${t}’`);
1004
+ const s = t[0], e = t[1], i = t[2], r = t[3];
1005
+ return new this(s, e, i, r, n);
1006
+ }
1007
+ /**
1008
+ * Returns a string representation of a UTM coordinate.
1009
+ *
1010
+ * To distinguish from MGRS grid zone designators, a space is left between the zone and the
1011
+ * hemisphere.
1012
+ *
1013
+ * Note that UTM coordinates get rounded, not truncated (unlike MGRS grid references).
1014
+ *
1015
+ * @param {number} [digits=0] - Number of digits to appear after the decimal point (3 ≡ mm).
1016
+ * @returns {string} A string representation of the coordinate.
1017
+ *
1018
+ * @example
1019
+ * const utm = new Utm('31', 'N', 448251, 5411932).toString(4); // 31 N 448251.0000 5411932.0000
1020
+ */
1021
+ toString(t = 0) {
1022
+ const n = this.zone.toString().padStart(2, "0"), s = this.hemisphere, e = this.easting.toFixed(t), i = this.northing.toFixed(t);
1023
+ return `${n} ${s} ${e} ${i}`;
1024
+ }
1025
+ }
1026
+ class K extends D {
1027
+ /**
1028
+ * Converts latitude/longitude to UTM coordinate.
1029
+ *
1030
+ * Implements Karney’s method, using Krüger series to order n⁶, giving results accurate to 5nm
1031
+ * for distances up to 3900km from the central meridian.
1032
+ *
1033
+ * @param {number} [zoneOverride] - Use specified zone rather than zone within which point lies;
1034
+ * note overriding the UTM zone has the potential to result in negative eastings, and
1035
+ * perverse results within Norway/Svalbard exceptions.
1036
+ * @returns {Utm} UTM coordinate.
1037
+ * @throws {TypeError} Latitude outside UTM limits.
1038
+ *
1039
+ * @example
1040
+ * const latlong = new LatLon(48.8582, 2.2945);
1041
+ * const utmCoord = latlong.toUtm(); // 31 N 448252 5411933
1042
+ */
1043
+ toUtm(t = void 0) {
1044
+ if (!(-80 <= this.lat && this.lat <= 84)) throw new RangeError(`latitude ‘${this.lat}’ outside UTM limits`);
1045
+ const n = 5e5, s = 1e7;
1046
+ let e = t || Math.floor((this.lon + 180) / 6) + 1, i = ((e - 1) * 6 - 180 + 3).toRadians();
1047
+ const a = "CDEFGHJKLMNPQRSTUVWXX".charAt(Math.floor(this.lat / 8 + 10));
1048
+ e == 31 && a == "V" && this.lon >= 3 && (e++, i += 6 .toRadians()), e == 32 && a == "X" && this.lon < 9 && (e--, i -= 6 .toRadians()), e == 32 && a == "X" && this.lon >= 9 && (e++, i += 6 .toRadians()), e == 34 && a == "X" && this.lon < 21 && (e--, i -= 6 .toRadians()), e == 34 && a == "X" && this.lon >= 21 && (e++, i += 6 .toRadians()), e == 36 && a == "X" && this.lon < 33 && (e--, i -= 6 .toRadians()), e == 36 && a == "X" && this.lon >= 33 && (e++, i += 6 .toRadians());
1049
+ const o = this.lat.toRadians(), f = this.lon.toRadians() - i, c = this.datum ? this.datum.ellipsoid : D.ellipsoids.WGS84, { a: u, f: w } = c, N = 0.9996, g = Math.sqrt(w * (2 - w)), d = w / (2 - w), p = d * d, m = d * p, y = d * m, b = d * y, S = d * b, L = Math.cos(f), P = Math.sin(f), G = Math.tan(f), v = Math.tan(o), F = Math.sinh(g * Math.atanh(g * v / Math.sqrt(1 + v * v))), T = v * Math.sqrt(1 + F * F) - F * Math.sqrt(1 + v * v), W = Math.atan2(T, L), E = Math.asinh(P / Math.sqrt(T * T + L * L)), q = u / (1 + d) * (1 + 1 / 4 * p + 1 / 64 * y + 1 / 256 * S), U = [
1050
+ null,
1051
+ // note α is one-based array (6th order Krüger expressions)
1052
+ 1 / 2 * d - 2 / 3 * p + 5 / 16 * m + 41 / 180 * y - 127 / 288 * b + 7891 / 37800 * S,
1053
+ 13 / 48 * p - 3 / 5 * m + 557 / 1440 * y + 281 / 630 * b - 1983433 / 1935360 * S,
1054
+ 61 / 240 * m - 103 / 140 * y + 15061 / 26880 * b + 167603 / 181440 * S,
1055
+ 49561 / 161280 * y - 179 / 168 * b + 6601661 / 7257600 * S,
1056
+ 34729 / 80640 * b - 3418889 / 1995840 * S,
1057
+ 212378941 / 319334400 * S
1058
+ ];
1059
+ let O = W;
1060
+ for (let l = 1; l <= 6; l++) O += U[l] * Math.sin(2 * l * W) * Math.cosh(2 * l * E);
1061
+ let C = E;
1062
+ for (let l = 1; l <= 6; l++) C += U[l] * Math.cos(2 * l * W) * Math.sinh(2 * l * E);
1063
+ let z = N * q * C, k = N * q * O, j = 1;
1064
+ for (let l = 1; l <= 6; l++) j += 2 * l * U[l] * Math.cos(2 * l * W) * Math.cosh(2 * l * E);
1065
+ let A = 0;
1066
+ for (let l = 1; l <= 6; l++) A += 2 * l * U[l] * Math.sin(2 * l * W) * Math.sinh(2 * l * E);
1067
+ const X = Math.atan(T / Math.sqrt(1 + T * T) * G), H = Math.atan2(A, j), Y = X + H, J = Math.sin(o), Z = Math.sqrt(1 - g * g * J * J) * Math.sqrt(1 + v * v) / Math.sqrt(T * T + L * L), V = q / u * Math.sqrt(j * j + A * A), tt = N * Z * V;
1068
+ z = z + n, k < 0 && (k = k + s), z = Number(z.toFixed(9)), k = Number(k.toFixed(9));
1069
+ const nt = Number(Y.toDegrees().toFixed(9)), et = Number(tt.toFixed(12)), I = this.lat >= 0 ? "N" : "S";
1070
+ return new pt(e, I, z, k, this.datum, nt, et, !!t);
1071
+ }
1072
+ }
1073
+ const rt = "CDEFGHJKLMNPQRSTUVWXX", ot = ["ABCDEFGH", "JKLMNPQR", "STUVWXYZ"], at = ["ABCDEFGHJKLMNPQRSTUV", "FGHJKLMNPQRSTUVABCDE"];
1074
+ class _ {
1075
+ /**
1076
+ * Creates an Mgrs grid reference object.
1077
+ *
1078
+ * @param {number} zone - 6° longitudinal zone (1..60 covering 180°W..180°E).
1079
+ * @param {string} band - 8° latitudinal band (C..X covering 80°S..84°N).
1080
+ * @param {string} e100k - First letter (E) of 100km grid square.
1081
+ * @param {string} n100k - Second letter (N) of 100km grid square.
1082
+ * @param {number} easting - Easting in metres within 100km grid square.
1083
+ * @param {number} northing - Northing in metres within 100km grid square.
1084
+ * @param {LatLon.datums} [datum=WGS84] - Datum UTM coordinate is based on.
1085
+ * @throws {RangeError} Invalid MGRS grid reference.
1086
+ *
1087
+ * @example
1088
+ * import Mgrs from '/js/geodesy/mgrs.js';
1089
+ * const mgrsRef = new Mgrs(31, 'U', 'D', 'Q', 48251, 11932); // 31U DQ 48251 11932
1090
+ */
1091
+ constructor(t, n, s, e, i, r, a = K.datums.WGS84) {
1092
+ if (!(1 <= t && t <= 60)) throw new RangeError(`invalid MGRS zone ‘${t}’`);
1093
+ if (t != parseInt(t)) throw new RangeError(`invalid MGRS zone ‘${t}’`);
1094
+ const o = [];
1095
+ if ((n.length != 1 || rt.indexOf(n) == -1) && o.push(`invalid MGRS band ‘${n}’`), (s.length != 1 || ot[(t - 1) % 3].indexOf(s) == -1) && o.push(`invalid MGRS 100km grid square column ‘${s}’ for zone ${t}`), (e.length != 1 || at[0].indexOf(e) == -1) && o.push(`invalid MGRS 100km grid square row ‘${e}’`), isNaN(Number(i)) && o.push(`invalid MGRS easting ‘${i}’`), isNaN(Number(r)) && o.push(`invalid MGRS northing ‘${r}’`), (!a || a.ellipsoid == null) && o.push(`unrecognised datum ‘${a}’`), o.length > 0) throw new RangeError(o.join(", "));
1096
+ this.zone = Number(t), this.band = n, this.e100k = s, this.n100k = e, this.easting = Number(i), this.northing = Number(r), this.datum = a;
1097
+ }
1098
+ /**
1099
+ * Converts MGRS grid reference to UTM coordinate.
1100
+ *
1101
+ * Grid references refer to squares rather than points (with the size of the square indicated
1102
+ * by the precision of the reference); this conversion will return the UTM coordinate of the SW
1103
+ * corner of the grid reference square.
1104
+ *
1105
+ * @returns {Utm} UTM coordinate of SW corner of this MGRS grid reference.
1106
+ *
1107
+ * @example
1108
+ * const mgrsRef = Mgrs.parse('31U DQ 48251 11932');
1109
+ * const utmCoord = mgrsRef.toUtm(); // 31 N 448251 5411932
1110
+ */
1111
+ toUtm() {
1112
+ const t = this.band >= "N" ? "N" : "S", s = (ot[(this.zone - 1) % 3].indexOf(this.e100k) + 1) * 1e5, i = at[(this.zone - 1) % 2].indexOf(this.n100k) * 1e5, r = (rt.indexOf(this.band) - 10) * 8, a = Math.floor(new K(r, 3).toUtm().northing / 1e5) * 1e5;
1113
+ let o = 0;
1114
+ for (; o + i + this.northing < a; ) o += 2e6;
1115
+ return new ht(this.zone, t, s + this.easting, o + i + this.northing, this.datum);
1116
+ }
1117
+ /**
1118
+ * Parses string representation of MGRS grid reference.
1119
+ *
1120
+ * An MGRS grid reference comprises (space-separated)
1121
+ * - grid zone designator (GZD)
1122
+ * - 100km grid square letter-pair
1123
+ * - easting
1124
+ * - northing.
1125
+ *
1126
+ * @param {string} mgrsGridRef - String representation of MGRS grid reference.
1127
+ * @returns {Mgrs} Mgrs grid reference object.
1128
+ * @throws {Error} Invalid MGRS grid reference.
1129
+ *
1130
+ * @example
1131
+ * const mgrsRef = Mgrs.parse('31U DQ 48251 11932');
1132
+ * const mgrsRef = Mgrs.parse('31UDQ4825111932');
1133
+ * // mgrsRef: { zone:31, band:'U', e100k:'D', n100k:'Q', easting:48251, northing:11932 }
1134
+ */
1135
+ static parse(t) {
1136
+ if (!t) throw new Error(`invalid MGRS grid reference ‘${t}’`);
1137
+ if (!t.trim().match(/\s/)) {
1138
+ if (!Number(t.slice(0, 2))) throw new Error(`invalid MGRS grid reference ‘${t}’`);
1139
+ let u = t.trim().slice(5);
1140
+ u = u.slice(0, u.length / 2) + " " + u.slice(-u.length / 2), t = t.slice(0, 3) + " " + t.slice(3, 5) + " " + u;
1141
+ }
1142
+ const n = t.match(/\S+/g);
1143
+ if (n == null || n.length != 4) throw new Error(`invalid MGRS grid reference ‘${t}’`);
1144
+ const s = n[0], e = s.slice(0, 2), i = s.slice(2, 3), r = n[1], a = r.slice(0, 1), o = r.slice(1, 2);
1145
+ let f = n[2], c = n[3];
1146
+ return f = f.length >= 5 ? f : (f + "00000").slice(0, 5), c = c.length >= 5 ? c : (c + "00000").slice(0, 5), new _(e, i, a, o, f, c);
1147
+ }
1148
+ /**
1149
+ * Returns a string representation of an MGRS grid reference.
1150
+ *
1151
+ * To distinguish from civilian UTM coordinate representations, no space is included within the
1152
+ * zone/band grid zone designator.
1153
+ *
1154
+ * Components are separated by spaces: for a military-style unseparated string, use
1155
+ * Mgrs.toString().replace(/ /g, '');
1156
+ *
1157
+ * Note that MGRS grid references get truncated, not rounded (unlike UTM coordinates); grid
1158
+ * references indicate a bounding square, rather than a point, with the size of the square
1159
+ * indicated by the precision - a precision of 10 indicates a 1-metre square, a precision of 4
1160
+ * indicates a 1,000-metre square (hence 31U DQ 48 11 indicates a 1km square with SW corner at
1161
+ * 31 N 448000 5411000, which would include the 1m square 31U DQ 48251 11932).
1162
+ *
1163
+ * @param {number} [digits=10] - Precision of returned grid reference (eg 4 = km, 10 = m).
1164
+ * @returns {string} This grid reference in standard format.
1165
+ * @throws {RangeError} Invalid precision.
1166
+ *
1167
+ * @example
1168
+ * const mgrsStr = new Mgrs(31, 'U', 'D', 'Q', 48251, 11932).toString(); // 31U DQ 48251 11932
1169
+ */
1170
+ toString(t = 10) {
1171
+ if (![2, 4, 6, 8, 10].includes(Number(t))) throw new RangeError(`invalid precision ‘${t}’`);
1172
+ const { zone: n, band: s, e100k: e, n100k: i, easting: r, northing: a } = this, o = Math.floor(r / Math.pow(10, 5 - t / 2)), f = Math.floor(a / Math.pow(10, 5 - t / 2)), c = n.toString().padStart(2, "0"), u = o.toString().padStart(t / 2, "0"), w = f.toString().padStart(t / 2, "0");
1173
+ return `${c}${s} ${e}${i} ${u} ${w}`;
1174
+ }
1175
+ }
1176
+ class ht extends pt {
1177
+ /**
1178
+ * Converts UTM coordinate to MGRS reference.
1179
+ *
1180
+ * @returns {Mgrs}
1181
+ * @throws {TypeError} Invalid UTM coordinate.
1182
+ *
1183
+ * @example
1184
+ * const utmCoord = new Utm(31, 'N', 448251, 5411932);
1185
+ * const mgrsRef = utmCoord.toMgrs(); // 31U DQ 48251 11932
1186
+ */
1187
+ toMgrs() {
1188
+ const t = this.zone, n = this.toLatLon(), s = rt.charAt(Math.floor(n.lat / 8 + 10)), e = Math.floor(this.easting / 1e5), i = ot[(t - 1) % 3].charAt(e - 1), r = Math.floor(this.northing / 1e5) % 20, a = at[(t - 1) % 2].charAt(r);
1189
+ let o = this.easting % 1e5, f = this.northing % 1e5;
1190
+ return o = Number(o.toFixed(6)), f = Number(f.toFixed(6)), new _(t, s, i, a, o, f);
1191
+ }
1192
+ }
1193
+ class wt extends K {
1194
+ /**
1195
+ * Converts latitude/longitude to UTM coordinate.
1196
+ *
1197
+ * Shadow of LatLon.toUtm, returning Utm augmented with toMgrs() method.
1198
+ *
1199
+ * @param {number} [zoneOverride] - Use specified zone rather than zone within which point lies;
1200
+ * note overriding the UTM zone has the potential to result in negative eastings, and
1201
+ * perverse results within Norway/Svalbard exceptions (this is unlikely to be relevant
1202
+ * for MGRS, but is needed as Mgrs passes through the Utm class).
1203
+ * @returns {Utm} UTM coordinate.
1204
+ * @throws {Error} If point not valid, if point outside latitude range.
1205
+ *
1206
+ * @example
1207
+ * const latlong = new LatLon(48.8582, 2.2945);
1208
+ * const utmCoord = latlong.toUtm(); // 31 N 448252 5411933
1209
+ */
1210
+ toUtm(t = void 0) {
1211
+ const n = super.toUtm(t);
1212
+ return new ht(n.zone, n.hemisphere, n.easting, n.northing, n.datum, n.convergence, n.scale);
1213
+ }
1214
+ }
1215
+ function Nt({
1216
+ coordinate: M,
1217
+ onChange: t
1218
+ }) {
1219
+ const [n, s] = it("LATLON"), [e, i] = it({
1220
+ latLon: {
1221
+ latitude: M[1],
1222
+ longitude: M[0]
1223
+ },
1224
+ utm: "",
1225
+ mgrs: "",
1226
+ dms: ""
1227
+ }), [r, a] = it({
1228
+ latitude: String(M[1]),
1229
+ longitude: String(M[0])
1230
+ });
1231
+ ct(() => (o(M[1], M[0]), () => {
1232
+ }), [M]), ct(() => {
1233
+ const { latitude: d, longitude: p } = e.latLon;
1234
+ return t && (d !== M[1] || p !== M[0]) && t({
1235
+ latitude: d,
1236
+ longitude: p
1237
+ }), () => {
1238
+ };
1239
+ }, [e]);
1240
+ const o = (d, p) => {
1241
+ try {
1242
+ const m = new wt(d, p), y = m.toUtm(), b = y.toMgrs(), S = m.toString("dms");
1243
+ i({
1244
+ latLon: {
1245
+ latitude: m.latitude,
1246
+ longitude: m.longitude
1247
+ },
1248
+ utm: y.toString(),
1249
+ mgrs: b.toString(),
1250
+ dms: S
1251
+ });
1252
+ } catch {
1253
+ }
1254
+ };
1255
+ return {
1256
+ state: {
1257
+ format: n,
1258
+ data: e,
1259
+ latLonStr: r
1260
+ },
1261
+ action: {
1262
+ onChangeFormat: (d) => {
1263
+ s(d.target.value);
1264
+ },
1265
+ onChangeLat: (d) => {
1266
+ let p = d.target.value;
1267
+ p = p.replace(",", "."), a({
1268
+ latitude: p,
1269
+ longitude: r.longitude
1270
+ }), o(Number(p), e.latLon.longitude);
1271
+ },
1272
+ onChangeLon: (d) => {
1273
+ let p = d.target.value;
1274
+ p = p.replace(",", "."), a({
1275
+ latitude: r.latitude,
1276
+ longitude: p
1277
+ }), o(e.latLon.latitude, Number(p));
1278
+ },
1279
+ onChangeDms: (d) => {
1280
+ try {
1281
+ const p = d.target.value.split(","), m = p[0].trim(), y = p[1].trim(), b = h.parse(m), S = h.parse(y);
1282
+ o(b, S);
1283
+ } catch {
1284
+ }
1285
+ },
1286
+ onChangeMgrs: (d) => {
1287
+ try {
1288
+ const m = _.parse(d.target.value).toUtm().toLatLon();
1289
+ o(m.latitude, m.longitude);
1290
+ } catch {
1291
+ }
1292
+ },
1293
+ onChangeUtm: (d) => {
1294
+ try {
1295
+ const m = ht.parse(d.target.value).toLatLon();
1296
+ o(m.latitude, m.longitude);
1297
+ } catch {
1298
+ }
1299
+ }
1300
+ }
1301
+ };
1302
+ }
1303
+ export {
1304
+ Nt as default
1305
+ };