Skip to content

Instantly share code, notes, and snippets.

@mrummuka
Last active May 25, 2020 20:10
Show Gist options
  • Save mrummuka/b70b9a9fb0825b4bace91a4b6d6b1257 to your computer and use it in GitHub Desktop.
Save mrummuka/b70b9a9fb0825b4bace91a4b6d6b1257 to your computer and use it in GitHub Desktop.
const MYSTERY_RADIUS = 3.218; // km
const CACHE_RADIUS = 0.160; // km (WAS: 0.1609)
// resolution for how dense the created points will be (target: one gps decimal)
// var cellSide = 0.00001666666667; // if I calculated correctly this should have been enough, but apparently I didn't so doubling the precision for tests
const cellSide = 0.000006;
// converts decimal degree value into array of degrees, minutes and minute decimals (gps)
// todo: range checks
function l_dd2d_m_dec(val) {
var valDeg, valMin, valMinDec, valDec, result = [];
valDeg = Math.floor( Math.abs(val) );
result.push( (Math.sign(val) * valDeg).toString() );
valMinDec = (( Math.abs(val) - valDeg) * 60);
valMin = Math.floor( valMinDec );
if( valMin < 10 ) {
result.push( "0" + valMin.toString() );
}
else {
result.push( valMin.toString() );
}
valDec = (valMinDec - valMin).toFixed(3).substring(2,5);
result.push( valDec );
return result;
}
function l_dd2dm(val) {
var valDeg, valMin, result;
if(val < 0) {
valDeg = Math.ceil( val );
result = valDeg.toString();
}
else {
valDeg = Math.floor( val );
result = valDeg.toString();
}
result += " ";
valMin = ( ( Math.abs(val) - Math.abs(valDeg) ) * 60).toFixed(3);
if( valMin < 10 ) {
result += "0";
}
result += valMin;
return result;
}
function generatePoints( fc ) {
// only one new featurecollection for gathering all the created waypoints as currently we don't really need (do we?) separation of waypoints between different polygons (i.e. labelling of regions)
let wps_fc = new turf.featureCollection( [] );
// generate waypoints within every hand-drawn region to wps_fc
// for every feature
fc.features.forEach( feat => {
// TODO: think if there should be a better way (e.g. labelling regions when drawing?)
// .. that is hand-drawn polygon, AND has NO description property
if( feat.geometry.type == "Polygon" ) {
// first create bounding box for each
let region_bbox = turf.bbox( feat );
// set mask to hand-drawn polygon
var opt = { units: 'degrees', mask : feat };
// generate set of waypoints cellSide distance apart from each other
var wpfc = turf.pointGrid( region_bbox, cellSide, opt);
// merge all features of all featurecollections to one featurecollection // PREFERRED WAY
// hack: just append the features to an existing array
wps_fc.features = wps_fc.features.concat( wpfc.features );
}
})
return wps_fc;
}
// find feature of bruteforce origo
function getBogus( fc ) {
return fc.features.find( feat => feat.properties.desc == "bruteforce" )
}
// find all features that are cache wps (excluding bruteforce cache's bogus)
function getCaches1( fc ) {
let known_caches = fc.features.filter( feat =>
(feat.properties.type == "Geocache|Traditional Cache" && (feat.properties.sym == "Geocache" || feat.properties.sym == "Geocache Found") )
|| feat.properties.sym == "Physical Stage"
|| feat.properties.sym == "Final Location"
)
return known_caches;
}
// find all features that are cache wps (excluding bruteforce cache's bogus)
function getCaches2( fc ) {
let known_caches = fc.features.filter( feat => feat.properties.sym == "triangle")
return known_caches;
}
// remove all waypoints from generated waypoints (features) in wps_fc that are either too far from bogus or too close to other caches cache
// todo: ignore this to option?
function removeOverlapping( wps_fc, bogus, caches ) {
let wps_ok;
if( bogus == undefined ) {
wps_ok = wps_fc.features.filter( feat =>
caches.find( cache => turf.distance(turf.getGeom(cache), turf.getGeom(feat)) < CACHE_RADIUS ) == undefined
)
}
else {
wps_ok = wps_fc.features.filter( feat =>
caches.find( cache => turf.distance(turf.getGeom(cache), turf.getGeom(feat)) < CACHE_RADIUS ) == undefined &&
turf.distance( turf.getGeom(bogus), turf.getGeom(feat) ) < MYSTERY_RADIUS
)
}
let wps_ok_fc = turf.featureCollection( wps_ok );
return wps_ok_fc;
}
// Sheets visualization preparation:
// TODO: perhaps instead of coordEach simple for each feature would be better approach..
// adds various gps latlon formattings as property for csv conversion and easier sheets visualization
// OBS! modifes feature collection object given as parameter
function addVisProperties( fc ) {
turf.coordEach( fc, function (currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex) {
//=currentCoord
//=coordIndex
//=featureIndex
//=multiFeatureIndex
//=geometryIndex
// convert all dd coordinates into degress-decimalminutes and store them into properties
//TODO: here I want to get
// 1: geo.fi checker compatible seaprate vvalues
latgps = l_dd2d_m_dec( currentCoord[1] );
fc.features[featureIndex].properties.latdeg = latgps[0];
fc.features[featureIndex].properties.latmin = latgps[1];
fc.features[featureIndex].properties.latdec = latgps[2];
longps = l_dd2d_m_dec( currentCoord[0] );
fc.features[featureIndex].properties.londeg = longps[0];
fc.features[featureIndex].properties.lonmin = longps[1];
fc.features[featureIndex].properties.londec = longps[2];
// 2: com checker compatible one latlon string
fc.features[featureIndex].properties.gps = l_dd2dm(currentCoord[1]) + " " + l_dd2dm(currentCoord[0]);
// 3: script compatible one string with ; at end
// TODO
// 4: ??
//wps_ok_fc.features[featureIndex].properties.latlongpsplain = [ l_dd2dm_plain(currentCoord[1]), l_dd2dm_plain(currentCoord[0]) ];
});
return fc;
}
// generate subset of features which have unique coordinates (on GPS coordinate resolution) i.e. remove unnecessary duplicates from generated wps
function removeDuplicates( wps_ok_fc ) {
let uniqueWpMap = new Map();
wps_ok_fc.features.forEach( f => {
let crd = turf.getCoord( f );
// use string of gps coordinates as key to reduce the total number of features to unique ones only
let gpsCrdStr = JSON.stringify( [l_dd2dm(crd[1]), l_dd2dm(crd[0]) ] );
uniqueWpMap.set( gpsCrdStr, f )
} );
let uniqueWps = [];
let uniqueCrds = [];
// push map values (i.e. features that have been reduced so that their coordinates are unique on gps resolution) back to an array
uniqueWpMap.forEach( (value,key) => {
uniqueWps.push( value );
uniqueCrds.push( key ); // for sanity check, also push the keys, i.e. gps coordinates
} );
// and map these features back to new feature collection for geojson creation
let unique_wps_fc = turf.featureCollection( uniqueWps );
return unique_wps_fc;
}
function generateUniqueWps( fc ) {
let generated = generatePoints( fc );
let bogus = getBogus( fc );
let caches = getCaches2( fc );
let filteredWps = removeOverlapping( generated, bogus, caches );
let visWps = addVisProperties( filteredWps );
let uniqueWps = removeDuplicates( visWps );
return uniqueWps;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment