Created
March 26, 2019 22:54
-
-
Save bmcminn/80da4da313f48c906a8388ccbf01a433 to your computer and use it in GitHub Desktop.
Playing around with zip code distance algorithms and radius search
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
const ZIPCODES = require('./zipcodes.js') | |
const sqlite = require('sqlite') | |
const Promise = require('bluebird') | |
// http://www.zipcodeapi.com/API | |
/** | |
* Calculates distance between two ZIPCODES | |
* @sauce: https://www.movable-type.co.uk/scripts/latlong.html | |
* @param {object} zip1 Object containing zip, lat, lng | |
* @param {object} zip2 Object containing zip, lat, lng | |
* @param {integer} PRECISION Flag to return the result in kilometers or miles | |
* @return {double} A double representing the distance between the two points | |
*/ | |
function zipDistance(zip1, zip2, PRECISION=3) { | |
const R = 6371 | |
// const R = 6371e3 // meters | |
// const M = R / 1.609 | |
const φ1 = degressToRadians(zip1.lat) | |
const φ2 = degressToRadians(zip2.lat) | |
const Δφ = degressToRadians((zip2.lat-zip1.lat)) | |
const Δλ = degressToRadians((zip2.lng-zip1.lng)) | |
let a = Math.sin(Δφ/2) * Math.sin(Δφ/2) + | |
Math.cos(φ1) * Math.cos(φ2) * | |
Math.sin(Δλ/2) * Math.sin(Δλ/2) | |
let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)) | |
return (R * c).toFixed(PRECISION) | |
} | |
/** | |
* Calculate the lat and lng ranges for a given "radius" | |
* @param {[type]} zip1 [description] | |
* @param {[type]} radius [description] | |
* @return {[type]} [description] | |
*/ | |
function getZipRadius(zip1, radius) { | |
let DIST = 0.01035 * radius | |
return { | |
latMin: zip1.lat - DIST, | |
latMax: zip1.lat + DIST, | |
lngMin: zip1.lng - DIST, | |
lngMax: zip1.lng + DIST, | |
} | |
} | |
/** | |
* [degressToRadians description] | |
* @param {[type]} degrees [description] | |
* @return {[type]} [description] | |
*/ | |
function degressToRadians(degrees) { | |
return degrees * (Math.PI/180) | |
} | |
/** | |
* Converts Km to miles | |
* @param {float} km distance in kilometers | |
* @return {double} miles distance in miles | |
*/ | |
function kmToMiles(km, PRECISION=3) { | |
return (km / 1.609).toFixed(PRECISION) | |
} | |
/** | |
* [getZipsInRadius description] | |
* @param {[type]} zip [description] | |
* @param {[type]} zips [description] | |
* @param {[type]} radius [description] | |
* @return {[type]} [description] | |
*/ | |
function getZipsInRadius(zip, zips, radius) { | |
const RADIUS = getZipRadius(zip, radius) | |
return zips.filter(el => { | |
if (RADIUS.latMin <= el.lat && el.lat <= RADIUS.latMax | |
&& RADIUS.lngMin <= el.lng && el.lng <= RADIUS.lngMax | |
) { | |
let distance = zipDistance(zip, el) | |
if (distance <= radius) { | |
return el | |
} | |
} | |
}) | |
} | |
// const TARGET = ZIPCODES[0] | |
const RADIUS = 100 | |
const TARGET = { | |
lat: 30.3, | |
lng: -97.6, | |
zip_code: '???', | |
} | |
// let res = getZipsInRadius(TARGET, ZIPCODES, RADIUS) | |
// res.map(el => { | |
// console.log(`distance from ${TARGET.zip_code} to ${el.zip_code} is`, kmToMiles(zipDistance(TARGET, el)), 'miles') | |
// }) | |
getZipsInRadius(TARGET, ZIPCODES, RADIUS) | |
.map(el => { | |
console.log(`distance from ${TARGET.zip_code} to ${el.zip_code} is`, kmToMiles(zipDistance(TARGET, el)), 'miles') | |
}) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment