diff --git a/filter/CMakeLists.txt b/filter/CMakeLists.txt index 2fd1d6d..990db22 100644 --- a/filter/CMakeLists.txt +++ b/filter/CMakeLists.txt @@ -10,5 +10,6 @@ add_executable( ${NAME} ${NAME}.cpp RTree.h + xml_centers_output.hpp ) target_link_libraries(${NAME} ${OSMIUM_IO_LIBRARIES}) diff --git a/filter/filter_planet_by_cats.cpp b/filter/filter_planet_by_cats.cpp index a65d33b..9f21468 100644 --- a/filter/filter_planet_by_cats.cpp +++ b/filter/filter_planet_by_cats.cpp @@ -32,46 +32,33 @@ #include #include "RTree.h" +#include "xml_centers_output.hpp" using index_type = osmium::index::map::FlexMem; using location_handler_type = osmium::handler::NodeLocationsForWays; -class AmenityRelationsManager : public osmium::relations::RelationsManager { -public: - - bool new_relation(osmium::Relation const & rel) noexcept { - const char *rel_type = rel.tags().get_value_by_key("type"); - return rel_type && !std::strcmp(rel_type, "multipolygon"); - } - - void complete_relation(osmium::Relation const & rel) { - this->buffer().add_item(rel); - this->buffer().commit(); - } -}; - bool AppendToVector(uint16_t cat_id, void *vec) { static_cast*>(vec)->push_back(cat_id); + return true; } class AmenityHandler : public osmium::handler::Handler { - constexpr static double kSearchRadius = 0.001; // ~1 km TODO! revert to 0.01 + constexpr static double kSearchRadius = 0.0001; // ~1 km TODO! revert to 0.01 typedef RTree DatasetTree; typedef std::vector> TQuery; typedef std::vector TCategory; DatasetTree m_tree; - osmium::io::Writer &m_writer; + osmium::io::xmlcenters::XMLCentersOutput m_centers; std::map> m_categories; std::map m_category_names; void print_object(const osmium::OSMObject &obj, const osmium::Location ¢er) { - // TODO - std::cout << obj.type() << ' ' << obj.id() << std::endl; + std::cout << m_centers.apply(obj, center); } // Calculate the center point of a NodeRefList. @@ -134,11 +121,13 @@ class AmenityHandler : public osmium::handler::Handler { TQuery ParseQuery(std::string const & query) { TQuery q; - std::vector parts, keys; + std::vector parts; SplitTrim(query, '|', 100, parts); for (std::string const & part : parts) { + std::vector keys; SplitTrim(part, '=', 100, keys); - // TODO + if (keys.size() > 0) + q.push_back(keys); } return q; } @@ -169,8 +158,7 @@ class AmenityHandler : public osmium::handler::Handler { } public: - AmenityHandler(const char *categories, osmium::io::Writer &writer) - : m_writer(writer) { + AmenityHandler(const char *categories) { LoadCategories(categories); } @@ -201,24 +189,7 @@ public: } } - void relation(osmium::Relation const & rel) { - int64_t x = 0, y = 0, cnt = 0; - for (const auto& member : rel.members()) { - if (member.full_member() && member.type() == osmium::item_type::way) { - const osmium::Way *way = reinterpret_cast(&member.get_object()); - for (const auto& node_ref : way->nodes()) { - if (false && node_ref.location()) { - x += node_ref.x(); - y += node_ref.y(); - cnt++; - } - } - } - } - if (!cnt) - return; - - const osmium::Location center(x / cnt, y / cnt); + void multi(osmium::Relation const & rel, osmium::Location const & center) { if (IsEligible(center, rel.tags())) { print_object(rel, center); } @@ -226,37 +197,67 @@ public: }; // class AmenityHandler +class AmenityRelationsManager : public osmium::relations::RelationsManager { + + AmenityHandler *m_handler; + +public: + + AmenityRelationsManager(AmenityHandler & handler) : + RelationsManager(), + m_handler(&handler) { + } + + bool new_relation(osmium::Relation const & rel) noexcept { + const char *rel_type = rel.tags().get_value_by_key("type"); + return rel_type && !std::strcmp(rel_type, "multipolygon"); + } + + void complete_relation(osmium::Relation const & rel) { + int64_t x = 0, y = 0, cnt = 0; + for (auto const & member : rel.members()) { + if (member.ref() != 0) { + const osmium::Way* way = this->get_member_way(member.ref()); + for (const auto& node_ref : way->nodes()) { + if (node_ref.location()) { + x += node_ref.x(); + y += node_ref.y(); + cnt++; + } + } + } + } + if (cnt > 0) + m_handler->multi(rel, osmium::Location{x / cnt, y / cnt}); + } +}; // class AmenityRelationsManager + int main(int argc, char *argv[]) { if (argc < 3) { std::cerr << "Usage: " << argv[0] - << " []\n"; + << " \n"; std::exit(1); } const osmium::io::File input_file{argv[2]}; - const osmium::io::File output_file{argc > 3 ? argv[3] : "", "osm"}; + const osmium::io::File output_file{"", "osm"}; - std::cerr << "Pass 1/2: Reading relations...\n"; - AmenityRelationsManager manager; + AmenityHandler data_handler(argv[1]); + AmenityRelationsManager manager(data_handler); osmium::relations::read_relations(input_file, manager); osmium::io::Header header; header.set("generator", argv[0]); osmium::io::Writer writer{output_file, header, osmium::io::overwrite::allow}; - AmenityHandler data_handler(argv[1], writer); - std::cerr << "Pass 2/2: Filtering points...\n"; index_type index; location_handler_type location_handler{index}; location_handler.ignore_errors(); osmium::io::Reader reader{input_file}; - osmium::apply(reader, location_handler, data_handler, - manager.handler( - [&data_handler](const osmium::memory::Buffer &area_buffer) { - osmium::apply(area_buffer, data_handler); - })); + osmium::apply(reader, location_handler, data_handler, manager.handler()); + std::cout.flush(); reader.close(); writer.close(); } diff --git a/filter/xml_centers_output.hpp b/filter/xml_centers_output.hpp new file mode 100644 index 0000000..514c07e --- /dev/null +++ b/filter/xml_centers_output.hpp @@ -0,0 +1,277 @@ +/* + +This file is part of Osmium (http://osmcode.org/libosmium). + +Copyright 2013-2017 Jochen Topf and others (see README). + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace osmium { + + namespace io { + + namespace xmlcenters { + + namespace detail { + + inline void append_lat_lon_attributes(std::string& out, const char* lat, const char* lon, const osmium::Location& location) { + out += ' '; + out += lat; + out += "=\""; + osmium::detail::append_location_coordinate_to_string(std::back_inserter(out), location.y()); + out += "\" "; + out += lon; + out += "=\""; + osmium::detail::append_location_coordinate_to_string(std::back_inserter(out), location.x()); + out += "\""; + } + + } // namespace detail + + class XMLCentersOutput { + + std::shared_ptr m_out; + + inline void append_xml_encoded_string(std::string & out, const char *data) { + osmium::io::detail::append_xml_encoded_string(out, data); + } + + void output_int(int64_t value) { + if (value < 0) { + *m_out += '-'; + value = -value; + } + + char temp[20]; + char *t = temp; + do { + *t++ = char(value % 10) + '0'; + value /= 10; + } while (value > 0); + + const auto old_size = m_out->size(); + m_out->resize(old_size + (t - temp)); + char* data = &(*m_out)[old_size]; + do { + *data++ += *--t; + } while (t != temp); + } + + void write_spaces(int num) { + for (; num != 0; --num) { + *m_out += ' '; + } + } + + void write_prefix() { + write_spaces(2); + } + + template + void write_attribute(const char* name, T value) { + *m_out += ' '; + *m_out += name; + *m_out += "=\""; + output_int(value); + *m_out += '"'; + } + + void write_meta(const osmium::OSMObject& object) { + write_attribute("id", object.id()); + + if (object.version()) { + write_attribute("version", object.version()); + } + + if (object.timestamp()) { + *m_out += " timestamp=\""; + *m_out += object.timestamp().to_iso(); + *m_out += "\""; + } + + if (!object.user_is_anonymous()) { + write_attribute("uid", object.uid()); + *m_out += " user=\""; + append_xml_encoded_string(*m_out, object.user()); + *m_out += "\""; + } + + if (object.changeset()) { + write_attribute("changeset", object.changeset()); + } + } + + void write_tags(const osmium::TagList& tags) { + for (const auto& tag : tags) { + write_spaces(2); + *m_out += " \n"; + } + } + + public: + + XMLCentersOutput() : m_out(std::make_shared()) { + } + + std::string apply(osmium::OSMObject const & item, osmium::Location const & center) { + switch(item.type()) { + case osmium::item_type::node: + node(static_cast(item)); + break; + case osmium::item_type::way: + way(static_cast(item), center); + break; + case osmium::item_type::relation: + relation(static_cast(item), center); + break; + default: + throw osmium::unknown_type{}; + } + + std::string out; + using std::swap; + swap(out, *m_out); + + return out; + } + + void node(const osmium::Node& node) { + write_prefix(); + *m_out += "\n"; + } + + write_tags(relation.tags()); + + write_prefix(); + *m_out += "\n"; + } + + }; // class XMLCentersOutputBlock + + } // namespace xmlcenters + + } // namespace io + +} // namespace osmium