void output_pgsql_t::pgsql_out_way(osmium::Way const &way, taglist_t *tags, bool polygon, bool roads) { if (polygon && way.is_closed()) { auto wkb = m_builder.get_wkb_polygon(way); if (!wkb.empty()) { expire.from_wkb(wkb.c_str(), way.id()); if (m_enable_way_area) { char tmp[32]; auto const area = m_options.reproject_area ? ewkb::parser_t(wkb).get_area<reprojection>( m_options.projection.get()) : ewkb::parser_t(wkb) .get_area<osmium::geom::IdentityProjection>(); snprintf(tmp, sizeof(tmp), "%g", area); tags->push_override(tag_t("way_area", tmp)); } m_tables[t_poly]->write_row(way.id(), *tags, wkb); } } else { double const split_at = m_options.projection->target_latlon() ? 1 : 100 * 1000; for (auto const &wkb : m_builder.get_wkb_line(way.nodes(), split_at)) { expire.from_wkb(wkb.c_str(), way.id()); m_tables[t_line]->write_row(way.id(), *tags, wkb); if (roads) { m_tables[t_roads]->write_row(way.id(), *tags, wkb); } } } }
/* COPY planet_osm (osm_id, name, place, landuse, leisure, "natural", man_made, waterway, highway, railway, amenity, tourism, learning, bu ilding, bridge, layer, way) FROM stdin; 198497 Bedford Road \N \N \N \N \N \N residential \N \N \N \N \N \N \N 0102000020E610000004000000452BF702B342D5BF1C60E63BF8DF49406B9C4D470037D5BF5471E316F3DF4940DFA815A6EF35D5BF9AE95E27F5DF4940B41EB E4C1421D5BF24D06053E7DF4940 212696 Oswald Road \N \N \N \N \N \N minor \N \N \N \N \N \N \N 0102000020E610000004000000467D923B6C22D5BFA359D93EE4DF4940B3976DA7AD11D5BF84BBB376DBDF4940997FF44D9A06D5BF4223D8B8FEDF49404D158C4AEA04D 5BF5BB39597FCDF4940 */ int output_pgsql_t::pgsql_out_way(osmid_t id, taglist_t &outtags, const nodelist_t &nodes, int polygon, int roads) { /* Split long ways after around 1 degree or 100km */ double split_at; if (m_options.projection->target_latlon()) split_at = 1; else split_at = 100 * 1000; char tmp[32]; auto wkbs = builder.get_wkb_split(nodes, polygon, split_at); for (const auto& wkb: wkbs) { /* FIXME: there should be a better way to detect polygons */ if (wkb.is_polygon()) { expire.from_nodes_poly(nodes, id); if ((wkb.area > 0.0) && m_enable_way_area) { snprintf(tmp, sizeof(tmp), "%g", wkb.area); outtags.push_override(tag_t("way_area", tmp)); } m_tables[t_poly]->write_row(id, outtags, wkb.geom); } else { expire.from_nodes_line(nodes); m_tables[t_line]->write_row(id, outtags, wkb.geom); if (roads) m_tables[t_roads]->write_row(id, outtags, wkb.geom); } } return 0; }
/* COPY planet_osm (osm_id, name, place, landuse, leisure, "natural", man_made, waterway, highway, railway, amenity, tourism, learning, bu ilding, bridge, layer, way) FROM stdin; 198497 Bedford Road \N \N \N \N \N \N residential \N \N \N \N \N \N \N 0102000020E610000004000000452BF702B342D5BF1C60E63BF8DF49406B9C4D470037D5BF5471E316F3DF4940DFA815A6EF35D5BF9AE95E27F5DF4940B41EB E4C1421D5BF24D06053E7DF4940 212696 Oswald Road \N \N \N \N \N \N minor \N \N \N \N \N \N \N 0102000020E610000004000000467D923B6C22D5BFA359D93EE4DF4940B3976DA7AD11D5BF84BBB376DBDF4940997FF44D9A06D5BF4223D8B8FEDF49404D158C4AEA04D 5BF5BB39597FCDF4940 */ int output_pgsql_t::pgsql_out_way(osmid_t id, const taglist_t &tags, const nodelist_t &nodes, int exists) { int polygon = 0, roads = 0; double split_at; /* If the flag says this object may exist already, delete it first */ if (exists) { pgsql_delete_way_from_output(id); // TODO: this now only has an effect when called from the iterate_ways // call-back, so we need some alternative way to trigger this within // osmdata_t. const idlist_t rel_ids = m_mid->relations_using_way(id); for (idlist_t::const_iterator itr = rel_ids.begin(); itr != rel_ids.end(); ++itr) { rels_pending_tracker->mark(*itr); } } taglist_t outtags; if (m_tagtransform->filter_way_tags(tags, &polygon, &roads, *m_export_list.get(), outtags)) return 0; /* Split long ways after around 1 degree or 100km */ if (m_options.projection->get_proj_id() == PROJ_LATLONG) split_at = 1; else split_at = 100 * 1000; tag_t *areatag = 0; auto wkbs = builder.get_wkb_split(nodes, polygon, split_at); for (const auto& wkb: wkbs) { /* FIXME: there should be a better way to detect polygons */ if (wkb.is_polygon()) { expire->from_nodes_poly(nodes, id); if ((wkb.area > 0.0) && m_enable_way_area) { char tmp[32]; snprintf(tmp, sizeof(tmp), "%g", wkb.area); if (!areatag) { outtags.push_dedupe(tag_t("way_area", tmp)); areatag = outtags.find("way_area"); } else areatag->value = tmp; } m_tables[t_poly]->write_row(id, outtags, wkb.geom); } else { expire->from_nodes_line(nodes); m_tables[t_line]->write_row(id, outtags, wkb.geom); if (roads) m_tables[t_roads]->write_row(id, outtags, wkb.geom); } } return 0; }
/* COPY planet_osm (osm_id, name, place, landuse, leisure, "natural", man_made, waterway, highway, railway, amenity, tourism, learning, bu ilding, bridge, layer, way) FROM stdin; 198497 Bedford Road \N \N \N \N \N \N residential \N \N \N \N \N \N \N 0102000020E610000004000000452BF702B342D5BF1C60E63BF8DF49406B9C4D470037D5BF5471E316F3DF4940DFA815A6EF35D5BF9AE95E27F5DF4940B41EB E4C1421D5BF24D06053E7DF4940 212696 Oswald Road \N \N \N \N \N \N minor \N \N \N \N \N \N \N 0102000020E610000004000000467D923B6C22D5BFA359D93EE4DF4940B3976DA7AD11D5BF84BBB376DBDF4940997FF44D9A06D5BF4223D8B8FEDF49404D158C4AEA04D 5BF5BB39597FCDF4940 */ int output_pgsql_t::pgsql_out_way(osmid_t id, taglist_t &outtags, const nodelist_t &nodes, int polygon, int roads) { /* Split long ways after around 1 degree or 100km */ double split_at; if (m_options.projection->get_proj_id() == PROJ_LATLONG) split_at = 1; else split_at = 100 * 1000; tag_t *areatag = 0; auto wkbs = builder.get_wkb_split(nodes, polygon, split_at); for (const auto& wkb: wkbs) { /* FIXME: there should be a better way to detect polygons */ if (wkb.is_polygon()) { expire->from_nodes_poly(nodes, id); if ((wkb.area > 0.0) && m_enable_way_area) { char tmp[32]; snprintf(tmp, sizeof(tmp), "%g", wkb.area); if (!areatag) { outtags.push_dedupe(tag_t("way_area", tmp)); areatag = outtags.find("way_area"); } else areatag->value = tmp; } m_tables[t_poly]->write_row(id, outtags, wkb.geom); } else { expire->from_nodes_line(nodes); m_tables[t_line]->write_row(id, outtags, wkb.geom); if (roads) m_tables[t_roads]->write_row(id, outtags, wkb.geom); } } return 0; }
void place_tag_processor::process_tags(const taglist_t &tags) { bool placeadmin = false; bool placehouse = false; bool placebuilding = false; const tag_t *place = 0; const tag_t *junction = 0; const tag_t *landuse = 0; bool isnamed = false; bool isinterpolation = false; const std::string *house_nr = 0; const std::string *conscr_nr = 0; const std::string *street_nr = 0; clear(); src = &tags; for (const auto& item: tags) { if (boost::ends_with(item.key, "source")) { // ignore } else if (item.key == "name:prefix" || item.key == "name:botanical" || boost::ends_with(item.key, "wikidata")) { extratags.push_back(&item); } else if (item.key == "ref" || item.key == "int_ref" || item.key == "nat_ref" || item.key == "reg_ref" || item.key == "loc_ref" || item.key == "old_ref" || item.key == "iata" || item.key == "icao" || item.key == "operator" || item.key == "pcode" || boost::starts_with(item.key, "pcode:")) { names.push_back(&item); } else if (item.key == "name" || boost::starts_with(item.key, "name:") || item.key == "int_name" || boost::starts_with(item.key, "int_name:") || item.key == "nat_name" || boost::starts_with(item.key, "nat_name:") || item.key == "reg_name" || boost::starts_with(item.key, "reg_name:") || item.key == "loc_name" || boost::starts_with(item.key, "loc_name:") || item.key == "old_name" || boost::starts_with(item.key, "old_name:") || item.key == "alt_name" || boost::starts_with(item.key, "alt_name:") || boost::starts_with(item.key, "alt_name_") || item.key == "official_name" || boost::starts_with(item.key, "official_name:") || item.key == "place_name" || boost::starts_with(item.key, "place_name:") || item.key == "short_name" || boost::starts_with(item.key, "short_name:") || item.key == "brand") { names.push_back(&item); isnamed = true; } else if (item.key == "addr:housename") { names.push_back(&item); placehouse = true; } else if (item.key == "emergency") { if (item.value != "fire_hydrant" && item.value != "yes" && item.value != "no") places.push_back(item); } else if (item.key == "tourism" || item.key == "historic" || item.key == "military") { if (item.value != "no" && item.value != "yes") places.push_back(item); } else if (item.key == "natural") { if (item.value != "no" && item.value != "yes" && item.value != "coastline") places.push_back(item); } else if (item.key == "landuse") { if (item.value == "cemetry") places.push_back(item); else landuse = &item; } else if (item.key == "highway") { if (item.value == "footway") { auto *footway = tags.get("footway"); if (footway == nullptr || *footway != "sidewalk") places.push_back(item); } else if (item.value != "no" && item.value != "turning_circle" && item.value != "mini_roundabout" && item.value != "noexit" && item.value != "crossing") places.push_back(item); } else if (item.key == "railway") { if (item.value != "level_crossing" && item.value != "no") places.push_back(item); } else if (item.key == "man_made") { if (item.value != "survey_point" && item.value != "cutline") places.push_back(item); } else if (item.key == "aerialway") { if (item.value != "pylon" && item.value != "no") places.push_back(item); } else if (item.key == "boundary") { if (item.value == "administrative") placeadmin = true; places.push_back(item); } else if (item.key == "aeroway" || item.key == "amenity" || item.key == "boundary" || item.key == "bridge" || item.key == "craft" || item.key == "leisure" || item.key == "office" || item.key == "shop" || item.key == "tunnel" || item.key == "mountain_pass") { if (item.value != "no") { places.push_back(item); } } else if (item.key == "waterway") { if (item.value != "riverbank") places.push_back(item); } else if (item.key == "place") { place = &item; } else if (item.key == "junction") { junction = &item; } else if (item.key == "addr:interpolation") { housenumber.clear(); escape(item.value, housenumber); isinterpolation = true; } else if (item.key == "addr:housenumber") { house_nr = &item.value; placehouse = true; } else if (item.key == "addr:conscriptionnumber") { conscr_nr = &item.value; placehouse = true; } else if (item.key == "addr:streetnumber") { street_nr = &item.value; placehouse = true; } else if (item.key == "addr:street") { street = &item.value; } else if (item.key == "addr:place") { addr_place = &item.value; } else if (item.key == "postal_code" || item.key == "postcode" || item.key == "addr:postcode" || item.key == "tiger:zip_left" || item.key == "tiger:zip_right") { if (!postcode) postcode = &item.value; } else if (item.key == "country_code" || item.key == "ISO3166-1" || item.key == "is_in:country_code" || item.key == "addr:country" || item.key == "addr:country_code") { if (item.value.length() == 2) countrycode = &item.value; } else if (boost::starts_with(item.key, "addr:") || item.key == "is_in" || boost::starts_with(item.key, "is_in:") || item.key == "tiger:county") { address.push_back(&item); } else if (item.key == "admin_level") { admin_level = atoi(item.value.c_str()); if (admin_level <= 0 || admin_level > 100) admin_level = 100; } else if (item.key == "tracktype" || item.key == "traffic_calming" || item.key == "service" || item.key == "cuisine" || item.key == "capital" || item.key == "dispensing" || item.key == "religion" || item.key == "denomination" || item.key == "sport" || item.key == "internet_access" || item.key == "lanes" || item.key == "surface" || item.key == "smoothness" || item.key == "width" || item.key == "est_width" || item.key == "incline" || item.key == "opening_hours" || item.key == "collection_times" || item.key == "service_times" || item.key == "disused" || item.key == "wheelchair" || item.key == "sac_scale" || item.key == "trail_visibility" || item.key == "mtb:scale" || item.key == "mtb:description" || item.key == "wood" || item.key == "drive_through" || item.key == "drive_in" || item.key == "access" || item.key == "vehicle" || item.key == "bicyle" || item.key == "foot" || item.key == "goods" || item.key == "hgv" || item.key == "motor_vehicle" || item.key == "motor_car" || boost::starts_with(item.key, "access:") || boost::starts_with(item.key, "contact:") || boost::starts_with(item.key, "drink:") || item.key == "oneway" || item.key == "date_on" || item.key == "date_off" || item.key == "day_on" || item.key == "day_off" || item.key == "hour_on" || item.key == "hour_off" || item.key == "maxweight" || item.key == "maxheight" || item.key == "maxspeed" || item.key == "fee" || item.key == "toll" || boost::starts_with(item.key, "toll:") || item.key == "charge" || item.key == "population" || item.key == "description" || item.key == "image" || item.key == "attribution" || item.key == "fax" || item.key == "email" || item.key == "url" || item.key == "website" || item.key == "phone" || item.key == "real_ale" || item.key == "smoking" || item.key == "food" || item.key == "camera" || item.key == "brewery" || item.key == "locality" || item.key == "wikipedia" || boost::starts_with(item.key, "wikipedia:")) { extratags.push_back(&item); } else if (item.key == "building") { placebuilding = true; } } // skip some tags, if they don't have a proper name (ref doesn't count) if (!isnamed) { if (!places.empty()) places.erase(std::remove_if(places.begin(), places.end(), UnnamedPredicate()), places.end()); } if (isinterpolation) places.push_back(tag_t("place", "houses")); if (place) { if (isinterpolation || (placeadmin && place ->value != "island" && place ->value != "islet")) extratags.push_back(place); else places.push_back(*place); } if (isnamed && places.empty()) { if (junction) places.push_back(*junction); else if (landuse) places.push_back(*landuse); } if (places.empty()) { if (placebuilding && (!names.empty() || placehouse || postcode)) { places.push_back(tag_t("building", "yes")); } else if (placehouse) { places.push_back(tag_t("place", "house")); } else if (postcode) { places.push_back(tag_t("place", "postcode")); } } // housenumbers if (!isinterpolation) { if (street_nr && conscr_nr) { housenumber.clear(); escape(*conscr_nr, housenumber); housenumber.append("/"); escape(*street_nr, housenumber); } else if (conscr_nr) { housenumber.clear(); escape(*conscr_nr, housenumber); } else if (street_nr) { housenumber.clear(); escape(*street_nr, housenumber); } else if (house_nr) { housenumber.clear(); escape(*house_nr, housenumber); } } }
int output_pgsql_t::pgsql_out_relation(osmid_t id, const taglist_t &rel_tags, const multinodelist_t &xnodes, const multitaglist_t & xtags, const idlist_t &xid, const rolelist_t &xrole, bool pending) { if (xnodes.empty()) return 0; int roads = 0; int make_polygon = 0; int make_boundary = 0; double split_at; std::vector<int> members_superseeded(xnodes.size(), 0); taglist_t outtags; //if its a route relation make_boundary and make_polygon will be false otherwise one or the other will be true if (m_tagtransform->filter_rel_member_tags(rel_tags, xtags, xrole, &(members_superseeded[0]), &make_boundary, &make_polygon, &roads, *m_export_list.get(), outtags)) { return 0; } /* Split long linear ways after around 1 degree or 100km (polygons not effected) */ if (m_options.projection->get_proj_id() == PROJ_LATLONG) split_at = 1; else split_at = 100 * 1000; //this will either make lines or polygons (unless the lines arent a ring or are less than 3 pts) depending on the tag transform above //TODO: pick one or the other based on which we expect to care about auto wkbs = builder.build_both(xnodes, make_polygon, m_options.enable_multi, split_at, id); if (wkbs.empty()) { return 0; } tag_t *areatag = 0; char tmp[32]; for (const auto& wkb: wkbs) { expire->from_wkb(wkb.geom.c_str(), -id); /* FIXME: there should be a better way to detect polygons */ if (wkb.is_polygon()) { if ((wkb.area > 0.0) && m_enable_way_area) { snprintf(tmp, sizeof(tmp), "%g", wkb.area); if (!areatag) { outtags.push_dedupe(tag_t("way_area", tmp)); areatag = outtags.find("way_area"); } } m_tables[t_poly]->write_row(-id, outtags, wkb.geom); } else { m_tables[t_line]->write_row(-id, outtags, wkb.geom); if (roads) m_tables[t_roads]->write_row(-id, outtags, wkb.geom); } } /* Tagtransform will have marked those member ways of the relation that * have fully been dealt with as part of the multi-polygon entry. * Set them in the database as done and delete their entry to not * have duplicates */ //dont do this when working with pending relations as its not needed if (make_polygon) { for (size_t i=0; i < xid.size(); i++) { if (members_superseeded[i]) { pgsql_delete_way_from_output(xid[i]); if(!pending) ways_done_tracker->mark(xid[i]); } } } // If the tag transform said the polygon looked like a boundary we want to make that as well // If we are making a boundary then also try adding any relations which form complete rings // The linear variants will have already been processed above if (make_boundary) { wkbs = builder.build_polygons(xnodes, m_options.enable_multi, id); for (const auto& wkb: wkbs) { expire->from_wkb(wkb.geom.c_str(), -id); if ((wkb.area > 0.0) && m_enable_way_area) { snprintf(tmp, sizeof(tmp), "%g", wkb.area); if (!areatag) { outtags.push_dedupe(tag_t("way_area", tmp)); areatag = outtags.find("way_area"); } } m_tables[t_poly]->write_row(-id, outtags, wkb.geom); } } return 0; }
/* This is the workhorse of pgsql_add_relation, split out because it is used as the callback for iterate relations */ int output_pgsql_t::pgsql_process_relation(osmium::Relation const &rel) { taglist_t prefiltered_tags; if (m_tagtransform->filter_tags(rel, nullptr, nullptr, prefiltered_tags)) { return 1; } idlist_t xid2; for (auto const &m : rel.members()) { /* Need to handle more than just ways... */ if (m.type() == osmium::item_type::way) { xid2.push_back(m.ref()); } } buffer.clear(); rolelist_t xrole; auto num_ways = m_mid->rel_way_members_get(rel, &xrole, buffer); if (num_ways == 0) return 0; int roads = 0; int make_polygon = 0; int make_boundary = 0; taglist_t outtags; // If it's a route relation make_boundary and make_polygon will be false // otherwise one or the other will be true. if (m_tagtransform->filter_rel_member_tags(prefiltered_tags, buffer, xrole, &make_boundary, &make_polygon, &roads, outtags)) { return 0; } for (auto &w : buffer.select<osmium::Way>()) { m_mid->nodes_get_list(&(w.nodes())); } // linear features and boundaries // Needs to be done before the polygon treatment below because // for boundaries the way_area tag may be added. if (!make_polygon) { double const split_at = m_options.projection->target_latlon() ? 1 : 100 * 1000; auto wkbs = m_builder.get_wkb_multiline(buffer, split_at); for (auto const &wkb : wkbs) { expire.from_wkb(wkb.c_str(), -rel.id()); m_tables[t_line]->write_row(-rel.id(), outtags, wkb); if (roads) m_tables[t_roads]->write_row(-rel.id(), outtags, wkb); } } // multipolygons and boundaries if (make_boundary || make_polygon) { auto wkbs = m_builder.get_wkb_multipolygon(rel, buffer); char tmp[32]; for (auto const &wkb : wkbs) { expire.from_wkb(wkb.c_str(), -rel.id()); if (m_enable_way_area) { auto const area = m_options.reproject_area ? ewkb::parser_t(wkb).get_area<reprojection>( m_options.projection.get()) : ewkb::parser_t(wkb) .get_area<osmium::geom::IdentityProjection>(); snprintf(tmp, sizeof(tmp), "%g", area); outtags.push_override(tag_t("way_area", tmp)); } m_tables[t_poly]->write_row(-rel.id(), outtags, wkb); } } return 0; }
unsigned lua_tagtransform_t::filter_rel_member_tags( taglist_t const &rel_tags, multitaglist_t const &members_tags, rolelist_t const &member_roles, int *member_superseded, int *make_boundary, int *make_polygon, int *roads, export_list const &, taglist_t &out_tags, bool) { lua_getglobal(L, m_rel_mem_func.c_str()); lua_newtable(L); /* relations key value table */ for (const auto &rel_tag : rel_tags) { lua_pushstring(L, rel_tag.key.c_str()); lua_pushstring(L, rel_tag.value.c_str()); lua_rawset(L, -3); } lua_newtable(L); /* member tags table */ int idx = 1; for (const auto &member_tags : members_tags) { lua_pushnumber(L, idx++); lua_newtable(L); /* member key value table */ for (const auto &member_tag : member_tags) { lua_pushstring(L, member_tag.key.c_str()); lua_pushstring(L, member_tag.value.c_str()); lua_rawset(L, -3); } lua_rawset(L, -3); } lua_newtable(L); /* member roles table */ for (size_t i = 0; i < member_roles.size(); i++) { lua_pushnumber(L, i + 1); lua_pushstring(L, member_roles[i]); lua_rawset(L, -3); } lua_pushnumber(L, member_roles.size()); if (lua_pcall(L, 4, 6, 0)) { fprintf( stderr, "Failed to execute lua function for relation tag processing: %s\n", lua_tostring(L, -1)); /* lua function failed */ return 1; } *roads = (int)lua_tointeger(L, -1); lua_pop(L, 1); *make_polygon = (int)lua_tointeger(L, -1); lua_pop(L, 1); *make_boundary = (int)lua_tointeger(L, -1); lua_pop(L, 1); lua_pushnil(L); for (size_t i = 0; i < members_tags.size(); i++) { if (lua_next(L, -2)) { member_superseded[i] = (int)lua_tointeger(L, -1); lua_pop(L, 1); } else { fprintf(stderr, "Failed to read member_superseded from lua function\n"); } } lua_pop(L, 2); lua_pushnil(L); while (lua_next(L, -2) != 0) { const char *key = lua_tostring(L, -2); const char *value = lua_tostring(L, -1); out_tags.push_back(tag_t(key, value)); lua_pop(L, 1); } lua_pop(L, 1); unsigned filter = (unsigned)lua_tointeger(L, -1); lua_pop(L, 1); return filter; }