@accelint/geo 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +98 -1
- package/catalog-info.yaml +1 -1
- package/dist/coordinates/latlon/decimal-degrees/formatter.d.ts +35 -2
- package/dist/coordinates/latlon/decimal-degrees/formatter.js +33 -4
- package/dist/coordinates/latlon/decimal-degrees/formatter.js.map +1 -1
- package/dist/coordinates/latlon/decimal-degrees/system.js +5 -3
- package/dist/coordinates/latlon/decimal-degrees/system.js.map +1 -1
- package/dist/coordinates/latlon/degrees-decimal-minutes/formatter.d.ts +42 -2
- package/dist/coordinates/latlon/degrees-decimal-minutes/formatter.js +60 -8
- package/dist/coordinates/latlon/degrees-decimal-minutes/formatter.js.map +1 -1
- package/dist/coordinates/latlon/degrees-decimal-minutes/system.js +7 -6
- package/dist/coordinates/latlon/degrees-decimal-minutes/system.js.map +1 -1
- package/dist/coordinates/latlon/degrees-minutes-seconds/formatter.d.ts +45 -2
- package/dist/coordinates/latlon/degrees-minutes-seconds/formatter.js +66 -12
- package/dist/coordinates/latlon/degrees-minutes-seconds/formatter.js.map +1 -1
- package/dist/coordinates/latlon/degrees-minutes-seconds/system.js +7 -6
- package/dist/coordinates/latlon/degrees-minutes-seconds/system.js.map +1 -1
- package/dist/coordinates/latlon/internal/format.d.ts +50 -5
- package/dist/coordinates/latlon/internal/format.js +39 -9
- package/dist/coordinates/latlon/internal/format.js.map +1 -1
- package/dist/coordinates/latlon/internal/index.d.ts +3 -2
- package/dist/coordinates/latlon/internal/index.js +3 -2
- package/dist/coordinates/latlon/internal/index.js.map +1 -1
- package/dist/coordinates/latlon/internal/lexer.js +2 -1
- package/dist/coordinates/latlon/internal/lexer.js.map +1 -1
- package/dist/coordinates/latlon/internal/ordinal.d.ts +39 -9
- package/dist/coordinates/latlon/internal/ordinal.js +31 -12
- package/dist/coordinates/latlon/internal/ordinal.js.map +1 -1
- package/dist/coordinates/latlon/internal/plain-decimal.d.ts +35 -0
- package/dist/coordinates/latlon/internal/plain-decimal.js +59 -0
- package/dist/coordinates/latlon/internal/plain-decimal.js.map +1 -0
- package/dist/coordinates/latlon/internal/validate.d.ts +28 -1
- package/dist/coordinates/latlon/internal/validate.js +30 -1
- package/dist/coordinates/latlon/internal/validate.js.map +1 -1
- package/dist/coordinates/mgrs/parts.d.ts +86 -0
- package/dist/coordinates/mgrs/parts.js +94 -0
- package/dist/coordinates/mgrs/parts.js.map +1 -0
- package/dist/coordinates/mgrs/system.js +4 -2
- package/dist/coordinates/mgrs/system.js.map +1 -1
- package/dist/coordinates/utm/parts.d.ts +134 -0
- package/dist/coordinates/utm/parts.js +142 -0
- package/dist/coordinates/utm/parts.js.map +1 -0
- package/dist/coordinates/utm/system.js +4 -3
- package/dist/coordinates/utm/system.js.map +1 -1
- package/dist/index.d.ts +10 -7
- package/dist/index.js +10 -7
- package/package.json +6 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ordinal.js","names":[],"sources":["../../../../src/coordinates/latlon/internal/ordinal.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n// __private-exports\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"ordinal.js","names":[],"sources":["../../../../src/coordinates/latlon/internal/ordinal.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n// __private-exports\n\n/**\n * Axis discriminator for a single coordinate value.\n *\n * `'lat'` selects the N/S hemisphere pair; `'lon'` selects E/W.\n */\nexport type Axis = 'lat' | 'lon';\n\n/**\n * Hemisphere letter for a coordinate value, following geo's `>= 0`\n * convention (0 maps to `N` on the lat axis and `E` on the lon axis).\n */\nexport type Hemisphere = 'N' | 'S' | 'E' | 'W';\n\n/**\n * Gets the typed hemisphere letter for a signed coordinate value on an axis.\n *\n * Follows the same `>= 0` convention as {@link getOrdinal}: a value of exactly\n * `0` maps to `N` on the latitude axis and `E` on the longitude axis.\n *\n * @param value - The signed coordinate value.\n * @param axis - Whether the value is a latitude (`'lat'`) or longitude (`'lon'`).\n * @returns Hemisphere letter: `'N'`, `'S'`, `'E'`, or `'W'`.\n *\n * @remarks pure function\n *\n * @example\n * ```typescript\n * getHemisphere(-77.0369, 'lon');\n * // 'W'\n * ```\n */\nexport const getHemisphere = (value: number, axis: Axis): Hemisphere => {\n if (axis === 'lat') {\n return value >= 0 ? 'N' : 'S';\n }\n\n return value >= 0 ? 'E' : 'W';\n};\n\n/**\n * Gets the ordinal direction (N/S/E/W) for a coordinate value.\n *\n * Retained as the established public API. Adapts {@link getHemisphere} — which\n * owns the `>= 0` convention — to a boolean axis and the wider `string` return\n * its existing callers expect.\n *\n * @param value - The coordinate value (positive or negative).\n * @param isLatitude - Whether this is a latitude coordinate (true) or longitude (false).\n * @returns Ordinal direction character: 'N', 'S', 'E', or 'W'.\n *\n * @remarks pure function\n *\n * @example\n * ```typescript\n * getOrdinal(37.7749, true);\n * // 'N'\n * ```\n *\n * @example\n * ```typescript\n * getOrdinal(-122.4194, false);\n * // 'W'\n * ```\n */\nexport const getOrdinal = (value: number, isLatitude: boolean): string =>\n getHemisphere(value, isLatitude ? 'lat' : 'lon');\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CA,MAAa,iBAAiB,OAAe,SAA2B;AACtE,KAAI,SAAS,MACX,QAAO,SAAS,IAAI,MAAM;AAG5B,QAAO,SAAS,IAAI,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4B5B,MAAa,cAAc,OAAe,eACxC,cAAc,OAAO,aAAa,QAAQ,MAAM"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/coordinates/latlon/internal/plain-decimal.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Renders a small number in plain decimal notation instead of exponential.
|
|
4
|
+
*
|
|
5
|
+
* JavaScript's default number-to-string conversion switches to exponential
|
|
6
|
+
* notation below `1e-6` (`String(0.0000001)` is `'1e-7'`), which the
|
|
7
|
+
* coordinate lexer would mis-tokenize (`-7` reads as a sign) and which the
|
|
8
|
+
* round-trip formatters must not emit. Values that already render plainly are
|
|
9
|
+
* returned unchanged, so this is a no-op for ordinary coordinates.
|
|
10
|
+
*
|
|
11
|
+
* Only negative exponents are expanded, to at most 20 fraction digits — enough
|
|
12
|
+
* for any coordinate magnitude. Numbers at or above `1e21` (positive exponent)
|
|
13
|
+
* are returned as JavaScript renders them.
|
|
14
|
+
*
|
|
15
|
+
* @param value - The number to render.
|
|
16
|
+
* @returns The value in plain decimal notation with no trailing zeros.
|
|
17
|
+
*
|
|
18
|
+
* @remarks pure function
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* toPlainDecimalString(0.0000001);
|
|
23
|
+
* // '0.0000001'
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* toPlainDecimalString(-122.4194);
|
|
29
|
+
* // '-122.4194'
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
declare const toPlainDecimalString: (value: number) => string;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { toPlainDecimalString };
|
|
35
|
+
//# sourceMappingURL=plain-decimal.d.ts.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
//#region src/coordinates/latlon/internal/plain-decimal.ts
|
|
15
|
+
/**
|
|
16
|
+
* Fraction digits used to expand an exponential-notation number. Twenty covers
|
|
17
|
+
* every magnitude that is meaningful for a coordinate (`1e-20°` is far below
|
|
18
|
+
* the width of an atom) while staying within `toFixed`'s supported range.
|
|
19
|
+
*/
|
|
20
|
+
const EXPANDED_FRACTION_DIGITS = 20;
|
|
21
|
+
/**
|
|
22
|
+
* Renders a small number in plain decimal notation instead of exponential.
|
|
23
|
+
*
|
|
24
|
+
* JavaScript's default number-to-string conversion switches to exponential
|
|
25
|
+
* notation below `1e-6` (`String(0.0000001)` is `'1e-7'`), which the
|
|
26
|
+
* coordinate lexer would mis-tokenize (`-7` reads as a sign) and which the
|
|
27
|
+
* round-trip formatters must not emit. Values that already render plainly are
|
|
28
|
+
* returned unchanged, so this is a no-op for ordinary coordinates.
|
|
29
|
+
*
|
|
30
|
+
* Only negative exponents are expanded, to at most 20 fraction digits — enough
|
|
31
|
+
* for any coordinate magnitude. Numbers at or above `1e21` (positive exponent)
|
|
32
|
+
* are returned as JavaScript renders them.
|
|
33
|
+
*
|
|
34
|
+
* @param value - The number to render.
|
|
35
|
+
* @returns The value in plain decimal notation with no trailing zeros.
|
|
36
|
+
*
|
|
37
|
+
* @remarks pure function
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* toPlainDecimalString(0.0000001);
|
|
42
|
+
* // '0.0000001'
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* toPlainDecimalString(-122.4194);
|
|
48
|
+
* // '-122.4194'
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
const toPlainDecimalString = (value) => {
|
|
52
|
+
const rendered = `${value}`;
|
|
53
|
+
if (!rendered.includes("e-")) return rendered;
|
|
54
|
+
return value.toFixed(EXPANDED_FRACTION_DIGITS).replace(/\.?0+$/, "");
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
export { toPlainDecimalString };
|
|
59
|
+
//# sourceMappingURL=plain-decimal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plain-decimal.js","names":[],"sources":["../../../../src/coordinates/latlon/internal/plain-decimal.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Fraction digits used to expand an exponential-notation number. Twenty covers\n * every magnitude that is meaningful for a coordinate (`1e-20°` is far below\n * the width of an atom) while staying within `toFixed`'s supported range.\n */\nconst EXPANDED_FRACTION_DIGITS = 20;\n\n/**\n * Renders a small number in plain decimal notation instead of exponential.\n *\n * JavaScript's default number-to-string conversion switches to exponential\n * notation below `1e-6` (`String(0.0000001)` is `'1e-7'`), which the\n * coordinate lexer would mis-tokenize (`-7` reads as a sign) and which the\n * round-trip formatters must not emit. Values that already render plainly are\n * returned unchanged, so this is a no-op for ordinary coordinates.\n *\n * Only negative exponents are expanded, to at most 20 fraction digits — enough\n * for any coordinate magnitude. Numbers at or above `1e21` (positive exponent)\n * are returned as JavaScript renders them.\n *\n * @param value - The number to render.\n * @returns The value in plain decimal notation with no trailing zeros.\n *\n * @remarks pure function\n *\n * @example\n * ```typescript\n * toPlainDecimalString(0.0000001);\n * // '0.0000001'\n * ```\n *\n * @example\n * ```typescript\n * toPlainDecimalString(-122.4194);\n * // '-122.4194'\n * ```\n */\nexport const toPlainDecimalString = (value: number): string => {\n const rendered = `${value}`;\n\n if (!rendered.includes('e-')) {\n return rendered;\n }\n\n return value.toFixed(EXPANDED_FRACTION_DIGITS).replace(/\\.?0+$/, '');\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAiBA,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCjC,MAAa,wBAAwB,UAA0B;CAC7D,MAAM,WAAW,GAAG;AAEpB,KAAI,CAAC,SAAS,SAAS,KAAK,CAC1B,QAAO;AAGT,QAAO,MAAM,QAAQ,yBAAyB,CAAC,QAAQ,UAAU,GAAG"}
|
|
@@ -70,6 +70,33 @@ declare function validateSignedRange(label: string, value: number, limit: number
|
|
|
70
70
|
* ```
|
|
71
71
|
*/
|
|
72
72
|
declare function validateNumericCoordinate(lat: number, lon: number): string[];
|
|
73
|
+
/**
|
|
74
|
+
* Reports whether latitude and longitude are both finite and in range.
|
|
75
|
+
*
|
|
76
|
+
* A boolean-only probe for hot paths that need validity but not the error
|
|
77
|
+
* messages: it short-circuits on the first finite/range failure and allocates
|
|
78
|
+
* nothing, unlike {@link validateNumericCoordinate}, which builds an error
|
|
79
|
+
* array. Use that function when the messages are consumed.
|
|
80
|
+
*
|
|
81
|
+
* @param lat - The latitude value to validate (must be -90 to 90).
|
|
82
|
+
* @param lon - The longitude value to validate (must be -180 to 180).
|
|
83
|
+
* @returns `true` when both values are finite and within range.
|
|
84
|
+
*
|
|
85
|
+
* @remarks pure function
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* isValidNumericCoordinate(45.5, -122.6);
|
|
90
|
+
* // => true
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* isValidNumericCoordinate(91, -122.6);
|
|
96
|
+
* // => false
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
declare function isValidNumericCoordinate(lat: number, lon: number): boolean;
|
|
73
100
|
//#endregion
|
|
74
|
-
export { isFiniteNumber, validateNumericCoordinate, validateSignedRange };
|
|
101
|
+
export { isFiniteNumber, isValidNumericCoordinate, validateNumericCoordinate, validateSignedRange };
|
|
75
102
|
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -99,7 +99,36 @@ function validateNumericCoordinate(lat, lon) {
|
|
|
99
99
|
if (lonError) errors.push(lonError);
|
|
100
100
|
return errors;
|
|
101
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Reports whether latitude and longitude are both finite and in range.
|
|
104
|
+
*
|
|
105
|
+
* A boolean-only probe for hot paths that need validity but not the error
|
|
106
|
+
* messages: it short-circuits on the first finite/range failure and allocates
|
|
107
|
+
* nothing, unlike {@link validateNumericCoordinate}, which builds an error
|
|
108
|
+
* array. Use that function when the messages are consumed.
|
|
109
|
+
*
|
|
110
|
+
* @param lat - The latitude value to validate (must be -90 to 90).
|
|
111
|
+
* @param lon - The longitude value to validate (must be -180 to 180).
|
|
112
|
+
* @returns `true` when both values are finite and within range.
|
|
113
|
+
*
|
|
114
|
+
* @remarks pure function
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* isValidNumericCoordinate(45.5, -122.6);
|
|
119
|
+
* // => true
|
|
120
|
+
* ```
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* isValidNumericCoordinate(91, -122.6);
|
|
125
|
+
* // => false
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
function isValidNumericCoordinate(lat, lon) {
|
|
129
|
+
return isFiniteNumber(lat) && isFiniteNumber(lon) && lat >= -LAT_LIMIT && lat <= LAT_LIMIT && lon >= -LON_LIMIT && lon <= LON_LIMIT;
|
|
130
|
+
}
|
|
102
131
|
|
|
103
132
|
//#endregion
|
|
104
|
-
export { isFiniteNumber, validateNumericCoordinate, validateSignedRange };
|
|
133
|
+
export { isFiniteNumber, isValidNumericCoordinate, validateNumericCoordinate, validateSignedRange };
|
|
105
134
|
//# sourceMappingURL=validate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","names":["errors: string[]"],"sources":["../../../../src/coordinates/latlon/internal/validate.ts"],"sourcesContent":["/*\n * Copyright 2024 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { violation } from './violation';\n\nconst LAT_LIMIT = 90;\nconst LON_LIMIT = 180;\n\n/**\n * Checks if a value is a finite number (not NaN, not Infinity, not -Infinity).\n *\n * @param value - The numeric value to check\n * @returns True if the value is a finite number, false otherwise\n *\n * @example\n * ```typescript\n * isFiniteNumber(42); // true\n * isFiniteNumber(NaN); // false\n * isFiniteNumber(Infinity); // false\n * ```\n */\nexport function isFiniteNumber(value: number): boolean {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\n/**\n * Validates that a value is within a signed range (-limit to +limit).\n *\n * @param label - The label for error messages (used as-is for range errors,\n * lowercased for \"Invalid\" errors)\n * @param value - The numeric value to validate\n * @param limit - The absolute limit (validates -limit to +limit)\n * @returns Error message string if validation fails, undefined if valid\n *\n * @example\n * ```typescript\n * validateSignedRange('Latitude', 45, 90);\n * // => undefined\n * ```\n *\n * @example\n * ```typescript\n * validateSignedRange('Latitude', 95, 90);\n * // => '[ERROR] Latitude value (95) is outside valid range (-90 to 90).'\n * ```\n *\n * @example\n * ```typescript\n * validateSignedRange('Longitude', NaN, 180);\n * // => '[ERROR] Invalid longitude value (NaN); expected a finite number.'\n * ```\n */\nexport function validateSignedRange(\n label: string,\n value: number,\n limit: number,\n): string | undefined {\n if (!isFiniteNumber(value)) {\n return violation(\n `Invalid ${label.toLowerCase()} value (${value}); expected a finite number.`,\n );\n }\n\n if (value < -limit || value > limit) {\n return violation(\n `${label} value (${value}) is outside valid range (-${limit} to ${limit}).`,\n );\n }\n}\n\n/**\n * Validates numeric latitude and longitude coordinate values.\n *\n * @param lat - The latitude value to validate (must be -90 to 90)\n * @param lon - The longitude value to validate (must be -180 to 180)\n * @returns Array of error message strings, empty if all validations pass\n *\n * @example\n * ```typescript\n * validateNumericCoordinate(45.5, -122.6);\n * // => []\n * ```\n *\n * @example\n * ```typescript\n * validateNumericCoordinate(91, -122.6);\n * // => ['[ERROR] Latitude value (91) is outside valid range (-90 to 90).']\n * ```\n *\n * @example\n * ```typescript\n * validateNumericCoordinate(NaN, 200);\n * // => [\n * // '[ERROR] Invalid latitude value (NaN); expected a finite number.',\n * // '[ERROR] Longitude value (200) is outside valid range (-180 to 180).'\n * // ]\n * ```\n */\nexport function validateNumericCoordinate(lat: number, lon: number): string[] {\n const errors: string[] = [];\n\n const latError = validateSignedRange('Latitude', lat, LAT_LIMIT);\n if (latError) {\n errors.push(latError);\n }\n\n const lonError = validateSignedRange('Longitude', lon, LON_LIMIT);\n if (lonError) {\n errors.push(lonError);\n }\n\n return errors;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAcA,MAAM,YAAY;AAClB,MAAM,YAAY;;;;;;;;;;;;;;AAelB,SAAgB,eAAe,OAAwB;AACrD,QAAO,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8B5D,SAAgB,oBACd,OACA,OACA,OACoB;AACpB,KAAI,CAAC,eAAe,MAAM,CACxB,QAAO,UACL,WAAW,MAAM,aAAa,CAAC,UAAU,MAAM,8BAChD;AAGH,KAAI,QAAQ,CAAC,SAAS,QAAQ,MAC5B,QAAO,UACL,GAAG,MAAM,UAAU,MAAM,6BAA6B,MAAM,MAAM,MAAM,IACzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCL,SAAgB,0BAA0B,KAAa,KAAuB;CAC5E,MAAMA,SAAmB,EAAE;CAE3B,MAAM,WAAW,oBAAoB,YAAY,KAAK,UAAU;AAChE,KAAI,SACF,QAAO,KAAK,SAAS;CAGvB,MAAM,WAAW,oBAAoB,aAAa,KAAK,UAAU;AACjE,KAAI,SACF,QAAO,KAAK,SAAS;AAGvB,QAAO"}
|
|
1
|
+
{"version":3,"file":"validate.js","names":["errors: string[]"],"sources":["../../../../src/coordinates/latlon/internal/validate.ts"],"sourcesContent":["/*\n * Copyright 2024 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { violation } from './violation';\n\nconst LAT_LIMIT = 90;\nconst LON_LIMIT = 180;\n\n/**\n * Checks if a value is a finite number (not NaN, not Infinity, not -Infinity).\n *\n * @param value - The numeric value to check\n * @returns True if the value is a finite number, false otherwise\n *\n * @example\n * ```typescript\n * isFiniteNumber(42); // true\n * isFiniteNumber(NaN); // false\n * isFiniteNumber(Infinity); // false\n * ```\n */\nexport function isFiniteNumber(value: number): boolean {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\n/**\n * Validates that a value is within a signed range (-limit to +limit).\n *\n * @param label - The label for error messages (used as-is for range errors,\n * lowercased for \"Invalid\" errors)\n * @param value - The numeric value to validate\n * @param limit - The absolute limit (validates -limit to +limit)\n * @returns Error message string if validation fails, undefined if valid\n *\n * @example\n * ```typescript\n * validateSignedRange('Latitude', 45, 90);\n * // => undefined\n * ```\n *\n * @example\n * ```typescript\n * validateSignedRange('Latitude', 95, 90);\n * // => '[ERROR] Latitude value (95) is outside valid range (-90 to 90).'\n * ```\n *\n * @example\n * ```typescript\n * validateSignedRange('Longitude', NaN, 180);\n * // => '[ERROR] Invalid longitude value (NaN); expected a finite number.'\n * ```\n */\nexport function validateSignedRange(\n label: string,\n value: number,\n limit: number,\n): string | undefined {\n if (!isFiniteNumber(value)) {\n return violation(\n `Invalid ${label.toLowerCase()} value (${value}); expected a finite number.`,\n );\n }\n\n if (value < -limit || value > limit) {\n return violation(\n `${label} value (${value}) is outside valid range (-${limit} to ${limit}).`,\n );\n }\n}\n\n/**\n * Validates numeric latitude and longitude coordinate values.\n *\n * @param lat - The latitude value to validate (must be -90 to 90)\n * @param lon - The longitude value to validate (must be -180 to 180)\n * @returns Array of error message strings, empty if all validations pass\n *\n * @example\n * ```typescript\n * validateNumericCoordinate(45.5, -122.6);\n * // => []\n * ```\n *\n * @example\n * ```typescript\n * validateNumericCoordinate(91, -122.6);\n * // => ['[ERROR] Latitude value (91) is outside valid range (-90 to 90).']\n * ```\n *\n * @example\n * ```typescript\n * validateNumericCoordinate(NaN, 200);\n * // => [\n * // '[ERROR] Invalid latitude value (NaN); expected a finite number.',\n * // '[ERROR] Longitude value (200) is outside valid range (-180 to 180).'\n * // ]\n * ```\n */\nexport function validateNumericCoordinate(lat: number, lon: number): string[] {\n const errors: string[] = [];\n\n const latError = validateSignedRange('Latitude', lat, LAT_LIMIT);\n if (latError) {\n errors.push(latError);\n }\n\n const lonError = validateSignedRange('Longitude', lon, LON_LIMIT);\n if (lonError) {\n errors.push(lonError);\n }\n\n return errors;\n}\n\n/**\n * Reports whether latitude and longitude are both finite and in range.\n *\n * A boolean-only probe for hot paths that need validity but not the error\n * messages: it short-circuits on the first finite/range failure and allocates\n * nothing, unlike {@link validateNumericCoordinate}, which builds an error\n * array. Use that function when the messages are consumed.\n *\n * @param lat - The latitude value to validate (must be -90 to 90).\n * @param lon - The longitude value to validate (must be -180 to 180).\n * @returns `true` when both values are finite and within range.\n *\n * @remarks pure function\n *\n * @example\n * ```typescript\n * isValidNumericCoordinate(45.5, -122.6);\n * // => true\n * ```\n *\n * @example\n * ```typescript\n * isValidNumericCoordinate(91, -122.6);\n * // => false\n * ```\n */\nexport function isValidNumericCoordinate(lat: number, lon: number): boolean {\n return (\n isFiniteNumber(lat) &&\n isFiniteNumber(lon) &&\n lat >= -LAT_LIMIT &&\n lat <= LAT_LIMIT &&\n lon >= -LON_LIMIT &&\n lon <= LON_LIMIT\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAcA,MAAM,YAAY;AAClB,MAAM,YAAY;;;;;;;;;;;;;;AAelB,SAAgB,eAAe,OAAwB;AACrD,QAAO,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8B5D,SAAgB,oBACd,OACA,OACA,OACoB;AACpB,KAAI,CAAC,eAAe,MAAM,CACxB,QAAO,UACL,WAAW,MAAM,aAAa,CAAC,UAAU,MAAM,8BAChD;AAGH,KAAI,QAAQ,CAAC,SAAS,QAAQ,MAC5B,QAAO,UACL,GAAG,MAAM,UAAU,MAAM,6BAA6B,MAAM,MAAM,MAAM,IACzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCL,SAAgB,0BAA0B,KAAa,KAAuB;CAC5E,MAAMA,SAAmB,EAAE;CAE3B,MAAM,WAAW,oBAAoB,YAAY,KAAK,UAAU;AAChE,KAAI,SACF,QAAO,KAAK,SAAS;CAGvB,MAAM,WAAW,oBAAoB,aAAa,KAAK,UAAU;AACjE,KAAI,SACF,QAAO,KAAK,SAAS;AAGvB,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BT,SAAgB,yBAAyB,KAAa,KAAsB;AAC1E,QACE,eAAe,IAAI,IACnB,eAAe,IAAI,IACnB,OAAO,CAAC,aACR,OAAO,aACP,OAAO,CAAC,aACR,OAAO"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { GridPartsResult } from "../utm/parts.js";
|
|
14
|
+
|
|
15
|
+
//#region src/coordinates/mgrs/parts.d.ts
|
|
16
|
+
/**
|
|
17
|
+
* Structured MGRS grid parts for a signed `[lat, lon]` coordinate.
|
|
18
|
+
*
|
|
19
|
+
* `zone`/`band`/`e100k`/`n100k` identify the grid square; `easting`/`northing`
|
|
20
|
+
* are the geodesy within-square metre values (`0`–`99999`) prior to truncation.
|
|
21
|
+
*/
|
|
22
|
+
type MgrsParts = {
|
|
23
|
+
zone: number;
|
|
24
|
+
band: string;
|
|
25
|
+
e100k: string;
|
|
26
|
+
n100k: string;
|
|
27
|
+
easting: number;
|
|
28
|
+
northing: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Converts a signed `[lat, lon]` coordinate into MGRS grid parts.
|
|
32
|
+
*
|
|
33
|
+
* Reads the geodesy `Mgrs` object fields directly instead of parsing a
|
|
34
|
+
* formatted string. The UTM/MGRS grid is defined for `-80 ≤ lat ≤ 84`
|
|
35
|
+
* inclusive; latitudes outside that band, a longitude of exactly `+180°` (the
|
|
36
|
+
* antimeridian zone singularity), or non-finite input, produce
|
|
37
|
+
* `{ ok: false, reason: 'out-of-range' }`.
|
|
38
|
+
*
|
|
39
|
+
* @param coordinate - Signed `[latitude, longitude]` tuple.
|
|
40
|
+
* @returns A discriminated result with `{ zone, band, e100k, n100k, easting, northing }` on success.
|
|
41
|
+
*
|
|
42
|
+
* @remarks pure function
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* toMgrsParts([38.8977, -77.0365]);
|
|
47
|
+
* // { ok: true, value: { zone: 18, band: 'S', e100k: 'U', n100k: 'J', easting: 23394.29…, northing: 7395.63… } }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* toMgrsParts([-81, 0]);
|
|
53
|
+
* // { ok: false, reason: 'out-of-range' }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
declare const toMgrsParts: ([lat, lon]: [number, number]) => GridPartsResult<MgrsParts>;
|
|
57
|
+
/**
|
|
58
|
+
* Renders MGRS grid parts as their canonical coordinate string.
|
|
59
|
+
*
|
|
60
|
+
* Mirrors geodesy's `Mgrs.toString(10)`: floors the within-square metres,
|
|
61
|
+
* left-pads the zone to two digits and easting/northing to five, and joins the
|
|
62
|
+
* zone+band, the `e100k`/`n100k` grid-square pair, and the padded metres with
|
|
63
|
+
* single spaces.
|
|
64
|
+
*
|
|
65
|
+
* @param parts - The MGRS grid parts to render.
|
|
66
|
+
* @returns The canonical MGRS string, e.g. `"18S UJ 23394 07396"`.
|
|
67
|
+
*
|
|
68
|
+
* @remarks pure function
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* formatMgrsParts({ zone: 18, band: 'S', e100k: 'U', n100k: 'J', easting: 23394, northing: 7396 });
|
|
73
|
+
* // '18S UJ 23394 07396'
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
declare const formatMgrsParts: ({
|
|
77
|
+
zone,
|
|
78
|
+
band,
|
|
79
|
+
e100k,
|
|
80
|
+
n100k,
|
|
81
|
+
easting,
|
|
82
|
+
northing
|
|
83
|
+
}: MgrsParts) => string;
|
|
84
|
+
//#endregion
|
|
85
|
+
export { MgrsParts, formatMgrsParts, toMgrsParts };
|
|
86
|
+
//# sourceMappingURL=parts.d.ts.map
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
import { isGridProjectable } from "../utm/parts.js";
|
|
15
|
+
import { LatLon } from "geodesy/mgrs";
|
|
16
|
+
|
|
17
|
+
//#region src/coordinates/mgrs/parts.ts
|
|
18
|
+
/**
|
|
19
|
+
* Converts a signed `[lat, lon]` coordinate into MGRS grid parts.
|
|
20
|
+
*
|
|
21
|
+
* Reads the geodesy `Mgrs` object fields directly instead of parsing a
|
|
22
|
+
* formatted string. The UTM/MGRS grid is defined for `-80 ≤ lat ≤ 84`
|
|
23
|
+
* inclusive; latitudes outside that band, a longitude of exactly `+180°` (the
|
|
24
|
+
* antimeridian zone singularity), or non-finite input, produce
|
|
25
|
+
* `{ ok: false, reason: 'out-of-range' }`.
|
|
26
|
+
*
|
|
27
|
+
* @param coordinate - Signed `[latitude, longitude]` tuple.
|
|
28
|
+
* @returns A discriminated result with `{ zone, band, e100k, n100k, easting, northing }` on success.
|
|
29
|
+
*
|
|
30
|
+
* @remarks pure function
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* toMgrsParts([38.8977, -77.0365]);
|
|
35
|
+
* // { ok: true, value: { zone: 18, band: 'S', e100k: 'U', n100k: 'J', easting: 23394.29…, northing: 7395.63… } }
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* toMgrsParts([-81, 0]);
|
|
41
|
+
* // { ok: false, reason: 'out-of-range' }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
const toMgrsParts = ([lat, lon]) => {
|
|
45
|
+
if (!isGridProjectable([lat, lon])) return {
|
|
46
|
+
ok: false,
|
|
47
|
+
reason: "out-of-range"
|
|
48
|
+
};
|
|
49
|
+
try {
|
|
50
|
+
const mgrs = new LatLon(lat, lon).toUtm().toMgrs();
|
|
51
|
+
return {
|
|
52
|
+
ok: true,
|
|
53
|
+
value: {
|
|
54
|
+
zone: mgrs.zone,
|
|
55
|
+
band: mgrs.band,
|
|
56
|
+
e100k: mgrs.e100k,
|
|
57
|
+
n100k: mgrs.n100k,
|
|
58
|
+
easting: mgrs.easting,
|
|
59
|
+
northing: mgrs.northing
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
} catch {
|
|
63
|
+
return {
|
|
64
|
+
ok: false,
|
|
65
|
+
reason: "out-of-range"
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Renders MGRS grid parts as their canonical coordinate string.
|
|
71
|
+
*
|
|
72
|
+
* Mirrors geodesy's `Mgrs.toString(10)`: floors the within-square metres,
|
|
73
|
+
* left-pads the zone to two digits and easting/northing to five, and joins the
|
|
74
|
+
* zone+band, the `e100k`/`n100k` grid-square pair, and the padded metres with
|
|
75
|
+
* single spaces.
|
|
76
|
+
*
|
|
77
|
+
* @param parts - The MGRS grid parts to render.
|
|
78
|
+
* @returns The canonical MGRS string, e.g. `"18S UJ 23394 07396"`.
|
|
79
|
+
*
|
|
80
|
+
* @remarks pure function
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* formatMgrsParts({ zone: 18, band: 'S', e100k: 'U', n100k: 'J', easting: 23394, northing: 7396 });
|
|
85
|
+
* // '18S UJ 23394 07396'
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
const formatMgrsParts = ({ zone, band, e100k, n100k, easting, northing }) => {
|
|
89
|
+
return `${zone.toString().padStart(2, "0")}${band} ${e100k}${n100k} ${Math.floor(easting).toString().padStart(5, "0")} ${Math.floor(northing).toString().padStart(5, "0")}`;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
//#endregion
|
|
93
|
+
export { formatMgrsParts, toMgrsParts };
|
|
94
|
+
//# sourceMappingURL=parts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parts.js","names":[],"sources":["../../../src/coordinates/mgrs/parts.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { LatLon } from 'geodesy/mgrs';\nimport { type GridPartsResult, isGridProjectable } from '../utm/parts';\n\n/**\n * Structured MGRS grid parts for a signed `[lat, lon]` coordinate.\n *\n * `zone`/`band`/`e100k`/`n100k` identify the grid square; `easting`/`northing`\n * are the geodesy within-square metre values (`0`–`99999`) prior to truncation.\n */\nexport type MgrsParts = {\n zone: number;\n band: string;\n e100k: string;\n n100k: string;\n easting: number;\n northing: number;\n};\n\n/**\n * Converts a signed `[lat, lon]` coordinate into MGRS grid parts.\n *\n * Reads the geodesy `Mgrs` object fields directly instead of parsing a\n * formatted string. The UTM/MGRS grid is defined for `-80 ≤ lat ≤ 84`\n * inclusive; latitudes outside that band, a longitude of exactly `+180°` (the\n * antimeridian zone singularity), or non-finite input, produce\n * `{ ok: false, reason: 'out-of-range' }`.\n *\n * @param coordinate - Signed `[latitude, longitude]` tuple.\n * @returns A discriminated result with `{ zone, band, e100k, n100k, easting, northing }` on success.\n *\n * @remarks pure function\n *\n * @example\n * ```typescript\n * toMgrsParts([38.8977, -77.0365]);\n * // { ok: true, value: { zone: 18, band: 'S', e100k: 'U', n100k: 'J', easting: 23394.29…, northing: 7395.63… } }\n * ```\n *\n * @example\n * ```typescript\n * toMgrsParts([-81, 0]);\n * // { ok: false, reason: 'out-of-range' }\n * ```\n */\nexport const toMgrsParts = ([lat, lon]: [\n number,\n number,\n]): GridPartsResult<MgrsParts> => {\n if (!isGridProjectable([lat, lon])) {\n return { ok: false, reason: 'out-of-range' };\n }\n\n try {\n const mgrs = new LatLon(lat, lon).toUtm().toMgrs();\n\n return {\n ok: true,\n value: {\n zone: mgrs.zone,\n band: mgrs.band,\n e100k: mgrs.e100k,\n n100k: mgrs.n100k,\n easting: mgrs.easting,\n northing: mgrs.northing,\n },\n };\n } catch {\n // geodesy re-verifies UTM bounds when building the MGRS reference; keep\n // the result total rather than leaking a RangeError.\n return { ok: false, reason: 'out-of-range' };\n }\n};\n\n/**\n * Renders MGRS grid parts as their canonical coordinate string.\n *\n * Mirrors geodesy's `Mgrs.toString(10)`: floors the within-square metres,\n * left-pads the zone to two digits and easting/northing to five, and joins the\n * zone+band, the `e100k`/`n100k` grid-square pair, and the padded metres with\n * single spaces.\n *\n * @param parts - The MGRS grid parts to render.\n * @returns The canonical MGRS string, e.g. `\"18S UJ 23394 07396\"`.\n *\n * @remarks pure function\n *\n * @example\n * ```typescript\n * formatMgrsParts({ zone: 18, band: 'S', e100k: 'U', n100k: 'J', easting: 23394, northing: 7396 });\n * // '18S UJ 23394 07396'\n * ```\n */\nexport const formatMgrsParts = ({\n zone,\n band,\n e100k,\n n100k,\n easting,\n northing,\n}: MgrsParts): string => {\n const zonePadded = zone.toString().padStart(2, '0');\n const eastingPadded = Math.floor(easting).toString().padStart(5, '0');\n const northingPadded = Math.floor(northing).toString().padStart(5, '0');\n\n return `${zonePadded}${band} ${e100k}${n100k} ${eastingPadded} ${northingPadded}`;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDA,MAAa,eAAe,CAAC,KAAK,SAGA;AAChC,KAAI,CAAC,kBAAkB,CAAC,KAAK,IAAI,CAAC,CAChC,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAgB;AAG9C,KAAI;EACF,MAAM,OAAO,IAAI,OAAO,KAAK,IAAI,CAAC,OAAO,CAAC,QAAQ;AAElD,SAAO;GACL,IAAI;GACJ,OAAO;IACL,MAAM,KAAK;IACX,MAAM,KAAK;IACX,OAAO,KAAK;IACZ,OAAO,KAAK;IACZ,SAAS,KAAK;IACd,UAAU,KAAK;IAChB;GACF;SACK;AAGN,SAAO;GAAE,IAAI;GAAO,QAAQ;GAAgB;;;;;;;;;;;;;;;;;;;;;;AAuBhD,MAAa,mBAAmB,EAC9B,MACA,MACA,OACA,OACA,SACA,eACuB;AAKvB,QAAO,GAJY,KAAK,UAAU,CAAC,SAAS,GAAG,IAAI,GAI5B,KAAK,GAAG,QAAQ,MAAM,GAHvB,KAAK,MAAM,QAAQ,CAAC,UAAU,CAAC,SAAS,GAAG,IAAI,CAGP,GAFvC,KAAK,MAAM,SAAS,CAAC,UAAU,CAAC,SAAS,GAAG,IAAI"}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import { SYMBOL_PATTERNS } from "../latlon/internal/index.js";
|
|
15
15
|
import { parseMGRS } from "./parser.js";
|
|
16
|
-
import {
|
|
16
|
+
import { formatMgrsParts, toMgrsParts } from "./parts.js";
|
|
17
17
|
|
|
18
18
|
//#region src/coordinates/mgrs/system.ts
|
|
19
19
|
/**
|
|
@@ -55,7 +55,9 @@ const systemMGRS = {
|
|
|
55
55
|
},
|
|
56
56
|
toFormat(format, [left, right]) {
|
|
57
57
|
const { LAT, LON } = Object.fromEntries([[format.slice(0, 3), left], [format.slice(3), right]]);
|
|
58
|
-
|
|
58
|
+
const result = toMgrsParts([LAT, LON]);
|
|
59
|
+
if (!result.ok) throw new RangeError(`Coordinate [${LAT}, ${LON}] cannot be represented in MGRS (outside 80°S–84°N, on the +180° antimeridian, or not finite).`);
|
|
60
|
+
return formatMgrsParts(result.value);
|
|
59
61
|
}
|
|
60
62
|
};
|
|
61
63
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system.js","names":["systemMGRS: CoordinateSystem"],"sources":["../../../src/coordinates/mgrs/system.ts"],"sourcesContent":["// __private-exports\n/*\n * Copyright 2024 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {
|
|
1
|
+
{"version":3,"file":"system.js","names":["systemMGRS: CoordinateSystem"],"sources":["../../../src/coordinates/mgrs/system.ts"],"sourcesContent":["// __private-exports\n/*\n * Copyright 2024 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { type Compass, type Format, SYMBOL_PATTERNS } from '../latlon/internal';\nimport { parseMGRS } from './parser';\nimport { formatMgrsParts, toMgrsParts } from './parts';\nimport type { CoordinateSystem } from '../latlon/internal/coordinate-system';\n\n/**\n * Military Grid Reference System (MGRS) coordinate system implementation.\n *\n * Provides parsing, conversion, and formatting for MGRS coordinates. MGRS is a geocoordinate\n * standard used by NATO militaries for locating points on Earth, based on the UTM coordinate\n * system. Format: Grid Zone Designation + 100km Square ID + Numerical Location (e.g., '31U BF 12345 67890').\n *\n * @property name - Human-readable name: 'Military Grid Reference System'.\n * @property parse - Parses MGRS coordinate strings into latitude/longitude values.\n * @property toFloat - Converts coordinate component with bearing to signed float value.\n * @property toFormat - Formats latitude/longitude pair back to MGRS coordinate string.\n *\n * @example\n * ```typescript\n * systemMGRS.parse(null, '31U BF 12345 67890');\n * // [[['48.123456', 'N'], ['11.234567', 'E']], []]\n * ```\n *\n * @example\n * ```typescript\n * systemMGRS.toFormat('LATLON', [48.123456, 11.234567]);\n * // '31U BF 12345 67890'\n * ```\n *\n * @example\n * ```typescript\n * systemMGRS.toFloat(['48.123456', 'N']);\n * // 48.123456\n * ```\n */\nexport const systemMGRS: CoordinateSystem = {\n name: 'Military Grid Reference System',\n\n parse: parseMGRS,\n\n toFloat(arg) {\n const [num, bear] = arg as [string, Compass];\n\n return (\n Number.parseFloat(num) *\n (SYMBOL_PATTERNS.NEGATIVE_BEARINGS.test(bear) ? -1 : 1)\n );\n },\n\n toFormat(format: Format, [left, right]: [number, number]) {\n const { LAT, LON } = Object.fromEntries([\n [format.slice(0, 3), left],\n [format.slice(3), right],\n ]) as Record<'LAT' | 'LON', number>;\n\n const result = toMgrsParts([LAT, LON]);\n\n if (!result.ok) {\n // The legacy `toFormat` contract throws for coordinates the grid cannot\n // represent; the parts API returns `{ ok: false }` for the same inputs.\n throw new RangeError(\n `Coordinate [${LAT}, ${LON}] cannot be represented in MGRS (outside 80°S–84°N, on the +180° antimeridian, or not finite).`,\n );\n }\n\n return formatMgrsParts(result.value);\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,MAAaA,aAA+B;CAC1C,MAAM;CAEN,OAAO;CAEP,QAAQ,KAAK;EACX,MAAM,CAAC,KAAK,QAAQ;AAEpB,SACE,OAAO,WAAW,IAAI,IACrB,gBAAgB,kBAAkB,KAAK,KAAK,GAAG,KAAK;;CAIzD,SAAS,QAAgB,CAAC,MAAM,QAA0B;EACxD,MAAM,EAAE,KAAK,QAAQ,OAAO,YAAY,CACtC,CAAC,OAAO,MAAM,GAAG,EAAE,EAAE,KAAK,EAC1B,CAAC,OAAO,MAAM,EAAE,EAAE,MAAM,CACzB,CAAC;EAEF,MAAM,SAAS,YAAY,CAAC,KAAK,IAAI,CAAC;AAEtC,MAAI,CAAC,OAAO,GAGV,OAAM,IAAI,WACR,eAAe,IAAI,IAAI,IAAI,gGAC5B;AAGH,SAAO,gBAAgB,OAAO,MAAM;;CAEvC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
//#region src/coordinates/utm/parts.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Lowest latitude (degrees) the UTM/MGRS grid is defined for, inclusive.
|
|
4
|
+
*
|
|
5
|
+
* Matches the patched geodesy valid range; latitudes below this yield an
|
|
6
|
+
* out-of-range result rather than a projected grid reference.
|
|
7
|
+
*/
|
|
8
|
+
declare const GRID_LATITUDE_MIN = -80;
|
|
9
|
+
/**
|
|
10
|
+
* Highest latitude (degrees) the UTM/MGRS grid is defined for, inclusive.
|
|
11
|
+
*
|
|
12
|
+
* Matches the patched geodesy valid range; latitudes above this yield an
|
|
13
|
+
* out-of-range result rather than a projected grid reference.
|
|
14
|
+
*/
|
|
15
|
+
declare const GRID_LATITUDE_MAX = 84;
|
|
16
|
+
/**
|
|
17
|
+
* Discriminated result for a grid-parts conversion.
|
|
18
|
+
*
|
|
19
|
+
* `ok: true` carries the structured grid parts; `ok: false` carries a typed
|
|
20
|
+
* `reason` so consumers branch on a field instead of matching error text.
|
|
21
|
+
*
|
|
22
|
+
* @template Value - The grid parts shape carried on success.
|
|
23
|
+
*/
|
|
24
|
+
type GridPartsResult<Value> = {
|
|
25
|
+
ok: true;
|
|
26
|
+
value: Value;
|
|
27
|
+
} | {
|
|
28
|
+
ok: false;
|
|
29
|
+
reason: 'out-of-range';
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Structured UTM grid parts for a signed `[lat, lon]` coordinate.
|
|
33
|
+
*
|
|
34
|
+
* `easting` and `northing` are the rounded integer metres geodesy yields.
|
|
35
|
+
*/
|
|
36
|
+
type UtmParts = {
|
|
37
|
+
zone: number;
|
|
38
|
+
hemisphere: 'N' | 'S';
|
|
39
|
+
easting: number;
|
|
40
|
+
northing: number;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Reports whether a latitude falls within the inclusive UTM/MGRS grid band.
|
|
44
|
+
*
|
|
45
|
+
* @param lat - The latitude in degrees.
|
|
46
|
+
* @returns `true` when `-80 ≤ lat ≤ 84`.
|
|
47
|
+
*
|
|
48
|
+
* @remarks pure function
|
|
49
|
+
*/
|
|
50
|
+
declare const isWithinGridBand: (lat: number) => boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Reports whether a longitude sits on the eastern antimeridian singularity.
|
|
53
|
+
*
|
|
54
|
+
* At exactly `+180°` the UTM zone formula yields the nonexistent zone `61`,
|
|
55
|
+
* for which geodesy throws. `-180°` and values beyond `±180°` project
|
|
56
|
+
* normally, so only `+180°` is excluded here — the same point is reachable as
|
|
57
|
+
* `-180°`, or via a caller's own longitude normalization.
|
|
58
|
+
*
|
|
59
|
+
* @param lon - The longitude in degrees.
|
|
60
|
+
* @returns `true` when `lon` is exactly `180`.
|
|
61
|
+
*
|
|
62
|
+
* @remarks pure function
|
|
63
|
+
*/
|
|
64
|
+
declare const isOnEasternAntimeridian: (lon: number) => boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Reports whether a signed `[lat, lon]` coordinate can be projected to a UTM
|
|
67
|
+
* zone (and therefore to MGRS).
|
|
68
|
+
*
|
|
69
|
+
* A coordinate is projectable when it is finite and in range, its latitude is
|
|
70
|
+
* within the inclusive `80°S`–`84°N` grid band, and it does not sit on the
|
|
71
|
+
* `+180°` antimeridian singularity. This is the single validity gate shared by
|
|
72
|
+
* {@link toUtmParts} and {@link toMgrsParts}.
|
|
73
|
+
*
|
|
74
|
+
* @param coordinate - Signed `[latitude, longitude]` tuple.
|
|
75
|
+
* @returns `true` when the coordinate projects to a grid reference.
|
|
76
|
+
*
|
|
77
|
+
* @remarks pure function
|
|
78
|
+
*/
|
|
79
|
+
declare const isGridProjectable: ([lat, lon]: [number, number]) => boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Converts a signed `[lat, lon]` coordinate into UTM grid parts.
|
|
82
|
+
*
|
|
83
|
+
* Reads the geodesy `Utm` fields directly and rounds `easting`/`northing` to
|
|
84
|
+
* integer metres (matching the existing UTM string renderer). The UTM/MGRS
|
|
85
|
+
* grid is defined for `-80 ≤ lat ≤ 84` inclusive; latitudes outside that band,
|
|
86
|
+
* a longitude of exactly `+180°` (the antimeridian zone singularity), or
|
|
87
|
+
* non-finite input, produce `{ ok: false, reason: 'out-of-range' }`.
|
|
88
|
+
*
|
|
89
|
+
* @param coordinate - Signed `[latitude, longitude]` tuple.
|
|
90
|
+
* @returns A discriminated result with `{ zone, hemisphere, easting, northing }` on success.
|
|
91
|
+
*
|
|
92
|
+
* @remarks pure function
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* toUtmParts([38.8977, -77.0365]);
|
|
97
|
+
* // { ok: true, value: { zone: 18, hemisphere: 'N', easting: 323394, northing: 4307396 } }
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* toUtmParts([85, 0]);
|
|
103
|
+
* // { ok: false, reason: 'out-of-range' }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
declare const toUtmParts: ([lat, lon]: [number, number]) => GridPartsResult<UtmParts>;
|
|
107
|
+
/**
|
|
108
|
+
* Renders UTM grid parts as their canonical coordinate string.
|
|
109
|
+
*
|
|
110
|
+
* Left-pads the zone to two digits and joins zone+hemisphere, easting, and
|
|
111
|
+
* northing with single spaces, matching geodesy's `Utm.toString()` output.
|
|
112
|
+
* `easting`/`northing` are already the rounded integer metres `toUtmParts`
|
|
113
|
+
* yields, so no further rounding is applied here.
|
|
114
|
+
*
|
|
115
|
+
* @param parts - The UTM grid parts to render.
|
|
116
|
+
* @returns The canonical UTM string, e.g. `"18N 323394 4307396"`.
|
|
117
|
+
*
|
|
118
|
+
* @remarks pure function
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* formatUtmParts({ zone: 18, hemisphere: 'N', easting: 323394, northing: 4307396 });
|
|
123
|
+
* // '18N 323394 4307396'
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
declare const formatUtmParts: ({
|
|
127
|
+
zone,
|
|
128
|
+
hemisphere,
|
|
129
|
+
easting,
|
|
130
|
+
northing
|
|
131
|
+
}: UtmParts) => string;
|
|
132
|
+
//#endregion
|
|
133
|
+
export { GRID_LATITUDE_MAX, GRID_LATITUDE_MIN, GridPartsResult, UtmParts, formatUtmParts, isGridProjectable, isOnEasternAntimeridian, isWithinGridBand, toUtmParts };
|
|
134
|
+
//# sourceMappingURL=parts.d.ts.map
|