Last active
March 22, 2022 17:56
-
-
Save donpdonp/90f77b35b5165e499c791f9e3e67cc6c to your computer and use it in GitHub Desktop.
gluon osm openstreetmap lookups
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
(function() { | |
// descriptor | |
return {name:"osm"} | |
}) | |
// osm json | |
//{"bearing":345.9410965462545,"distance":355.0966239302687, | |
// "node":{"id":1963188104,"lat":45.5233261,"lon":-122.6584695,"tags":{... | |
function go(msg) { | |
if (msg.method == "irc.privmsg") { | |
var cmd = /^!osm(\s+(.*))?/.exec(msg.params.message) | |
if(cmd) { | |
if(cmd[2]) { | |
bot.say(bot.admin_channel, "osm: "+msg.params.nick+' '+cmd[2]) | |
track(msg.params.nick, function(track){ | |
if (track) { | |
//bot.say(msg.params.channel, msg.params.nick+' '+JSON.stringify(track.location)) | |
var data = osmtag(cmd[2], track.location.latitude, track.location.longitude, 0.01) | |
bot.say(msg.params.channel, 'search +/-0.01 deg lat/lng of ['+ | |
track.location.latitude.toFixed(4)+','+track.location.longitude.toFixed(4)+'] nodes found: ' | |
+data.elements.length) | |
if(data.elements.length == 0) { // try again, a bit wider | |
data = osmtag(cmd[2], track.location.latitude, track.location.longitude, 0.1) | |
bot.say(msg.params.channel, 'search +/-0.1 deg lat/lng of ['+ | |
track.location.latitude.toFixed(4)+','+track.location.longitude.toFixed(4)+'] nodes found: ' | |
+data.elements.length) | |
} | |
if(data.elements.length > 0) { | |
var winner = closest(track.location, data.elements) | |
var name = winner.node.tags['name'] ? winner.node.tags['name'] : "[no name]" | |
var direction = headingDirection(winner.bearing) + "(" + winner.bearing.toFixed(0) + "°)" | |
var info = name+" is "+winner.distance.toFixed(0)+"m "+direction+" "+ | |
" https://www.openstreetmap.org/node/"+winner.node.id | |
bot.say(msg.params.channel, msg.params.nick+': '+info) | |
var route = 'https://maps.openrouteservice.org/directions?c=0&a=' | |
route = route + [track.location.latitude, track.location.longitude, winner.node.lat, winner.node.lon].join(',') | |
//bot.say(msg.params.channel, msg.params.nick+': route '+route) | |
} else { | |
bot.say(msg.params.channel, msg.params.nick+' no '+cmd[2]+' in your vicinity.') | |
} | |
} else { | |
bot.say(msg.params.channel, 'no icecondor track for '+msg.params.nick) | |
} | |
}) | |
} else { | |
bot.say(msg.params.channel, "!osm <tag_name>=<tag_value>") | |
} | |
} | |
var barcmd = /^!nearestbar/.exec(msg.params.message) | |
if(barcmd) { | |
bot.say(bot.admin_channel, "osm: "+msg.params.nick+' !nearestbar') | |
track(msg.params.nick, function(track){ | |
if (track) { | |
var barfind = 'amenity~"^bar$|^pub$"' | |
var data = osmtag(barfind, track.location.latitude, track.location.longitude, 0.02) | |
if(data.elements.length > 0) { | |
var winner = closest(track.location, data.elements) | |
var name = winner.node.tags['name'] ? winner.node.tags['name'] : "" | |
var direction = winner.distance.toFixed(0) + ' meters ' + headingDirection(winner.bearing) | |
bot.say(msg.params.channel, msg.params.nick+': '+name+'. '+direction) | |
} else { | |
bot.say(msg.params.channel, msg.params.nick+": nothing within 0.02deg of you.") | |
} | |
} | |
}) | |
} | |
var nearest = /^!nearest(\s+(.*))/.exec(msg.params.message) | |
if(nearest) { | |
track(msg.params.nick, function(track){ | |
if (track) { | |
var query = 'amenity~"'+nearest[2]+'"' | |
bot.say(msg.params.channel, msg.params.nick+": "+query) | |
var data = osmtag(query, track.location.latitude, track.location.longitude, 0.02) | |
if(data.elements.length > 0) { | |
var winner = closest(track.location, data.elements) | |
var name = winner.node.tags['name'] ? winner.node.tags['name'] : "" | |
var direction = winner.distance.toFixed(0) + ' meters ' + headingDirection(winner.bearing) | |
var node_url = "https://www.openstreetmap.org/node/"+winner.node.id | |
bot.say(msg.params.channel, msg.params.nick+': '+name+'. '+direction+' '+node_url) | |
} else { | |
bot.say(msg.params.channel, msg.params.nick+": nothing within 0.02deg of you.") | |
} | |
} | |
}) | |
} | |
} | |
} | |
function closest(me, nodes) { | |
var winner = {node: null, distance: null} | |
nodes.forEach(function(node){ | |
var meDistance = pointDistance(me, {latitude: node.lat, longitude: node.lon}) | |
if(!winner.node || meDistance < winner.distance) { | |
winner.node = node | |
winner.distance = meDistance | |
winner.bearing = segmentBearing(me, {latitude: node.lat, longitude: node.lon}) | |
} | |
}) | |
return winner | |
} | |
function osmtag(tag, lat, lng, delta) { | |
var url = 'http://overpass-api.de/api/interpreter' | |
var coords = [lat-delta, lng-delta, lat+delta, lng+delta] | |
var tagquery | |
if(tag.indexOf('=') > 0 || tag.indexOf('~') > 0) { | |
tagquery = tag | |
} else { | |
tagquery = "\"name\"~\""+tag+"\",i" | |
} | |
var overpass = '[out:json];' + | |
//'node('+coords.join(',')+')['+tagquery+'];'+ | |
'(node('+coords.join(',')+')['+tagquery+'];'+ | |
'way('+coords.join(',')+')['+tagquery+'];);'+ | |
'(._;>;);'+ | |
'out;' | |
//(node(45.5016018,-122.6960055,45.6216018,-122.57600549999999) [aeroway=aerodrome]; | |
// way(45.5016018,-122.6960055,46.5216018,-122.57600549999999) [aeroway=aerodrome];); | |
//(._;>;); | |
bot.say(bot.admin_channel, overpass) | |
var resp = http.get({url:url+'?data='+encodeURIComponent(overpass)}) | |
bot.say(bot.admin_channel, url+'?data='+encodeURIComponent(overpass)) | |
if(resp.status != 200) { | |
bot.say(bot.admin_channel, "osm http "+resp.status) | |
} | |
var data = JSON.parse(resp.body) | |
var filtered = data.elements.filter(function(n){return n.tags}) | |
bot.say(bot.admin_channel, "osm found "+data.elements.length+" nodes and "+filtered.length+" nodes with tags") | |
data.elements = filtered | |
return data | |
} | |
function track(username, cb) { | |
db.get('icecondor:user'+':'+username+':track', function(trackJson){ | |
var track | |
if (trackJson) { | |
cb(JSON.parse(trackJson)) | |
} else { cb() } | |
}) | |
} | |
// from http://www.movable-type.co.uk/scripts/latlong.html | |
function pointDistance(la, lb) { | |
var lat1 = la.latitude, lon1 = la.longitude | |
var lat2 = lb.latitude, lon2 = lb.longitude | |
var dLat = numberToRadius(lat2 - lat1), | |
dLon = numberToRadius(lon2 - lon1), | |
a = Math.pow(Math.sin(dLat / 2), 2) + Math.cos(numberToRadius(lat1)) | |
* Math.cos(numberToRadius(lat2)) * Math.pow(Math.sin(dLon / 2), 2), | |
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); | |
return (6371 * c) * 1000; // returns meters | |
} | |
function numberToRadius(number) { | |
return number * Math.PI / 180; | |
} | |
function numberToDegree(number) { | |
return number * 180 / Math.PI | |
} | |
function segmentBearing(loc1, loc2) { | |
var λ1 = numberToRadius(loc1.longitude) | |
var λ2 = numberToRadius(loc2.longitude) | |
var φ1 = numberToRadius(loc1.latitude) | |
var φ2 = numberToRadius(loc2.latitude) | |
var y = Math.sin(λ2-λ1) * Math.cos(φ2); | |
var x = Math.cos(φ1)*Math.sin(φ2) - | |
Math.sin(φ1)*Math.cos(φ2)*Math.cos(λ2-λ1); | |
var brng = Math.atan2(y, x)// .toDegrees() | |
var bearingDegrees = numberToDegree(brng) | |
var offset = (bearingDegrees < 0) ? 360 : 0 | |
return offset + bearingDegrees | |
} | |
function headingDirection(degrees) { | |
var directions = ["north", "northeast", "east", "southeast", "south", "southwest", "west", "northwest"] | |
var anglewidth = 360 / directions.length | |
var halfwidth = anglewidth/2 | |
for(var i=0; i < directions.length; i++) { | |
var j = i == 0 ? directions.length-1 : i-1 | |
var min = (anglewidth*j)+halfwidth | |
var max = (anglewidth*i)+halfwidth | |
var inside | |
if(i==0) { | |
inside = degrees <= max || degrees > min | |
} else { | |
inside = degrees <= max && degrees > min | |
} | |
if(inside) return directions[i] | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment