Created
September 9, 2015 10:07
-
-
Save blemoine/6ea25402b37e9830f6ca to your computer and use it in GitHub Desktop.
Compressing GeoJSON with informations loss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
pour lancer : | |
node geoJsonMinifier.js <cheminDuFichierGeoJson> > <cheminDuFichierDeSorti> | |
*/ | |
var fs = require('fs'); | |
var _ = require('lodash'); | |
var geoJsonPath = process.argv[2]; | |
if (!geoJsonPath) { | |
console.error("You must pass a path to a geoJson file", geoJsonPath); | |
return; | |
} | |
fs.readFile(geoJsonPath, function (err, geoJsonContent) { | |
if (err) { | |
console.error("Error while reading file", err); | |
return; | |
} | |
var geoJson = JSON.parse(geoJsonContent); | |
if (geoJson.type != 'FeatureCollection') { | |
console.error("The type of the geoJsonContent must be FeatureCollection", geoJson.type); | |
return; | |
} | |
console.log(JSON.stringify(minifyGeoJson(geoJson))); | |
}); | |
function minifyGeoJson(geoJson) { | |
var minifiedFeatures = geoJson.features.map(function (feature) { | |
var minifyCoordinate = _.flow(decreasePrecision(3), removeDuplicatePoint); | |
var newCoordinates = minifyCoordinate(feature.geometry.coordinates); | |
return { | |
"type": "Feature", | |
"id": feature.id, | |
"properties": feature.properties, | |
"geometry": { | |
"type": feature.geometry.type, | |
"coordinates": newCoordinates | |
} | |
}; | |
}); | |
return { | |
"type": "FeatureCollection", | |
"features": minifiedFeatures | |
} | |
} | |
function isCoordinate(maybeCoordinates) { | |
return _.isArray(maybeCoordinates) && maybeCoordinates.length == 2 && _.isNumber(maybeCoordinates[0]) && _.isNumber(maybeCoordinates[1]) | |
} | |
function removeDuplicatePoint(arr) { | |
var arrSize = arr.length; | |
return arr.map(function(el) { | |
if(_.isArray(el) ) { | |
if(el.every(isCoordinate)) { | |
var elSize = el.length; | |
return el.filter(function(coordinates, idx) { | |
//Minus 2 beacause we want at least 3 points | |
if(idx > 0 && idx < elSize - 2) { | |
return distanceBetweenCoordinates(coordinates, el[idx - 1]) > 100 | |
} else { | |
return true; | |
} | |
}); | |
} else { | |
return removeDuplicatePoint(el); | |
} | |
} else { | |
return el; | |
} | |
}) | |
} | |
function decreasePrecision(precision) { | |
return function _decreasePrecision(arr) { | |
var tenFactor = Math.pow(10, precision); | |
return arr.map(function (el) { | |
if (_.isArray(el)) { | |
return _decreasePrecision(el); | |
} else if (_.isNumber(el)) { | |
return Math.round(el * tenFactor) / tenFactor; | |
} else { | |
return el; | |
} | |
}) | |
} | |
} | |
function toRadians(n) { | |
return n * Math.PI / 180; | |
} | |
function distanceBetweenCoordinates(coord1, coord2) { | |
var lon1 = coord1[0]; | |
var lat1 = coord1[1]; | |
var lon2 = coord2[0]; | |
var lat2 = coord2[1]; | |
var R = 6371000; // earth radius in meters | |
var φ1 = toRadians(lat1); | |
var φ2 = toRadians(lat2); | |
var Δφ = toRadians(lat2-lat1); | |
var Δλ = toRadians(lon2-lon1); | |
var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) + | |
Math.cos(φ1) * Math.cos(φ2) * | |
Math.sin(Δλ/2) * Math.sin(Δλ/2); | |
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); | |
return R * c; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment