Last active
February 22, 2016 14:04
-
-
Save tomfun/431434bc026b143a65d3 to your computer and use it in GitHub Desktop.
rough location filter with same minimum/maximum lattitude/longitude range
This file contains hidden or 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
"use strict"; | |
const EARTH_RADIUS = 6371; | |
function degToRad(deg) { | |
return deg * Math.PI / 180; | |
} | |
/** | |
* @param {Number} distance km | |
* @returns {Number} | |
*/ | |
function approximateLatitude(distance) { | |
return 180 * distance / EARTH_RADIUS / Math.PI; | |
} | |
/** | |
* Return min/max lat/lon for approximately search by coordinates | |
* | |
* @param {Number} distance MUST be fixed for caching, km | |
* @param {Number} latitude search point center | |
* @param {Number} longitude search point center | |
* @returns {{latMin: number, latMax: number, lonMin: number, lonMax: number, latIgnore: boolean, lonIgnore: boolean}} | |
*/ | |
function approximateDistance(distance, latitude, longitude) { | |
const lat = parseFloat(latitude); | |
const lon = parseFloat(longitude); | |
const deltaLat = approximateLatitude(distance);//сдвиг по широте | |
let tmpLon = Math.abs(lat) + deltaLat; | |
const resMinLat = Math.floor((lat - deltaLat) / deltaLat) * deltaLat; | |
const resMaxLat = Math.ceil((lat + deltaLat) / deltaLat) * deltaLat; | |
tmpLon = Math.ceil(tmpLon / deltaLat) * deltaLat;//ближе к экватору | |
if (tmpLon > 90) { | |
tmpLon = 90; | |
} | |
const r = EARTH_RADIUS * Math.cos(degToRad(tmpLon)); | |
const deltaLon = 360 * distance / (Math.PI * r * 2); | |
const resMaxLon = Math.ceil((lon + deltaLon) / deltaLon) * deltaLon; | |
const resMinLon = Math.floor((lon - deltaLon) / deltaLon) * deltaLon; | |
return { | |
//latMin: resMinLat < -90 ? -90 : resMinLat, | |
//latMax: resMaxLat > 90 ? 90 : resMaxLat, | |
//lonMin: resMinLon < -180 ? -180 : resMinLon, | |
//lonMax: resMaxLon > 180 ? 180 : resMaxLon | |
latMin: resMinLat, | |
latMax: resMaxLat, | |
lonMin: resMinLon, | |
lonMax: resMaxLon, | |
latIgnore: deltaLat >= 90, | |
lonIgnore: deltaLon >= 180 | |
}; | |
} | |
function getDistanceFromLatLonInKm(lat1, lon1, lat2, lon2) { | |
var R = 6371; // Radius of the earth in km | |
var dLat = deg2rad(lat2 - lat1); // deg2rad below | |
var dLon = deg2rad(lon2 - lon1); | |
var a = | |
Math.sin(dLat / 2) * Math.sin(dLat / 2) + | |
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * | |
Math.sin(dLon / 2) * Math.sin(dLon / 2) | |
; | |
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); | |
var d = R * c; // Distance in km | |
return d; | |
} | |
function deg2rad(deg) { | |
return deg * (Math.PI / 180) | |
} | |
//console.log(180 * 100 * 360 * 100 * 3) | |
var _ = require('lodash'); | |
var testResult = {}; | |
_.each(_.range(1, 11), function (v) { | |
testResult[v] = { | |
latMin: 90, | |
latMax: -90, | |
lonMin: 180, | |
lonMax: -180 | |
}; | |
}); | |
function updateError(key, lat1, lon1) { | |
var tr = testResult[key]; | |
if (!tr) { | |
console.error(key); | |
process.exit(1); | |
} | |
tr.latMin = Math.min(tr.latMin, lat1); | |
tr.latMax = Math.max(tr.latMax, lat1); | |
tr.lonMax = Math.max(tr.lonMax, lon1); | |
tr.lonMin = Math.min(tr.lonMin, lon1); | |
} | |
var maxDistance = 0; | |
var latStart = 90, latStep = 0.5, latHole = 0; | |
var lonStart = 180, lonStep = 0.5; | |
var distStart = 5, distStep = 5, distEnd = 10; | |
var len = ((latStart - latHole) * 2 / latStep) * (lonStart * 2 / lonStep) * ((distEnd - distStart) / distStep); | |
//var len = (latStart * 2 / latStep) * (lonStart * 2 / lonStep) * ((distEnd - distStart)/ distStep); | |
var passedOver = 0; | |
var flag1 = false; | |
var flag2 = false; | |
_.each(_.union(_.range(-latStart, -latHole, latStep), _.range(latHole, latStart + latStep, latStep)), function (lat) { | |
//_.each(_.range(-latStart, latStart + latStep, latStep), function (lat) { | |
_.each(_.range(-lonStart, lonStart + lonStep, lonStep), function (lon) { | |
_.each(_.range(distStart, distEnd, distStep), function (distance) { | |
var distanceTest = distance; | |
var cb = function () { | |
var res = approximateDistance(distance, lat, lon); | |
if (res.latIgnore) { | |
//console.log('aaalat', distance); | |
flag1 = true; | |
return; | |
} | |
if (res.lonIgnore) { | |
//console.log('aaalon', distance); | |
flag2 = true; | |
return; | |
} | |
updateError(9, res.latMin, res.lonMin); | |
updateError(10, res.latMax, res.lonMax); | |
//console.log(lat, lon, distance) | |
//console.log(res) | |
var dist = getDistanceFromLatLonInKm(lat, lon, res.latMax, res.lonMax); | |
//console.log(dist) | |
maxDistance = Math.max(maxDistance, dist); | |
if (dist < distanceTest) { | |
console.error("**t1**", Math.round(dist), lat, lon); | |
updateError(1, lat, lon); | |
} | |
dist = getDistanceFromLatLonInKm(lat, lon, res.latMax, res.lonMin); | |
maxDistance = Math.max(maxDistance, dist); | |
//console.log(dist) | |
if (dist < distanceTest) { | |
console.error("**t2**", Math.round(dist), lat, lon); | |
updateError(2, lat, lon); | |
} | |
dist = getDistanceFromLatLonInKm(lat, lon, res.latMin, res.lonMax); | |
maxDistance = Math.max(maxDistance, dist); | |
//console.log(dist) | |
if (dist < distanceTest) { | |
console.error("**t3**", Math.round(dist), lat, lon); | |
updateError(3, lat, lon); | |
} | |
dist = getDistanceFromLatLonInKm(lat, lon, res.latMin, res.lonMin); | |
maxDistance = Math.max(maxDistance, dist); | |
//console.log(dist) | |
if (dist < distanceTest) { | |
console.error("**t4**", Math.round(dist), lat, lon); | |
updateError(4, lat, lon); | |
} | |
dist = getDistanceFromLatLonInKm(lat, lon, 90, 180); | |
if (dist < distanceTest) { | |
console.log("**t5**", Math.round(dist), lat, lon); | |
updateError(5, lat, lon); | |
} | |
dist = getDistanceFromLatLonInKm(lat, lon, 90, -180); | |
if (dist < distanceTest) { | |
console.log("**t6**", Math.round(dist), lat, lon); | |
updateError(6, lat, lon); | |
} | |
dist = getDistanceFromLatLonInKm(lat, lon, -90, 180); | |
if (dist < distanceTest) { | |
console.log("**t7**", Math.round(dist), lat, lon); | |
updateError(7, lat, lon); | |
} | |
dist = getDistanceFromLatLonInKm(lat, lon, -90, -180); | |
if (dist < distanceTest) { | |
console.log("**t8**", Math.round(dist), lat, lon); | |
updateError(8, lat, lon); | |
} | |
}; | |
cb(); | |
if (passedOver++ % 1000000 === 0) { | |
console.log(100 * passedOver / len, "% (", passedOver, len, ")"); | |
console.log(testResult); | |
} | |
//process.nextTick(cb); | |
}); | |
}); | |
}); | |
console.log("\n DONE", testResult, flag1, flag2, maxDistance); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment