@konfirm/geojson 1.0.1 → 2.0.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/README.md +195 -40
- package/dist/main.d.mts +27 -21
- package/dist/main.d.ts +27 -21
- package/dist/main.global.js +735 -164
- package/dist/main.global.js.map +1 -1
- package/dist/main.js +880 -246
- package/dist/main.js.map +1 -1
- package/dist/main.mjs +856 -228
- package/dist/main.mjs.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -3,7 +3,108 @@
|
|
|
3
3
|
|
|
4
4
|
# @konfirm/geojson
|
|
5
5
|
|
|
6
|
-
GeoJSON
|
|
6
|
+
GeoJSON is a standard format for encoding geographic data structures — points, lines, polygons — as JSON. It was formalized in [RFC 7946](https://www.rfc-editor.org/rfc/rfc7946) in 2016, which introduced requirements (like winding order for polygon rings) that many tools still don't enforce.
|
|
7
|
+
> This TypeScript-first library gives you strict RFC 7946 validation and relaxed structural checks — so you can choose the right level of correctness for your data — along with geodesic distance across four formulas, intersection testing, and geometry iteration.
|
|
8
|
+
|
|
9
|
+
## Installation and usage
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install @konfirm/geojson
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { isGeoJSON, isStrictGeoJSON, distance, karney } from '@konfirm/geojson';
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## What @konfirm/geojson offers
|
|
20
|
+
|
|
21
|
+
**Types.** All RFC 7946 GeoJSON types (`Point`, `LineString`, `Polygon`, their `Multi*` variants, `GeometryCollection`, `Feature`, `FeatureCollection`) are exported as TypeScript types. `Feature<G>`, `FeatureCollection<G>`, and `GeometryCollection<G>` are generic so you can narrow the geometry type at compile time.
|
|
22
|
+
|
|
23
|
+
**Validation.** Every type has two guards: `is*` checks structure (is this a valid GeoJSON object at all?), and `isStrict*` also checks coordinate ranges and RFC 7946 (§3.1.6) winding order. You pick the tier; you can use both in the same codebase.
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { isGeoJSON, isStrictGeoJSON } from '@konfirm/geojson';
|
|
27
|
+
|
|
28
|
+
isGeoJSON(value) // structural check — coordinates in bounds? irrelevant.
|
|
29
|
+
isStrictGeoJSON(value) // also checks ranges and CCW/CW winding per RFC 7946
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Distance.** Geodesic distance between any two GeoJSON objects (not just points) across four formulas. `haversine` covers most use cases. `karney` always converges.
|
|
33
|
+
|
|
34
|
+
**Intersection.** Boolean intersection test across all geometry type combinations (`Point`, `LineString`, `Polygon` and their `Multi*` and `Feature`/`FeatureCollection` wrappers).
|
|
35
|
+
|
|
36
|
+
**Iteration.** `SimpleGeometryIterator` flattens any GeoJSON — including nested `GeometryCollection` and `FeatureCollection` — into a sequence of simple `Point`, `LineString`, and `Polygon` geometries.
|
|
37
|
+
|
|
38
|
+
## Upgrading to v2?
|
|
39
|
+
|
|
40
|
+
**What's new:**
|
|
41
|
+
- `karney` — fourth distance formula; always converges, ~15 nm accuracy on WGS84, including near-antipodal inputs
|
|
42
|
+
- Generic `Feature<G>`, `FeatureCollection<G>`, `GeometryCollection<G>` — narrow the geometry type at compile time by passing a guard: `isFeature(value, isPoint)` → `value is Feature<Point>`
|
|
43
|
+
- Named formula exports — `cartesian`, `haversine`, `vincenty`, `karney` as standalone `(GeoJSON, GeoJSON) => number` functions for direct use and tree-shaking
|
|
44
|
+
- RFC 7946 winding enforcement in `isStrictPolygon` and `isStrictMultiPolygon` — was silently skipped in v1
|
|
45
|
+
|
|
46
|
+
Five breaking changes. Quick fixes below; the [full migration guide](./MIGRATION.md) has the details.
|
|
47
|
+
|
|
48
|
+
| Change | v1 | v2 | Quick fix |
|
|
49
|
+
|--------|----|----|-----------|
|
|
50
|
+
| `distance()` default | `'cartesian'` | `'haversine'` | Pass `'cartesian'` explicitly, or `import { cartesian as distance }` |
|
|
51
|
+
| `isStrictPolygon` winding | not enforced | RFC 7946 §3.1.6 (CCW exterior, CW interior) | Use `isPolygon` for loose validation |
|
|
52
|
+
| `vincenty` near-antipodal | silent wrong result | throws `EvalError` | Catch the error, or switch to `'karney'` |
|
|
53
|
+
| `Geometry` / `isGeometry` | excluded `GeometryCollection` | includes `GeometryCollection` | Use `isGeometryPrimitive` if you need the six coordinate-bearing types only |
|
|
54
|
+
| `Feature.geometry` type | `Geometry \| GeometryCollection` (null never typed) | `Geometry \| null` (matches runtime) | Add null checks where `geometry` was assumed non-null; `isFeature(v, isGeometry)` narrows to non-null |
|
|
55
|
+
|
|
56
|
+
On the winding: `isStrictPolygon` didn't check the one thing [RFC 7946](https://www.rfc-editor.org/rfc/rfc7946#section-3.1.6) says polygons MUST do — the winding. Counterclockwise for the outer ring, and clockwise for the inner rings (holes). To top it off, if it had checked, it would have been wrong anyway. Wrong formula, wrong data backing it up. That's on me — [read more on what happened, why I didn't notice, and what was done to prevent it](./docs/adr-winding-and-test-data.md).
|
|
57
|
+
|
|
58
|
+
**The most likely change you need to make** is the `distance()` default. If you had:
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { distance } from '@konfirm/geojson';
|
|
62
|
+
distance(pointA, polygonB);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
you are getting a better answer now. Don't want that? Pick your fix:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
// explicit at the call site
|
|
69
|
+
distance(pointA, polygonB, 'cartesian');
|
|
70
|
+
|
|
71
|
+
// or: import the formula directly — zero call-site changes
|
|
72
|
+
import { cartesian as distance } from '@konfirm/geojson';
|
|
73
|
+
distance(pointA, polygonB);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Either way, [ask yourself whether `cartesian` is actually what you want](./MIGRATION.md#1-distance-default-formula-changed-from-cartesian-to-haversine) — for real-world coordinates it can be off by more than 50%.
|
|
77
|
+
|
|
78
|
+
## Why this over...?
|
|
79
|
+
|
|
80
|
+
The one thing most GeoJSON validators skip is winding order. [RFC 7946 §3.1.6](https://www.rfc-editor.org/rfc/rfc7946#section-3.1.6) says polygon exterior rings **must** be counterclockwise and interior rings (holes) clockwise — but virtually no public library enforces this. `isStrictPolygon` is one of the very few that does.
|
|
81
|
+
|
|
82
|
+
This has a concrete consequence: [Natural Earth](https://www.naturalearthdata.com/), the de-facto standard country dataset, [uses the opposite convention](https://github.com/nvkelso/natural-earth-vector/issues/885) and fails strict validation. That is a feature, not a bug — `isPolygon` accepts it, `isStrictPolygon` rejects it. The split lets you choose strictness without switching libraries.
|
|
83
|
+
|
|
84
|
+
| | this | @types/geojson | geojson-validation | @mapbox/geojsonhint | @mapbox/geojson-rewind | @turf/turf |
|
|
85
|
+
|---|:-:|:-:|:-:|:-:|:-:|:-:|
|
|
86
|
+
| TypeScript types | ✓ | ✓ | — | — | — | ✓ |
|
|
87
|
+
| Structural (loose) validation | ✓ | — | ✓ | ✓ | — | — |
|
|
88
|
+
| Strict validation (ranges + winding) | ✓ | — | — | — | — | — |
|
|
89
|
+
| Validation failure reasons | — | — | ✓ | ✓ | — | — |
|
|
90
|
+
| RFC 7946 winding enforcement | ✓ | — | — | — | — | — |
|
|
91
|
+
| Winding correction | — | — | — | — | ✓¹ | — |
|
|
92
|
+
| Intersection testing | ✓ | — | — | — | — | ✓ |
|
|
93
|
+
| Haversine distance | ✓ | — | — | — | — | ✓ |
|
|
94
|
+
| Vincenty distance | ✓ | — | — | — | — | — |
|
|
95
|
+
| Karney distance (always converges, ~15 nm) | ✓ | — | — | — | — | — |
|
|
96
|
+
| Spatial ops (buffer, union, simplify, …) | — | — | — | — | — | ✓ |
|
|
97
|
+
| CLI | — | — | ✓ | ✓ | ✓ | — |
|
|
98
|
+
| Zero runtime dependencies | ✓ | ✓ | ✓ | — | — | — |
|
|
99
|
+
| Active maintenance | ✓ | ✓ | — | ✓ | ✓ | ✓ |
|
|
100
|
+
|
|
101
|
+
¹ `@mapbox/geojson-rewind` defaults to clockwise exterior — the pre-RFC 7946 convention. To match RFC 7946 you must pass `rewind(geojson, false)` explicitly.
|
|
102
|
+
|
|
103
|
+
**When you should use something else instead:**
|
|
104
|
+
|
|
105
|
+
- Need spatial operations — buffer, union, difference, simplify, Voronoi, clustering? Use [Turf](https://turfjs.org/). It is a far broader library and this package does not compete with it.
|
|
106
|
+
- Need to know *why* a value failed — which ring, which coordinate, which rule? [`geojson-validation`](https://www.npmjs.com/package/geojson-validation) and [`@mapbox/geojsonhint`](https://www.npmjs.com/package/@mapbox/geojsonhint) return error strings; this package returns `boolean`.
|
|
107
|
+
- Need a CLI to lint GeoJSON files? Neither does this package; `geojsonhint` is the right tool for that.
|
|
7
108
|
|
|
8
109
|
## API
|
|
9
110
|
|
|
@@ -20,20 +121,22 @@ All [GeoJSON types](https://datatracker.ietf.org/doc/html/rfc7946#section-3.1) a
|
|
|
20
121
|
| MultiLineString | A [GeoJSON MultiLineString](https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.5) | The `coordinates` property is an array of`LineString` coordinates |
|
|
21
122
|
| Polygon | A [GeoJSON Polygon](https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.6) | The `coordinates` property is an array of "LinearRings" (closed `LineString` coordinates, where the first and last `Position` are identical) |
|
|
22
123
|
| MultiPolygon | A [GeoJSON MultiPolygon](https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.7) | The `coordinates` property is an array of `Polygon` coordinate arrays |
|
|
23
|
-
| GeometryCollection | A [GeoJSON GeometryCollection](https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.8) | geometries is an array of Geometries (`Point`, `MultiPoint`, `LineString`, `MultiLineString`, `Polygon`, `MultiPolygon`)
|
|
24
|
-
| Feature | A [GeoJSON Feature](https://datatracker.ietf.org/doc/html/rfc7946#section-3.2) | A spatially bounded
|
|
25
|
-
| FeatureCollection | A [GeoJSON Collection](https://datatracker.ietf.org/doc/html/rfc7946#section-3.3) | The `features` property is an array of `Feature` objects
|
|
124
|
+
| GeometryCollection | A [GeoJSON GeometryCollection](https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.8) | `geometries` is an array of Geometries (`Point`, `MultiPoint`, `LineString`, `MultiLineString`, `Polygon`, `MultiPolygon`). Generic: `GeometryCollection<G extends Geometry>` |
|
|
125
|
+
| Feature | A [GeoJSON Feature](https://datatracker.ietf.org/doc/html/rfc7946#section-3.2) | A spatially bounded thing with a `geometry` (`Geometry \| null`) and `properties`. Generic: `Feature<G extends Geometry \| null>` |
|
|
126
|
+
| FeatureCollection | A [GeoJSON Collection](https://datatracker.ietf.org/doc/html/rfc7946#section-3.3) | The `features` property is an array of `Feature` objects. Generic: `FeatureCollection<G extends Geometry \| null>` |
|
|
127
|
+
| Geometry | — (union type) | Union of all geometry types including `GeometryCollection`. Use `GeometryPrimitive` when you need only the six coordinate-bearing types. |
|
|
128
|
+
| GeometryPrimitive | — (union type) | The six coordinate-bearing geometry types: `Point`, `MultiPoint`, `LineString`, `MultiLineString`, `Polygon`, `MultiPolygon`. Excludes `GeometryCollection`. |
|
|
26
129
|
|
|
27
130
|
|
|
28
131
|
### Type Guards
|
|
29
132
|
|
|
30
|
-
Most of the exported functionality is based on validation of GeoJSON objects, validating required and optional (if provided) properties.
|
|
133
|
+
Most of the exported functionality is based on validation of GeoJSON objects, validating required and optional (if provided) properties.
|
|
31
134
|
The `isStrict*` variants of the type guards also validate the following:
|
|
32
135
|
- `Longitude` is a number in the range (inclusive) `-180..180`
|
|
33
136
|
- `Latitude` is a number in the range (inclusive) `-90..90`
|
|
34
137
|
- `Altitude` is a number in the range (inclusive) `-6371008.7714..20180000` (Earth center(-ish) up to the GPS satelite distance)
|
|
35
138
|
- `Polygon` "LinearRing" are closed (first and last `Position` are identical)
|
|
36
|
-
-
|
|
139
|
+
- `Polygon` "LinearRing" have the correct winding per RFC 7946 (§3.1.6): counterclockwise for exterior rings, clockwise for interior rings (holes)
|
|
37
140
|
|
|
38
141
|
|
|
39
142
|
| type | guard | strict guard | description |
|
|
@@ -46,7 +149,8 @@ The `isStrict*` variants of the type guards also validate the following:
|
|
|
46
149
|
| Polygon | `isPolygon` | `isStrictPolygon` | validate whether the input is valid GeoJSON Polygon |
|
|
47
150
|
| MultiPolygon | `isMultiPolygon` | `isStrictMultiPolygon` | validate whether the input is valid GeoJSON MultiPolygon |
|
|
48
151
|
| GeometryCollection | `isGeometryCollection` | `isStrictGeometryCollection` | validate whether the input is valid GeoJSON GeometryCollection |
|
|
49
|
-
| Geometry | `isGeometry` | `isStrictGeometry` | validate whether the input is valid GeoJSON Geometry
|
|
152
|
+
| Geometry | `isGeometry` | `isStrictGeometry` | validate whether the input is any valid GeoJSON Geometry, including `GeometryCollection` |
|
|
153
|
+
| GeometryPrimitive | `isGeometryPrimitive` | `isStrictGeometryPrimitive` | validate whether the input is one of the six coordinate-bearing geometry types (excludes `GeometryCollection`) |
|
|
50
154
|
| Feature | `isFeature` | `isStrictFeature` | validate whether the input is valid GeoJSON Feature |
|
|
51
155
|
| FeatureCollection | `isFeatureCollection` | `isStrictFeatureCollection` | validate whether the input is valid GeoJSON FeatureCollection |
|
|
52
156
|
| GeoJSON | `isGeoJSON` | `isStrictGeoJSON` | validate the input to be valid GeoJSON |
|
|
@@ -63,6 +167,30 @@ console.log('the point is a GeoJSON Point', isPoint(point)); // true, as the str
|
|
|
63
167
|
console.log('the point is a strict GeoJSON Point', isStrictPoint(point)); // false, as the coordinates are not within the specified ranges
|
|
64
168
|
```
|
|
65
169
|
|
|
170
|
+
#### Generics and narrowing
|
|
171
|
+
|
|
172
|
+
`Feature<G>`, `FeatureCollection<G>`, and `GeometryCollection<G>` are generic. The corresponding guards accept an optional second argument — a geometry guard — to narrow the inferred type:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
import { isFeature, isFeatureCollection, isGeometryCollection, isPoint, isStrictPoint } from '@konfirm/geojson';
|
|
176
|
+
|
|
177
|
+
// Without a guard: value is Feature<Geometry | null>
|
|
178
|
+
isFeature(value);
|
|
179
|
+
|
|
180
|
+
// With a guard: value is Feature<Point>
|
|
181
|
+
isFeature(value, isPoint);
|
|
182
|
+
|
|
183
|
+
// Works with strict guards and custom guards too
|
|
184
|
+
isFeature(value, isStrictPoint); // value is Feature<Point> (strict coordinates)
|
|
185
|
+
isFeatureCollection(value, isPoint); // value is FeatureCollection<Point>
|
|
186
|
+
isGeometryCollection(value, isPoint); // value is GeometryCollection<Point>
|
|
187
|
+
|
|
188
|
+
// The strict variants of the three guards accept the same optional narrowing argument
|
|
189
|
+
isStrictFeature(value, isStrictPoint); // value is Feature<Point>
|
|
190
|
+
isStrictFeatureCollection(value, isStrictPoint); // value is FeatureCollection<Point>
|
|
191
|
+
isStrictGeometryCollection(value, isStrictPoint); // value is GeometryCollection<Point>
|
|
192
|
+
```
|
|
193
|
+
|
|
66
194
|
### intersect
|
|
67
195
|
|
|
68
196
|
Verify whether the provided GeoJSON objects intersect.
|
|
@@ -93,47 +221,70 @@ console.log('feature intersects point', intersect(feature, point)); // true
|
|
|
93
221
|
|
|
94
222
|
### distance
|
|
95
223
|
|
|
96
|
-
Obtain the (shortest) distance in meters between two GeoJSON objects.
|
|
224
|
+
Obtain the (shortest) distance in meters between two GeoJSON objects. Choose a formula based on your use case:
|
|
97
225
|
|
|
98
|
-
- `
|
|
99
|
-
- `
|
|
100
|
-
- `
|
|
226
|
+
- `haversine` (**default**) — geographic lon/lat coordinates, most use cases; good accuracy, good performance
|
|
227
|
+
- `vincenty` — when you need higher accuracy than haversine and can guarantee inputs are not near-antipodal — points on nearly opposite sides of the Earth — (throws for those)
|
|
228
|
+
- `karney` — when correctness is unconditional: near-antipodal inputs, or when you simply cannot afford a wrong answer; ~15 nm accuracy on WGS84
|
|
229
|
+
- `cartesian` — when coordinates are in a metric projected system (e.g. RD New / EPSG:28992, UTM) where Euclidean distance is correct; note that projected coordinates are not valid strict GeoJSON (RFC 7946 requires geographic lon/lat, WGS84) — **do not use for geographic coordinates**
|
|
101
230
|
|
|
102
|
-
|
|
231
|
+
Each formula is also exported as a standalone function for direct use and better tree-shaking.
|
|
232
|
+
|
|
233
|
+
The formula argument accepts either a string or a custom `(a: Position, b: Position) => number` function — useful when you need a projection-specific calculation or want to plug in your own formula. The `PointToPointCalculation` type covers both and is exported for use in typed wrapper functions.
|
|
234
|
+
|
|
235
|
+
Usage: `distance(<GeoJSON>, <GeoJSON> [, <PointToPointCalculation>]): number`
|
|
103
236
|
|
|
104
237
|
```ts
|
|
105
|
-
import { distance, Feature } from '@konfirm/geojson';
|
|
238
|
+
import { distance, karney, Feature } from '@konfirm/geojson';
|
|
106
239
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const b: Feature = {
|
|
118
|
-
type: 'Feature',
|
|
119
|
-
properties: {
|
|
120
|
-
name: 'John F. Kennedy International Airport, New York',
|
|
121
|
-
},
|
|
122
|
-
geometry: {
|
|
123
|
-
type: 'Point',
|
|
124
|
-
coordinates: [-73.778889, 40.639722],
|
|
125
|
-
},
|
|
126
|
-
};
|
|
240
|
+
const a: Feature = {
|
|
241
|
+
type: 'Feature',
|
|
242
|
+
properties: { name: 'Schiphol Airport, Amsterdam' },
|
|
243
|
+
geometry: { type: 'Point', coordinates: [4.763889, 52.308333] },
|
|
244
|
+
};
|
|
245
|
+
const b: Feature = {
|
|
246
|
+
type: 'Feature',
|
|
247
|
+
properties: { name: 'John F. Kennedy International Airport, New York' },
|
|
248
|
+
geometry: { type: 'Point', coordinates: [-73.778889, 40.639722] },
|
|
249
|
+
};
|
|
127
250
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
251
|
+
console.log(distance(a, b)); // 5847546.425707642 ('haversine' is the default)
|
|
252
|
+
console.log(distance(a, b, 'haversine')); // 5847546.425707642
|
|
253
|
+
console.log(distance(a, b, 'vincenty')); // 5863355.371234315
|
|
254
|
+
console.log(distance(a, b, 'karney')); // 5863355.371221913
|
|
255
|
+
console.log(distance(a, b, 'cartesian')); // 8829424.604594177
|
|
256
|
+
|
|
257
|
+
console.log(karney(a, b)); // 5863355.371221913 — same as distance(a, b, 'karney')
|
|
132
258
|
```
|
|
133
259
|
|
|
260
|
+
#### Accuracy versus performance
|
|
261
|
+
|
|
262
|
+
This library's karney implementation matches Karney's own GeographicLib C++ reference within 1 nm on average and 11 nm at worst, across 500,000 test cases — close enough to use as the accuracy benchmark below.
|
|
263
|
+
A result is counted as **wrong** when it deviates from the benchmark by more than 10.0 m. Throws count as wrong too.
|
|
264
|
+
|
|
265
|
+
Performance: karney shows absolute µs/call on this machine; other formulas show speed relative to karney (~Nx = N times faster) — ratios are more portable across machines than absolute times.
|
|
266
|
+
|
|
267
|
+
| band | n | karney | vincenty | haversine | cartesian |
|
|
268
|
+
| --- | ---: | --- | --- | --- | --- |
|
|
269
|
+
| <1 m | 45 | none · 13.2 µs | none · ~23x | none · ~53x | **4.4% · ~86x** |
|
|
270
|
+
| <10 m | 375 | none · 1.87 µs | none · ~4x | none · ~12x | 14.4% · ~20x |
|
|
271
|
+
| <100 m | 3,980 | none · 1.84 µs | none · ~4x | none · ~12x | 42.9% · ~20x |
|
|
272
|
+
| <1 km | 40,523 | none · 2.00 µs | none · ~4x | none · ~13x | 73.0% · ~21x |
|
|
273
|
+
| <10 km | 5,125 | none · 2.18 µs | none · ~4x | **0.3% · ~14x** | 81.3% · ~22x |
|
|
274
|
+
| <25 km | 78 | none · 2.41 µs | none · ~4x | 96.2% · ~12x | 96.2% · ~20x |
|
|
275
|
+
| <50 km | 108 | none · 2.68 µs | none · ~4x | 97.2% · ~14x | 98.1% · ~23x |
|
|
276
|
+
| <100 km | 239 | none · 2.20 µs | none · ~4x | 99.6% · ~13x | 99.6% · ~24x |
|
|
277
|
+
| <1 000 km | 5,371 | none · 2.32 µs | none · ~4x | 99.9% · ~14x | 99.9% · ~25x |
|
|
278
|
+
| <10 000 km | 119,455 | none · 2.90 µs | none · ~4x | 100.0% · ~14x | 100.0% · ~30x |
|
|
279
|
+
| <15 000 km | 77,875 | none · 3.06 µs | **none · ~4x** | 100.0% · ~16x | 100.0% · ~31x |
|
|
280
|
+
| >15 000 km | 146,826 | none · 2.68 µs | 19.8% · ~4x | 100.0% · ~14x | 100.0% · ~27x |
|
|
281
|
+
| near-antipodal | 100,000 | none · 3.25 µs | 34.9% · ~1x | 99.9% · ~18x | 100.0% · ~31x |
|
|
282
|
+
|
|
283
|
+
Run your own numbers: `npm run compare:formulas -- --threshold <metres>` (current: 10 m)
|
|
284
|
+
|
|
134
285
|
### SimpleGeometryIterator
|
|
135
286
|
|
|
136
|
-
The SimpleGeometryIterator class is a
|
|
287
|
+
The SimpleGeometryIterator class is a helper utility that flattens any GeoJSON input — including nested `FeatureCollection` and `GeometryCollection` — into a flat sequence of simple geometries (`Point`, `LineString`, `Polygon`). Multi-geometry types are split into their individual components. The original structure is never modified and no intermediate arrays are built.
|
|
137
288
|
|
|
138
289
|
| input type | yields type(s) | description |
|
|
139
290
|
| -------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
@@ -237,9 +388,13 @@ const simplified = [...new SimpleGeometryIterator(multipoint, geometrycollection
|
|
|
237
388
|
*/
|
|
238
389
|
```
|
|
239
390
|
|
|
391
|
+
## Contributing
|
|
392
|
+
|
|
393
|
+
Contributions are welcome — see [CONTRIBUTING.md](./CONTRIBUTING.md) for how to get started. To report a vulnerability, see [SECURITY.md](./SECURITY.md).
|
|
394
|
+
|
|
240
395
|
## License
|
|
241
396
|
|
|
242
|
-
MIT License Copyright (c) 2021-
|
|
397
|
+
MIT License Copyright (c) 2021-2026 Rogier Spieker (Konfirm)
|
|
243
398
|
|
|
244
399
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
245
400
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -257,4 +412,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
257
412
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
258
413
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
259
414
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
260
|
-
SOFTWARE.
|
|
415
|
+
SOFTWARE.
|
package/dist/main.d.mts
CHANGED
|
@@ -7,9 +7,9 @@ type Latitude = number;
|
|
|
7
7
|
|
|
8
8
|
type Longitude = number;
|
|
9
9
|
|
|
10
|
-
type Position = [Longitude, Latitude, Altitude
|
|
11
|
-
declare const isPosition: _konfirm_guard.Guard<
|
|
12
|
-
declare const isStrictPosition: _konfirm_guard.Guard<
|
|
10
|
+
type Position = [Longitude, Latitude, Altitude?, ...Array<unknown>];
|
|
11
|
+
declare const isPosition: _konfirm_guard.Guard<[number, number, (number | undefined)?, ...unknown[]]>;
|
|
12
|
+
declare const isStrictPosition: _konfirm_guard.Guard<[number, number, (number | undefined)?, ...unknown[]]>;
|
|
13
13
|
|
|
14
14
|
type BoundingBox = [Longitude, Latitude, Altitude, Longitude, Latitude, Altitude] | [Longitude, Latitude, Longitude, Latitude];
|
|
15
15
|
|
|
@@ -68,33 +68,35 @@ type MultiPolygon = MultiGeometryObject<Polygon>;
|
|
|
68
68
|
declare const isMultiPolygon: _konfirm_guard.Guard<MultiPolygon>;
|
|
69
69
|
declare const isStrictMultiPolygon: _konfirm_guard.Guard<MultiPolygon>;
|
|
70
70
|
|
|
71
|
-
type
|
|
72
|
-
declare const
|
|
73
|
-
declare const
|
|
74
|
-
|
|
75
|
-
type GeometryCollection = GeoJSONObject<{
|
|
71
|
+
type GeometryPrimitive = Point | MultiPoint | LineString | MultiLineString | Polygon | MultiPolygon;
|
|
72
|
+
declare const isGeometryPrimitive: Guard<GeometryPrimitive>;
|
|
73
|
+
declare const isStrictGeometryPrimitive: Guard<GeometryPrimitive>;
|
|
74
|
+
type GeometryCollection<G extends GeometryPrimitive = GeometryPrimitive> = GeoJSONObject<{
|
|
76
75
|
type: 'GeometryCollection';
|
|
77
|
-
geometries: Array<
|
|
76
|
+
geometries: Array<G | GeometryCollection<G>>;
|
|
78
77
|
}>;
|
|
79
|
-
|
|
80
|
-
declare
|
|
78
|
+
type Geometry = GeometryPrimitive | GeometryCollection;
|
|
79
|
+
declare const isGeometry: Guard<Geometry>;
|
|
80
|
+
declare const isStrictGeometry: Guard<Geometry>;
|
|
81
|
+
declare function isGeometryCollection<G extends GeometryPrimitive = GeometryPrimitive>(value: unknown, isG?: Guard<G>): value is GeometryCollection<G>;
|
|
82
|
+
declare function isStrictGeometryCollection<G extends GeometryPrimitive = GeometryPrimitive>(value: unknown, isG?: Guard<G>): value is GeometryCollection<G>;
|
|
81
83
|
|
|
82
|
-
type Feature = GeoJSONObject<{
|
|
84
|
+
type Feature<G extends Geometry | null = Geometry | null> = GeoJSONObject<{
|
|
83
85
|
type: 'Feature';
|
|
84
|
-
geometry:
|
|
86
|
+
geometry: G;
|
|
85
87
|
properties: {
|
|
86
88
|
[key: string]: unknown;
|
|
87
89
|
} | null;
|
|
88
90
|
}>;
|
|
89
|
-
declare
|
|
90
|
-
declare
|
|
91
|
+
declare function isFeature<G extends Geometry | null>(input: unknown, isG?: Guard<G>): input is Feature<G>;
|
|
92
|
+
declare function isStrictFeature<G extends Geometry | null>(input: unknown, isG?: Guard<G>): input is Feature<G>;
|
|
91
93
|
|
|
92
|
-
type FeatureCollection = GeoJSONObject<{
|
|
94
|
+
type FeatureCollection<G extends Geometry | null = Geometry | null> = GeoJSONObject<{
|
|
93
95
|
type: 'FeatureCollection';
|
|
94
|
-
features: Array<Feature
|
|
96
|
+
features: Array<Feature<G>>;
|
|
95
97
|
}>;
|
|
96
|
-
declare
|
|
97
|
-
declare
|
|
98
|
+
declare function isFeatureCollection<G extends Geometry | null>(value: unknown, isG?: Guard<G>): value is FeatureCollection<G>;
|
|
99
|
+
declare function isStrictFeatureCollection<G extends Geometry | null>(value: unknown, isG?: Guard<G>): value is FeatureCollection<G>;
|
|
98
100
|
|
|
99
101
|
type GeoJSON = Geometry | GeometryCollection | Feature | FeatureCollection;
|
|
100
102
|
declare const isGeoJSON: _konfirm_guard.Guard<GeoJSON>;
|
|
@@ -128,10 +130,14 @@ declare class SimpleGeometryIterator {
|
|
|
128
130
|
private unwrap;
|
|
129
131
|
}
|
|
130
132
|
|
|
131
|
-
type PointToPointCalculation = 'cartesian' | 'haversine' | 'vincenty' | ((a: Point['coordinates'], b: Point['coordinates']) => number);
|
|
133
|
+
type PointToPointCalculation = 'cartesian' | 'haversine' | 'vincenty' | 'karney' | ((a: Point['coordinates'], b: Point['coordinates']) => number);
|
|
132
134
|
|
|
135
|
+
declare function cartesian(a: GeoJSON, b: GeoJSON): number;
|
|
136
|
+
declare function haversine(a: GeoJSON, b: GeoJSON): number;
|
|
137
|
+
declare function vincenty(a: GeoJSON, b: GeoJSON): number;
|
|
138
|
+
declare function karney(a: GeoJSON, b: GeoJSON): number;
|
|
133
139
|
declare function distance(a: GeoJSON, b: GeoJSON, calculation?: PointToPointCalculation): number;
|
|
134
140
|
|
|
135
141
|
declare function intersect(a: GeoJSON, b: GeoJSON): boolean;
|
|
136
142
|
|
|
137
|
-
export { type Feature, type FeatureCollection, type GeoJSON, type Geometry, type GeometryCollection, type LineString, type MultiLineString, type MultiPoint, type MultiPolygon, type Point, type Polygon, type Position, SimpleGeometryIterator, distance, intersect, isFeature, isFeatureCollection, isGeoJSON, isGeometry, isGeometryCollection, isLineString, isMultiLineString, isMultiPoint, isMultiPolygon, isPoint, isPolygon, isPosition, isStrictFeature, isStrictFeatureCollection, isStrictGeoJSON, isStrictGeometry, isStrictGeometryCollection, isStrictLineString, isStrictMultiLineString, isStrictMultiPoint, isStrictMultiPolygon, isStrictPoint, isStrictPolygon, isStrictPosition };
|
|
143
|
+
export { type Feature, type FeatureCollection, type GeoJSON, type Geometry, type GeometryCollection, type GeometryPrimitive, type LineString, type MultiLineString, type MultiPoint, type MultiPolygon, type Point, type Polygon, type Position, SimpleGeometryIterator, cartesian, distance, haversine, intersect, isFeature, isFeatureCollection, isGeoJSON, isGeometry, isGeometryCollection, isGeometryPrimitive, isLineString, isMultiLineString, isMultiPoint, isMultiPolygon, isPoint, isPolygon, isPosition, isStrictFeature, isStrictFeatureCollection, isStrictGeoJSON, isStrictGeometry, isStrictGeometryCollection, isStrictGeometryPrimitive, isStrictLineString, isStrictMultiLineString, isStrictMultiPoint, isStrictMultiPolygon, isStrictPoint, isStrictPolygon, isStrictPosition, karney, vincenty };
|
package/dist/main.d.ts
CHANGED
|
@@ -7,9 +7,9 @@ type Latitude = number;
|
|
|
7
7
|
|
|
8
8
|
type Longitude = number;
|
|
9
9
|
|
|
10
|
-
type Position = [Longitude, Latitude, Altitude
|
|
11
|
-
declare const isPosition: _konfirm_guard.Guard<
|
|
12
|
-
declare const isStrictPosition: _konfirm_guard.Guard<
|
|
10
|
+
type Position = [Longitude, Latitude, Altitude?, ...Array<unknown>];
|
|
11
|
+
declare const isPosition: _konfirm_guard.Guard<[number, number, (number | undefined)?, ...unknown[]]>;
|
|
12
|
+
declare const isStrictPosition: _konfirm_guard.Guard<[number, number, (number | undefined)?, ...unknown[]]>;
|
|
13
13
|
|
|
14
14
|
type BoundingBox = [Longitude, Latitude, Altitude, Longitude, Latitude, Altitude] | [Longitude, Latitude, Longitude, Latitude];
|
|
15
15
|
|
|
@@ -68,33 +68,35 @@ type MultiPolygon = MultiGeometryObject<Polygon>;
|
|
|
68
68
|
declare const isMultiPolygon: _konfirm_guard.Guard<MultiPolygon>;
|
|
69
69
|
declare const isStrictMultiPolygon: _konfirm_guard.Guard<MultiPolygon>;
|
|
70
70
|
|
|
71
|
-
type
|
|
72
|
-
declare const
|
|
73
|
-
declare const
|
|
74
|
-
|
|
75
|
-
type GeometryCollection = GeoJSONObject<{
|
|
71
|
+
type GeometryPrimitive = Point | MultiPoint | LineString | MultiLineString | Polygon | MultiPolygon;
|
|
72
|
+
declare const isGeometryPrimitive: Guard<GeometryPrimitive>;
|
|
73
|
+
declare const isStrictGeometryPrimitive: Guard<GeometryPrimitive>;
|
|
74
|
+
type GeometryCollection<G extends GeometryPrimitive = GeometryPrimitive> = GeoJSONObject<{
|
|
76
75
|
type: 'GeometryCollection';
|
|
77
|
-
geometries: Array<
|
|
76
|
+
geometries: Array<G | GeometryCollection<G>>;
|
|
78
77
|
}>;
|
|
79
|
-
|
|
80
|
-
declare
|
|
78
|
+
type Geometry = GeometryPrimitive | GeometryCollection;
|
|
79
|
+
declare const isGeometry: Guard<Geometry>;
|
|
80
|
+
declare const isStrictGeometry: Guard<Geometry>;
|
|
81
|
+
declare function isGeometryCollection<G extends GeometryPrimitive = GeometryPrimitive>(value: unknown, isG?: Guard<G>): value is GeometryCollection<G>;
|
|
82
|
+
declare function isStrictGeometryCollection<G extends GeometryPrimitive = GeometryPrimitive>(value: unknown, isG?: Guard<G>): value is GeometryCollection<G>;
|
|
81
83
|
|
|
82
|
-
type Feature = GeoJSONObject<{
|
|
84
|
+
type Feature<G extends Geometry | null = Geometry | null> = GeoJSONObject<{
|
|
83
85
|
type: 'Feature';
|
|
84
|
-
geometry:
|
|
86
|
+
geometry: G;
|
|
85
87
|
properties: {
|
|
86
88
|
[key: string]: unknown;
|
|
87
89
|
} | null;
|
|
88
90
|
}>;
|
|
89
|
-
declare
|
|
90
|
-
declare
|
|
91
|
+
declare function isFeature<G extends Geometry | null>(input: unknown, isG?: Guard<G>): input is Feature<G>;
|
|
92
|
+
declare function isStrictFeature<G extends Geometry | null>(input: unknown, isG?: Guard<G>): input is Feature<G>;
|
|
91
93
|
|
|
92
|
-
type FeatureCollection = GeoJSONObject<{
|
|
94
|
+
type FeatureCollection<G extends Geometry | null = Geometry | null> = GeoJSONObject<{
|
|
93
95
|
type: 'FeatureCollection';
|
|
94
|
-
features: Array<Feature
|
|
96
|
+
features: Array<Feature<G>>;
|
|
95
97
|
}>;
|
|
96
|
-
declare
|
|
97
|
-
declare
|
|
98
|
+
declare function isFeatureCollection<G extends Geometry | null>(value: unknown, isG?: Guard<G>): value is FeatureCollection<G>;
|
|
99
|
+
declare function isStrictFeatureCollection<G extends Geometry | null>(value: unknown, isG?: Guard<G>): value is FeatureCollection<G>;
|
|
98
100
|
|
|
99
101
|
type GeoJSON = Geometry | GeometryCollection | Feature | FeatureCollection;
|
|
100
102
|
declare const isGeoJSON: _konfirm_guard.Guard<GeoJSON>;
|
|
@@ -128,10 +130,14 @@ declare class SimpleGeometryIterator {
|
|
|
128
130
|
private unwrap;
|
|
129
131
|
}
|
|
130
132
|
|
|
131
|
-
type PointToPointCalculation = 'cartesian' | 'haversine' | 'vincenty' | ((a: Point['coordinates'], b: Point['coordinates']) => number);
|
|
133
|
+
type PointToPointCalculation = 'cartesian' | 'haversine' | 'vincenty' | 'karney' | ((a: Point['coordinates'], b: Point['coordinates']) => number);
|
|
132
134
|
|
|
135
|
+
declare function cartesian(a: GeoJSON, b: GeoJSON): number;
|
|
136
|
+
declare function haversine(a: GeoJSON, b: GeoJSON): number;
|
|
137
|
+
declare function vincenty(a: GeoJSON, b: GeoJSON): number;
|
|
138
|
+
declare function karney(a: GeoJSON, b: GeoJSON): number;
|
|
133
139
|
declare function distance(a: GeoJSON, b: GeoJSON, calculation?: PointToPointCalculation): number;
|
|
134
140
|
|
|
135
141
|
declare function intersect(a: GeoJSON, b: GeoJSON): boolean;
|
|
136
142
|
|
|
137
|
-
export { type Feature, type FeatureCollection, type GeoJSON, type Geometry, type GeometryCollection, type LineString, type MultiLineString, type MultiPoint, type MultiPolygon, type Point, type Polygon, type Position, SimpleGeometryIterator, distance, intersect, isFeature, isFeatureCollection, isGeoJSON, isGeometry, isGeometryCollection, isLineString, isMultiLineString, isMultiPoint, isMultiPolygon, isPoint, isPolygon, isPosition, isStrictFeature, isStrictFeatureCollection, isStrictGeoJSON, isStrictGeometry, isStrictGeometryCollection, isStrictLineString, isStrictMultiLineString, isStrictMultiPoint, isStrictMultiPolygon, isStrictPoint, isStrictPolygon, isStrictPosition };
|
|
143
|
+
export { type Feature, type FeatureCollection, type GeoJSON, type Geometry, type GeometryCollection, type GeometryPrimitive, type LineString, type MultiLineString, type MultiPoint, type MultiPolygon, type Point, type Polygon, type Position, SimpleGeometryIterator, cartesian, distance, haversine, intersect, isFeature, isFeatureCollection, isGeoJSON, isGeometry, isGeometryCollection, isGeometryPrimitive, isLineString, isMultiLineString, isMultiPoint, isMultiPolygon, isPoint, isPolygon, isPosition, isStrictFeature, isStrictFeatureCollection, isStrictGeoJSON, isStrictGeometry, isStrictGeometryCollection, isStrictGeometryPrimitive, isStrictLineString, isStrictMultiLineString, isStrictMultiPoint, isStrictMultiPolygon, isStrictPoint, isStrictPolygon, isStrictPosition, karney, vincenty };
|