Skip to content

Instantly share code, notes, and snippets.

@reinvantveer
Last active November 9, 2015 12:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reinvantveer/8c3dd817c70ff0304482 to your computer and use it in GitHub Desktop.
Save reinvantveer/8c3dd817c70ff0304482 to your computer and use it in GitHub Desktop.
JavaScript Topology Suite wrapper functions to validate GeoJSON features
'use strict';
var jsts = require('jsts');
var geometryFactory = new jsts.geom.GeometryFactory();
var reader = new jsts.io.GeoJSONReader();
// Proper attribution:
// adapted from http://stackoverflow.com/questions/25017463/google-maps-polygons-self-intersecting-detection
var findSelfIntersects = function(geoJSONPolygon) {
var jstsGeometry = reader.read(geoJSONPolygon.geometry);
// if the geometry is aleady a simple linear ring, do not
// try to find self intersection points.
if (jstsGeometry) {
var validator = new jsts.operation.IsSimpleOp(jstsGeometry);
if (validator.isSimpleLinearGeometry(jstsGeometry)) {
return;
}
var res = {};
var graph = new jsts.geomgraph.GeometryGraph(0, jstsGeometry);
var cat = new jsts.operation.valid.ConsistentAreaTester(graph);
var r = cat.isNodeConsistentArea();
if (!r) {
res = cat.getInvalidPoint();
}
return res;
}
};
function isSimpleGeoJSON(geoJSONPolygon){
var jstsGeometry = reader.read(geoJSONPolygon.geometry);
if (jstsGeometry) {
var validator = new jsts.operation.IsSimpleOp(jstsGeometry);
return validator.isSimple();
}
}
function isValidGeoJSON(geoJSONPolygon){
var jstsGeometry = reader.read(geoJSONPolygon.geometry);
if (jstsGeometry) {
var validator = new jsts.operation.valid.IsValidOp(jstsGeometry);
return validator.isValid();
}
}
var geojson = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": { name: 'My non-simple hourglass-shaped geometry' },
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
5.614013671875,
52.47608904123904
],
[
6.35009765625,
52.93539665862318
],
[
6.8939208984375,
52.13011607781287
],
[
7.239990234375,
52.65639394198803
],
[
5.614013671875,
52.47608904123904
]
]
]
}
},
{
"type": "Feature",
"properties": { name: "my valid geometry"},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
6.558837890625,
52.97180028087252
],
[
6.536865234375,
53.1039189119836
],
[
7.22625732421875,
53.08412692217884
],
[
7.21527099609375,
52.91552722044141
],
[
6.558837890625,
52.97180028087252
]
]
]
}
},
{
"type": "Feature",
"properties": {
"name": "My double hourglass shape"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
5.811767578125,
53.19451575316597
],
[
5.6744384765625,
53.19451575316597
],
[
5.67169189453125,
52.9751081817353
],
[
5.809020996093749,
52.99990936843343
],
[
5.9326171875,
53.21096737507053
],
[
6.031494140625,
53.21425694166793
],
[
6.185302734375,
52.985030365232305
],
[
6.451721191406249,
52.96849212681396
],
[
6.46270751953125,
53.199451902831555
],
[
6.24298095703125,
53.207677555890015
],
[
6.031494140625,
52.994950270267985
],
[
5.9161376953125,
52.993297110978936
],
[
5.811767578125,
53.19451575316597
]
]
]
}
},
{
"type": "Feature",
"properties": {
"name": "One point for good measure"
},
"geometry": {
"type": "Point",
"coordinates": [
6.611022949218749,
52.82766141733736
]
}
}
]
};
geojson.features.forEach(
function validateEachFeature(feature, index, array) {
console.log("Processing feature: " + index);
var result = findSelfIntersects(feature);
if (result) {
var jstsPoint = geometryFactory.createPoint(result);
var writer = new jsts.io.GeoJSONWriter();
var geojsonResult = writer.write(jstsPoint);
console.log("Self-intersection found at GeoJSON point: " + JSON.stringify(geojsonResult));
} else {
console.log("No self-intersection found");
}
console.log("Is a Simple Feature: " + isSimpleGeoJSON(feature));
console.log("Is a valid feature: " + isValidGeoJSON(feature) + "\n");
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment