Merge commit 'babbda98a6ea1d53a8bc5015ef5dfb313c47186a' into libosmium-2.10.0

This commit is contained in:
Daniel J. Hofmann
2016-11-11 15:50:02 +01:00
120 changed files with 4266 additions and 2031 deletions
+5 -3
View File
@@ -10,18 +10,20 @@ message(STATUS "Configuring examples")
set(EXAMPLES
area_test
change_tags
convert
count
create_pois
debug
dump_internal
filter_discussions
index
index_lookup
location_cache_create
location_cache_use
pub_names
read
read_with_progress
road_length
serdump
tiles
CACHE STRING "Example programs"
)
@@ -32,7 +34,7 @@ set(EXAMPLES
# Examples depending on wingetopt
#
#-----------------------------------------------------------------------------
set(GETOPT_EXAMPLES area_test convert index serdump)
set(GETOPT_EXAMPLES area_test convert index_lookup)
if(NOT GETOPT_MISSING)
foreach(example ${GETOPT_EXAMPLES})
list(APPEND EXAMPLE_LIBS_${example} ${GETOPT_LIBRARY})
+12
View File
@@ -18,12 +18,24 @@ them.
## Still reasonably simple examples
* `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
+2 -2
View File
@@ -106,7 +106,7 @@ int main(int argc, char* argv[]) {
// Read options from command line.
while (true) {
int c = getopt_long(argc, argv, "hwo", long_options, 0);
const int c = getopt_long(argc, argv, "hwo", long_options, 0);
if (c == -1) {
break;
}
@@ -126,7 +126,7 @@ int main(int argc, char* argv[]) {
}
}
int remaining_args = argc - optind;
const int remaining_args = argc - optind;
if (remaining_args != 1) {
std::cerr << "Usage: " << argv[0] << " [OPTIONS] OSMFILE\n";
std::exit(1);
+203
View File
@@ -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.
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 node 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 node 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);
}
}
+4 -4
View File
@@ -67,7 +67,7 @@ int main(int argc, char* argv[]) {
// Read options from command line.
while (true) {
int c = getopt_long(argc, argv, "dhf:t:", long_options, 0);
const int c = getopt_long(argc, argv, "dhf:t:", long_options, 0);
if (c == -1) {
break;
}
@@ -87,7 +87,7 @@ int main(int argc, char* argv[]) {
}
}
int remaining_args = argc - optind;
const int remaining_args = argc - optind;
if (remaining_args > 2) {
std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]\n";
std::exit(1);
@@ -124,13 +124,13 @@ int main(int argc, char* argv[]) {
osmium::io::Reader reader{input_file};
// Get header from input file and change the "generator" setting to
// outselves.
// 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);
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
+96
View File
@@ -0,0 +1,96 @@
/*
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]};
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_name, 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);
}
}
+179
View File
@@ -0,0 +1,179 @@
/*
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 file, 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 _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:
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);
}
}
~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);
}
// 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());
}
@@ -67,7 +67,7 @@ int main(int argc, char* argv[]) {
// 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);
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".
-260
View File
@@ -1,260 +0,0 @@
/*
Example program to look at Osmium indexes on disk.
The code in this example file is released into the Public Domain.
*/
#include <fcntl.h>
#include <iomanip>
#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
#include <getopt.h>
#include <osmium/index/map/dense_file_array.hpp>
#include <osmium/index/map/sparse_file_array.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/types.hpp>
template <typename TKey, typename TValue>
class IndexSearch {
typedef typename osmium::index::map::DenseFileArray<TKey, TValue> dense_index_type;
typedef typename osmium::index::map::SparseFileArray<TKey, TValue> sparse_index_type;
int m_fd;
bool m_dense_format;
void dump_dense() {
dense_index_type index(m_fd);
for (std::size_t i = 0; i < index.size(); ++i) {
if (index.get(i) != TValue()) {
std::cout << i << " " << index.get(i) << "\n";
}
}
}
void dump_sparse() {
sparse_index_type index(m_fd);
for (auto& element : index) {
std::cout << element.first << " " << element.second << "\n";
}
}
bool search_dense(TKey key) {
dense_index_type index(m_fd);
try {
TValue value = index.get(key);
std::cout << key << " " << value << "\n";
} catch (...) {
std::cout << key << " not found\n";
return false;
}
return true;
}
bool search_sparse(TKey key) {
typedef typename sparse_index_type::element_type element_type;
sparse_index_type index(m_fd);
element_type elem {key, TValue()};
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;
}
public:
IndexSearch(int fd, bool dense_format) :
m_fd(fd),
m_dense_format(dense_format) {
}
void dump() {
if (m_dense_format) {
dump_dense();
} else {
dump_sparse();
}
}
bool search(TKey key) {
if (m_dense_format) {
return search_dense(key);
} else {
return search_sparse(key);
}
}
bool search(const std::vector<TKey>& keys) {
bool found_all = true;
for (const auto key : keys) {
if (!search(key)) {
found_all = false;
}
}
return found_all;
}
}; // class IndexSearch
enum return_code : int {
okay = 0,
not_found = 1,
error = 2,
fatal = 3
};
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 [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' or 'offset')\n"
;
}
public:
Options(int argc, char* argv[]) {
static struct option long_options[] = {
{"array", required_argument, 0, 'a'},
{"dump", no_argument, 0, 'd'},
{"help", no_argument, 0, 'h'},
{"list", required_argument, 0, 'l'},
{"search", required_argument, 0, 's'},
{"type", required_argument, 0, 't'},
{0, 0, 0, 0}
};
while (true) {
int c = getopt_long(argc, argv, "a:dhl:s:t:", long_options, 0);
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(return_code::okay);
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 != "offset") {
std::cerr << "Unknown type '" << m_type << "'. Must be 'location' or 'offset'.\n";
std::exit(return_code::fatal);
}
break;
default:
std::exit(return_code::fatal);
}
}
if (m_array_format == m_list_format) {
std::cerr << "Need option --array or --list, but not both\n";
std::exit(return_code::fatal);
}
if (m_type.empty()) {
std::cerr << "Need --type argument.\n";
std::exit(return_code::fatal);
}
}
const std::string& filename() const noexcept {
return m_filename;
}
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
int main(int argc, char* argv[]) {
std::ios_base::sync_with_stdio(false);
Options options(argc, argv);
std::cout << std::fixed << std::setprecision(7);
int fd = open(options.filename().c_str(), O_RDWR);
bool result_okay = true;
if (options.type_is("location")) {
IndexSearch<osmium::unsigned_object_id_type, osmium::Location> is(fd, options.dense_format());
if (options.do_dump()) {
is.dump();
} else {
result_okay = is.search(options.search_keys());
}
} else {
IndexSearch<osmium::unsigned_object_id_type, size_t> is(fd, options.dense_format());
if (options.do_dump()) {
is.dump();
} else {
result_okay = is.search(options.search_keys());
}
}
std::exit(result_okay ? return_code::okay : return_code::not_found);
}
+333
View File
@@ -0,0 +1,333 @@
/*
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
// 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:
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:
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:
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, 0, 'a'},
{"dump", no_argument, 0, 'd'},
{"help", no_argument, 0, 'h'},
{"list", required_argument, 0, 'l'},
{"search", required_argument, 0, 's'},
{"type", required_argument, 0, 't'},
{0, 0, 0, 0}
};
while (true) {
const int c = getopt_long(argc, argv, "a:dhl:s:t:", long_options, 0);
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);
}
// 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);
}
}
View File
View File
-206
View File
@@ -1,206 +0,0 @@
/*
This is a small tool to dump the contents of the input file
in serialized format to stdout.
The code in this example file is released into the Public Domain.
*/
#include <cerrno>
#include <cstring>
#include <getopt.h>
#include <iostream>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef _MSC_VER
# include <direct.h>
#endif
#include <osmium/io/any_input.hpp>
#include <osmium/handler/disk_store.hpp>
#include <osmium/handler/object_relations.hpp>
#include <osmium/index/map/sparse_mem_array.hpp>
#include <osmium/index/multimap/sparse_mem_multimap.hpp>
#include <osmium/index/multimap/sparse_mem_array.hpp>
#include <osmium/index/multimap/hybrid.hpp>
// ==============================================================================
// Choose the following depending on the size of the input OSM files:
// ==============================================================================
// for smaller OSM files (extracts)
typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, size_t> offset_index_type;
//typedef osmium::index::map::SparseMapMmap<osmium::unsigned_object_id_type, size_t> offset_index_type;
//typedef osmium::index::map::SparseMapFile<osmium::unsigned_object_id_type, size_t> offset_index_type;
typedef osmium::index::multimap::SparseMemArray<osmium::unsigned_object_id_type, osmium::unsigned_object_id_type> map_type;
//typedef osmium::index::multimap::SparseMemMultimap<osmium::unsigned_object_id_type, osmium::unsigned_object_id_type> map_type;
//typedef osmium::index::multimap::Hybrid<osmium::unsigned_object_id_type, osmium::unsigned_object_id_type> map_type;
// ==============================================================================
// for very large OSM files (planet)
//typedef osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, size_t> offset_index_type;
// ==============================================================================
void print_help() {
std::cout << "osmium_serdump OSMFILE DIR\n" \
<< "Serialize content of OSMFILE into data file in DIR.\n" \
<< "\nOptions:\n" \
<< " -h, --help This help message\n";
}
int main(int argc, char* argv[]) {
std::ios_base::sync_with_stdio(false);
static struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
while (true) {
int c = getopt_long(argc, argv, "h", long_options, 0);
if (c == -1) {
break;
}
switch (c) {
case 'h':
print_help();
std::exit(0);
default:
std::exit(2);
}
}
int remaining_args = argc - optind;
if (remaining_args != 2) {
std::cerr << "Usage: " << argv[0] << " OSMFILE DIR\n";
std::exit(2);
}
std::string dir(argv[optind+1]);
#ifndef _WIN32
int result = ::mkdir(dir.c_str(), 0777);
#else
int result = mkdir(dir.c_str());
#endif
if (result == -1 && errno != EEXIST) {
std::cerr << "Problem creating directory '" << dir << "': " << strerror(errno) << "\n";
std::exit(2);
}
std::string data_file(dir + "/data.osm.ser");
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 << "': " << strerror(errno) << "\n";
std::exit(2);
}
offset_index_type node_index;
offset_index_type way_index;
offset_index_type relation_index;
osmium::handler::DiskStore disk_store_handler(data_fd, node_index, way_index, relation_index);
map_type map_node2way;
map_type map_node2relation;
map_type map_way2relation;
map_type map_relation2relation;
osmium::handler::ObjectRelations object_relations_handler(map_node2way, map_node2relation, map_way2relation, map_relation2relation);
osmium::io::Reader reader(argv[1]);
while (osmium::memory::Buffer buffer = reader.read()) {
disk_store_handler(buffer); // XXX
osmium::apply(buffer, object_relations_handler);
}
reader.close();
{
std::string index_file(dir + "/nodes.idx");
int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
std::cerr << "Can't open nodes index file '" << index_file << "': " << strerror(errno) << "\n";
std::exit(2);
}
node_index.dump_as_list(fd);
close(fd);
}
{
std::string index_file(dir + "/ways.idx");
int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
std::cerr << "Can't open ways index file '" << index_file << "': " << strerror(errno) << "\n";
std::exit(2);
}
way_index.dump_as_list(fd);
close(fd);
}
{
std::string index_file(dir + "/relations.idx");
int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
std::cerr << "Can't open relations index file '" << index_file << "': " << strerror(errno) << "\n";
std::exit(2);
}
relation_index.dump_as_list(fd);
close(fd);
}
{
map_node2way.sort();
std::string index_file(dir + "/node2way.map");
int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
std::cerr << "Can't open node->way map file '" << index_file << "': " << strerror(errno) << "\n";
std::exit(2);
}
map_node2way.dump_as_list(fd);
close(fd);
}
{
map_node2relation.sort();
std::string index_file(dir + "/node2rel.map");
int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
std::cerr << "Can't open node->rel map file '" << index_file << "': " << strerror(errno) << "\n";
std::exit(2);
}
map_node2relation.dump_as_list(fd);
close(fd);
}
{
map_way2relation.sort();
std::string index_file(dir + "/way2rel.map");
int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
std::cerr << "Can't open way->rel map file '" << index_file << "': " << strerror(errno) << "\n";
std::exit(2);
}
map_way2relation.dump_as_list(fd);
close(fd);
}
{
map_relation2relation.sort();
std::string index_file(dir + "/rel2rel.map");
int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
std::cerr << "Can't open rel->rel map file '" << index_file << "': " << strerror(errno) << "\n";
std::exit(2);
}
map_relation2relation.dump_as_list(fd);
close(fd);
}
}