/* Description of this program: http://ojw.dev.openstreetmap.org/driving_pubs/ Usage: ./osmium_pubs ~/osm/data/british_isles.osm.pbf > osm_pubs_near_junctions.kml WARNING: HTML output is not safe from malicious data stored in OSM nodes (KML output should be OK) Copyright 2012, Oliver White Derived from sample code that was part of Osmium (https://github.com/joto/osmium) and Copyright 2011 Jochen Topf and others (see README).. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License or (at your option) the GNU General Public License as published by the Free Software Foundation, either version 3 of the Licenses, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License and the GNU General Public License for more details. You should have received a copy of the Licenses along with this program. If not, see . */ const bool inhibitNotAttachedToMotorway = true; // false allows junctions which aren't part of a motorway, e.g. if they're floating, or attached to trunk roads const double max_distance_from_junction = 5.0; // km const double min_distance_from_city = 5.0; // km const double min_distance_from_capital = 15.0; // km #include #include #include #include using kmldom::CoordinatesPtr; using kmldom::KmlPtr; using kmldom::KmlFactory; using kmldom::PlacemarkPtr; using kmldom::PointPtr; using kmldom::FolderPtr; typedef struct { double lat; double lon; char road[8]; char jct[8]; long id; }TRG_jct; std::string junction_name(TRG_jct VRI_j){ if(!VRI_j.road[0]) return("junction"); if(!VRI_j.jct[0]) return("junction on " + std::string(VRI_j.road)); return(VRI_j.road + std::string(" junction ") + VRI_j.jct); } typedef struct { double lat; double lon; std::string name; std::string url; std::string telephone; std::string description; double distance_from_junction; double distance_from_city; long id; bool ale; bool dogs; }TRG_pub; typedef struct { double lat; double lon; std::string name; bool capital; }TRG_city; double distance(double lat1, double lon1, double lat2, double lon2) // degrees in, kilometers out { // Haversine formula from http://www.movable-type.co.uk/scripts/latlong.html const double deg2rad = 0.0174532925; const double R = 6371; // km double dLat = (lat2-lat1) * deg2rad; double dLon = (lon2-lon1) * deg2rad; lat1 *= deg2rad; lat2 *= deg2rad; double a = sin(dLat/2) * sin(dLat/2) + sin(dLon/2) * sin(dLon/2) * cos(lat1) * cos(lat2); double c = 2 * atan2(sqrt(a), sqrt(1-a)); double d = R * c; return(d); } class MyDebugHandler : public Osmium::Handler::Base { Osmium::Handler::Debug handler_debug; std::vector VRM_pubs; std::vector VRM_jcts; std::vector VRM_cities; KmlFactory* factory; KmlPtr kml; FolderPtr folder; public: void init(Osmium::OSM::Meta &) { factory = KmlFactory::GetFactory(); kml = factory->CreateKml(); folder = factory->CreateFolder(); folder->set_name("Pubs with food near junctions"); } void before_nodes() {} void node(Osmium::OSM::Node *node) { // Ignore blank nodes if(node->tags().size() != 0) { // Look for junctions const char *highway = node->tags().get_tag_by_key("highway"); const char *ref = node->tags().get_tag_by_key("ref"); if(highway != 0 && !strcmp(highway, "motorway_junction")){ if(!ref) ref = ""; TRG_jct VRL_jct; VRL_jct.lat = node->position().lat(); VRL_jct.lon = node->position().lon(); VRL_jct.id = node->id(); VRL_jct.road[0] = '\0'; // Will be filled in later if we find a road passing through this ID strncpy(VRL_jct.jct, ref, sizeof(VRL_jct.jct)); VRL_jct.jct[sizeof(VRL_jct.jct)-1] = '\0'; // wot no strcpy_s? VRM_jcts.push_back(VRL_jct); } // Look for cities const char *place = node->tags().get_tag_by_key("place"); if(place != 0 && !strcmp(place, "city")){ const char *name = node->tags().get_tag_by_key("name"); if(!name) name = ""; const char *capital = node->tags().get_tag_by_key("capital"); TRG_city VRL_city; VRL_city.lat = node->position().lat(); VRL_city.lon = node->position().lon(); VRL_city.name = name; VRL_city.capital = (capital && !strcmp(capital, "yes")); VRM_cities.push_back(VRL_city); } // Look for pubs const char *amenity = node->tags().get_tag_by_key("amenity"); if(amenity != 0 && !strcmp(amenity, "pub")){ const char *food = node->tags().get_tag_by_key("food"); if(food!= 0 && !strcmp(food, "yes")){ const char *name = node->tags().get_tag_by_key("name"); if(!name) name = ""; const char *url = node->tags().get_tag_by_key("website"); const char *tel = node->tags().get_tag_by_key("telephone"); const char *desc = node->tags().get_tag_by_key("description"); const char *ale = node->tags().get_tag_by_key("real_ale"); const char *dogs = node->tags().get_tag_by_key("dog"); TRG_pub VRL_pub; VRL_pub.lat = node->position().lat(); VRL_pub.lon = node->position().lon(); VRL_pub.name = name; VRL_pub.id = node->id(); VRL_pub.ale = (ale && !strcmp(ale, "yes")); VRL_pub.dogs = (dogs && !strcmp(dogs, "yes")); if(url) VRL_pub.url = url; if(tel) VRL_pub.telephone = tel; if(desc) VRL_pub.description = desc; VRM_pubs.push_back(VRL_pub); } } } } void after_nodes() {} void before_ways() {} void way(Osmium::OSM::Way *way) { // When we find a motorway... const char *highway = way->tags().get_tag_by_key("highway"); if(highway != 0 && !strcmp(highway, "motorway")){ // see if its nodes match any of the junctions we're keeping track of for(unsigned VIL_loop = 0; VIL_loop < (unsigned)way->nodes().size(); VIL_loop++){ for(std::vector::iterator VRL_loop = VRM_jcts.begin(); VRL_loop != VRM_jcts.end(); VRL_loop++){ if(VRL_loop->id == way->nodes()[VIL_loop].ref()){ // If so, store the motorway name in the junction object const char *ref = way->tags().get_tag_by_key("ref"); if(!ref) ref = ""; strncpy(VRL_loop->road, ref, sizeof(VRL_loop->road)); VRL_loop->road[sizeof(VRL_loop->road)-1] = '\0'; } } } } } void after_ways() {} void before_relations() {} void relation(Osmium::OSM::Relation *) {} void after_relations() {} void final() { FILE *VAL_fp = fopen("osm_pubs_near_junctions.html", "w"); // hardcoded filename - classy! :( if(VAL_fp){ fprintf(VAL_fp, "Pubs near junctions\n"); } else{ std::cerr << "Couldn't write to HTML"; } // For each pub: for(std::vector::iterator VRL_p = VRM_pubs.begin(); VRL_p != VRM_pubs.end(); VRL_p++){ // How far is it from a motorway junction VRL_p->distance_from_junction = 1E+10; // we assume there's at least one junction in the dataset TRG_jct VRL_nearestJct; // could make this an attribute of the pub object for(std::vector::iterator VRL_j = VRM_jcts.begin(); VRL_j != VRM_jcts.end(); VRL_j++){ double VFL_distance = distance(VRL_p->lat, VRL_p->lon, VRL_j->lat, VRL_j->lon); if(VFL_distance < VRL_p->distance_from_junction){ VRL_p->distance_from_junction = VFL_distance; VRL_nearestJct = *VRL_j; } } // How far is it from a city? VRL_p->distance_from_city = 1E+10; TRG_city VRL_nearestCity; // could make this an attribute of the pub object for(std::vector::iterator VRL_c = VRM_cities.begin(); VRL_c != VRM_cities.end(); VRL_c++){ double VFL_distance = distance(VRL_p->lat, VRL_p->lon, VRL_c->lat, VRL_c->lon); if(VFL_distance < VRL_p->distance_from_city){ VRL_p->distance_from_city = VFL_distance; VRL_nearestCity = *VRL_c; } } char VCL_distanceJ[20]; snprintf(VCL_distanceJ, sizeof(VCL_distanceJ), "%1.1fkm", VRL_p->distance_from_junction); char VCL_distanceC[20]; snprintf(VCL_distanceC, sizeof(VCL_distanceC), "%1.1fkm", VRL_p->distance_from_city); if(VRL_p->distance_from_junction < max_distance_from_junction && VRL_p->distance_from_city > min_distance_from_city && (!VRL_nearestCity.capital || VRL_p->distance_from_city > min_distance_from_capital) && (!inhibitNotAttachedToMotorway || VRL_nearestJct.road[0]) ){ CoordinatesPtr coordinates = factory->CreateCoordinates(); coordinates->add_latlng(VRL_p->lat, VRL_p->lon); PointPtr point = factory->CreatePoint(); point->set_coordinates(coordinates); PlacemarkPtr placemark = factory->CreatePlacemark(); placemark->set_name(VRL_p->name); placemark->set_description( // watch out this could be HTML VRL_p->name + "
" + VCL_distanceJ + " from " + junction_name(VRL_nearestJct) + ".
" + VCL_distanceC + " from " + VRL_nearestCity.name + ".
" + "Website: " + VRL_p->url + "
" + "Telephone: " + VRL_p->telephone + "
" + VRL_p->description); placemark->set_geometry(point); folder->add_feature(placemark); // Write details to the HTML file // TODO: HTML writing library that can escape any junk/exploits put into OSM nodes if(VAL_fp){ fprintf(VAL_fp, "
"); fprintf(VAL_fp, "", VRL_p->name.c_str()); fprintf(VAL_fp, "", VRL_p->id); fprintf(VAL_fp, "", VRL_p->lat, VRL_p->lon); fprintf(VAL_fp, "", VRL_p->name.c_str(), VRL_nearestCity.name.c_str()); fprintf(VAL_fp, "", VRL_nearestJct.lat, VRL_nearestJct.lon, junction_name(VRL_nearestJct).c_str()); fprintf(VAL_fp, "", VRL_nearestCity.name.empty() ? " ": VRL_nearestCity.name.c_str()); if(VRL_p->url.empty()) fprintf(VAL_fp, ""); else fprintf(VAL_fp, "", VRL_p->url.c_str()); if(0) fprintf(VAL_fp, "", VRL_p->ale?"Real ale":" ", // Don't display real ale availability since this is a motorway journey and we're not intending to drink VRL_p->dogs?"Dogs permitted":" " // Don't display whether we can bring the dog inside since there are only 2 pubs in britain tagged this way ); fprintf(VAL_fp, "\n"); } } } // long-suffering KML object has been storing everything in memory - serialise it into yet more memory then give to STDOUT which should be redirected into a kml file kml->set_feature(folder); std::string xml = kmldom::SerializePretty(kml); std::cout << xml; if(VAL_fp){ fprintf(VAL_fp, "
%sNodeMapGoogle%s%s Website%s %s
"); fclose(VAL_fp); } } }; int main(int argc, char *argv[]) { Osmium::init(true); if (argc < 2) { std::cerr << "Usage: " << argv[0] << " OSMFILE" << std::endl; exit(1); } Osmium::OSMFile infile(argv[1]); MyDebugHandler handler; infile.read(handler); }