@trackunit/geo-json-utils 1.14.66 → 1.14.67-alpha-636ec415cd1.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/index.cjs.js +77 -61
- package/index.esm.js +76 -62
- package/package.json +1 -1
- package/src/GeoJsonGeometryUtils.d.ts +18 -1
- package/src/GeoJsonSchemas.d.ts +2 -0
- package/src/GeoJsonUtils.d.ts +4 -2
package/index.cjs.js
CHANGED
|
@@ -29,6 +29,66 @@ const isPositionInsideRing = (point, ring) => {
|
|
|
29
29
|
}
|
|
30
30
|
return inside;
|
|
31
31
|
};
|
|
32
|
+
/**
|
|
33
|
+
* Hole-aware point-in-polygon: true when the point is inside the exterior ring
|
|
34
|
+
* and outside every hole ring (RFC 7946 Section 3.1.6).
|
|
35
|
+
*
|
|
36
|
+
* This is an unvalidated, performance-optimized version of
|
|
37
|
+
* `isGeoJsonPointInPolygon` for use in hot rendering paths.
|
|
38
|
+
*/
|
|
39
|
+
const isPointInPolygon = (point, polygon) => {
|
|
40
|
+
const [exteriorRing, ...holeRings] = polygon.coordinates;
|
|
41
|
+
if (!exteriorRing) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
if (!isPositionInsideRing(point, exteriorRing)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return !holeRings.some(hole => isPositionInsideRing(point, hole));
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Whether every outer-ring vertex of `geom1` lies inside `geom2` (holes respected;
|
|
51
|
+
* for a MultiPolygon `geom2`, "inside" means inside any one member). A degenerate
|
|
52
|
+
* `geom1` with no outer rings is contained in nothing.
|
|
53
|
+
*
|
|
54
|
+
* This is an unvalidated, performance-optimized version of
|
|
55
|
+
* `isFullyContainedInGeoJsonGeometry` for use in hot rendering paths.
|
|
56
|
+
*/
|
|
57
|
+
const isFullyContainedInGeometry = (geom1, geom2) => {
|
|
58
|
+
const outerRings1 = [];
|
|
59
|
+
if (geom1.type === "Polygon") {
|
|
60
|
+
const outerRing = geom1.coordinates[0];
|
|
61
|
+
if (outerRing)
|
|
62
|
+
outerRings1.push(outerRing);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
for (const poly of geom1.coordinates) {
|
|
66
|
+
const outerRing = poly[0];
|
|
67
|
+
if (outerRing)
|
|
68
|
+
outerRings1.push(outerRing);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (outerRings1.length === 0) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
const polygonParts2 = [];
|
|
75
|
+
if (geom2.type === "Polygon") {
|
|
76
|
+
polygonParts2.push(geom2);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
for (const poly of geom2.coordinates) {
|
|
80
|
+
polygonParts2.push({ type: "Polygon", coordinates: poly });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
for (const outerRing of outerRings1) {
|
|
84
|
+
for (const position of outerRing) {
|
|
85
|
+
if (!polygonParts2.some(part => isPointInPolygon(position, part))) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return true;
|
|
91
|
+
};
|
|
32
92
|
/**
|
|
33
93
|
* Check if a bounding box is fully inside any polygon in a feature collection.
|
|
34
94
|
* All four corners of the bbox must be inside the same polygon and outside
|
|
@@ -403,12 +463,14 @@ const geoJsonPolygonSchema = zod.z.object({
|
|
|
403
463
|
});
|
|
404
464
|
/**
|
|
405
465
|
* MultiPolygon geometry object.
|
|
466
|
+
* Each member is a Polygon coordinate array and must have at least one ring
|
|
467
|
+
* (its exterior ring), per RFC 7946 Sections 3.1.6/3.1.7.
|
|
406
468
|
* Foreign members (RFC 7946 Section 6.1) are stripped during parse.
|
|
407
469
|
* https://tools.ietf.org/html/rfc7946#section-3.1.7
|
|
408
470
|
*/
|
|
409
471
|
const geoJsonMultiPolygonSchema = zod.z.object({
|
|
410
472
|
type: zod.z.literal("MultiPolygon"),
|
|
411
|
-
coordinates: zod.z.array(zod.z.array(geoJsonLinearRingSchema)),
|
|
473
|
+
coordinates: zod.z.array(zod.z.array(geoJsonLinearRingSchema).min(1)),
|
|
412
474
|
bbox: geoJsonBboxSchema.optional(),
|
|
413
475
|
});
|
|
414
476
|
/**
|
|
@@ -1170,37 +1232,15 @@ const isGeoJsonPositionInLinearRing = ({ position, linearRing, }) => {
|
|
|
1170
1232
|
* @description Checks if a point is inside a polygon.
|
|
1171
1233
|
* Correctly handles holes per RFC 7946 Section 3.1.6: the first ring is the
|
|
1172
1234
|
* exterior boundary, subsequent rings are holes. A point inside a hole is
|
|
1173
|
-
* considered outside the polygon.
|
|
1235
|
+
* considered outside the polygon. Validates, then delegates to the pure
|
|
1236
|
+
* `isPointInPolygon`.
|
|
1174
1237
|
*/
|
|
1175
1238
|
const isGeoJsonPointInPolygon = ({ point, polygon, }) => {
|
|
1176
1239
|
const polygonParsed = geoJsonPolygonSchema.safeParse(polygon);
|
|
1177
1240
|
if (!polygonParsed.success) {
|
|
1178
1241
|
return null;
|
|
1179
1242
|
}
|
|
1180
|
-
|
|
1181
|
-
if (!exteriorRing) {
|
|
1182
|
-
return null;
|
|
1183
|
-
}
|
|
1184
|
-
// Explicit null checks are intentional: isGeoJsonPositionInLinearRing returns
|
|
1185
|
-
// boolean | null, and using it directly in boolean expressions like
|
|
1186
|
-
// `!result` or `.some()` would silently treat null as false/truthy, masking errors.
|
|
1187
|
-
const insideExterior = isGeoJsonPositionInLinearRing({ position: point.coordinates, linearRing: exteriorRing });
|
|
1188
|
-
if (insideExterior === null) {
|
|
1189
|
-
return null;
|
|
1190
|
-
}
|
|
1191
|
-
if (!insideExterior) {
|
|
1192
|
-
return false;
|
|
1193
|
-
}
|
|
1194
|
-
for (const hole of holeRings) {
|
|
1195
|
-
const insideHole = isGeoJsonPositionInLinearRing({ position: point.coordinates, linearRing: hole });
|
|
1196
|
-
if (insideHole === null) {
|
|
1197
|
-
return null;
|
|
1198
|
-
}
|
|
1199
|
-
if (insideHole) {
|
|
1200
|
-
return false;
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
return true;
|
|
1243
|
+
return isPointInPolygon(point.coordinates, polygonParsed.data);
|
|
1204
1244
|
};
|
|
1205
1245
|
/**
|
|
1206
1246
|
* Checks if polygon1 is fully contained within polygon2.
|
|
@@ -1423,63 +1463,37 @@ const unprojectPolygonalFromWebMercator = (geometry) => mapPolygonalCoordinates(
|
|
|
1423
1463
|
* Generalisation of isFullyContainedInGeoJsonPolygon to Polygon|MultiPolygon arguments.
|
|
1424
1464
|
* Returns true when every outer-ring vertex of geom1 lies inside geom2 (holes respected).
|
|
1425
1465
|
* For a MultiPolygon geom2, "inside" means inside any one of its polygon members.
|
|
1426
|
-
* Returns null if either geometry fails validation.
|
|
1466
|
+
* Returns null if either geometry fails validation. Once validated, delegates to
|
|
1467
|
+
* the pure `isFullyContainedInGeometry`.
|
|
1427
1468
|
*/
|
|
1428
1469
|
const isFullyContainedInGeoJsonGeometry = (geom1, geom2) => {
|
|
1429
|
-
|
|
1470
|
+
let validGeom1;
|
|
1430
1471
|
if (geom1.type === "Polygon") {
|
|
1431
1472
|
const parsed = geoJsonPolygonSchema.safeParse(geom1);
|
|
1432
1473
|
if (!parsed.success)
|
|
1433
1474
|
return null;
|
|
1434
|
-
|
|
1435
|
-
if (!outerRing)
|
|
1436
|
-
return null;
|
|
1437
|
-
outerRings1.push(outerRing);
|
|
1475
|
+
validGeom1 = parsed.data;
|
|
1438
1476
|
}
|
|
1439
1477
|
else {
|
|
1440
1478
|
const parsed = geoJsonMultiPolygonSchema.safeParse(geom1);
|
|
1441
1479
|
if (!parsed.success)
|
|
1442
1480
|
return null;
|
|
1443
|
-
|
|
1444
|
-
const outerRing = poly[0];
|
|
1445
|
-
if (!outerRing)
|
|
1446
|
-
return null;
|
|
1447
|
-
outerRings1.push(outerRing);
|
|
1448
|
-
}
|
|
1481
|
+
validGeom1 = parsed.data;
|
|
1449
1482
|
}
|
|
1450
|
-
|
|
1483
|
+
let validGeom2;
|
|
1451
1484
|
if (geom2.type === "Polygon") {
|
|
1452
1485
|
const parsed = geoJsonPolygonSchema.safeParse(geom2);
|
|
1453
1486
|
if (!parsed.success)
|
|
1454
1487
|
return null;
|
|
1455
|
-
|
|
1488
|
+
validGeom2 = parsed.data;
|
|
1456
1489
|
}
|
|
1457
1490
|
else {
|
|
1458
1491
|
const parsed = geoJsonMultiPolygonSchema.safeParse(geom2);
|
|
1459
1492
|
if (!parsed.success)
|
|
1460
1493
|
return null;
|
|
1461
|
-
|
|
1462
|
-
polygonParts2.push({ type: "Polygon", coordinates: poly });
|
|
1463
|
-
}
|
|
1494
|
+
validGeom2 = parsed.data;
|
|
1464
1495
|
}
|
|
1465
|
-
|
|
1466
|
-
for (const position of outerRing) {
|
|
1467
|
-
const point = { coordinates: position };
|
|
1468
|
-
let insideAny = false;
|
|
1469
|
-
for (const part of polygonParts2) {
|
|
1470
|
-
const result = isGeoJsonPointInPolygon({ point, polygon: part });
|
|
1471
|
-
if (result === null)
|
|
1472
|
-
return null;
|
|
1473
|
-
if (result) {
|
|
1474
|
-
insideAny = true;
|
|
1475
|
-
break;
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
if (!insideAny)
|
|
1479
|
-
return false;
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
return true;
|
|
1496
|
+
return isFullyContainedInGeometry(validGeom1, validGeom2);
|
|
1483
1497
|
};
|
|
1484
1498
|
/**
|
|
1485
1499
|
* Returns the minimum distance (in coordinate units) from the given position to the
|
|
@@ -1919,8 +1933,10 @@ exports.getPolygonFromPointAndRadius = getPolygonFromPointAndRadius;
|
|
|
1919
1933
|
exports.isBboxInsideFeatureCollection = isBboxInsideFeatureCollection;
|
|
1920
1934
|
exports.isFullyContainedInGeoJsonGeometry = isFullyContainedInGeoJsonGeometry;
|
|
1921
1935
|
exports.isFullyContainedInGeoJsonPolygon = isFullyContainedInGeoJsonPolygon;
|
|
1936
|
+
exports.isFullyContainedInGeometry = isFullyContainedInGeometry;
|
|
1922
1937
|
exports.isGeoJsonPointInPolygon = isGeoJsonPointInPolygon;
|
|
1923
1938
|
exports.isGeoJsonPositionInLinearRing = isGeoJsonPositionInLinearRing;
|
|
1939
|
+
exports.isPointInPolygon = isPointInPolygon;
|
|
1924
1940
|
exports.isPositionInsideRing = isPositionInsideRing;
|
|
1925
1941
|
exports.lngLatToMercatorPxWS = lngLatToMercatorPxWS;
|
|
1926
1942
|
exports.lngLatToWebMercatorPx = lngLatToWebMercatorPx;
|
package/index.esm.js
CHANGED
|
@@ -27,6 +27,66 @@ const isPositionInsideRing = (point, ring) => {
|
|
|
27
27
|
}
|
|
28
28
|
return inside;
|
|
29
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* Hole-aware point-in-polygon: true when the point is inside the exterior ring
|
|
32
|
+
* and outside every hole ring (RFC 7946 Section 3.1.6).
|
|
33
|
+
*
|
|
34
|
+
* This is an unvalidated, performance-optimized version of
|
|
35
|
+
* `isGeoJsonPointInPolygon` for use in hot rendering paths.
|
|
36
|
+
*/
|
|
37
|
+
const isPointInPolygon = (point, polygon) => {
|
|
38
|
+
const [exteriorRing, ...holeRings] = polygon.coordinates;
|
|
39
|
+
if (!exteriorRing) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
if (!isPositionInsideRing(point, exteriorRing)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
return !holeRings.some(hole => isPositionInsideRing(point, hole));
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Whether every outer-ring vertex of `geom1` lies inside `geom2` (holes respected;
|
|
49
|
+
* for a MultiPolygon `geom2`, "inside" means inside any one member). A degenerate
|
|
50
|
+
* `geom1` with no outer rings is contained in nothing.
|
|
51
|
+
*
|
|
52
|
+
* This is an unvalidated, performance-optimized version of
|
|
53
|
+
* `isFullyContainedInGeoJsonGeometry` for use in hot rendering paths.
|
|
54
|
+
*/
|
|
55
|
+
const isFullyContainedInGeometry = (geom1, geom2) => {
|
|
56
|
+
const outerRings1 = [];
|
|
57
|
+
if (geom1.type === "Polygon") {
|
|
58
|
+
const outerRing = geom1.coordinates[0];
|
|
59
|
+
if (outerRing)
|
|
60
|
+
outerRings1.push(outerRing);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
for (const poly of geom1.coordinates) {
|
|
64
|
+
const outerRing = poly[0];
|
|
65
|
+
if (outerRing)
|
|
66
|
+
outerRings1.push(outerRing);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (outerRings1.length === 0) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const polygonParts2 = [];
|
|
73
|
+
if (geom2.type === "Polygon") {
|
|
74
|
+
polygonParts2.push(geom2);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
for (const poly of geom2.coordinates) {
|
|
78
|
+
polygonParts2.push({ type: "Polygon", coordinates: poly });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
for (const outerRing of outerRings1) {
|
|
82
|
+
for (const position of outerRing) {
|
|
83
|
+
if (!polygonParts2.some(part => isPointInPolygon(position, part))) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
};
|
|
30
90
|
/**
|
|
31
91
|
* Check if a bounding box is fully inside any polygon in a feature collection.
|
|
32
92
|
* All four corners of the bbox must be inside the same polygon and outside
|
|
@@ -401,12 +461,14 @@ const geoJsonPolygonSchema = z.object({
|
|
|
401
461
|
});
|
|
402
462
|
/**
|
|
403
463
|
* MultiPolygon geometry object.
|
|
464
|
+
* Each member is a Polygon coordinate array and must have at least one ring
|
|
465
|
+
* (its exterior ring), per RFC 7946 Sections 3.1.6/3.1.7.
|
|
404
466
|
* Foreign members (RFC 7946 Section 6.1) are stripped during parse.
|
|
405
467
|
* https://tools.ietf.org/html/rfc7946#section-3.1.7
|
|
406
468
|
*/
|
|
407
469
|
const geoJsonMultiPolygonSchema = z.object({
|
|
408
470
|
type: z.literal("MultiPolygon"),
|
|
409
|
-
coordinates: z.array(z.array(geoJsonLinearRingSchema)),
|
|
471
|
+
coordinates: z.array(z.array(geoJsonLinearRingSchema).min(1)),
|
|
410
472
|
bbox: geoJsonBboxSchema.optional(),
|
|
411
473
|
});
|
|
412
474
|
/**
|
|
@@ -1168,37 +1230,15 @@ const isGeoJsonPositionInLinearRing = ({ position, linearRing, }) => {
|
|
|
1168
1230
|
* @description Checks if a point is inside a polygon.
|
|
1169
1231
|
* Correctly handles holes per RFC 7946 Section 3.1.6: the first ring is the
|
|
1170
1232
|
* exterior boundary, subsequent rings are holes. A point inside a hole is
|
|
1171
|
-
* considered outside the polygon.
|
|
1233
|
+
* considered outside the polygon. Validates, then delegates to the pure
|
|
1234
|
+
* `isPointInPolygon`.
|
|
1172
1235
|
*/
|
|
1173
1236
|
const isGeoJsonPointInPolygon = ({ point, polygon, }) => {
|
|
1174
1237
|
const polygonParsed = geoJsonPolygonSchema.safeParse(polygon);
|
|
1175
1238
|
if (!polygonParsed.success) {
|
|
1176
1239
|
return null;
|
|
1177
1240
|
}
|
|
1178
|
-
|
|
1179
|
-
if (!exteriorRing) {
|
|
1180
|
-
return null;
|
|
1181
|
-
}
|
|
1182
|
-
// Explicit null checks are intentional: isGeoJsonPositionInLinearRing returns
|
|
1183
|
-
// boolean | null, and using it directly in boolean expressions like
|
|
1184
|
-
// `!result` or `.some()` would silently treat null as false/truthy, masking errors.
|
|
1185
|
-
const insideExterior = isGeoJsonPositionInLinearRing({ position: point.coordinates, linearRing: exteriorRing });
|
|
1186
|
-
if (insideExterior === null) {
|
|
1187
|
-
return null;
|
|
1188
|
-
}
|
|
1189
|
-
if (!insideExterior) {
|
|
1190
|
-
return false;
|
|
1191
|
-
}
|
|
1192
|
-
for (const hole of holeRings) {
|
|
1193
|
-
const insideHole = isGeoJsonPositionInLinearRing({ position: point.coordinates, linearRing: hole });
|
|
1194
|
-
if (insideHole === null) {
|
|
1195
|
-
return null;
|
|
1196
|
-
}
|
|
1197
|
-
if (insideHole) {
|
|
1198
|
-
return false;
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
return true;
|
|
1241
|
+
return isPointInPolygon(point.coordinates, polygonParsed.data);
|
|
1202
1242
|
};
|
|
1203
1243
|
/**
|
|
1204
1244
|
* Checks if polygon1 is fully contained within polygon2.
|
|
@@ -1421,63 +1461,37 @@ const unprojectPolygonalFromWebMercator = (geometry) => mapPolygonalCoordinates(
|
|
|
1421
1461
|
* Generalisation of isFullyContainedInGeoJsonPolygon to Polygon|MultiPolygon arguments.
|
|
1422
1462
|
* Returns true when every outer-ring vertex of geom1 lies inside geom2 (holes respected).
|
|
1423
1463
|
* For a MultiPolygon geom2, "inside" means inside any one of its polygon members.
|
|
1424
|
-
* Returns null if either geometry fails validation.
|
|
1464
|
+
* Returns null if either geometry fails validation. Once validated, delegates to
|
|
1465
|
+
* the pure `isFullyContainedInGeometry`.
|
|
1425
1466
|
*/
|
|
1426
1467
|
const isFullyContainedInGeoJsonGeometry = (geom1, geom2) => {
|
|
1427
|
-
|
|
1468
|
+
let validGeom1;
|
|
1428
1469
|
if (geom1.type === "Polygon") {
|
|
1429
1470
|
const parsed = geoJsonPolygonSchema.safeParse(geom1);
|
|
1430
1471
|
if (!parsed.success)
|
|
1431
1472
|
return null;
|
|
1432
|
-
|
|
1433
|
-
if (!outerRing)
|
|
1434
|
-
return null;
|
|
1435
|
-
outerRings1.push(outerRing);
|
|
1473
|
+
validGeom1 = parsed.data;
|
|
1436
1474
|
}
|
|
1437
1475
|
else {
|
|
1438
1476
|
const parsed = geoJsonMultiPolygonSchema.safeParse(geom1);
|
|
1439
1477
|
if (!parsed.success)
|
|
1440
1478
|
return null;
|
|
1441
|
-
|
|
1442
|
-
const outerRing = poly[0];
|
|
1443
|
-
if (!outerRing)
|
|
1444
|
-
return null;
|
|
1445
|
-
outerRings1.push(outerRing);
|
|
1446
|
-
}
|
|
1479
|
+
validGeom1 = parsed.data;
|
|
1447
1480
|
}
|
|
1448
|
-
|
|
1481
|
+
let validGeom2;
|
|
1449
1482
|
if (geom2.type === "Polygon") {
|
|
1450
1483
|
const parsed = geoJsonPolygonSchema.safeParse(geom2);
|
|
1451
1484
|
if (!parsed.success)
|
|
1452
1485
|
return null;
|
|
1453
|
-
|
|
1486
|
+
validGeom2 = parsed.data;
|
|
1454
1487
|
}
|
|
1455
1488
|
else {
|
|
1456
1489
|
const parsed = geoJsonMultiPolygonSchema.safeParse(geom2);
|
|
1457
1490
|
if (!parsed.success)
|
|
1458
1491
|
return null;
|
|
1459
|
-
|
|
1460
|
-
polygonParts2.push({ type: "Polygon", coordinates: poly });
|
|
1461
|
-
}
|
|
1492
|
+
validGeom2 = parsed.data;
|
|
1462
1493
|
}
|
|
1463
|
-
|
|
1464
|
-
for (const position of outerRing) {
|
|
1465
|
-
const point = { coordinates: position };
|
|
1466
|
-
let insideAny = false;
|
|
1467
|
-
for (const part of polygonParts2) {
|
|
1468
|
-
const result = isGeoJsonPointInPolygon({ point, polygon: part });
|
|
1469
|
-
if (result === null)
|
|
1470
|
-
return null;
|
|
1471
|
-
if (result) {
|
|
1472
|
-
insideAny = true;
|
|
1473
|
-
break;
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
if (!insideAny)
|
|
1477
|
-
return false;
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
return true;
|
|
1494
|
+
return isFullyContainedInGeometry(validGeom1, validGeom2);
|
|
1481
1495
|
};
|
|
1482
1496
|
/**
|
|
1483
1497
|
* Returns the minimum distance (in coordinate units) from the given position to the
|
|
@@ -1875,4 +1889,4 @@ const edgePixelLength = (x0, y0, x1, y1, zoom, midLatDeg, tileSize = 256) => {
|
|
|
1875
1889
|
return Math.sqrt(dxPx * dxPx + dyPx * dyPx);
|
|
1876
1890
|
};
|
|
1877
1891
|
|
|
1878
|
-
export { EARTH_RADIUS, EMPTY_FEATURE_COLLECTION, boundingBoxCrossesMeridian, checkCrossesMeridian, computeGeometryCentroid, coordinatesToStandardFormat, denormalizeLongitude, distanceToGeoJsonPolygonBoundary, edgePixelLength, extractEdges, extractFirstPointCoordinate, extractPositionsFromGeometry, geoJsonBboxSchema, geoJsonFeatureCollectionSchema, geoJsonFeatureSchema, geoJsonGeometryCollectionSchema, geoJsonGeometrySchema, geoJsonLineStringSchema, geoJsonLinearRingSchema, geoJsonMultiLineStringSchema, geoJsonMultiPointSchema, geoJsonMultiPolygonSchema, geoJsonPointSchema, geoJsonPolygonDifference, geoJsonPolygonSchema, geoJsonPosition2dSchema, geoJsonPositionSchema, getBboxFromGeoJsonPolygon, getBoundingBoxFromGeoJsonBbox, getBoundingBoxFromGeoJsonPolygon, getExtremeGeoJsonPointFromPolygon, getGeoJsonPolygonFromBoundingBox, getGeoJsonPolygonIntersection, getMinMaxLongitudes, getMultipleCoordinatesFromGeoJsonObject, getPointCoordinateFromGeoJsonObject, getPointCoordinateFromGeoJsonPoint, getPolygonFromBbox, getPolygonFromPointAndRadius, isBboxInsideFeatureCollection, isFullyContainedInGeoJsonGeometry, isFullyContainedInGeoJsonPolygon, isGeoJsonPointInPolygon, isGeoJsonPositionInLinearRing, isPositionInsideRing, lngLatToMercatorPxWS, lngLatToWebMercatorPx, mercatorPxToLngLatWS, normalizeLongitudes, padGeoJsonBbox, pixelsToLatDegrees, projectLngLatToWebMercator, projectPolygonalToWebMercator, scaleGeoJsonBbox, splitPolygonAtAntimeridian, splitPolygonWithHolesAtAntimeridian, toFeatureCollection, toPosition2d, tuGeoJsonPointRadiusSchema, tuGeoJsonPolygonNoHolesSchema, tuGeoJsonRectangularBoxPolygonSchema, unprojectPolygonalFromWebMercator, unprojectWebMercatorToLngLat, validateBbox, validateBboxWithFallback, validateFeatureCollection, validatePosition, webMercatorPxToLngLat };
|
|
1892
|
+
export { EARTH_RADIUS, EMPTY_FEATURE_COLLECTION, boundingBoxCrossesMeridian, checkCrossesMeridian, computeGeometryCentroid, coordinatesToStandardFormat, denormalizeLongitude, distanceToGeoJsonPolygonBoundary, edgePixelLength, extractEdges, extractFirstPointCoordinate, extractPositionsFromGeometry, geoJsonBboxSchema, geoJsonFeatureCollectionSchema, geoJsonFeatureSchema, geoJsonGeometryCollectionSchema, geoJsonGeometrySchema, geoJsonLineStringSchema, geoJsonLinearRingSchema, geoJsonMultiLineStringSchema, geoJsonMultiPointSchema, geoJsonMultiPolygonSchema, geoJsonPointSchema, geoJsonPolygonDifference, geoJsonPolygonSchema, geoJsonPosition2dSchema, geoJsonPositionSchema, getBboxFromGeoJsonPolygon, getBoundingBoxFromGeoJsonBbox, getBoundingBoxFromGeoJsonPolygon, getExtremeGeoJsonPointFromPolygon, getGeoJsonPolygonFromBoundingBox, getGeoJsonPolygonIntersection, getMinMaxLongitudes, getMultipleCoordinatesFromGeoJsonObject, getPointCoordinateFromGeoJsonObject, getPointCoordinateFromGeoJsonPoint, getPolygonFromBbox, getPolygonFromPointAndRadius, isBboxInsideFeatureCollection, isFullyContainedInGeoJsonGeometry, isFullyContainedInGeoJsonPolygon, isFullyContainedInGeometry, isGeoJsonPointInPolygon, isGeoJsonPositionInLinearRing, isPointInPolygon, isPositionInsideRing, lngLatToMercatorPxWS, lngLatToWebMercatorPx, mercatorPxToLngLatWS, normalizeLongitudes, padGeoJsonBbox, pixelsToLatDegrees, projectLngLatToWebMercator, projectPolygonalToWebMercator, scaleGeoJsonBbox, splitPolygonAtAntimeridian, splitPolygonWithHolesAtAntimeridian, toFeatureCollection, toPosition2d, tuGeoJsonPointRadiusSchema, tuGeoJsonPolygonNoHolesSchema, tuGeoJsonRectangularBoxPolygonSchema, unprojectPolygonalFromWebMercator, unprojectWebMercatorToLngLat, validateBbox, validateBboxWithFallback, validateFeatureCollection, validatePosition, webMercatorPxToLngLat };
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GeoJsonBbox, GeoJsonFeatureCollection, GeoJsonGeometry, GeoJsonPosition } from "./GeoJsonSchemas";
|
|
1
|
+
import type { GeoJsonBbox, GeoJsonFeatureCollection, GeoJsonGeometry, GeoJsonMultiPolygon, GeoJsonPolygon, GeoJsonPosition } from "./GeoJsonSchemas";
|
|
2
2
|
type Edge = readonly [GeoJsonPosition, GeoJsonPosition];
|
|
3
3
|
/**
|
|
4
4
|
* Ray-casting point-in-polygon test for a single coordinate ring.
|
|
@@ -8,6 +8,23 @@ type Edge = readonly [GeoJsonPosition, GeoJsonPosition];
|
|
|
8
8
|
* `isGeoJsonPositionInLinearRing` for use in hot rendering paths.
|
|
9
9
|
*/
|
|
10
10
|
export declare const isPositionInsideRing: (point: GeoJsonPosition, ring: ReadonlyArray<GeoJsonPosition>) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Hole-aware point-in-polygon: true when the point is inside the exterior ring
|
|
13
|
+
* and outside every hole ring (RFC 7946 Section 3.1.6).
|
|
14
|
+
*
|
|
15
|
+
* This is an unvalidated, performance-optimized version of
|
|
16
|
+
* `isGeoJsonPointInPolygon` for use in hot rendering paths.
|
|
17
|
+
*/
|
|
18
|
+
export declare const isPointInPolygon: (point: GeoJsonPosition, polygon: GeoJsonPolygon) => boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Whether every outer-ring vertex of `geom1` lies inside `geom2` (holes respected;
|
|
21
|
+
* for a MultiPolygon `geom2`, "inside" means inside any one member). A degenerate
|
|
22
|
+
* `geom1` with no outer rings is contained in nothing.
|
|
23
|
+
*
|
|
24
|
+
* This is an unvalidated, performance-optimized version of
|
|
25
|
+
* `isFullyContainedInGeoJsonGeometry` for use in hot rendering paths.
|
|
26
|
+
*/
|
|
27
|
+
export declare const isFullyContainedInGeometry: (geom1: GeoJsonPolygon | GeoJsonMultiPolygon, geom2: GeoJsonPolygon | GeoJsonMultiPolygon) => boolean;
|
|
11
28
|
/**
|
|
12
29
|
* Check if a bounding box is fully inside any polygon in a feature collection.
|
|
13
30
|
* All four corners of the bbox must be inside the same polygon and outside
|
package/src/GeoJsonSchemas.d.ts
CHANGED
|
@@ -140,6 +140,8 @@ export declare const geoJsonPolygonSchema: z.ZodObject<{
|
|
|
140
140
|
export type GeoJsonPolygon = z.infer<typeof geoJsonPolygonSchema>;
|
|
141
141
|
/**
|
|
142
142
|
* MultiPolygon geometry object.
|
|
143
|
+
* Each member is a Polygon coordinate array and must have at least one ring
|
|
144
|
+
* (its exterior ring), per RFC 7946 Sections 3.1.6/3.1.7.
|
|
143
145
|
* Foreign members (RFC 7946 Section 6.1) are stripped during parse.
|
|
144
146
|
* https://tools.ietf.org/html/rfc7946#section-3.1.7
|
|
145
147
|
*/
|
package/src/GeoJsonUtils.d.ts
CHANGED
|
@@ -84,7 +84,8 @@ export declare const isGeoJsonPositionInLinearRing: ({ position, linearRing, }:
|
|
|
84
84
|
* @description Checks if a point is inside a polygon.
|
|
85
85
|
* Correctly handles holes per RFC 7946 Section 3.1.6: the first ring is the
|
|
86
86
|
* exterior boundary, subsequent rings are holes. A point inside a hole is
|
|
87
|
-
* considered outside the polygon.
|
|
87
|
+
* considered outside the polygon. Validates, then delegates to the pure
|
|
88
|
+
* `isPointInPolygon`.
|
|
88
89
|
*/
|
|
89
90
|
export declare const isGeoJsonPointInPolygon: ({ point, polygon, }: {
|
|
90
91
|
point: GeoJsonPoint;
|
|
@@ -167,7 +168,8 @@ export declare const unprojectPolygonalFromWebMercator: (geometry: GeoJsonPolygo
|
|
|
167
168
|
* Generalisation of isFullyContainedInGeoJsonPolygon to Polygon|MultiPolygon arguments.
|
|
168
169
|
* Returns true when every outer-ring vertex of geom1 lies inside geom2 (holes respected).
|
|
169
170
|
* For a MultiPolygon geom2, "inside" means inside any one of its polygon members.
|
|
170
|
-
* Returns null if either geometry fails validation.
|
|
171
|
+
* Returns null if either geometry fails validation. Once validated, delegates to
|
|
172
|
+
* the pure `isFullyContainedInGeometry`.
|
|
171
173
|
*/
|
|
172
174
|
export declare const isFullyContainedInGeoJsonGeometry: (geom1: GeoJsonPolygon | GeoJsonMultiPolygon, geom2: GeoJsonPolygon | GeoJsonMultiPolygon) => boolean | null;
|
|
173
175
|
/**
|