Merge commit '6eb4f090f98f6b17a23c57768c16b7716b6c9cbd' as 'third_party/libosmium'
This commit is contained in:
+74
@@ -0,0 +1,74 @@
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
# CMake Config
|
||||
#
|
||||
# Libosmium examples
|
||||
#
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
message(STATUS "Configuring examples")
|
||||
|
||||
set(EXAMPLES
|
||||
amenity_list
|
||||
area_test
|
||||
change_tags
|
||||
convert
|
||||
count
|
||||
create_pois
|
||||
debug
|
||||
dump_internal
|
||||
filter_discussions
|
||||
index_lookup
|
||||
location_cache_create
|
||||
location_cache_use
|
||||
pub_names
|
||||
read
|
||||
read_with_progress
|
||||
road_length
|
||||
tiles
|
||||
CACHE STRING "Example programs"
|
||||
)
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
# Examples depending on wingetopt
|
||||
#
|
||||
#-----------------------------------------------------------------------------
|
||||
set(GETOPT_EXAMPLES area_test convert index_lookup)
|
||||
if(NOT GETOPT_MISSING)
|
||||
foreach(example ${GETOPT_EXAMPLES})
|
||||
list(APPEND EXAMPLE_LIBS_${example} ${GETOPT_LIBRARY})
|
||||
endforeach()
|
||||
else()
|
||||
message(STATUS "Configuring examples - Skipping examples because on Visual Studio the wingetopt library is needed and was not found:")
|
||||
foreach(example ${GETOPT_EXAMPLES})
|
||||
message(STATUS " - osmium_${example}")
|
||||
list(REMOVE_ITEM EXAMPLES ${example})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
# Configure examples
|
||||
#
|
||||
#-----------------------------------------------------------------------------
|
||||
message(STATUS "Configuring examples - Building these examples:")
|
||||
foreach(example ${EXAMPLES})
|
||||
message(STATUS " - osmium_${example}")
|
||||
add_executable(osmium_${example} "osmium_${example}.cpp")
|
||||
set_pthread_on_target(osmium_${example})
|
||||
target_link_libraries(osmium_${example} ${OSMIUM_IO_LIBRARIES} ${EXAMPLE_LIBS_${example}})
|
||||
add_test(NAME examples_usage_${example} COMMAND osmium_${example})
|
||||
set_tests_properties(examples_usage_${example} PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "^Usage: "
|
||||
)
|
||||
endforeach()
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
message(STATUS "Configuring examples - done")
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
|
||||
# Osmium example programs
|
||||
|
||||
The programs in this directory are intended as examples for developers. They
|
||||
contain extensive comments explaining what's going on. Note that the examples
|
||||
only cover a small part of what Osmium can do, you should also read the manuals
|
||||
and API documentation.
|
||||
|
||||
All programs can be run without arguments and they will tell you how to use
|
||||
them.
|
||||
|
||||
## Very simple examples
|
||||
|
||||
* `osmium_read`
|
||||
* `osmium_count`
|
||||
* `osmium_debug`
|
||||
* `osmium_tiles`
|
||||
|
||||
## Still reasonably simple examples
|
||||
|
||||
* `osmium_amenity_list`
|
||||
* `osmium_read_with_progress`
|
||||
* `osmium_filter_discussions`
|
||||
* `osmium_convert`
|
||||
* `osmium_pub_names`
|
||||
* `osmium_road_length`
|
||||
|
||||
## More advanced examples
|
||||
|
||||
* `osmium_area_test`
|
||||
* `osmium_create_pois`
|
||||
|
||||
## Even more advanced examples
|
||||
|
||||
* `osmium_change_tags`
|
||||
* `osmium_location_cache_create`
|
||||
* `osmium_location_cache_use`
|
||||
* `osmium_dump_internal`
|
||||
* `osmium_index_lookup`
|
||||
|
||||
## License
|
||||
|
||||
The code in these example files is released into the Public Domain. Feel free
|
||||
to copy the code and build on it.
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_amenity_list
|
||||
|
||||
Create a list of all amenities in the OSM input data. The type of amenity
|
||||
(tag value) and, if available, the name is printed. For nodes, the location
|
||||
is printed, for areas the center location.
|
||||
|
||||
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)
|
||||
* accessing tags
|
||||
* osmium::geom::Coordinates
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
* osmium_debug
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdio> // for std::printf
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <iostream> // for std::cerr
|
||||
#include <string> // for std::string
|
||||
|
||||
// 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>
|
||||
|
||||
// For the NodeLocationForWays handler
|
||||
#include <osmium/handler/node_locations_for_ways.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>;
|
||||
|
||||
// For assembling multipolygons
|
||||
#include <osmium/area/assembler.hpp>
|
||||
#include <osmium/area/multipolygon_manager.hpp>
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// For osmium::apply()
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
// For osmium::geom::Coordinates
|
||||
#include <osmium/geom/coordinates.hpp>
|
||||
|
||||
class AmenityHandler : public osmium::handler::Handler {
|
||||
|
||||
// Print info about one amenity to stdout.
|
||||
void print_amenity(const char* type, const char* name, const osmium::geom::Coordinates& c) {
|
||||
std::printf("%8.4f,%8.4f %-15s %s\n", c.x, c.y, type, name ? name : "");
|
||||
}
|
||||
|
||||
// Calculate the center point of a NodeRefList.
|
||||
osmium::geom::Coordinates calc_center(const osmium::NodeRefList& nr_list) {
|
||||
// Coordinates simply store an X and Y coordinate pair as doubles.
|
||||
// (Unlike osmium::Location which stores them more efficiently as
|
||||
// 32 bit integers.) Use Coordinates when you want to do calculations
|
||||
// or store projected coordinates.
|
||||
osmium::geom::Coordinates c{0.0, 0.0};
|
||||
|
||||
for (const auto& nr : nr_list) {
|
||||
c.x += nr.lon();
|
||||
c.y += nr.lat();
|
||||
}
|
||||
|
||||
c.x /= nr_list.size();
|
||||
c.y /= nr_list.size();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void node(const osmium::Node& node) {
|
||||
// Getting a tag value can be expensive, because a list of tags has
|
||||
// to be gone through and each tag has to be checked. So we store the
|
||||
// result and reuse it.
|
||||
const char* amenity = node.tags()["amenity"];
|
||||
if (amenity) {
|
||||
print_amenity(amenity, node.tags()["name"], node.location());
|
||||
}
|
||||
}
|
||||
|
||||
void area(const osmium::Area& area) {
|
||||
const char* amenity = area.tags()["amenity"];
|
||||
if (amenity) {
|
||||
// Use the center of the first outer ring. Because we set
|
||||
// create_empty_areas = false in the assembler config, we can
|
||||
// be sure there will always be at least one outer ring.
|
||||
const auto center = calc_center(*area.cbegin<osmium::OuterRing>());
|
||||
|
||||
print_amenity(amenity, area.tags()["name"], center);
|
||||
}
|
||||
}
|
||||
|
||||
}; // class AmenityHandler
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// The input file
|
||||
const osmium::io::File input_file{argv[1]};
|
||||
|
||||
// Configuration for the multipolygon assembler. We disable the option to
|
||||
// create empty areas when invalid multipolygons are encountered. This
|
||||
// means areas created have a valid geometry and invalid multipolygons
|
||||
// are simply ignored.
|
||||
osmium::area::Assembler::config_type assembler_config;
|
||||
assembler_config.create_empty_areas = false;
|
||||
|
||||
// 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.
|
||||
osmium::area::MultipolygonManager<osmium::area::Assembler> mp_manager{assembler_config};
|
||||
|
||||
// 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";
|
||||
|
||||
// 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();
|
||||
|
||||
// Create our handler.
|
||||
AmenityHandler data_handler;
|
||||
|
||||
// On the second pass we read all objects and run them first through the
|
||||
// node location handler and then the multipolygon manager. The manager
|
||||
// will put the areas it has created into the "buffer" which are then
|
||||
// fed through our handler.
|
||||
//
|
||||
// The read_meta::no option disables reading of meta data (such as version
|
||||
// numbers, timestamps, etc.) which are not needed in this case. Disabling
|
||||
// this can speed up your program.
|
||||
std::cerr << "Pass 2...\n";
|
||||
osmium::io::Reader reader{input_file, osmium::io::read_meta::no};
|
||||
|
||||
osmium::apply(reader, location_handler, data_handler, mp_manager.handler([&data_handler](const osmium::memory::Buffer& area_buffer) {
|
||||
osmium::apply(area_buffer, data_handler);
|
||||
}));
|
||||
|
||||
reader.close();
|
||||
std::cerr << "Pass 2 done\n";
|
||||
}
|
||||
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
|
||||
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 <getopt.h> // for getopt_long
|
||||
#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";
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
static struct option long_options[] = {
|
||||
{"help", no_argument, nullptr, 'h'},
|
||||
{"dump-wkt", no_argument, nullptr, 'w'},
|
||||
{"dump-objects", no_argument, nullptr, 'o'},
|
||||
{nullptr, 0, nullptr, 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;
|
||||
|
||||
// Read options from command line.
|
||||
while (true) {
|
||||
const int c = getopt_long(argc, argv, "hwo", long_options, nullptr);
|
||||
if (c == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case 'h':
|
||||
print_help();
|
||||
std::exit(0);
|
||||
case 'w':
|
||||
handler.set<WKTDump>();
|
||||
break;
|
||||
case 'o':
|
||||
handler.set<osmium::handler::Dump>(std::cout);
|
||||
break;
|
||||
default:
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
const int remaining_args = argc - optind;
|
||||
if (remaining_args != 1) {
|
||||
std::cerr << "Usage: " << argv[0] << " [OPTIONS] OSMFILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
osmium::io::File input_file{argv[optind]};
|
||||
|
||||
// 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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_change_tags
|
||||
|
||||
An example how tags in OSM files can be removed or changed. Removes
|
||||
"created_by" tags and changes tag "landuse=forest" into "natural_wood".
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input and output
|
||||
* Osmium buffers
|
||||
* your own handler
|
||||
* access to tags
|
||||
* using builders to write data
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
* osmium_pub_names
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <cstring> // for std::strcmp
|
||||
#include <exception> // for std::exception
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
#include <string> // for std::string
|
||||
#include <utility> // for std::move
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// Allow any format of output files (XML, PBF, ...)
|
||||
#include <osmium/io/any_output.hpp>
|
||||
|
||||
// We want to use the builder interface
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
|
||||
// We want to use the handler interface
|
||||
#include <osmium/handler.hpp>
|
||||
|
||||
// For osmium::apply()
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
// The functions in this class will be called for each object in the input
|
||||
// and will write a (changed) copy of those objects to the given buffer.
|
||||
class RewriteHandler : public osmium::handler::Handler {
|
||||
|
||||
osmium::memory::Buffer& m_buffer;
|
||||
|
||||
// Copy attributes common to all OSM objects (nodes, ways, and relations).
|
||||
template <typename T>
|
||||
void copy_attributes(T& builder, const osmium::OSMObject& object) {
|
||||
// The setter functions on the builder object all return the same
|
||||
// builder object so they can be chained.
|
||||
builder.set_id(object.id())
|
||||
.set_version(object.version())
|
||||
.set_changeset(object.changeset())
|
||||
.set_timestamp(object.timestamp())
|
||||
.set_uid(object.uid())
|
||||
.set_user(object.user());
|
||||
}
|
||||
|
||||
// Copy all tags with two changes:
|
||||
// * Do not copy "created_by" tags
|
||||
// * Change "landuse=forest" into "natural=wood"
|
||||
void copy_tags(osmium::builder::Builder& parent, const osmium::TagList& tags) {
|
||||
|
||||
// The TagListBuilder is used to create a list of tags. The parameter
|
||||
// to create it is a reference to the builder of the object that
|
||||
// should have those tags.
|
||||
osmium::builder::TagListBuilder builder{parent};
|
||||
|
||||
// Iterate over all tags and build new tags using the new builder
|
||||
// based on the old ones.
|
||||
for (const auto& tag : tags) {
|
||||
if (std::strcmp(tag.key(), "created_by")) {
|
||||
if (!std::strcmp(tag.key(), "landuse") && !std::strcmp(tag.value(), "forest")) {
|
||||
// add_tag() can be called with key and value C strings
|
||||
builder.add_tag("natural", "wood");
|
||||
} else {
|
||||
// add_tag() can also be called with an osmium::Tag
|
||||
builder.add_tag(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// Constructor. New data will be added to the given buffer.
|
||||
explicit RewriteHandler(osmium::memory::Buffer& buffer) :
|
||||
m_buffer(buffer) {
|
||||
}
|
||||
|
||||
// The node handler is called for each node in the input data.
|
||||
void node(const osmium::Node& node) {
|
||||
// Open a new scope, because the NodeBuilder we are creating has to
|
||||
// be destructed, before we can call commit() below.
|
||||
{
|
||||
// To create a node, we need a NodeBuilder object. It will create
|
||||
// the node in the given buffer.
|
||||
osmium::builder::NodeBuilder builder{m_buffer};
|
||||
|
||||
// Copy common object attributes over to the new node.
|
||||
copy_attributes(builder, node);
|
||||
|
||||
// Copy the location over to the new node.
|
||||
builder.set_location(node.location());
|
||||
|
||||
// Copy (changed) tags.
|
||||
copy_tags(builder, node.tags());
|
||||
}
|
||||
|
||||
// Once the object is written to the buffer completely, we have to call
|
||||
// commit().
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
// The way handler is called for each way in the input data.
|
||||
void way(const osmium::Way& way) {
|
||||
{
|
||||
osmium::builder::WayBuilder builder{m_buffer};
|
||||
copy_attributes(builder, way);
|
||||
copy_tags(builder, way.tags());
|
||||
|
||||
// Copy the node list over to the new way.
|
||||
builder.add_item(way.nodes());
|
||||
}
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
// The relation handler is called for each relation in the input data.
|
||||
void relation(const osmium::Relation& relation) {
|
||||
{
|
||||
osmium::builder::RelationBuilder builder{m_buffer};
|
||||
copy_attributes(builder, relation);
|
||||
copy_tags(builder, relation.tags());
|
||||
|
||||
// Copy the relation member list over to the new way.
|
||||
builder.add_item(relation.members());
|
||||
}
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
}; // class RewriteHandler
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " INFILE OUTFILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Get input and output file names from command line.
|
||||
std::string input_file_name{argv[1]};
|
||||
std::string output_file_name{argv[2]};
|
||||
|
||||
try {
|
||||
// Initialize Reader
|
||||
osmium::io::Reader reader{input_file_name};
|
||||
|
||||
// Get header from input file and change the "generator" setting to
|
||||
// ourselves.
|
||||
osmium::io::Header header = reader.header();
|
||||
header.set("generator", "osmium_change_tags");
|
||||
|
||||
// Initialize Writer using the header from above and tell it that it
|
||||
// is allowed to overwrite a possibly existing file.
|
||||
osmium::io::Writer writer{output_file_name, header, osmium::io::overwrite::allow};
|
||||
|
||||
// Read in buffers with OSM objects until there are no more.
|
||||
while (osmium::memory::Buffer input_buffer = reader.read()) {
|
||||
// Create an empty buffer with the same size as the input buffer.
|
||||
// We'll copy the changed data into output buffer, the changes
|
||||
// are small, so the output buffer needs to be about the same size.
|
||||
// In case it has to be bigger, we allow it to grow automatically
|
||||
// by adding the auto_grow::yes parameter.
|
||||
osmium::memory::Buffer output_buffer{input_buffer.committed(), osmium::memory::Buffer::auto_grow::yes};
|
||||
|
||||
// Construct a handler as defined above and feed the input buffer
|
||||
// to it.
|
||||
RewriteHandler handler{output_buffer};
|
||||
osmium::apply(input_buffer, handler);
|
||||
|
||||
// Write out the contents of the output buffer.
|
||||
writer(std::move(output_buffer));
|
||||
}
|
||||
|
||||
// Explicitly close the writer and reader. Will throw an exception if
|
||||
// there is a problem. If you wait for the destructor to close the writer
|
||||
// and reader, you will not notice the problem, because destructors must
|
||||
// not throw.
|
||||
writer.close();
|
||||
reader.close();
|
||||
} catch (const std::exception& e) {
|
||||
// All exceptions used by the Osmium library derive from std::exception.
|
||||
std::cerr << e.what() << "\n";
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_convert
|
||||
|
||||
Convert OSM files from one format into another.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input and output
|
||||
* file types
|
||||
* Osmium buffers
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <exception> // for std::exception
|
||||
#include <getopt.h> // for getopt_long
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
#include <string> // for std::string
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// Allow any format of output files (XML, PBF, ...)
|
||||
#include <osmium/io/any_output.hpp>
|
||||
|
||||
void print_help() {
|
||||
std::cout << "osmium_convert [OPTIONS] [INFILE [OUTFILE]]\n\n" \
|
||||
<< "If INFILE or OUTFILE is not given stdin/stdout is assumed.\n" \
|
||||
<< "File format is autodetected from file name suffix.\n" \
|
||||
<< "Use -f and -t options to force file format.\n" \
|
||||
<< "\nFile types:\n" \
|
||||
<< " osm normal OSM file\n" \
|
||||
<< " osc OSM change file\n" \
|
||||
<< " osh OSM file with history information\n" \
|
||||
<< "\nFile format:\n" \
|
||||
<< " (default) XML encoding\n" \
|
||||
<< " pbf binary PBF encoding\n" \
|
||||
<< " opl OPL encoding\n" \
|
||||
<< "\nFile compression\n" \
|
||||
<< " gz compressed with gzip\n" \
|
||||
<< " bz2 compressed with bzip2\n" \
|
||||
<< "\nOptions:\n" \
|
||||
<< " -h, --help This help message\n" \
|
||||
<< " -f, --from-format=FORMAT Input format\n" \
|
||||
<< " -t, --to-format=FORMAT Output format\n";
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
static struct option long_options[] = {
|
||||
{"help", no_argument, nullptr, 'h'},
|
||||
{"from-format", required_argument, nullptr, 'f'},
|
||||
{"to-format", required_argument, nullptr, 't'},
|
||||
{nullptr, 0, nullptr, 0}
|
||||
};
|
||||
|
||||
// Input and output format are empty by default. Later this will mean that
|
||||
// the format should be taken from the input and output file suffix,
|
||||
// respectively.
|
||||
std::string input_format;
|
||||
std::string output_format;
|
||||
|
||||
// Read options from command line.
|
||||
while (true) {
|
||||
const int c = getopt_long(argc, argv, "dhf:t:", long_options, nullptr);
|
||||
if (c == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case 'h':
|
||||
print_help();
|
||||
std::exit(0);
|
||||
case 'f':
|
||||
input_format = optarg;
|
||||
break;
|
||||
case 't':
|
||||
output_format = optarg;
|
||||
break;
|
||||
default:
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
const int remaining_args = argc - optind;
|
||||
if (remaining_args == 0 || remaining_args > 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Get input file name from command line.
|
||||
std::string input_file_name;
|
||||
if (remaining_args >= 1) {
|
||||
input_file_name = argv[optind];
|
||||
}
|
||||
|
||||
// Get output file name from command line.
|
||||
std::string output_file_name;
|
||||
if (remaining_args == 2) {
|
||||
output_file_name = argv[optind+1];
|
||||
}
|
||||
|
||||
// This declares the input and output files using either the suffix of
|
||||
// the file names or the format in the 2nd argument. It does not yet open
|
||||
// the files.
|
||||
const osmium::io::File input_file{input_file_name, input_format};
|
||||
const osmium::io::File output_file{output_file_name, output_format};
|
||||
|
||||
// Input and output files can be OSM data files (without history) or
|
||||
// OSM history files. History files are detected if they use the '.osh'
|
||||
// file suffix.
|
||||
if ( input_file.has_multiple_object_versions() &&
|
||||
!output_file.has_multiple_object_versions()) {
|
||||
std::cerr << "Warning! You are converting from an OSM file with (potentially) several versions of the same object to one that is not marked as such.\n";
|
||||
}
|
||||
|
||||
try {
|
||||
// Initialize Reader
|
||||
osmium::io::Reader reader{input_file};
|
||||
|
||||
// Get header from input file and change the "generator" setting to
|
||||
// ourselves.
|
||||
osmium::io::Header header = reader.header();
|
||||
header.set("generator", "osmium_convert");
|
||||
|
||||
// Initialize Writer using the header from above and tell it that it
|
||||
// is allowed to overwrite a possibly existing file.
|
||||
osmium::io::Writer writer{output_file, header, osmium::io::overwrite::allow};
|
||||
|
||||
// Copy the contents from the input to the output file one buffer at
|
||||
// a time. This is much easier and faster than copying each object
|
||||
// in the file. Buffers are moved around, so there is no cost for
|
||||
// copying in memory.
|
||||
while (osmium::memory::Buffer buffer = reader.read()) {
|
||||
writer(std::move(buffer));
|
||||
}
|
||||
|
||||
// Explicitly close the writer and reader. Will throw an exception if
|
||||
// there is a problem. If you wait for the destructor to close the writer
|
||||
// and reader, you will not notice the problem, because destructors must
|
||||
// not throw.
|
||||
writer.close();
|
||||
reader.close();
|
||||
} catch (const std::exception& e) {
|
||||
// All exceptions used by the Osmium library derive from std::exception.
|
||||
std::cerr << e.what() << "\n";
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_count
|
||||
|
||||
Counts the number of nodes, ways, and relations in the input file.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* OSM file input
|
||||
* your own handler
|
||||
* the memory usage utility class
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdint> // for std::uint64_t
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// We want to use the handler interface
|
||||
#include <osmium/handler.hpp>
|
||||
|
||||
// Utility class gives us access to memory usage information
|
||||
#include <osmium/util/memory.hpp>
|
||||
|
||||
// For osmium::apply()
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
// Handler derive from the osmium::handler::Handler base class. Usually you
|
||||
// overwrite functions node(), way(), and relation(). Other functions are
|
||||
// available, too. Read the API documentation for details.
|
||||
struct CountHandler : public osmium::handler::Handler {
|
||||
|
||||
std::uint64_t nodes = 0;
|
||||
std::uint64_t ways = 0;
|
||||
std::uint64_t relations = 0;
|
||||
|
||||
// This callback is called by osmium::apply for each node in the data.
|
||||
void node(const osmium::Node&) noexcept {
|
||||
++nodes;
|
||||
}
|
||||
|
||||
// This callback is called by osmium::apply for each way in the data.
|
||||
void way(const osmium::Way&) noexcept {
|
||||
++ways;
|
||||
}
|
||||
|
||||
// This callback is called by osmium::apply for each relation in the data.
|
||||
void relation(const osmium::Relation&) noexcept {
|
||||
++relations;
|
||||
}
|
||||
|
||||
}; // struct CountHandler
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// The Reader is initialized here with an osmium::io::File, but could
|
||||
// also be directly initialized with a file name.
|
||||
osmium::io::File input_file{argv[1]};
|
||||
osmium::io::Reader reader{input_file};
|
||||
|
||||
// Create an instance of our own CountHandler and push the data from the
|
||||
// input file through it.
|
||||
CountHandler handler;
|
||||
osmium::apply(reader, handler);
|
||||
|
||||
// You do not have to close the Reader explicitly, but because the
|
||||
// destructor can't throw, you will not see any errors otherwise.
|
||||
reader.close();
|
||||
|
||||
std::cout << "Nodes: " << handler.nodes << "\n";
|
||||
std::cout << "Ways: " << handler.ways << "\n";
|
||||
std::cout << "Relations: " << handler.relations << "\n";
|
||||
|
||||
// Because of the huge amount of OSM data, some Osmium-based programs
|
||||
// (though not this one) can use huge amounts of data. So checking actual
|
||||
// memore usage is often useful and can be done easily with this class.
|
||||
// (Currently only works on Linux, not OSX and Windows.)
|
||||
osmium::MemoryUsage memory;
|
||||
|
||||
std::cout << "\nMemory used: " << memory.peak() << " MBytes\n";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_create_pois
|
||||
|
||||
Showing how to create nodes for points of interest out of thin air.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file output
|
||||
* Osmium buffers
|
||||
* using builders to write data
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
* osmium_pub_names
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <cstring> // for std::strcmp
|
||||
#include <ctime> // for std::time
|
||||
#include <exception> // for std::exception
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
#include <string> // for std::string
|
||||
#include <utility> // for std::move
|
||||
|
||||
// Allow any format of output files (XML, PBF, ...)
|
||||
#include <osmium/io/any_output.hpp>
|
||||
|
||||
// We want to use the builder interface
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
#include <osmium/builder/attr.hpp>
|
||||
|
||||
// Declare this to use the functions starting with the underscore (_) below.
|
||||
using namespace osmium::builder::attr;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OUTFILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Get output file name from command line.
|
||||
std::string output_file_name{argv[1]};
|
||||
|
||||
// If output file name is "-", this means STDOUT. Set the OPL file type
|
||||
// in this case. Otherwise take the file type from the file name suffix.
|
||||
osmium::io::File output_file{output_file_name, output_file_name == "-" ? ".opl" : ""};
|
||||
|
||||
try {
|
||||
// Create a buffer where all objects will live. Use a sensible initial
|
||||
// buffer size and set the buffer to automatically grow if needed.
|
||||
const size_t initial_buffer_size = 10000;
|
||||
osmium::memory::Buffer buffer{initial_buffer_size, osmium::memory::Buffer::auto_grow::yes};
|
||||
|
||||
// Add nodes to the buffer. This is, of course, only an example.
|
||||
// You can set any of the attributes and more tags, etc. Ways and
|
||||
// relations can be added in a similar way.
|
||||
osmium::builder::add_node(buffer,
|
||||
_id(-1),
|
||||
_version(1),
|
||||
_timestamp(std::time(nullptr)),
|
||||
_location(osmium::Location{1.23, 3.45}),
|
||||
_tag("amenity", "post_box")
|
||||
);
|
||||
|
||||
osmium::builder::add_node(buffer,
|
||||
_id(-2),
|
||||
_version(1),
|
||||
_timestamp(std::time(nullptr)),
|
||||
_location(1.24, 3.46),
|
||||
_tags({{"amenity", "restaurant"},
|
||||
{"name", "Chez OSM"}})
|
||||
);
|
||||
|
||||
// Create header and set generator.
|
||||
osmium::io::Header header;
|
||||
header.set("generator", "osmium_create_pois");
|
||||
|
||||
// Initialize Writer using the header from above and tell it that it
|
||||
// is allowed to overwrite a possibly existing file.
|
||||
osmium::io::Writer writer{output_file, header, osmium::io::overwrite::allow};
|
||||
|
||||
// Write out the contents of the output buffer.
|
||||
writer(std::move(buffer));
|
||||
|
||||
// Explicitly close the writer. Will throw an exception if there is
|
||||
// a problem. If you wait for the destructor to close the writer, you
|
||||
// will not notice the problem, because destructors must not throw.
|
||||
writer.close();
|
||||
} catch (const std::exception& e) {
|
||||
// All exceptions used by the Osmium library derive from std::exception.
|
||||
std::cerr << e.what() << "\n";
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_debug
|
||||
|
||||
Dump the contents of the input file in a debug format.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input reading only some types
|
||||
* the dump handler
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
#include <string> // for std::string
|
||||
|
||||
// The Dump handler
|
||||
#include <osmium/handler/dump.hpp>
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Speed up output (not Osmium-specific)
|
||||
std::ios_base::sync_with_stdio(false);
|
||||
|
||||
if (argc < 2 || argc > 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE [TYPES]\n";
|
||||
std::cerr << "TYPES can be any combination of 'n', 'w', 'r', and 'c' to indicate what types of OSM entities you want (default: all).\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Default is all entity types: nodes, ways, relations, and changesets
|
||||
osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all;
|
||||
|
||||
// Get entity types from command line if there is a 2nd argument.
|
||||
if (argc == 3) {
|
||||
read_types = osmium::osm_entity_bits::nothing;
|
||||
std::string types = argv[2];
|
||||
if (types.find('n') != std::string::npos) {
|
||||
read_types |= osmium::osm_entity_bits::node;
|
||||
}
|
||||
if (types.find('w') != std::string::npos) {
|
||||
read_types |= osmium::osm_entity_bits::way;
|
||||
}
|
||||
if (types.find('r') != std::string::npos) {
|
||||
read_types |= osmium::osm_entity_bits::relation;
|
||||
}
|
||||
if (types.find('c') != std::string::npos) {
|
||||
read_types |= osmium::osm_entity_bits::changeset;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize Reader with file name and the types of entities we want to
|
||||
// read.
|
||||
osmium::io::Reader reader{argv[1], read_types};
|
||||
|
||||
// The file header can contain metadata such as the program that generated
|
||||
// the file and the bounding box of the data.
|
||||
osmium::io::Header header = reader.header();
|
||||
std::cout << "HEADER:\n generator=" << header.get("generator") << "\n";
|
||||
|
||||
for (const auto& bbox : header.boxes()) {
|
||||
std::cout << " bbox=" << bbox << "\n";
|
||||
}
|
||||
|
||||
// Initialize Dump handler.
|
||||
osmium::handler::Dump dump{std::cout};
|
||||
|
||||
// Read from input and send everything to Dump handler.
|
||||
osmium::apply(reader, dump);
|
||||
|
||||
// You do not have to close the Reader explicitly, but because the
|
||||
// destructor can't throw, you will not see any errors otherwise.
|
||||
reader.close();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_dump_internal
|
||||
|
||||
Reads an OSM file and dumps the internal datastructure to disk including
|
||||
indexes to find objects and object relations.
|
||||
|
||||
Note that this example programm will only work with small and medium sized
|
||||
OSM files, not with the planet.
|
||||
|
||||
You can use the osmium_index example program to inspect the indexes.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input
|
||||
* indexes and maps
|
||||
* use of the DiskStore handler
|
||||
* use of the ObjectRelations handler
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
* osmium_road_length
|
||||
* osmium_location_cache_create
|
||||
* osmium_location_cache_use
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cerrno> // for errno
|
||||
#include <cstring> // for std::strerror
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
#include <string> // for std::string
|
||||
#include <sys/stat.h> // for open
|
||||
#include <sys/types.h> // for open
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <io.h> // for _setmode
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# include <direct.h>
|
||||
#endif
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// The DiskStore handler
|
||||
#include <osmium/handler/disk_store.hpp>
|
||||
|
||||
// The ObjectRelations handler
|
||||
#include <osmium/handler/object_relations.hpp>
|
||||
|
||||
// The indexes
|
||||
#include <osmium/index/map/sparse_mem_array.hpp>
|
||||
#include <osmium/index/multimap/sparse_mem_array.hpp>
|
||||
|
||||
using offset_index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, size_t>;
|
||||
using map_type = osmium::index::multimap::SparseMemArray<osmium::unsigned_object_id_type, osmium::unsigned_object_id_type>;
|
||||
|
||||
/**
|
||||
* Small class wrapping index files, basically making sure errors are handled
|
||||
* and the files are closed on destruction.
|
||||
*/
|
||||
class IndexFile {
|
||||
|
||||
int m_fd;
|
||||
|
||||
public:
|
||||
|
||||
explicit IndexFile(const std::string& filename) :
|
||||
m_fd(::open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666)) {
|
||||
if (m_fd < 0) {
|
||||
std::cerr << "Can't open index file '" << filename << "': " << std::strerror(errno) << "\n";
|
||||
std::exit(2);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
_setmode(m_fd, _O_BINARY);
|
||||
#endif
|
||||
}
|
||||
|
||||
~IndexFile() {
|
||||
if (m_fd >= 0) {
|
||||
close(m_fd);
|
||||
}
|
||||
}
|
||||
|
||||
int fd() const noexcept {
|
||||
return m_fd;
|
||||
}
|
||||
|
||||
}; // class IndexFile
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE DIR\n";
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
const std::string input_file_name{argv[1]};
|
||||
const std::string output_dir{argv[2]};
|
||||
|
||||
// Create output directory. Ignore the error if it already exists.
|
||||
#ifndef _WIN32
|
||||
const int result = ::mkdir(output_dir.c_str(), 0777);
|
||||
#else
|
||||
const int result = mkdir(output_dir.c_str());
|
||||
#endif
|
||||
if (result == -1 && errno != EEXIST) {
|
||||
std::cerr << "Problem creating directory '" << output_dir << "': " << std::strerror(errno) << "\n";
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
// Create the output file which will contain our serialized OSM data
|
||||
const std::string data_file{output_dir + "/data.osm.ser"};
|
||||
const int data_fd = ::open(data_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (data_fd < 0) {
|
||||
std::cerr << "Can't open data file '" << data_file << "': " << std::strerror(errno) << "\n";
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
_setmode(data_fd, _O_BINARY);
|
||||
#endif
|
||||
|
||||
// These indexes store the offset in the data file where each node, way,
|
||||
// or relation is stored.
|
||||
offset_index_type node_index;
|
||||
offset_index_type way_index;
|
||||
offset_index_type relation_index;
|
||||
|
||||
// This handler will dump the internal data to disk using the given file
|
||||
// descriptor while updating the indexes.
|
||||
osmium::handler::DiskStore disk_store_handler{data_fd, node_index, way_index, relation_index};
|
||||
|
||||
// These indexes store the mapping from node id to the ids of the ways
|
||||
// containing this node, and from node/way/relation ids to the ids of the
|
||||
// relations containing those objects.
|
||||
map_type map_node2way;
|
||||
map_type map_node2relation;
|
||||
map_type map_way2relation;
|
||||
map_type map_relation2relation;
|
||||
|
||||
// This handler will update the map indexes.
|
||||
osmium::handler::ObjectRelations object_relations_handler{map_node2way, map_node2relation, map_way2relation, map_relation2relation};
|
||||
|
||||
// Read OSM data buffer by buffer.
|
||||
osmium::io::Reader reader{input_file_name};
|
||||
|
||||
while (osmium::memory::Buffer buffer = reader.read()) {
|
||||
// Write buffer to disk and update indexes.
|
||||
disk_store_handler(buffer);
|
||||
|
||||
// Update object relation index maps.
|
||||
osmium::apply(buffer, object_relations_handler);
|
||||
}
|
||||
|
||||
reader.close();
|
||||
|
||||
// Write out node, way, and relation offset indexes to disk.
|
||||
IndexFile nodes_idx{output_dir + "/nodes.idx"};
|
||||
node_index.dump_as_list(nodes_idx.fd());
|
||||
|
||||
IndexFile ways_idx{output_dir + "/ways.idx"};
|
||||
way_index.dump_as_list(ways_idx.fd());
|
||||
|
||||
IndexFile relations_idx{output_dir + "/relations.idx"};
|
||||
relation_index.dump_as_list(relations_idx.fd());
|
||||
|
||||
// Sort the maps (so later binary search will work on them) and write
|
||||
// them to disk.
|
||||
map_node2way.sort();
|
||||
IndexFile node2way_idx{output_dir + "/node2way.map"};
|
||||
map_node2way.dump_as_list(node2way_idx.fd());
|
||||
|
||||
map_node2relation.sort();
|
||||
IndexFile node2relation_idx{output_dir + "/node2rel.map"};
|
||||
map_node2relation.dump_as_list(node2relation_idx.fd());
|
||||
|
||||
map_way2relation.sort();
|
||||
IndexFile way2relation_idx{output_dir + "/way2rel.map"};
|
||||
map_way2relation.dump_as_list(way2relation_idx.fd());
|
||||
|
||||
map_relation2relation.sort();
|
||||
IndexFile relation2relation_idx{output_dir + "/rel2rel.map"};
|
||||
map_relation2relation.dump_as_list(relation2relation_idx.fd());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_filter_discussions
|
||||
|
||||
Read OSM changesets with discussions from a changeset dump like the one
|
||||
you get from http://planet.osm.org/planet/discussions-latest.osm.bz2
|
||||
and write out only those changesets which have discussions (ie comments).
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input and output
|
||||
* setting file formats using the osmium::io::File class
|
||||
* OSM file headers
|
||||
* input and output iterators
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <algorithm> // for std::copy_if
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
|
||||
// We want to read OSM files in XML format
|
||||
// (other formats don't support full changesets, so only XML is needed here).
|
||||
#include <osmium/io/xml_input.hpp>
|
||||
|
||||
// We want to write OSM files in XML format.
|
||||
#include <osmium/io/xml_output.hpp>
|
||||
|
||||
// We want to use input and output iterators for easy integration with the
|
||||
// algorithms of the standard library.
|
||||
#include <osmium/io/input_iterator.hpp>
|
||||
#include <osmium/io/output_iterator.hpp>
|
||||
|
||||
// We want to support any compression (none, gzip, and bzip2).
|
||||
#include <osmium/io/any_compression.hpp>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
std::cout << "Usage: " << argv[0] << " INFILE OUTFILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// The input file, deduce file format from file suffix.
|
||||
osmium::io::File input_file{argv[1]};
|
||||
|
||||
// The output file, force XML OSM file format.
|
||||
osmium::io::File output_file{argv[2], "osm"};
|
||||
|
||||
// Initialize Reader for the input file.
|
||||
// Read only changesets (will ignore nodes, ways, and
|
||||
// relations if there are any).
|
||||
osmium::io::Reader reader{input_file, osmium::osm_entity_bits::changeset};
|
||||
|
||||
// Get the header from the input file.
|
||||
osmium::io::Header header = reader.header();
|
||||
|
||||
// Set the "generator" on the header to ourselves.
|
||||
header.set("generator", "osmium_filter_discussions");
|
||||
|
||||
// Initialize writer for the output file. Use the header from the input
|
||||
// file for the output file. This will copy over some header information.
|
||||
// The last parameter will tell the writer that it is allowed to overwrite
|
||||
// an existing file. Without it, it will refuse to do so.
|
||||
osmium::io::Writer writer{output_file, header, osmium::io::overwrite::allow};
|
||||
|
||||
// Create range of input iterators that will iterator over all changesets
|
||||
// delivered from input file through the "reader".
|
||||
auto input_range = osmium::io::make_input_iterator_range<osmium::Changeset>(reader);
|
||||
|
||||
// Create an output iterator writing through the "writer" object to the
|
||||
// output file.
|
||||
auto output_iterator = osmium::io::make_output_iterator(writer);
|
||||
|
||||
// Copy all changesets from input to output that have at least one comment.
|
||||
std::copy_if(input_range.begin(), input_range.end(), output_iterator, [](const osmium::Changeset& changeset) {
|
||||
return changeset.num_comments() > 0;
|
||||
});
|
||||
|
||||
// Explicitly close the writer and reader. Will throw an exception if
|
||||
// there is a problem. If you wait for the destructor to close the writer
|
||||
// and reader, you will not notice the problem, because destructors must
|
||||
// not throw.
|
||||
writer.close();
|
||||
reader.close();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_index
|
||||
|
||||
Example program to look at Osmium indexes on disk.
|
||||
|
||||
You can use the osmium_dump_internal example program to create the offset
|
||||
indexes or osmium_location_cache_create to create a node location index.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* access to indexes on disk
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
* osmium_road_length
|
||||
* osmium_location_cache_create
|
||||
* osmium_location_cache_use
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <algorithm> // for std::all_of, std::equal_range
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <fcntl.h> // for open
|
||||
#include <getopt.h> // for getopt_long
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
#include <memory> // for std::unique_ptr
|
||||
#include <string> // for std::string
|
||||
#include <sys/stat.h> // for open
|
||||
#include <sys/types.h> // for open
|
||||
#include <vector> // for std::vector
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <io.h> // for _setmode
|
||||
#endif
|
||||
|
||||
// Disk-based indexes
|
||||
#include <osmium/index/map/dense_file_array.hpp>
|
||||
#include <osmium/index/map/sparse_file_array.hpp>
|
||||
|
||||
// osmium::Location
|
||||
#include <osmium/osm/location.hpp>
|
||||
|
||||
// Basic Osmium types
|
||||
#include <osmium/osm/types.hpp>
|
||||
|
||||
// Virtual class for disk index access. If offers functions to dump the
|
||||
// indexes and to search for ids in the index.
|
||||
template <typename TValue>
|
||||
class IndexAccess {
|
||||
|
||||
int m_fd;
|
||||
|
||||
public:
|
||||
|
||||
explicit IndexAccess(int fd) :
|
||||
m_fd(fd) {
|
||||
}
|
||||
|
||||
int fd() const noexcept {
|
||||
return m_fd;
|
||||
}
|
||||
|
||||
virtual ~IndexAccess() = default;
|
||||
|
||||
virtual void dump() const = 0;
|
||||
|
||||
virtual bool search(const osmium::unsigned_object_id_type& key) const = 0;
|
||||
|
||||
bool search(const std::vector<osmium::unsigned_object_id_type>& keys) const {
|
||||
return std::all_of(keys.cbegin(), keys.cend(), [this](const osmium::unsigned_object_id_type& key) {
|
||||
return search(key);
|
||||
});
|
||||
}
|
||||
|
||||
}; // class IndexAccess
|
||||
|
||||
// Implementation of IndexAccess for dense indexes usually used for very large
|
||||
// extracts or the planet.
|
||||
template <typename TValue>
|
||||
class IndexAccessDense : public IndexAccess<TValue> {
|
||||
|
||||
using index_type = typename osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, TValue>;
|
||||
|
||||
public:
|
||||
|
||||
explicit IndexAccessDense(int fd) :
|
||||
IndexAccess<TValue>(fd) {
|
||||
}
|
||||
|
||||
void dump() const override {
|
||||
index_type index{this->fd()};
|
||||
|
||||
for (std::size_t i = 0; i < index.size(); ++i) {
|
||||
if (index.get(i) != TValue{}) {
|
||||
std::cout << i << " " << index.get(i) << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool search(const osmium::unsigned_object_id_type& key) const override {
|
||||
index_type index{this->fd()};
|
||||
|
||||
try {
|
||||
TValue value = index.get(key);
|
||||
std::cout << key << " " << value << "\n";
|
||||
} catch (...) {
|
||||
std::cout << key << " not found\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // class IndexAccessDense
|
||||
|
||||
// Implementation of IndexAccess for sparse indexes usually used for small or
|
||||
// medium sized extracts or for "multimap" type indexes.
|
||||
template <typename TValue>
|
||||
class IndexAccessSparse : public IndexAccess<TValue> {
|
||||
|
||||
using index_type = typename osmium::index::map::SparseFileArray<osmium::unsigned_object_id_type, TValue>;
|
||||
|
||||
public:
|
||||
|
||||
explicit IndexAccessSparse(int fd) :
|
||||
IndexAccess<TValue>(fd) {
|
||||
}
|
||||
|
||||
void dump() const override {
|
||||
index_type index{this->fd()};
|
||||
|
||||
for (const auto& element : index) {
|
||||
std::cout << element.first << " " << element.second << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
bool search(const osmium::unsigned_object_id_type& key) const override {
|
||||
using element_type = typename index_type::element_type;
|
||||
index_type index{this->fd()};
|
||||
|
||||
element_type elem{key, TValue{}};
|
||||
const auto positions = std::equal_range(index.begin(),
|
||||
index.end(),
|
||||
elem,
|
||||
[](const element_type& lhs,
|
||||
const element_type& rhs) {
|
||||
return lhs.first < rhs.first;
|
||||
});
|
||||
if (positions.first == positions.second) {
|
||||
std::cout << key << " not found\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto it = positions.first; it != positions.second; ++it) {
|
||||
std::cout << it->first << " " << it->second << "\n";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // class IndexAccessSparse
|
||||
|
||||
// This class contains the code to parse the command line arguments, check
|
||||
// them and present the results to the rest of the program in an easy-to-use
|
||||
// way.
|
||||
class Options {
|
||||
|
||||
std::vector<osmium::unsigned_object_id_type> m_ids;
|
||||
std::string m_type;
|
||||
std::string m_filename;
|
||||
bool m_dump = false;
|
||||
bool m_array_format = false;
|
||||
bool m_list_format = false;
|
||||
|
||||
void print_help() {
|
||||
std::cout << "Usage: osmium_index_lookup [OPTIONS]\n\n"
|
||||
<< "-h, --help Print this help message\n"
|
||||
<< "-a, --array=FILE Read given index file in array format\n"
|
||||
<< "-l, --list=FILE Read given index file in list format\n"
|
||||
<< "-d, --dump Dump contents of index file to STDOUT\n"
|
||||
<< "-s, --search=ID Search for given id (Option can appear multiple times)\n"
|
||||
<< "-t, --type=TYPE Type of value ('location', 'id', or 'offset')\n"
|
||||
;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Options(int argc, char* argv[]) {
|
||||
if (argc == 1) {
|
||||
print_help();
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"array", required_argument, nullptr, 'a'},
|
||||
{"dump", no_argument, nullptr, 'd'},
|
||||
{"help", no_argument, nullptr, 'h'},
|
||||
{"list", required_argument, nullptr, 'l'},
|
||||
{"search", required_argument, nullptr, 's'},
|
||||
{"type", required_argument, nullptr, 't'},
|
||||
{nullptr, 0, nullptr, 0}
|
||||
};
|
||||
|
||||
while (true) {
|
||||
const int c = getopt_long(argc, argv, "a:dhl:s:t:", long_options, nullptr);
|
||||
if (c == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case 'a':
|
||||
m_array_format = true;
|
||||
m_filename = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
m_dump = true;
|
||||
break;
|
||||
case 'h':
|
||||
print_help();
|
||||
std::exit(0);
|
||||
case 'l':
|
||||
m_list_format = true;
|
||||
m_filename = optarg;
|
||||
break;
|
||||
case 's':
|
||||
m_ids.push_back(std::atoll(optarg));
|
||||
break;
|
||||
case 't':
|
||||
m_type = optarg;
|
||||
if (m_type != "location" && m_type != "id" && m_type != "offset") {
|
||||
std::cerr << "Unknown type '" << m_type
|
||||
<< "'. Must be 'location', 'id', or 'offset'.\n";
|
||||
std::exit(2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
std::exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_array_format == m_list_format) {
|
||||
std::cerr << "Need option --array or --list, but not both\n";
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
if (m_dump == !m_ids.empty()) {
|
||||
std::cerr << "Need option --dump or --search, but not both\n";
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
if (m_type.empty()) {
|
||||
std::cerr << "Need --type argument.\n";
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const char* filename() const noexcept {
|
||||
return m_filename.c_str();
|
||||
}
|
||||
|
||||
bool dense_format() const noexcept {
|
||||
return m_array_format;
|
||||
}
|
||||
|
||||
bool do_dump() const noexcept {
|
||||
return m_dump;
|
||||
}
|
||||
|
||||
const std::vector<osmium::unsigned_object_id_type>& search_keys() const noexcept {
|
||||
return m_ids;
|
||||
}
|
||||
|
||||
bool type_is(const char* type) const noexcept {
|
||||
return m_type == type;
|
||||
}
|
||||
|
||||
}; // class Options
|
||||
|
||||
|
||||
// Factory function to create the right IndexAccess-derived class.
|
||||
template <typename TValue>
|
||||
std::unique_ptr<IndexAccess<TValue>> create(bool dense, int fd) {
|
||||
std::unique_ptr<IndexAccess<TValue>> ptr;
|
||||
|
||||
if (dense) {
|
||||
ptr.reset(new IndexAccessDense<TValue>{fd});
|
||||
} else {
|
||||
ptr.reset(new IndexAccessSparse<TValue>{fd});
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Do the actual work: Either dump the index or search in the index.
|
||||
template <typename TValue>
|
||||
int run(const IndexAccess<TValue>& index, const Options& options) {
|
||||
if (options.do_dump()) {
|
||||
index.dump();
|
||||
return 0;
|
||||
} else {
|
||||
return index.search(options.search_keys()) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Parse command line options.
|
||||
Options options{argc, argv};
|
||||
|
||||
// Open the index file.
|
||||
const int fd = ::open(options.filename(), O_RDWR);
|
||||
if (fd < 0) {
|
||||
std::cerr << "Can not open file '" << options.filename()
|
||||
<< "': " << std::strerror(errno) << '\n';
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
_setmode(fd, _O_BINARY);
|
||||
#endif
|
||||
|
||||
try {
|
||||
// Depending on the type of index, we have different implementations.
|
||||
if (options.type_is("location")) {
|
||||
// index id -> location
|
||||
const auto index = create<osmium::Location>(options.dense_format(), fd);
|
||||
return run(*index, options);
|
||||
} else if (options.type_is("id")) {
|
||||
// index id -> id
|
||||
const auto index = create<osmium::unsigned_object_id_type>(options.dense_format(), fd);
|
||||
return run(*index, options);
|
||||
} else {
|
||||
// index id -> offset
|
||||
const auto index = create<std::size_t>(options.dense_format(), fd);
|
||||
return run(*index, options);
|
||||
}
|
||||
} catch(const std::exception& e) {
|
||||
std::cerr << "Error: " << e.what() << '\n';
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_location_cache_create
|
||||
|
||||
Reads nodes from an OSM file and writes out their locations to a cache
|
||||
file. The cache file can then be read with osmium_location_cache_use.
|
||||
|
||||
Warning: The locations cache file will get huge (>32GB) if you are using
|
||||
the DenseFileArray index even if the input file is small, because
|
||||
it depends on the *largest* node ID, not the number of nodes.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input
|
||||
* location indexes and the NodeLocationsForWays handler
|
||||
* location indexes on disk
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
* osmium_road_length
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cerrno> // for errno
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <cstring> // for strerror
|
||||
#include <fcntl.h> // for open
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
#include <string> // for std::string
|
||||
#include <sys/stat.h> // for open
|
||||
#include <sys/types.h> // for open
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <io.h> // for _setmode
|
||||
#endif
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// For the location index. There are different types of index implementation
|
||||
// available. These implementations put the index on disk. See below.
|
||||
#include <osmium/index/map/sparse_file_array.hpp>
|
||||
#include <osmium/index/map/dense_file_array.hpp>
|
||||
|
||||
// For the NodeLocationForWays handler
|
||||
#include <osmium/handler/node_locations_for_ways.hpp>
|
||||
|
||||
// For osmium::apply()
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
// Chose one of these two. "sparse" is best used for small and medium extracts,
|
||||
// the "dense" index for large extracts or the whole planet.
|
||||
using index_type = osmium::index::map::SparseFileArray<osmium::unsigned_object_id_type, osmium::Location>;
|
||||
//using index_type = osmium::index::map::DenseFileArray<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>;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSM_FILE CACHE_FILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
const std::string input_filename{argv[1]};
|
||||
const std::string cache_filename{argv[2]};
|
||||
|
||||
// Construct Reader reading only nodes
|
||||
osmium::io::Reader reader{input_filename, osmium::osm_entity_bits::node};
|
||||
|
||||
// Initialize location index on disk creating a new file.
|
||||
const int fd = ::open(cache_filename.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
|
||||
if (fd == -1) {
|
||||
std::cerr << "Can not open location cache file '" << cache_filename << "': " << std::strerror(errno) << "\n";
|
||||
std::exit(1);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
_setmode(fd, _O_BINARY);
|
||||
#endif
|
||||
index_type index{fd};
|
||||
|
||||
// The handler that stores all node locations in the index.
|
||||
location_handler_type location_handler{index};
|
||||
|
||||
// Feed all nodes through the location handler.
|
||||
osmium::apply(reader, location_handler);
|
||||
|
||||
// Explicitly close input so we get notified of any errors.
|
||||
reader.close();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_location_cache_use
|
||||
|
||||
This reads ways from an OSM file and writes out the way node locations
|
||||
it got from a location cache generated with osmium_location_cache_create.
|
||||
|
||||
Warning: The locations cache file will get huge (>32GB) if you are using
|
||||
the DenseFileArray index even if the input file is small, because
|
||||
it depends on the *largest* node ID, not the number of nodes.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input
|
||||
* location indexes and the NodeLocationsForWays handler
|
||||
* location indexes on disk
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
* osmium_road_length
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cerrno> // for errno
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <cstring> // for strerror
|
||||
#include <fcntl.h> // for open
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
#include <string> // for std::string
|
||||
#include <sys/stat.h> // for open
|
||||
#include <sys/types.h> // for open
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <io.h> // for _setmode
|
||||
#endif
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// For the location index. There are different types of index implementation
|
||||
// available. These implementations put the index on disk. See below.
|
||||
#include <osmium/index/map/dense_file_array.hpp>
|
||||
#include <osmium/index/map/sparse_file_array.hpp>
|
||||
|
||||
// For the NodeLocationForWays handler
|
||||
#include <osmium/handler/node_locations_for_ways.hpp>
|
||||
|
||||
// For osmium::apply()
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
// Chose one of these two. "sparse" is best used for small and medium extracts,
|
||||
// the "dense" index for large extracts or the whole planet.
|
||||
using index_type = osmium::index::map::SparseFileArray<osmium::unsigned_object_id_type, osmium::Location>;
|
||||
//using index_type = osmium::index::map::DenseFileArray<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 only implements the way() function which prints out the way
|
||||
// ID and all nodes IDs and locations in those ways.
|
||||
struct MyHandler : public osmium::handler::Handler {
|
||||
|
||||
void way(const osmium::Way& way) {
|
||||
std::cout << "way " << way.id() << "\n";
|
||||
for (const auto& nr : way.nodes()) {
|
||||
std::cout << " node " << nr.ref() << " " << nr.location() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
}; // struct MyHandler
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSM_FILE CACHE_FILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
const std::string input_filename{argv[1]};
|
||||
const std::string cache_filename{argv[2]};
|
||||
|
||||
// Construct Reader reading only ways
|
||||
osmium::io::Reader reader{input_filename, osmium::osm_entity_bits::way};
|
||||
|
||||
// Initialize location index on disk using an existing file
|
||||
const int fd = ::open(cache_filename.c_str(), O_RDWR);
|
||||
if (fd == -1) {
|
||||
std::cerr << "Can not open location cache file '" << cache_filename << "': " << std::strerror(errno) << "\n";
|
||||
return 1;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
_setmode(fd, _O_BINARY);
|
||||
#endif
|
||||
index_type index{fd};
|
||||
|
||||
// The handler that adds node locations from the index to the ways.
|
||||
location_handler_type location_handler{index};
|
||||
|
||||
// Feed all ways through the location handler and then our own handler.
|
||||
MyHandler handler;
|
||||
osmium::apply(reader, location_handler, handler);
|
||||
|
||||
// Explicitly close input so we get notified of any errors.
|
||||
reader.close();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_pub_names
|
||||
|
||||
Show the names and addresses of all pubs found in an OSM file.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input
|
||||
* your own handler
|
||||
* access to tags
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <cstring> // for std::strncmp
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// We want to use the handler interface
|
||||
#include <osmium/handler.hpp>
|
||||
|
||||
// For osmium::apply()
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
class NamesHandler : public osmium::handler::Handler {
|
||||
|
||||
void output_pubs(const osmium::OSMObject& object) {
|
||||
const osmium::TagList& tags = object.tags();
|
||||
if (tags.has_tag("amenity", "pub")) {
|
||||
|
||||
// Print name of the pub if it is set.
|
||||
const char* name = tags["name"];
|
||||
if (name) {
|
||||
std::cout << name << "\n";
|
||||
} else {
|
||||
std::cout << "pub with unknown name\n";
|
||||
}
|
||||
|
||||
// Iterate over all tags finding those which start with "addr:"
|
||||
// and print them.
|
||||
for (const osmium::Tag& tag : tags) {
|
||||
if (!std::strncmp(tag.key(), "addr:", 5)) {
|
||||
std::cout << " " << tag.key() << ": " << tag.value() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// Nodes can be tagged amenity=pub.
|
||||
void node(const osmium::Node& node) {
|
||||
output_pubs(node);
|
||||
}
|
||||
|
||||
// Ways can be tagged amenity=pub, too (typically buildings).
|
||||
void way(const osmium::Way& way) {
|
||||
output_pubs(way);
|
||||
}
|
||||
|
||||
}; // class NamesHandler
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Construct the handler defined above
|
||||
NamesHandler names_handler;
|
||||
|
||||
// Initialize the reader with the filename from the command line and
|
||||
// tell it to only read nodes and ways. We are ignoring multipolygon
|
||||
// relations in this simple example.
|
||||
osmium::io::Reader reader{argv[1], osmium::osm_entity_bits::node | osmium::osm_entity_bits::way};
|
||||
|
||||
// Apply input data to our own handler
|
||||
osmium::apply(reader, names_handler);
|
||||
}
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_read
|
||||
|
||||
Reads and discards the contents of the input file.
|
||||
(It can be used for timing.)
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <iostream> // for std::cerr
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// The Reader is initialized here with an osmium::io::File, but could
|
||||
// also be directly initialized with a file name.
|
||||
osmium::io::File input_file{argv[1]};
|
||||
osmium::io::Reader reader{input_file};
|
||||
|
||||
// OSM data comes in buffers, read until there are no more.
|
||||
while (osmium::memory::Buffer buffer = reader.read()) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// You do not have to close the Reader explicitly, but because the
|
||||
// destructor can't throw, you will not see any errors otherwise.
|
||||
reader.close();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_read_with_progress
|
||||
|
||||
Reads the contents of the input file showing a progress bar.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input
|
||||
* ProgressBar utility function
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <iostream> // for std::cerr
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// Get access to isatty utility function and progress bar utility class.
|
||||
#include <osmium/util/file.hpp>
|
||||
#include <osmium/util/progress_bar.hpp>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// The Reader is initialized here with an osmium::io::File, but could
|
||||
// also be directly initialized with a file name.
|
||||
osmium::io::File input_file{argv[1]};
|
||||
osmium::io::Reader reader{input_file};
|
||||
|
||||
// Initialize progress bar, enable it only if STDERR is a TTY.
|
||||
osmium::ProgressBar progress{reader.file_size(), osmium::util::isatty(2)};
|
||||
|
||||
// OSM data comes in buffers, read until there are no more.
|
||||
while (osmium::memory::Buffer buffer = reader.read()) {
|
||||
// Update progress bar for each buffer.
|
||||
progress.update(reader.offset());
|
||||
}
|
||||
|
||||
// Progress bar is done.
|
||||
progress.done();
|
||||
|
||||
// You do not have to close the Reader explicitly, but because the
|
||||
// destructor can't throw, you will not see any errors otherwise.
|
||||
reader.close();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_road_length
|
||||
|
||||
Calculate the length of the road network (everything tagged `highway=*`)
|
||||
from the given OSM file.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input
|
||||
* location indexes and the NodeLocationsForWays handler
|
||||
* length calculation on the earth using the haversine function
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
* osmium_pub_names
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// For the osmium::geom::haversine::distance() function
|
||||
#include <osmium/geom/haversine.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>
|
||||
|
||||
// For the NodeLocationForWays handler
|
||||
#include <osmium/handler/node_locations_for_ways.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 only implements the way() function, we are not interested in
|
||||
// any other objects.
|
||||
struct RoadLengthHandler : public osmium::handler::Handler {
|
||||
|
||||
double length = 0;
|
||||
|
||||
// If the way has a "highway" tag, find its length and add it to the
|
||||
// overall length.
|
||||
void way(const osmium::Way& way) {
|
||||
const char* highway = way.tags()["highway"];
|
||||
if (highway) {
|
||||
length += osmium::geom::haversine::distance(way.nodes());
|
||||
}
|
||||
}
|
||||
|
||||
}; // struct RoadLengthHandler
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Initialize the reader with the filename from the command line and
|
||||
// tell it to only read nodes and ways.
|
||||
osmium::io::Reader reader{argv[1], osmium::osm_entity_bits::node | osmium::osm_entity_bits::way};
|
||||
|
||||
// The index to hold node locations.
|
||||
index_type index;
|
||||
|
||||
// The location handler will add the node locations to the index and then
|
||||
// to the ways
|
||||
location_handler_type location_handler{index};
|
||||
|
||||
// Our handler defined above
|
||||
RoadLengthHandler road_length_handler;
|
||||
|
||||
// Apply input data to first the location handler and then our own handler
|
||||
osmium::apply(reader, location_handler, road_length_handler);
|
||||
|
||||
// Output the length. The haversine function calculates it in meters,
|
||||
// so we first devide by 1000 to get kilometers.
|
||||
std::cout << "Length: " << road_length_handler.length / 1000 << " km\n";
|
||||
}
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_tiles
|
||||
|
||||
Convert WGS84 longitude and latitude to Mercator coordinates and tile
|
||||
coordinates.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* the Location and Coordinates classes
|
||||
* the Mercator projection function
|
||||
* the Tile class
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdlib> // for std::exit, std::atoi, std::atof
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
|
||||
// The Location contains a longitude and latitude and is usually used inside
|
||||
// a node to store its location in the world.
|
||||
#include <osmium/osm/location.hpp>
|
||||
|
||||
// Needed for the Mercator projection function. Osmium supports the Mercator
|
||||
// projection out of the box, or pretty much any projection using the Proj.4
|
||||
// library (with the osmium::geom::Projection class).
|
||||
#include <osmium/geom/mercator_projection.hpp>
|
||||
|
||||
// The Tile class handles tile coordinates and zoom levels.
|
||||
#include <osmium/geom/tile.hpp>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 4) {
|
||||
std::cerr << "Usage: " << argv[0] << " ZOOM LON LAT\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
const int zoom = std::atoi(argv[1]);
|
||||
|
||||
if (zoom < 0 || zoom > 30) {
|
||||
std::cerr << "ERROR: Zoom must be between 0 and 30\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
const double lon = std::atof(argv[2]);
|
||||
const double lat = std::atof(argv[3]);
|
||||
|
||||
// Create location from WGS84 coordinates. In Osmium the order of
|
||||
// coordinate values is always x/longitude first, then y/latitude.
|
||||
const osmium::Location location{lon, lat};
|
||||
|
||||
std::cout << "WGS84: lon=" << lon << " lat=" << lat << "\n";
|
||||
|
||||
// A location can store some invalid locations, ie locations outside the
|
||||
// -180 to 180 and -90 to 90 degree range. This function checks for that.
|
||||
if (!location.valid()) {
|
||||
std::cerr << "ERROR: Location is invalid\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Project the coordinates using a helper function. You can also use the
|
||||
// osmium::geom::MercatorProjection class.
|
||||
const osmium::geom::Coordinates c = osmium::geom::lonlat_to_mercator(location);
|
||||
std::cout << "Mercator: x=" << c.x << " y=" << c.y << "\n";
|
||||
|
||||
// Create a tile at this location. This will also internally use the
|
||||
// Mercator projection and then calculate the tile coordinates.
|
||||
const osmium::geom::Tile tile{uint32_t(zoom), location};
|
||||
std::cout << "Tile: zoom=" << tile.z << " x=" << tile.x << " y=" << tile.y << "\n";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user