James Beard e7227f51b7
Preliminary improvements to documentation, esp internal types e.g. Units (#2727)
* Added JSDoc for internal types and constants e.g. Unts and earthRadius. Minimal other changes to bring JSDoc types into line with code types. Added GeoJsonProperties to documentation.yml for type linking.

* Generated README.md files based on updated source that now includes JSDoc for internal types and constants e.g. Units. Also synced up some out of data JSDoc types with what is in the code.

* Switched the structure of documentation.yml to be more traditionally nested. We'll use this new structure from the turf-www repo to generate the website documentation in a more robust manner.

* For some reason leaving this function documented as the default (geojsonRbush) causes @turf/turf last-checks to fail. Specifically defining it as rbush like it used to be, except with the @function tag rather than @name.
2024-10-11 12:56:42 +11:00

125 lines
3.6 KiB
TypeScript

import { Feature, Geometry, Position } from "geojson";
import { getGeom } from "@turf/invariant";
import { polygon, lineString } from "@turf/helpers";
import { booleanDisjoint } from "@turf/boolean-disjoint";
import { booleanCrosses } from "@turf/boolean-crosses";
import { lineIntersect } from "@turf/line-intersect";
import { booleanPointOnLine as isPointOnLine } from "@turf/boolean-point-on-line";
/**
* booleanValid checks if the geometry is a valid according to the OGC Simple Feature Specification.
*
* @function
* @param {Geometry|Feature<any>} feature GeoJSON Feature or Geometry
* @returns {boolean} true/false
* @example
* var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]);
*
* turf.booleanValid(line); // => true
* turf.booleanValid({foo: "bar"}); // => false
*/
function booleanValid(feature: Feature<any> | Geometry) {
// Automatic False
if (!feature.type) return false;
// Parse GeoJSON
const geom = getGeom(feature);
const type = geom.type;
const coords = geom.coordinates;
switch (type) {
case "Point":
return coords.length > 1;
case "MultiPoint":
for (var i = 0; i < coords.length; i++) {
if (coords[i].length < 2) return false;
}
return true;
case "LineString":
if (coords.length < 2) return false;
for (var i = 0; i < coords.length; i++) {
if (coords[i].length < 2) return false;
}
return true;
case "MultiLineString":
if (coords.length < 2) return false;
for (var i = 0; i < coords.length; i++) {
if (coords[i].length < 2) return false;
}
return true;
case "Polygon":
for (var i = 0; i < geom.coordinates.length; i++) {
if (coords[i].length < 4) return false;
if (!checkRingsClose(coords[i])) return false;
if (checkRingsForSpikesPunctures(coords[i])) return false;
if (i > 0) {
if (
lineIntersect(polygon([coords[0]]), polygon([coords[i]])).features
.length > 1
)
return false;
}
}
return true;
case "MultiPolygon":
for (var i = 0; i < geom.coordinates.length; i++) {
var poly: any = geom.coordinates[i];
for (var ii = 0; ii < poly.length; ii++) {
if (poly[ii].length < 4) return false;
if (!checkRingsClose(poly[ii])) return false;
if (checkRingsForSpikesPunctures(poly[ii])) return false;
if (ii === 0) {
if (!checkPolygonAgainstOthers(poly, geom.coordinates, i))
return false;
}
if (ii > 0) {
if (
lineIntersect(polygon([poly[0]]), polygon([poly[ii]])).features
.length > 1
)
return false;
}
}
}
return true;
default:
return false;
}
}
function checkRingsClose(geom: Position[]) {
return (
geom[0][0] === geom[geom.length - 1][0] &&
geom[0][1] === geom[geom.length - 1][1]
);
}
function checkRingsForSpikesPunctures(geom: Position[]) {
for (var i = 0; i < geom.length - 1; i++) {
var point = geom[i];
for (var ii = i + 1; ii < geom.length - 2; ii++) {
var seg = [geom[ii], geom[ii + 1]];
if (isPointOnLine(point, lineString(seg))) return true;
}
}
return false;
}
function checkPolygonAgainstOthers(
poly: Position[][],
geom: Position[][][],
index: number
) {
var polyToCheck = polygon(poly);
for (var i = index + 1; i < geom.length; i++) {
if (!booleanDisjoint(polyToCheck, polygon(geom[i]))) {
if (booleanCrosses(polyToCheck, lineString(geom[i][0]))) return false;
}
}
return true;
}
export { booleanValid };
export default booleanValid;