@accelint/geo 0.6.0 → 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 +26 -0
- package/README.md +98 -1
- package/catalog-info.yaml +1 -1
- package/dist/cartesian.js +1 -1
- package/dist/coordinates/coordinate.d.ts +1 -1
- package/dist/coordinates/coordinate.js +1 -1
- package/dist/coordinates/latlon/decimal-degrees/formatter.d.ts +36 -3
- package/dist/coordinates/latlon/decimal-degrees/formatter.js +34 -5
- package/dist/coordinates/latlon/decimal-degrees/formatter.js.map +1 -1
- package/dist/coordinates/latlon/decimal-degrees/parser.d.ts +1 -1
- package/dist/coordinates/latlon/decimal-degrees/parser.js +1 -1
- package/dist/coordinates/latlon/decimal-degrees/system.d.ts +1 -1
- package/dist/coordinates/latlon/decimal-degrees/system.js +6 -4
- package/dist/coordinates/latlon/decimal-degrees/system.js.map +1 -1
- package/dist/coordinates/latlon/degrees-decimal-minutes/formatter.d.ts +43 -3
- package/dist/coordinates/latlon/degrees-decimal-minutes/formatter.js +61 -6
- package/dist/coordinates/latlon/degrees-decimal-minutes/formatter.js.map +1 -1
- package/dist/coordinates/latlon/degrees-decimal-minutes/parser.d.ts +1 -1
- package/dist/coordinates/latlon/degrees-decimal-minutes/parser.js +1 -1
- package/dist/coordinates/latlon/degrees-decimal-minutes/system.d.ts +1 -1
- package/dist/coordinates/latlon/degrees-decimal-minutes/system.js +8 -7
- package/dist/coordinates/latlon/degrees-decimal-minutes/system.js.map +1 -1
- package/dist/coordinates/latlon/degrees-minutes-seconds/formatter.d.ts +46 -3
- package/dist/coordinates/latlon/degrees-minutes-seconds/formatter.js +67 -8
- package/dist/coordinates/latlon/degrees-minutes-seconds/formatter.js.map +1 -1
- package/dist/coordinates/latlon/degrees-minutes-seconds/parser.d.ts +1 -1
- package/dist/coordinates/latlon/degrees-minutes-seconds/parser.js +1 -1
- package/dist/coordinates/latlon/degrees-minutes-seconds/system.d.ts +1 -1
- package/dist/coordinates/latlon/degrees-minutes-seconds/system.js +8 -7
- package/dist/coordinates/latlon/degrees-minutes-seconds/system.js.map +1 -1
- package/dist/coordinates/latlon/internal/coordinate-system.d.ts +1 -1
- package/dist/coordinates/latlon/internal/coordinate-system.js +1 -1
- package/dist/coordinates/latlon/internal/create-cache.d.ts +1 -1
- package/dist/coordinates/latlon/internal/create-cache.js +1 -1
- package/dist/coordinates/latlon/internal/exhaustive-errors.js +1 -1
- package/dist/coordinates/latlon/internal/format.d.ts +50 -5
- package/dist/coordinates/latlon/internal/format.js +40 -10
- package/dist/coordinates/latlon/internal/format.js.map +1 -1
- package/dist/coordinates/latlon/internal/in-range.js +1 -1
- package/dist/coordinates/latlon/internal/index.d.ts +4 -3
- package/dist/coordinates/latlon/internal/index.js +4 -3
- package/dist/coordinates/latlon/internal/index.js.map +1 -1
- package/dist/coordinates/latlon/internal/lexer.js +3 -2
- package/dist/coordinates/latlon/internal/lexer.js.map +1 -1
- package/dist/coordinates/latlon/internal/normalize.js +1 -1
- package/dist/coordinates/latlon/internal/ordinal.d.ts +39 -9
- package/dist/coordinates/latlon/internal/ordinal.js +32 -13
- package/dist/coordinates/latlon/internal/ordinal.js.map +1 -1
- package/dist/coordinates/latlon/internal/parse-format.d.ts +1 -1
- package/dist/coordinates/latlon/internal/parse-format.js +1 -1
- package/dist/coordinates/latlon/internal/parse.d.ts +1 -1
- package/dist/coordinates/latlon/internal/parse.js +1 -1
- package/dist/coordinates/latlon/internal/pipes/check-ambiguous.d.ts +1 -1
- package/dist/coordinates/latlon/internal/pipes/check-ambiguous.js +1 -1
- package/dist/coordinates/latlon/internal/pipes/check-numbers.d.ts +1 -1
- package/dist/coordinates/latlon/internal/pipes/check-numbers.js +1 -1
- package/dist/coordinates/latlon/internal/pipes/fix-bearings.d.ts +1 -1
- package/dist/coordinates/latlon/internal/pipes/fix-bearings.js +1 -1
- package/dist/coordinates/latlon/internal/pipes/fix-dividers.d.ts +1 -1
- package/dist/coordinates/latlon/internal/pipes/fix-dividers.js +1 -1
- package/dist/coordinates/latlon/internal/pipes/genome.d.ts +1 -1
- package/dist/coordinates/latlon/internal/pipes/genome.js +1 -1
- package/dist/coordinates/latlon/internal/pipes/index.d.ts +1 -1
- package/dist/coordinates/latlon/internal/pipes/index.js +1 -1
- package/dist/coordinates/latlon/internal/pipes/simpler.d.ts +1 -1
- package/dist/coordinates/latlon/internal/pipes/simpler.js +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 +31 -2
- package/dist/coordinates/latlon/internal/validate.js.map +1 -1
- package/dist/coordinates/latlon/internal/violation.js +1 -1
- package/dist/coordinates/mgrs/parser.d.ts +1 -1
- package/dist/coordinates/mgrs/parser.js +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.d.ts +1 -1
- package/dist/coordinates/mgrs/system.js +5 -3
- package/dist/coordinates/mgrs/system.js.map +1 -1
- package/dist/coordinates/utm/parser.d.ts +1 -1
- package/dist/coordinates/utm/parser.js +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.d.ts +1 -1
- package/dist/coordinates/utm/system.js +5 -4
- package/dist/coordinates/utm/system.js.map +1 -1
- package/dist/index.d.ts +11 -8
- package/dist/index.js +11 -8
- package/dist/patterning.js +1 -1
- package/package.json +4 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import { toPlainDecimalString } from "../internal/plain-decimal.js";
|
|
15
|
+
import { SYMBOL_PATTERNS } from "../internal/index.js";
|
|
16
|
+
import { formatCoordinateSystem } from "../internal/format.js";
|
|
15
17
|
import { parseDegreesDecimalMinutes } from "./parser.js";
|
|
16
18
|
|
|
17
19
|
//#region src/coordinates/latlon/degrees-decimal-minutes/system.ts
|
|
@@ -53,12 +55,11 @@ const systemDegreesDecimalMinutes = {
|
|
|
53
55
|
const [degrees, minutes, bear] = arg;
|
|
54
56
|
return Number.parseFloat(((Number.parseFloat(degrees) + Number.parseFloat(minutes) / 60) * (SYMBOL_PATTERNS.NEGATIVE_BEARINGS.test(bear) ? -1 : 1)).toFixed(9));
|
|
55
57
|
},
|
|
56
|
-
toFormat(format,
|
|
57
|
-
return
|
|
58
|
-
const abs = Math.abs(num);
|
|
58
|
+
toFormat(format, coordinates) {
|
|
59
|
+
return formatCoordinateSystem(format, coordinates, (abs) => {
|
|
59
60
|
const deg = Math.floor(abs);
|
|
60
|
-
return `${deg} ${Number.parseFloat(((abs - deg) * 60).toFixed(10))
|
|
61
|
-
})
|
|
61
|
+
return `${deg} ${toPlainDecimalString(Number.parseFloat(((abs - deg) * 60).toFixed(10)))}`;
|
|
62
|
+
});
|
|
62
63
|
}
|
|
63
64
|
};
|
|
64
65
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system.js","names":["systemDegreesDecimalMinutes: CoordinateSystem"],"sources":["../../../../src/coordinates/latlon/degrees-decimal-minutes/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":["systemDegreesDecimalMinutes: CoordinateSystem"],"sources":["../../../../src/coordinates/latlon/degrees-decimal-minutes/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 '../internal';\nimport { formatCoordinateSystem } from '../internal/format';\nimport { toPlainDecimalString } from '../internal/plain-decimal';\nimport { parseDegreesDecimalMinutes } from './parser';\nimport type { CoordinateSystem } from '../internal/coordinate-system';\n\n/**\n * Degrees Decimal Minutes coordinate system implementation.\n *\n * Provides parsing, conversion, and formatting for coordinates in degrees decimal minutes notation.\n * Coordinates are expressed as integer degrees and decimal minutes (e.g., 37° 46.4940' N).\n *\n * @property name - Human-readable name of the coordinate system.\n * @property parse - Parses degrees decimal minutes coordinate strings.\n * @property toFloat - Converts parsed coordinate components to floating point numbers.\n * @property toFormat - Formats numeric coordinates back to degrees decimal minutes string.\n *\n * @example\n * ```typescript\n * // Parse a coordinate string\n * const [coords, errors] = systemDegreesDecimalMinutes.parse('37° 46.4940' N / 122° 25.1640' W', 'LATLON');\n * ```\n *\n * @example\n * ```typescript\n * // Convert to float\n * const lat = systemDegreesDecimalMinutes.toFloat(['37', '46.4940', 'N']);\n * // 37.7749\n * ```\n *\n * @example\n * ```typescript\n * // Format to string\n * const formatted = systemDegreesDecimalMinutes.toFormat('LATLON', [37.7749, -122.4194]);\n * // '37 46.494 N / 122 25.164 W'\n * ```\n */\nexport const systemDegreesDecimalMinutes: CoordinateSystem = {\n name: 'Degrees Decimal Minutes',\n\n parse: parseDegreesDecimalMinutes,\n\n toFloat(arg) {\n const [degrees, minutes, bear] = arg as [string, string, Compass];\n\n return Number.parseFloat(\n (\n (Number.parseFloat(degrees) + Number.parseFloat(minutes) / 60) *\n (SYMBOL_PATTERNS.NEGATIVE_BEARINGS.test(bear) ? -1 : 1)\n ).toFixed(9),\n );\n },\n\n toFormat(format: Format, coordinates: [number, number]) {\n return formatCoordinateSystem(format, coordinates, (abs) => {\n const deg = Math.floor(abs);\n const min = Number.parseFloat(((abs - deg) * 60).toFixed(10));\n\n return `${deg} ${toPlainDecimalString(min)}`;\n });\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,MAAaA,8BAAgD;CAC3D,MAAM;CAEN,OAAO;CAEP,QAAQ,KAAK;EACX,MAAM,CAAC,SAAS,SAAS,QAAQ;AAEjC,SAAO,OAAO,aAET,OAAO,WAAW,QAAQ,GAAG,OAAO,WAAW,QAAQ,GAAG,OAC1D,gBAAgB,kBAAkB,KAAK,KAAK,GAAG,KAAK,IACrD,QAAQ,EAAE,CACb;;CAGH,SAAS,QAAgB,aAA+B;AACtD,SAAO,uBAAuB,QAAQ,cAAc,QAAQ;GAC1D,MAAM,MAAM,KAAK,MAAM,IAAI;AAG3B,UAAO,GAAG,IAAI,GAAG,qBAFL,OAAO,aAAa,MAAM,OAAO,IAAI,QAAQ,GAAG,CAAC,CAEnB;IAC1C;;CAEL"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -11,9 +11,52 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { FormatOptions } from "../internal/format.js";
|
|
14
|
+
import { Axis, Hemisphere } from "../internal/ordinal.js";
|
|
14
15
|
|
|
15
16
|
//#region src/coordinates/latlon/degrees-minutes-seconds/formatter.d.ts
|
|
16
|
-
|
|
17
|
+
/** Default number of decimal places for degrees-minutes-seconds formatting. */
|
|
18
|
+
declare const DMS_PRECISION = 2;
|
|
19
|
+
/**
|
|
20
|
+
* Structured degrees-minutes-seconds parts for a single signed coordinate value.
|
|
21
|
+
*
|
|
22
|
+
* `degrees`, `minutes`, and `seconds` are non-negative; carry keeps `seconds`
|
|
23
|
+
* and `minutes` below `60`. The signed value is recoverable from the axis and
|
|
24
|
+
* `hemisphere`.
|
|
25
|
+
*/
|
|
26
|
+
type DmsParts = {
|
|
27
|
+
degrees: number;
|
|
28
|
+
minutes: number;
|
|
29
|
+
seconds: number;
|
|
30
|
+
hemisphere: Hemisphere;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Converts a single signed coordinate value into degrees-minutes-seconds parts.
|
|
34
|
+
*
|
|
35
|
+
* Applies the seconds/minutes carry (`60″ → +1′`, `60′ → +1°`) after rounding
|
|
36
|
+
* so `seconds` and `minutes` never reach `60`, then attaches the hemisphere
|
|
37
|
+
* letter for the axis.
|
|
38
|
+
*
|
|
39
|
+
* This is the display path: it rounds to `precision` and carries. The
|
|
40
|
+
* lossless round-trip representation returned by `createCoordinate(...).dms()`
|
|
41
|
+
* lives separately in `degrees-minutes-seconds/system.ts` (`toFormat`, via the
|
|
42
|
+
* shared `formatCoordinateSystem`), which keeps full precision and applies no
|
|
43
|
+
* carry so a value survives format → parse unchanged. The two are
|
|
44
|
+
* intentionally not shared — do not route one through the other.
|
|
45
|
+
*
|
|
46
|
+
* @param value - The signed coordinate value.
|
|
47
|
+
* @param axis - Whether the value is a latitude (`'lat'`) or longitude (`'lon'`).
|
|
48
|
+
* @param precision - Decimal places for the seconds (default `2`).
|
|
49
|
+
* @returns The `{ degrees, minutes, seconds, hemisphere }` parts object.
|
|
50
|
+
*
|
|
51
|
+
* @remarks pure function
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* toDmsParts(-77.0369, 'lon');
|
|
56
|
+
* // { degrees: 77, minutes: 2, seconds: 12.84, hemisphere: 'W' }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
declare const toDmsParts: (value: number, axis: Axis, precision?: number) => DmsParts;
|
|
17
60
|
/**
|
|
18
61
|
* Formats latitude/longitude coordinates in degrees minutes seconds notation.
|
|
19
62
|
*
|
|
@@ -35,5 +78,5 @@ import { FormatOptions } from "../internal/format.js";
|
|
|
35
78
|
*/
|
|
36
79
|
declare const formatDegreesMinutesSeconds: (coordinates: [number, number], config?: FormatOptions) => string;
|
|
37
80
|
//#endregion
|
|
38
|
-
export { formatDegreesMinutesSeconds };
|
|
81
|
+
export { DMS_PRECISION, DmsParts, formatDegreesMinutesSeconds, toDmsParts };
|
|
39
82
|
//# sourceMappingURL=formatter.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -11,13 +11,74 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
import { getHemisphere } from "../internal/ordinal.js";
|
|
14
15
|
import { createFormatter } from "../internal/format.js";
|
|
15
16
|
|
|
16
17
|
//#region src/coordinates/latlon/degrees-minutes-seconds/formatter.ts
|
|
18
|
+
/** Default number of decimal places for degrees-minutes-seconds formatting. */
|
|
19
|
+
const DMS_PRECISION = 2;
|
|
20
|
+
/**
|
|
21
|
+
* Splits a non-negative magnitude into whole degrees, whole minutes, and
|
|
22
|
+
* decimal seconds, rounding the seconds to `precision` and carrying
|
|
23
|
+
* `60″ → +1′ → +1°` so the output stays a valid coordinate. Shared core of
|
|
24
|
+
* {@link toDmsParts} and the display string formatter.
|
|
25
|
+
*
|
|
26
|
+
* @param magnitude - Non-negative coordinate magnitude in degrees.
|
|
27
|
+
* @param precision - Decimal places for the seconds.
|
|
28
|
+
* @returns The `{ degrees, minutes, seconds }` triple.
|
|
29
|
+
*
|
|
30
|
+
* @remarks pure function
|
|
31
|
+
*/
|
|
32
|
+
const toDmsMagnitude = (magnitude, precision) => {
|
|
33
|
+
let degrees = Math.floor(magnitude);
|
|
34
|
+
const minutesFull = (magnitude - degrees) * 60;
|
|
35
|
+
let minutes = Math.floor(minutesFull);
|
|
36
|
+
let seconds = Number(((minutesFull - minutes) * 60).toFixed(precision));
|
|
37
|
+
minutes += Math.floor(seconds / 60);
|
|
38
|
+
seconds %= 60;
|
|
39
|
+
degrees += Math.floor(minutes / 60);
|
|
40
|
+
minutes %= 60;
|
|
41
|
+
return {
|
|
42
|
+
degrees,
|
|
43
|
+
minutes,
|
|
44
|
+
seconds
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Converts a single signed coordinate value into degrees-minutes-seconds parts.
|
|
49
|
+
*
|
|
50
|
+
* Applies the seconds/minutes carry (`60″ → +1′`, `60′ → +1°`) after rounding
|
|
51
|
+
* so `seconds` and `minutes` never reach `60`, then attaches the hemisphere
|
|
52
|
+
* letter for the axis.
|
|
53
|
+
*
|
|
54
|
+
* This is the display path: it rounds to `precision` and carries. The
|
|
55
|
+
* lossless round-trip representation returned by `createCoordinate(...).dms()`
|
|
56
|
+
* lives separately in `degrees-minutes-seconds/system.ts` (`toFormat`, via the
|
|
57
|
+
* shared `formatCoordinateSystem`), which keeps full precision and applies no
|
|
58
|
+
* carry so a value survives format → parse unchanged. The two are
|
|
59
|
+
* intentionally not shared — do not route one through the other.
|
|
60
|
+
*
|
|
61
|
+
* @param value - The signed coordinate value.
|
|
62
|
+
* @param axis - Whether the value is a latitude (`'lat'`) or longitude (`'lon'`).
|
|
63
|
+
* @param precision - Decimal places for the seconds (default `2`).
|
|
64
|
+
* @returns The `{ degrees, minutes, seconds, hemisphere }` parts object.
|
|
65
|
+
*
|
|
66
|
+
* @remarks pure function
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* toDmsParts(-77.0369, 'lon');
|
|
71
|
+
* // { degrees: 77, minutes: 2, seconds: 12.84, hemisphere: 'W' }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
const toDmsParts = (value, axis, precision = DMS_PRECISION) => ({
|
|
75
|
+
...toDmsMagnitude(Math.abs(value), precision),
|
|
76
|
+
hemisphere: getHemisphere(value, axis)
|
|
77
|
+
});
|
|
17
78
|
/**
|
|
18
79
|
* Converts a coordinate value to degrees minutes seconds format.
|
|
19
80
|
*
|
|
20
|
-
* @param
|
|
81
|
+
* @param value - The coordinate value to format.
|
|
21
82
|
* @returns Formatted coordinate string with degrees, minutes, and seconds (e.g., "45° 30' 15.23″").
|
|
22
83
|
*
|
|
23
84
|
* @example
|
|
@@ -32,11 +93,9 @@ import { createFormatter } from "../internal/format.js";
|
|
|
32
93
|
* // '122° 25' 9.84″'
|
|
33
94
|
* ```
|
|
34
95
|
*/
|
|
35
|
-
const toDegreesMinutesSeconds = (
|
|
36
|
-
const degrees =
|
|
37
|
-
|
|
38
|
-
const minutes = Math.floor(minutesFull);
|
|
39
|
-
return `${degrees}° ${minutes}' ${((minutesFull - minutes) * 60).toFixed(2)}″`;
|
|
96
|
+
const toDegreesMinutesSeconds = (value) => {
|
|
97
|
+
const { degrees, minutes, seconds } = toDmsMagnitude(Math.abs(value), DMS_PRECISION);
|
|
98
|
+
return `${degrees}° ${minutes}' ${seconds.toFixed(DMS_PRECISION)}″`;
|
|
40
99
|
};
|
|
41
100
|
/**
|
|
42
101
|
* Formats latitude/longitude coordinates in degrees minutes seconds notation.
|
|
@@ -60,5 +119,5 @@ const toDegreesMinutesSeconds = (num) => {
|
|
|
60
119
|
const formatDegreesMinutesSeconds = createFormatter(toDegreesMinutesSeconds);
|
|
61
120
|
|
|
62
121
|
//#endregion
|
|
63
|
-
export { formatDegreesMinutesSeconds };
|
|
122
|
+
export { DMS_PRECISION, formatDegreesMinutesSeconds, toDmsParts };
|
|
64
123
|
//# sourceMappingURL=formatter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatter.js","names":[],"sources":["../../../../src/coordinates/latlon/degrees-minutes-seconds/formatter.ts"],"sourcesContent":["/*\n * Copyright
|
|
1
|
+
{"version":3,"file":"formatter.js","names":[],"sources":["../../../../src/coordinates/latlon/degrees-minutes-seconds/formatter.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 { createFormatter } from '../internal/format';\nimport { type Axis, getHemisphere, type Hemisphere } from '../internal/ordinal';\n\n/** Default number of decimal places for degrees-minutes-seconds formatting. */\nexport const DMS_PRECISION = 2;\n\n/**\n * Structured degrees-minutes-seconds parts for a single signed coordinate value.\n *\n * `degrees`, `minutes`, and `seconds` are non-negative; carry keeps `seconds`\n * and `minutes` below `60`. The signed value is recoverable from the axis and\n * `hemisphere`.\n */\nexport type DmsParts = {\n degrees: number;\n minutes: number;\n seconds: number;\n hemisphere: Hemisphere;\n};\n\n/**\n * Splits a non-negative magnitude into whole degrees, whole minutes, and\n * decimal seconds, rounding the seconds to `precision` and carrying\n * `60″ → +1′ → +1°` so the output stays a valid coordinate. Shared core of\n * {@link toDmsParts} and the display string formatter.\n *\n * @param magnitude - Non-negative coordinate magnitude in degrees.\n * @param precision - Decimal places for the seconds.\n * @returns The `{ degrees, minutes, seconds }` triple.\n *\n * @remarks pure function\n */\nconst toDmsMagnitude = (\n magnitude: number,\n precision: number,\n): Pick<DmsParts, 'degrees' | 'minutes' | 'seconds'> => {\n let degrees = Math.floor(magnitude);\n const minutesFull = (magnitude - degrees) * 60;\n let minutes = Math.floor(minutesFull);\n let seconds = Number(((minutesFull - minutes) * 60).toFixed(precision));\n\n // Rounding can produce 60 seconds (e.g. 40.9999999 -> 40° 59' 60.00″);\n // carry into minutes (and degrees) so the output stays a valid coordinate.\n minutes += Math.floor(seconds / 60);\n seconds %= 60;\n degrees += Math.floor(minutes / 60);\n minutes %= 60;\n\n return { degrees, minutes, seconds };\n};\n\n/**\n * Converts a single signed coordinate value into degrees-minutes-seconds parts.\n *\n * Applies the seconds/minutes carry (`60″ → +1′`, `60′ → +1°`) after rounding\n * so `seconds` and `minutes` never reach `60`, then attaches the hemisphere\n * letter for the axis.\n *\n * This is the display path: it rounds to `precision` and carries. The\n * lossless round-trip representation returned by `createCoordinate(...).dms()`\n * lives separately in `degrees-minutes-seconds/system.ts` (`toFormat`, via the\n * shared `formatCoordinateSystem`), which keeps full precision and applies no\n * carry so a value survives format → parse unchanged. The two are\n * intentionally not shared — do not route one through the other.\n *\n * @param value - The signed coordinate value.\n * @param axis - Whether the value is a latitude (`'lat'`) or longitude (`'lon'`).\n * @param precision - Decimal places for the seconds (default `2`).\n * @returns The `{ degrees, minutes, seconds, hemisphere }` parts object.\n *\n * @remarks pure function\n *\n * @example\n * ```typescript\n * toDmsParts(-77.0369, 'lon');\n * // { degrees: 77, minutes: 2, seconds: 12.84, hemisphere: 'W' }\n * ```\n */\nexport const toDmsParts = (\n value: number,\n axis: Axis,\n precision: number = DMS_PRECISION,\n): DmsParts => ({\n ...toDmsMagnitude(Math.abs(value), precision),\n hemisphere: getHemisphere(value, axis),\n});\n\n/**\n * Converts a coordinate value to degrees minutes seconds format.\n *\n * @param value - The coordinate value to format.\n * @returns Formatted coordinate string with degrees, minutes, and seconds (e.g., \"45° 30' 15.23″\").\n *\n * @example\n * ```typescript\n * toDegreesMinutesSeconds(45.5042);\n * // '45° 30' 15.12″'\n * ```\n *\n * @example\n * ```typescript\n * toDegreesMinutesSeconds(-122.4194);\n * // '122° 25' 9.84″'\n * ```\n */\nconst toDegreesMinutesSeconds = (value: number): string => {\n const { degrees, minutes, seconds } = toDmsMagnitude(\n Math.abs(value),\n DMS_PRECISION,\n );\n\n return `${degrees}° ${minutes}' ${seconds.toFixed(DMS_PRECISION)}″`;\n};\n\n/**\n * Formats latitude/longitude coordinates in degrees minutes seconds notation.\n *\n * @param coordinates - Tuple of [latitude, longitude] values.\n * @param config - Optional formatting configuration.\n * @returns Formatted coordinate string in degrees minutes seconds format.\n *\n * @example\n * ```typescript\n * formatDegreesMinutesSeconds([37.7749, -122.4194]);\n * // '37° 46' 29.64″ N, 122° 25' 9.84″ W'\n * ```\n *\n * @example\n * ```typescript\n * formatDegreesMinutesSeconds([37.7749, -122.4194], { separator: ' / ' });\n * // '37° 46' 29.64″ N / 122° 25' 9.84″ W'\n * ```\n */\nexport const formatDegreesMinutesSeconds = createFormatter(\n toDegreesMinutesSeconds,\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;AAgBA,MAAa,gBAAgB;;;;;;;;;;;;;AA4B7B,MAAM,kBACJ,WACA,cACsD;CACtD,IAAI,UAAU,KAAK,MAAM,UAAU;CACnC,MAAM,eAAe,YAAY,WAAW;CAC5C,IAAI,UAAU,KAAK,MAAM,YAAY;CACrC,IAAI,UAAU,SAAS,cAAc,WAAW,IAAI,QAAQ,UAAU,CAAC;AAIvE,YAAW,KAAK,MAAM,UAAU,GAAG;AACnC,YAAW;AACX,YAAW,KAAK,MAAM,UAAU,GAAG;AACnC,YAAW;AAEX,QAAO;EAAE;EAAS;EAAS;EAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BtC,MAAa,cACX,OACA,MACA,YAAoB,mBACN;CACd,GAAG,eAAe,KAAK,IAAI,MAAM,EAAE,UAAU;CAC7C,YAAY,cAAc,OAAO,KAAK;CACvC;;;;;;;;;;;;;;;;;;;AAoBD,MAAM,2BAA2B,UAA0B;CACzD,MAAM,EAAE,SAAS,SAAS,YAAY,eACpC,KAAK,IAAI,MAAM,EACf,cACD;AAED,QAAO,GAAG,QAAQ,IAAI,QAAQ,IAAI,QAAQ,QAAQ,cAAc,CAAC;;;;;;;;;;;;;;;;;;;;;AAsBnE,MAAa,8BAA8B,gBACzC,wBACD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import { toPlainDecimalString } from "../internal/plain-decimal.js";
|
|
15
|
+
import { SYMBOL_PATTERNS } from "../internal/index.js";
|
|
16
|
+
import { formatCoordinateSystem } from "../internal/format.js";
|
|
15
17
|
import { parseDegreesMinutesSeconds } from "./parser.js";
|
|
16
18
|
|
|
17
19
|
//#region src/coordinates/latlon/degrees-minutes-seconds/system.ts
|
|
@@ -53,14 +55,13 @@ const systemDegreesMinutesSeconds = {
|
|
|
53
55
|
const [degrees, minutes, seconds, bear] = arg;
|
|
54
56
|
return Number.parseFloat(((Number.parseFloat(degrees) + Number.parseFloat(minutes) / 60 + Number.parseFloat(seconds) / 3600) * (SYMBOL_PATTERNS.NEGATIVE_BEARINGS.test(bear) ? -1 : 1)).toFixed(9));
|
|
55
57
|
},
|
|
56
|
-
toFormat(format,
|
|
57
|
-
return
|
|
58
|
-
const abs = Math.abs(num);
|
|
58
|
+
toFormat(format, coordinates) {
|
|
59
|
+
return formatCoordinateSystem(format, coordinates, (abs) => {
|
|
59
60
|
const deg = Math.floor(abs);
|
|
60
61
|
const rem = (abs - deg) * 60;
|
|
61
62
|
const min = Math.floor(rem);
|
|
62
|
-
return `${deg} ${min} ${Number.parseFloat(((rem - min) * 60).toFixed(10))
|
|
63
|
-
})
|
|
63
|
+
return `${deg} ${min} ${toPlainDecimalString(Number.parseFloat(((rem - min) * 60).toFixed(10)))}`;
|
|
64
|
+
});
|
|
64
65
|
}
|
|
65
66
|
};
|
|
66
67
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system.js","names":["systemDegreesMinutesSeconds: CoordinateSystem"],"sources":["../../../../src/coordinates/latlon/degrees-minutes-seconds/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":["systemDegreesMinutesSeconds: CoordinateSystem"],"sources":["../../../../src/coordinates/latlon/degrees-minutes-seconds/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 '../internal';\nimport { formatCoordinateSystem } from '../internal/format';\nimport { toPlainDecimalString } from '../internal/plain-decimal';\nimport { parseDegreesMinutesSeconds } from './parser';\nimport type { CoordinateSystem } from '../internal/coordinate-system';\n\n/**\n * Degrees Minutes Seconds coordinate system implementation.\n *\n * Provides parsing, conversion, and formatting for coordinates in degrees minutes seconds notation.\n * Coordinates are expressed as integer degrees, integer minutes, and decimal seconds (e.g., 37° 46' 29.64″ N).\n *\n * @property name - Human-readable name of the coordinate system.\n * @property parse - Parses degrees minutes seconds coordinate strings.\n * @property toFloat - Converts parsed coordinate components to floating point numbers.\n * @property toFormat - Formats numeric coordinates back to degrees minutes seconds string.\n *\n * @example\n * ```typescript\n * // Parse a coordinate string\n * const [coords, errors] = systemDegreesMinutesSeconds.parse('37° 46' 29.64″ N / 122° 25' 9.84″ W', 'LATLON');\n * ```\n *\n * @example\n * ```typescript\n * // Convert to float\n * const lat = systemDegreesMinutesSeconds.toFloat(['37', '46', '29.64', 'N']);\n * // 37.7749\n * ```\n *\n * @example\n * ```typescript\n * // Format to string\n * const formatted = systemDegreesMinutesSeconds.toFormat('LATLON', [37.7749, -122.4194]);\n * // '37 46 29.64 N / 122 25 9.84 W'\n * ```\n */\nexport const systemDegreesMinutesSeconds: CoordinateSystem = {\n name: 'Degrees Minutes Seconds',\n\n parse: parseDegreesMinutesSeconds,\n\n toFloat(arg) {\n const [degrees, minutes, seconds, bear] = arg as [\n string,\n string,\n string,\n Compass,\n ];\n\n return Number.parseFloat(\n (\n (Number.parseFloat(degrees) +\n Number.parseFloat(minutes) / 60 +\n Number.parseFloat(seconds) / 3600) *\n (SYMBOL_PATTERNS.NEGATIVE_BEARINGS.test(bear) ? -1 : 1)\n ).toFixed(9),\n );\n },\n\n toFormat(format: Format, coordinates: [number, number]) {\n return formatCoordinateSystem(format, coordinates, (abs) => {\n const deg = Math.floor(abs);\n const rem = (abs - deg) * 60;\n const min = Math.floor(rem);\n const sec = Number.parseFloat(((rem - min) * 60).toFixed(10));\n\n return `${deg} ${min} ${toPlainDecimalString(sec)}`;\n });\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,MAAaA,8BAAgD;CAC3D,MAAM;CAEN,OAAO;CAEP,QAAQ,KAAK;EACX,MAAM,CAAC,SAAS,SAAS,SAAS,QAAQ;AAO1C,SAAO,OAAO,aAET,OAAO,WAAW,QAAQ,GACzB,OAAO,WAAW,QAAQ,GAAG,KAC7B,OAAO,WAAW,QAAQ,GAAG,SAC9B,gBAAgB,kBAAkB,KAAK,KAAK,GAAG,KAAK,IACrD,QAAQ,EAAE,CACb;;CAGH,SAAS,QAAgB,aAA+B;AACtD,SAAO,uBAAuB,QAAQ,cAAc,QAAQ;GAC1D,MAAM,MAAM,KAAK,MAAM,IAAI;GAC3B,MAAM,OAAO,MAAM,OAAO;GAC1B,MAAM,MAAM,KAAK,MAAM,IAAI;AAG3B,UAAO,GAAG,IAAI,GAAG,IAAI,GAAG,qBAFZ,OAAO,aAAa,MAAM,OAAO,IAAI,QAAQ,GAAG,CAAC,CAEZ;IACjD;;CAEL"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -1,10 +1,53 @@
|
|
|
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 { Format } from "./index.js";
|
|
14
|
+
|
|
1
15
|
//#region src/coordinates/latlon/internal/format.d.ts
|
|
2
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Display options for the `format*` coordinate formatters: text wrapped around
|
|
18
|
+
* the whole string, the divider between axes, and whether each axis carries
|
|
19
|
+
* its `N`/`S`/`E`/`W` letter.
|
|
20
|
+
*/
|
|
21
|
+
type FormatOptions = {
|
|
3
22
|
prefix: string;
|
|
4
23
|
suffix: string;
|
|
5
24
|
separator: string;
|
|
6
25
|
withOrdinal?: boolean;
|
|
7
|
-
}
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Shared scaffold for a `CoordinateSystem`'s `toFormat` round-trip string.
|
|
29
|
+
*
|
|
30
|
+
* This is the loss-less internal representation `createCoordinate(...).dd()` /
|
|
31
|
+
* `.ddm()` / `.dms()` returns — deliberately distinct from the display
|
|
32
|
+
* formatters in each system's `formatter.ts`. The `to*Parts` / `format*`
|
|
33
|
+
* functions round and carry to a fixed precision for human display; this path
|
|
34
|
+
* keeps full precision and applies **no** carry so a value survives a
|
|
35
|
+
* format → parse → float round-trip unchanged. The two must not be merged.
|
|
36
|
+
*
|
|
37
|
+
* Owns the parts every system's `toFormat` shares — the `[lat, lon]` map, the
|
|
38
|
+
* ` / ` divider join, and the signed → `N`/`S`/`E`/`W` direction lookup — and
|
|
39
|
+
* defers only the per-axis magnitude rendering (which is all that differs
|
|
40
|
+
* between DD, DDM, and DMS) to `renderMagnitude`.
|
|
41
|
+
*
|
|
42
|
+
* @param format - Axis ordering (`'LATLON'` or `'LONLAT'`).
|
|
43
|
+
* @param coordinates - Signed `[left, right]` values in the given ordering.
|
|
44
|
+
* @param renderMagnitude - Renders the space-separated magnitude components of
|
|
45
|
+
* one axis (e.g. `"37 46.494"` for DDM) from its absolute value.
|
|
46
|
+
* @returns The joined round-trip string, e.g. `"37 46.494 N / 122 25.164 W"`.
|
|
47
|
+
*
|
|
48
|
+
* @remarks pure function
|
|
49
|
+
*/
|
|
50
|
+
declare const formatCoordinateSystem: (format: Format, [left, right]: [number, number], renderMagnitude: (magnitude: number) => string) => string;
|
|
8
51
|
/**
|
|
9
52
|
* Creates a coordinate formatter function from a coordinate conversion function.
|
|
10
53
|
*
|
|
@@ -13,8 +56,10 @@ interface FormatOptions {
|
|
|
13
56
|
*
|
|
14
57
|
* @example
|
|
15
58
|
* ```typescript
|
|
16
|
-
* const formatDD = createFormatter(
|
|
17
|
-
*
|
|
59
|
+
* const formatDD = createFormatter(
|
|
60
|
+
* (value, withOrdinal) => `${(withOrdinal ? Math.abs(value) : value).toFixed(6)}°`,
|
|
61
|
+
* );
|
|
62
|
+
* formatDD([37.7749, -122.4194], { withOrdinal: true });
|
|
18
63
|
* // '37.774900° N, 122.419400° W'
|
|
19
64
|
* ```
|
|
20
65
|
*
|
|
@@ -27,5 +72,5 @@ interface FormatOptions {
|
|
|
27
72
|
*/
|
|
28
73
|
declare const createFormatter: (fn: (coord: number, withOrdinal?: boolean) => string) => (coordinates: [number, number], config?: FormatOptions) => string;
|
|
29
74
|
//#endregion
|
|
30
|
-
export { FormatOptions, createFormatter };
|
|
75
|
+
export { FormatOptions, createFormatter, formatCoordinateSystem };
|
|
31
76
|
//# sourceMappingURL=format.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -11,10 +11,38 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import { BEARINGS, SYMBOLS } from "./index.js";
|
|
15
|
+
import { getHemisphere } from "./ordinal.js";
|
|
15
16
|
|
|
16
17
|
//#region src/coordinates/latlon/internal/format.ts
|
|
17
18
|
/**
|
|
19
|
+
* Shared scaffold for a `CoordinateSystem`'s `toFormat` round-trip string.
|
|
20
|
+
*
|
|
21
|
+
* This is the loss-less internal representation `createCoordinate(...).dd()` /
|
|
22
|
+
* `.ddm()` / `.dms()` returns — deliberately distinct from the display
|
|
23
|
+
* formatters in each system's `formatter.ts`. The `to*Parts` / `format*`
|
|
24
|
+
* functions round and carry to a fixed precision for human display; this path
|
|
25
|
+
* keeps full precision and applies **no** carry so a value survives a
|
|
26
|
+
* format → parse → float round-trip unchanged. The two must not be merged.
|
|
27
|
+
*
|
|
28
|
+
* Owns the parts every system's `toFormat` shares — the `[lat, lon]` map, the
|
|
29
|
+
* ` / ` divider join, and the signed → `N`/`S`/`E`/`W` direction lookup — and
|
|
30
|
+
* defers only the per-axis magnitude rendering (which is all that differs
|
|
31
|
+
* between DD, DDM, and DMS) to `renderMagnitude`.
|
|
32
|
+
*
|
|
33
|
+
* @param format - Axis ordering (`'LATLON'` or `'LONLAT'`).
|
|
34
|
+
* @param coordinates - Signed `[left, right]` values in the given ordering.
|
|
35
|
+
* @param renderMagnitude - Renders the space-separated magnitude components of
|
|
36
|
+
* one axis (e.g. `"37 46.494"` for DDM) from its absolute value.
|
|
37
|
+
* @returns The joined round-trip string, e.g. `"37 46.494 N / 122 25.164 W"`.
|
|
38
|
+
*
|
|
39
|
+
* @remarks pure function
|
|
40
|
+
*/
|
|
41
|
+
const formatCoordinateSystem = (format, [left, right], renderMagnitude) => [left, right].map((value, index) => {
|
|
42
|
+
const direction = BEARINGS[format][index][+(value < 0)];
|
|
43
|
+
return `${renderMagnitude(Math.abs(value))} ${direction}`;
|
|
44
|
+
}).join(` ${SYMBOLS.DIVIDER} `);
|
|
45
|
+
/**
|
|
18
46
|
* Creates a coordinate formatter function from a coordinate conversion function.
|
|
19
47
|
*
|
|
20
48
|
* @param fn - Function that converts a single coordinate value to a formatted string.
|
|
@@ -22,8 +50,10 @@ import { getOrdinal } from "./ordinal.js";
|
|
|
22
50
|
*
|
|
23
51
|
* @example
|
|
24
52
|
* ```typescript
|
|
25
|
-
* const formatDD = createFormatter(
|
|
26
|
-
*
|
|
53
|
+
* const formatDD = createFormatter(
|
|
54
|
+
* (value, withOrdinal) => `${(withOrdinal ? Math.abs(value) : value).toFixed(6)}°`,
|
|
55
|
+
* );
|
|
56
|
+
* formatDD([37.7749, -122.4194], { withOrdinal: true });
|
|
27
57
|
* // '37.774900° N, 122.419400° W'
|
|
28
58
|
* ```
|
|
29
59
|
*
|
|
@@ -36,15 +66,15 @@ import { getOrdinal } from "./ordinal.js";
|
|
|
36
66
|
*/
|
|
37
67
|
const createFormatter = (fn) => (coordinates, config) => {
|
|
38
68
|
const [latitude, longitude] = coordinates;
|
|
39
|
-
const latOrdinal =
|
|
40
|
-
const lonOrdinal =
|
|
41
|
-
const
|
|
42
|
-
const
|
|
69
|
+
const latOrdinal = config?.withOrdinal ? ` ${getHemisphere(latitude, "lat")}` : "";
|
|
70
|
+
const lonOrdinal = config?.withOrdinal ? ` ${getHemisphere(longitude, "lon")}` : "";
|
|
71
|
+
const latValue = fn(latitude, config?.withOrdinal);
|
|
72
|
+
const lonValue = fn(longitude, config?.withOrdinal);
|
|
43
73
|
const prefix = config?.prefix ?? "";
|
|
44
74
|
const suffix = config?.suffix ?? "";
|
|
45
|
-
return `${prefix}${
|
|
75
|
+
return `${prefix}${latValue}${latOrdinal}${config?.separator ?? ", "}${lonValue}${lonOrdinal}${suffix}`;
|
|
46
76
|
};
|
|
47
77
|
|
|
48
78
|
//#endregion
|
|
49
|
-
export { createFormatter };
|
|
79
|
+
export { createFormatter, formatCoordinateSystem };
|
|
50
80
|
//# sourceMappingURL=format.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","names":[],"sources":["../../../../src/coordinates/latlon/internal/format.ts"],"sourcesContent":["/*\n * Copyright
|
|
1
|
+
{"version":3,"file":"format.js","names":[],"sources":["../../../../src/coordinates/latlon/internal/format.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\nimport { BEARINGS, type Format, SYMBOLS } from '.';\nimport { getHemisphere } from './ordinal';\n\n/**\n * Display options for the `format*` coordinate formatters: text wrapped around\n * the whole string, the divider between axes, and whether each axis carries\n * its `N`/`S`/`E`/`W` letter.\n */\nexport type FormatOptions = {\n prefix: string;\n suffix: string;\n separator: string;\n withOrdinal?: boolean;\n};\n\n/**\n * Shared scaffold for a `CoordinateSystem`'s `toFormat` round-trip string.\n *\n * This is the loss-less internal representation `createCoordinate(...).dd()` /\n * `.ddm()` / `.dms()` returns — deliberately distinct from the display\n * formatters in each system's `formatter.ts`. The `to*Parts` / `format*`\n * functions round and carry to a fixed precision for human display; this path\n * keeps full precision and applies **no** carry so a value survives a\n * format → parse → float round-trip unchanged. The two must not be merged.\n *\n * Owns the parts every system's `toFormat` shares — the `[lat, lon]` map, the\n * ` / ` divider join, and the signed → `N`/`S`/`E`/`W` direction lookup — and\n * defers only the per-axis magnitude rendering (which is all that differs\n * between DD, DDM, and DMS) to `renderMagnitude`.\n *\n * @param format - Axis ordering (`'LATLON'` or `'LONLAT'`).\n * @param coordinates - Signed `[left, right]` values in the given ordering.\n * @param renderMagnitude - Renders the space-separated magnitude components of\n * one axis (e.g. `\"37 46.494\"` for DDM) from its absolute value.\n * @returns The joined round-trip string, e.g. `\"37 46.494 N / 122 25.164 W\"`.\n *\n * @remarks pure function\n */\nexport const formatCoordinateSystem = (\n format: Format,\n [left, right]: [number, number],\n renderMagnitude: (magnitude: number) => string,\n): string =>\n [left, right]\n .map((value, index) => {\n const direction = BEARINGS[format][index as 0 | 1][+(value < 0)];\n\n return `${renderMagnitude(Math.abs(value))} ${direction}`;\n })\n .join(` ${SYMBOLS.DIVIDER} `);\n\n/**\n * Creates a coordinate formatter function from a coordinate conversion function.\n *\n * @param fn - Function that converts a single coordinate value to a formatted string.\n * @returns Formatter function that takes coordinate pair and optional config.\n *\n * @example\n * ```typescript\n * const formatDD = createFormatter(\n * (value, withOrdinal) => `${(withOrdinal ? Math.abs(value) : value).toFixed(6)}°`,\n * );\n * formatDD([37.7749, -122.4194], { withOrdinal: true });\n * // '37.774900° N, 122.419400° W'\n * ```\n *\n * @example\n * ```typescript\n * const formatDMS = createFormatter(toDegreesMinutesSeconds);\n * formatDMS([37.7749, -122.4194], { separator: ' / ', withOrdinal: true });\n * // '37° 46' 29.64″ N / 122° 25' 9.84″ W'\n * ```\n */\nexport const createFormatter =\n (fn: (coord: number, withOrdinal?: boolean) => string) =>\n (coordinates: [number, number], config?: FormatOptions): string => {\n const [latitude, longitude] = coordinates;\n const latOrdinal = config?.withOrdinal\n ? ` ${getHemisphere(latitude, 'lat')}`\n : '';\n const lonOrdinal = config?.withOrdinal\n ? ` ${getHemisphere(longitude, 'lon')}`\n : '';\n const latValue = fn(latitude, config?.withOrdinal);\n const lonValue = fn(longitude, config?.withOrdinal);\n const prefix = config?.prefix ?? '';\n const suffix = config?.suffix ?? '';\n const separator = config?.separator ?? ', ';\n\n return `${prefix}${latValue}${latOrdinal}${separator}${lonValue}${lonOrdinal}${suffix}`;\n };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,MAAa,0BACX,QACA,CAAC,MAAM,QACP,oBAEA,CAAC,MAAM,MAAM,CACV,KAAK,OAAO,UAAU;CACrB,MAAM,YAAY,SAAS,QAAQ,OAAgB,EAAE,QAAQ;AAE7D,QAAO,GAAG,gBAAgB,KAAK,IAAI,MAAM,CAAC,CAAC,GAAG;EAC9C,CACD,KAAK,IAAI,QAAQ,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;AAwBjC,MAAa,mBACV,QACA,aAA+B,WAAmC;CACjE,MAAM,CAAC,UAAU,aAAa;CAC9B,MAAM,aAAa,QAAQ,cACvB,IAAI,cAAc,UAAU,MAAM,KAClC;CACJ,MAAM,aAAa,QAAQ,cACvB,IAAI,cAAc,WAAW,MAAM,KACnC;CACJ,MAAM,WAAW,GAAG,UAAU,QAAQ,YAAY;CAClD,MAAM,WAAW,GAAG,WAAW,QAAQ,YAAY;CACnD,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,SAAS,QAAQ,UAAU;AAGjC,QAAO,GAAG,SAAS,WAAW,aAFZ,QAAQ,aAAa,OAEgB,WAAW,aAAa"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { CoordinateInput, CoordinateInternalValue, CoordinateObject, CoordinateTuple, LatLonTuple, LonLatTuple, isCoordinateObject, isCoordinateTuple, normalizeObjectToLatLon, tupleToLatLon } from "./normalize.js";
|
|
14
|
-
import {
|
|
14
|
+
import { toPlainDecimalString } from "./plain-decimal.js";
|
|
15
|
+
import { isFiniteNumber, isValidNumericCoordinate, validateNumericCoordinate, validateSignedRange } from "./validate.js";
|
|
15
16
|
|
|
16
17
|
//#region src/coordinates/latlon/internal/index.d.ts
|
|
17
18
|
type Axes = 'LAT' | 'LON';
|
|
@@ -72,5 +73,5 @@ declare const PARTIAL_PATTERNS: {
|
|
|
72
73
|
readonly secDec: RegExp;
|
|
73
74
|
};
|
|
74
75
|
//#endregion
|
|
75
|
-
export { Axes, BEARINGS, Compass, type CoordinateInput, type CoordinateInternalValue, type CoordinateObject, type CoordinateTuple, Errors, FORMATS, FORMATS_DEFAULT, Format, LIMITS, type LatLonTuple, type LonLatTuple, PARTIAL_PATTERNS, SYMBOLS, SYMBOL_PATTERNS, isCoordinateObject, isCoordinateTuple, isFiniteNumber, normalizeObjectToLatLon, tupleToLatLon, validateNumericCoordinate, validateSignedRange };
|
|
76
|
+
export { Axes, BEARINGS, Compass, type CoordinateInput, type CoordinateInternalValue, type CoordinateObject, type CoordinateTuple, Errors, FORMATS, FORMATS_DEFAULT, Format, LIMITS, type LatLonTuple, type LonLatTuple, PARTIAL_PATTERNS, SYMBOLS, SYMBOL_PATTERNS, isCoordinateObject, isCoordinateTuple, isFiniteNumber, isValidNumericCoordinate, normalizeObjectToLatLon, toPlainDecimalString, tupleToLatLon, validateNumericCoordinate, validateSignedRange };
|
|
76
77
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
import { capture, merge, optional } from "../../../patterning.js";
|
|
15
15
|
import { isCoordinateObject, isCoordinateTuple, normalizeObjectToLatLon, tupleToLatLon } from "./normalize.js";
|
|
16
|
-
import {
|
|
16
|
+
import { toPlainDecimalString } from "./plain-decimal.js";
|
|
17
|
+
import { isFiniteNumber, isValidNumericCoordinate, validateNumericCoordinate, validateSignedRange } from "./validate.js";
|
|
17
18
|
|
|
18
19
|
//#region src/coordinates/latlon/internal/index.ts
|
|
19
20
|
/**
|
|
@@ -98,5 +99,5 @@ const PARTIAL_PATTERNS = {
|
|
|
98
99
|
};
|
|
99
100
|
|
|
100
101
|
//#endregion
|
|
101
|
-
export { BEARINGS, FORMATS, FORMATS_DEFAULT, LIMITS, PARTIAL_PATTERNS, SYMBOLS, SYMBOL_PATTERNS, isCoordinateObject, isCoordinateTuple, isFiniteNumber, normalizeObjectToLatLon, tupleToLatLon, validateNumericCoordinate, validateSignedRange };
|
|
102
|
+
export { BEARINGS, FORMATS, FORMATS_DEFAULT, LIMITS, PARTIAL_PATTERNS, SYMBOLS, SYMBOL_PATTERNS, isCoordinateObject, isCoordinateTuple, isFiniteNumber, isValidNumericCoordinate, normalizeObjectToLatLon, toPlainDecimalString, tupleToLatLon, validateNumericCoordinate, validateSignedRange };
|
|
102
103
|
//# sourceMappingURL=index.js.map
|