199 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| 
 | |
|   EXAMPLE osmium_area_test
 | |
| 
 | |
|   Create multipolygons from OSM data and dump them to stdout in one of two
 | |
|   formats: WKT or using the built-in Dump format.
 | |
| 
 | |
|   DEMONSTRATES USE OF:
 | |
|   * file input
 | |
|   * location indexes and the NodeLocationsForWays handler
 | |
|   * the MultipolygonManager and Assembler to assemble areas (multipolygons)
 | |
|   * your own handler that works with areas (multipolygons)
 | |
|   * the WKTFactory to write geometries in WKT format
 | |
|   * the Dump handler
 | |
|   * the DynamicHandler
 | |
| 
 | |
|   SIMPLER EXAMPLES you might want to understand first:
 | |
|   * osmium_read
 | |
|   * osmium_count
 | |
|   * osmium_debug
 | |
|   * osmium_amenity_list
 | |
| 
 | |
|   LICENSE
 | |
|   The code in this example file is released into the Public Domain.
 | |
| 
 | |
| */
 | |
| 
 | |
| #include <cstdlib>  // for std::exit
 | |
| #include <cstring>  // for std::strcmp
 | |
| #include <iostream> // for std::cout, std::cerr
 | |
| 
 | |
| // For assembling multipolygons
 | |
| #include <osmium/area/assembler.hpp>
 | |
| #include <osmium/area/multipolygon_manager.hpp>
 | |
| 
 | |
| // For the DynamicHandler class
 | |
| #include <osmium/dynamic_handler.hpp>
 | |
| 
 | |
| // For the WKT factory
 | |
| #include <osmium/geom/wkt.hpp>
 | |
| 
 | |
| // For the Dump handler
 | |
| #include <osmium/handler/dump.hpp>
 | |
| 
 | |
| // For the NodeLocationForWays handler
 | |
| #include <osmium/handler/node_locations_for_ways.hpp>
 | |
| 
 | |
| // Allow any format of input files (XML, PBF, ...)
 | |
| #include <osmium/io/any_input.hpp>
 | |
| 
 | |
| // For osmium::apply()
 | |
| #include <osmium/visitor.hpp>
 | |
| 
 | |
| // For the location index. There are different types of indexes available.
 | |
| // This will work for all input files keeping the index in memory.
 | |
| #include <osmium/index/map/flex_mem.hpp>
 | |
| 
 | |
| // The type of index used. This must match the include file above
 | |
| using index_type = osmium::index::map::FlexMem<osmium::unsigned_object_id_type, osmium::Location>;
 | |
| 
 | |
| // The location handler always depends on the index type
 | |
| using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
 | |
| 
 | |
| // This handler writes all area geometries out in WKT (Well Known Text) format.
 | |
| class WKTDump : public osmium::handler::Handler {
 | |
| 
 | |
|     // This factory is used to create a geometry in WKT format from OSM
 | |
|     // objects. The template parameter is empty here, because we output WGS84
 | |
|     // coordinates, but could be used for a projection.
 | |
|     osmium::geom::WKTFactory<> m_factory;
 | |
| 
 | |
| public:
 | |
| 
 | |
|     // This callback is called by osmium::apply for each area in the data.
 | |
|     void area(const osmium::Area& area) {
 | |
|         try {
 | |
|             std::cout << m_factory.create_multipolygon(area) << "\n";
 | |
|         } catch (const osmium::geometry_error& e) {
 | |
|             std::cout << "GEOMETRY ERROR: " << e.what() << "\n";
 | |
|         }
 | |
|     }
 | |
| 
 | |
| }; // class WKTDump
 | |
| 
 | |
| void print_help() {
 | |
|     std::cout << "osmium_area_test [OPTIONS] OSMFILE\n\n"
 | |
|               << "Read OSMFILE and build multipolygons from it.\n"
 | |
|               << "\nOptions:\n"
 | |
|               << "  -h, --help           This help message\n"
 | |
|               << "  -w, --dump-wkt       Dump area geometries as WKT\n"
 | |
|               << "  -o, --dump-objects   Dump area objects\n";
 | |
| }
 | |
| 
 | |
| void print_usage(const char* prgname) {
 | |
|     std::cerr << "Usage: " << prgname << " [OPTIONS] OSMFILE\n";
 | |
|     std::exit(1);
 | |
| }
 | |
| 
 | |
| int main(int argc, char* argv[]) {
 | |
|     if (argc > 1 && (!std::strcmp(argv[1], "-h") ||
 | |
|                      !std::strcmp(argv[1], "--help"))) {
 | |
|         print_help();
 | |
|         std::exit(0);
 | |
|     }
 | |
| 
 | |
|     if (argc != 3) {
 | |
|         print_usage(argv[0]);
 | |
|     }
 | |
| 
 | |
|     // Initialize an empty DynamicHandler. Later it will be associated
 | |
|     // with one of the handlers. You can think of the DynamicHandler as
 | |
|     // a kind of "variant handler" or a "pointer handler" pointing to the
 | |
|     // real handler.
 | |
|     osmium::handler::DynamicHandler handler;
 | |
| 
 | |
|     if (!std::strcmp(argv[1], "-w") || !std::strcmp(argv[1], "--dump-wkt")) {
 | |
|         handler.set<WKTDump>();
 | |
|     } else if (!std::strcmp(argv[1], "-o") || !std::strcmp(argv[1], "--dump-objects")) {
 | |
|         handler.set<osmium::handler::Dump>(std::cout);
 | |
|     } else {
 | |
|         print_usage(argv[0]);
 | |
|     }
 | |
| 
 | |
|     osmium::io::File input_file{argv[2]};
 | |
| 
 | |
|     // Configuration for the multipolygon assembler. Here the default settings
 | |
|     // are used, but you could change multiple settings.
 | |
|     osmium::area::Assembler::config_type assembler_config;
 | |
| 
 | |
|     // Set up a filter matching only forests. This will be used to only build
 | |
|     // areas with matching tags.
 | |
|     osmium::TagsFilter filter{false};
 | |
|     filter.add_rule(true, "landuse", "forest");
 | |
|     filter.add_rule(true, "natural", "wood");
 | |
| 
 | |
|     // Initialize the MultipolygonManager. Its job is to collect all
 | |
|     // relations and member ways needed for each area. It then calls an
 | |
|     // instance of the osmium::area::Assembler class (with the given config)
 | |
|     // to actually assemble one area. The filter parameter is optional, if
 | |
|     // it is not set, all areas will be built.
 | |
|     osmium::area::MultipolygonManager<osmium::area::Assembler> mp_manager{assembler_config, filter};
 | |
| 
 | |
|     // We read the input file twice. In the first pass, only relations are
 | |
|     // read and fed into the multipolygon manager.
 | |
|     std::cerr << "Pass 1...\n";
 | |
|     osmium::relations::read_relations(input_file, mp_manager);
 | |
|     std::cerr << "Pass 1 done\n";
 | |
| 
 | |
|     // Output the amount of main memory used so far. All multipolygon relations
 | |
|     // are in memory now.
 | |
|     std::cerr << "Memory:\n";
 | |
|     osmium::relations::print_used_memory(std::cerr, mp_manager.used_memory());
 | |
| 
 | |
|     // The index storing all node locations.
 | |
|     index_type index;
 | |
| 
 | |
|     // The handler that stores all node locations in the index and adds them
 | |
|     // to the ways.
 | |
|     location_handler_type location_handler{index};
 | |
| 
 | |
|     // If a location is not available in the index, we ignore it. It might
 | |
|     // not be needed (if it is not part of a multipolygon relation), so why
 | |
|     // create an error?
 | |
|     location_handler.ignore_errors();
 | |
| 
 | |
|     // On the second pass we read all objects and run them first through the
 | |
|     // node location handler and then the multipolygon collector. The collector
 | |
|     // will put the areas it has created into the "buffer" which are then
 | |
|     // fed through our "handler".
 | |
|     std::cerr << "Pass 2...\n";
 | |
|     osmium::io::Reader reader{input_file};
 | |
|     osmium::apply(reader, location_handler, mp_manager.handler([&handler](osmium::memory::Buffer&& buffer) {
 | |
|         osmium::apply(buffer, handler);
 | |
|     }));
 | |
|     reader.close();
 | |
|     std::cerr << "Pass 2 done\n";
 | |
| 
 | |
|     // Output the amount of main memory used so far. All complete multipolygon
 | |
|     // relations have been cleaned up.
 | |
|     std::cerr << "Memory:\n";
 | |
|     osmium::relations::print_used_memory(std::cerr, mp_manager.used_memory());
 | |
| 
 | |
|     // If there were multipolgyon relations in the input, but some of their
 | |
|     // members are not in the input file (which often happens for extracts)
 | |
|     // this will write the IDs of the incomplete relations to stderr.
 | |
|     std::vector<osmium::object_id_type> incomplete_relations_ids;
 | |
|     mp_manager.for_each_incomplete_relation([&](const osmium::relations::RelationHandle& handle){
 | |
|         incomplete_relations_ids.push_back(handle->id());
 | |
|     });
 | |
|     if (!incomplete_relations_ids.empty()) {
 | |
|         std::cerr << "Warning! Some member ways missing for these multipolygon relations:";
 | |
|         for (const auto id : incomplete_relations_ids) {
 | |
|             std::cerr << " " << id;
 | |
|         }
 | |
|         std::cerr << "\n";
 | |
|     }
 | |
| }
 | |
| 
 |