Osmium  0.1
include/osmium/handler/multipolygon.hpp
Go to the documentation of this file.
00001 #ifndef OSMIUM_HANDLER_MULTIPOLYGON_HPP
00002 #define OSMIUM_HANDLER_MULTIPOLYGON_HPP
00003 
00004 /*
00005 
00006 Copyright 2011 Jochen Topf <jochen@topf.org> and others (see README).
00007 
00008 This file is part of Osmium (https://github.com/joto/osmium).
00009 
00010 Osmium is free software: you can redistribute it and/or modify it under the
00011 terms of the GNU Lesser General Public License or (at your option) the GNU
00012 General Public License as published by the Free Software Foundation, either
00013 version 3 of the Licenses, or (at your option) any later version.
00014 
00015 Osmium is distributed in the hope that it will be useful, but WITHOUT ANY
00016 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
00017 PARTICULAR PURPOSE. See the GNU Lesser General Public License and the GNU
00018 General Public License for more details.
00019 
00020 You should have received a copy of the Licenses along with Osmium. If not, see
00021 <http://www.gnu.org/licenses/>.
00022 
00023 */
00024 
00025 #include <google/sparse_hash_map>
00026 
00027 #include <osmium/handler.hpp>
00028 #include <osmium/osm/way.hpp>
00029 #include <osmium/osm/area.hpp>
00030 
00031 namespace Osmium {
00032 
00033     namespace Handler {
00034 
00035         class Multipolygon : public Base {
00036 
00038             std::vector<Osmium::OSM::AreaFromRelation*> m_areas;
00039 
00040             // a map from way_id to a vector of indexes into the areas array
00041             // this is used to find in which multipolygon relations a way is
00042             typedef google::sparse_hash_map<osm_object_id_t, std::vector<osm_object_id_t> > way2areaidx_t;
00043             way2areaidx_t m_way2areaidx;
00044 
00045             bool m_attempt_repair;
00046             void (*m_callback_area)(Osmium::OSM::Area*);
00047 
00048             uint64_t m_count_ways_in_all_areas;
00049 
00050         public:
00051 
00052             Multipolygon(bool attempt_repair,
00053                          void (*callback_area)(Osmium::OSM::Area*))
00054                 : Base(),
00055                   m_areas(),
00056                   m_way2areaidx(),
00057                   m_attempt_repair(attempt_repair),
00058                   m_callback_area(callback_area),
00059                   m_count_ways_in_all_areas(0) {
00060             }
00061 
00062             // in pass 1
00063             void relation(const shared_ptr<Osmium::OSM::Relation const>& relation) {
00064                 const char* type = relation->tags().get_tag_by_key("type");
00065 
00066                 // ignore relations without "type" tag
00067                 if (!type) {
00068                     return;
00069                 }
00070 
00071                 bool is_boundary;
00072                 if (strcmp(type, "multipolygon") == 0) {
00073                     is_boundary = false;
00074                 } else if (strcmp(type, "boundary") == 0) {
00075                     is_boundary = true;
00076                 } else {
00077                     return;
00078                 }
00079 
00080                 int num_ways = 0;
00081                 for (osm_sequence_id_t i=0; i < relation->members().size(); i++) {
00082                     const Osmium::OSM::RelationMember* member = relation->get_member(i);
00083                     if (member->type() == 'w') {
00084                         m_way2areaidx[member->ref()].push_back(m_areas.size());
00085                         num_ways++;
00086                     } else {
00087                         std::cerr << "warning: multipolygon/boundary relation "
00088                                   << relation->id()
00089                                   << " has a non-way member which was ignored\n";
00090                     }
00091                 }
00092 
00093                 m_count_ways_in_all_areas += num_ways;
00094 
00095                 Osmium::OSM::AreaFromRelation* area = new Osmium::OSM::AreaFromRelation(new Osmium::OSM::Relation(*relation), is_boundary, num_ways, m_callback_area, m_attempt_repair);
00096                 m_areas.push_back(area);
00097             }
00098 
00099             // in pass 1
00100             void after_relations() {
00101                 if (Osmium::debug()) {
00102                     std::cerr << "found " << m_areas.size() << " areas (each needs "
00103                               << sizeof(Osmium::OSM::Area) << " bytes, thats together about "
00104                               << sizeof(Osmium::OSM::Area) * m_areas.size() / (1024 * 1024) << "MB)\n"
00105                               << "they used " << m_count_ways_in_all_areas << " ways (each will need "
00106                               << sizeof(Osmium::OSM::Way) << " bytes, thats in the worst case together about "
00107                               << sizeof(Osmium::OSM::Way) * m_count_ways_in_all_areas / (1024 * 1024) << "MB)\n";
00108                 }
00109             }
00110 
00111             // in pass 2
00112             void way(const shared_ptr<Osmium::OSM::Way>& way) {
00113                 way2areaidx_t::const_iterator way2areaidx_iterator(m_way2areaidx.find(way->id()));
00114 
00115                 if (way2areaidx_iterator == m_way2areaidx.end()) { // not in any relation
00116                     if (way->is_closed() && way->node_count() >= 4) { // way is closed and has enough nodes, build simple multipolygon
00117 #ifdef OSMIUM_WITH_GEOS
00118                         Osmium::Geometry::Polygon polygon(*way);
00119                         Osmium::OSM::AreaFromWay* area = new Osmium::OSM::AreaFromWay(way.get(), polygon.create_geos_geometry());
00120 #else
00121                         Osmium::OSM::AreaFromWay* area = new Osmium::OSM::AreaFromWay(way.get());
00122 #endif // OSMIUM_WITH_GEOS
00123                         if (Osmium::debug()) {
00124                             std::cerr << "MP simple way_id=" << way->id() << "\n";
00125                         }
00126                         m_callback_area(area);
00127                         delete area;
00128                     }
00129                     return;
00130                 }
00131 
00132                 // is in at least one multipolygon relation
00133 
00134                 std::vector<osm_object_id_t> v = way2areaidx_iterator->second;
00135                 if (Osmium::debug()) std::cerr << "MP way_id=" << way->id() << " is in " << v.size() << " areas\n";
00136 
00137                 // go through all the areas this way is in
00138                 for (unsigned int i=0; i < v.size(); i++) {
00139                     Osmium::OSM::AreaFromRelation* area = m_areas[v[i]];
00140                     if (!area) {
00141                         throw std::runtime_error("Zero multipolygon. This should not happen. Reason can be a way appearing more than once in your input file.");
00142                     }
00143                     if (Osmium::debug()) {
00144                         std::cerr << "MP multi way_id=" << way->id() << " is in relation_id=" << area->id() << "\n";
00145                     }
00146 
00147                     // store copy of current way in multipolygon
00148                     area->add_member_way(way.get());
00149 
00150                     if (area->is_complete()) {
00151                         area->handle_complete_multipolygon();
00152                         m_areas[v[i]] = NULL;
00153                         delete area;
00154                     }
00155                 }
00156             }
00157 
00158             // in pass 2
00159             void after_ways() {
00160                 m_way2areaidx.clear();
00161             }
00162 
00163             void init(Osmium::OSM::Meta&) {
00164 #ifdef OSMIUM_WITH_MULTIPOLYGON_PROFILING
00165                 Osmium::OSM::AreaFromRelation::init_timings();
00166 #endif // OSMIUM_WITH_MULTIPOLYGON_PROFILING
00167             }
00168 
00169             void final() {
00170 #ifdef OSMIUM_WITH_MULTIPOLYGON_PROFILING
00171                 Osmium::OSM::AreaFromRelation::print_timings();
00172 #endif // OSMIUM_WITH_MULTIPOLYGON_PROFILING
00173             }
00174 
00175         }; // class Multipolygon
00176 
00177     } // namespace Handler
00178 
00179 } // namespace Osmium
00180 
00181 #endif // OSMIUM_HANDLER_MULTIPOLYGON_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines