@jarenjs/core 0.9.2 → 0.34.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/ARCHITECTURE.md +229 -26
  2. package/README.md +64 -10
  3. package/dist/types/array.d.ts +13 -0
  4. package/dist/types/cache.d.ts +166 -0
  5. package/dist/types/chunk.d.ts +102 -0
  6. package/dist/types/color.d.ts +64 -0
  7. package/dist/types/convert/convert.d.ts +33 -0
  8. package/dist/types/convert/currency.d.ts +47 -0
  9. package/dist/types/convert/index.d.ts +9 -0
  10. package/dist/types/convert/registry.d.ts +55 -0
  11. package/dist/types/dates/civil.d.ts +146 -0
  12. package/dist/types/dates/duration.d.ts +83 -0
  13. package/dist/types/dates/format.d.ts +59 -0
  14. package/dist/types/dates/index.d.ts +4 -0
  15. package/dist/types/{dates.d.ts → dates/rfc3339.d.ts} +57 -3
  16. package/dist/types/errors.d.ts +77 -0
  17. package/dist/types/finance/amortization.d.ts +51 -0
  18. package/dist/types/finance/bond.d.ts +45 -0
  19. package/dist/types/finance/cashflow.d.ts +44 -0
  20. package/dist/types/finance/depreciation.d.ts +26 -0
  21. package/dist/types/finance/index.d.ts +16 -0
  22. package/dist/types/finance/indicators.d.ts +76 -0
  23. package/dist/types/finance/interest.d.ts +44 -0
  24. package/dist/types/finance/returns.d.ts +43 -0
  25. package/dist/types/finance/tvm.d.ts +50 -0
  26. package/dist/types/geo/angle.d.ts +4 -0
  27. package/dist/types/geo/bbox.d.ts +32 -0
  28. package/dist/types/geo/distance.d.ts +67 -0
  29. package/dist/types/geo/geohash.d.ts +63 -0
  30. package/dist/types/geo/geojson.d.ts +108 -0
  31. package/dist/types/geo/index-tree.d.ts +52 -0
  32. package/dist/types/geo/index.d.ts +11 -0
  33. package/dist/types/geo/mercator.d.ts +57 -0
  34. package/dist/types/geo/predicates.d.ts +44 -0
  35. package/dist/types/geo/ring.d.ts +80 -0
  36. package/dist/types/geo/simplify.d.ts +31 -0
  37. package/dist/types/geo/valid.d.ts +24 -0
  38. package/dist/types/geo/wkt.d.ts +16 -0
  39. package/dist/types/math/float64.d.ts +126 -3
  40. package/dist/types/math/format.d.ts +58 -0
  41. package/dist/types/math/index.d.ts +5 -0
  42. package/dist/types/math/mat4.d.ts +60 -0
  43. package/dist/types/math/project.d.ts +54 -0
  44. package/dist/types/math/solve.d.ts +67 -0
  45. package/dist/types/math/word.d.ts +82 -0
  46. package/dist/types/message.d.ts +52 -0
  47. package/dist/types/object.d.ts +151 -0
  48. package/dist/types/scan.d.ts +30 -0
  49. package/dist/types/schema.d.ts +24 -0
  50. package/dist/types/string.d.ts +96 -0
  51. package/dist/types/text/base64.d.ts +6 -4
  52. package/dist/types/text/email.d.ts +0 -1
  53. package/dist/types/text/host.d.ts +39 -8
  54. package/dist/types/text/i18n.d.ts +13 -1
  55. package/dist/types/text/index.d.ts +1 -0
  56. package/dist/types/text/misc.d.ts +15 -1
  57. package/dist/types/text/punycode.d.ts +45 -85
  58. package/docs/CONVERT.md +45 -0
  59. package/docs/DATES.md +78 -0
  60. package/docs/FINANCE.md +59 -0
  61. package/docs/GEO.md +114 -0
  62. package/docs/MATH.md +75 -0
  63. package/package.json +57 -4
  64. package/src/array.js +16 -0
  65. package/src/cache.js +206 -0
  66. package/src/chunk.js +159 -0
  67. package/src/color.js +125 -0
  68. package/src/convert/convert.js +59 -0
  69. package/src/convert/currency.js +74 -0
  70. package/src/convert/index.js +11 -0
  71. package/src/convert/registry.js +213 -0
  72. package/src/dates/civil.js +360 -0
  73. package/src/dates/duration.js +225 -0
  74. package/src/dates/format.js +238 -0
  75. package/src/dates/index.js +30 -0
  76. package/src/dates/rfc3339.js +621 -0
  77. package/src/errors.js +102 -0
  78. package/src/finance/amortization.js +50 -0
  79. package/src/finance/bond.js +100 -0
  80. package/src/finance/cashflow.js +122 -0
  81. package/src/finance/depreciation.js +54 -0
  82. package/src/finance/index.js +27 -0
  83. package/src/finance/indicators.js +207 -0
  84. package/src/finance/interest.js +63 -0
  85. package/src/finance/returns.js +90 -0
  86. package/src/finance/tvm.js +94 -0
  87. package/src/function.js +0 -2
  88. package/src/geo/angle.js +12 -0
  89. package/src/geo/bbox.js +80 -0
  90. package/src/geo/distance.js +155 -0
  91. package/src/geo/geohash.js +224 -0
  92. package/src/geo/geojson.js +361 -0
  93. package/src/geo/index-tree.js +294 -0
  94. package/src/geo/index.js +52 -0
  95. package/src/geo/mercator.js +124 -0
  96. package/src/geo/predicates.js +313 -0
  97. package/src/geo/ring.js +182 -0
  98. package/src/geo/simplify.js +130 -0
  99. package/src/geo/valid.js +142 -0
  100. package/src/geo/wkt.js +262 -0
  101. package/src/math/float64.js +228 -11
  102. package/src/math/format.js +157 -0
  103. package/src/math/index.js +5 -0
  104. package/src/math/mat4.js +131 -0
  105. package/src/math/project.js +49 -0
  106. package/src/math/solve.js +112 -0
  107. package/src/math/word.js +177 -0
  108. package/src/message.js +119 -0
  109. package/src/object.js +329 -0
  110. package/src/scan.js +42 -0
  111. package/src/schema.js +37 -0
  112. package/src/string.js +189 -0
  113. package/src/text/base64.js +15 -52
  114. package/src/text/email.js +0 -5
  115. package/src/text/host.js +515 -140
  116. package/src/text/i18n.js +13 -6
  117. package/src/text/identifiers.js +1 -1
  118. package/src/text/index.js +1 -0
  119. package/src/text/misc.js +81 -5
  120. package/src/text/punycode.js +235 -323
  121. package/src/dates.js +0 -371
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @file Time Value of Money. The five TVM quantities — N,
3
+ * I/Y, PV, PMT, FV — obey one identity; each function here solves for its
4
+ * own variable. Sign convention follows the standard cash-flow model
5
+ * (money in is positive, money out negative), matching Excel/HP-12C:
6
+ *
7
+ * PV·(1+i)^n + PMT·(1 + i·type)·((1+i)^n − 1)/i + FV = 0
8
+ *
9
+ * `type` is 0 for an ordinary annuity (payment at period end) or 1 for an
10
+ * annuity-due (payment at period begin). Rates are per period; a caller
11
+ * with an annual rate and monthly periods passes `rate/12`.
12
+ *
13
+ * Pure and zero-dep except `math/solve` for the iterative `rate`.
14
+ */
15
+ /**
16
+ * Future value.
17
+ * @param {number} rate @param {number} nper @param {number} pmt
18
+ * @param {number} [pv] @param {number} [type]
19
+ * @returns {number}
20
+ */
21
+ export declare function fv(rate: number, nper: number, pmt: number, pv?: number, type?: number): number;
22
+ /**
23
+ * Present value.
24
+ * @param {number} rate @param {number} nper @param {number} pmt
25
+ * @param {number} [fval] @param {number} [type]
26
+ * @returns {number}
27
+ */
28
+ export declare function pv(rate: number, nper: number, pmt: number, fval?: number, type?: number): number;
29
+ /**
30
+ * Payment per period.
31
+ * @param {number} rate @param {number} nper @param {number} pval
32
+ * @param {number} [fval] @param {number} [type]
33
+ * @returns {number}
34
+ */
35
+ export declare function pmt(rate: number, nper: number, pval: number, fval?: number, type?: number): number;
36
+ /**
37
+ * Number of periods.
38
+ * @param {number} rate @param {number} pmtv @param {number} pval
39
+ * @param {number} [fval] @param {number} [type]
40
+ * @returns {number}
41
+ */
42
+ export declare function nper(rate: number, pmtv: number, pval: number, fval?: number, type?: number): number;
43
+ /**
44
+ * Periodic interest rate, solved iteratively (Newton, bisection
45
+ * fallback). Returns `NaN` if no rate is found.
46
+ * @param {number} nperv @param {number} pmtv @param {number} pval
47
+ * @param {number} [fval] @param {number} [type] @param {number} [guess]
48
+ * @returns {number}
49
+ */
50
+ export declare function rate(nperv: number, pmtv: number, pval: number, fval?: number, type?: number, guess?: number): number;
@@ -0,0 +1,4 @@
1
+ /** Radians per degree — multiply degrees by this to get radians. */
2
+ export declare const DEG: number;
3
+ /** Degrees per radian — multiply radians by this to get degrees. */
4
+ export declare const RAD: number;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The bounding box of a list of positions, as `[west, south, east, north]`.
3
+ * Returns null for an empty list — there is no box that bounds nothing,
4
+ * and an all-Infinity placeholder would silently intersect everything.
5
+ * @param {Array<number[]>} positions
6
+ * @returns {number[] | null}
7
+ */
8
+ export declare function bboxOfPositions(positions: Array<number[]>): number[] | null;
9
+ /**
10
+ * Whether two bounding boxes share any area. Boxes that merely touch
11
+ * along an edge count as intersecting, matching `pointInRing`'s
12
+ * treatment of a boundary as inside.
13
+ * @param {number[]} a - [west, south, east, north]
14
+ * @param {number[]} b
15
+ * @returns {boolean}
16
+ */
17
+ export declare function bboxIntersects(a: number[], b: number[]): boolean;
18
+ /**
19
+ * Whether a bounding box contains a position (edges included).
20
+ * @param {number[]} box - [west, south, east, north]
21
+ * @param {number} x - longitude
22
+ * @param {number} y - latitude
23
+ * @returns {boolean}
24
+ */
25
+ export declare function bboxContains(box: number[], x: number, y: number): boolean;
26
+ /**
27
+ * The smallest box containing both inputs.
28
+ * @param {number[]} a
29
+ * @param {number[]} b
30
+ * @returns {number[]}
31
+ */
32
+ export declare function bboxUnion(a: number[], b: number[]): number[];
@@ -0,0 +1,67 @@
1
+ /** IUGG mean Earth radius in metres — the sphere GeoJSON distances use. */
2
+ export declare const EARTH_RADIUS = 6371008.8;
3
+ /**
4
+ * Great-circle distance between two positions, in metres.
5
+ *
6
+ * @param {number} lon1 - longitude of the first position, degrees
7
+ * @param {number} lat1 - latitude of the first position, degrees
8
+ * @param {number} lon2 - longitude of the second position, degrees
9
+ * @param {number} lat2 - latitude of the second position, degrees
10
+ * @param {number} [radius] - sphere radius, to answer in other units
11
+ * @returns {number} distance in metres (or in `radius`'s unit)
12
+ * @example
13
+ * haversineDistance(4.9041, 52.3676, 2.3522, 48.8566); // 429_862 (Amsterdam-Paris)
14
+ */
15
+ export declare function haversineDistance(lon1: number, lat1: number, lon2: number, lat2: number, radius?: number): number;
16
+ /**
17
+ * Equirectangular approximation of the distance between two positions,
18
+ * in metres — the **screening** form.
19
+ *
20
+ * Accurate to about 0.02% over a few hundred kilometres and roughly 12%
21
+ * across a hemisphere, for about a seventh of the cost. Use it to reject
22
+ * candidates that cannot be within a radius, then confirm the survivors
23
+ * with `haversineDistance`; do not report it as a measurement.
24
+ *
25
+ * @param {number} lon1
26
+ * @param {number} lat1
27
+ * @param {number} lon2
28
+ * @param {number} lat2
29
+ * @param {number} [radius]
30
+ * @returns {number} approximate distance
31
+ */
32
+ export declare function equirectDistance(lon1: number, lat1: number, lon2: number, lat2: number, radius?: number): number;
33
+ /**
34
+ * Initial bearing from one position to another: degrees clockwise from
35
+ * true north, in `[0, 360)`.
36
+ *
37
+ * This is the bearing at the *start* of the great circle, and it changes
38
+ * along the path — a course of constant bearing is a rhumb line, which
39
+ * is a different curve.
40
+ *
41
+ * @param {number} lon1
42
+ * @param {number} lat1
43
+ * @param {number} lon2
44
+ * @param {number} lat2
45
+ * @returns {number} degrees in [0, 360)
46
+ */
47
+ export declare function initialBearing(lon1: number, lat1: number, lon2: number, lat2: number): number;
48
+ /**
49
+ * The position reached by travelling `distance` metres from a position
50
+ * along a constant initial bearing (a great-circle course).
51
+ *
52
+ * @param {number} lon - starting longitude, degrees
53
+ * @param {number} lat - starting latitude, degrees
54
+ * @param {number} bearing - degrees clockwise from true north
55
+ * @param {number} distance - metres
56
+ * @param {number} [radius]
57
+ * @returns {[number, number]} the destination as a GeoJSON position
58
+ */
59
+ export declare function destinationPoint(lon: number, lat: number, bearing: number, distance: number, radius?: number): [number, number];
60
+ /**
61
+ * Total great-circle length of a line of positions, in metres. An empty
62
+ * or single-position line has length 0.
63
+ * @param {Array<number[]>} positions - GeoJSON positions
64
+ * @param {number} [radius]
65
+ * @returns {number}
66
+ */
67
+ export declare function lineLength(positions: Array<number[]>, radius?: number): number;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Encode a position as a geohash string.
3
+ *
4
+ * @param {number} lon - longitude, degrees
5
+ * @param {number} lat - latitude, degrees
6
+ * @param {number} [precision] - characters, 1-12 (default 9, about 5 m)
7
+ * @returns {string}
8
+ * @example
9
+ * geohashEncode(4.9041, 52.3676, 5); // 'u173z' (Amsterdam)
10
+ */
11
+ export declare function geohashEncode(lon: number, lat: number, precision?: number): string;
12
+ /**
13
+ * Whether a string is a well-formed geohash: non-empty and every
14
+ * character in the base-32 alphabet (lowercase; `a`, `i`, `l` and `o`
15
+ * are deliberately absent from it). Any length is valid — each
16
+ * character only names a finer cell.
17
+ * @param {string} hash
18
+ * @returns {boolean}
19
+ * @example
20
+ * isValidGeohash('u173z'); // true (Amsterdam)
21
+ * isValidGeohash('u17a'); // false ('a' is not in the alphabet)
22
+ */
23
+ export declare function isValidGeohash(hash: string): boolean;
24
+ /**
25
+ * The bounding box of a geohash cell, as `[west, south, east, north]`.
26
+ * Returns null for a string containing a character outside the base-32
27
+ * alphabet (`a`, `i`, `l` and `o` are deliberately absent).
28
+ * @param {string} hash
29
+ * @returns {number[] | null}
30
+ */
31
+ export declare function geohashBounds(hash: string): number[] | null;
32
+ /**
33
+ * The centre of a geohash cell, as a GeoJSON position. Null for an
34
+ * invalid hash.
35
+ *
36
+ * Decoding is lossy by construction — a hash names a cell, not a point —
37
+ * so this is the cell's centre and the error is bounded by
38
+ * {@link geohashCellSize}.
39
+ *
40
+ * @param {string} hash
41
+ * @returns {[number, number] | null}
42
+ */
43
+ export declare function geohashDecode(hash: string): [number, number] | null;
44
+ /**
45
+ * Approximate cell size at a precision, as `[lonWidth, latHeight]` in
46
+ * degrees. Null outside 1-12.
47
+ * @param {number} precision
48
+ * @returns {number[] | null}
49
+ */
50
+ export declare function geohashCellSize(precision: number): number[] | null;
51
+ /**
52
+ * The eight geohash cells surrounding one, plus the cell itself, as a
53
+ * nine-element array. Cells that would fall off the poles are omitted,
54
+ * so the result may be shorter.
55
+ *
56
+ * This is what makes a prefix search safe near a boundary: two points
57
+ * metres apart can sit in different cells, so a proximity query tests
58
+ * the neighbourhood rather than the single cell.
59
+ *
60
+ * @param {string} hash
61
+ * @returns {string[]}
62
+ */
63
+ export declare function geohashNeighbours(hash: string): string[];
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Whether a value looks like a bare position: an array of at least two
3
+ * finite numbers.
4
+ * @param {any} value
5
+ * @returns {boolean}
6
+ */
7
+ export declare function isPosition(value: any): boolean;
8
+ /**
9
+ * The geometry inside a value: the value itself when it is already one,
10
+ * a Feature's `geometry`, or null when there is none (including a
11
+ * Feature whose geometry is legitimately null).
12
+ *
13
+ * A FeatureCollection has no single geometry and yields null — use
14
+ * {@link eachPosition} or {@link bboxOf}, which handle collections.
15
+ *
16
+ * @param {any} value
17
+ * @returns {object | null}
18
+ */
19
+ export declare function geometryOf(value: any): object | null;
20
+ /**
21
+ * Call `visit(position)` for every position in a GeoJSON value, in
22
+ * document order. Accepts a bare position, a geometry, a Feature, a
23
+ * FeatureCollection or a GeometryCollection.
24
+ * @param {any} value
25
+ * @param {(position: number[]) => void} visit
26
+ */
27
+ export declare function eachPosition(value: any, visit: (position: number[]) => void): void;
28
+ /**
29
+ * The bounding box of any GeoJSON value, as `[west, south, east, north]`.
30
+ * Null when the value contains no positions.
31
+ *
32
+ * A `bbox` member already present on the value is ignored: it is an
33
+ * optimization the producer may have got wrong, and recomputing is the
34
+ * only way to be sure.
35
+ *
36
+ * @param {any} value
37
+ * @returns {number[] | null}
38
+ */
39
+ export declare function bboxOf(value: any): number[] | null;
40
+ /**
41
+ * Every position of a GeoJSON value, flattened into one array.
42
+ * @param {any} value
43
+ * @returns {Array<number[]>}
44
+ */
45
+ export declare function positionsOf(value: any): Array<number[]>;
46
+ /**
47
+ * Geodesic area of a value in square metres: the sum over its polygons
48
+ * of the exterior ring's area less its holes'. Anything with no surface
49
+ * — a point, a line — has area 0 rather than being an error.
50
+ * @param {any} value
51
+ * @param {number} [radius]
52
+ * @returns {number}
53
+ */
54
+ export declare function geometryArea(value: any, radius?: number): number;
55
+ /**
56
+ * Great-circle length of a value in metres: the sum of its line
57
+ * lengths, and of its polygon ring perimeters. A point has length 0.
58
+ * @param {any} value
59
+ * @param {number} [radius]
60
+ * @returns {number}
61
+ */
62
+ export declare function geometryLength(value: any, radius?: number): number;
63
+ /**
64
+ * The centroid of a value's positions, as a GeoJSON position. Null when
65
+ * there are none.
66
+ *
67
+ * This is the mean of the vertices, NOT the area-weighted centre of
68
+ * mass: it is the cheap answer, it always lies in the convex hull, and
69
+ * for a concave shape it can fall outside the polygon. Labelling and
70
+ * clustering want this; a physics centre of mass does not.
71
+ *
72
+ * @param {any} value
73
+ * @returns {[number, number] | null}
74
+ */
75
+ export declare function centroidOf(value: any): [number, number] | null;
76
+ /**
77
+ * Whether a position lies inside a value's surface. Only polygons have
78
+ * an inside, so a point or a line always answers false.
79
+ * @param {any} value - a Polygon, MultiPolygon, Feature or collection
80
+ * @param {number} lon
81
+ * @param {number} lat
82
+ * @returns {boolean}
83
+ */
84
+ export declare function containsPosition(value: any, lon: number, lat: number): boolean;
85
+ /**
86
+ * The distance in metres between two GeoJSON values, measured between
87
+ * their **representative positions**: a bare position or Point is
88
+ * itself, anything else is its centroid. Null when either side has no
89
+ * positions.
90
+ *
91
+ * This is deliberately not the minimum distance between two shapes,
92
+ * which needs point-to-segment geodesics and is a different (and much
93
+ * larger) piece of work. Callers wanting "how far is this point from
94
+ * that region" should test containment first.
95
+ *
96
+ * @param {any} a
97
+ * @param {any} b
98
+ * @param {number} [radius]
99
+ * @returns {number | null}
100
+ */
101
+ export declare function geoDistance(a: any, b: any, radius?: number): number | null;
102
+ /**
103
+ * Whether every linear ring of a value is closed — the invariant the
104
+ * portable GeoJSON schema cannot express. True for values with no rings.
105
+ * @param {any} value
106
+ * @returns {boolean}
107
+ */
108
+ export declare function ringsClosed(value: any): boolean;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Interleave the low 16 bits of x and y into a Hilbert distance.
3
+ * Boxes ordered by this stay spatially clustered, which is what makes
4
+ * the packed parents tight.
5
+ *
6
+ * Bit-parallel: all sixteen levels of the per-bit quadrant rotation run
7
+ * at once as mask arithmetic (the public-domain transform from
8
+ * rawrunprotected/hilbert_curves), which is what makes computing 100k of
9
+ * these a millisecond instead of the build's dominant cost. The values
10
+ * are identical to the classical per-bit walk of the curve.
11
+ *
12
+ * @param {number} x - 0..65535
13
+ * @param {number} y - 0..65535
14
+ * @returns {number}
15
+ */
16
+ export declare function hilbertDistance(x: number, y: number): number;
17
+ export type BboxIndex = {
18
+ /**
19
+ * - how many boxes were indexed
20
+ */
21
+ size: number;
22
+ /**
23
+ * the indexes of every box whose bounds overlap the query box
24
+ */
25
+ search: (minX: number, minY: number, maxX: number, maxY: number) => number[];
26
+ };
27
+ /**
28
+ * A queryable static index over bounding boxes.
29
+ * @typedef {Object} BboxIndex
30
+ * @property {number} size - how many boxes were indexed
31
+ * @property {(minX: number, minY: number, maxX: number, maxY: number) => number[]} search
32
+ * the indexes of every box whose bounds overlap the query box
33
+ */
34
+ /**
35
+ * Build a static index over `[west, south, east, north]` boxes.
36
+ *
37
+ * The returned `search` yields **candidate** indexes into the original
38
+ * array: every box that truly overlaps is included, and boxes that merely
39
+ * share a tree node may be too. Confirm each with the exact test.
40
+ *
41
+ * A null entry (a value with no positions, so no box) is indexed as a
42
+ * degenerate box that overlaps nothing, so it can never be a candidate
43
+ * while the array indexes stay aligned with the caller's data.
44
+ *
45
+ * @param {Array<number[] | null>} boxes
46
+ * @param {number} [nodeSize] - children per node
47
+ * @returns {BboxIndex}
48
+ * @example
49
+ * const index = createBboxIndex(regions.map(bboxOf));
50
+ * for (const i of index.search(...bboxOf(point))) confirm(regions[i]);
51
+ */
52
+ export declare function createBboxIndex(boxes: Array<number[] | null>, nodeSize?: number): BboxIndex;
@@ -0,0 +1,11 @@
1
+ export * from './predicates.js';
2
+ export * from './distance.js';
3
+ export * from './ring.js';
4
+ export * from './bbox.js';
5
+ export * from './geohash.js';
6
+ export * from './geojson.js';
7
+ export * from './valid.js';
8
+ export * from './wkt.js';
9
+ export * from './index-tree.js';
10
+ export * from './mercator.js';
11
+ export * from './simplify.js';
@@ -0,0 +1,57 @@
1
+ /**
2
+ * The latitude where Web Mercator's y reaches the edge of its square.
3
+ * Poleward of this the projection is unbounded.
4
+ */
5
+ export declare const MERCATOR_MAX_LAT = 85.05112877980659;
6
+ /**
7
+ * Project a position into the Web Mercator unit square: x and y both in
8
+ * `[0, 1]`, with **y increasing southward** so the result is already in
9
+ * screen order and a renderer needs no flip.
10
+ *
11
+ * Latitude is clamped, longitude is not: a latitude past the Mercator
12
+ * limit has a defensible answer (the edge) while a longitude past ±180
13
+ * is simply invalid under RFC 7946, and folding it silently into range
14
+ * would move a shape to the wrong side of the world rather than let the
15
+ * defect show.
16
+ *
17
+ * @param {number} lon - longitude in degrees, `[-180, 180]`
18
+ * @param {number} lat - latitude in degrees, clamped to ±85.051129
19
+ * @returns {[number, number]} `[x, y]` in the unit square
20
+ * @example
21
+ * projectMercator(0, 0); // [0.5, 0.5] — null island is the centre
22
+ * projectMercator(-180, 85.05112877980659); // [0, 0] — the north-west corner
23
+ */
24
+ export declare function projectMercator(lon: number, lat: number): [number, number];
25
+ /**
26
+ * The inverse of {@link projectMercator}: a unit-square point back to a
27
+ * position. Needed to turn a click or a viewport corner back into
28
+ * longitude and latitude.
29
+ *
30
+ * @param {number} x - 0..1
31
+ * @param {number} y - 0..1, increasing southward
32
+ * @returns {[number, number]} `[longitude, latitude]` in degrees
33
+ */
34
+ export declare function unprojectMercator(x: number, y: number): [number, number];
35
+ /**
36
+ * A projection fitted to a geographic bounding box: the transform that
37
+ * maps positions inside `bbox` into `[0, 1]` on both axes, **without
38
+ * distorting the aspect ratio**, centring whichever axis has room left
39
+ * over.
40
+ *
41
+ * Stretching a map to fill its frame is the single most common way to
42
+ * make one look wrong, so the fit is uniform by construction and the
43
+ * spare room becomes margin rather than distortion. `aspect` is the
44
+ * width:height ratio of the frame the result will be drawn into: the fit
45
+ * happens in a box `aspect` wide and 1 tall, then x is divided back down
46
+ * so both outputs are in `[0, 1]` — the same unit-square convention the
47
+ * treemap uses, where the renderer maps height from width by the same
48
+ * ratio.
49
+ *
50
+ * @param {number[]} bbox - `[west, south, east, north]`
51
+ * @param {number} [aspect] - frame width:height (default 1, a square)
52
+ * @returns {(lon: number, lat: number) => [number, number]}
53
+ * @example
54
+ * const fit = fitMercator([4, 52, 5, 53], 1.6);
55
+ * fit(4.5, 52.5); // near [0.5, 0.5] whatever the box's shape
56
+ */
57
+ export declare function fitMercator(bbox: number[], aspect?: number): (lon: number, lat: number) => [number, number];
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The orientation of the triple (a, b, c): **positive** when c lies to
3
+ * the left of the directed line a->b (counter-clockwise), **negative**
4
+ * when it lies to the right, and **exactly zero** when the three points
5
+ * are collinear.
6
+ *
7
+ * The sign is always correct. The magnitude is twice the signed area of
8
+ * the triangle, but only approximately — callers must use this for its
9
+ * sign, and `ringArea` for a measurement.
10
+ *
11
+ * Coordinates are raw numbers rather than vector objects so a GeoJSON
12
+ * position (`[lon, lat]`) can be passed straight through.
13
+ *
14
+ * @param {number} ax
15
+ * @param {number} ay
16
+ * @param {number} bx
17
+ * @param {number} by
18
+ * @param {number} cx
19
+ * @param {number} cy
20
+ * @returns {number} positive, negative, or zero
21
+ * @example
22
+ * orient2d(0, 0, 1, 0, 0, 1); // > 0 — (0,1) is left of the x axis
23
+ * orient2d(0, 0, 1, 0, 0, -1); // < 0
24
+ * orient2d(0, 0, 2, 2, 1, 1); // 0 — exactly collinear
25
+ */
26
+ export declare function orient2d(ax: number, ay: number, bx: number, by: number, cx: number, cy: number): number;
27
+ /**
28
+ * The same determinant without the exact fallback: fast, and **wrong on
29
+ * near-collinear input**.
30
+ *
31
+ * This exists for the one case where that is acceptable — a bounding
32
+ * pre-filter whose answer is checked by `orient2d` afterwards. Anything
33
+ * that decides containment, winding or intersection must use `orient2d`;
34
+ * a wrong sign there is a wrong answer, not a rounding error.
35
+ *
36
+ * @param {number} ax
37
+ * @param {number} ay
38
+ * @param {number} bx
39
+ * @param {number} by
40
+ * @param {number} cx
41
+ * @param {number} cy
42
+ * @returns {number}
43
+ */
44
+ export declare function orient2dFast(ax: number, ay: number, bx: number, by: number, cx: number, cy: number): number;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Whether a ring is closed: its last position repeats its first.
3
+ *
4
+ * Compares longitude and latitude only. A position may legally carry a
5
+ * third element (altitude), and RFC 7946 does not require it to match
6
+ * for the ring to close.
7
+ *
8
+ * @param {Array<number[]>} ring - positions
9
+ * @returns {boolean}
10
+ * @example
11
+ * isRingClosed([[0,0],[1,0],[1,1],[0,0]]); // true
12
+ * isRingClosed([[0,0],[1,0],[1,1]]); // false
13
+ */
14
+ export declare function isRingClosed(ring: Array<number[]>): boolean;
15
+ /**
16
+ * Twice the signed planar area of a ring (the shoelace sum), in squared
17
+ * degrees. **Positive is counter-clockwise.**
18
+ *
19
+ * The sign is the useful part and is exact for the purpose: it is a sum
20
+ * of `orient2d` determinants about the ring's first vertex, so a ring
21
+ * whose vertices are near-collinear still winds the way this says. The
22
+ * magnitude is a planar quantity in degree-space and is NOT an area on
23
+ * the Earth — use `sphericalRingArea` for that.
24
+ *
25
+ * @param {Array<number[]>} ring - positions
26
+ * @returns {number} twice the signed area; positive = counter-clockwise
27
+ */
28
+ export declare function ringSignedArea(ring: Array<number[]>): number;
29
+ /**
30
+ * The winding direction of a ring: `1` counter-clockwise, `-1`
31
+ * clockwise, `0` degenerate (zero area).
32
+ *
33
+ * RFC 7946 section 3.1.6 requires exterior rings to be counter-clockwise
34
+ * and holes clockwise — the right-hand rule. Parsers are told to accept
35
+ * non-conforming data, so this reports rather than rejects.
36
+ *
37
+ * @param {Array<number[]>} ring - positions
38
+ * @returns {number} 1, -1 or 0
39
+ */
40
+ export declare function ringWinding(ring: Array<number[]>): number;
41
+ /**
42
+ * Geodesic area of a ring on the sphere, in square metres, always
43
+ * non-negative.
44
+ *
45
+ * Uses the spherical excess of the polygon (the standard formula for a
46
+ * ring of great-circle edges), so unlike `ringSignedArea` this is a real
47
+ * measurement. Accurate to the sphere approximation — under half a
48
+ * percent, the same bound as `haversineDistance`.
49
+ *
50
+ * @param {Array<number[]>} ring - positions
51
+ * @param {number} [radius]
52
+ * @returns {number} square metres
53
+ */
54
+ export declare function sphericalRingArea(ring: Array<number[]>, radius?: number): number;
55
+ /**
56
+ * Whether a position lies inside a ring, by the even-odd (crossing)
57
+ * rule. A position exactly on an edge or vertex counts as **inside**,
58
+ * which is the convention that makes adjacent polygons tile without
59
+ * gaps.
60
+ *
61
+ * The ray cast runs in the ring's own coordinate space, so this is a
62
+ * planar test on longitude/latitude. That is what GeoJSON consumers
63
+ * mean by containment, and it is correct for any ring that does not
64
+ * cross the antimeridian — which RFC 7946 tells producers to cut.
65
+ *
66
+ * @param {number} x - longitude
67
+ * @param {number} y - latitude
68
+ * @param {Array<number[]>} ring - positions
69
+ * @returns {boolean}
70
+ */
71
+ export declare function pointInRing(x: number, y: number, ring: Array<number[]>): boolean;
72
+ /**
73
+ * Whether a position lies inside a polygon: inside its exterior ring and
74
+ * outside every hole.
75
+ * @param {number} x - longitude
76
+ * @param {number} y - latitude
77
+ * @param {Array<Array<number[]>>} rings - a GeoJSON Polygon's coordinates
78
+ * @returns {boolean}
79
+ */
80
+ export declare function pointInPolygon(x: number, y: number, rings: Array<Array<number[]>>): boolean;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Simplify a line with the Douglas-Peucker algorithm, keeping every
3
+ * vertex further than `tolerance` from the line its neighbours describe.
4
+ *
5
+ * The first and last positions always survive, so a **ring stays closed**
6
+ * — simplification can never turn a valid polygon into an invalid one.
7
+ * Positions are returned by reference, not copied, so any third element
8
+ * (altitude) rides along untouched.
9
+ *
10
+ * @param {Array<number[]>} line - positions
11
+ * @param {number} tolerance - in the input's own coordinate units
12
+ * @returns {Array<number[]>} a new array; the input is not modified
13
+ * @example
14
+ * simplifyLine([[0,0],[1,0.001],[2,0]], 0.01); // [[0,0],[2,0]]
15
+ * simplifyLine([[0,0],[1,1],[2,0]], 0.01); // all three: the corner carries the shape
16
+ */
17
+ export declare function simplifyLine(line: Array<number[]>, tolerance: number): Array<number[]>;
18
+ /**
19
+ * Simplify a linear ring, refusing to destroy it.
20
+ *
21
+ * A ring needs four positions to bound a surface, so when the tolerance
22
+ * would leave fewer the ring is returned **unsimplified** rather than
23
+ * degenerate. Dropping a small island entirely is a defensible rendering
24
+ * choice, but silently emitting a two-vertex "polygon" is not — a caller
25
+ * wanting the island gone should filter by area first.
26
+ *
27
+ * @param {Array<number[]>} ring - positions, first === last
28
+ * @param {number} tolerance
29
+ * @returns {Array<number[]>}
30
+ */
31
+ export declare function simplifyRing(ring: Array<number[]>, tolerance: number): Array<number[]>;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Whether a value is a structurally valid GeoJSON object: one of the
3
+ * seven geometry types, a Feature, or a FeatureCollection, with the
4
+ * coordinate nesting its `type` requires, positions of 2 or 3 numbers
5
+ * inside the WGS 84 bounds, and **every linear ring closed** — the
6
+ * invariant a JSON Schema cannot state.
7
+ *
8
+ * This is the shallow twin of the schema artifacts in `@jarenjs/json`:
9
+ * it answers yes or no in one call, where the meta-schema reports what
10
+ * failed and where, and the Jaren-extended variant also checks winding.
11
+ * Foreign members and a `bbox` are ignored rather than judged, exactly
12
+ * as the meta-schema leaves them open.
13
+ *
14
+ * @param {any} value
15
+ * @returns {boolean}
16
+ * @example
17
+ * isValidGeoJson({ type: 'Point', coordinates: [4.9, 52.4] }); // true
18
+ * isValidGeoJson({ type: 'Polygon',
19
+ * coordinates: [[[0,0],[1,0],[1,1],[0,0]]] }); // true
20
+ * isValidGeoJson({ type: 'Polygon',
21
+ * coordinates: [[[0,0],[1,0],[1,1],[2,2]]] }); // false (open ring)
22
+ * isValidGeoJson({ type: 'Point', coordinates: [52.4, 4.9, 0, 0] }); // false (4 axes)
23
+ */
24
+ export declare function isValidGeoJson(value: any): boolean;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Whether a string is a well-formed WKT geometry: one of the seven
3
+ * tagged types, `EMPTY` or a body whose nesting matches the tag, a
4
+ * coordinate count consistent with the `Z`/`M`/`ZM` modifier and with
5
+ * itself, closed polygon rings, and nothing before or after.
6
+ *
7
+ * @param {string} text
8
+ * @returns {boolean}
9
+ * @example
10
+ * isValidWkt('POINT (4.9041 52.3676)'); // true
11
+ * isValidWkt('POLYGON ((0 0, 4 0, 4 4, 0 0))'); // true (closed)
12
+ * isValidWkt('POLYGON ((0 0, 4 0, 4 4, 1 1))'); // false (open ring)
13
+ * isValidWkt('POINT Z (1 2)'); // false (Z wants 3)
14
+ * isValidWkt('LINESTRING (0 0, 1 1 1)'); // false (mixed dimension)
15
+ */
16
+ export declare function isValidWkt(text: string): boolean;