Squashed 'third_party/libosmium/' changes from 80df1d6..40c4a48
40c4a48 Release v2.10.0 6addb2e Search for protozero also in the place where libosmium was found. 9c0d4bb Consistently use lhs and rhs as parameter names in operators etc. 6179759 Update change log. 894eb7d Explicitly use size_t to get no narrowing conversions. e549e73 Fix CMake config for index_lookup. ccf0bc2 Fix bug where some compilers deduce the wrong type. fc3507d Cleaned and documented index example and renamed to osmium_index_lookup. d3c3036 Rename serdump example to dump_internal and document it. 0e9822e Also forward set_uid_from_signed() function. 29ef95c Rename build_taglist function because it was to similar to build_tag_list. c088dd0 Move static constant out of class so clang will compile it. 606cdc4 Fix CMake build script: Path for finding libosmium. 65f91fe Removed unused typedef. 07174f5 Use condition_variable to tell producer when thread queue is not full. b35e957 Some code cleanup in XML parser. c703dff Fix problem with MemberMeta. 1ccbbef Refactoring CompressionFactory. 6561bd6 Use our own exception type for map factory errors. 56e31fa Throw not_found error directly instead of using helper function. 28230c3 Test empty value for node location store, reorganize tests. 2ba316c Reorganize and fix projection tests. f949485 Don't run quite as many tests with projections because they are slow. 1bad16d Add information about build environment to benchmark output. 99617bb Change proj_geojson benchmark into mercator benchmark. 553b946 Allow optional parameters on Reader in any order. dcc3d8f Factor out some common code. 004d8cd Fix forwarding constructor. 9702978 Fix metadata check. 6cfb6c4 Faster implementation of decode_dense_nodes without reading metdata. 4ba4638 Add additional read_metadata parameter to other Reader constructors. d005937 Optionally ignore metadata when reading file. 63961da Mark all CRC32 update functions as noexcept. cc4ca75 Refactor set_user() function to speed it up. 38d19dc Update comments with file sizes. OSM has grown... f7d0824 Add new benchmark that shows performance when main thread is busy. 25070dc Use const ref params. 88e8d96 Mark add_user() as deprecated. f58d9db Refactor some low-level collection code to clean up code. 4680def Add example showing how to create OSM data out of thin air. d42fd50 Add an example showing how tags in OSM files can be changed. 49bf5bc Add additional constructors to Builders taking a reference to parent. 7b91d63 Change Builder::add_item() to take a reference instead of pointer. 2957e48 Some cleanup of examples. d0b458d Calculate size of object at compile time. 3fbb6e7 Use explicit cast. 1851f3d Remove a test that depends on math details. f6a0802 Various cleanups of example programs. ba4921f Rename add_user() to set_user(). d7637c9 Various cleanups related to builders. 07827bc Fix add_user(). 9a5b395 Also refactor OSMObjectBuilder like ChangesetBuilder before. b1f423c Use call chaining on the builder. e49473d Get rid of ObjectBuilder class. 67d70b9 Refactor ChangesetBuilder::add_user(). 8199c33 Make ChangesetBuilder derive directly from Builder. 61d1b67 Simplify some code. d38467a Change derivation hierarchy of some builder classes. b52f8af Refactor Builder code. d012bfa Refactored some code setting attributes on objects using builder instead. 6a05f60 Also forward set_removed function from builders. 8d63b7d Return *this from Builder setter functions and test it. 72a1266 Update catch.hpp to newest version. 3424a74 Check GEOS version is <= 3.5. aee9f9d Cleanup test code. aef198c Improved asserts in Buffer. a98b9bf Code cleanup in tests. a150466 Use GDAL/OGR instead of GEOS to test our WKB implementation. b04a525 Refactor test. 39aa932 Refactored test_factory_with_projection so it works without GEOS. 648f43a Remove unused dependency on geos from tile test. f1748ae Add setters to Builder classes forwarding to underlying objects. 8166879 In debug mode check that Builders are correctly called and destructed. 1c4257e Call commit() on buffer only after all builders are destructed. 2618636 Add functions to check availability of relation members. b45a4d9 Mark RelationMember::set_ref() as deprecated. 7886771 Move "basic" and "buffer" tests to "osm" and "memory", respectively. b664685 Use functions instead of macros in location test for faster compile. b4929ac Add more tests for number parser. 02662a7 Merge pull request #171 from lonvia/fix-long-exponentials 5344a6c fix parsing of numbers in e-notiation with many post-comma digits 3aeaff3 Add some typedefs to NodeRefList and memory::Collection. e750665 Add iterators to IdSetSmall and add docs and tests to IdSet classes. 50ecb2a Add more features to IdSetDense, including unset and iterator. e3dec78 Make IdSet virtual base class with two implementations. 8ea0153 Use C array instead of std::array in IdSet and clear explicitly. 3ba9905 Deprecate osmium::index::BoolVector in favour of new IdSet. 453d1ca Add osmium::index::IdSet. c78254e Add function to (temporarily) disable the progress bar. 4d88a9f Better document osmium::io::Header class. 320e3af Look for protozero includes in CMake config. 838d25e Allow optional checking for libosmium version number in CMake config. 6ce60c1 Fix entity_bits static_assert() tests. f054731 Update change log. 77ac4c2 Make sleep duration for full queues much smaller. 7e39c01 Make some entity_bits functions constexpr. 69ea72f Fix ~ operator on entity_bits and more tests for entity bits. dafe4cf Update embedded Catch unit test header to version 1.5.7. a41c832 Fixed parsing of location coordinates starting with decimal dot. 6523bae README cosmetics. 229acac Add tests for some examples. f1e753d Merge pull request #163 from sebastic/executable-not-elf-or-script ccea2d5 Remove executable bit from .cpp files. af77fb4 Changelog formatting fixes. git-subtree-dir: third_party/libosmium git-subtree-split: 40c4a48f88d25edace6f0b9e079c306308c7760b
This commit is contained in:
parent
879f7eb042
commit
babbda98a6
58
CHANGELOG.md
58
CHANGELOG.md
@ -13,6 +13,53 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
### Fixed
|
||||
|
||||
|
||||
## [2.10.0] - 2016-11-11
|
||||
|
||||
### Added
|
||||
|
||||
- The `Reader` can take an additional optional `read_meta` flag. If this is
|
||||
set to false the PBF input will ignore metadata on OSM objects (like version,
|
||||
timestamp, uid, ...) which speeds up file reading by 10 to 20%.
|
||||
- New `IdSet` virtual class with two implementations: `IdSetDense` and
|
||||
`IdSetSmall`. Used to efficiently store a set of Ids. This is often needed
|
||||
to track, for instance, which nodes are needed for ways, etc.
|
||||
- Added more examples and better documented existing examples.
|
||||
- Add a benchmark "mercator" converting all node locations in a file to
|
||||
WebMercator and creating geometries in WKB format.
|
||||
|
||||
### Changed
|
||||
|
||||
- Better queue handling makes I/O faster in some circumstances.
|
||||
- The `FindOsmium.cmake` CMake script can now check a current enough libosmium
|
||||
version is found.
|
||||
- Builders can now be constructed with a reference to parent builder.
|
||||
- Made builders more robust by adding asserts that will catch common usage
|
||||
problems.
|
||||
- Calling `OSMObjectBuilder::add_user()` is now optional, and the method was
|
||||
renamed to `set_user()`. (`add_user()` is marked as deprecated.)
|
||||
- Benchmarks now show compiler and compiler options used.
|
||||
- `Builder::add_item()` now takes a reference instead of pointer (old version
|
||||
of the function marked as deprecated).
|
||||
- GEOS support is deprecated. It does not work any more for GEOS 3.6 or newer.
|
||||
Reason is the changed interface in GEOS 3.6. If there is interest for the
|
||||
GEOS support, we can add support back in later (but probably using the
|
||||
GEOS C API which is more stable than the C++ API). Some tests using GEOS
|
||||
were rewritten to work without it.
|
||||
- The `BoolVector` has been deprecated in favour of the new `IdSet` classes.
|
||||
- Lots of code cleanups and improved API documentation in many places.
|
||||
- The relations collector can now tell you whether a relation member was in
|
||||
the input data. See the new `is_available()` and
|
||||
`get_availability_and_offset()` methods.
|
||||
- Updated embedded Catch unit test header to version 1.5.8.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Parsing of coordinates starting with decimal dot and coordinates in
|
||||
scientific notation.
|
||||
- `~` operator for `entity_bits` doesn't set unused bits any more.
|
||||
- Progress bar can now be (temporarily) removed, to allow other output.
|
||||
|
||||
|
||||
## [2.9.0] - 2016-09-15
|
||||
|
||||
### Added
|
||||
@ -110,7 +157,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- New functions for iterating over specific item types in buffers
|
||||
(`osmium::memory::Buffer::select()`), over specific subitems
|
||||
(`osmium::OSMObject::subitems()`), and for iterating over all rings of
|
||||
an area (`osmium::Areas::outer_rings(`), `inner_rings()`).
|
||||
an area (`osmium::Areas::outer_rings()`, `inner_rings()`).
|
||||
- Debug output optionally prints CRC32 when `add_crc32` file option is set.
|
||||
|
||||
### Changed
|
||||
@ -267,9 +314,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
one in Writer. Calling flush() on the OutputIterator isn't needed any
|
||||
more.
|
||||
- Reader now throws when trying to read after eof or an error.
|
||||
- I/O functions that used to throw std::runtime_error now throw
|
||||
osmium::io_error or derived.
|
||||
- Optional parameters on osmium::io::Writer now work in any order.
|
||||
- I/O functions that used to throw `std::runtime_error` now throw
|
||||
`osmium::io_error` or derived.
|
||||
- Optional parameters on `osmium::io::Writer` now work in any order.
|
||||
|
||||
### Fixed
|
||||
|
||||
@ -410,7 +457,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
Doxygen (up to version 1.8.8). This version contains a workaround to fix
|
||||
this.
|
||||
|
||||
[unreleased]: https://github.com/osmcode/libosmium/compare/v2.9.0...HEAD
|
||||
[unreleased]: https://github.com/osmcode/libosmium/compare/v2.10.0...HEAD
|
||||
[2.10.0]: https://github.com/osmcode/libosmium/compare/v2.9.0...v2.10.0
|
||||
[2.9.0]: https://github.com/osmcode/libosmium/compare/v2.8.0...v2.9.0
|
||||
[2.8.0]: https://github.com/osmcode/libosmium/compare/v2.7.2...v2.8.0
|
||||
[2.7.2]: https://github.com/osmcode/libosmium/compare/v2.7.1...v2.7.2
|
||||
|
@ -24,7 +24,7 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel;Dev;Cover
|
||||
project(libosmium)
|
||||
|
||||
set(LIBOSMIUM_VERSION_MAJOR 2)
|
||||
set(LIBOSMIUM_VERSION_MINOR 9)
|
||||
set(LIBOSMIUM_VERSION_MINOR 10)
|
||||
set(LIBOSMIUM_VERSION_PATCH 0)
|
||||
|
||||
set(LIBOSMIUM_VERSION
|
||||
@ -285,6 +285,10 @@ if(BUILD_DATA_TESTS)
|
||||
add_subdirectory(test/data-tests)
|
||||
endif()
|
||||
|
||||
if(BUILD_EXAMPLES)
|
||||
add_subdirectory(test/examples)
|
||||
endif()
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
|
@ -4,8 +4,8 @@ http://osmcode.org/libosmium
|
||||
|
||||
A fast and flexible C++ library for working with OpenStreetMap data.
|
||||
|
||||
[](https://travis-ci.org/osmcode/libosmium)
|
||||
[](https://ci.appveyor.com/project/Mapbox/libosmium)
|
||||
[](https://travis-ci.org/osmcode/libosmium)
|
||||
[](https://ci.appveyor.com/project/Mapbox/libosmium)
|
||||
|
||||
Libosmium is developed on Linux, but also works on OSX and Windows (with some
|
||||
limitations).
|
||||
|
@ -12,6 +12,7 @@ set(BENCHMARKS
|
||||
count
|
||||
count_tag
|
||||
index_map
|
||||
mercator
|
||||
static_vs_dynamic_index
|
||||
write_pbf
|
||||
CACHE STRING "Benchmark programs"
|
||||
@ -37,6 +38,8 @@ foreach(benchmark ${BENCHMARKS})
|
||||
@ONLY)
|
||||
endforeach()
|
||||
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" _cmake_build_type)
|
||||
set(_cxx_flags "${CMAKE_CXX_FLAGS_${_cmake_build_type}}")
|
||||
foreach(file setup run_benchmarks)
|
||||
configure_file(${file}.sh ${CMAKE_CURRENT_BINARY_DIR}/${file}.sh @ONLY)
|
||||
endforeach()
|
||||
|
@ -4,9 +4,9 @@
|
||||
#
|
||||
|
||||
cd $DATA_DIR
|
||||
curl --location --output 1_liechtenstein.osm.pbf http://download.geofabrik.de/europe/liechtenstein-latest.osm.pbf # about 1 MB
|
||||
curl --location --output 2_bremen.osm.pbf http://download.geofabrik.de/europe/germany/bremen-latest.osm.pbf # about 13 MB
|
||||
curl --location --output 3_sachsen.osm.pbf http://download.geofabrik.de/europe/germany/sachsen-latest.osm.pbf # about 120 MB
|
||||
curl --location --output 4_germany.osm.pbf http://download.geofabrik.de/europe/germany-latest.osm.pbf # about 2 GB
|
||||
curl --location --output 5_planet.osm.pbf http://planet.osm.org/pbf/planet-latest.osm.pbf # about 26 GB
|
||||
curl --location --output 1_liechtenstein.osm.pbf http://download.geofabrik.de/europe/liechtenstein-latest.osm.pbf # about 2 MB
|
||||
curl --location --output 2_bremen.osm.pbf http://download.geofabrik.de/europe/germany/bremen-latest.osm.pbf # about 16 MB
|
||||
curl --location --output 3_sachsen.osm.pbf http://download.geofabrik.de/europe/germany/sachsen-latest.osm.pbf # about 160 MB
|
||||
curl --location --output 4_germany.osm.pbf http://download.geofabrik.de/europe/germany-latest.osm.pbf # about 3 GB
|
||||
curl --location --output 5_planet.osm.pbf http://planet.osm.org/pbf/planet-latest.osm.pbf # about 35 GB
|
||||
|
||||
|
@ -19,15 +19,15 @@ struct CountHandler : public osmium::handler::Handler {
|
||||
uint64_t ways = 0;
|
||||
uint64_t relations = 0;
|
||||
|
||||
void node(osmium::Node&) {
|
||||
void node(const osmium::Node&) {
|
||||
++nodes;
|
||||
}
|
||||
|
||||
void way(osmium::Way&) {
|
||||
void way(const osmium::Way&) {
|
||||
++ways;
|
||||
}
|
||||
|
||||
void relation(osmium::Relation&) {
|
||||
void relation(const osmium::Relation&) {
|
||||
++relations;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ struct CountHandler : public osmium::handler::Handler {
|
||||
uint64_t counter = 0;
|
||||
uint64_t all = 0;
|
||||
|
||||
void node(osmium::Node& node) {
|
||||
void node(const osmium::Node& node) {
|
||||
++all;
|
||||
const char* amenity = node.tags().get_value_by_key("amenity");
|
||||
if (amenity && !strcmp(amenity, "post_box")) {
|
||||
@ -26,11 +26,11 @@ struct CountHandler : public osmium::handler::Handler {
|
||||
}
|
||||
}
|
||||
|
||||
void way(osmium::Way&) {
|
||||
void way(const osmium::Way&) {
|
||||
++all;
|
||||
}
|
||||
|
||||
void relation(osmium::Relation&) {
|
||||
void relation(const osmium::Relation&) {
|
||||
++all;
|
||||
}
|
||||
|
||||
|
43
benchmarks/osmium_benchmark_mercator.cpp
Normal file
43
benchmarks/osmium_benchmark_mercator.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
|
||||
The code in this file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <osmium/io/any_input.hpp>
|
||||
#include <osmium/handler.hpp>
|
||||
#include <osmium/visitor.hpp>
|
||||
#include <osmium/geom/wkb.hpp>
|
||||
#include <osmium/geom/mercator_projection.hpp>
|
||||
|
||||
struct GeomHandler : public osmium::handler::Handler {
|
||||
|
||||
osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory;
|
||||
|
||||
void node(const osmium::Node& node) {
|
||||
const std::string geom = factory.create_point(node);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
const std::string input_filename{argv[1]};
|
||||
|
||||
osmium::io::Reader reader{input_filename};
|
||||
|
||||
GeomHandler handler;
|
||||
osmium::apply(reader, handler);
|
||||
reader.close();
|
||||
}
|
||||
|
22
benchmarks/run_benchmark_mercator.sh
Executable file
22
benchmarks/run_benchmark_mercator.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# run_benchmark_mercator.sh
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
BENCHMARK_NAME=mercator
|
||||
|
||||
. @CMAKE_BINARY_DIR@/benchmarks/setup.sh
|
||||
|
||||
CMD=$OB_DIR/osmium_benchmark_$BENCHMARK_NAME
|
||||
|
||||
echo "# file size num mem time cpu_kernel cpu_user cpu_percent cmd options"
|
||||
for data in $OB_DATA_FILES; do
|
||||
filename=`basename $data`
|
||||
filesize=`stat --format="%s" --dereference $data`
|
||||
for n in $OB_SEQ; do
|
||||
$OB_TIME_CMD -f "$filename $filesize $n $OB_TIME_FORMAT" $CMD $data 2>&1 >/dev/null | sed -e "s%$DATA_DIR/%%" | sed -e "s%$OB_DIR/%%"
|
||||
done
|
||||
done
|
||||
|
@ -9,6 +9,10 @@ if [ -z $DATA_DIR ]; then
|
||||
fi
|
||||
|
||||
OB_DIR=@CMAKE_BINARY_DIR@/benchmarks
|
||||
OB_BUILD_TYPE=@CMAKE_BUILD_TYPE@
|
||||
OB_COMPILER=@CMAKE_CXX_COMPILER@
|
||||
OB_COMPILER_VERSION=`$OB_COMPILER --version | head -1`
|
||||
OB_CXXFLAGS="@_cxx_flags@"
|
||||
|
||||
OB_RUNS=3
|
||||
OB_SEQ=`seq -s' ' 1 $OB_RUNS`
|
||||
@ -20,11 +24,17 @@ OB_DATA_FILES=`find -L $DATA_DIR -mindepth 1 -maxdepth 1 -type f | sort`
|
||||
|
||||
echo "BENCHMARK: $BENCHMARK_NAME"
|
||||
echo "---------------------"
|
||||
echo "BUILD:"
|
||||
echo "build type\t: $OB_BUILD_TYPE"
|
||||
echo "compiler\t: $OB_COMPILER"
|
||||
echo "CXX version\t: $OB_COMPILER_VERSION"
|
||||
echo "CXX flags\t: $OB_CXXFLAGS"
|
||||
echo "---------------------"
|
||||
echo "CPU:"
|
||||
grep '^model name' /proc/cpuinfo | tail -1
|
||||
grep '^cpu MHz' /proc/cpuinfo | tail -1
|
||||
grep '^cpu cores' /proc/cpuinfo | tail -1
|
||||
grep '^siblings' /proc/cpuinfo | tail -1
|
||||
grep '^cpu MHz' /proc/cpuinfo | tail -1
|
||||
grep '^cpu cores' /proc/cpuinfo | tail -1
|
||||
grep '^siblings' /proc/cpuinfo | tail -1
|
||||
|
||||
echo "---------------------"
|
||||
echo "MEMORY:"
|
||||
|
@ -2,8 +2,8 @@
|
||||
#
|
||||
# FindOsmium.cmake
|
||||
#
|
||||
# Find the Libosmium headers and, optionally, several components needed for
|
||||
# different Libosmium functions.
|
||||
# Find the Libosmium headers and, optionally, several components needed
|
||||
# for different Libosmium functions.
|
||||
#
|
||||
#----------------------------------------------------------------------
|
||||
#
|
||||
@ -18,9 +18,12 @@
|
||||
#
|
||||
# Then add the following in your CMakeLists.txt:
|
||||
#
|
||||
# find_package(Osmium REQUIRED COMPONENTS <XXX>)
|
||||
# find_package(Osmium [version] REQUIRED COMPONENTS <XXX>)
|
||||
# include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS})
|
||||
#
|
||||
# The version number is optional. If it is not set, any version of
|
||||
# libosmium will do.
|
||||
#
|
||||
# For the <XXX> substitute a space separated list of one or more of the
|
||||
# following components:
|
||||
#
|
||||
@ -51,10 +54,9 @@
|
||||
#
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
# Look for the header file.
|
||||
find_path(OSMIUM_INCLUDE_DIR osmium/osm.hpp
|
||||
PATH_SUFFIXES include
|
||||
PATHS
|
||||
# This is the list of directories where we look for osmium and protozero
|
||||
# includes.
|
||||
set(_osmium_include_path
|
||||
../libosmium
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
@ -62,6 +64,22 @@ find_path(OSMIUM_INCLUDE_DIR osmium/osm.hpp
|
||||
/opt
|
||||
)
|
||||
|
||||
# Look for the header file.
|
||||
find_path(OSMIUM_INCLUDE_DIR osmium/version.hpp
|
||||
PATH_SUFFIXES include
|
||||
PATHS ${_osmium_include_path}
|
||||
)
|
||||
|
||||
# Check libosmium version number
|
||||
if(Osmium_FIND_VERSION)
|
||||
file(STRINGS "${OSMIUM_INCLUDE_DIR}/osmium/version.hpp" _libosmium_version_define REGEX "#define LIBOSMIUM_VERSION_STRING")
|
||||
if("${_libosmium_version_define}" MATCHES "#define LIBOSMIUM_VERSION_STRING \"([0-9.]+)\"")
|
||||
set(_libosmium_version "${CMAKE_MATCH_1}")
|
||||
else()
|
||||
set(_libosmium_version "unknown")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(OSMIUM_INCLUDE_DIRS "${OSMIUM_INCLUDE_DIR}")
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
@ -95,17 +113,31 @@ if(Osmium_USE_PBF)
|
||||
find_package(ZLIB)
|
||||
find_package(Threads)
|
||||
|
||||
list(APPEND OSMIUM_EXTRA_FIND_VARS ZLIB_FOUND Threads_FOUND)
|
||||
if(ZLIB_FOUND AND Threads_FOUND)
|
||||
message(STATUS "Looking for protozero")
|
||||
find_path(PROTOZERO_INCLUDE_DIR protozero/version.hpp
|
||||
PATH_SUFFIXES include
|
||||
PATHS ${_osmium_include_path}
|
||||
${OSMIUM_INCLUDE_DIR}
|
||||
)
|
||||
if(PROTOZERO_INCLUDE_DIR)
|
||||
message(STATUS "Looking for protozero - found")
|
||||
else()
|
||||
message(STATUS "Looking for protozero - not found")
|
||||
endif()
|
||||
|
||||
list(APPEND OSMIUM_EXTRA_FIND_VARS ZLIB_FOUND Threads_FOUND PROTOZERO_INCLUDE_DIR)
|
||||
if(ZLIB_FOUND AND Threads_FOUND AND PROTOZERO_INCLUDE_DIR)
|
||||
list(APPEND OSMIUM_PBF_LIBRARIES
|
||||
${ZLIB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
if(WIN32)
|
||||
# This is needed for the ntohl() function
|
||||
list(APPEND OSMIUM_PBF_LIBRARIES ws2_32)
|
||||
endif()
|
||||
list(APPEND OSMIUM_INCLUDE_DIRS
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
${PROTOZERO_INCLUDE_DIR}
|
||||
)
|
||||
else()
|
||||
message(WARNING "Osmium: Can not find some libraries for PBF input/output, please install them or configure the paths.")
|
||||
@ -203,7 +235,7 @@ if(Osmium_USE_SPARSEHASH)
|
||||
if(SPARSEHASH_INCLUDE_DIR)
|
||||
# Find size of sparsetable::size_type. This does not work on older
|
||||
# CMake versions because they can do this check only in C, not in C++.
|
||||
if (NOT CMAKE_VERSION VERSION_LESS 3.0)
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.0)
|
||||
include(CheckTypeSize)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR})
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable")
|
||||
@ -253,13 +285,15 @@ endif()
|
||||
# Check that all required libraries are available
|
||||
#
|
||||
#----------------------------------------------------------------------
|
||||
if (OSMIUM_EXTRA_FIND_VARS)
|
||||
if(OSMIUM_EXTRA_FIND_VARS)
|
||||
list(REMOVE_DUPLICATES OSMIUM_EXTRA_FIND_VARS)
|
||||
endif()
|
||||
# Handle the QUIETLY and REQUIRED arguments and set OSMIUM_FOUND to TRUE if
|
||||
# all listed variables are TRUE.
|
||||
# Handle the QUIETLY and REQUIRED arguments and the optional version check
|
||||
# and set OSMIUM_FOUND to TRUE if all listed variables are TRUE.
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Osmium REQUIRED_VARS OSMIUM_INCLUDE_DIR ${OSMIUM_EXTRA_FIND_VARS})
|
||||
find_package_handle_standard_args(Osmium
|
||||
REQUIRED_VARS OSMIUM_INCLUDE_DIR ${OSMIUM_EXTRA_FIND_VARS}
|
||||
VERSION_VAR _libosmium_version)
|
||||
unset(OSMIUM_EXTRA_FIND_VARS)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
@ -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})
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
examples/osmium_change_tags.cpp
Normal file
203
examples/osmium_change_tags.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
@ -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
examples/osmium_create_pois.cpp
Normal file
96
examples/osmium_create_pois.cpp
Normal 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
examples/osmium_dump_internal.cpp
Normal file
179
examples/osmium_dump_internal.cpp
Normal 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".
|
||||
|
@ -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
examples/osmium_index_lookup.cpp
Normal file
333
examples/osmium_index_lookup.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
0
examples/osmium_pub_names.cpp
Executable file → Normal file
0
examples/osmium_pub_names.cpp
Executable file → Normal file
0
examples/osmium_road_length.cpp
Executable file → Normal file
0
examples/osmium_road_length.cpp
Executable file → Normal 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);
|
||||
}
|
||||
}
|
||||
|
@ -193,12 +193,12 @@ namespace osmium {
|
||||
|
||||
}; // struct location_to_ring_map
|
||||
|
||||
inline bool operator==(const location_to_ring_map& a, const location_to_ring_map& b) noexcept {
|
||||
return a.location == b.location;
|
||||
inline bool operator==(const location_to_ring_map& lhs, const location_to_ring_map& rhs) noexcept {
|
||||
return lhs.location == rhs.location;
|
||||
}
|
||||
|
||||
inline bool operator<(const location_to_ring_map& a, const location_to_ring_map& b) noexcept {
|
||||
return a.location < b.location;
|
||||
inline bool operator<(const location_to_ring_map& lhs, const location_to_ring_map& rhs) noexcept {
|
||||
return lhs.location < rhs.location;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
@ -288,7 +288,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Way& way) const {
|
||||
builder.add_item(&way.tags());
|
||||
builder.add_item(way.tags());
|
||||
}
|
||||
|
||||
void add_common_tags(osmium::builder::TagListBuilder& tl_builder, std::set<const osmium::Way*>& ways) const {
|
||||
@ -333,7 +333,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
static void copy_tags_without_type(osmium::builder::AreaBuilder& builder, const osmium::TagList& tags) {
|
||||
osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
|
||||
osmium::builder::TagListBuilder tl_builder{builder};
|
||||
for (const osmium::Tag& tag : tags) {
|
||||
if (std::strcmp(tag.key(), "type")) {
|
||||
tl_builder.add_tag(tag.key(), tag.value());
|
||||
@ -354,7 +354,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
if (m_config.keep_type_tag) {
|
||||
builder.add_item(&relation.tags());
|
||||
builder.add_item(relation.tags());
|
||||
} else {
|
||||
copy_tags_without_type(builder, relation.tags());
|
||||
}
|
||||
@ -373,12 +373,12 @@ namespace osmium {
|
||||
if (debug()) {
|
||||
std::cerr << " only one outer way\n";
|
||||
}
|
||||
builder.add_item(&(*ways.cbegin())->tags());
|
||||
builder.add_item((*ways.cbegin())->tags());
|
||||
} else {
|
||||
if (debug()) {
|
||||
std::cerr << " multiple outer ways, get common tags\n";
|
||||
}
|
||||
osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
|
||||
osmium::builder::TagListBuilder tl_builder{builder};
|
||||
add_common_tags(tl_builder, ways);
|
||||
}
|
||||
}
|
||||
@ -386,7 +386,7 @@ namespace osmium {
|
||||
|
||||
template <typename TBuilder>
|
||||
static void build_ring_from_proto_ring(osmium::builder::AreaBuilder& builder, const detail::ProtoRing& ring) {
|
||||
TBuilder ring_builder(builder.buffer(), &builder);
|
||||
TBuilder ring_builder{builder};
|
||||
ring_builder.add_node_ref(ring.get_node_ref_start());
|
||||
for (const auto& segment : ring.segments()) {
|
||||
ring_builder.add_node_ref(segment->stop());
|
||||
@ -458,8 +458,8 @@ namespace osmium {
|
||||
}
|
||||
|
||||
detail::NodeRefSegment* get_next_segment(const osmium::Location& location) {
|
||||
auto it = std::lower_bound(m_locations.begin(), m_locations.end(), slocation{}, [this, &location](const slocation& a, const slocation& b) {
|
||||
return a.location(m_segment_list, location) < b.location(m_segment_list, location);
|
||||
auto it = std::lower_bound(m_locations.begin(), m_locations.end(), slocation{}, [this, &location](const slocation& lhs, const slocation& rhs) {
|
||||
return lhs.location(m_segment_list, location) < rhs.location(m_segment_list, location);
|
||||
});
|
||||
|
||||
assert(it != m_locations.end());
|
||||
@ -744,8 +744,8 @@ namespace osmium {
|
||||
m_locations.emplace_back(n, true);
|
||||
}
|
||||
|
||||
std::stable_sort(m_locations.begin(), m_locations.end(), [this](const slocation& a, const slocation& b) {
|
||||
return a.location(m_segment_list) < b.location(m_segment_list);
|
||||
std::stable_sort(m_locations.begin(), m_locations.end(), [this](const slocation& lhs, const slocation& rhs) {
|
||||
return lhs.location(m_segment_list) < rhs.location(m_segment_list);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1015,8 +1015,8 @@ namespace osmium {
|
||||
|
||||
std::vector<location_to_ring_map> xrings = create_location_to_ring_map(open_ring_its);
|
||||
|
||||
const auto ring_min = std::min_element(xrings.begin(), xrings.end(), [](const location_to_ring_map& a, const location_to_ring_map& b) {
|
||||
return a.ring().min_segment() < b.ring().min_segment();
|
||||
const auto ring_min = std::min_element(xrings.begin(), xrings.end(), [](const location_to_ring_map& lhs, const location_to_ring_map& rhs) {
|
||||
return lhs.ring().min_segment() < rhs.ring().min_segment();
|
||||
});
|
||||
|
||||
find_inner_outer_complex();
|
||||
@ -1068,11 +1068,11 @@ namespace osmium {
|
||||
|
||||
// Find the candidate with the smallest/largest area
|
||||
const auto chosen_cand = ring_min_is_outer ?
|
||||
std::min_element(candidates.cbegin(), candidates.cend(), [](const candidate& a, const candidate& b) {
|
||||
return std::abs(a.sum) < std::abs(b.sum);
|
||||
std::min_element(candidates.cbegin(), candidates.cend(), [](const candidate& lhs, const candidate& rhs) {
|
||||
return std::abs(lhs.sum) < std::abs(rhs.sum);
|
||||
}) :
|
||||
std::max_element(candidates.cbegin(), candidates.cend(), [](const candidate& a, const candidate& b) {
|
||||
return std::abs(a.sum) < std::abs(b.sum);
|
||||
std::max_element(candidates.cbegin(), candidates.cend(), [](const candidate& lhs, const candidate& rhs) {
|
||||
return std::abs(lhs.sum) < std::abs(rhs.sum);
|
||||
});
|
||||
|
||||
if (debug()) {
|
||||
@ -1103,8 +1103,8 @@ namespace osmium {
|
||||
const auto locs = make_range(std::equal_range(m_locations.begin(),
|
||||
m_locations.end(),
|
||||
slocation{},
|
||||
[this, &location](const slocation& a, const slocation& b) {
|
||||
return a.location(m_segment_list, location) < b.location(m_segment_list, location);
|
||||
[this, &location](const slocation& lhs, const slocation& rhs) {
|
||||
return lhs.location(m_segment_list, location) < rhs.location(m_segment_list, location);
|
||||
}));
|
||||
for (auto& loc : locs) {
|
||||
if (!m_segment_list[loc.item].is_done()) {
|
||||
@ -1267,8 +1267,8 @@ namespace osmium {
|
||||
}
|
||||
for (const auto& location : m_split_locations) {
|
||||
if (m_config.problem_reporter) {
|
||||
auto it = std::lower_bound(m_locations.cbegin(), m_locations.cend(), slocation{}, [this, &location](const slocation& a, const slocation& b) {
|
||||
return a.location(m_segment_list, location) < b.location(m_segment_list, location);
|
||||
auto it = std::lower_bound(m_locations.cbegin(), m_locations.cend(), slocation{}, [this, &location](const slocation& lhs, const slocation& rhs) {
|
||||
return lhs.location(m_segment_list, location) < rhs.location(m_segment_list, location);
|
||||
});
|
||||
assert(it != m_locations.cend());
|
||||
const osmium::object_id_type id = it->node_ref(m_segment_list).ref();
|
||||
@ -1362,7 +1362,7 @@ namespace osmium {
|
||||
#endif
|
||||
|
||||
bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Way& way) {
|
||||
osmium::builder::AreaBuilder builder(out_buffer);
|
||||
osmium::builder::AreaBuilder builder{out_buffer};
|
||||
builder.initialize_from_object(way);
|
||||
|
||||
const bool area_okay = create_rings();
|
||||
@ -1382,7 +1382,7 @@ namespace osmium {
|
||||
|
||||
bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Relation& relation, const std::vector<const osmium::Way*>& members) {
|
||||
m_num_members = members.size();
|
||||
osmium::builder::AreaBuilder builder(out_buffer);
|
||||
osmium::builder::AreaBuilder builder{out_buffer};
|
||||
builder.initialize_from_object(relation);
|
||||
|
||||
const bool area_okay = create_rings();
|
||||
|
@ -379,8 +379,8 @@ namespace osmium {
|
||||
sl[2] = {1, s2.first().location() };
|
||||
sl[3] = {1, s2.second().location()};
|
||||
|
||||
std::sort(sl, sl+4, [](const seg_loc& a, const seg_loc& b) {
|
||||
return a.location < b.location;
|
||||
std::sort(sl, sl+4, [](const seg_loc& lhs, const seg_loc& rhs) {
|
||||
return lhs.location < rhs.location;
|
||||
});
|
||||
|
||||
if (sl[1].location == sl[2].location) {
|
||||
|
@ -101,7 +101,7 @@ namespace osmium {
|
||||
* Calculate the number of segments in all the ways together.
|
||||
*/
|
||||
static size_t get_num_segments(const std::vector<const osmium::Way*>& members) noexcept {
|
||||
return std::accumulate(members.cbegin(), members.cend(), 0, [](size_t sum, const osmium::Way* way) {
|
||||
return std::accumulate(members.cbegin(), members.cend(), static_cast<size_t>(0), [](size_t sum, const osmium::Way* way) {
|
||||
if (way->nodes().empty()) {
|
||||
return sum;
|
||||
} else {
|
||||
|
@ -73,18 +73,18 @@ namespace osmium {
|
||||
}; // struct vec
|
||||
|
||||
// addition
|
||||
constexpr inline vec operator+(const vec& a, const vec& b) noexcept {
|
||||
return vec{a.x + b.x, a.y + b.y};
|
||||
constexpr inline vec operator+(const vec& lhs, const vec& rhs) noexcept {
|
||||
return vec{lhs.x + rhs.x, lhs.y + rhs.y};
|
||||
}
|
||||
|
||||
// subtraction
|
||||
constexpr inline vec operator-(const vec& a, const vec& b) noexcept {
|
||||
return vec{a.x - b.x, a.y - b.y};
|
||||
constexpr inline vec operator-(const vec& lhs, const vec& rhs) noexcept {
|
||||
return vec{lhs.x - rhs.x, lhs.y - rhs.y};
|
||||
}
|
||||
|
||||
// cross product
|
||||
constexpr inline int64_t operator*(const vec& a, const vec& b) noexcept {
|
||||
return a.x * b.y - a.y * b.x;
|
||||
constexpr inline int64_t operator*(const vec& lhs, const vec& rhs) noexcept {
|
||||
return lhs.x * rhs.y - lhs.y * rhs.x;
|
||||
}
|
||||
|
||||
// scale vector
|
||||
@ -98,13 +98,13 @@ namespace osmium {
|
||||
}
|
||||
|
||||
// equality
|
||||
constexpr inline bool operator==(const vec& a, const vec& b) noexcept {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
constexpr inline bool operator==(const vec& lhs, const vec& rhs) noexcept {
|
||||
return lhs.x == rhs.x && lhs.y == rhs.y;
|
||||
}
|
||||
|
||||
// inequality
|
||||
constexpr inline bool operator!=(const vec& a, const vec& b) noexcept {
|
||||
return !(a == b);
|
||||
constexpr inline bool operator!=(const vec& lhs, const vec& rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
|
@ -617,7 +617,7 @@ namespace osmium {
|
||||
|
||||
template <typename TBuilder, typename... TArgs>
|
||||
inline void add_user(TBuilder& builder, const TArgs&... args) {
|
||||
builder.add_user(get_user(args...));
|
||||
builder.set_user(get_user(args...));
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
@ -761,11 +761,13 @@ namespace osmium {
|
||||
static_assert(sizeof...(args) > 0, "add_node() must have buffer and at least one additional argument");
|
||||
static_assert(detail::are_all_handled_by<detail::any_node_handlers, TArgs...>::value, "Attribute not allowed in add_node()");
|
||||
|
||||
NodeBuilder builder(buffer);
|
||||
{
|
||||
NodeBuilder builder(buffer);
|
||||
|
||||
detail::add_basic<detail::node_handler>(builder, args...);
|
||||
detail::add_user(builder, args...);
|
||||
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
|
||||
detail::add_basic<detail::node_handler>(builder, args...);
|
||||
detail::add_user(builder, args...);
|
||||
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
|
||||
}
|
||||
|
||||
return buffer.commit();
|
||||
}
|
||||
@ -782,12 +784,14 @@ namespace osmium {
|
||||
static_assert(sizeof...(args) > 0, "add_way() must have buffer and at least one additional argument");
|
||||
static_assert(detail::are_all_handled_by<detail::any_way_handlers, TArgs...>::value, "Attribute not allowed in add_way()");
|
||||
|
||||
WayBuilder builder(buffer);
|
||||
{
|
||||
WayBuilder builder(buffer);
|
||||
|
||||
detail::add_basic<detail::object_handler>(builder, args...);
|
||||
detail::add_user(builder, args...);
|
||||
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
|
||||
detail::add_list<WayNodeListBuilder, detail::nodes_handler>(builder, args...);
|
||||
detail::add_basic<detail::object_handler>(builder, args...);
|
||||
detail::add_user(builder, args...);
|
||||
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
|
||||
detail::add_list<WayNodeListBuilder, detail::nodes_handler>(builder, args...);
|
||||
}
|
||||
|
||||
return buffer.commit();
|
||||
}
|
||||
@ -804,12 +808,14 @@ namespace osmium {
|
||||
static_assert(sizeof...(args) > 0, "add_relation() must have buffer and at least one additional argument");
|
||||
static_assert(detail::are_all_handled_by<detail::any_relation_handlers, TArgs...>::value, "Attribute not allowed in add_relation()");
|
||||
|
||||
RelationBuilder builder(buffer);
|
||||
{
|
||||
RelationBuilder builder(buffer);
|
||||
|
||||
detail::add_basic<detail::object_handler>(builder, args...);
|
||||
detail::add_user(builder, args...);
|
||||
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
|
||||
detail::add_list<RelationMemberListBuilder, detail::members_handler>(builder, args...);
|
||||
detail::add_basic<detail::object_handler>(builder, args...);
|
||||
detail::add_user(builder, args...);
|
||||
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
|
||||
detail::add_list<RelationMemberListBuilder, detail::members_handler>(builder, args...);
|
||||
}
|
||||
|
||||
return buffer.commit();
|
||||
}
|
||||
@ -826,12 +832,14 @@ namespace osmium {
|
||||
static_assert(sizeof...(args) > 0, "add_changeset() must have buffer and at least one additional argument");
|
||||
static_assert(detail::are_all_handled_by<detail::any_changeset_handlers, TArgs...>::value, "Attribute not allowed in add_changeset()");
|
||||
|
||||
ChangesetBuilder builder(buffer);
|
||||
{
|
||||
ChangesetBuilder builder(buffer);
|
||||
|
||||
detail::add_basic<detail::changeset_handler>(builder, args...);
|
||||
detail::add_user(builder, args...);
|
||||
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
|
||||
detail::add_list<ChangesetDiscussionBuilder, detail::discussion_handler>(builder, args...);
|
||||
detail::add_basic<detail::changeset_handler>(builder, args...);
|
||||
detail::add_user(builder, args...);
|
||||
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
|
||||
detail::add_list<ChangesetDiscussionBuilder, detail::discussion_handler>(builder, args...);
|
||||
}
|
||||
|
||||
return buffer.commit();
|
||||
}
|
||||
@ -848,15 +856,17 @@ namespace osmium {
|
||||
static_assert(sizeof...(args) > 0, "add_area() must have buffer and at least one additional argument");
|
||||
static_assert(detail::are_all_handled_by<detail::any_area_handlers, TArgs...>::value, "Attribute not allowed in add_area()");
|
||||
|
||||
AreaBuilder builder(buffer);
|
||||
{
|
||||
AreaBuilder builder(buffer);
|
||||
|
||||
detail::add_basic<detail::object_handler>(builder, args...);
|
||||
detail::add_user(builder, args...);
|
||||
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
|
||||
detail::add_basic<detail::object_handler>(builder, args...);
|
||||
detail::add_user(builder, args...);
|
||||
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
|
||||
|
||||
(void)std::initializer_list<int>{
|
||||
(detail::ring_handler::set_value(builder, args), 0)...
|
||||
};
|
||||
(void)std::initializer_list<int>{
|
||||
(detail::ring_handler::set_value(builder, args), 0)...
|
||||
};
|
||||
}
|
||||
|
||||
return buffer.commit();
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/memory/item.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/util/cast.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@ -53,6 +54,10 @@ namespace osmium {
|
||||
*/
|
||||
namespace builder {
|
||||
|
||||
/**
|
||||
* Parent class for individual builder classes. Instantiate one of
|
||||
* its derived classes.
|
||||
*/
|
||||
class Builder {
|
||||
|
||||
osmium::memory::Buffer& m_buffer;
|
||||
@ -71,20 +76,34 @@ namespace osmium {
|
||||
m_buffer(buffer),
|
||||
m_parent(parent),
|
||||
m_item_offset(buffer.written()) {
|
||||
m_buffer.reserve_space(size);
|
||||
reserve_space(size);
|
||||
assert(buffer.is_aligned());
|
||||
if (m_parent) {
|
||||
assert(m_buffer.builder_count() == 1 && "Only one sub-builder can be open at any time.");
|
||||
m_parent->add_size(size);
|
||||
} else {
|
||||
assert(m_buffer.builder_count() == 0 && "Only one builder can be open at any time.");
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
m_buffer.increment_builder_count();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
~Builder() = default;
|
||||
#else
|
||||
~Builder() noexcept {
|
||||
m_buffer.decrement_builder_count();
|
||||
}
|
||||
#endif
|
||||
|
||||
osmium::memory::Item& item() const {
|
||||
return *reinterpret_cast<osmium::memory::Item*>(m_buffer.data() + m_item_offset);
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned char* reserve_space(size_t size) {
|
||||
return m_buffer.reserve_space(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add padding to buffer (if needed) to align data properly.
|
||||
@ -102,7 +121,7 @@ namespace osmium {
|
||||
void add_padding(bool self = false) {
|
||||
const auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
|
||||
if (padding != osmium::memory::align_bytes) {
|
||||
std::fill_n(m_buffer.reserve_space(padding), padding, 0);
|
||||
std::fill_n(reserve_space(padding), padding, 0);
|
||||
if (self) {
|
||||
add_size(padding);
|
||||
} else if (m_parent) {
|
||||
@ -123,12 +142,6 @@ namespace osmium {
|
||||
return item().byte_size();
|
||||
}
|
||||
|
||||
void add_item(const osmium::memory::Item* item) {
|
||||
unsigned char* target = m_buffer.reserve_space(item->padded_size());
|
||||
std::copy_n(reinterpret_cast<const unsigned char*>(item), item->padded_size(), target);
|
||||
add_size(item->padded_size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve space for an object of class T in buffer and return
|
||||
* pointer to it.
|
||||
@ -136,7 +149,7 @@ namespace osmium {
|
||||
template <typename T>
|
||||
T* reserve_space_for() {
|
||||
assert(m_buffer.is_aligned());
|
||||
return reinterpret_cast<T*>(m_buffer.reserve_space(sizeof(T)));
|
||||
return reinterpret_cast<T*>(reserve_space(sizeof(T)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,7 +162,7 @@ namespace osmium {
|
||||
* @returns The number of bytes appended (length).
|
||||
*/
|
||||
osmium::memory::item_size_type append(const char* data, const osmium::memory::item_size_type length) {
|
||||
unsigned char* target = m_buffer.reserve_space(length);
|
||||
unsigned char* target = reserve_space(length);
|
||||
std::copy_n(reinterpret_cast<const unsigned char*>(data), length, target);
|
||||
return length;
|
||||
}
|
||||
@ -170,65 +183,37 @@ namespace osmium {
|
||||
* @returns The number of bytes appended (always 1).
|
||||
*/
|
||||
osmium::memory::item_size_type append_zero() {
|
||||
*m_buffer.reserve_space(1) = '\0';
|
||||
*reserve_space(1) = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// Return the buffer this builder is using.
|
||||
osmium::memory::Buffer& buffer() noexcept {
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a subitem to the object being built. This can be something
|
||||
* like a TagList or RelationMemberList.
|
||||
*/
|
||||
void add_item(const osmium::memory::Item& item) {
|
||||
m_buffer.add_item(item);
|
||||
add_size(item.padded_size());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use the version of add_item() taking a
|
||||
* reference instead.
|
||||
*/
|
||||
OSMIUM_DEPRECATED void add_item(const osmium::memory::Item* item) {
|
||||
assert(item);
|
||||
add_item(*item);
|
||||
}
|
||||
|
||||
}; // class Builder
|
||||
|
||||
template <typename TItem>
|
||||
class ObjectBuilder : public Builder {
|
||||
|
||||
static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "ObjectBuilder can only build objects derived from osmium::memory::Item");
|
||||
|
||||
public:
|
||||
|
||||
explicit ObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
Builder(buffer, parent, sizeof(TItem)) {
|
||||
new (&item()) TItem();
|
||||
}
|
||||
|
||||
TItem& object() noexcept {
|
||||
return static_cast<TItem&>(item());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add user name to buffer.
|
||||
*
|
||||
* @param user Pointer to user name.
|
||||
* @param length Length of user name (without \0 termination).
|
||||
*/
|
||||
void add_user(const char* user, const string_size_type length) {
|
||||
object().set_user_size(length + 1);
|
||||
add_size(append(user, length) + append_zero());
|
||||
add_padding(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add user name to buffer.
|
||||
*
|
||||
* @param user Pointer to \0-terminated user name.
|
||||
*/
|
||||
void add_user(const char* user) {
|
||||
add_user(user, static_cast_with_assert<string_size_type>(std::strlen(user)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add user name to buffer.
|
||||
*
|
||||
* @param user User name.
|
||||
*/
|
||||
void add_user(const std::string& user) {
|
||||
add_user(user.data(), static_cast_with_assert<string_size_type>(user.size()));
|
||||
}
|
||||
|
||||
}; // class ObjectBuilder
|
||||
|
||||
} // namespace builder
|
||||
|
||||
} // namespace osmium
|
||||
|
@ -45,6 +45,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/builder/builder.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/tag.hpp>
|
||||
@ -55,6 +56,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@ -66,12 +68,18 @@ namespace osmium {
|
||||
|
||||
namespace builder {
|
||||
|
||||
class TagListBuilder : public ObjectBuilder<TagList> {
|
||||
class TagListBuilder : public Builder {
|
||||
|
||||
public:
|
||||
|
||||
explicit TagListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
ObjectBuilder<TagList>(buffer, parent) {
|
||||
Builder(buffer, parent, sizeof(TagList)) {
|
||||
new (&item()) TagList();
|
||||
}
|
||||
|
||||
explicit TagListBuilder(Builder& parent) :
|
||||
Builder(parent.buffer(), &parent, sizeof(TagList)) {
|
||||
new (&item()) TagList();
|
||||
}
|
||||
|
||||
~TagListBuilder() {
|
||||
@ -169,21 +177,27 @@ namespace osmium {
|
||||
}; // class TagListBuilder
|
||||
|
||||
template <typename T>
|
||||
class NodeRefListBuilder : public ObjectBuilder<T> {
|
||||
class NodeRefListBuilder : public Builder {
|
||||
|
||||
public:
|
||||
|
||||
explicit NodeRefListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
ObjectBuilder<T>(buffer, parent) {
|
||||
Builder(buffer, parent, sizeof(T)) {
|
||||
new (&item()) T();
|
||||
}
|
||||
|
||||
explicit NodeRefListBuilder(Builder& parent) :
|
||||
Builder(parent.buffer(), &parent, sizeof(T)) {
|
||||
new (&item()) T();
|
||||
}
|
||||
|
||||
~NodeRefListBuilder() {
|
||||
static_cast<Builder*>(this)->add_padding();
|
||||
add_padding();
|
||||
}
|
||||
|
||||
void add_node_ref(const NodeRef& node_ref) {
|
||||
new (static_cast<Builder*>(this)->reserve_space_for<osmium::NodeRef>()) osmium::NodeRef(node_ref);
|
||||
static_cast<Builder*>(this)->add_size(sizeof(osmium::NodeRef));
|
||||
new (reserve_space_for<osmium::NodeRef>()) osmium::NodeRef(node_ref);
|
||||
add_size(sizeof(osmium::NodeRef));
|
||||
}
|
||||
|
||||
void add_node_ref(const object_id_type ref, const osmium::Location& location = Location{}) {
|
||||
@ -196,7 +210,7 @@ namespace osmium {
|
||||
using OuterRingBuilder = NodeRefListBuilder<OuterRing>;
|
||||
using InnerRingBuilder = NodeRefListBuilder<InnerRing>;
|
||||
|
||||
class RelationMemberListBuilder : public ObjectBuilder<RelationMemberList> {
|
||||
class RelationMemberListBuilder : public Builder {
|
||||
|
||||
/**
|
||||
* Add role to buffer.
|
||||
@ -219,7 +233,13 @@ namespace osmium {
|
||||
public:
|
||||
|
||||
explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
ObjectBuilder<RelationMemberList>(buffer, parent) {
|
||||
Builder(buffer, parent, sizeof(RelationMemberList)) {
|
||||
new (&item()) RelationMemberList();
|
||||
}
|
||||
|
||||
explicit RelationMemberListBuilder(Builder& parent) :
|
||||
Builder(parent.buffer(), &parent, sizeof(RelationMemberList)) {
|
||||
new (&item()) RelationMemberList();
|
||||
}
|
||||
|
||||
~RelationMemberListBuilder() {
|
||||
@ -245,7 +265,7 @@ namespace osmium {
|
||||
add_size(sizeof(RelationMember));
|
||||
add_role(*member, role, role_length);
|
||||
if (full_member) {
|
||||
add_item(full_member);
|
||||
add_item(*full_member);
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,7 +301,7 @@ namespace osmium {
|
||||
|
||||
}; // class RelationMemberListBuilder
|
||||
|
||||
class ChangesetDiscussionBuilder : public ObjectBuilder<ChangesetDiscussion> {
|
||||
class ChangesetDiscussionBuilder : public Builder {
|
||||
|
||||
osmium::ChangesetComment* m_comment = nullptr;
|
||||
|
||||
@ -309,7 +329,13 @@ namespace osmium {
|
||||
public:
|
||||
|
||||
explicit ChangesetDiscussionBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
ObjectBuilder<ChangesetDiscussion>(buffer, parent) {
|
||||
Builder(buffer, parent, sizeof(ChangesetDiscussion)) {
|
||||
new (&item()) ChangesetDiscussion();
|
||||
}
|
||||
|
||||
explicit ChangesetDiscussionBuilder(Builder& parent) :
|
||||
Builder(parent.buffer(), &parent, sizeof(ChangesetDiscussion)) {
|
||||
new (&item()) ChangesetDiscussion();
|
||||
}
|
||||
|
||||
~ChangesetDiscussionBuilder() {
|
||||
@ -339,19 +365,101 @@ namespace osmium {
|
||||
|
||||
}; // class ChangesetDiscussionBuilder
|
||||
|
||||
template <typename T>
|
||||
class OSMObjectBuilder : public ObjectBuilder<T> {
|
||||
#define OSMIUM_FORWARD(setter) \
|
||||
template <typename... TArgs> \
|
||||
type& setter(TArgs&&... args) { \
|
||||
object().setter(std::forward<TArgs>(args)...); \
|
||||
return static_cast<type&>(*this); \
|
||||
}
|
||||
|
||||
template <typename TDerived, typename T>
|
||||
class OSMObjectBuilder : public Builder {
|
||||
|
||||
using type = TDerived;
|
||||
|
||||
constexpr static const size_t min_size_for_user = osmium::memory::padded_length(sizeof(string_size_type) + 1);
|
||||
|
||||
public:
|
||||
|
||||
explicit OSMObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
ObjectBuilder<T>(buffer, parent) {
|
||||
static_cast<Builder*>(this)->reserve_space_for<string_size_type>();
|
||||
static_cast<Builder*>(this)->add_size(sizeof(string_size_type));
|
||||
Builder(buffer, parent, sizeof(T) + min_size_for_user) {
|
||||
new (&item()) T();
|
||||
add_size(min_size_for_user);
|
||||
std::fill_n(object().data() + sizeof(T), min_size_for_user, 0);
|
||||
object().set_user_size(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the object buing built.
|
||||
*
|
||||
* Note that this reference will be invalidated by every action
|
||||
* on the builder that might make the buffer grow. This includes
|
||||
* calls to set_user() and any time a new sub-builder is created.
|
||||
*/
|
||||
T& object() noexcept {
|
||||
return static_cast<T&>(item());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user name.
|
||||
*
|
||||
* @param user Pointer to user name.
|
||||
* @param length Length of user name (without \0 termination).
|
||||
*/
|
||||
TDerived& set_user(const char* user, const string_size_type length) {
|
||||
const auto size_of_object = sizeof(T) + sizeof(string_size_type);
|
||||
assert(object().user_size() == 1 && (size() <= size_of_object + osmium::memory::padded_length(1))
|
||||
&& "set_user() must be called at most once and before any sub-builders");
|
||||
const auto available_space = min_size_for_user - sizeof(string_size_type) - 1;
|
||||
if (length > available_space) {
|
||||
const auto space_needed = osmium::memory::padded_length(length - available_space);
|
||||
reserve_space(space_needed);
|
||||
add_size(static_cast<uint32_t>(space_needed));
|
||||
}
|
||||
std::copy_n(user, length, object().data() + size_of_object);
|
||||
std::fill_n(object().data() + size_of_object + length, osmium::memory::padded_length(length + 1) - length, 0);
|
||||
object().set_user_size(length + 1);
|
||||
|
||||
return static_cast<TDerived&>(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user name.
|
||||
*
|
||||
* @param user Pointer to \0-terminated user name.
|
||||
*/
|
||||
TDerived& set_user(const char* user) {
|
||||
return set_user(user, static_cast_with_assert<string_size_type>(std::strlen(user)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user name.
|
||||
*
|
||||
* @param user User name.
|
||||
*/
|
||||
TDerived& set_user(const std::string& user) {
|
||||
return set_user(user.data(), static_cast_with_assert<string_size_type>(user.size()));
|
||||
}
|
||||
|
||||
/// @deprecated Use set_user(...) instead.
|
||||
template <typename... TArgs>
|
||||
OSMIUM_DEPRECATED void add_user(TArgs&&... args) {
|
||||
set_user(std::forward<TArgs>(args)...);
|
||||
}
|
||||
|
||||
OSMIUM_FORWARD(set_id)
|
||||
OSMIUM_FORWARD(set_visible)
|
||||
OSMIUM_FORWARD(set_deleted)
|
||||
OSMIUM_FORWARD(set_version)
|
||||
OSMIUM_FORWARD(set_changeset)
|
||||
OSMIUM_FORWARD(set_uid)
|
||||
OSMIUM_FORWARD(set_uid_from_signed)
|
||||
OSMIUM_FORWARD(set_timestamp)
|
||||
OSMIUM_FORWARD(set_attribute)
|
||||
OSMIUM_FORWARD(set_removed)
|
||||
|
||||
void add_tags(const std::initializer_list<std::pair<const char*, const char*>>& tags) {
|
||||
osmium::builder::TagListBuilder tl_builder(static_cast<Builder*>(this)->buffer(), this);
|
||||
osmium::builder::TagListBuilder tl_builder{buffer(), this};
|
||||
for (const auto& p : tags) {
|
||||
tl_builder.add_tag(p.first, p.second);
|
||||
}
|
||||
@ -359,19 +467,40 @@ namespace osmium {
|
||||
|
||||
}; // class OSMObjectBuilder
|
||||
|
||||
using NodeBuilder = OSMObjectBuilder<osmium::Node>;
|
||||
using RelationBuilder = OSMObjectBuilder<osmium::Relation>;
|
||||
class NodeBuilder : public OSMObjectBuilder<NodeBuilder, Node> {
|
||||
|
||||
class WayBuilder : public OSMObjectBuilder<osmium::Way> {
|
||||
using type = NodeBuilder;
|
||||
|
||||
public:
|
||||
|
||||
explicit NodeBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
OSMObjectBuilder<NodeBuilder, Node>(buffer, parent) {
|
||||
}
|
||||
|
||||
explicit NodeBuilder(Builder& parent) :
|
||||
OSMObjectBuilder<NodeBuilder, Node>(parent.buffer(), &parent) {
|
||||
}
|
||||
|
||||
OSMIUM_FORWARD(set_location)
|
||||
|
||||
}; // class NodeBuilder
|
||||
|
||||
class WayBuilder : public OSMObjectBuilder<WayBuilder, Way> {
|
||||
|
||||
using type = WayBuilder;
|
||||
|
||||
public:
|
||||
|
||||
explicit WayBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
OSMObjectBuilder<osmium::Way>(buffer, parent) {
|
||||
OSMObjectBuilder<WayBuilder, Way>(buffer, parent) {
|
||||
}
|
||||
|
||||
explicit WayBuilder(Builder& parent) :
|
||||
OSMObjectBuilder<WayBuilder, Way>(parent.buffer(), &parent) {
|
||||
}
|
||||
|
||||
void add_node_refs(const std::initializer_list<osmium::NodeRef>& nodes) {
|
||||
osmium::builder::WayNodeListBuilder builder(buffer(), this);
|
||||
osmium::builder::WayNodeListBuilder builder{buffer(), this};
|
||||
for (const auto& node_ref : nodes) {
|
||||
builder.add_node_ref(node_ref);
|
||||
}
|
||||
@ -379,32 +508,147 @@ namespace osmium {
|
||||
|
||||
}; // class WayBuilder
|
||||
|
||||
class AreaBuilder : public OSMObjectBuilder<osmium::Area> {
|
||||
class RelationBuilder : public OSMObjectBuilder<RelationBuilder, Relation> {
|
||||
|
||||
using type = RelationBuilder;
|
||||
|
||||
public:
|
||||
|
||||
explicit RelationBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
OSMObjectBuilder<RelationBuilder, Relation>(buffer, parent) {
|
||||
}
|
||||
|
||||
explicit RelationBuilder(Builder& parent) :
|
||||
OSMObjectBuilder<RelationBuilder, Relation>(parent.buffer(), &parent) {
|
||||
}
|
||||
|
||||
}; // class RelationBuilder
|
||||
|
||||
class AreaBuilder : public OSMObjectBuilder<AreaBuilder, Area> {
|
||||
|
||||
using type = AreaBuilder;
|
||||
|
||||
public:
|
||||
|
||||
explicit AreaBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
OSMObjectBuilder<osmium::Area>(buffer, parent) {
|
||||
OSMObjectBuilder<AreaBuilder, Area>(buffer, parent) {
|
||||
}
|
||||
|
||||
explicit AreaBuilder(Builder& parent) :
|
||||
OSMObjectBuilder<AreaBuilder, Area>(parent.buffer(), &parent) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize area attributes from the attributes of the given object.
|
||||
*/
|
||||
void initialize_from_object(const osmium::OSMObject& source) {
|
||||
osmium::Area& area = object();
|
||||
area.set_id(osmium::object_id_to_area_id(source.id(), source.type()));
|
||||
area.set_version(source.version());
|
||||
area.set_changeset(source.changeset());
|
||||
area.set_timestamp(source.timestamp());
|
||||
area.set_visible(source.visible());
|
||||
area.set_uid(source.uid());
|
||||
|
||||
add_user(source.user());
|
||||
set_id(osmium::object_id_to_area_id(source.id(), source.type()));
|
||||
set_version(source.version());
|
||||
set_changeset(source.changeset());
|
||||
set_timestamp(source.timestamp());
|
||||
set_visible(source.visible());
|
||||
set_uid(source.uid());
|
||||
set_user(source.user());
|
||||
}
|
||||
|
||||
}; // class AreaBuilder
|
||||
|
||||
using ChangesetBuilder = ObjectBuilder<osmium::Changeset>;
|
||||
class ChangesetBuilder : public Builder {
|
||||
|
||||
using type = ChangesetBuilder;
|
||||
|
||||
constexpr static const size_t min_size_for_user = osmium::memory::padded_length(1);
|
||||
|
||||
public:
|
||||
|
||||
explicit ChangesetBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
Builder(buffer, parent, sizeof(Changeset) + min_size_for_user) {
|
||||
new (&item()) Changeset();
|
||||
add_size(min_size_for_user);
|
||||
std::fill_n(object().data() + sizeof(Changeset), min_size_for_user, 0);
|
||||
object().set_user_size(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the changeset buing built.
|
||||
*
|
||||
* Note that this reference will be invalidated by every action
|
||||
* on the builder that might make the buffer grow. This includes
|
||||
* calls to set_user() and any time a new sub-builder is created.
|
||||
*/
|
||||
Changeset& object() noexcept {
|
||||
return static_cast<Changeset&>(item());
|
||||
}
|
||||
|
||||
OSMIUM_FORWARD(set_id)
|
||||
OSMIUM_FORWARD(set_uid)
|
||||
OSMIUM_FORWARD(set_uid_from_signed)
|
||||
OSMIUM_FORWARD(set_created_at)
|
||||
OSMIUM_FORWARD(set_closed_at)
|
||||
OSMIUM_FORWARD(set_num_changes)
|
||||
OSMIUM_FORWARD(set_num_comments)
|
||||
OSMIUM_FORWARD(set_attribute)
|
||||
OSMIUM_FORWARD(set_removed)
|
||||
|
||||
// @deprecated Use set_bounds() instead.
|
||||
OSMIUM_DEPRECATED osmium::Box& bounds() noexcept {
|
||||
return object().bounds();
|
||||
}
|
||||
|
||||
ChangesetBuilder& set_bounds(const osmium::Box& box) noexcept {
|
||||
object().bounds() = box;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user name.
|
||||
*
|
||||
* @param user Pointer to user name.
|
||||
* @param length Length of user name (without \0 termination).
|
||||
*/
|
||||
ChangesetBuilder& set_user(const char* user, const string_size_type length) {
|
||||
assert(object().user_size() == 1 && (size() <= sizeof(Changeset) + osmium::memory::padded_length(1))
|
||||
&& "set_user() must be called at most once and before any sub-builders");
|
||||
const auto available_space = min_size_for_user - 1;
|
||||
if (length > available_space) {
|
||||
const auto space_needed = osmium::memory::padded_length(length - available_space);
|
||||
reserve_space(space_needed);
|
||||
add_size(static_cast<uint32_t>(space_needed));
|
||||
}
|
||||
std::copy_n(user, length, object().data() + sizeof(Changeset));
|
||||
std::fill_n(object().data() + sizeof(Changeset) + length, osmium::memory::padded_length(length + 1) - length, 0);
|
||||
object().set_user_size(length + 1);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user name.
|
||||
*
|
||||
* @param user Pointer to \0-terminated user name.
|
||||
*/
|
||||
ChangesetBuilder& set_user(const char* user) {
|
||||
return set_user(user, static_cast_with_assert<string_size_type>(std::strlen(user)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user name.
|
||||
*
|
||||
* @param user User name.
|
||||
*/
|
||||
ChangesetBuilder& set_user(const std::string& user) {
|
||||
return set_user(user.data(), static_cast_with_assert<string_size_type>(user.size()));
|
||||
}
|
||||
|
||||
/// @deprecated Use set_user(...) instead.
|
||||
template <typename... TArgs>
|
||||
OSMIUM_DEPRECATED void add_user(TArgs&&... args) {
|
||||
set_user(std::forward<TArgs>(args)...);
|
||||
}
|
||||
|
||||
}; // class ChangesetBuilder
|
||||
|
||||
#undef OSMIUM_FORWARD
|
||||
|
||||
} // namespace builder
|
||||
|
||||
|
@ -95,7 +95,7 @@ namespace osmium {
|
||||
return m_message.c_str();
|
||||
}
|
||||
|
||||
}; // struct geometry_error
|
||||
}; // class geometry_error
|
||||
|
||||
/**
|
||||
* @brief Everything related to geometry handling.
|
||||
|
@ -33,12 +33,22 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <geos/version.h>
|
||||
#if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && (GEOS_VERSION_MAJOR < 3 || (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR <= 5))
|
||||
|
||||
#define OSMIUM_WITH_GEOS
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* This file contains code for conversion of OSM geometries into GDAL
|
||||
* This file contains code for conversion of OSM geometries into GEOS
|
||||
* geometries.
|
||||
*
|
||||
* Note that everything in this file is deprecated and only works up to
|
||||
* GEOS 3.5. It uses the GEOS C++ API which the GEOS project does not consider
|
||||
* to be a stable, external API. We probably should have used the GEOS C API
|
||||
* instead.
|
||||
*
|
||||
* @attention If you include this file, you'll need to link with `libgeos`.
|
||||
*/
|
||||
|
||||
@ -88,6 +98,7 @@ namespace osmium {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// @deprecated
|
||||
class GEOSFactoryImpl {
|
||||
|
||||
std::unique_ptr<const geos::geom::PrecisionModel> m_precision_model;
|
||||
@ -245,6 +256,7 @@ namespace osmium {
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// @deprecated
|
||||
template <typename TProjection = IdentityProjection>
|
||||
using GEOSFactory = GeometryFactory<osmium::geom::detail::GEOSFactoryImpl, TProjection>;
|
||||
|
||||
@ -254,4 +266,6 @@ namespace osmium {
|
||||
|
||||
#undef THROW
|
||||
|
||||
#endif
|
||||
|
||||
#endif // OSMIUM_GEOM_GEOS_HPP
|
||||
|
@ -43,11 +43,11 @@ namespace osmium {
|
||||
/**
|
||||
* Check whether one geometry contains another.
|
||||
*/
|
||||
inline bool contains(const osmium::Box& a, const osmium::Box& b) {
|
||||
return ((a.bottom_left().x() >= b.bottom_left().x()) &&
|
||||
(a.top_right().x() <= b.top_right().x()) &&
|
||||
(a.bottom_left().y() >= b.bottom_left().y()) &&
|
||||
(a.top_right().y() <= b.top_right().y()));
|
||||
inline bool contains(const osmium::Box& lhs, const osmium::Box& rhs) {
|
||||
return ((lhs.bottom_left().x() >= rhs.bottom_left().x()) &&
|
||||
(lhs.top_right().x() <= rhs.top_right().x()) &&
|
||||
(lhs.bottom_left().y() >= rhs.bottom_left().y()) &&
|
||||
(lhs.top_right().y() <= rhs.top_right().y()));
|
||||
}
|
||||
|
||||
} // namespace geom
|
||||
|
@ -118,23 +118,23 @@ namespace osmium {
|
||||
}; // struct Tile
|
||||
|
||||
/// Tiles are equal if all their attributes are equal.
|
||||
inline bool operator==(const Tile& a, const Tile& b) {
|
||||
return a.z == b.z && a.x == b.x && a.y == b.y;
|
||||
inline bool operator==(const Tile& lhs, const Tile& rhs) {
|
||||
return lhs.z == rhs.z && lhs.x == rhs.x && lhs.y == rhs.y;
|
||||
}
|
||||
|
||||
inline bool operator!=(const Tile& a, const Tile& b) {
|
||||
return ! (a == b);
|
||||
inline bool operator!=(const Tile& lhs, const Tile& rhs) {
|
||||
return ! (lhs == rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* This defines an arbitrary order on tiles for use in std::map etc.
|
||||
*/
|
||||
inline bool operator<(const Tile& a, const Tile& b) {
|
||||
if (a.z < b.z) return true;
|
||||
if (a.z > b.z) return false;
|
||||
if (a.x < b.x) return true;
|
||||
if (a.x > b.x) return false;
|
||||
return a.y < b.y;
|
||||
inline bool operator<(const Tile& lhs, const Tile& rhs) {
|
||||
if (lhs.z < rhs.z) return true;
|
||||
if (lhs.z > rhs.z) return false;
|
||||
if (lhs.x < rhs.x) return true;
|
||||
if (lhs.x > rhs.x) return false;
|
||||
return lhs.y < rhs.y;
|
||||
}
|
||||
|
||||
} // namespace geom
|
||||
|
@ -51,6 +51,9 @@ namespace osmium {
|
||||
namespace handler {
|
||||
|
||||
/**
|
||||
* Writes OSM data in the Osmium-internal serialized format to disk
|
||||
* keeping track of object offsets in the indexes given to the
|
||||
* constructor.
|
||||
*
|
||||
* Note: This handler will only work if either all object IDs are
|
||||
* positive or all object IDs are negative.
|
||||
@ -95,10 +98,8 @@ namespace osmium {
|
||||
m_offset += relation.byte_size();
|
||||
}
|
||||
|
||||
// XXX
|
||||
void operator()(const osmium::memory::Buffer& buffer) {
|
||||
osmium::io::detail::reliable_write(m_data_fd, buffer.data(), buffer.committed());
|
||||
|
||||
osmium::apply(buffer.begin(), buffer.end(), *this);
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
if (error && !m_ignore_errors) {
|
||||
throw osmium::not_found("location for one or more nodes not found in node location index");
|
||||
throw osmium::not_found{"location for one or more nodes not found in node location index"};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,8 @@ namespace osmium {
|
||||
namespace handler {
|
||||
|
||||
/**
|
||||
* This handler updates the indexes given to the constructor with
|
||||
* the relations between objects.
|
||||
*
|
||||
* Note: This handler will only work if either all object IDs are
|
||||
* positive or all object IDs are negative.
|
||||
|
@ -33,50 +33,15 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <osmium/index/id_set.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace index {
|
||||
|
||||
/**
|
||||
* Index storing one bit for each Id. The index automatically scales
|
||||
* with the Ids stored. Default value is 'false'. Storage uses
|
||||
* std::vector<bool> and needs a minimum of memory if the Ids are
|
||||
* dense.
|
||||
*/
|
||||
/// @deprecated Use osmium::index::IdSet instead.
|
||||
template <typename T>
|
||||
class BoolVector {
|
||||
|
||||
static_assert(std::is_unsigned<T>::value, "Needs unsigned type");
|
||||
|
||||
std::vector<bool> m_bits;
|
||||
|
||||
public:
|
||||
|
||||
BoolVector() = default;
|
||||
|
||||
BoolVector(const BoolVector&) = default;
|
||||
BoolVector(BoolVector&&) = default;
|
||||
BoolVector& operator=(const BoolVector&) = default;
|
||||
BoolVector& operator=(BoolVector&&) = default;
|
||||
|
||||
~BoolVector() noexcept = default;
|
||||
|
||||
void set(T id, bool value = true) {
|
||||
if (m_bits.size() <= id) {
|
||||
m_bits.resize(id + 1024 * 1024);
|
||||
}
|
||||
|
||||
m_bits[id] = value;
|
||||
}
|
||||
|
||||
bool get(T id) const {
|
||||
return id < m_bits.size() && m_bits[id];
|
||||
}
|
||||
|
||||
}; // class BoolVector
|
||||
using BoolVector = IdSet<T>;
|
||||
|
||||
} // namespace index
|
||||
|
||||
|
@ -85,11 +85,11 @@ namespace osmium {
|
||||
try {
|
||||
const TValue& value = m_vector.at(id);
|
||||
if (value == osmium::index::empty_value<TValue>()) {
|
||||
not_found_error(id);
|
||||
throw osmium::not_found{id};
|
||||
}
|
||||
return value;
|
||||
} catch (const std::out_of_range&) {
|
||||
not_found_error(id);
|
||||
throw osmium::not_found{id};
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,7 +180,7 @@ namespace osmium {
|
||||
return a.first < b.first;
|
||||
});
|
||||
if (result == m_vector.end() || result->first != id) {
|
||||
not_found_error(id);
|
||||
throw osmium::not_found{id};
|
||||
} else {
|
||||
return result->second;
|
||||
}
|
||||
|
431
include/osmium/index/id_set.hpp
Normal file
431
include/osmium/index/id_set.hpp
Normal file
@ -0,0 +1,431 @@
|
||||
#ifndef OSMIUM_INDEX_ID_SET_HPP
|
||||
#define OSMIUM_INDEX_ID_SET_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2016 Jochen Topf <jochen@topf.org> and others (see README).
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace index {
|
||||
|
||||
/**
|
||||
* Virtual parent class for IdSets. Use one of the implementations
|
||||
* provided.
|
||||
*/
|
||||
template <typename T>
|
||||
class IdSet {
|
||||
|
||||
public:
|
||||
|
||||
virtual ~IdSet() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given Id to the set.
|
||||
*/
|
||||
virtual void set(T id) = 0;
|
||||
|
||||
/**
|
||||
* Is the Id in the set?
|
||||
*/
|
||||
virtual bool get(T id) const noexcept = 0;
|
||||
|
||||
/**
|
||||
* Is the set empty?
|
||||
*/
|
||||
virtual bool empty() const = 0;
|
||||
|
||||
/**
|
||||
* Clear the set.
|
||||
*/
|
||||
virtual void clear() = 0;
|
||||
|
||||
}; // class IdSet
|
||||
|
||||
template <typename T>
|
||||
class IdSetDense;
|
||||
|
||||
/**
|
||||
* Const_iterator for iterating over a IdSetDense.
|
||||
*/
|
||||
template <typename T>
|
||||
class IdSetDenseIterator {
|
||||
|
||||
const IdSetDense<T>* m_set;
|
||||
T m_value;
|
||||
T m_last;
|
||||
|
||||
void next() noexcept {
|
||||
while (m_value != m_last && !m_set->get(m_value)) {
|
||||
const auto cid = IdSetDense<T>::chunk_id(m_value);
|
||||
assert(cid < m_set->m_data.size());
|
||||
if (!m_set->m_data[cid]) {
|
||||
m_value = (cid + 1) << (IdSetDense<T>::chunk_bits + 3);
|
||||
} else {
|
||||
const auto slot = m_set->m_data[cid][IdSetDense<T>::offset(m_value)];
|
||||
if (slot == 0) {
|
||||
m_value += 8;
|
||||
m_value &= ~0x7;
|
||||
} else {
|
||||
++m_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = T;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
IdSetDenseIterator(const IdSetDense<T>* set, T value, T last) noexcept :
|
||||
m_set(set),
|
||||
m_value(value),
|
||||
m_last(last) {
|
||||
next();
|
||||
}
|
||||
|
||||
IdSetDenseIterator<T>& operator++() noexcept {
|
||||
if (m_value != m_last) {
|
||||
++m_value;
|
||||
next();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
IdSetDenseIterator<T> operator++(int) noexcept {
|
||||
IdSetDenseIterator<T> tmp(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const IdSetDenseIterator<T>& rhs) const noexcept {
|
||||
return m_set == rhs.m_set && m_value == rhs.m_value;
|
||||
}
|
||||
|
||||
bool operator!=(const IdSetDenseIterator<T>& rhs) const noexcept {
|
||||
return ! (*this == rhs);
|
||||
}
|
||||
|
||||
T operator*() const noexcept {
|
||||
assert(m_value < m_last);
|
||||
return m_value;
|
||||
}
|
||||
|
||||
}; // class IdSetDenseIterator
|
||||
|
||||
/**
|
||||
* A set of Ids of the given type. Internal storage is in chunks of
|
||||
* arrays used as bit fields. Internally those chunks will be allocated
|
||||
* as needed, so it works relatively efficiently with both smaller
|
||||
* and larger Id sets. If it is not used, no memory is allocated at
|
||||
* all.
|
||||
*/
|
||||
template <typename T>
|
||||
class IdSetDense : public IdSet<T> {
|
||||
|
||||
static_assert(std::is_unsigned<T>::value, "Needs unsigned type");
|
||||
static_assert(sizeof(T) >= 4, "Needs at least 32bit type");
|
||||
|
||||
friend class IdSetDenseIterator<T>;
|
||||
|
||||
// This value is a compromise. For node Ids it could be bigger
|
||||
// which would mean less (but larger) memory allocations. For
|
||||
// relations Ids it could be smaller, because they would all fit
|
||||
// into a smaller allocation.
|
||||
constexpr static const size_t chunk_bits = 22;
|
||||
constexpr static const size_t chunk_size = 1 << chunk_bits;
|
||||
|
||||
std::vector<std::unique_ptr<unsigned char[]>> m_data;
|
||||
size_t m_size = 0;
|
||||
|
||||
static size_t chunk_id(T id) noexcept {
|
||||
return id >> (chunk_bits + 3);
|
||||
}
|
||||
|
||||
static size_t offset(T id) noexcept {
|
||||
return (id >> 3) & ((1 << chunk_bits) - 1);
|
||||
}
|
||||
|
||||
static unsigned char bitmask(T id) noexcept {
|
||||
return 1 << (id & 0x7);
|
||||
}
|
||||
|
||||
T last() const noexcept {
|
||||
return m_data.size() * chunk_size * 8;
|
||||
}
|
||||
|
||||
unsigned char& get_element(T id) {
|
||||
const auto cid = chunk_id(id);
|
||||
if (cid >= m_data.size()) {
|
||||
m_data.resize(cid + 1);
|
||||
}
|
||||
|
||||
auto& chunk = m_data[cid];
|
||||
if (!chunk) {
|
||||
chunk.reset(new unsigned char[chunk_size]);
|
||||
::memset(chunk.get(), 0, chunk_size);
|
||||
}
|
||||
|
||||
return chunk[offset(id)];
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
using const_iterator = IdSetDenseIterator<T>;
|
||||
|
||||
IdSetDense() = default;
|
||||
|
||||
/**
|
||||
* Add the Id to the set if it is not already in there.
|
||||
*
|
||||
* @param id The Id to set.
|
||||
* @returns true if the Id was added, false if it was already set.
|
||||
*/
|
||||
bool check_and_set(T id) {
|
||||
auto& element = get_element(id);
|
||||
|
||||
if ((element & bitmask(id)) == 0) {
|
||||
element |= bitmask(id);
|
||||
++m_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given Id to the set.
|
||||
*
|
||||
* @param id The Id to set.
|
||||
*/
|
||||
void set(T id) override final {
|
||||
(void)check_and_set(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given Id from the set.
|
||||
*
|
||||
* @param id The Id to set.
|
||||
*/
|
||||
void unset(T id) {
|
||||
auto& element = get_element(id);
|
||||
|
||||
if ((element & bitmask(id)) != 0) {
|
||||
element &= ~bitmask(id);
|
||||
--m_size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the Id in the set?
|
||||
*
|
||||
* @param id The Id to check.
|
||||
*/
|
||||
bool get(T id) const noexcept override final {
|
||||
if (chunk_id(id) >= m_data.size()) {
|
||||
return false;
|
||||
}
|
||||
auto* r = m_data[chunk_id(id)].get();
|
||||
if (!r) {
|
||||
return false;
|
||||
}
|
||||
return (r[offset(id)] & bitmask(id)) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the set empty?
|
||||
*/
|
||||
bool empty() const noexcept override final {
|
||||
return m_size == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of Ids stored in the set.
|
||||
*/
|
||||
size_t size() const noexcept {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the set.
|
||||
*/
|
||||
void clear() override final {
|
||||
m_data.clear();
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
IdSetDenseIterator<T> begin() const {
|
||||
return IdSetDenseIterator<T>{this, 0, last()};
|
||||
}
|
||||
|
||||
IdSetDenseIterator<T> end() const {
|
||||
return IdSetDenseIterator<T>{this, last(), last()};
|
||||
}
|
||||
|
||||
}; // class IdSetDense
|
||||
|
||||
/**
|
||||
* IdSet implementation for small Id sets. It writes the Ids
|
||||
* into a vector and uses linear search.
|
||||
*/
|
||||
template <typename T>
|
||||
class IdSetSmall : public IdSet<T> {
|
||||
|
||||
std::vector<T> m_data;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Add the given Id to the set.
|
||||
*/
|
||||
void set(T id) override final {
|
||||
m_data.push_back(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the Id in the set? Uses linear search.
|
||||
*
|
||||
* @param id The Id to check.
|
||||
*/
|
||||
bool get(T id) const noexcept override final {
|
||||
const auto it = std::find(m_data.cbegin(), m_data.cend(), id);
|
||||
return it != m_data.cend();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the Id in the set? Uses a binary search. For larger sets
|
||||
* this might be more efficient than calling get(), the set
|
||||
* must be sorted.
|
||||
*
|
||||
* @param id The Id to check.
|
||||
* @pre You must have called sort_unique() before calling this
|
||||
* or be sure there are no duplicates and the Ids have been
|
||||
* set in order.
|
||||
*/
|
||||
bool get_binary_search(T id) const noexcept {
|
||||
return std::binary_search(m_data.cbegin(), m_data.cend(), id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the set empty?
|
||||
*/
|
||||
bool empty() const noexcept override final {
|
||||
return m_data.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the set.
|
||||
*/
|
||||
void clear() override final {
|
||||
m_data.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the internal vector and remove any duplicates. Call this
|
||||
* before using size(), get_binary_search() or using an iterator.
|
||||
*/
|
||||
void sort_unique() {
|
||||
std::sort(m_data.begin(), m_data.end());
|
||||
const auto last = std::unique(m_data.begin(), m_data.end());
|
||||
m_data.erase(last, m_data.end());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of Ids stored in the set.
|
||||
*
|
||||
* @pre You must have called sort_unique() before calling this
|
||||
* or be sure there are no duplicates.
|
||||
*/
|
||||
size_t size() const noexcept {
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
/// Iterator type. There is no non-const iterator.
|
||||
using const_iterator = typename std::vector<T>::const_iterator;
|
||||
|
||||
const_iterator begin() const noexcept {
|
||||
return m_data.cbegin();
|
||||
}
|
||||
|
||||
const_iterator end() const noexcept {
|
||||
return m_data.cend();
|
||||
}
|
||||
|
||||
const_iterator cbegin() const noexcept {
|
||||
return m_data.cbegin();
|
||||
}
|
||||
|
||||
const_iterator cend() const noexcept {
|
||||
return m_data.cend();
|
||||
}
|
||||
|
||||
}; // class IdSetSmall
|
||||
|
||||
template <template<typename> class IdSetType>
|
||||
class NWRIdSet {
|
||||
|
||||
using id_set_type = IdSetType<osmium::unsigned_object_id_type>;
|
||||
|
||||
id_set_type m_sets[3];
|
||||
|
||||
public:
|
||||
|
||||
id_set_type& operator()(osmium::item_type type) noexcept {
|
||||
return m_sets[osmium::item_type_to_nwr_index(type)];
|
||||
}
|
||||
|
||||
const id_set_type& operator()(osmium::item_type type) const noexcept {
|
||||
return m_sets[osmium::item_type_to_nwr_index(type)];
|
||||
}
|
||||
|
||||
}; // class NWRIdSet
|
||||
|
||||
} // namespace index
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_INDEX_ID_SET_HPP
|
@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
@ -57,6 +56,10 @@ namespace osmium {
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
explicit not_found(uint64_t id) :
|
||||
std::runtime_error(std::string{"id "} + std::to_string(id) + " not found") {
|
||||
}
|
||||
|
||||
}; // struct not_found
|
||||
|
||||
/**
|
||||
@ -64,13 +67,6 @@ namespace osmium {
|
||||
*/
|
||||
namespace index {
|
||||
|
||||
template <typename TKey>
|
||||
OSMIUM_NORETURN void not_found_error(TKey key) {
|
||||
std::stringstream s;
|
||||
s << "id " << key << " not found";
|
||||
throw not_found(s.str());
|
||||
}
|
||||
|
||||
/**
|
||||
* Some of the index classes need an "empty" value that can
|
||||
* never appear in real data. This function must return this
|
||||
|
@ -48,6 +48,18 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
namespace osmium {
|
||||
|
||||
struct map_factory_error : public std::runtime_error {
|
||||
|
||||
explicit map_factory_error(const char* message) :
|
||||
std::runtime_error(message) {
|
||||
}
|
||||
|
||||
explicit map_factory_error(const std::string& message) :
|
||||
std::runtime_error(message) {
|
||||
}
|
||||
|
||||
}; // struct map_factory_error
|
||||
|
||||
namespace index {
|
||||
|
||||
/**
|
||||
@ -148,14 +160,14 @@ namespace osmium {
|
||||
// default implementation is empty
|
||||
}
|
||||
|
||||
// This function could usually be const in derived classes,
|
||||
// This function can usually be const in derived classes,
|
||||
// but not always. It could, for instance, sort internal data.
|
||||
// This is why it is not declared const here.
|
||||
virtual void dump_as_list(const int /*fd*/) {
|
||||
throw std::runtime_error("can't dump as list");
|
||||
}
|
||||
|
||||
// This function could usually be const in derived classes,
|
||||
// This function can usually be const in derived classes,
|
||||
// but not always. It could, for instance, sort internal data.
|
||||
// This is why it is not declared const here.
|
||||
virtual void dump_as_array(const int /*fd*/) {
|
||||
@ -188,13 +200,6 @@ namespace osmium {
|
||||
MapFactory(MapFactory&&) = delete;
|
||||
MapFactory& operator=(MapFactory&&) = delete;
|
||||
|
||||
OSMIUM_NORETURN static void error(const std::string& map_type_name) {
|
||||
std::string error_message {"Support for map type '"};
|
||||
error_message += map_type_name;
|
||||
error_message += "' not compiled into this binary.";
|
||||
throw std::runtime_error(error_message);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static MapFactory<id_type, value_type>& instance() {
|
||||
@ -226,7 +231,7 @@ namespace osmium {
|
||||
std::vector<std::string> config = osmium::split_string(config_string, ',');
|
||||
|
||||
if (config.empty()) {
|
||||
throw std::runtime_error("Need non-empty map type name.");
|
||||
throw map_factory_error{"Need non-empty map type name"};
|
||||
}
|
||||
|
||||
auto it = m_callbacks.find(config[0]);
|
||||
@ -234,7 +239,7 @@ namespace osmium {
|
||||
return std::unique_ptr<map_type>((it->second)(config));
|
||||
}
|
||||
|
||||
error(config[0]);
|
||||
throw map_factory_error{std::string{"Support for map type '"} + config[0] + "' not compiled into this binary"};
|
||||
}
|
||||
|
||||
}; // class MapFactory
|
||||
|
@ -63,7 +63,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
const TValue get(const TId id) const final {
|
||||
not_found_error(id);
|
||||
throw osmium::not_found{id};
|
||||
}
|
||||
|
||||
size_t size() const final {
|
||||
|
@ -79,7 +79,7 @@ namespace osmium {
|
||||
const TValue get(const TId id) const final {
|
||||
auto it = m_elements.find(id);
|
||||
if (it == m_elements.end()) {
|
||||
not_found_error(id);
|
||||
throw osmium::not_found{id};
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
@ -99,10 +99,10 @@ namespace osmium {
|
||||
|
||||
const TValue get(const TId id) const final {
|
||||
if (id >= m_elements.size()) {
|
||||
not_found_error(id);
|
||||
throw osmium::not_found{id};
|
||||
}
|
||||
if (m_elements[id] == osmium::index::empty_value<TValue>()) {
|
||||
not_found_error(id);
|
||||
throw osmium::not_found{id};
|
||||
}
|
||||
return m_elements[id];
|
||||
}
|
||||
|
@ -145,10 +145,11 @@ namespace osmium {
|
||||
|
||||
private:
|
||||
|
||||
using compression_map_type = std::map<const osmium::io::file_compression,
|
||||
std::tuple<create_compressor_type,
|
||||
create_decompressor_type_fd,
|
||||
create_decompressor_type_buffer>>;
|
||||
using callbacks_type = std::tuple<create_compressor_type,
|
||||
create_decompressor_type_fd,
|
||||
create_decompressor_type_buffer>;
|
||||
|
||||
using compression_map_type = std::map<const osmium::io::file_compression, callbacks_type>;
|
||||
|
||||
compression_map_type m_callbacks;
|
||||
|
||||
@ -160,11 +161,17 @@ namespace osmium {
|
||||
CompressionFactory(CompressionFactory&&) = delete;
|
||||
CompressionFactory& operator=(CompressionFactory&&) = delete;
|
||||
|
||||
OSMIUM_NORETURN void error(osmium::io::file_compression compression) {
|
||||
std::string error_message {"Support for compression '"};
|
||||
const callbacks_type& find_callbacks(osmium::io::file_compression compression) const {
|
||||
const auto it = m_callbacks.find(compression);
|
||||
|
||||
if (it != m_callbacks.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::string error_message{"Support for compression '"};
|
||||
error_message += as_string(compression);
|
||||
error_message += "' not compiled into this binary.";
|
||||
throw unsupported_file_format_error(error_message);
|
||||
error_message += "' not compiled into this binary";
|
||||
throw unsupported_file_format_error{error_message};
|
||||
}
|
||||
|
||||
public:
|
||||
@ -189,36 +196,21 @@ namespace osmium {
|
||||
}
|
||||
|
||||
template <typename... TArgs>
|
||||
std::unique_ptr<osmium::io::Compressor> create_compressor(osmium::io::file_compression compression, TArgs&&... args) {
|
||||
auto it = m_callbacks.find(compression);
|
||||
|
||||
if (it != m_callbacks.end()) {
|
||||
return std::unique_ptr<osmium::io::Compressor>(std::get<0>(it->second)(std::forward<TArgs>(args)...));
|
||||
}
|
||||
|
||||
error(compression);
|
||||
std::unique_ptr<osmium::io::Compressor> create_compressor(osmium::io::file_compression compression, TArgs&&... args) const {
|
||||
const auto callbacks = find_callbacks(compression);
|
||||
return std::unique_ptr<osmium::io::Compressor>(std::get<0>(callbacks)(std::forward<TArgs>(args)...));
|
||||
}
|
||||
|
||||
std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, int fd) {
|
||||
auto it = m_callbacks.find(compression);
|
||||
|
||||
if (it != m_callbacks.end()) {
|
||||
auto p = std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd));
|
||||
p->set_file_size(osmium::util::file_size(fd));
|
||||
return p;
|
||||
}
|
||||
|
||||
error(compression);
|
||||
std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, int fd) const {
|
||||
const auto callbacks = find_callbacks(compression);
|
||||
auto p = std::unique_ptr<osmium::io::Decompressor>(std::get<1>(callbacks)(fd));
|
||||
p->set_file_size(osmium::util::file_size(fd));
|
||||
return p;
|
||||
}
|
||||
|
||||
std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, const char* buffer, size_t size) {
|
||||
auto it = m_callbacks.find(compression);
|
||||
|
||||
if (it != m_callbacks.end()) {
|
||||
return std::unique_ptr<osmium::io::Decompressor>(std::get<2>(it->second)(buffer, size));
|
||||
}
|
||||
|
||||
error(compression);
|
||||
std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, const char* buffer, size_t size) const {
|
||||
const auto callbacks = find_callbacks(compression);
|
||||
return std::unique_ptr<osmium::io::Decompressor>(std::get<2>(callbacks)(buffer, size));
|
||||
}
|
||||
|
||||
}; // class CompressionFactory
|
||||
|
@ -55,12 +55,17 @@ namespace osmium {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct reader_options {
|
||||
osmium::osm_entity_bits::type read_which_entities = osm_entity_bits::all;
|
||||
osmium::io::read_meta read_metadata = read_meta::yes;
|
||||
};
|
||||
|
||||
class Parser {
|
||||
|
||||
future_buffer_queue_type& m_output_queue;
|
||||
std::promise<osmium::io::Header>& m_header_promise;
|
||||
queue_wrapper<std::string> m_input_queue;
|
||||
osmium::osm_entity_bits::type m_read_types;
|
||||
reader_options m_options;
|
||||
bool m_header_is_done;
|
||||
|
||||
protected:
|
||||
@ -73,11 +78,15 @@ namespace osmium {
|
||||
return m_input_queue.has_reached_end_of_data();
|
||||
}
|
||||
|
||||
osmium::osm_entity_bits::type read_types() const {
|
||||
return m_read_types;
|
||||
osmium::osm_entity_bits::type read_types() const noexcept {
|
||||
return m_options.read_which_entities;
|
||||
}
|
||||
|
||||
bool header_is_done() const {
|
||||
osmium::io::read_meta read_metadata() const noexcept {
|
||||
return m_options.read_metadata;
|
||||
}
|
||||
|
||||
bool header_is_done() const noexcept {
|
||||
return m_header_is_done;
|
||||
}
|
||||
|
||||
@ -111,11 +120,11 @@ namespace osmium {
|
||||
Parser(future_string_queue_type& input_queue,
|
||||
future_buffer_queue_type& output_queue,
|
||||
std::promise<osmium::io::Header>& header_promise,
|
||||
osmium::osm_entity_bits::type read_types) :
|
||||
osmium::io::detail::reader_options options) :
|
||||
m_output_queue(output_queue),
|
||||
m_header_promise(header_promise),
|
||||
m_input_queue(input_queue),
|
||||
m_read_types(read_types),
|
||||
m_options(options),
|
||||
m_header_is_done(false) {
|
||||
}
|
||||
|
||||
@ -157,7 +166,7 @@ namespace osmium {
|
||||
using create_parser_type = std::function<std::unique_ptr<Parser>(future_string_queue_type&,
|
||||
future_buffer_queue_type&,
|
||||
std::promise<osmium::io::Header>& header_promise,
|
||||
osmium::osm_entity_bits::type read_which_entities)>;
|
||||
osmium::io::detail::reader_options options)>;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -80,7 +80,7 @@ namespace osmium {
|
||||
struct o5m_error : public io_error {
|
||||
|
||||
explicit o5m_error(const char* what) :
|
||||
io_error(std::string("o5m format error: ") + what) {
|
||||
io_error(std::string{"o5m format error: "} + what) {
|
||||
}
|
||||
|
||||
}; // struct o5m_error
|
||||
@ -135,7 +135,7 @@ namespace osmium {
|
||||
|
||||
const char* get(uint64_t index) const {
|
||||
if (m_table.empty() || index == 0 || index > number_of_entries) {
|
||||
throw o5m_error("reference to non-existing string in table");
|
||||
throw o5m_error{"reference to non-existing string in table"};
|
||||
}
|
||||
auto entry = (current_entry + number_of_entries - index) % number_of_entries;
|
||||
return &m_table[entry * entry_size];
|
||||
@ -191,7 +191,7 @@ namespace osmium {
|
||||
static const unsigned char header_magic[] = { 0xff, 0xe0, 0x04, 'o', '5' };
|
||||
|
||||
if (std::strncmp(reinterpret_cast<const char*>(header_magic), m_data, sizeof(header_magic))) {
|
||||
throw o5m_error("wrong header magic");
|
||||
throw o5m_error{"wrong header magic"};
|
||||
}
|
||||
|
||||
m_data += sizeof(header_magic);
|
||||
@ -203,7 +203,7 @@ namespace osmium {
|
||||
} else if (*m_data == 'c') { // o5c change file
|
||||
m_header.set_has_multiple_object_versions(true);
|
||||
} else {
|
||||
throw o5m_error("wrong header magic");
|
||||
throw o5m_error{"wrong header magic"};
|
||||
}
|
||||
|
||||
m_data++;
|
||||
@ -211,7 +211,7 @@ namespace osmium {
|
||||
|
||||
void check_file_format_version() {
|
||||
if (*m_data != '2') {
|
||||
throw o5m_error("wrong header magic");
|
||||
throw o5m_error{"wrong header magic"};
|
||||
}
|
||||
|
||||
m_data++;
|
||||
@ -219,7 +219,7 @@ namespace osmium {
|
||||
|
||||
void decode_header() {
|
||||
if (! ensure_bytes_available(7)) { // overall length of header
|
||||
throw o5m_error("file too short (incomplete header info)");
|
||||
throw o5m_error{"file too short (incomplete header info)"};
|
||||
}
|
||||
|
||||
check_header_magic();
|
||||
@ -260,7 +260,7 @@ namespace osmium {
|
||||
if (**dataptr == 0x00) { // get inline string
|
||||
(*dataptr)++;
|
||||
if (*dataptr == end) {
|
||||
throw o5m_error("string format error");
|
||||
throw o5m_error{"string format error"};
|
||||
}
|
||||
return *dataptr;
|
||||
} else { // get from reference table
|
||||
@ -277,7 +277,7 @@ namespace osmium {
|
||||
auto uid = protozero::decode_varint(&data, end);
|
||||
|
||||
if (data == end) {
|
||||
throw o5m_error("missing user name");
|
||||
throw o5m_error{"missing user name"};
|
||||
}
|
||||
|
||||
const char* user = ++data;
|
||||
@ -290,7 +290,7 @@ namespace osmium {
|
||||
|
||||
while (*data++) {
|
||||
if (data == end) {
|
||||
throw o5m_error("no null byte in user name");
|
||||
throw o5m_error{"no null byte in user name"};
|
||||
}
|
||||
}
|
||||
|
||||
@ -302,24 +302,24 @@ namespace osmium {
|
||||
return std::make_pair(static_cast_with_assert<osmium::user_id_type>(uid), user);
|
||||
}
|
||||
|
||||
void decode_tags(osmium::builder::Builder* builder, const char** dataptr, const char* const end) {
|
||||
osmium::builder::TagListBuilder tl_builder(m_buffer, builder);
|
||||
void decode_tags(osmium::builder::Builder& parent, const char** dataptr, const char* const end) {
|
||||
osmium::builder::TagListBuilder builder{parent};
|
||||
|
||||
while(*dataptr != end) {
|
||||
while (*dataptr != end) {
|
||||
bool update_pointer = (**dataptr == 0x00);
|
||||
const char* data = decode_string(dataptr, end);
|
||||
const char* start = data;
|
||||
|
||||
while (*data++) {
|
||||
if (data == end) {
|
||||
throw o5m_error("no null byte in tag key");
|
||||
throw o5m_error{"no null byte in tag key"};
|
||||
}
|
||||
}
|
||||
|
||||
const char* value = data;
|
||||
while (*data++) {
|
||||
if (data == end) {
|
||||
throw o5m_error("no null byte in tag value");
|
||||
throw o5m_error{"no null byte in tag value"};
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,7 +328,7 @@ namespace osmium {
|
||||
*dataptr = data;
|
||||
}
|
||||
|
||||
tl_builder.add_tag(start, value);
|
||||
builder.add_tag(start, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,50 +357,46 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void decode_node(const char* data, const char* const end) {
|
||||
osmium::builder::NodeBuilder builder(m_buffer);
|
||||
osmium::Node& node = builder.object();
|
||||
osmium::builder::NodeBuilder builder{m_buffer};
|
||||
|
||||
node.set_id(m_delta_id.update(zvarint(&data, end)));
|
||||
builder.set_id(m_delta_id.update(zvarint(&data, end)));
|
||||
|
||||
builder.add_user(decode_info(node, &data, end));
|
||||
builder.set_user(decode_info(builder.object(), &data, end));
|
||||
|
||||
if (data == end) {
|
||||
// no location, object is deleted
|
||||
builder.object().set_visible(false);
|
||||
builder.object().set_location(osmium::Location{});
|
||||
builder.set_visible(false);
|
||||
builder.set_location(osmium::Location{});
|
||||
} else {
|
||||
auto lon = m_delta_lon.update(zvarint(&data, end));
|
||||
auto lat = m_delta_lat.update(zvarint(&data, end));
|
||||
builder.object().set_location(osmium::Location{lon, lat});
|
||||
builder.set_location(osmium::Location{lon, lat});
|
||||
|
||||
if (data != end) {
|
||||
decode_tags(&builder, &data, end);
|
||||
decode_tags(builder, &data, end);
|
||||
}
|
||||
}
|
||||
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
void decode_way(const char* data, const char* const end) {
|
||||
osmium::builder::WayBuilder builder(m_buffer);
|
||||
osmium::Way& way = builder.object();
|
||||
osmium::builder::WayBuilder builder{m_buffer};
|
||||
|
||||
way.set_id(m_delta_id.update(zvarint(&data, end)));
|
||||
builder.set_id(m_delta_id.update(zvarint(&data, end)));
|
||||
|
||||
builder.add_user(decode_info(way, &data, end));
|
||||
builder.set_user(decode_info(builder.object(), &data, end));
|
||||
|
||||
if (data == end) {
|
||||
// no reference section, object is deleted
|
||||
builder.object().set_visible(false);
|
||||
builder.set_visible(false);
|
||||
} else {
|
||||
auto reference_section_length = protozero::decode_varint(&data, end);
|
||||
if (reference_section_length > 0) {
|
||||
const char* const end_refs = data + reference_section_length;
|
||||
if (end_refs > end) {
|
||||
throw o5m_error("way nodes ref section too long");
|
||||
throw o5m_error{"way nodes ref section too long"};
|
||||
}
|
||||
|
||||
osmium::builder::WayNodeListBuilder wn_builder(m_buffer, &builder);
|
||||
osmium::builder::WayNodeListBuilder wn_builder{builder};
|
||||
|
||||
while (data < end_refs) {
|
||||
wn_builder.add_node_ref(m_delta_way_node_id.update(zvarint(&data, end)));
|
||||
@ -408,16 +404,14 @@ namespace osmium {
|
||||
}
|
||||
|
||||
if (data != end) {
|
||||
decode_tags(&builder, &data, end);
|
||||
decode_tags(builder, &data, end);
|
||||
}
|
||||
}
|
||||
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
osmium::item_type decode_member_type(char c) {
|
||||
if (c < '0' || c > '2') {
|
||||
throw o5m_error("unknown member type");
|
||||
throw o5m_error{"unknown member type"};
|
||||
}
|
||||
return osmium::nwr_index_to_item_type(c - '0');
|
||||
}
|
||||
@ -429,13 +423,13 @@ namespace osmium {
|
||||
|
||||
auto member_type = decode_member_type(*data++);
|
||||
if (data == end) {
|
||||
throw o5m_error("missing role");
|
||||
throw o5m_error{"missing role"};
|
||||
}
|
||||
const char* role = data;
|
||||
|
||||
while (*data++) {
|
||||
if (data == end) {
|
||||
throw o5m_error("no null byte in role");
|
||||
throw o5m_error{"no null byte in role"};
|
||||
}
|
||||
}
|
||||
|
||||
@ -448,30 +442,29 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void decode_relation(const char* data, const char* const end) {
|
||||
osmium::builder::RelationBuilder builder(m_buffer);
|
||||
osmium::Relation& relation = builder.object();
|
||||
osmium::builder::RelationBuilder builder{m_buffer};
|
||||
|
||||
relation.set_id(m_delta_id.update(zvarint(&data, end)));
|
||||
builder.set_id(m_delta_id.update(zvarint(&data, end)));
|
||||
|
||||
builder.add_user(decode_info(relation, &data, end));
|
||||
builder.set_user(decode_info(builder.object(), &data, end));
|
||||
|
||||
if (data == end) {
|
||||
// no reference section, object is deleted
|
||||
builder.object().set_visible(false);
|
||||
builder.set_visible(false);
|
||||
} else {
|
||||
auto reference_section_length = protozero::decode_varint(&data, end);
|
||||
if (reference_section_length > 0) {
|
||||
const char* const end_refs = data + reference_section_length;
|
||||
if (end_refs > end) {
|
||||
throw o5m_error("relation format error");
|
||||
throw o5m_error{"relation format error"};
|
||||
}
|
||||
|
||||
osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder);
|
||||
osmium::builder::RelationMemberListBuilder rml_builder{builder};
|
||||
|
||||
while (data < end_refs) {
|
||||
auto delta_id = zvarint(&data, end);
|
||||
if (data == end) {
|
||||
throw o5m_error("relation member format error");
|
||||
throw o5m_error{"relation member format error"};
|
||||
}
|
||||
auto type_role = decode_role(&data, end);
|
||||
auto i = osmium::item_type_to_nwr_index(type_role.first);
|
||||
@ -481,11 +474,9 @@ namespace osmium {
|
||||
}
|
||||
|
||||
if (data != end) {
|
||||
decode_tags(&builder, &data, end);
|
||||
decode_tags(builder, &data, end);
|
||||
}
|
||||
}
|
||||
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
void decode_bbox(const char* data, const char* const end) {
|
||||
@ -537,11 +528,11 @@ namespace osmium {
|
||||
try {
|
||||
length = protozero::decode_varint(&m_data, m_end);
|
||||
} catch (const protozero::end_of_buffer_exception&) {
|
||||
throw o5m_error("premature end of file");
|
||||
throw o5m_error{"premature end of file"};
|
||||
}
|
||||
|
||||
if (! ensure_bytes_available(length)) {
|
||||
throw o5m_error("premature end of file");
|
||||
throw o5m_error{"premature end of file"};
|
||||
}
|
||||
|
||||
switch (ds_type) {
|
||||
@ -549,18 +540,21 @@ namespace osmium {
|
||||
mark_header_as_done();
|
||||
if (read_types() & osmium::osm_entity_bits::node) {
|
||||
decode_node(m_data, m_data + length);
|
||||
m_buffer.commit();
|
||||
}
|
||||
break;
|
||||
case dataset_type::way:
|
||||
mark_header_as_done();
|
||||
if (read_types() & osmium::osm_entity_bits::way) {
|
||||
decode_way(m_data, m_data + length);
|
||||
m_buffer.commit();
|
||||
}
|
||||
break;
|
||||
case dataset_type::relation:
|
||||
mark_header_as_done();
|
||||
if (read_types() & osmium::osm_entity_bits::relation) {
|
||||
decode_relation(m_data, m_data + length);
|
||||
m_buffer.commit();
|
||||
}
|
||||
break;
|
||||
case dataset_type::bounding_box:
|
||||
@ -598,8 +592,8 @@ namespace osmium {
|
||||
O5mParser(future_string_queue_type& input_queue,
|
||||
future_buffer_queue_type& output_queue,
|
||||
std::promise<osmium::io::Header>& header_promise,
|
||||
osmium::osm_entity_bits::type read_types) :
|
||||
Parser(input_queue, output_queue, header_promise, read_types),
|
||||
osmium::io::detail::reader_options options) :
|
||||
Parser(input_queue, output_queue, header_promise, options),
|
||||
m_header(),
|
||||
m_buffer(buffer_size),
|
||||
m_input(),
|
||||
@ -625,8 +619,8 @@ namespace osmium {
|
||||
[](future_string_queue_type& input_queue,
|
||||
future_buffer_queue_type& output_queue,
|
||||
std::promise<osmium::io::Header>& header_promise,
|
||||
osmium::osm_entity_bits::type read_which_entities) {
|
||||
return std::unique_ptr<Parser>(new O5mParser(input_queue, output_queue, header_promise, read_which_entities));
|
||||
osmium::io::detail::reader_options options) {
|
||||
return std::unique_ptr<Parser>(new O5mParser(input_queue, output_queue, header_promise, options));
|
||||
});
|
||||
|
||||
// dummy function to silence the unused variable warning from above
|
||||
|
@ -82,8 +82,8 @@ namespace osmium {
|
||||
OPLParser(future_string_queue_type& input_queue,
|
||||
future_buffer_queue_type& output_queue,
|
||||
std::promise<osmium::io::Header>& header_promise,
|
||||
osmium::osm_entity_bits::type read_types) :
|
||||
Parser(input_queue, output_queue, header_promise, read_types) {
|
||||
osmium::io::detail::reader_options options) :
|
||||
Parser(input_queue, output_queue, header_promise, options) {
|
||||
set_header_value(osmium::io::Header{});
|
||||
}
|
||||
|
||||
@ -137,8 +137,8 @@ namespace osmium {
|
||||
[](future_string_queue_type& input_queue,
|
||||
future_buffer_queue_type& output_queue,
|
||||
std::promise<osmium::io::Header>& header_promise,
|
||||
osmium::osm_entity_bits::type read_which_entities) {
|
||||
return std::unique_ptr<Parser>(new OPLParser(input_queue, output_queue, header_promise, read_which_entities));
|
||||
osmium::io::detail::reader_options options) {
|
||||
return std::unique_ptr<Parser>(new OPLParser(input_queue, output_queue, header_promise, options));
|
||||
});
|
||||
|
||||
// dummy function to silence the unused variable warning from above
|
||||
|
@ -365,9 +365,8 @@ namespace osmium {
|
||||
|
||||
inline void opl_parse_node(const char** data, osmium::memory::Buffer& buffer) {
|
||||
osmium::builder::NodeBuilder builder{buffer};
|
||||
osmium::Node& node = builder.object();
|
||||
|
||||
node.set_id(opl_parse_id(data));
|
||||
builder.set_id(opl_parse_id(data));
|
||||
|
||||
const char* tags_begin = nullptr;
|
||||
|
||||
@ -382,19 +381,19 @@ namespace osmium {
|
||||
++(*data);
|
||||
switch (c) {
|
||||
case 'v':
|
||||
node.set_version(opl_parse_version(data));
|
||||
builder.set_version(opl_parse_version(data));
|
||||
break;
|
||||
case 'd':
|
||||
node.set_visible(opl_parse_visible(data));
|
||||
builder.set_visible(opl_parse_visible(data));
|
||||
break;
|
||||
case 'c':
|
||||
node.set_changeset(opl_parse_changeset_id(data));
|
||||
builder.set_changeset(opl_parse_changeset_id(data));
|
||||
break;
|
||||
case 't':
|
||||
node.set_timestamp(opl_parse_timestamp(data));
|
||||
builder.set_timestamp(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'i':
|
||||
node.set_uid(opl_parse_uid(data));
|
||||
builder.set_uid(opl_parse_uid(data));
|
||||
break;
|
||||
case 'u':
|
||||
opl_parse_string(data, user);
|
||||
@ -422,23 +421,20 @@ namespace osmium {
|
||||
}
|
||||
|
||||
if (location.valid()) {
|
||||
node.set_location(location);
|
||||
builder.set_location(location);
|
||||
}
|
||||
|
||||
builder.add_user(user);
|
||||
builder.set_user(user);
|
||||
|
||||
if (tags_begin) {
|
||||
opl_parse_tags(tags_begin, buffer, &builder);
|
||||
}
|
||||
|
||||
buffer.commit();
|
||||
}
|
||||
|
||||
inline void opl_parse_way(const char** data, osmium::memory::Buffer& buffer) {
|
||||
osmium::builder::WayBuilder builder{buffer};
|
||||
osmium::Way& way = builder.object();
|
||||
|
||||
way.set_id(opl_parse_id(data));
|
||||
builder.set_id(opl_parse_id(data));
|
||||
|
||||
const char* tags_begin = nullptr;
|
||||
|
||||
@ -455,19 +451,19 @@ namespace osmium {
|
||||
++(*data);
|
||||
switch (c) {
|
||||
case 'v':
|
||||
way.set_version(opl_parse_version(data));
|
||||
builder.set_version(opl_parse_version(data));
|
||||
break;
|
||||
case 'd':
|
||||
way.set_visible(opl_parse_visible(data));
|
||||
builder.set_visible(opl_parse_visible(data));
|
||||
break;
|
||||
case 'c':
|
||||
way.set_changeset(opl_parse_changeset_id(data));
|
||||
builder.set_changeset(opl_parse_changeset_id(data));
|
||||
break;
|
||||
case 't':
|
||||
way.set_timestamp(opl_parse_timestamp(data));
|
||||
builder.set_timestamp(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'i':
|
||||
way.set_uid(opl_parse_uid(data));
|
||||
builder.set_uid(opl_parse_uid(data));
|
||||
break;
|
||||
case 'u':
|
||||
opl_parse_string(data, user);
|
||||
@ -488,15 +484,13 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
builder.add_user(user);
|
||||
builder.set_user(user);
|
||||
|
||||
if (tags_begin) {
|
||||
opl_parse_tags(tags_begin, buffer, &builder);
|
||||
}
|
||||
|
||||
opl_parse_way_nodes(nodes_begin, nodes_end, buffer, &builder);
|
||||
|
||||
buffer.commit();
|
||||
}
|
||||
|
||||
inline void opl_parse_relation_members(const char* s, const char* e, osmium::memory::Buffer& buffer, osmium::builder::RelationBuilder* parent_builder = nullptr) {
|
||||
@ -536,9 +530,8 @@ namespace osmium {
|
||||
|
||||
inline void opl_parse_relation(const char** data, osmium::memory::Buffer& buffer) {
|
||||
osmium::builder::RelationBuilder builder{buffer};
|
||||
osmium::Relation& relation = builder.object();
|
||||
|
||||
relation.set_id(opl_parse_id(data));
|
||||
builder.set_id(opl_parse_id(data));
|
||||
|
||||
const char* tags_begin = nullptr;
|
||||
|
||||
@ -555,19 +548,19 @@ namespace osmium {
|
||||
++(*data);
|
||||
switch (c) {
|
||||
case 'v':
|
||||
relation.set_version(opl_parse_version(data));
|
||||
builder.set_version(opl_parse_version(data));
|
||||
break;
|
||||
case 'd':
|
||||
relation.set_visible(opl_parse_visible(data));
|
||||
builder.set_visible(opl_parse_visible(data));
|
||||
break;
|
||||
case 'c':
|
||||
relation.set_changeset(opl_parse_changeset_id(data));
|
||||
builder.set_changeset(opl_parse_changeset_id(data));
|
||||
break;
|
||||
case 't':
|
||||
relation.set_timestamp(opl_parse_timestamp(data));
|
||||
builder.set_timestamp(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'i':
|
||||
relation.set_uid(opl_parse_uid(data));
|
||||
builder.set_uid(opl_parse_uid(data));
|
||||
break;
|
||||
case 'u':
|
||||
opl_parse_string(data, user);
|
||||
@ -588,7 +581,7 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
builder.add_user(user);
|
||||
builder.set_user(user);
|
||||
|
||||
if (tags_begin) {
|
||||
opl_parse_tags(tags_begin, buffer, &builder);
|
||||
@ -597,15 +590,12 @@ namespace osmium {
|
||||
if (members_begin != members_end) {
|
||||
opl_parse_relation_members(members_begin, members_end, buffer, &builder);
|
||||
}
|
||||
|
||||
buffer.commit();
|
||||
}
|
||||
|
||||
inline void opl_parse_changeset(const char** data, osmium::memory::Buffer& buffer) {
|
||||
osmium::builder::ChangesetBuilder builder{buffer};
|
||||
osmium::Changeset& changeset = builder.object();
|
||||
|
||||
changeset.set_id(opl_parse_changeset_id(data));
|
||||
builder.set_id(opl_parse_changeset_id(data));
|
||||
|
||||
const char* tags_begin = nullptr;
|
||||
|
||||
@ -621,19 +611,19 @@ namespace osmium {
|
||||
++(*data);
|
||||
switch (c) {
|
||||
case 'k':
|
||||
changeset.set_num_changes(opl_parse_int<osmium::num_changes_type>(data));
|
||||
builder.set_num_changes(opl_parse_int<osmium::num_changes_type>(data));
|
||||
break;
|
||||
case 's':
|
||||
changeset.set_created_at(opl_parse_timestamp(data));
|
||||
builder.set_created_at(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'e':
|
||||
changeset.set_closed_at(opl_parse_timestamp(data));
|
||||
builder.set_closed_at(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'd':
|
||||
changeset.set_num_comments(opl_parse_int<osmium::num_comments_type>(data));
|
||||
builder.set_num_comments(opl_parse_int<osmium::num_comments_type>(data));
|
||||
break;
|
||||
case 'i':
|
||||
changeset.set_uid(opl_parse_uid(data));
|
||||
builder.set_uid(opl_parse_uid(data));
|
||||
break;
|
||||
case 'u':
|
||||
opl_parse_string(data, user);
|
||||
@ -672,17 +662,17 @@ namespace osmium {
|
||||
}
|
||||
|
||||
if (location1.valid() && location2.valid()) {
|
||||
changeset.bounds().extend(location1);
|
||||
changeset.bounds().extend(location2);
|
||||
osmium::Box box;
|
||||
box.extend(location1);
|
||||
box.extend(location2);
|
||||
builder.set_bounds(box);
|
||||
}
|
||||
|
||||
builder.add_user(user);
|
||||
builder.set_user(user);
|
||||
|
||||
if (tags_begin) {
|
||||
opl_parse_tags(tags_begin, buffer, &builder);
|
||||
}
|
||||
|
||||
buffer.commit();
|
||||
}
|
||||
|
||||
inline bool opl_parse_line(uint64_t line_count,
|
||||
@ -702,6 +692,7 @@ namespace osmium {
|
||||
if (read_types & osmium::osm_entity_bits::node) {
|
||||
++data;
|
||||
opl_parse_node(&data, buffer);
|
||||
buffer.commit();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@ -709,6 +700,7 @@ namespace osmium {
|
||||
if (read_types & osmium::osm_entity_bits::way) {
|
||||
++data;
|
||||
opl_parse_way(&data, buffer);
|
||||
buffer.commit();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@ -716,6 +708,7 @@ namespace osmium {
|
||||
if (read_types & osmium::osm_entity_bits::relation) {
|
||||
++data;
|
||||
opl_parse_relation(&data, buffer);
|
||||
buffer.commit();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@ -723,6 +716,7 @@ namespace osmium {
|
||||
if (read_types & osmium::osm_entity_bits::changeset) {
|
||||
++data;
|
||||
opl_parse_changeset(&data, buffer);
|
||||
buffer.commit();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
@ -50,6 +50,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/detail/protobuf_tags.hpp>
|
||||
#include <osmium/io/detail/zlib.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
@ -94,6 +95,8 @@ namespace osmium {
|
||||
|
||||
osmium::memory::Buffer m_buffer { initial_buffer_size };
|
||||
|
||||
osmium::io::read_meta m_read_metadata;
|
||||
|
||||
void decode_stringtable(const data_view& data) {
|
||||
if (!m_stringtable.empty()) {
|
||||
throw osmium::pbf_error("more than one stringtable in pbf file");
|
||||
@ -143,13 +146,19 @@ namespace osmium {
|
||||
case OSMFormat::PrimitiveGroup::repeated_Node_nodes:
|
||||
if (m_read_types & osmium::osm_entity_bits::node) {
|
||||
decode_node(pbf_primitive_group.get_view());
|
||||
m_buffer.commit();
|
||||
} else {
|
||||
pbf_primitive_group.skip();
|
||||
}
|
||||
break;
|
||||
case OSMFormat::PrimitiveGroup::optional_DenseNodes_dense:
|
||||
if (m_read_types & osmium::osm_entity_bits::node) {
|
||||
decode_dense_nodes(pbf_primitive_group.get_view());
|
||||
if (m_read_metadata == osmium::io::read_meta::yes) {
|
||||
decode_dense_nodes(pbf_primitive_group.get_view());
|
||||
} else {
|
||||
decode_dense_nodes_without_metadata(pbf_primitive_group.get_view());
|
||||
}
|
||||
m_buffer.commit();
|
||||
} else {
|
||||
pbf_primitive_group.skip();
|
||||
}
|
||||
@ -157,6 +166,7 @@ namespace osmium {
|
||||
case OSMFormat::PrimitiveGroup::repeated_Way_ways:
|
||||
if (m_read_types & osmium::osm_entity_bits::way) {
|
||||
decode_way(pbf_primitive_group.get_view());
|
||||
m_buffer.commit();
|
||||
} else {
|
||||
pbf_primitive_group.skip();
|
||||
}
|
||||
@ -164,6 +174,7 @@ namespace osmium {
|
||||
case OSMFormat::PrimitiveGroup::repeated_Relation_relations:
|
||||
if (m_read_types & osmium::osm_entity_bits::relation) {
|
||||
decode_relation(pbf_primitive_group.get_view());
|
||||
m_buffer.commit();
|
||||
} else {
|
||||
pbf_primitive_group.skip();
|
||||
}
|
||||
@ -221,9 +232,9 @@ namespace osmium {
|
||||
|
||||
using kv_type = protozero::iterator_range<protozero::pbf_reader::const_uint32_iterator>;
|
||||
|
||||
void build_tag_list(osmium::builder::Builder& builder, const kv_type& keys, const kv_type& vals) {
|
||||
void build_tag_list(osmium::builder::Builder& parent, const kv_type& keys, const kv_type& vals) {
|
||||
if (!keys.empty()) {
|
||||
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
|
||||
osmium::builder::TagListBuilder builder{parent};
|
||||
auto kit = keys.begin();
|
||||
auto vit = vals.begin();
|
||||
while (kit != keys.end()) {
|
||||
@ -233,7 +244,7 @@ namespace osmium {
|
||||
}
|
||||
const auto& k = m_stringtable.at(*kit++);
|
||||
const auto& v = m_stringtable.at(*vit++);
|
||||
tl_builder.add_tag(k.first, k.second, v.first, v.second);
|
||||
builder.add_tag(k.first, k.second, v.first, v.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -243,7 +254,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void decode_node(const data_view& data) {
|
||||
osmium::builder::NodeBuilder builder(m_buffer);
|
||||
osmium::builder::NodeBuilder builder{m_buffer};
|
||||
osmium::Node& node = builder.object();
|
||||
|
||||
kv_type keys;
|
||||
@ -266,7 +277,11 @@ namespace osmium {
|
||||
vals = pbf_node.get_packed_uint32();
|
||||
break;
|
||||
case OSMFormat::Node::optional_Info_info:
|
||||
user = decode_info(pbf_node.get_view(), builder.object());
|
||||
if (m_read_metadata == osmium::io::read_meta::yes) {
|
||||
user = decode_info(pbf_node.get_view(), builder.object());
|
||||
} else {
|
||||
pbf_node.skip();
|
||||
}
|
||||
break;
|
||||
case OSMFormat::Node::required_sint64_lat:
|
||||
lat = pbf_node.get_sint64();
|
||||
@ -290,15 +305,13 @@ namespace osmium {
|
||||
));
|
||||
}
|
||||
|
||||
builder.add_user(user.first, user.second);
|
||||
builder.set_user(user.first, user.second);
|
||||
|
||||
build_tag_list(builder, keys, vals);
|
||||
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
void decode_way(const data_view& data) {
|
||||
osmium::builder::WayBuilder builder(m_buffer);
|
||||
osmium::builder::WayBuilder builder{m_buffer};
|
||||
|
||||
kv_type keys;
|
||||
kv_type vals;
|
||||
@ -321,7 +334,11 @@ namespace osmium {
|
||||
vals = pbf_way.get_packed_uint32();
|
||||
break;
|
||||
case OSMFormat::Way::optional_Info_info:
|
||||
user = decode_info(pbf_way.get_view(), builder.object());
|
||||
if (m_read_metadata == osmium::io::read_meta::yes) {
|
||||
user = decode_info(pbf_way.get_view(), builder.object());
|
||||
} else {
|
||||
pbf_way.skip();
|
||||
}
|
||||
break;
|
||||
case OSMFormat::Way::packed_sint64_refs:
|
||||
refs = pbf_way.get_packed_sint64();
|
||||
@ -337,10 +354,10 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
builder.add_user(user.first, user.second);
|
||||
builder.set_user(user.first, user.second);
|
||||
|
||||
if (!refs.empty()) {
|
||||
osmium::builder::WayNodeListBuilder wnl_builder(m_buffer, &builder);
|
||||
osmium::builder::WayNodeListBuilder wnl_builder{builder};
|
||||
osmium::util::DeltaDecode<int64_t> ref;
|
||||
if (lats.empty()) {
|
||||
for (const auto& ref_value : refs) {
|
||||
@ -363,12 +380,10 @@ namespace osmium {
|
||||
}
|
||||
|
||||
build_tag_list(builder, keys, vals);
|
||||
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
void decode_relation(const data_view& data) {
|
||||
osmium::builder::RelationBuilder builder(m_buffer);
|
||||
osmium::builder::RelationBuilder builder{m_buffer};
|
||||
|
||||
kv_type keys;
|
||||
kv_type vals;
|
||||
@ -391,7 +406,11 @@ namespace osmium {
|
||||
vals = pbf_relation.get_packed_uint32();
|
||||
break;
|
||||
case OSMFormat::Relation::optional_Info_info:
|
||||
user = decode_info(pbf_relation.get_view(), builder.object());
|
||||
if (m_read_metadata == osmium::io::read_meta::yes) {
|
||||
user = decode_info(pbf_relation.get_view(), builder.object());
|
||||
} else {
|
||||
pbf_relation.skip();
|
||||
}
|
||||
break;
|
||||
case OSMFormat::Relation::packed_int32_roles_sid:
|
||||
roles = pbf_relation.get_packed_int32();
|
||||
@ -407,10 +426,10 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
builder.add_user(user.first, user.second);
|
||||
builder.set_user(user.first, user.second);
|
||||
|
||||
if (!refs.empty()) {
|
||||
osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder);
|
||||
osmium::builder::RelationMemberListBuilder rml_builder{builder};
|
||||
osmium::util::DeltaDecode<int64_t> ref;
|
||||
while (!roles.empty() && !refs.empty() && !types.empty()) {
|
||||
const auto& r = m_stringtable.at(roles.front());
|
||||
@ -431,8 +450,84 @@ namespace osmium {
|
||||
}
|
||||
|
||||
build_tag_list(builder, keys, vals);
|
||||
}
|
||||
|
||||
void build_tag_list_from_dense_nodes(osmium::builder::NodeBuilder& builder, protozero::pbf_reader::const_int32_iterator& it, protozero::pbf_reader::const_int32_iterator last) {
|
||||
osmium::builder::TagListBuilder tl_builder{builder};
|
||||
while (it != last && *it != 0) {
|
||||
const auto& k = m_stringtable.at(*it++);
|
||||
if (it == last) {
|
||||
throw osmium::pbf_error("PBF format error"); // this is against the spec, keys/vals must come in pairs
|
||||
}
|
||||
const auto& v = m_stringtable.at(*it++);
|
||||
tl_builder.add_tag(k.first, k.second, v.first, v.second);
|
||||
}
|
||||
|
||||
if (it != last) {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void decode_dense_nodes_without_metadata(const data_view& data) {
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> ids;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lats;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lons;
|
||||
|
||||
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> tags;
|
||||
|
||||
protozero::pbf_message<OSMFormat::DenseNodes> pbf_dense_nodes(data);
|
||||
while (pbf_dense_nodes.next()) {
|
||||
switch (pbf_dense_nodes.tag()) {
|
||||
case OSMFormat::DenseNodes::packed_sint64_id:
|
||||
ids = pbf_dense_nodes.get_packed_sint64();
|
||||
break;
|
||||
case OSMFormat::DenseNodes::packed_sint64_lat:
|
||||
lats = pbf_dense_nodes.get_packed_sint64();
|
||||
break;
|
||||
case OSMFormat::DenseNodes::packed_sint64_lon:
|
||||
lons = pbf_dense_nodes.get_packed_sint64();
|
||||
break;
|
||||
case OSMFormat::DenseNodes::packed_int32_keys_vals:
|
||||
tags = pbf_dense_nodes.get_packed_int32();
|
||||
break;
|
||||
default:
|
||||
pbf_dense_nodes.skip();
|
||||
}
|
||||
}
|
||||
|
||||
osmium::util::DeltaDecode<int64_t> dense_id;
|
||||
osmium::util::DeltaDecode<int64_t> dense_latitude;
|
||||
osmium::util::DeltaDecode<int64_t> dense_longitude;
|
||||
|
||||
auto tag_it = tags.begin();
|
||||
|
||||
while (!ids.empty()) {
|
||||
if (lons.empty() ||
|
||||
lats.empty()) {
|
||||
// this is against the spec, must have same number of elements
|
||||
throw osmium::pbf_error("PBF format error");
|
||||
}
|
||||
|
||||
osmium::builder::NodeBuilder builder{m_buffer};
|
||||
osmium::Node& node = builder.object();
|
||||
|
||||
node.set_id(dense_id.update(ids.front()));
|
||||
ids.drop_front();
|
||||
|
||||
const auto lon = dense_longitude.update(lons.front());
|
||||
lons.drop_front();
|
||||
const auto lat = dense_latitude.update(lats.front());
|
||||
lats.drop_front();
|
||||
builder.object().set_location(osmium::Location(
|
||||
convert_pbf_coordinate(lon),
|
||||
convert_pbf_coordinate(lat)
|
||||
));
|
||||
|
||||
if (tag_it != tags.end()) {
|
||||
build_tag_list_from_dense_nodes(builder, tag_it, tags.end());
|
||||
}
|
||||
}
|
||||
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
void decode_dense_nodes(const data_view& data) {
|
||||
@ -522,7 +617,7 @@ namespace osmium {
|
||||
|
||||
bool visible = true;
|
||||
|
||||
osmium::builder::NodeBuilder builder(m_buffer);
|
||||
osmium::builder::NodeBuilder builder{m_buffer};
|
||||
osmium::Node& node = builder.object();
|
||||
|
||||
node.set_id(dense_id.update(ids.front()));
|
||||
@ -569,9 +664,7 @@ namespace osmium {
|
||||
|
||||
const auto& u = m_stringtable.at(dense_user_sid.update(user_sids.front()));
|
||||
user_sids.drop_front();
|
||||
builder.add_user(u.first, u.second);
|
||||
} else {
|
||||
builder.add_user("");
|
||||
builder.set_user(u.first, u.second);
|
||||
}
|
||||
|
||||
// even if the node isn't visible, there's still a record
|
||||
@ -588,31 +681,18 @@ namespace osmium {
|
||||
}
|
||||
|
||||
if (tag_it != tags.end()) {
|
||||
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
|
||||
while (tag_it != tags.end() && *tag_it != 0) {
|
||||
const auto& k = m_stringtable.at(*tag_it++);
|
||||
if (tag_it == tags.end()) {
|
||||
throw osmium::pbf_error("PBF format error"); // this is against the spec, keys/vals must come in pairs
|
||||
}
|
||||
const auto& v = m_stringtable.at(*tag_it++);
|
||||
tl_builder.add_tag(k.first, k.second, v.first, v.second);
|
||||
}
|
||||
|
||||
if (tag_it != tags.end()) {
|
||||
++tag_it;
|
||||
}
|
||||
build_tag_list_from_dense_nodes(builder, tag_it, tags.end());
|
||||
}
|
||||
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
PBFPrimitiveBlockDecoder(const data_view& data, osmium::osm_entity_bits::type read_types) :
|
||||
PBFPrimitiveBlockDecoder(const data_view& data, osmium::osm_entity_bits::type read_types, osmium::io::read_meta read_metadata) :
|
||||
m_data(data),
|
||||
m_read_types(read_types) {
|
||||
m_read_types(read_types),
|
||||
m_read_metadata(read_metadata) {
|
||||
}
|
||||
|
||||
PBFPrimitiveBlockDecoder(const PBFPrimitiveBlockDecoder&) = delete;
|
||||
@ -789,12 +869,14 @@ namespace osmium {
|
||||
|
||||
std::shared_ptr<std::string> m_input_buffer;
|
||||
osmium::osm_entity_bits::type m_read_types;
|
||||
osmium::io::read_meta m_read_metadata;
|
||||
|
||||
public:
|
||||
|
||||
PBFDataBlobDecoder(std::string&& input_buffer, osmium::osm_entity_bits::type read_types) :
|
||||
PBFDataBlobDecoder(std::string&& input_buffer, osmium::osm_entity_bits::type read_types, osmium::io::read_meta read_metadata) :
|
||||
m_input_buffer(std::make_shared<std::string>(std::move(input_buffer))),
|
||||
m_read_types(read_types) {
|
||||
m_read_types(read_types),
|
||||
m_read_metadata(read_metadata) {
|
||||
}
|
||||
|
||||
PBFDataBlobDecoder(const PBFDataBlobDecoder&) = default;
|
||||
@ -807,7 +889,7 @@ namespace osmium {
|
||||
|
||||
osmium::memory::Buffer operator()() {
|
||||
std::string output;
|
||||
PBFPrimitiveBlockDecoder decoder(decode_blob(*m_input_buffer, output), m_read_types);
|
||||
PBFPrimitiveBlockDecoder decoder(decode_blob(*m_input_buffer, output), m_read_types, m_read_metadata);
|
||||
return decoder();
|
||||
}
|
||||
|
||||
|
@ -180,7 +180,7 @@ namespace osmium {
|
||||
while (const auto size = check_type_and_get_blob_size("OSMData")) {
|
||||
std::string input_buffer = read_from_input_queue_with_check(size);
|
||||
|
||||
PBFDataBlobDecoder data_blob_parser{ std::move(input_buffer), read_types() };
|
||||
PBFDataBlobDecoder data_blob_parser{std::move(input_buffer), read_types(), read_metadata()};
|
||||
|
||||
if (osmium::config::use_pool_threads_for_pbf_parsing()) {
|
||||
send_to_output_queue(osmium::thread::Pool::instance().submit(std::move(data_blob_parser)));
|
||||
@ -195,8 +195,8 @@ namespace osmium {
|
||||
PBFParser(future_string_queue_type& input_queue,
|
||||
future_buffer_queue_type& output_queue,
|
||||
std::promise<osmium::io::Header>& header_promise,
|
||||
osmium::osm_entity_bits::type read_types) :
|
||||
Parser(input_queue, output_queue, header_promise, read_types),
|
||||
osmium::io::detail::reader_options options) :
|
||||
Parser(input_queue, output_queue, header_promise, options),
|
||||
m_input_buffer() {
|
||||
}
|
||||
|
||||
@ -221,8 +221,8 @@ namespace osmium {
|
||||
[](future_string_queue_type& input_queue,
|
||||
future_buffer_queue_type& output_queue,
|
||||
std::promise<osmium::io::Header>& header_promise,
|
||||
osmium::osm_entity_bits::type read_which_entities) {
|
||||
return std::unique_ptr<Parser>(new PBFParser(input_queue, output_queue, header_promise, read_which_entities));
|
||||
osmium::io::detail::reader_options options) {
|
||||
return std::unique_ptr<Parser>(new PBFParser(input_queue, output_queue, header_promise, options));
|
||||
});
|
||||
|
||||
// dummy function to silence the unused variable warning from above
|
||||
|
@ -33,10 +33,10 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/thread/queue.hpp>
|
||||
@ -59,13 +59,6 @@ namespace osmium {
|
||||
*/
|
||||
using future_buffer_queue_type = future_queue_type<osmium::memory::Buffer>;
|
||||
|
||||
/**
|
||||
* This type of queue contains OSM file data in the form it is
|
||||
* stored on disk, ie encoded as XML, PBF, etc.
|
||||
* The "end of file" is marked by an empty string.
|
||||
*/
|
||||
using string_queue_type = osmium::thread::Queue<std::string>;
|
||||
|
||||
/**
|
||||
* This type of queue contains OSM file data in the form it is
|
||||
* stored on disk, ie encoded as XML, PBF, etc.
|
||||
@ -95,11 +88,11 @@ namespace osmium {
|
||||
add_to_queue<T>(queue, T{});
|
||||
}
|
||||
|
||||
inline bool at_end_of_data(const std::string& data) {
|
||||
inline bool at_end_of_data(const std::string& data) noexcept {
|
||||
return data.empty();
|
||||
}
|
||||
|
||||
inline bool at_end_of_data(osmium::memory::Buffer& buffer) {
|
||||
inline bool at_end_of_data(osmium::memory::Buffer& buffer) noexcept {
|
||||
return !buffer;
|
||||
}
|
||||
|
||||
|
@ -80,8 +80,8 @@ namespace osmium {
|
||||
XML_Error error_code;
|
||||
std::string error_string;
|
||||
|
||||
explicit xml_error(XML_Parser parser) :
|
||||
io_error(std::string("XML parsing error at line ")
|
||||
explicit xml_error(const XML_Parser& parser) :
|
||||
io_error(std::string{"XML parsing error at line "}
|
||||
+ std::to_string(XML_GetCurrentLineNumber(parser))
|
||||
+ ", column "
|
||||
+ std::to_string(XML_GetCurrentColumnNumber(parser))
|
||||
@ -117,7 +117,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
explicit format_version_error(const char* v) :
|
||||
io_error(std::string("Can not read file with version ") + v),
|
||||
io_error(std::string{"Can not read file with version "} + v),
|
||||
version(v) {
|
||||
}
|
||||
|
||||
@ -201,7 +201,7 @@ namespace osmium {
|
||||
static void entity_declaration_handler(void*,
|
||||
const XML_Char*, int, const XML_Char*, int, const XML_Char*,
|
||||
const XML_Char*, const XML_Char*, const XML_Char*) {
|
||||
throw osmium::xml_error("XML entities are not supported");
|
||||
throw osmium::xml_error{"XML entities are not supported"};
|
||||
}
|
||||
|
||||
public:
|
||||
@ -209,7 +209,7 @@ namespace osmium {
|
||||
explicit ExpatXMLParser(T* callback_object) :
|
||||
m_parser(XML_ParserCreate(nullptr)) {
|
||||
if (!m_parser) {
|
||||
throw osmium::io_error("Internal error: Can not create parser");
|
||||
throw osmium::io_error{"Internal error: Can not create parser"};
|
||||
}
|
||||
XML_SetUserData(m_parser, callback_object);
|
||||
XML_SetElementHandler(m_parser, start_element_wrapper, end_element_wrapper);
|
||||
@ -229,7 +229,7 @@ namespace osmium {
|
||||
|
||||
void operator()(const std::string& data, bool last) {
|
||||
if (XML_Parse(m_parser, data.data(), static_cast_with_assert<int>(data.size()), last) == XML_STATUS_ERROR) {
|
||||
throw osmium::xml_error(m_parser);
|
||||
throw osmium::xml_error{m_parser};
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,37 +271,32 @@ namespace osmium {
|
||||
return user;
|
||||
}
|
||||
|
||||
void init_changeset(osmium::builder::ChangesetBuilder* builder, const XML_Char** attrs) {
|
||||
const char* user = "";
|
||||
osmium::Changeset& new_changeset = builder->object();
|
||||
void init_changeset(osmium::builder::ChangesetBuilder& builder, const XML_Char** attrs) {
|
||||
osmium::Box box;
|
||||
|
||||
osmium::Location min;
|
||||
osmium::Location max;
|
||||
check_attributes(attrs, [&min, &max, &user, &new_changeset](const XML_Char* name, const XML_Char* value) {
|
||||
check_attributes(attrs, [&builder, &box](const XML_Char* name, const XML_Char* value) {
|
||||
if (!std::strcmp(name, "min_lon")) {
|
||||
min.set_lon(value);
|
||||
box.bottom_left().set_lon(value);
|
||||
} else if (!std::strcmp(name, "min_lat")) {
|
||||
min.set_lat(value);
|
||||
box.bottom_left().set_lat(value);
|
||||
} else if (!std::strcmp(name, "max_lon")) {
|
||||
max.set_lon(value);
|
||||
box.top_right().set_lon(value);
|
||||
} else if (!std::strcmp(name, "max_lat")) {
|
||||
max.set_lat(value);
|
||||
box.top_right().set_lat(value);
|
||||
} else if (!std::strcmp(name, "user")) {
|
||||
user = value;
|
||||
builder.set_user(value);
|
||||
} else {
|
||||
new_changeset.set_attribute(name, value);
|
||||
builder.set_attribute(name, value);
|
||||
}
|
||||
});
|
||||
|
||||
new_changeset.bounds().extend(min);
|
||||
new_changeset.bounds().extend(max);
|
||||
|
||||
builder->add_user(user);
|
||||
builder.set_bounds(box);
|
||||
}
|
||||
|
||||
void get_tag(osmium::builder::Builder* builder, const XML_Char** attrs) {
|
||||
void get_tag(osmium::builder::Builder& builder, const XML_Char** attrs) {
|
||||
const char* k = "";
|
||||
const char* v = "";
|
||||
|
||||
check_attributes(attrs, [&k, &v](const XML_Char* name, const XML_Char* value) {
|
||||
if (name[0] == 'k' && name[1] == 0) {
|
||||
k = value;
|
||||
@ -309,8 +304,9 @@ namespace osmium {
|
||||
v = value;
|
||||
}
|
||||
});
|
||||
|
||||
if (!m_tl_builder) {
|
||||
m_tl_builder = std::unique_ptr<osmium::builder::TagListBuilder>(new osmium::builder::TagListBuilder(m_buffer, builder));
|
||||
m_tl_builder.reset(new osmium::builder::TagListBuilder{builder});
|
||||
}
|
||||
m_tl_builder->add_tag(k, v);
|
||||
}
|
||||
@ -330,17 +326,17 @@ namespace osmium {
|
||||
if (!std::strcmp(name, "version")) {
|
||||
m_header.set("version", value);
|
||||
if (std::strcmp(value, "0.6")) {
|
||||
throw osmium::format_version_error(value);
|
||||
throw osmium::format_version_error{value};
|
||||
}
|
||||
} else if (!std::strcmp(name, "generator")) {
|
||||
m_header.set("generator", value);
|
||||
}
|
||||
});
|
||||
if (m_header.get("version") == "") {
|
||||
throw osmium::format_version_error();
|
||||
throw osmium::format_version_error{};
|
||||
}
|
||||
} else {
|
||||
throw osmium::xml_error(std::string("Unknown top-level element: ") + element);
|
||||
throw osmium::xml_error{std::string{"Unknown top-level element: "} + element};
|
||||
}
|
||||
m_context = context::top;
|
||||
break;
|
||||
@ -349,8 +345,8 @@ namespace osmium {
|
||||
if (!std::strcmp(element, "node")) {
|
||||
mark_header_as_done();
|
||||
if (read_types() & osmium::osm_entity_bits::node) {
|
||||
m_node_builder = std::unique_ptr<osmium::builder::NodeBuilder>(new osmium::builder::NodeBuilder(m_buffer));
|
||||
m_node_builder->add_user(init_object(m_node_builder->object(), attrs));
|
||||
m_node_builder.reset(new osmium::builder::NodeBuilder{m_buffer});
|
||||
m_node_builder->set_user(init_object(m_node_builder->object(), attrs));
|
||||
m_context = context::node;
|
||||
} else {
|
||||
m_context = context::ignored_node;
|
||||
@ -358,8 +354,8 @@ namespace osmium {
|
||||
} else if (!std::strcmp(element, "way")) {
|
||||
mark_header_as_done();
|
||||
if (read_types() & osmium::osm_entity_bits::way) {
|
||||
m_way_builder = std::unique_ptr<osmium::builder::WayBuilder>(new osmium::builder::WayBuilder(m_buffer));
|
||||
m_way_builder->add_user(init_object(m_way_builder->object(), attrs));
|
||||
m_way_builder.reset(new osmium::builder::WayBuilder{m_buffer});
|
||||
m_way_builder->set_user(init_object(m_way_builder->object(), attrs));
|
||||
m_context = context::way;
|
||||
} else {
|
||||
m_context = context::ignored_way;
|
||||
@ -367,8 +363,8 @@ namespace osmium {
|
||||
} else if (!std::strcmp(element, "relation")) {
|
||||
mark_header_as_done();
|
||||
if (read_types() & osmium::osm_entity_bits::relation) {
|
||||
m_relation_builder = std::unique_ptr<osmium::builder::RelationBuilder>(new osmium::builder::RelationBuilder(m_buffer));
|
||||
m_relation_builder->add_user(init_object(m_relation_builder->object(), attrs));
|
||||
m_relation_builder.reset(new osmium::builder::RelationBuilder{m_buffer});
|
||||
m_relation_builder->set_user(init_object(m_relation_builder->object(), attrs));
|
||||
m_context = context::relation;
|
||||
} else {
|
||||
m_context = context::ignored_relation;
|
||||
@ -376,8 +372,8 @@ namespace osmium {
|
||||
} else if (!std::strcmp(element, "changeset")) {
|
||||
mark_header_as_done();
|
||||
if (read_types() & osmium::osm_entity_bits::changeset) {
|
||||
m_changeset_builder = std::unique_ptr<osmium::builder::ChangesetBuilder>(new osmium::builder::ChangesetBuilder(m_buffer));
|
||||
init_changeset(m_changeset_builder.get(), attrs);
|
||||
m_changeset_builder.reset(new osmium::builder::ChangesetBuilder{m_buffer});
|
||||
init_changeset(*m_changeset_builder, attrs);
|
||||
m_context = context::changeset;
|
||||
} else {
|
||||
m_context = context::ignored_changeset;
|
||||
@ -407,7 +403,7 @@ namespace osmium {
|
||||
m_last_context = context::node;
|
||||
m_context = context::in_object;
|
||||
if (!std::strcmp(element, "tag")) {
|
||||
get_tag(m_node_builder.get(), attrs);
|
||||
get_tag(*m_node_builder, attrs);
|
||||
}
|
||||
break;
|
||||
case context::way:
|
||||
@ -417,7 +413,7 @@ namespace osmium {
|
||||
m_tl_builder.reset();
|
||||
|
||||
if (!m_wnl_builder) {
|
||||
m_wnl_builder = std::unique_ptr<osmium::builder::WayNodeListBuilder>(new osmium::builder::WayNodeListBuilder(m_buffer, m_way_builder.get()));
|
||||
m_wnl_builder.reset(new osmium::builder::WayNodeListBuilder{*m_way_builder});
|
||||
}
|
||||
|
||||
NodeRef nr;
|
||||
@ -433,7 +429,7 @@ namespace osmium {
|
||||
m_wnl_builder->add_node_ref(nr);
|
||||
} else if (!std::strcmp(element, "tag")) {
|
||||
m_wnl_builder.reset();
|
||||
get_tag(m_way_builder.get(), attrs);
|
||||
get_tag(*m_way_builder, attrs);
|
||||
}
|
||||
break;
|
||||
case context::relation:
|
||||
@ -443,7 +439,7 @@ namespace osmium {
|
||||
m_tl_builder.reset();
|
||||
|
||||
if (!m_rml_builder) {
|
||||
m_rml_builder = std::unique_ptr<osmium::builder::RelationMemberListBuilder>(new osmium::builder::RelationMemberListBuilder(m_buffer, m_relation_builder.get()));
|
||||
m_rml_builder.reset(new osmium::builder::RelationMemberListBuilder{*m_relation_builder});
|
||||
}
|
||||
|
||||
item_type type = item_type::undefined;
|
||||
@ -459,15 +455,15 @@ namespace osmium {
|
||||
}
|
||||
});
|
||||
if (type != item_type::node && type != item_type::way && type != item_type::relation) {
|
||||
throw osmium::xml_error("Unknown type on relation member");
|
||||
throw osmium::xml_error{"Unknown type on relation member"};
|
||||
}
|
||||
if (ref == 0) {
|
||||
throw osmium::xml_error("Missing ref on relation member");
|
||||
throw osmium::xml_error{"Missing ref on relation member"};
|
||||
}
|
||||
m_rml_builder->add_member(type, ref, role);
|
||||
} else if (!std::strcmp(element, "tag")) {
|
||||
m_rml_builder.reset();
|
||||
get_tag(m_relation_builder.get(), attrs);
|
||||
get_tag(*m_relation_builder, attrs);
|
||||
}
|
||||
break;
|
||||
case context::changeset:
|
||||
@ -476,12 +472,12 @@ namespace osmium {
|
||||
m_context = context::discussion;
|
||||
m_tl_builder.reset();
|
||||
if (!m_changeset_discussion_builder) {
|
||||
m_changeset_discussion_builder = std::unique_ptr<osmium::builder::ChangesetDiscussionBuilder>(new osmium::builder::ChangesetDiscussionBuilder(m_buffer, m_changeset_builder.get()));
|
||||
m_changeset_discussion_builder.reset(new osmium::builder::ChangesetDiscussionBuilder{*m_changeset_builder});
|
||||
}
|
||||
} else if (!std::strcmp(element, "tag")) {
|
||||
m_context = context::in_object;
|
||||
m_changeset_discussion_builder.reset();
|
||||
get_tag(m_changeset_builder.get(), attrs);
|
||||
get_tag(*m_changeset_builder, attrs);
|
||||
}
|
||||
break;
|
||||
case context::discussion:
|
||||
@ -632,8 +628,8 @@ namespace osmium {
|
||||
XMLParser(future_string_queue_type& input_queue,
|
||||
future_buffer_queue_type& output_queue,
|
||||
std::promise<osmium::io::Header>& header_promise,
|
||||
osmium::osm_entity_bits::type read_types) :
|
||||
Parser(input_queue, output_queue, header_promise, read_types),
|
||||
osmium::io::detail::reader_options options) :
|
||||
Parser(input_queue, output_queue, header_promise, options),
|
||||
m_context(context::root),
|
||||
m_last_context(context::root),
|
||||
m_in_delete_section(false),
|
||||
@ -657,7 +653,7 @@ namespace osmium {
|
||||
ExpatXMLParser<XMLParser> parser(this);
|
||||
|
||||
while (!input_done()) {
|
||||
std::string data = get_input();
|
||||
const std::string data{get_input()};
|
||||
parser(data, input_done());
|
||||
if (read_types() == osmium::osm_entity_bits::nothing && header_is_done()) {
|
||||
break;
|
||||
@ -680,8 +676,8 @@ namespace osmium {
|
||||
[](future_string_queue_type& input_queue,
|
||||
future_buffer_queue_type& output_queue,
|
||||
std::promise<osmium::io::Header>& header_promise,
|
||||
osmium::osm_entity_bits::type read_which_entities) {
|
||||
return std::unique_ptr<Parser>(new XMLParser(input_queue, output_queue, header_promise, read_which_entities));
|
||||
osmium::io::detail::reader_options options) {
|
||||
return std::unique_ptr<Parser>(new XMLParser{input_queue, output_queue, header_promise, options});
|
||||
});
|
||||
|
||||
// dummy function to silence the unused variable warning from above
|
||||
|
@ -49,6 +49,11 @@ namespace osmium {
|
||||
debug = 6
|
||||
};
|
||||
|
||||
enum class read_meta {
|
||||
no = 0,
|
||||
yes = 1
|
||||
};
|
||||
|
||||
// avoid g++ false positive
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wreturn-type"
|
||||
|
@ -44,17 +44,37 @@ namespace osmium {
|
||||
namespace io {
|
||||
|
||||
/**
|
||||
* Meta information from the header of an OSM file.
|
||||
*/
|
||||
* Meta information from the header of an OSM file.
|
||||
*
|
||||
* The header can contain any number of bounding boxes, although
|
||||
* usually there is only a single one (or none). PBF files only
|
||||
* allow a single bounding box, but XML files can have multiple ones,
|
||||
* although it is unusual and the semantics are unclear, so it is
|
||||
* discouraged to create files with multiple bounding boxes.
|
||||
*
|
||||
* The header contains a flag telling you whether this file can
|
||||
* contain multiple versions of the same object. This is true for
|
||||
* history files and for change files, but not for normal OSM data
|
||||
* files. Not all OSM file formats can distinguish between those
|
||||
* cases, so the flag might be wrong.
|
||||
*
|
||||
* In addition the header can contain any number of key-value pairs
|
||||
* with additional information. Most often this is used to set the
|
||||
* "generator", the program that generated the file. Depending on
|
||||
* the file format some of these key-value pairs are handled
|
||||
* specially. The the Options parent class for details on how to
|
||||
* set and get those key-value pairs.
|
||||
*/
|
||||
class Header : public osmium::util::Options {
|
||||
|
||||
/// Bounding boxes
|
||||
std::vector<osmium::Box> m_boxes;
|
||||
|
||||
/**
|
||||
* Are there possibly multiple versions of the same object in this stream of objects?
|
||||
* This is true for history files and for change files, but not for normal OSM files.
|
||||
*/
|
||||
* Are there possibly multiple versions of the same object in
|
||||
* this stream of objects? This should be true for history files
|
||||
* and for change files, but not for normal OSM data files.
|
||||
*/
|
||||
bool m_has_multiple_object_versions = false;
|
||||
|
||||
public:
|
||||
@ -65,49 +85,76 @@ namespace osmium {
|
||||
Options(values) {
|
||||
}
|
||||
|
||||
Header(const Header&) = default;
|
||||
Header& operator=(const Header&) = default;
|
||||
|
||||
Header(Header&&) = default;
|
||||
Header& operator=(Header&&) = default;
|
||||
|
||||
~Header() = default;
|
||||
|
||||
/**
|
||||
* Get the bounding boxes defined in the header.
|
||||
*/
|
||||
std::vector<osmium::Box>& boxes() noexcept {
|
||||
return m_boxes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bounding boxes defined in the header.
|
||||
*/
|
||||
const std::vector<osmium::Box>& boxes() const noexcept {
|
||||
return m_boxes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all the bounding boxes in the header.
|
||||
*/
|
||||
Header& boxes(const std::vector<osmium::Box>& boxes) noexcept {
|
||||
m_boxes = boxes;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first (or only if there is only one) bounding box.
|
||||
*
|
||||
* Returns an empty, invalid box if there is none.
|
||||
*/
|
||||
osmium::Box box() const {
|
||||
return m_boxes.empty() ? osmium::Box() : m_boxes.front();
|
||||
return m_boxes.empty() ? osmium::Box{} : m_boxes.front();
|
||||
}
|
||||
|
||||
/**
|
||||
* Join up all the bounding boxes in the header into one and return
|
||||
* it. This method is what you probably want to use unless you want
|
||||
* to handle the possibly multiple bounding boxes yourself.
|
||||
*
|
||||
* Returns an empty, invalid box if there is none.
|
||||
*/
|
||||
osmium::Box joined_boxes() const {
|
||||
osmium::Box box;
|
||||
for (const auto& b : m_boxes) {
|
||||
box.extend(b.bottom_left());
|
||||
box.extend(b.top_right());
|
||||
box.extend(b);
|
||||
}
|
||||
return box;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given bounding box to the list of bounding boxes in the
|
||||
* header.
|
||||
*
|
||||
* @returns The header itself to allow chaining.
|
||||
*/
|
||||
Header& add_box(const osmium::Box& box) {
|
||||
m_boxes.push_back(box);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can this file contain multiple versions of the same object?
|
||||
*/
|
||||
bool has_multiple_object_versions() const noexcept {
|
||||
return m_has_multiple_object_versions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag that tells us whether this file can contain
|
||||
* multiple versions of the same object?
|
||||
*
|
||||
* @returns The header itself to allow chaining.
|
||||
*/
|
||||
Header& set_has_multiple_object_versions(bool value) noexcept {
|
||||
m_has_multiple_object_versions = value;
|
||||
return *this;
|
||||
|
@ -91,7 +91,6 @@ namespace osmium {
|
||||
class Reader {
|
||||
|
||||
osmium::io::File m_file;
|
||||
osmium::osm_entity_bits::type m_read_which_entities;
|
||||
|
||||
enum class status {
|
||||
okay = 0, // normal reading
|
||||
@ -118,15 +117,25 @@ namespace osmium {
|
||||
|
||||
size_t m_file_size;
|
||||
|
||||
osmium::io::detail::reader_options m_options;
|
||||
|
||||
void set_option(osmium::osm_entity_bits::type value) noexcept {
|
||||
m_options.read_which_entities = value;
|
||||
}
|
||||
|
||||
void set_option(osmium::io::read_meta value) noexcept {
|
||||
m_options.read_metadata = value;
|
||||
}
|
||||
|
||||
// This function will run in a separate thread.
|
||||
static void parser_thread(const osmium::io::File& file,
|
||||
detail::future_string_queue_type& input_queue,
|
||||
detail::future_buffer_queue_type& osmdata_queue,
|
||||
std::promise<osmium::io::Header>&& header_promise,
|
||||
osmium::osm_entity_bits::type read_which_entities) {
|
||||
osmium::io::detail::reader_options options) {
|
||||
std::promise<osmium::io::Header> promise = std::move(header_promise);
|
||||
const auto creator = detail::ParserFactory::instance().get_creator_function(file);
|
||||
const auto parser = creator(input_queue, osmdata_queue, promise, read_which_entities);
|
||||
const auto parser = creator(input_queue, osmdata_queue, promise, options);
|
||||
parser->parse();
|
||||
}
|
||||
|
||||
@ -205,15 +214,28 @@ namespace osmium {
|
||||
/**
|
||||
* Create new Reader object.
|
||||
*
|
||||
* @param file The file we want to open.
|
||||
* @param read_which_entities Which OSM entities (nodes, ways, relations, and/or changesets)
|
||||
* should be read from the input file. It can speed the read up
|
||||
* significantly if objects that are not needed anyway are not
|
||||
* parsed.
|
||||
* @param file The file (contains name and format info) to open.
|
||||
* @param args All further arguments are optional and can appear
|
||||
* in any order:
|
||||
*
|
||||
* * osmium::osm_entities::bits: Which OSM entities (nodes, ways,
|
||||
* relations, and/or changesets) should be read from the
|
||||
* input file. It can speed the read up significantly if
|
||||
* objects that are not needed anyway are not parsed.
|
||||
*
|
||||
* * osmium::io::read_meta: Read meta data or not. The default is
|
||||
* osmium::io::read_meta::yes which means that meta data
|
||||
* is read normally. If you set this to
|
||||
* osmium::io::read_meta::no, meta data (like version, uid,
|
||||
* etc.) is not read possibly speeding up the read. Not all
|
||||
* file formats use this setting.
|
||||
*
|
||||
* @throws osmium::io_error If there was an error.
|
||||
* @throws std::system_error If the file could not be opened.
|
||||
*/
|
||||
explicit Reader(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities = osmium::osm_entity_bits::all) :
|
||||
template <typename... TArgs>
|
||||
explicit Reader(const osmium::io::File& file, TArgs&&... args) :
|
||||
m_file(file.check()),
|
||||
m_read_which_entities(read_which_entities),
|
||||
m_status(status::okay),
|
||||
m_childpid(0),
|
||||
m_input_queue(detail::get_input_queue_size(), "raw_input"),
|
||||
@ -227,17 +249,24 @@ namespace osmium {
|
||||
m_header(),
|
||||
m_thread(),
|
||||
m_file_size(m_decompressor->file_size()) {
|
||||
|
||||
(void)std::initializer_list<int>{
|
||||
(set_option(args), 0)...
|
||||
};
|
||||
|
||||
std::promise<osmium::io::Header> header_promise;
|
||||
m_header_future = header_promise.get_future();
|
||||
m_thread = osmium::thread::thread_handler{parser_thread, std::ref(m_file), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), read_which_entities};
|
||||
m_thread = osmium::thread::thread_handler{parser_thread, std::ref(m_file), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), m_options};
|
||||
}
|
||||
|
||||
explicit Reader(const std::string& filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
|
||||
Reader(osmium::io::File(filename), read_types) {
|
||||
template <typename... TArgs>
|
||||
explicit Reader(const std::string& filename, TArgs&&... args) :
|
||||
Reader(osmium::io::File(filename), std::forward<TArgs>(args)...) {
|
||||
}
|
||||
|
||||
explicit Reader(const char* filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
|
||||
Reader(osmium::io::File(filename), read_types) {
|
||||
template <typename... TArgs>
|
||||
explicit Reader(const char* filename, TArgs&&... args) :
|
||||
Reader(osmium::io::File(filename), std::forward<TArgs>(args)...) {
|
||||
}
|
||||
|
||||
Reader(const Reader&) = delete;
|
||||
@ -304,7 +333,7 @@ namespace osmium {
|
||||
try {
|
||||
if (m_header_future.valid()) {
|
||||
m_header = m_header_future.get();
|
||||
if (m_read_which_entities == osmium::osm_entity_bits::nothing) {
|
||||
if (m_options.read_which_entities == osmium::osm_entity_bits::nothing) {
|
||||
m_status = status::eof;
|
||||
}
|
||||
}
|
||||
@ -330,7 +359,7 @@ namespace osmium {
|
||||
osmium::memory::Buffer buffer;
|
||||
|
||||
if (m_status != status::okay ||
|
||||
m_read_which_entities == osmium::osm_entity_bits::nothing) {
|
||||
m_options.read_which_entities == osmium::osm_entity_bits::nothing) {
|
||||
throw io_error("Can not read from reader when in status 'closed', 'eof', or 'error'");
|
||||
}
|
||||
|
||||
|
@ -113,6 +113,9 @@ namespace osmium {
|
||||
size_t m_capacity;
|
||||
size_t m_written;
|
||||
size_t m_committed;
|
||||
#ifndef NDEBUG
|
||||
uint8_t m_builder_count{0};
|
||||
#endif
|
||||
auto_grow m_auto_grow {auto_grow::no};
|
||||
std::function<void(Buffer&)> m_full;
|
||||
|
||||
@ -216,13 +219,28 @@ namespace osmium {
|
||||
|
||||
~Buffer() = default;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void increment_builder_count() noexcept {
|
||||
++m_builder_count;
|
||||
}
|
||||
|
||||
void decrement_builder_count() noexcept {
|
||||
assert(m_builder_count > 0);
|
||||
--m_builder_count;
|
||||
}
|
||||
|
||||
uint8_t builder_count() const noexcept {
|
||||
return m_builder_count;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Return a pointer to data inside the buffer.
|
||||
*
|
||||
* @pre The buffer must be valid.
|
||||
*/
|
||||
unsigned char* data() const noexcept {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return m_data;
|
||||
}
|
||||
|
||||
@ -258,7 +276,7 @@ namespace osmium {
|
||||
* @pre The buffer must be valid.
|
||||
*/
|
||||
bool is_aligned() const noexcept {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return (m_written % align_bytes == 0) && (m_committed % align_bytes == 0);
|
||||
}
|
||||
|
||||
@ -283,7 +301,7 @@ namespace osmium {
|
||||
* than the difference between committed() and capacity().
|
||||
*/
|
||||
OSMIUM_DEPRECATED void set_full_callback(std::function<void(Buffer&)> full) {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
m_full = full;
|
||||
}
|
||||
|
||||
@ -292,7 +310,6 @@ namespace osmium {
|
||||
* This works only with internally memory-managed buffers.
|
||||
* If the given size is not larger than the current capacity,
|
||||
* nothing is done.
|
||||
* Already written but not committed data is discarded.
|
||||
*
|
||||
* @pre The buffer must be valid.
|
||||
*
|
||||
@ -305,7 +322,7 @@ namespace osmium {
|
||||
* @throws std::bad_alloc if there isn't enough memory available.
|
||||
*/
|
||||
void grow(size_t size) {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
if (!m_memory) {
|
||||
throw std::logic_error("Can't grow Buffer if it doesn't use internal memory management.");
|
||||
}
|
||||
@ -325,15 +342,18 @@ namespace osmium {
|
||||
/**
|
||||
* Mark currently written bytes in the buffer as committed.
|
||||
*
|
||||
* @pre The buffer must be valid and aligned properly (as indicated
|
||||
* @pre The buffer must be valid.
|
||||
* @pre The buffer must be aligned properly (as indicated
|
||||
* by is_aligned().
|
||||
* @pre No builder can be open on this buffer.
|
||||
*
|
||||
* @returns Number of committed bytes before this commit. Can be
|
||||
* used as an offset into the buffer to get to the
|
||||
* object being committed by this call.
|
||||
*/
|
||||
size_t commit() {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
|
||||
assert(is_aligned());
|
||||
|
||||
const size_t offset = m_committed;
|
||||
@ -345,9 +365,11 @@ namespace osmium {
|
||||
* Roll back changes in buffer to last committed state.
|
||||
*
|
||||
* @pre The buffer must be valid.
|
||||
* @pre No builder can be open on this buffer.
|
||||
*/
|
||||
void rollback() {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
|
||||
m_written = m_committed;
|
||||
}
|
||||
|
||||
@ -356,9 +378,12 @@ namespace osmium {
|
||||
*
|
||||
* No-op on an invalid buffer.
|
||||
*
|
||||
* @pre No builder can be open on this buffer.
|
||||
*
|
||||
* @returns Number of bytes in the buffer before it was cleared.
|
||||
*/
|
||||
size_t clear() {
|
||||
assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
|
||||
const size_t committed = m_committed;
|
||||
m_written = 0;
|
||||
m_committed = 0;
|
||||
@ -377,7 +402,7 @@ namespace osmium {
|
||||
*/
|
||||
template <typename T>
|
||||
T& get(const size_t offset) const {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return *reinterpret_cast<T*>(&m_data[offset]);
|
||||
}
|
||||
|
||||
@ -415,7 +440,7 @@ namespace osmium {
|
||||
* no callback defined and the buffer isn't auto-growing.
|
||||
*/
|
||||
unsigned char* reserve_space(const size_t size) {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
// try to flush the buffer empty first.
|
||||
if (m_written + size > m_capacity && m_full) {
|
||||
m_full(*this);
|
||||
@ -455,7 +480,7 @@ namespace osmium {
|
||||
*/
|
||||
template <typename T>
|
||||
T& add_item(const T& item) {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
unsigned char* target = reserve_space(item.padded_size());
|
||||
std::copy_n(reinterpret_cast<const unsigned char*>(&item), item.padded_size(), target);
|
||||
return *reinterpret_cast<T*>(target);
|
||||
@ -465,6 +490,7 @@ namespace osmium {
|
||||
* Add committed contents of the given buffer to this buffer.
|
||||
*
|
||||
* @pre The buffer must be valid.
|
||||
* @pre No builder can be open on this buffer.
|
||||
*
|
||||
* Note that you have to eventually call commit() to actually
|
||||
* commit this data.
|
||||
@ -472,7 +498,9 @@ namespace osmium {
|
||||
* @param buffer The source of the copy. Must be valid.
|
||||
*/
|
||||
void add_buffer(const Buffer& buffer) {
|
||||
assert(m_data && buffer);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
assert(buffer && "Buffer parameter must be a valid buffer");
|
||||
assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
|
||||
unsigned char* target = reserve_space(buffer.committed());
|
||||
std::copy_n(buffer.data(), buffer.committed(), target);
|
||||
}
|
||||
@ -482,11 +510,13 @@ namespace osmium {
|
||||
* you can use std::back_inserter.
|
||||
*
|
||||
* @pre The buffer must be valid.
|
||||
* @pre No builder can be open on this buffer.
|
||||
*
|
||||
* @param item The item to be added.
|
||||
*/
|
||||
void push_back(const osmium::memory::Item& item) {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
|
||||
add_item(item);
|
||||
commit();
|
||||
}
|
||||
@ -537,7 +567,7 @@ namespace osmium {
|
||||
*/
|
||||
template <typename T>
|
||||
t_iterator<T> begin() {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return t_iterator<T>(m_data, m_data + m_committed);
|
||||
}
|
||||
|
||||
@ -550,7 +580,7 @@ namespace osmium {
|
||||
* @returns Iterator to first OSMEntity in the buffer.
|
||||
*/
|
||||
iterator begin() {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return iterator(m_data, m_data + m_committed);
|
||||
}
|
||||
|
||||
@ -565,7 +595,7 @@ namespace osmium {
|
||||
*/
|
||||
template <typename T>
|
||||
t_iterator<T> get_iterator(size_t offset) {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return t_iterator<T>(m_data + offset, m_data + m_committed);
|
||||
}
|
||||
|
||||
@ -579,7 +609,7 @@ namespace osmium {
|
||||
* buffer.
|
||||
*/
|
||||
iterator get_iterator(size_t offset) {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return iterator(m_data + offset, m_data + m_committed);
|
||||
}
|
||||
|
||||
@ -593,7 +623,7 @@ namespace osmium {
|
||||
*/
|
||||
template <typename T>
|
||||
t_iterator<T> end() {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return t_iterator<T>(m_data + m_committed, m_data + m_committed);
|
||||
}
|
||||
|
||||
@ -606,40 +636,40 @@ namespace osmium {
|
||||
* @returns End iterator.
|
||||
*/
|
||||
iterator end() {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return iterator(m_data + m_committed, m_data + m_committed);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
t_const_iterator<T> cbegin() const {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return t_const_iterator<T>(m_data, m_data + m_committed);
|
||||
}
|
||||
|
||||
const_iterator cbegin() const {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return const_iterator(m_data, m_data + m_committed);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
t_const_iterator<T> get_iterator(size_t offset) const {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return t_const_iterator<T>(m_data + offset, m_data + m_committed);
|
||||
}
|
||||
|
||||
const_iterator get_iterator(size_t offset) const {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return const_iterator(m_data + offset, m_data + m_committed);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
t_const_iterator<T> cend() const {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return t_const_iterator<T>(m_data + m_committed, m_data + m_committed);
|
||||
}
|
||||
|
||||
const_iterator cend() const {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
return const_iterator(m_data + m_committed, m_data + m_committed);
|
||||
}
|
||||
|
||||
@ -698,7 +728,7 @@ namespace osmium {
|
||||
*/
|
||||
template <typename TCallbackClass>
|
||||
void purge_removed(TCallbackClass* callback) {
|
||||
assert(m_data);
|
||||
assert(m_data && "This must be a valid buffer");
|
||||
if (begin() == end()) {
|
||||
return;
|
||||
}
|
||||
|
@ -46,9 +46,9 @@ namespace osmium {
|
||||
template <typename TMember>
|
||||
class CollectionIterator {
|
||||
|
||||
// This data_type is either 'unsigned char*' or 'const unsigned char*' depending
|
||||
// on whether TMember is const. This allows this class to be used as an iterator and
|
||||
// as a const_iterator.
|
||||
// This data_type is either 'unsigned char*' or 'const unsigned
|
||||
// char*' depending on whether TMember is const. This allows this
|
||||
// class to be used as an iterator and as a const_iterator.
|
||||
using data_type = typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type;
|
||||
|
||||
data_type m_data;
|
||||
@ -92,11 +92,11 @@ namespace osmium {
|
||||
return m_data;
|
||||
}
|
||||
|
||||
TMember& operator*() const {
|
||||
TMember& operator*() const noexcept {
|
||||
return *reinterpret_cast<TMember*>(m_data);
|
||||
}
|
||||
|
||||
TMember* operator->() const {
|
||||
TMember* operator->() const noexcept {
|
||||
return reinterpret_cast<TMember*>(m_data);
|
||||
}
|
||||
|
||||
@ -118,9 +118,12 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
using iterator = CollectionIterator<TMember>;
|
||||
using const_iterator = CollectionIterator<const TMember>;
|
||||
using value_type = TMember;
|
||||
using value_type = TMember;
|
||||
using reference = TMember&;
|
||||
using const_reference = const TMember&;
|
||||
using iterator = CollectionIterator<TMember>;
|
||||
using const_iterator = CollectionIterator<const TMember>;
|
||||
using size_type = size_t;
|
||||
|
||||
static constexpr osmium::item_type itemtype = TCollectionItemType;
|
||||
|
||||
@ -128,31 +131,45 @@ namespace osmium {
|
||||
Item(sizeof(Collection<TMember, TCollectionItemType>), TCollectionItemType) {
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
/**
|
||||
* Does this collection contain any items?
|
||||
*
|
||||
* Complexity: Constant.
|
||||
*/
|
||||
bool empty() const noexcept {
|
||||
return sizeof(Collection<TMember, TCollectionItemType>) == byte_size();
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
/**
|
||||
* Returns the number of items in this collection.
|
||||
*
|
||||
* Complexity: Linear in the number of items.
|
||||
*/
|
||||
size_type size() const noexcept {
|
||||
return static_cast<size_type>(std::distance(begin(), end()));
|
||||
}
|
||||
|
||||
iterator begin() noexcept {
|
||||
return iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
iterator end() noexcept {
|
||||
return iterator(data() + byte_size());
|
||||
}
|
||||
|
||||
const_iterator cbegin() const {
|
||||
const_iterator cbegin() const noexcept {
|
||||
return const_iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
|
||||
}
|
||||
|
||||
const_iterator cend() const {
|
||||
const_iterator cend() const noexcept {
|
||||
return const_iterator(data() + byte_size());
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
const_iterator begin() const noexcept {
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
const_iterator end() const noexcept {
|
||||
return cend();
|
||||
}
|
||||
|
||||
|
@ -59,9 +59,9 @@ namespace osmium {
|
||||
using item_size_type = uint32_t;
|
||||
|
||||
// align datastructures to this many bytes
|
||||
constexpr item_size_type align_bytes = 8;
|
||||
constexpr const item_size_type align_bytes = 8;
|
||||
|
||||
inline std::size_t padded_length(std::size_t length) noexcept {
|
||||
inline constexpr std::size_t padded_length(std::size_t length) noexcept {
|
||||
return (length + align_bytes - 1) & ~(align_bytes - 1);
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,8 @@ DEALINGS IN THE SOFTWARE.
|
||||
namespace osmium {
|
||||
|
||||
namespace builder {
|
||||
template <class T> class ObjectBuilder;
|
||||
template <typename TDerived, typename T>
|
||||
class OSMObjectBuilder;
|
||||
} // namespace builder
|
||||
|
||||
/**
|
||||
@ -117,7 +118,8 @@ namespace osmium {
|
||||
*/
|
||||
class Area : public OSMObject {
|
||||
|
||||
friend class osmium::builder::ObjectBuilder<osmium::Area>;
|
||||
template <typename TDerived, typename T>
|
||||
friend class osmium::builder::OSMObjectBuilder;
|
||||
|
||||
Area() :
|
||||
OSMObject(sizeof(Area), osmium::item_type::area) {
|
||||
@ -130,6 +132,8 @@ namespace osmium {
|
||||
/**
|
||||
* Was this area created from a way? (In contrast to areas
|
||||
* created from a relation and their members.)
|
||||
*
|
||||
* Complexity: Constant.
|
||||
*/
|
||||
bool from_way() const noexcept {
|
||||
return (positive_id() & 0x1) == 0;
|
||||
@ -137,6 +141,8 @@ namespace osmium {
|
||||
|
||||
/**
|
||||
* Return the Id of the way or relation this area was created from.
|
||||
*
|
||||
* Complexity: Constant.
|
||||
*/
|
||||
osmium::object_id_type orig_id() const noexcept {
|
||||
return osmium::area_id_to_object_id(id());
|
||||
@ -145,6 +151,8 @@ namespace osmium {
|
||||
/**
|
||||
* Count the number of outer and inner rings of this area.
|
||||
*
|
||||
* Complexity: Linear in the number of rings.
|
||||
*
|
||||
* @returns Pair (number outer rings, number inner rings)
|
||||
*/
|
||||
std::pair<size_t, size_t> num_rings() const {
|
||||
|
@ -51,7 +51,7 @@ namespace osmium {
|
||||
|
||||
namespace builder {
|
||||
class ChangesetDiscussionBuilder;
|
||||
template <typename T> class ObjectBuilder;
|
||||
class ChangesetBuilder;
|
||||
} // namespace builder
|
||||
|
||||
class Changeset;
|
||||
@ -129,20 +129,12 @@ namespace osmium {
|
||||
|
||||
class ChangesetDiscussion : public osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion> {
|
||||
|
||||
friend class osmium::builder::ObjectBuilder<osmium::Changeset>;
|
||||
|
||||
public:
|
||||
|
||||
using size_type = size_t;
|
||||
|
||||
ChangesetDiscussion() :
|
||||
osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion>() {
|
||||
}
|
||||
|
||||
size_type size() const noexcept {
|
||||
return static_cast<size_type>(std::distance(begin(), end()));
|
||||
}
|
||||
|
||||
}; // class ChangesetDiscussion
|
||||
|
||||
static_assert(sizeof(ChangesetDiscussion) % osmium::memory::align_bytes == 0, "Class osmium::ChangesetDiscussion has wrong size to be aligned properly!");
|
||||
@ -156,7 +148,7 @@ namespace osmium {
|
||||
*/
|
||||
class Changeset : public osmium::OSMEntity {
|
||||
|
||||
friend class osmium::builder::ObjectBuilder<osmium::Changeset>;
|
||||
friend class osmium::builder::ChangesetBuilder;
|
||||
|
||||
osmium::Box m_bounds;
|
||||
osmium::Timestamp m_created_at;
|
||||
@ -173,10 +165,14 @@ namespace osmium {
|
||||
OSMEntity(sizeof(Changeset), osmium::item_type::changeset) {
|
||||
}
|
||||
|
||||
void set_user_size(string_size_type size) {
|
||||
void set_user_size(string_size_type size) noexcept {
|
||||
m_user_size = size;
|
||||
}
|
||||
|
||||
string_size_type user_size() const noexcept {
|
||||
return m_user_size;
|
||||
}
|
||||
|
||||
unsigned char* subitems_position() {
|
||||
return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size);
|
||||
}
|
||||
|
@ -100,15 +100,15 @@ namespace osmium {
|
||||
return m_crc;
|
||||
}
|
||||
|
||||
void update_bool(const bool value) {
|
||||
void update_bool(const bool value) noexcept {
|
||||
m_crc.process_byte(value);
|
||||
}
|
||||
|
||||
void update_int8(const uint8_t value) {
|
||||
void update_int8(const uint8_t value) noexcept {
|
||||
m_crc.process_byte(value);
|
||||
}
|
||||
|
||||
void update_int16(const uint16_t value) {
|
||||
void update_int16(const uint16_t value) noexcept {
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
m_crc.process_bytes(&value, sizeof(uint16_t));
|
||||
#else
|
||||
@ -117,7 +117,7 @@ namespace osmium {
|
||||
#endif
|
||||
}
|
||||
|
||||
void update_int32(const uint32_t value) {
|
||||
void update_int32(const uint32_t value) noexcept {
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
m_crc.process_bytes(&value, sizeof(uint32_t));
|
||||
#else
|
||||
@ -126,7 +126,7 @@ namespace osmium {
|
||||
#endif
|
||||
}
|
||||
|
||||
void update_int64(const uint64_t value) {
|
||||
void update_int64(const uint64_t value) noexcept {
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
m_crc.process_bytes(&value, sizeof(uint64_t));
|
||||
#else
|
||||
@ -135,57 +135,57 @@ namespace osmium {
|
||||
#endif
|
||||
}
|
||||
|
||||
void update_string(const char* str) {
|
||||
void update_string(const char* str) noexcept {
|
||||
while (*str) {
|
||||
m_crc.process_byte(*str++);
|
||||
}
|
||||
}
|
||||
|
||||
void update(const Timestamp& timestamp) {
|
||||
void update(const Timestamp& timestamp) noexcept {
|
||||
update_int32(uint32_t(timestamp));
|
||||
}
|
||||
|
||||
void update(const osmium::Location& location) {
|
||||
void update(const osmium::Location& location) noexcept {
|
||||
update_int32(location.x());
|
||||
update_int32(location.y());
|
||||
}
|
||||
|
||||
void update(const osmium::Box& box) {
|
||||
void update(const osmium::Box& box) noexcept {
|
||||
update(box.bottom_left());
|
||||
update(box.top_right());
|
||||
}
|
||||
|
||||
void update(const NodeRef& node_ref) {
|
||||
void update(const NodeRef& node_ref) noexcept {
|
||||
update_int64(node_ref.ref());
|
||||
update(node_ref.location());
|
||||
}
|
||||
|
||||
void update(const NodeRefList& node_refs) {
|
||||
void update(const NodeRefList& node_refs) noexcept {
|
||||
for (const NodeRef& node_ref : node_refs) {
|
||||
update(node_ref);
|
||||
}
|
||||
}
|
||||
|
||||
void update(const TagList& tags) {
|
||||
void update(const TagList& tags) noexcept {
|
||||
for (const Tag& tag : tags) {
|
||||
update_string(tag.key());
|
||||
update_string(tag.value());
|
||||
}
|
||||
}
|
||||
|
||||
void update(const osmium::RelationMember& member) {
|
||||
void update(const osmium::RelationMember& member) noexcept {
|
||||
update_int64(member.ref());
|
||||
update_int16(uint16_t(member.type()));
|
||||
update_string(member.role());
|
||||
}
|
||||
|
||||
void update(const osmium::RelationMemberList& members) {
|
||||
void update(const osmium::RelationMemberList& members) noexcept {
|
||||
for (const RelationMember& member : members) {
|
||||
update(member);
|
||||
}
|
||||
}
|
||||
|
||||
void update(const osmium::OSMObject& object) {
|
||||
void update(const osmium::OSMObject& object) noexcept {
|
||||
update_int64(object.id());
|
||||
update_bool(object.visible());
|
||||
update_int32(object.version());
|
||||
@ -195,22 +195,22 @@ namespace osmium {
|
||||
update(object.tags());
|
||||
}
|
||||
|
||||
void update(const osmium::Node& node) {
|
||||
void update(const osmium::Node& node) noexcept {
|
||||
update(static_cast<const osmium::OSMObject&>(node));
|
||||
update(node.location());
|
||||
}
|
||||
|
||||
void update(const osmium::Way& way) {
|
||||
void update(const osmium::Way& way) noexcept {
|
||||
update(static_cast<const osmium::OSMObject&>(way));
|
||||
update(way.nodes());
|
||||
}
|
||||
|
||||
void update(const osmium::Relation& relation) {
|
||||
void update(const osmium::Relation& relation) noexcept {
|
||||
update(static_cast<const osmium::OSMObject&>(relation));
|
||||
update(relation.members());
|
||||
}
|
||||
|
||||
void update(const osmium::Area& area) {
|
||||
void update(const osmium::Area& area) noexcept {
|
||||
update(static_cast<const osmium::OSMObject&>(area));
|
||||
for (const auto& subitem : area) {
|
||||
if (subitem.type() == osmium::item_type::outer_ring ||
|
||||
@ -220,7 +220,7 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
void update(const osmium::ChangesetDiscussion& discussion) {
|
||||
void update(const osmium::ChangesetDiscussion& discussion) noexcept {
|
||||
for (const auto& comment : discussion) {
|
||||
update(comment.date());
|
||||
update_int32(comment.uid());
|
||||
@ -229,7 +229,7 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
void update(const osmium::Changeset& changeset) {
|
||||
void update(const osmium::Changeset& changeset) noexcept {
|
||||
update_int64(changeset.id());
|
||||
update(changeset.created_at());
|
||||
update(changeset.closed_at());
|
||||
|
@ -60,7 +60,9 @@ namespace osmium {
|
||||
* assert(! (entities & osmium::osm_entity_bits::changeset));
|
||||
* @endcode
|
||||
*/
|
||||
enum type : unsigned char {
|
||||
enum type : unsigned char { // this should have been an enum class
|
||||
// but now we can't change it any more
|
||||
// without breaking lots of code
|
||||
|
||||
nothing = 0x00,
|
||||
node = 0x01,
|
||||
@ -75,8 +77,16 @@ namespace osmium {
|
||||
|
||||
}; // enum type
|
||||
|
||||
inline type operator|(const type lhs, const type rhs) noexcept {
|
||||
return static_cast<type>(static_cast<int>(lhs) | static_cast<int> (rhs));
|
||||
inline constexpr type operator|(const type lhs, const type rhs) noexcept {
|
||||
return static_cast<type>(static_cast<int>(lhs) | static_cast<int>(rhs));
|
||||
}
|
||||
|
||||
inline constexpr type operator&(const type lhs, const type rhs) noexcept {
|
||||
return static_cast<type>(static_cast<int>(lhs) & static_cast<int>(rhs));
|
||||
}
|
||||
|
||||
inline constexpr type operator~(const type value) noexcept {
|
||||
return all & static_cast<type>(~static_cast<int>(value));
|
||||
}
|
||||
|
||||
inline type& operator|=(type& lhs, const type rhs) noexcept {
|
||||
@ -84,14 +94,6 @@ namespace osmium {
|
||||
return lhs;
|
||||
}
|
||||
|
||||
inline type operator&(const type lhs, const type rhs) noexcept {
|
||||
return static_cast<type>(static_cast<int>(lhs) & static_cast<int> (rhs));
|
||||
}
|
||||
|
||||
inline type operator~(const type value) noexcept {
|
||||
return static_cast<type>(~static_cast<int>(value));
|
||||
}
|
||||
|
||||
inline type operator&=(type& lhs, const type rhs) noexcept {
|
||||
lhs = lhs & rhs;
|
||||
return lhs;
|
||||
@ -104,7 +106,7 @@ namespace osmium {
|
||||
* changeset.
|
||||
*/
|
||||
inline type from_item_type(osmium::item_type item_type) noexcept {
|
||||
auto ut = static_cast<std::underlying_type<osmium::item_type>::type>(item_type);
|
||||
const auto ut = static_cast<std::underlying_type<osmium::item_type>::type>(item_type);
|
||||
assert(ut <= 0x05);
|
||||
if (ut == 0) {
|
||||
return nothing;
|
||||
|
@ -86,23 +86,31 @@ namespace osmium {
|
||||
++str;
|
||||
}
|
||||
|
||||
// there has to be at least one digit
|
||||
if (*str >= '0' && *str <= '9') {
|
||||
result = *str - '0';
|
||||
++str;
|
||||
if (*str != '.') {
|
||||
// there has to be at least one digit
|
||||
if (*str >= '0' && *str <= '9') {
|
||||
result = *str - '0';
|
||||
++str;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// optional additional digits before decimal point
|
||||
while (*str >= '0' && *str <= '9' && max_digits > 0) {
|
||||
result = result * 10 + (*str - '0');
|
||||
++str;
|
||||
--max_digits;
|
||||
}
|
||||
|
||||
if (max_digits == 0) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// optional additional digits before decimal point
|
||||
while (*str >= '0' && *str <= '9' && max_digits > 0) {
|
||||
result = result * 10 + (*str - '0');
|
||||
++str;
|
||||
--max_digits;
|
||||
}
|
||||
|
||||
if (max_digits == 0) {
|
||||
goto error;
|
||||
// need at least one digit after decimal dot if there was no
|
||||
// digit before decimal dot
|
||||
if (*(str + 1) < '0' || *(str + 1) > '9') {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
// optional decimal point
|
||||
@ -163,18 +171,20 @@ namespace osmium {
|
||||
}
|
||||
|
||||
if (scale < 0) {
|
||||
result = 0;
|
||||
for (; scale < 0 && result > 0; ++scale) {
|
||||
result /= 10;
|
||||
}
|
||||
} else {
|
||||
for (; scale > 0; --scale) {
|
||||
result *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
result = (result + 5) / 10 * sign;
|
||||
result = (result + 5) / 10 * sign;
|
||||
|
||||
if (result > std::numeric_limits<int32_t>::max() ||
|
||||
result < std::numeric_limits<int32_t>::min()) {
|
||||
goto error;
|
||||
}
|
||||
if (result > std::numeric_limits<int32_t>::max() ||
|
||||
result < std::numeric_limits<int32_t>::min()) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
*data = str;
|
||||
|
@ -41,12 +41,14 @@ DEALINGS IN THE SOFTWARE.
|
||||
namespace osmium {
|
||||
|
||||
namespace builder {
|
||||
template <typename T> class ObjectBuilder;
|
||||
template <typename TDerived, typename T>
|
||||
class OSMObjectBuilder;
|
||||
} // namespace builder
|
||||
|
||||
class Node : public OSMObject {
|
||||
|
||||
friend class osmium::builder::ObjectBuilder<osmium::Node>;
|
||||
template <typename TDerived, typename T>
|
||||
friend class osmium::builder::OSMObjectBuilder;
|
||||
|
||||
osmium::Location m_location;
|
||||
|
||||
@ -62,7 +64,7 @@ namespace osmium {
|
||||
return m_location;
|
||||
}
|
||||
|
||||
Node& set_location(const osmium::Location& location) {
|
||||
Node& set_location(const osmium::Location& location) noexcept {
|
||||
m_location = location;
|
||||
return *this;
|
||||
}
|
||||
|
@ -52,12 +52,23 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
using value_type = NodeRef;
|
||||
using reference = NodeRef&;
|
||||
using const_reference = const NodeRef&;
|
||||
using iterator = NodeRef*;
|
||||
using const_iterator = const NodeRef*;
|
||||
using const_reverse_iterator = std::reverse_iterator<const NodeRef*>;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using size_type = std::size_t;
|
||||
|
||||
explicit NodeRefList(osmium::item_type itemtype) noexcept :
|
||||
osmium::memory::Item(sizeof(NodeRefList), itemtype) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the collection is empty.
|
||||
*
|
||||
* Complexity: Constant.
|
||||
*/
|
||||
bool empty() const noexcept {
|
||||
return sizeof(NodeRefList) == byte_size();
|
||||
@ -65,8 +76,10 @@ namespace osmium {
|
||||
|
||||
/**
|
||||
* Returns the number of NodeRefs in the collection.
|
||||
*
|
||||
* Complexity: Constant.
|
||||
*/
|
||||
size_t size() const noexcept {
|
||||
size_type size() const noexcept {
|
||||
const auto size_node_refs = byte_size() - sizeof(NodeRefList);
|
||||
assert(size_node_refs % sizeof(NodeRef) == 0);
|
||||
return size_node_refs / sizeof(NodeRef);
|
||||
@ -75,11 +88,13 @@ namespace osmium {
|
||||
/**
|
||||
* Access specified element.
|
||||
*
|
||||
* Complexity: Constant.
|
||||
*
|
||||
* @pre @code n < size() @endcode
|
||||
*
|
||||
* @param n Get the n-th element of the collection.
|
||||
*/
|
||||
const NodeRef& operator[](size_t n) const noexcept {
|
||||
const NodeRef& operator[](size_type n) const noexcept {
|
||||
assert(n < size());
|
||||
const NodeRef* node_ref = &*(cbegin());
|
||||
return node_ref[n];
|
||||
@ -88,6 +103,8 @@ namespace osmium {
|
||||
/**
|
||||
* Access the first element.
|
||||
*
|
||||
* Complexity: Constant.
|
||||
*
|
||||
* @pre @code !empty() @endcode
|
||||
*/
|
||||
const NodeRef& front() const noexcept {
|
||||
@ -98,6 +115,8 @@ namespace osmium {
|
||||
/**
|
||||
* Access the last element.
|
||||
*
|
||||
* Complexity: Constant.
|
||||
*
|
||||
* @pre @code !empty() @endcode
|
||||
*/
|
||||
const NodeRef& back() const noexcept {
|
||||
@ -109,6 +128,8 @@ namespace osmium {
|
||||
* Checks whether the first and last node in the collection have the
|
||||
* same ID. The locations are not checked.
|
||||
*
|
||||
* Complexity: Constant.
|
||||
*
|
||||
* @pre @code !empty() @endcode
|
||||
*/
|
||||
bool is_closed() const noexcept {
|
||||
@ -119,6 +140,8 @@ namespace osmium {
|
||||
* Checks whether the first and last node in the collection have the
|
||||
* same ID. The locations are not checked.
|
||||
*
|
||||
* Complexity: Constant.
|
||||
*
|
||||
* @pre @code !empty() @endcode
|
||||
*/
|
||||
bool ends_have_same_id() const noexcept {
|
||||
@ -129,6 +152,8 @@ namespace osmium {
|
||||
* Checks whether the first and last node in the collection have the
|
||||
* same location. The IDs are not checked.
|
||||
*
|
||||
* Complexity: Constant.
|
||||
*
|
||||
* @pre @code !empty() @endcode
|
||||
* @pre @code front().location() && back().location() @endcode
|
||||
*/
|
||||
@ -137,10 +162,6 @@ namespace osmium {
|
||||
return front().location() == back().location();
|
||||
}
|
||||
|
||||
using iterator = NodeRef*;
|
||||
using const_iterator = const NodeRef*;
|
||||
using const_reverse_iterator = std::reverse_iterator<const NodeRef*>;
|
||||
|
||||
/// Returns an iterator to the beginning.
|
||||
iterator begin() noexcept {
|
||||
return iterator(data() + sizeof(NodeRefList));
|
||||
|
@ -52,11 +52,19 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace builder {
|
||||
template <typename TDerived, typename T>
|
||||
class OSMObjectBuilder;
|
||||
} // namespace builder
|
||||
|
||||
/**
|
||||
* OSMObject (Node, Way, Relation, or Area).
|
||||
*/
|
||||
class OSMObject : public osmium::OSMEntity {
|
||||
|
||||
template <typename TDerived, typename T>
|
||||
friend class osmium::builder::OSMObjectBuilder;
|
||||
|
||||
object_id_type m_id;
|
||||
bool m_deleted : 1;
|
||||
object_version_type m_version : 31;
|
||||
|
@ -43,11 +43,14 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace builder {
|
||||
template <typename> class ObjectBuilder;
|
||||
template <typename TDerived, typename T>
|
||||
class OSMObjectBuilder;
|
||||
|
||||
class RelationMemberListBuilder;
|
||||
} // namespace builder
|
||||
|
||||
@ -109,7 +112,8 @@ namespace osmium {
|
||||
return m_ref;
|
||||
}
|
||||
|
||||
RelationMember& ref(object_id_type ref) noexcept {
|
||||
/// @deprecated Use set_ref() instead.
|
||||
OSMIUM_DEPRECATED RelationMember& ref(object_id_type ref) noexcept {
|
||||
m_ref = ref;
|
||||
return *this;
|
||||
}
|
||||
@ -149,23 +153,18 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
using size_type = size_t;
|
||||
|
||||
RelationMemberList() :
|
||||
osmium::memory::Collection<RelationMember, osmium::item_type::relation_member_list>() {
|
||||
}
|
||||
|
||||
size_type size() const noexcept {
|
||||
return static_cast<size_type>(std::distance(begin(), end()));
|
||||
}
|
||||
|
||||
}; // class RelationMemberList
|
||||
|
||||
static_assert(sizeof(RelationMemberList) % osmium::memory::align_bytes == 0, "Class osmium::RelationMemberList has wrong size to be aligned properly!");
|
||||
|
||||
class Relation : public OSMObject {
|
||||
|
||||
friend class osmium::builder::ObjectBuilder<osmium::Relation>;
|
||||
template <typename TDerived, typename T>
|
||||
friend class osmium::builder::OSMObjectBuilder;
|
||||
|
||||
Relation() noexcept :
|
||||
OSMObject(sizeof(Relation), osmium::item_type::relation) {
|
||||
|
@ -86,12 +86,14 @@ namespace osmium {
|
||||
|
||||
}; // class Tag
|
||||
|
||||
inline bool operator==(const Tag& a, const Tag& b) {
|
||||
return !std::strcmp(a.key(), b.key()) && !std::strcmp(a.value(), b.value());
|
||||
inline bool operator==(const Tag& lhs, const Tag& rhs) {
|
||||
return !std::strcmp(lhs.key(), rhs.key()) &&
|
||||
!std::strcmp(lhs.value(), rhs.value());
|
||||
}
|
||||
|
||||
inline bool operator<(const Tag& a, const Tag& b) {
|
||||
return (!std::strcmp(a.key(), b.key()) && (std::strcmp(a.value(), b.value()) < 0)) || (std::strcmp(a.key(), b.key()) < 0);
|
||||
inline bool operator<(const Tag& lhs, const Tag& rhs) {
|
||||
const auto c = std::strcmp(lhs.key(), rhs.key());
|
||||
return (c == 0 ? std::strcmp(lhs.value(), rhs.value()) : c) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -112,19 +114,10 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
using size_type = size_t;
|
||||
|
||||
TagList() :
|
||||
osmium::memory::Collection<Tag, osmium::item_type::tag_list>() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of tags in this tag list.
|
||||
*/
|
||||
size_type size() const noexcept {
|
||||
return static_cast<size_type>(std::distance(begin(), end()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tag value for the given tag key. If the key is not set, returns
|
||||
* the default_value.
|
||||
|
@ -44,7 +44,8 @@ DEALINGS IN THE SOFTWARE.
|
||||
namespace osmium {
|
||||
|
||||
namespace builder {
|
||||
template <typename T> class ObjectBuilder;
|
||||
template <typename TDerived, typename T>
|
||||
class OSMObjectBuilder;
|
||||
} // namespace builder
|
||||
|
||||
/**
|
||||
@ -66,7 +67,8 @@ namespace osmium {
|
||||
|
||||
class Way : public OSMObject {
|
||||
|
||||
friend class osmium::builder::ObjectBuilder<osmium::Way>;
|
||||
template <typename TDerived, typename T>
|
||||
friend class osmium::builder::OSMObjectBuilder;
|
||||
|
||||
Way() noexcept :
|
||||
OSMObject(sizeof(Way), osmium::item_type::way) {
|
||||
|
@ -40,6 +40,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
@ -353,7 +354,7 @@ namespace osmium {
|
||||
member_meta(member.type()).emplace_back(member.ref(), m_relations.size(), n);
|
||||
relation_meta.increment_need_members();
|
||||
} else {
|
||||
member.ref(0); // set member id to zero to indicate we are not interested
|
||||
member.set_ref(0); // set member id to zero to indicate we are not interested
|
||||
}
|
||||
++n;
|
||||
}
|
||||
@ -494,12 +495,65 @@ namespace osmium {
|
||||
return m_members_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the given member available in the members buffer?
|
||||
*
|
||||
* If you also need the offset of the object, use
|
||||
* get_availability_and_offset() instead, it is more efficient
|
||||
* that way.
|
||||
*
|
||||
* @param type Item type
|
||||
* @param id Object Id
|
||||
* @returns True if the object is available, false otherwise.
|
||||
*/
|
||||
bool is_available(osmium::item_type type, osmium::object_id_type id) {
|
||||
const auto range = find_member_meta(type, id);
|
||||
assert(!range.empty());
|
||||
return range.begin()->is_available();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get offset of a member in the members buffer.
|
||||
*
|
||||
* @pre The member must be available. If you are not sure, call
|
||||
* get_availability_and_offset() instead.
|
||||
* @param type Item type
|
||||
* @param id Object Id
|
||||
* @returns The offset of the object in the members buffer.
|
||||
*/
|
||||
size_t get_offset(osmium::item_type type, osmium::object_id_type id) {
|
||||
const auto range = find_member_meta(type, id);
|
||||
assert(!range.empty());
|
||||
assert(range.begin()->is_available());
|
||||
return range.begin()->buffer_offset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a member is available in the members buffer
|
||||
* and returns its offset.
|
||||
*
|
||||
* If the member is not available, the boolean returned as the
|
||||
* first element in the pair is false. In that case the offset
|
||||
* in the second element is undefined.
|
||||
*
|
||||
* If the member is available, the boolean returned as the first
|
||||
* element in the pair is true and the second element of the
|
||||
* pair contains the offset into the members buffer.
|
||||
*
|
||||
* @param type Item type
|
||||
* @param id Object Id
|
||||
* @returns Pair of bool (showing availability) and the offset.
|
||||
*/
|
||||
std::pair<bool, size_t> get_availability_and_offset(osmium::item_type type, osmium::object_id_type id) {
|
||||
const auto range = find_member_meta(type, id);
|
||||
assert(!range.empty());
|
||||
if (range.begin()->is_available()) {
|
||||
return std::make_pair(true, range.begin()->buffer_offset());
|
||||
} else {
|
||||
return std::make_pair(false, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TIter>
|
||||
void read_relations(TIter begin, TIter end) {
|
||||
HandlerPass1 handler(*static_cast<TCollector*>(this));
|
||||
@ -525,7 +579,7 @@ namespace osmium {
|
||||
/**
|
||||
* Decide whether to purge removed members and then do it.
|
||||
*
|
||||
* Currently the purging is done every thousand calls.
|
||||
* Currently the purging is done every 10000 calls.
|
||||
* This could probably be improved upon.
|
||||
*/
|
||||
void possibly_purge_removed_members() {
|
||||
|
@ -35,6 +35,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <cstddef>
|
||||
#include <iosfwd>
|
||||
#include <limits>
|
||||
|
||||
#include <osmium/osm/types.hpp>
|
||||
|
||||
@ -71,24 +72,44 @@ namespace osmium {
|
||||
|
||||
/**
|
||||
* Offset in the buffer where the object is stored.
|
||||
*
|
||||
* The default value is one that will never be valid, so it is
|
||||
* easier to catch problems.
|
||||
*/
|
||||
size_t m_buffer_offset { 0 };
|
||||
size_t m_buffer_offset = std::numeric_limits<size_t>::max();
|
||||
|
||||
/**
|
||||
* Has this member been found in the input data.
|
||||
*/
|
||||
bool m_available = false;
|
||||
|
||||
/**
|
||||
* Marks this member as removed. It can not be used any more.
|
||||
*/
|
||||
bool m_removed = false;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create new MemberMeta. The variant with zeros for relation_pos and
|
||||
* member_pos is used to create dummy MemberMeta that can be compared
|
||||
* to the MemberMeta in the vectors using the equal_range algorithm.
|
||||
* Create new MemberMeta.
|
||||
*/
|
||||
explicit MemberMeta(osmium::object_id_type member_id, size_t relation_pos=0, size_t member_pos=0) noexcept :
|
||||
explicit MemberMeta(osmium::object_id_type member_id, size_t relation_pos, size_t member_pos) noexcept :
|
||||
m_member_id(member_id),
|
||||
m_relation_pos(relation_pos),
|
||||
m_member_pos(member_pos) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new MemberMeta. This constructor is used to create
|
||||
* dummy MemberMeta objects that can be compared to the
|
||||
* MemberMetas in a vector using the equal_range algorithm.
|
||||
*/
|
||||
explicit MemberMeta(osmium::object_id_type member_id) noexcept :
|
||||
m_member_id(member_id),
|
||||
m_relation_pos(0),
|
||||
m_member_pos(0) {
|
||||
}
|
||||
|
||||
osmium::object_id_type member_id() const noexcept {
|
||||
return m_member_id;
|
||||
}
|
||||
@ -107,6 +128,11 @@ namespace osmium {
|
||||
|
||||
void set_buffer_offset(size_t offset) noexcept {
|
||||
m_buffer_offset = offset;
|
||||
m_available = true;
|
||||
}
|
||||
|
||||
bool is_available() const noexcept {
|
||||
return m_available;
|
||||
}
|
||||
|
||||
bool removed() const noexcept {
|
||||
@ -124,8 +150,8 @@ namespace osmium {
|
||||
* Used to sort a vector of MemberMeta objects and to later find
|
||||
* them using binary search.
|
||||
*/
|
||||
inline bool operator<(const MemberMeta& a, const MemberMeta& b) noexcept {
|
||||
return a.member_id() < b.member_id();
|
||||
inline bool operator<(const MemberMeta& lhs, const MemberMeta& rhs) noexcept {
|
||||
return lhs.member_id() < rhs.member_id();
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
|
@ -51,7 +51,7 @@ namespace osmium {
|
||||
|
||||
namespace thread {
|
||||
|
||||
static const std::chrono::milliseconds full_queue_sleep_duration { 10 }; // XXX
|
||||
static const std::chrono::milliseconds max_wait{10};
|
||||
|
||||
/**
|
||||
* A thread-safe queue.
|
||||
@ -70,9 +70,12 @@ namespace osmium {
|
||||
|
||||
std::queue<T> m_queue;
|
||||
|
||||
/// Used to signal readers when data is available in the queue.
|
||||
/// Used to signal consumers when data is available in the queue.
|
||||
std::condition_variable m_data_available;
|
||||
|
||||
/// Used to signal producers when queue is not full.
|
||||
std::condition_variable m_space_available;
|
||||
|
||||
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
|
||||
/// The largest size the queue has been so far.
|
||||
size_t m_largest_size;
|
||||
@ -109,7 +112,8 @@ namespace osmium {
|
||||
m_name(name),
|
||||
m_mutex(),
|
||||
m_queue(),
|
||||
m_data_available()
|
||||
m_data_available(),
|
||||
m_space_available()
|
||||
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
|
||||
,
|
||||
m_largest_size(0),
|
||||
@ -123,13 +127,20 @@ namespace osmium {
|
||||
|
||||
~Queue() {
|
||||
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
|
||||
std::cerr << "queue '" << m_name << "' with max_size=" << m_max_size << " had largest size " << m_largest_size << " and was full " << m_full_counter << " times in " << m_push_counter << " push() calls and was empty " << m_empty_counter << " times in " << m_pop_counter << " pop() calls\n";
|
||||
std::cerr << "queue '" << m_name
|
||||
<< "' with max_size=" << m_max_size
|
||||
<< " had largest size " << m_largest_size
|
||||
<< " and was full " << m_full_counter
|
||||
<< " times in " << m_push_counter
|
||||
<< " push() calls and was empty " << m_empty_counter
|
||||
<< " times in " << m_pop_counter
|
||||
<< " pop() calls\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Push an element onto the queue. If the queue has a max size, this
|
||||
* call will block if the queue is full.
|
||||
* Push an element onto the queue. If the queue has a max size,
|
||||
* this call will block if the queue is full.
|
||||
*/
|
||||
void push(T value) {
|
||||
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
|
||||
@ -137,13 +148,16 @@ namespace osmium {
|
||||
#endif
|
||||
if (m_max_size) {
|
||||
while (size() >= m_max_size) {
|
||||
std::this_thread::sleep_for(full_queue_sleep_duration);
|
||||
std::unique_lock<std::mutex> lock{m_mutex};
|
||||
m_space_available.wait_for(lock, max_wait, [this] {
|
||||
return m_queue.size() < m_max_size;
|
||||
});
|
||||
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
|
||||
++m_full_counter;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
m_queue.push(std::move(value));
|
||||
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
|
||||
if (m_largest_size < m_queue.size()) {
|
||||
@ -157,7 +171,7 @@ namespace osmium {
|
||||
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
|
||||
++m_pop_counter;
|
||||
#endif
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
std::unique_lock<std::mutex> lock{m_mutex};
|
||||
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
|
||||
if (m_queue.empty()) {
|
||||
++m_empty_counter;
|
||||
@ -169,6 +183,10 @@ namespace osmium {
|
||||
if (!m_queue.empty()) {
|
||||
value = std::move(m_queue.front());
|
||||
m_queue.pop();
|
||||
lock.unlock();
|
||||
if (m_max_size) {
|
||||
m_space_available.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,25 +194,30 @@ namespace osmium {
|
||||
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
|
||||
++m_pop_counter;
|
||||
#endif
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
if (m_queue.empty()) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
if (m_queue.empty()) {
|
||||
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
|
||||
++m_empty_counter;
|
||||
++m_empty_counter;
|
||||
#endif
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
value = std::move(m_queue.front());
|
||||
m_queue.pop();
|
||||
}
|
||||
if (m_max_size) {
|
||||
m_space_available.notify_one();
|
||||
}
|
||||
value = std::move(m_queue.front());
|
||||
m_queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
return m_queue.empty();
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
return m_queue.size();
|
||||
}
|
||||
|
||||
|
@ -172,6 +172,18 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the progress bar. Call this before doing any other output.
|
||||
* The next time update() is called, the progress bar will be visible
|
||||
* again.
|
||||
*/
|
||||
void remove() {
|
||||
if (m_enable) {
|
||||
std::cerr << spc() << " \r";
|
||||
m_prev_percent = 100 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
}; // class ProgressBar
|
||||
|
||||
} // namespace osmium
|
||||
|
@ -34,9 +34,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define LIBOSMIUM_VERSION_MAJOR 2
|
||||
#define LIBOSMIUM_VERSION_MINOR 9
|
||||
#define LIBOSMIUM_VERSION_MINOR 10
|
||||
#define LIBOSMIUM_VERSION_PATCH 0
|
||||
|
||||
#define LIBOSMIUM_VERSION_STRING "2.9.0"
|
||||
#define LIBOSMIUM_VERSION_STRING "2.10.0"
|
||||
|
||||
#endif // OSMIUM_VERSION_HPP
|
||||
|
@ -112,12 +112,6 @@ if(NOT Threads_FOUND)
|
||||
set(Threads_FOUND FALSE)
|
||||
endif()
|
||||
|
||||
if(GEOS_FOUND AND PROJ_FOUND)
|
||||
set(GEOS_AND_PROJ_FOUND TRUE)
|
||||
else()
|
||||
set(GEOS_AND_PROJ_FOUND FALSE)
|
||||
endif()
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
@ -127,45 +121,45 @@ endif()
|
||||
add_unit_test(area test_area_id)
|
||||
add_unit_test(area test_node_ref_segment)
|
||||
|
||||
add_unit_test(basic test_area)
|
||||
add_unit_test(basic test_box)
|
||||
add_unit_test(basic test_changeset)
|
||||
add_unit_test(basic test_crc)
|
||||
add_unit_test(basic test_entity_bits)
|
||||
add_unit_test(basic test_location)
|
||||
add_unit_test(basic test_node)
|
||||
add_unit_test(basic test_node_ref)
|
||||
add_unit_test(basic test_object_comparisons)
|
||||
add_unit_test(basic test_relation)
|
||||
add_unit_test(basic test_timestamp)
|
||||
add_unit_test(basic test_types_from_string)
|
||||
add_unit_test(basic test_way)
|
||||
add_unit_test(osm test_area)
|
||||
add_unit_test(osm test_box)
|
||||
add_unit_test(osm test_changeset)
|
||||
add_unit_test(osm test_crc)
|
||||
add_unit_test(osm test_entity_bits)
|
||||
add_unit_test(osm test_location)
|
||||
add_unit_test(osm test_node)
|
||||
add_unit_test(osm test_node_ref)
|
||||
add_unit_test(osm test_object_comparisons)
|
||||
add_unit_test(osm test_relation)
|
||||
add_unit_test(osm test_timestamp)
|
||||
add_unit_test(osm test_types_from_string)
|
||||
add_unit_test(osm test_way)
|
||||
|
||||
add_unit_test(buffer test_buffer_basics)
|
||||
add_unit_test(buffer test_buffer_node)
|
||||
add_unit_test(buffer test_buffer_purge)
|
||||
add_unit_test(memory test_buffer_basics)
|
||||
add_unit_test(memory test_buffer_node)
|
||||
add_unit_test(memory test_buffer_purge)
|
||||
|
||||
add_unit_test(builder test_attr)
|
||||
|
||||
add_unit_test(geom test_factory_with_projection
|
||||
ENABLE_IF ${GEOS_AND_PROJ_FOUND}
|
||||
LIBS ${GEOS_LIBRARY} ${PROJ_LIBRARY})
|
||||
add_unit_test(builder test_object_builder)
|
||||
|
||||
add_unit_test(geom test_crs ENABLE_IF ${PROJ_FOUND} LIBS ${PROJ_LIBRARY})
|
||||
add_unit_test(geom test_exception)
|
||||
add_unit_test(geom test_factory_with_projection ENABLE_IF ${PROJ_FOUND} LIBS ${PROJ_LIBRARY})
|
||||
add_unit_test(geom test_geojson)
|
||||
add_unit_test(geom test_geos ENABLE_IF ${GEOS_FOUND} LIBS ${GEOS_LIBRARY})
|
||||
add_unit_test(geom test_geos_wkb ENABLE_IF ${GEOS_FOUND} LIBS ${GEOS_LIBRARY})
|
||||
add_unit_test(geom test_mercator)
|
||||
add_unit_test(geom test_ogr ENABLE_IF ${GDAL_FOUND} LIBS ${GDAL_LIBRARY})
|
||||
add_unit_test(geom test_ogr_wkb ENABLE_IF ${GDAL_FOUND} LIBS ${GDAL_LIBRARY})
|
||||
add_unit_test(geom test_projection ENABLE_IF ${PROJ_FOUND} LIBS ${PROJ_LIBRARY})
|
||||
add_unit_test(geom test_tile ENABLE_IF ${GEOS_FOUND})
|
||||
add_unit_test(geom test_tile)
|
||||
add_unit_test(geom test_wkb)
|
||||
add_unit_test(geom test_wkt)
|
||||
|
||||
add_unit_test(index test_id_set)
|
||||
add_unit_test(index test_id_to_location ENABLE_IF ${SPARSEHASH_FOUND})
|
||||
add_unit_test(index test_file_based_index)
|
||||
|
||||
add_unit_test(io test_compression_factory)
|
||||
add_unit_test(io test_bzip2 ENABLE_IF ${BZIP2_FOUND} LIBS ${BZIP2_LIBRARIES})
|
||||
add_unit_test(io test_file_formats)
|
||||
add_unit_test(io test_reader LIBS "${OSMIUM_XML_LIBRARIES};${OSMIUM_PBF_LIBRARIES}")
|
||||
|
@ -83,7 +83,7 @@ header_buffer_type parse_xml(std::string input) {
|
||||
osmium::io::detail::add_to_queue(input_queue, std::move(input));
|
||||
osmium::io::detail::add_to_queue(input_queue, std::string{});
|
||||
|
||||
osmium::io::detail::XMLParser parser{input_queue, output_queue, header_promise, osmium::osm_entity_bits::all};
|
||||
osmium::io::detail::XMLParser parser{input_queue, output_queue, header_promise, osmium::io::detail::reader_options{}};
|
||||
parser.parse();
|
||||
|
||||
header_buffer_type result;
|
||||
|
21
test/examples/CMakeLists.txt
Normal file
21
test/examples/CMakeLists.txt
Normal file
@ -0,0 +1,21 @@
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
# CMake Config
|
||||
#
|
||||
# Libosmium example tests
|
||||
#
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
message(STATUS "Configuring example tests")
|
||||
|
||||
file(GLOB _dirs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/t/*)
|
||||
|
||||
foreach(_dir ${_dirs})
|
||||
message(STATUS " adding test: ${_dir}")
|
||||
add_subdirectory("${_dir}")
|
||||
endforeach()
|
||||
|
||||
message(STATUS "Configuring example tests - done")
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
7
test/examples/t/pub_names/CMakeLists.txt
Normal file
7
test/examples/t/pub_names/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
add_test(NAME examples_pub_names
|
||||
COMMAND osmium_pub_names ${CMAKE_CURRENT_SOURCE_DIR}/pubs.osm)
|
||||
|
||||
set_tests_properties(examples_pub_names PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "^Im Holze\n$")
|
||||
|
7
test/examples/t/pub_names/pubs.osm
Normal file
7
test/examples/t/pub_names/pubs.osm
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<osm version="0.6">
|
||||
<node id="167199652" version="3" timestamp="2010-12-27T13:15:02Z" uid="57645" user="KartoGrapHiti" changeset="6777507" lat="53.0526516" lon="8.8919477">
|
||||
<tag k="amenity" v="pub"/>
|
||||
<tag k="name" v="Im Holze"/>
|
||||
</node>
|
||||
</osm>
|
8
test/examples/t/road_length/CMakeLists.txt
Normal file
8
test/examples/t/road_length/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
add_test(NAME examples_road_length
|
||||
COMMAND osmium_road_length ${CMAKE_CURRENT_SOURCE_DIR}/road.osm)
|
||||
|
||||
set_tests_properties(examples_road_length PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "^Length: 0\\.405.*km\n$"
|
||||
)
|
||||
|
59
test/examples/t/road_length/road.osm
Normal file
59
test/examples/t/road_length/road.osm
Normal file
@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<osm version="0.6" generator="CGImap 0.3.3 (31041 thorn-01.openstreetmap.org)" copyright="OpenStreetMap and contributors" attribution="http://www.openstreetmap.org/copyright" license="http://opendatacommons.org/licenses/odbl/1-0/">
|
||||
<node id="5599384" visible="true" version="5" changeset="829716" timestamp="2009-03-18T17:16:26Z" user="burts" uid="97529" lat="51.0271601" lon="13.7252197"/>
|
||||
<node id="250384970" visible="true" version="3" changeset="855544" timestamp="2009-01-30T21:58:37Z" user="saftl" uid="7989" lat="51.0288568" lon="13.7248159">
|
||||
<tag k="created_by" v="JOSM"/>
|
||||
</node>
|
||||
<node id="250996316" visible="true" version="5" changeset="838711" timestamp="2009-03-21T13:10:39Z" user="burts" uid="97529" lat="51.0274683" lon="13.7251464"/>
|
||||
<node id="250996321" visible="true" version="3" changeset="855544" timestamp="2009-01-30T21:59:14Z" user="saftl" uid="7989" lat="51.0284283" lon="13.7249179">
|
||||
<tag k="created_by" v="JOSM"/>
|
||||
</node>
|
||||
<node id="252587568" visible="true" version="3" changeset="855544" timestamp="2009-01-30T21:58:45Z" user="saftl" uid="7989" lat="51.0275477" lon="13.7251275">
|
||||
<tag k="created_by" v="JOSM"/>
|
||||
</node>
|
||||
<node id="5599381" visible="true" version="6" changeset="15768585" timestamp="2013-04-18T01:20:26Z" user="Wolle DD" uid="1161559" lat="51.0307642" lon="13.7243263"/>
|
||||
<node id="1122039499" visible="true" version="2" changeset="26063898" timestamp="2014-10-14T04:09:11Z" user="Seandebasti" uid="550560" lat="51.0285248" lon="13.7248970"/>
|
||||
<node id="1122039521" visible="true" version="2" changeset="12753110" timestamp="2012-08-16T17:03:47Z" user="TEAM_CN_TUD" uid="716608" lat="51.0277456" lon="13.7250806"/>
|
||||
<node id="5599382" visible="true" version="6" changeset="8191054" timestamp="2011-05-19T16:19:51Z" user="stw1701" uid="102899" lat="51.0297991" lon="13.7245892"/>
|
||||
<node id="1299329303" visible="true" version="1" changeset="8242335" timestamp="2011-05-25T07:46:01Z" user="bigbug21" uid="15748" lat="51.0290875" lon="13.7247628"/>
|
||||
<node id="1868844753" visible="true" version="2" changeset="13260925" timestamp="2012-09-26T15:26:31Z" user="TEAM_CN_TUD" uid="716608" lat="51.0289617" lon="13.7247917"/>
|
||||
<node id="1868844765" visible="true" version="2" changeset="13260925" timestamp="2012-09-26T15:26:31Z" user="TEAM_CN_TUD" uid="716608" lat="51.0292872" lon="13.7247140"/>
|
||||
<node id="1868844782" visible="true" version="2" changeset="13260925" timestamp="2012-09-26T15:26:31Z" user="TEAM_CN_TUD" uid="716608" lat="51.0295717" lon="13.7246429"/>
|
||||
<node id="1922091528" visible="true" version="2" changeset="13260925" timestamp="2012-09-26T15:26:31Z" user="TEAM_CN_TUD" uid="716608" lat="51.0281700" lon="13.7249813"/>
|
||||
<node id="1953249124" visible="true" version="1" changeset="13418280" timestamp="2012-10-08T20:18:35Z" user="TEAM_CN_TUD" uid="716608" lat="51.0292437" lon="13.7247246"/>
|
||||
<node id="2015120752" visible="true" version="1" changeset="13883494" timestamp="2012-11-15T14:22:31Z" user="TEAM_CN_TUD" uid="716608" lat="51.0293536" lon="13.7246974"/>
|
||||
<node id="2056871900" visible="true" version="1" changeset="14207491" timestamp="2012-12-09T00:03:11Z" user="bigbug21" uid="15748" lat="51.0305821" lon="13.7243895"/>
|
||||
<node id="2458246647" visible="true" version="1" changeset="17836591" timestamp="2013-09-14T17:05:06Z" user="bigbug21" uid="15748" lat="51.0295979" lon="13.7246367"/>
|
||||
<node id="250384969" visible="true" version="4" changeset="17857555" timestamp="2013-09-15T20:17:55Z" user="4b696d" uid="1420318" lat="51.0282021" lon="13.7249734"/>
|
||||
<node id="3128723784" visible="true" version="1" changeset="26063898" timestamp="2014-10-14T04:09:07Z" user="Seandebasti" uid="550560" lat="51.0281018" lon="13.7249973"/>
|
||||
<way id="4428564" visible="true" version="21" changeset="26063898" timestamp="2014-10-14T04:09:13Z" user="Seandebasti" uid="550560">
|
||||
<nd ref="5599381"/>
|
||||
<nd ref="2056871900"/>
|
||||
<nd ref="5599382"/>
|
||||
<nd ref="2458246647"/>
|
||||
<nd ref="1868844782"/>
|
||||
<nd ref="2015120752"/>
|
||||
<nd ref="1868844765"/>
|
||||
<nd ref="1953249124"/>
|
||||
<nd ref="1299329303"/>
|
||||
<nd ref="1868844753"/>
|
||||
<nd ref="250384970"/>
|
||||
<nd ref="1122039499"/>
|
||||
<nd ref="250996321"/>
|
||||
<nd ref="250384969"/>
|
||||
<nd ref="1922091528"/>
|
||||
<nd ref="3128723784"/>
|
||||
<nd ref="1122039521"/>
|
||||
<nd ref="252587568"/>
|
||||
<nd ref="250996316"/>
|
||||
<nd ref="5599384"/>
|
||||
<tag k="highway" v="residential"/>
|
||||
<tag k="lit" v="yes"/>
|
||||
<tag k="maxspeed" v="30"/>
|
||||
<tag k="name" v="Helmholtzstraße"/>
|
||||
<tag k="postal_code" v="01069"/>
|
||||
<tag k="sidewalk" v="both"/>
|
||||
<tag k="smoothness" v="good"/>
|
||||
<tag k="surface" v="asphalt"/>
|
||||
</way>
|
||||
</osm>
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Catch v1.5.6
|
||||
* Generated: 2016-06-09 19:20:41.460328
|
||||
* Catch v1.5.8
|
||||
* Generated: 2016-10-26 12:07:30.938259
|
||||
* ----------------------------------------------------------
|
||||
* This file has been merged from multiple headers. Please don't edit it directly
|
||||
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
|
||||
@ -3223,10 +3223,11 @@ namespace Catch {
|
||||
|
||||
bool matches( TestCaseInfo const& testCase ) const {
|
||||
// All patterns in a filter must match for the filter to be a match
|
||||
for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it )
|
||||
for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) {
|
||||
if( !(*it)->matches( testCase ) )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@ -4719,8 +4720,11 @@ namespace Catch {
|
||||
std::string line;
|
||||
while( std::getline( f, line ) ) {
|
||||
line = trim(line);
|
||||
if( !line.empty() && !startsWith( line, "#" ) )
|
||||
addTestOrTags( config, "\"" + line + "\"," );
|
||||
if( !line.empty() && !startsWith( line, "#" ) ) {
|
||||
if( !startsWith( line, "\"" ) )
|
||||
line = "\"" + line + "\"";
|
||||
addTestOrTags( config, line + "," );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5368,7 +5372,10 @@ namespace Catch {
|
||||
++it ) {
|
||||
matchedTests++;
|
||||
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
|
||||
Catch::cout() << testCaseInfo.name << std::endl;
|
||||
if( startsWith( testCaseInfo.name, "#" ) )
|
||||
Catch::cout() << "\"" << testCaseInfo.name << "\"" << std::endl;
|
||||
else
|
||||
Catch::cout() << testCaseInfo.name << std::endl;
|
||||
}
|
||||
return matchedTests;
|
||||
}
|
||||
@ -6454,7 +6461,7 @@ namespace Catch {
|
||||
namespace Catch {
|
||||
|
||||
struct RandomNumberGenerator {
|
||||
typedef int result_type;
|
||||
typedef std::ptrdiff_t result_type;
|
||||
|
||||
result_type operator()( result_type n ) const { return std::rand() % n; }
|
||||
|
||||
@ -7571,7 +7578,7 @@ namespace Catch {
|
||||
return os;
|
||||
}
|
||||
|
||||
Version libraryVersion( 1, 5, 6, "", 0 );
|
||||
Version libraryVersion( 1, 5, 8, "", 0 );
|
||||
|
||||
}
|
||||
|
||||
@ -7802,8 +7809,11 @@ namespace Catch {
|
||||
bool contains( std::string const& s, std::string const& infix ) {
|
||||
return s.find( infix ) != std::string::npos;
|
||||
}
|
||||
char toLowerCh(char c) {
|
||||
return static_cast<char>( ::tolower( c ) );
|
||||
}
|
||||
void toLowerInPlace( std::string& s ) {
|
||||
std::transform( s.begin(), s.end(), s.begin(), ::tolower );
|
||||
std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
|
||||
}
|
||||
std::string toLower( std::string const& s ) {
|
||||
std::string lc = s;
|
||||
@ -8951,9 +8961,10 @@ namespace Catch {
|
||||
break;
|
||||
|
||||
default:
|
||||
// Escape control chars - based on contribution by @espenalb in PR #465
|
||||
// Escape control chars - based on contribution by @espenalb in PR #465 and
|
||||
// by @mrpi PR #588
|
||||
if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' )
|
||||
os << "&#x" << std::uppercase << std::hex << static_cast<int>( c );
|
||||
os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>( c ) << ';';
|
||||
else
|
||||
os << c;
|
||||
}
|
||||
@ -9008,13 +9019,20 @@ namespace Catch {
|
||||
: m_tagIsOpen( false ),
|
||||
m_needsNewline( false ),
|
||||
m_os( &Catch::cout() )
|
||||
{}
|
||||
{
|
||||
// We encode control characters, which requires
|
||||
// XML 1.1
|
||||
// see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
|
||||
*m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
|
||||
}
|
||||
|
||||
XmlWriter( std::ostream& os )
|
||||
: m_tagIsOpen( false ),
|
||||
m_needsNewline( false ),
|
||||
m_os( &os )
|
||||
{}
|
||||
{
|
||||
*m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
|
||||
}
|
||||
|
||||
~XmlWriter() {
|
||||
while( !m_tags.empty() )
|
||||
@ -9181,7 +9199,7 @@ namespace Catch {
|
||||
|
||||
virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
|
||||
StreamingReporterBase::testCaseStarting(testInfo);
|
||||
m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
|
||||
m_xml.startElement( "TestCase" ).writeAttribute( "name", testInfo.name );
|
||||
|
||||
if ( m_config->showDurations() == ShowDurations::Always )
|
||||
m_testCaseTimer.start();
|
||||
@ -9243,7 +9261,7 @@ namespace Catch {
|
||||
.writeText( assertionResult.getMessage() );
|
||||
break;
|
||||
case ResultWas::FatalErrorCondition:
|
||||
m_xml.scopedElement( "Fatal Error Condition" )
|
||||
m_xml.scopedElement( "FatalErrorCondition" )
|
||||
.writeAttribute( "filename", assertionResult.getSourceInfo().file )
|
||||
.writeAttribute( "line", assertionResult.getSourceInfo().line )
|
||||
.writeText( assertionResult.getMessage() );
|
||||
|
@ -1,32 +0,0 @@
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
|
||||
TEST_CASE("entity_bits") {
|
||||
|
||||
SECTION("can_be_set_and_checked") {
|
||||
osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::node | osmium::osm_entity_bits::way;
|
||||
REQUIRE(entities == (osmium::osm_entity_bits::node | osmium::osm_entity_bits::way));
|
||||
|
||||
entities |= osmium::osm_entity_bits::relation;
|
||||
REQUIRE((entities & osmium::osm_entity_bits::object));
|
||||
|
||||
entities |= osmium::osm_entity_bits::area;
|
||||
REQUIRE(entities == osmium::osm_entity_bits::object);
|
||||
|
||||
REQUIRE(! (entities & osmium::osm_entity_bits::changeset));
|
||||
|
||||
entities &= osmium::osm_entity_bits::node;
|
||||
REQUIRE((entities & osmium::osm_entity_bits::node));
|
||||
REQUIRE(! (entities & osmium::osm_entity_bits::way));
|
||||
REQUIRE(entities == osmium::osm_entity_bits::node);
|
||||
|
||||
REQUIRE(osmium::osm_entity_bits::nothing == osmium::osm_entity_bits::from_item_type(osmium::item_type::undefined));
|
||||
REQUIRE(osmium::osm_entity_bits::node == osmium::osm_entity_bits::from_item_type(osmium::item_type::node));
|
||||
REQUIRE(osmium::osm_entity_bits::way == osmium::osm_entity_bits::from_item_type(osmium::item_type::way));
|
||||
REQUIRE(osmium::osm_entity_bits::relation == osmium::osm_entity_bits::from_item_type(osmium::item_type::relation));
|
||||
REQUIRE(osmium::osm_entity_bits::changeset == osmium::osm_entity_bits::from_item_type(osmium::item_type::changeset));
|
||||
REQUIRE(osmium::osm_entity_bits::area == osmium::osm_entity_bits::from_item_type(osmium::item_type::area));
|
||||
}
|
||||
|
||||
}
|
444
test/t/builder/test_object_builder.cpp
Normal file
444
test/t/builder/test_object_builder.cpp
Normal file
@ -0,0 +1,444 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm.hpp>
|
||||
|
||||
TEST_CASE("create objects using builder") {
|
||||
osmium::memory::Buffer buffer{1024*10};
|
||||
std::string user;
|
||||
|
||||
SECTION("complete node with tags") {
|
||||
SECTION("user length 0") {
|
||||
user = "";
|
||||
}
|
||||
SECTION("user length 1") {
|
||||
user = "1";
|
||||
}
|
||||
SECTION("user length 2") {
|
||||
user = "12";
|
||||
}
|
||||
SECTION("user length 3") {
|
||||
user = "123";
|
||||
}
|
||||
SECTION("user length 4") {
|
||||
user = "1234";
|
||||
}
|
||||
SECTION("user length 5") {
|
||||
user = "12345";
|
||||
}
|
||||
SECTION("user length 6") {
|
||||
user = "123456";
|
||||
}
|
||||
SECTION("user length 7") {
|
||||
user = "1234567";
|
||||
}
|
||||
SECTION("user length 8") {
|
||||
user = "12345678";
|
||||
}
|
||||
SECTION("user length 9") {
|
||||
user = "123456789";
|
||||
}
|
||||
SECTION("user length 10") {
|
||||
user = "1234567890";
|
||||
}
|
||||
SECTION("user length 11") {
|
||||
user = "12345678901";
|
||||
}
|
||||
SECTION("user length 12") {
|
||||
user = "123456789012";
|
||||
}
|
||||
SECTION("user length 13") {
|
||||
user = "1234567890123";
|
||||
}
|
||||
SECTION("user length 14") {
|
||||
user = "12345678901234";
|
||||
}
|
||||
SECTION("user length 15") {
|
||||
user = "123456789012345";
|
||||
}
|
||||
SECTION("user length 16") {
|
||||
user = "1234567890123456";
|
||||
}
|
||||
SECTION("user length 17") {
|
||||
user = "12345678901234567";
|
||||
}
|
||||
SECTION("user length 18") {
|
||||
user = "123456789012345678";
|
||||
}
|
||||
|
||||
osmium::Location loc{1.2, 3.4};
|
||||
|
||||
{
|
||||
osmium::builder::NodeBuilder builder{buffer};
|
||||
|
||||
builder.set_id(17)
|
||||
.set_visible(true)
|
||||
.set_version(1)
|
||||
.set_changeset(123)
|
||||
.set_uid(555)
|
||||
.set_timestamp("2015-07-01T00:00:01Z")
|
||||
.set_location(loc)
|
||||
.set_user(user);
|
||||
|
||||
builder.add_tags({{"highway", "primary"}, {"oneway", "yes"}});
|
||||
}
|
||||
|
||||
const auto& node = buffer.get<osmium::Node>(buffer.commit());
|
||||
|
||||
REQUIRE(node.id() == 17);
|
||||
REQUIRE(node.version() == 1);
|
||||
REQUIRE(node.changeset() == 123);
|
||||
REQUIRE(node.uid() == 555);
|
||||
REQUIRE(node.timestamp() == osmium::Timestamp{"2015-07-01T00:00:01Z"});
|
||||
REQUIRE(node.location() == loc);
|
||||
|
||||
REQUIRE(user == node.user());
|
||||
|
||||
REQUIRE(node.tags().size() == 2);
|
||||
}
|
||||
|
||||
SECTION("complete way with tags") {
|
||||
SECTION("user length 0") {
|
||||
user = "";
|
||||
}
|
||||
SECTION("user length 1") {
|
||||
user = "1";
|
||||
}
|
||||
SECTION("user length 2") {
|
||||
user = "12";
|
||||
}
|
||||
SECTION("user length 3") {
|
||||
user = "123";
|
||||
}
|
||||
SECTION("user length 4") {
|
||||
user = "1234";
|
||||
}
|
||||
SECTION("user length 5") {
|
||||
user = "12345";
|
||||
}
|
||||
SECTION("user length 6") {
|
||||
user = "123456";
|
||||
}
|
||||
SECTION("user length 7") {
|
||||
user = "1234567";
|
||||
}
|
||||
SECTION("user length 8") {
|
||||
user = "12345678";
|
||||
}
|
||||
SECTION("user length 9") {
|
||||
user = "123456789";
|
||||
}
|
||||
SECTION("user length 10") {
|
||||
user = "1234567890";
|
||||
}
|
||||
SECTION("user length 11") {
|
||||
user = "12345678901";
|
||||
}
|
||||
SECTION("user length 12") {
|
||||
user = "123456789012";
|
||||
}
|
||||
SECTION("user length 13") {
|
||||
user = "1234567890123";
|
||||
}
|
||||
SECTION("user length 14") {
|
||||
user = "12345678901234";
|
||||
}
|
||||
SECTION("user length 15") {
|
||||
user = "123456789012345";
|
||||
}
|
||||
SECTION("user length 16") {
|
||||
user = "1234567890123456";
|
||||
}
|
||||
SECTION("user length 17") {
|
||||
user = "12345678901234567";
|
||||
}
|
||||
SECTION("user length 18") {
|
||||
user = "123456789012345678";
|
||||
}
|
||||
|
||||
{
|
||||
osmium::builder::WayBuilder builder{buffer};
|
||||
|
||||
builder.set_id(17)
|
||||
.set_visible(true)
|
||||
.set_version(1)
|
||||
.set_changeset(123)
|
||||
.set_uid(555)
|
||||
.set_timestamp("2015-07-01T00:00:01Z")
|
||||
.set_user(user);
|
||||
|
||||
builder.add_tags({{"highway", "primary"}, {"oneway", "yes"}});
|
||||
}
|
||||
|
||||
const auto& way = buffer.get<osmium::Way>(buffer.commit());
|
||||
|
||||
REQUIRE(way.id() == 17);
|
||||
REQUIRE(way.version() == 1);
|
||||
REQUIRE(way.changeset() == 123);
|
||||
REQUIRE(way.uid() == 555);
|
||||
REQUIRE(way.timestamp() == osmium::Timestamp{"2015-07-01T00:00:01Z"});
|
||||
|
||||
REQUIRE(user == way.user());
|
||||
|
||||
REQUIRE(way.tags().size() == 2);
|
||||
}
|
||||
|
||||
SECTION("complete relation with tags") {
|
||||
SECTION("user length 0") {
|
||||
user = "";
|
||||
}
|
||||
SECTION("user length 1") {
|
||||
user = "1";
|
||||
}
|
||||
SECTION("user length 2") {
|
||||
user = "12";
|
||||
}
|
||||
SECTION("user length 3") {
|
||||
user = "123";
|
||||
}
|
||||
SECTION("user length 4") {
|
||||
user = "1234";
|
||||
}
|
||||
SECTION("user length 5") {
|
||||
user = "12345";
|
||||
}
|
||||
SECTION("user length 6") {
|
||||
user = "123456";
|
||||
}
|
||||
SECTION("user length 7") {
|
||||
user = "1234567";
|
||||
}
|
||||
SECTION("user length 8") {
|
||||
user = "12345678";
|
||||
}
|
||||
SECTION("user length 9") {
|
||||
user = "123456789";
|
||||
}
|
||||
SECTION("user length 10") {
|
||||
user = "1234567890";
|
||||
}
|
||||
SECTION("user length 11") {
|
||||
user = "12345678901";
|
||||
}
|
||||
SECTION("user length 12") {
|
||||
user = "123456789012";
|
||||
}
|
||||
SECTION("user length 13") {
|
||||
user = "1234567890123";
|
||||
}
|
||||
SECTION("user length 14") {
|
||||
user = "12345678901234";
|
||||
}
|
||||
SECTION("user length 15") {
|
||||
user = "123456789012345";
|
||||
}
|
||||
SECTION("user length 16") {
|
||||
user = "1234567890123456";
|
||||
}
|
||||
SECTION("user length 17") {
|
||||
user = "12345678901234567";
|
||||
}
|
||||
SECTION("user length 18") {
|
||||
user = "123456789012345678";
|
||||
}
|
||||
|
||||
{
|
||||
osmium::builder::RelationBuilder builder{buffer};
|
||||
|
||||
builder.set_id(17)
|
||||
.set_visible(true)
|
||||
.set_version(1)
|
||||
.set_changeset(123)
|
||||
.set_uid(555)
|
||||
.set_timestamp("2015-07-01T00:00:01Z")
|
||||
.set_user(user);
|
||||
|
||||
builder.add_tags({{"highway", "primary"}, {"oneway", "yes"}});
|
||||
}
|
||||
|
||||
const auto& relation = buffer.get<osmium::Relation>(buffer.commit());
|
||||
|
||||
REQUIRE(relation.id() == 17);
|
||||
REQUIRE(relation.version() == 1);
|
||||
REQUIRE(relation.changeset() == 123);
|
||||
REQUIRE(relation.uid() == 555);
|
||||
REQUIRE(relation.timestamp() == osmium::Timestamp{"2015-07-01T00:00:01Z"});
|
||||
|
||||
REQUIRE(user == relation.user());
|
||||
|
||||
REQUIRE(relation.tags().size() == 2);
|
||||
}
|
||||
|
||||
SECTION("complete changeset with tags") {
|
||||
osmium::Location bl{-1.2, -3.4};
|
||||
osmium::Location tr{1.2, 3.4};
|
||||
|
||||
SECTION("user length 0") {
|
||||
user = "";
|
||||
}
|
||||
SECTION("user length 1") {
|
||||
user = "1";
|
||||
}
|
||||
SECTION("user length 2") {
|
||||
user = "12";
|
||||
}
|
||||
SECTION("user length 3") {
|
||||
user = "123";
|
||||
}
|
||||
SECTION("user length 4") {
|
||||
user = "1234";
|
||||
}
|
||||
SECTION("user length 5") {
|
||||
user = "12345";
|
||||
}
|
||||
SECTION("user length 6") {
|
||||
user = "123456";
|
||||
}
|
||||
SECTION("user length 7") {
|
||||
user = "1234567";
|
||||
}
|
||||
SECTION("user length 8") {
|
||||
user = "12345678";
|
||||
}
|
||||
SECTION("user length 9") {
|
||||
user = "123456789";
|
||||
}
|
||||
SECTION("user length 10") {
|
||||
user = "1234567890";
|
||||
}
|
||||
SECTION("user length 11") {
|
||||
user = "12345678901";
|
||||
}
|
||||
SECTION("user length 12") {
|
||||
user = "123456789012";
|
||||
}
|
||||
SECTION("user length 13") {
|
||||
user = "1234567890123";
|
||||
}
|
||||
SECTION("user length 14") {
|
||||
user = "12345678901234";
|
||||
}
|
||||
SECTION("user length 15") {
|
||||
user = "123456789012345";
|
||||
}
|
||||
SECTION("user length 16") {
|
||||
user = "1234567890123456";
|
||||
}
|
||||
SECTION("user length 17") {
|
||||
user = "12345678901234567";
|
||||
}
|
||||
SECTION("user length 18") {
|
||||
user = "123456789012345678";
|
||||
}
|
||||
|
||||
{
|
||||
osmium::builder::ChangesetBuilder builder{buffer};
|
||||
|
||||
builder.set_id(17)
|
||||
.set_uid(222)
|
||||
.set_created_at(osmium::Timestamp{"2016-07-03T01:23:45Z"})
|
||||
.set_closed_at(osmium::Timestamp{"2016-07-03T01:23:48Z"})
|
||||
.set_num_changes(3)
|
||||
.set_num_comments(2)
|
||||
.set_bounds(osmium::Box{bl, tr})
|
||||
.set_user(user);
|
||||
}
|
||||
|
||||
const auto& changeset = buffer.get<osmium::Changeset>(buffer.commit());
|
||||
|
||||
REQUIRE(changeset.id() == 17);
|
||||
REQUIRE(changeset.uid() == 222);
|
||||
REQUIRE(changeset.created_at() == osmium::Timestamp{"2016-07-03T01:23:45Z"});
|
||||
REQUIRE(changeset.closed_at() == osmium::Timestamp{"2016-07-03T01:23:48Z"});
|
||||
REQUIRE(changeset.num_changes() == 3);
|
||||
REQUIRE(changeset.num_comments() == 2);
|
||||
|
||||
const auto& box = changeset.bounds();
|
||||
REQUIRE(box.bottom_left() == bl);
|
||||
REQUIRE(box.top_right() == tr);
|
||||
|
||||
REQUIRE(user == changeset.user());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("no call to set_user on node") {
|
||||
osmium::memory::Buffer buffer{1024*10};
|
||||
|
||||
{
|
||||
osmium::builder::NodeBuilder builder{buffer};
|
||||
}
|
||||
|
||||
const auto& node = buffer.get<osmium::Node>(buffer.commit());
|
||||
|
||||
REQUIRE(*node.user() == '\0');
|
||||
}
|
||||
|
||||
TEST_CASE("set_user with length on node") {
|
||||
osmium::memory::Buffer buffer{1024*10};
|
||||
std::string user = "userx";
|
||||
|
||||
{
|
||||
osmium::builder::NodeBuilder builder{buffer};
|
||||
builder.set_user(user.c_str(), 4);
|
||||
}
|
||||
|
||||
const auto& node = buffer.get<osmium::Node>(buffer.commit());
|
||||
|
||||
REQUIRE(std::string{"user"} == node.user());
|
||||
}
|
||||
|
||||
TEST_CASE("no call to set_user on way") {
|
||||
osmium::memory::Buffer buffer{1024*10};
|
||||
|
||||
{
|
||||
osmium::builder::WayBuilder builder{buffer};
|
||||
}
|
||||
|
||||
const auto& way = buffer.get<osmium::Way>(buffer.commit());
|
||||
|
||||
REQUIRE(*way.user() == '\0');
|
||||
}
|
||||
|
||||
TEST_CASE("set_user with length on way") {
|
||||
osmium::memory::Buffer buffer{1024*10};
|
||||
std::string user = "userx";
|
||||
|
||||
{
|
||||
osmium::builder::WayBuilder builder{buffer};
|
||||
builder.set_user(user.c_str(), 4);
|
||||
}
|
||||
|
||||
const auto& way = buffer.get<osmium::Way>(buffer.commit());
|
||||
|
||||
REQUIRE(std::string{"user"} == way.user());
|
||||
}
|
||||
|
||||
TEST_CASE("no call to set_user on changeset") {
|
||||
osmium::memory::Buffer buffer{1024*10};
|
||||
|
||||
{
|
||||
osmium::builder::ChangesetBuilder builder{buffer};
|
||||
}
|
||||
|
||||
const auto& changeset = buffer.get<osmium::Changeset>(buffer.commit());
|
||||
|
||||
REQUIRE(*changeset.user() == '\0');
|
||||
}
|
||||
|
||||
TEST_CASE("set_user with length on changeset") {
|
||||
osmium::memory::Buffer buffer{1024*10};
|
||||
std::string user = "userx";
|
||||
|
||||
{
|
||||
osmium::builder::ChangesetBuilder builder{buffer};
|
||||
builder.set_user(user.c_str(), 4);
|
||||
}
|
||||
|
||||
const auto& changeset = buffer.get<osmium::Changeset>(buffer.commit());
|
||||
|
||||
REQUIRE(std::string{"user"} == changeset.user());
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
#ifndef TEST_GEOM_HELPER_HPP
|
||||
#define TEST_GEOM_HELPER_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <geos/io/WKBWriter.h>
|
||||
|
||||
inline std::string geos_to_wkb(const geos::geom::Geometry* geometry) {
|
||||
std::stringstream ss;
|
||||
geos::io::WKBWriter wkb_writer;
|
||||
wkb_writer.writeHEX(*geometry, ss);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
#endif // TEST_GEOM_HELPER_HPP
|
@ -5,12 +5,12 @@
|
||||
#include <osmium/geom/projection.hpp>
|
||||
|
||||
TEST_CASE("CRS") {
|
||||
osmium::geom::CRS wgs84{4326};
|
||||
osmium::geom::CRS mercator{3857};
|
||||
const osmium::geom::CRS wgs84{4326};
|
||||
const osmium::geom::CRS mercator{3857};
|
||||
|
||||
osmium::geom::Coordinates c{osmium::geom::deg_to_rad(1.2), osmium::geom::deg_to_rad(3.4)};
|
||||
auto ct = osmium::geom::transform(wgs84, mercator, c);
|
||||
auto c2 = osmium::geom::transform(mercator, wgs84, ct);
|
||||
const osmium::geom::Coordinates c{osmium::geom::deg_to_rad(1.2), osmium::geom::deg_to_rad(3.4)};
|
||||
const auto ct = osmium::geom::transform(wgs84, mercator, c);
|
||||
const auto c2 = osmium::geom::transform(mercator, wgs84, ct);
|
||||
|
||||
REQUIRE(c.x == Approx(c2.x));
|
||||
REQUIRE(c.y == Approx(c2.y));
|
||||
|
@ -6,11 +6,9 @@
|
||||
|
||||
TEST_CASE("Geometry exception") {
|
||||
|
||||
SECTION("geometry_error") {
|
||||
osmium::geometry_error e("some error message", "node", 17);
|
||||
REQUIRE(e.id() == 17);
|
||||
REQUIRE(std::string(e.what()) == "some error message (node_id=17)");
|
||||
}
|
||||
osmium::geometry_error e{"some error message", "node", 17};
|
||||
REQUIRE(e.id() == 17);
|
||||
REQUIRE(std::string{e.what()} == "some error message (node_id=17)");
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,41 +1,21 @@
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <osmium/geom/geos.hpp>
|
||||
#include <osmium/geom/mercator_projection.hpp>
|
||||
#include <osmium/geom/projection.hpp>
|
||||
#include <osmium/geom/wkb.hpp>
|
||||
#include <osmium/geom/wkt.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
TEST_CASE("Projection") {
|
||||
|
||||
SECTION("point_mercator") {
|
||||
osmium::geom::WKTFactory<osmium::geom::MercatorProjection> factory(2);
|
||||
|
||||
std::string wkt {factory.create_point(osmium::Location(3.2, 4.2))};
|
||||
REQUIRE(std::string {"POINT(356222.37 467961.14)"} == wkt);
|
||||
}
|
||||
|
||||
SECTION("point_epsg_3857") {
|
||||
osmium::geom::WKTFactory<osmium::geom::Projection> factory(osmium::geom::Projection(3857), 2);
|
||||
|
||||
std::string wkt {factory.create_point(osmium::Location(3.2, 4.2))};
|
||||
REQUIRE(std::string {"POINT(356222.37 467961.14)"} == wkt);
|
||||
}
|
||||
|
||||
SECTION("wkb_with_parameter") {
|
||||
osmium::geom::WKBFactory<osmium::geom::Projection> wkb_factory(osmium::geom::Projection(3857), osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::GEOSFactory<osmium::geom::Projection> geos_factory(osmium::geom::Projection(3857));
|
||||
|
||||
std::string wkb = wkb_factory.create_point(osmium::Location(3.2, 4.2));
|
||||
std::unique_ptr<geos::geom::Point> geos_point = geos_factory.create_point(osmium::Location(3.2, 4.2));
|
||||
REQUIRE(geos_to_wkb(geos_point.get()) == wkb);
|
||||
}
|
||||
|
||||
SECTION("cleanup") {
|
||||
// trying to make valgrind happy, but there is still a memory leak in proj library
|
||||
pj_deallocate_grids();
|
||||
}
|
||||
TEST_CASE("Projection using MercatorProjection class to WKT") {
|
||||
osmium::geom::WKTFactory<osmium::geom::MercatorProjection> factory{2};
|
||||
|
||||
const std::string wkt{factory.create_point(osmium::Location{3.2, 4.2})};
|
||||
REQUIRE(wkt == "POINT(356222.37 467961.14)");
|
||||
}
|
||||
|
||||
TEST_CASE("Projection using Projection class to WKT") {
|
||||
osmium::geom::WKTFactory<osmium::geom::Projection> factory{osmium::geom::Projection{3857}, 2};
|
||||
|
||||
const std::string wkt{factory.create_point(osmium::Location{3.2, 4.2})};
|
||||
REQUIRE(wkt == "POINT(356222.37 467961.14)");
|
||||
}
|
||||
|
||||
|
@ -5,162 +5,143 @@
|
||||
#include "area_helper.hpp"
|
||||
#include "wnl_helper.hpp"
|
||||
|
||||
TEST_CASE("GeoJSON_Geometry") {
|
||||
|
||||
SECTION("point") {
|
||||
TEST_CASE("GeoJSON point geometry") {
|
||||
osmium::geom::GeoJSONFactory<> factory;
|
||||
|
||||
std::string json {factory.create_point(osmium::Location(3.2, 4.2))};
|
||||
REQUIRE(std::string{"{\"type\":\"Point\",\"coordinates\":[3.2,4.2]}"} == json);
|
||||
SECTION("point") {
|
||||
const std::string json{factory.create_point(osmium::Location{3.2, 4.2})};
|
||||
REQUIRE(std::string{"{\"type\":\"Point\",\"coordinates\":[3.2,4.2]}"} == json);
|
||||
}
|
||||
|
||||
SECTION("empty_point") {
|
||||
REQUIRE_THROWS_AS(factory.create_point(osmium::Location{}), osmium::invalid_location);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SECTION("empty_point") {
|
||||
TEST_CASE("GeoJSON linestring geometry") {
|
||||
osmium::geom::GeoJSONFactory<> factory;
|
||||
osmium::memory::Buffer buffer{1000};
|
||||
|
||||
REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
|
||||
}
|
||||
|
||||
SECTION("linestring") {
|
||||
osmium::geom::GeoJSONFactory<> factory;
|
||||
|
||||
osmium::memory::Buffer buffer(1000);
|
||||
auto &wnl = create_test_wnl_okay(buffer);
|
||||
|
||||
{
|
||||
std::string json {factory.create_linestring(wnl)};
|
||||
SECTION("linestring, default") {
|
||||
const auto& wnl = create_test_wnl_okay(buffer);
|
||||
const std::string json{factory.create_linestring(wnl)};
|
||||
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.2,4.2],[3.5,4.7],[3.6,4.9]]}"} == json);
|
||||
}
|
||||
|
||||
{
|
||||
std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
|
||||
SECTION("linestring, unique, backwards") {
|
||||
const auto& wnl = create_test_wnl_okay(buffer);
|
||||
const std::string json{factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
|
||||
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.6,4.9],[3.5,4.7],[3.2,4.2]]}"} == json);
|
||||
}
|
||||
|
||||
{
|
||||
std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
|
||||
SECTION("linestring, all") {
|
||||
const auto& wnl = create_test_wnl_okay(buffer);
|
||||
const std::string json{factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
|
||||
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.2,4.2],[3.5,4.7],[3.5,4.7],[3.6,4.9]]}"} == json);
|
||||
}
|
||||
|
||||
{
|
||||
std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
|
||||
SECTION("linestring, all, backwards") {
|
||||
const auto& wnl = create_test_wnl_okay(buffer);
|
||||
const std::string json{factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
|
||||
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.6,4.9],[3.5,4.7],[3.5,4.7],[3.2,4.2]]}"} == json);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("empty_linestring") {
|
||||
osmium::geom::GeoJSONFactory<> factory;
|
||||
SECTION("empty_linestring") {
|
||||
const auto& wnl = create_test_wnl_empty(buffer);
|
||||
|
||||
osmium::memory::Buffer buffer(1000);
|
||||
auto& wnl = create_test_wnl_empty(buffer);
|
||||
|
||||
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
|
||||
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
|
||||
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
|
||||
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
|
||||
}
|
||||
|
||||
SECTION("linestring_with_two_same_locations") {
|
||||
osmium::geom::GeoJSONFactory<> factory;
|
||||
|
||||
osmium::memory::Buffer buffer(1000);
|
||||
auto& wnl = create_test_wnl_same_location(buffer);
|
||||
|
||||
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
|
||||
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
|
||||
|
||||
{
|
||||
std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
|
||||
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.5,4.7],[3.5,4.7]]}"} == json);
|
||||
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
|
||||
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
|
||||
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
|
||||
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
|
||||
}
|
||||
|
||||
{
|
||||
std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
|
||||
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.5,4.7],[3.5,4.7]]}"} == json);
|
||||
SECTION("linestring with two same locations") {
|
||||
const auto& wnl = create_test_wnl_same_location(buffer);
|
||||
|
||||
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
|
||||
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
|
||||
|
||||
{
|
||||
const std::string json{factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
|
||||
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.5,4.7],[3.5,4.7]]}"} == json);
|
||||
}
|
||||
|
||||
{
|
||||
const std::string json{factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
|
||||
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.5,4.7],[3.5,4.7]]}"} == json);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("linestring with undefined location") {
|
||||
const auto& wnl = create_test_wnl_undefined_location(buffer);
|
||||
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SECTION("linestring_with_undefined_location") {
|
||||
TEST_CASE("GeoJSON area geometry") {
|
||||
osmium::geom::GeoJSONFactory<> factory;
|
||||
osmium::memory::Buffer buffer{1000};
|
||||
|
||||
osmium::memory::Buffer buffer(1000);
|
||||
auto& wnl = create_test_wnl_undefined_location(buffer);
|
||||
SECTION("area_1outer_0inner") {
|
||||
const osmium::Area& area = create_test_area_1outer_0inner(buffer);
|
||||
|
||||
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
|
||||
}
|
||||
REQUIRE(!area.is_multipolygon());
|
||||
REQUIRE(std::distance(area.cbegin(), area.cend()) == 2);
|
||||
REQUIRE(area.subitems<osmium::OuterRing>().size() == area.num_rings().first);
|
||||
|
||||
SECTION("area_1outer_0inner") {
|
||||
osmium::geom::GeoJSONFactory<> factory;
|
||||
|
||||
osmium::memory::Buffer buffer(1000);
|
||||
const osmium::Area& area = create_test_area_1outer_0inner(buffer);
|
||||
|
||||
REQUIRE(!area.is_multipolygon());
|
||||
REQUIRE(std::distance(area.cbegin(), area.cend()) == 2);
|
||||
REQUIRE(area.subitems<osmium::OuterRing>().size() == area.num_rings().first);
|
||||
|
||||
{
|
||||
std::string json {factory.create_multipolygon(area)};
|
||||
std::string json{factory.create_multipolygon(area)};
|
||||
REQUIRE(std::string{"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[3.2,4.2],[3.5,4.7],[3.6,4.9],[3.2,4.2]]]]}"} == json);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("area_1outer_1inner") {
|
||||
osmium::geom::GeoJSONFactory<> factory;
|
||||
SECTION("area_1outer_1inner") {
|
||||
const osmium::Area& area = create_test_area_1outer_1inner(buffer);
|
||||
|
||||
osmium::memory::Buffer buffer(1000);
|
||||
const osmium::Area& area = create_test_area_1outer_1inner(buffer);
|
||||
REQUIRE(!area.is_multipolygon());
|
||||
REQUIRE(std::distance(area.cbegin(), area.cend()) == 3);
|
||||
REQUIRE(area.subitems<osmium::OuterRing>().size() == area.num_rings().first);
|
||||
REQUIRE(area.subitems<osmium::InnerRing>().size() == area.num_rings().second);
|
||||
|
||||
REQUIRE(!area.is_multipolygon());
|
||||
REQUIRE(std::distance(area.cbegin(), area.cend()) == 3);
|
||||
REQUIRE(area.subitems<osmium::OuterRing>().size() == area.num_rings().first);
|
||||
REQUIRE(area.subitems<osmium::InnerRing>().size() == area.num_rings().second);
|
||||
|
||||
{
|
||||
std::string json {factory.create_multipolygon(area)};
|
||||
std::string json{factory.create_multipolygon(area)};
|
||||
REQUIRE(std::string{"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[0.1,0.1],[9.1,0.1],[9.1,9.1],[0.1,9.1],[0.1,0.1]],[[1,1],[8,1],[8,8],[1,8],[1,1]]]]}"} == json);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("area_2outer_2inner") {
|
||||
osmium::geom::GeoJSONFactory<> factory;
|
||||
SECTION("area_2outer_2inner") {
|
||||
const osmium::Area& area = create_test_area_2outer_2inner(buffer);
|
||||
|
||||
osmium::memory::Buffer buffer(1000);
|
||||
const osmium::Area& area = create_test_area_2outer_2inner(buffer);
|
||||
REQUIRE(area.is_multipolygon());
|
||||
REQUIRE(std::distance(area.cbegin(), area.cend()) == 5);
|
||||
REQUIRE(area.subitems<osmium::OuterRing>().size() == area.num_rings().first);
|
||||
REQUIRE(area.subitems<osmium::InnerRing>().size() == area.num_rings().second);
|
||||
|
||||
REQUIRE(area.is_multipolygon());
|
||||
REQUIRE(std::distance(area.cbegin(), area.cend()) == 5);
|
||||
REQUIRE(area.subitems<osmium::OuterRing>().size() == area.num_rings().first);
|
||||
REQUIRE(area.subitems<osmium::InnerRing>().size() == area.num_rings().second);
|
||||
|
||||
int outer_ring=0;
|
||||
int inner_ring=0;
|
||||
for (const auto& outer : area.outer_rings()) {
|
||||
if (outer_ring == 0) {
|
||||
REQUIRE(outer.front().ref() == 1);
|
||||
} else if (outer_ring == 1) {
|
||||
REQUIRE(outer.front().ref() == 100);
|
||||
} else {
|
||||
REQUIRE(false);
|
||||
}
|
||||
for (const auto& inner : area.inner_rings(outer)) {
|
||||
if (outer_ring == 0 && inner_ring == 0) {
|
||||
REQUIRE(inner.front().ref() == 5);
|
||||
} else if (outer_ring == 0 && inner_ring == 1) {
|
||||
REQUIRE(inner.front().ref() == 10);
|
||||
int outer_ring=0;
|
||||
int inner_ring=0;
|
||||
for (const auto& outer : area.outer_rings()) {
|
||||
if (outer_ring == 0) {
|
||||
REQUIRE(outer.front().ref() == 1);
|
||||
} else if (outer_ring == 1) {
|
||||
REQUIRE(outer.front().ref() == 100);
|
||||
} else {
|
||||
REQUIRE(false);
|
||||
}
|
||||
++inner_ring;
|
||||
for (const auto& inner : area.inner_rings(outer)) {
|
||||
if (outer_ring == 0 && inner_ring == 0) {
|
||||
REQUIRE(inner.front().ref() == 5);
|
||||
} else if (outer_ring == 0 && inner_ring == 1) {
|
||||
REQUIRE(inner.front().ref() == 10);
|
||||
} else {
|
||||
REQUIRE(false);
|
||||
}
|
||||
++inner_ring;
|
||||
}
|
||||
inner_ring = 0;
|
||||
++outer_ring;
|
||||
}
|
||||
inner_ring = 0;
|
||||
++outer_ring;
|
||||
}
|
||||
|
||||
{
|
||||
std::string json {factory.create_multipolygon(area)};
|
||||
std::string json{factory.create_multipolygon(area)};
|
||||
REQUIRE(std::string{"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[0.1,0.1],[9.1,0.1],[9.1,9.1],[0.1,9.1],[0.1,0.1]],[[1,1],[4,1],[4,4],[1,4],[1,1]],[[5,5],[5,7],[7,7],[5,5]]],[[[10,10],[11,10],[11,11],[10,11],[10,10]]]]}"} == json);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <osmium/geom/geos.hpp>
|
||||
|
||||
#ifdef OSMIUM_WITH_GEOS
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <osmium/geom/mercator_projection.hpp>
|
||||
|
||||
#include "area_helper.hpp"
|
||||
@ -9,7 +13,7 @@
|
||||
TEST_CASE("GEOS geometry factory - create point") {
|
||||
osmium::geom::GEOSFactory<> factory;
|
||||
|
||||
std::unique_ptr<geos::geom::Point> point {factory.create_point(osmium::Location(3.2, 4.2))};
|
||||
const std::unique_ptr<geos::geom::Point> point{factory.create_point(osmium::Location{3.2, 4.2})};
|
||||
REQUIRE(3.2 == point->getX());
|
||||
REQUIRE(4.2 == point->getY());
|
||||
REQUIRE(4326 == point->getSRID());
|
||||
@ -18,7 +22,7 @@ TEST_CASE("GEOS geometry factory - create point") {
|
||||
TEST_CASE("GEOS geometry factory - create point in web mercator") {
|
||||
osmium::geom::GEOSFactory<osmium::geom::MercatorProjection> factory;
|
||||
|
||||
std::unique_ptr<geos::geom::Point> point {factory.create_point(osmium::Location(3.2, 4.2))};
|
||||
const std::unique_ptr<geos::geom::Point> point{factory.create_point(osmium::Location{3.2, 4.2})};
|
||||
REQUIRE(Approx(356222.3705384755l) == point->getX());
|
||||
REQUIRE(Approx(467961.143605213l) == point->getY());
|
||||
REQUIRE(3857 == point->getSRID());
|
||||
@ -26,9 +30,9 @@ TEST_CASE("GEOS geometry factory - create point in web mercator") {
|
||||
|
||||
TEST_CASE("GEOS geometry factory - create point with externally created GEOS factory") {
|
||||
geos::geom::GeometryFactory geos_factory;
|
||||
osmium::geom::GEOSFactory<> factory(geos_factory);
|
||||
osmium::geom::GEOSFactory<> factory{geos_factory};
|
||||
|
||||
std::unique_ptr<geos::geom::Point> point {factory.create_point(osmium::Location(3.2, 4.2))};
|
||||
const std::unique_ptr<geos::geom::Point> point{factory.create_point(osmium::Location{3.2, 4.2})};
|
||||
REQUIRE(3.2 == point->getX());
|
||||
REQUIRE(4.2 == point->getY());
|
||||
REQUIRE(0 == point->getSRID());
|
||||
@ -37,45 +41,45 @@ TEST_CASE("GEOS geometry factory - create point with externally created GEOS fac
|
||||
TEST_CASE("GEOS geometry factory - can not create from invalid location") {
|
||||
osmium::geom::GEOSFactory<> factory;
|
||||
|
||||
REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
|
||||
REQUIRE_THROWS_AS(factory.create_point(osmium::Location{}), osmium::invalid_location);
|
||||
}
|
||||
|
||||
TEST_CASE("GEOS geometry factory - create linestring") {
|
||||
osmium::geom::GEOSFactory<> factory;
|
||||
|
||||
osmium::memory::Buffer buffer(10000);
|
||||
auto &wnl = create_test_wnl_okay(buffer);
|
||||
osmium::memory::Buffer buffer{10000};
|
||||
const auto& wnl = create_test_wnl_okay(buffer);
|
||||
|
||||
SECTION("from way node list") {
|
||||
std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl)};
|
||||
const std::unique_ptr<geos::geom::LineString> linestring{factory.create_linestring(wnl)};
|
||||
REQUIRE(3 == linestring->getNumPoints());
|
||||
|
||||
std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
|
||||
const auto p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
|
||||
REQUIRE(3.2 == p0->getX());
|
||||
std::unique_ptr<geos::geom::Point> p2 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(2));
|
||||
const auto p2 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(2));
|
||||
REQUIRE(3.6 == p2->getX());
|
||||
}
|
||||
|
||||
SECTION("without duplicates and backwards") {
|
||||
std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
|
||||
const std::unique_ptr<geos::geom::LineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
|
||||
REQUIRE(3 == linestring->getNumPoints());
|
||||
std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
|
||||
const auto p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
|
||||
REQUIRE(3.6 == p0->getX());
|
||||
std::unique_ptr<geos::geom::Point> p2 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(2));
|
||||
const auto p2 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(2));
|
||||
REQUIRE(3.2 == p2->getX());
|
||||
}
|
||||
|
||||
SECTION("with duplicates") {
|
||||
std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
|
||||
const std::unique_ptr<geos::geom::LineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
|
||||
REQUIRE(4 == linestring->getNumPoints());
|
||||
std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
|
||||
const auto p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
|
||||
REQUIRE(3.2 == p0->getX());
|
||||
}
|
||||
|
||||
SECTION("with duplicates and backwards") {
|
||||
std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
|
||||
const std::unique_ptr<geos::geom::LineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
|
||||
REQUIRE(4 == linestring->getNumPoints());
|
||||
std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
|
||||
const auto p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
|
||||
REQUIRE(3.6 == p0->getX());
|
||||
}
|
||||
}
|
||||
@ -83,10 +87,10 @@ TEST_CASE("GEOS geometry factory - create linestring") {
|
||||
TEST_CASE("GEOS geometry factory - create area with one outer and no inner rings") {
|
||||
osmium::geom::GEOSFactory<> factory;
|
||||
|
||||
osmium::memory::Buffer buffer(10000);
|
||||
osmium::memory::Buffer buffer{10000};
|
||||
const osmium::Area& area = create_test_area_1outer_0inner(buffer);
|
||||
|
||||
std::unique_ptr<geos::geom::MultiPolygon> mp {factory.create_multipolygon(area)};
|
||||
const std::unique_ptr<geos::geom::MultiPolygon> mp{factory.create_multipolygon(area)};
|
||||
REQUIRE(1 == mp->getNumGeometries());
|
||||
|
||||
const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0));
|
||||
@ -96,17 +100,17 @@ TEST_CASE("GEOS geometry factory - create area with one outer and no inner rings
|
||||
const geos::geom::LineString* l0e = p0->getExteriorRing();
|
||||
REQUIRE(4 == l0e->getNumPoints());
|
||||
|
||||
std::unique_ptr<geos::geom::Point> l0e_p0 = std::unique_ptr<geos::geom::Point>(l0e->getPointN(1));
|
||||
const auto l0e_p0 = std::unique_ptr<geos::geom::Point>(l0e->getPointN(1));
|
||||
REQUIRE(3.5 == l0e_p0->getX());
|
||||
}
|
||||
|
||||
TEST_CASE("GEOS geometry factory - create area with one outer and one inner ring") {
|
||||
osmium::geom::GEOSFactory<> factory;
|
||||
|
||||
osmium::memory::Buffer buffer(10000);
|
||||
osmium::memory::Buffer buffer{10000};
|
||||
const osmium::Area& area = create_test_area_1outer_1inner(buffer);
|
||||
|
||||
std::unique_ptr<geos::geom::MultiPolygon> mp {factory.create_multipolygon(area)};
|
||||
const std::unique_ptr<geos::geom::MultiPolygon> mp{factory.create_multipolygon(area)};
|
||||
REQUIRE(1 == mp->getNumGeometries());
|
||||
|
||||
const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0));
|
||||
@ -123,10 +127,10 @@ TEST_CASE("GEOS geometry factory - create area with one outer and one inner ring
|
||||
TEST_CASE("GEOS geometry factory - create area with two outer and two inner rings") {
|
||||
osmium::geom::GEOSFactory<> factory;
|
||||
|
||||
osmium::memory::Buffer buffer(10000);
|
||||
osmium::memory::Buffer buffer{10000};
|
||||
const osmium::Area& area = create_test_area_2outer_2inner(buffer);
|
||||
|
||||
std::unique_ptr<geos::geom::MultiPolygon> mp {factory.create_multipolygon(area)};
|
||||
const std::unique_ptr<geos::geom::MultiPolygon> mp{factory.create_multipolygon(area)};
|
||||
REQUIRE(2 == mp->getNumGeometries());
|
||||
|
||||
const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0));
|
||||
@ -144,3 +148,5 @@ TEST_CASE("GEOS geometry factory - create area with two outer and two inner ring
|
||||
REQUIRE(5 == l1e->getNumPoints());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,92 +0,0 @@
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <osmium/geom/geos.hpp>
|
||||
#include <osmium/geom/wkb.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
#include "area_helper.hpp"
|
||||
#include "wnl_helper.hpp"
|
||||
|
||||
TEST_CASE("WKB_Geometry_with_GEOS") {
|
||||
|
||||
SECTION("point") {
|
||||
osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::GEOSFactory<> geos_factory;
|
||||
|
||||
std::string wkb {wkb_factory.create_point(osmium::Location(3.2, 4.2))};
|
||||
|
||||
std::unique_ptr<geos::geom::Point> geos_point = geos_factory.create_point(osmium::Location(3.2, 4.2));
|
||||
REQUIRE(geos_to_wkb(geos_point.get()) == wkb);
|
||||
}
|
||||
|
||||
|
||||
SECTION("linestring") {
|
||||
osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::GEOSFactory<> geos_factory;
|
||||
|
||||
osmium::memory::Buffer buffer(10000);
|
||||
auto &wnl = create_test_wnl_okay(buffer);
|
||||
|
||||
{
|
||||
std::string wkb = wkb_factory.create_linestring(wnl);
|
||||
std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl);
|
||||
REQUIRE(geos_to_wkb(geos.get()) == wkb);
|
||||
}
|
||||
|
||||
{
|
||||
std::string wkb = wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward);
|
||||
std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward);
|
||||
REQUIRE(geos_to_wkb(geos.get()) == wkb);
|
||||
}
|
||||
|
||||
{
|
||||
std::string wkb = wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::all);
|
||||
std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl, osmium::geom::use_nodes::all);
|
||||
REQUIRE(geos_to_wkb(geos.get()) == wkb);
|
||||
}
|
||||
|
||||
{
|
||||
std::string wkb = wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward);
|
||||
std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward);
|
||||
REQUIRE(geos_to_wkb(geos.get()) == wkb);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("area_1outer_0inner") {
|
||||
osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::GEOSFactory<> geos_factory;
|
||||
|
||||
osmium::memory::Buffer buffer(10000);
|
||||
const osmium::Area& area = create_test_area_1outer_0inner(buffer);
|
||||
|
||||
std::string wkb = wkb_factory.create_multipolygon(area);
|
||||
std::unique_ptr<geos::geom::MultiPolygon> geos = geos_factory.create_multipolygon(area);
|
||||
REQUIRE(geos_to_wkb(geos.get()) == wkb);
|
||||
}
|
||||
|
||||
SECTION("area_1outer_1inner") {
|
||||
osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::GEOSFactory<> geos_factory;
|
||||
|
||||
osmium::memory::Buffer buffer(10000);
|
||||
const osmium::Area& area = create_test_area_1outer_1inner(buffer);
|
||||
|
||||
std::string wkb = wkb_factory.create_multipolygon(area);
|
||||
std::unique_ptr<geos::geom::MultiPolygon> geos = geos_factory.create_multipolygon(area);
|
||||
REQUIRE(geos_to_wkb(geos.get()) == wkb);
|
||||
}
|
||||
|
||||
SECTION("area_2outer_2inner") {
|
||||
osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::GEOSFactory<> geos_factory;
|
||||
|
||||
osmium::memory::Buffer buffer(10000);
|
||||
const osmium::Area& area = create_test_area_2outer_2inner(buffer);
|
||||
|
||||
std::string wkb = wkb_factory.create_multipolygon(area);
|
||||
std::unique_ptr<geos::geom::MultiPolygon> geos = geos_factory.create_multipolygon(area);
|
||||
REQUIRE(geos_to_wkb(geos.get()) == wkb);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,121 +5,115 @@
|
||||
#include "area_helper.hpp"
|
||||
#include "wnl_helper.hpp"
|
||||
|
||||
TEST_CASE("OGR_Geometry") {
|
||||
|
||||
SECTION("point") {
|
||||
TEST_CASE("OGR point geometry") {
|
||||
osmium::geom::OGRFactory<> factory;
|
||||
|
||||
std::unique_ptr<OGRPoint> point {factory.create_point(osmium::Location(3.2, 4.2))};
|
||||
REQUIRE(3.2 == point->getX());
|
||||
REQUIRE(4.2 == point->getY());
|
||||
SECTION("point") {
|
||||
std::unique_ptr<OGRPoint> point{factory.create_point(osmium::Location{3.2, 4.2})};
|
||||
REQUIRE(3.2 == point->getX());
|
||||
REQUIRE(4.2 == point->getY());
|
||||
}
|
||||
|
||||
SECTION("empty_point") {
|
||||
REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SECTION("empty_point") {
|
||||
TEST_CASE("OGR linestring geometry") {
|
||||
osmium::geom::OGRFactory<> factory;
|
||||
osmium::memory::Buffer buffer{10000};
|
||||
const auto& wnl = create_test_wnl_okay(buffer);
|
||||
|
||||
REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
|
||||
}
|
||||
|
||||
SECTION("linestring") {
|
||||
osmium::geom::OGRFactory<> factory;
|
||||
|
||||
osmium::memory::Buffer buffer(10000);
|
||||
auto &wnl = create_test_wnl_okay(buffer);
|
||||
|
||||
{
|
||||
std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl)};
|
||||
SECTION("linestring, default") {
|
||||
std::unique_ptr<OGRLineString> linestring{factory.create_linestring(wnl)};
|
||||
REQUIRE(3 == linestring->getNumPoints());
|
||||
|
||||
REQUIRE(3.2 == linestring->getX(0));
|
||||
REQUIRE(3.6 == linestring->getX(2));
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
|
||||
SECTION("linestring, unique nodes, backwards") {
|
||||
std::unique_ptr<OGRLineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
|
||||
REQUIRE(3 == linestring->getNumPoints());
|
||||
|
||||
REQUIRE(3.6 == linestring->getX(0));
|
||||
REQUIRE(3.2 == linestring->getX(2));
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
|
||||
SECTION("linestring, all nodes") {
|
||||
std::unique_ptr<OGRLineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
|
||||
REQUIRE(4 == linestring->getNumPoints());
|
||||
|
||||
REQUIRE(3.2 == linestring->getX(0));
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
|
||||
SECTION("linestring, all nodes, backwards") {
|
||||
std::unique_ptr<OGRLineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
|
||||
REQUIRE(4 == linestring->getNumPoints());
|
||||
|
||||
REQUIRE(3.6 == linestring->getX(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SECTION("area_1outer_0inner") {
|
||||
TEST_CASE("OGR area geometry") {
|
||||
osmium::geom::OGRFactory<> factory;
|
||||
osmium::memory::Buffer buffer{10000};
|
||||
|
||||
osmium::memory::Buffer buffer(10000);
|
||||
const osmium::Area& area = create_test_area_1outer_0inner(buffer);
|
||||
SECTION("area_1outer_0inner") {
|
||||
const osmium::Area& area = create_test_area_1outer_0inner(buffer);
|
||||
|
||||
std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
|
||||
REQUIRE(1 == mp->getNumGeometries());
|
||||
std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
|
||||
REQUIRE(1 == mp->getNumGeometries());
|
||||
|
||||
const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
|
||||
REQUIRE(p0);
|
||||
REQUIRE(0 == p0->getNumInteriorRings());
|
||||
const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
|
||||
REQUIRE(p0);
|
||||
REQUIRE(0 == p0->getNumInteriorRings());
|
||||
|
||||
const OGRLineString* l0e = p0->getExteriorRing();
|
||||
REQUIRE(4 == l0e->getNumPoints());
|
||||
const OGRLineString* l0e = p0->getExteriorRing();
|
||||
REQUIRE(4 == l0e->getNumPoints());
|
||||
|
||||
REQUIRE(3.5 == l0e->getX(1));
|
||||
}
|
||||
REQUIRE(3.5 == l0e->getX(1));
|
||||
}
|
||||
|
||||
SECTION("area_1outer_1inner") {
|
||||
osmium::geom::OGRFactory<> factory;
|
||||
SECTION("area_1outer_1inner") {
|
||||
const osmium::Area& area = create_test_area_1outer_1inner(buffer);
|
||||
|
||||
osmium::memory::Buffer buffer(10000);
|
||||
const osmium::Area& area = create_test_area_1outer_1inner(buffer);
|
||||
std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
|
||||
REQUIRE(1 == mp->getNumGeometries());
|
||||
|
||||
std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
|
||||
REQUIRE(1 == mp->getNumGeometries());
|
||||
const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
|
||||
REQUIRE(p0);
|
||||
REQUIRE(1 == p0->getNumInteriorRings());
|
||||
|
||||
const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
|
||||
REQUIRE(p0);
|
||||
REQUIRE(1 == p0->getNumInteriorRings());
|
||||
const OGRLineString* l0e = p0->getExteriorRing();
|
||||
REQUIRE(5 == l0e->getNumPoints());
|
||||
|
||||
const OGRLineString* l0e = p0->getExteriorRing();
|
||||
REQUIRE(5 == l0e->getNumPoints());
|
||||
const OGRLineString* l0i0 = p0->getInteriorRing(0);
|
||||
REQUIRE(5 == l0i0->getNumPoints());
|
||||
}
|
||||
|
||||
const OGRLineString* l0i0 = p0->getInteriorRing(0);
|
||||
REQUIRE(5 == l0i0->getNumPoints());
|
||||
}
|
||||
SECTION("area_2outer_2inner") {
|
||||
const osmium::Area& area = create_test_area_2outer_2inner(buffer);
|
||||
|
||||
SECTION("area_2outer_2inner") {
|
||||
osmium::geom::OGRFactory<> factory;
|
||||
std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
|
||||
REQUIRE(2 == mp->getNumGeometries());
|
||||
|
||||
osmium::memory::Buffer buffer(10000);
|
||||
const osmium::Area& area = create_test_area_2outer_2inner(buffer);
|
||||
const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
|
||||
REQUIRE(p0);
|
||||
REQUIRE(2 == p0->getNumInteriorRings());
|
||||
|
||||
std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
|
||||
REQUIRE(2 == mp->getNumGeometries());
|
||||
const OGRLineString* l0e = p0->getExteriorRing();
|
||||
REQUIRE(5 == l0e->getNumPoints());
|
||||
|
||||
const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
|
||||
REQUIRE(p0);
|
||||
REQUIRE(2 == p0->getNumInteriorRings());
|
||||
const OGRPolygon* p1 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(1));
|
||||
REQUIRE(p1);
|
||||
REQUIRE(0 == p1->getNumInteriorRings());
|
||||
|
||||
const OGRLineString* l0e = p0->getExteriorRing();
|
||||
REQUIRE(5 == l0e->getNumPoints());
|
||||
|
||||
const OGRPolygon* p1 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(1));
|
||||
REQUIRE(p1);
|
||||
REQUIRE(0 == p1->getNumInteriorRings());
|
||||
|
||||
const OGRLineString* l1e = p1->getExteriorRing();
|
||||
REQUIRE(5 == l1e->getNumPoints());
|
||||
}
|
||||
const OGRLineString* l1e = p1->getExteriorRing();
|
||||
REQUIRE(5 == l1e->getNumPoints());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
100
test/t/geom/test_ogr_wkb.cpp
Normal file
100
test/t/geom/test_ogr_wkb.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <osmium/geom/ogr.hpp>
|
||||
#include <osmium/geom/wkb.hpp>
|
||||
|
||||
#include "area_helper.hpp"
|
||||
#include "wnl_helper.hpp"
|
||||
|
||||
std::string to_wkb(const OGRGeometry* geometry) {
|
||||
std::string buffer;
|
||||
buffer.resize(geometry->WkbSize());
|
||||
|
||||
geometry->exportToWkb(wkbNDR, const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(buffer.data())));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
TEST_CASE("compare WKB point against GDAL/OGR") {
|
||||
osmium::geom::WKBFactory<> wkb_factory{osmium::geom::wkb_type::wkb};
|
||||
osmium::geom::OGRFactory<> ogr_factory;
|
||||
|
||||
osmium::Location loc{3.2, 4.2};
|
||||
const std::string wkb{wkb_factory.create_point(loc)};
|
||||
const std::unique_ptr<OGRPoint> geometry = ogr_factory.create_point(loc);
|
||||
REQUIRE(to_wkb(geometry.get()) == wkb);
|
||||
}
|
||||
|
||||
TEST_CASE("compare WKB linestring against GDAL/OGR") {
|
||||
osmium::geom::WKBFactory<> wkb_factory{osmium::geom::wkb_type::wkb};
|
||||
osmium::geom::OGRFactory<> ogr_factory;
|
||||
osmium::memory::Buffer buffer{10000};
|
||||
|
||||
const auto& wnl = create_test_wnl_okay(buffer);
|
||||
|
||||
SECTION("linestring") {
|
||||
const std::string wkb{wkb_factory.create_linestring(wnl)};
|
||||
const std::unique_ptr<OGRLineString> geometry = ogr_factory.create_linestring(wnl);
|
||||
REQUIRE(to_wkb(geometry.get()) == wkb);
|
||||
}
|
||||
|
||||
SECTION("linestring, unique nodes, backwards") {
|
||||
const std::string wkb{wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
|
||||
const std::unique_ptr<OGRLineString> geometry = ogr_factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward);
|
||||
REQUIRE(to_wkb(geometry.get()) == wkb);
|
||||
}
|
||||
|
||||
SECTION("linestring, all nodes, forwards") {
|
||||
const std::string wkb{wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
|
||||
const std::unique_ptr<OGRLineString> geometry = ogr_factory.create_linestring(wnl, osmium::geom::use_nodes::all);
|
||||
REQUIRE(to_wkb(geometry.get()) == wkb);
|
||||
}
|
||||
|
||||
SECTION("linestring, all nodes, backwards") {
|
||||
const std::string wkb{wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
|
||||
const std::unique_ptr<OGRLineString> geometry = ogr_factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward);
|
||||
REQUIRE(to_wkb(geometry.get()) == wkb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("compare WKB area against GDAL/OGR") {
|
||||
osmium::geom::WKBFactory<> wkb_factory{osmium::geom::wkb_type::wkb};
|
||||
osmium::geom::OGRFactory<> ogr_factory;
|
||||
osmium::memory::Buffer buffer{10000};
|
||||
|
||||
SECTION("area_1outer_0inner") {
|
||||
const osmium::Area& area = create_test_area_1outer_0inner(buffer);
|
||||
|
||||
const std::string wkb{wkb_factory.create_multipolygon(area)};
|
||||
const std::unique_ptr<OGRMultiPolygon> geometry = ogr_factory.create_multipolygon(area);
|
||||
REQUIRE(to_wkb(geometry.get()) == wkb);
|
||||
}
|
||||
|
||||
SECTION("area_1outer_1inner") {
|
||||
const osmium::Area& area = create_test_area_1outer_1inner(buffer);
|
||||
|
||||
const std::string wkb{wkb_factory.create_multipolygon(area)};
|
||||
const std::unique_ptr<OGRMultiPolygon> geometry = ogr_factory.create_multipolygon(area);
|
||||
REQUIRE(to_wkb(geometry.get()) == wkb);
|
||||
}
|
||||
|
||||
SECTION("area_2outer_2inner") {
|
||||
const osmium::Area& area = create_test_area_2outer_2inner(buffer);
|
||||
|
||||
const std::string wkb{wkb_factory.create_multipolygon(area)};
|
||||
const std::unique_ptr<OGRMultiPolygon> geometry = ogr_factory.create_multipolygon(area);
|
||||
REQUIRE(to_wkb(geometry.get()) == wkb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,144 +6,121 @@
|
||||
#include <osmium/geom/mercator_projection.hpp>
|
||||
#include <osmium/geom/projection.hpp>
|
||||
|
||||
TEST_CASE("Projection") {
|
||||
|
||||
SECTION("identity_projection") {
|
||||
TEST_CASE("Indentity Projection") {
|
||||
osmium::geom::IdentityProjection projection;
|
||||
REQUIRE(4326 == projection.epsg());
|
||||
REQUIRE("+proj=longlat +datum=WGS84 +no_defs" == projection.proj_string());
|
||||
}
|
||||
|
||||
SECTION("project_location_4326") {
|
||||
osmium::geom::Projection projection(4326);
|
||||
TEST_CASE("Projection 4326") {
|
||||
osmium::geom::Projection projection{4326};
|
||||
REQUIRE(4326 == projection.epsg());
|
||||
REQUIRE("+init=epsg:4326" == projection.proj_string());
|
||||
|
||||
const osmium::Location loc(1.0, 2.0);
|
||||
const osmium::geom::Coordinates c {1.0, 2.0};
|
||||
const osmium::Location loc{1.0, 2.0};
|
||||
const osmium::geom::Coordinates c{1.0, 2.0};
|
||||
REQUIRE(c == projection(loc));
|
||||
}
|
||||
|
||||
SECTION("project_location_4326_string") {
|
||||
osmium::geom::Projection projection("+init=epsg:4326");
|
||||
TEST_CASE("Projection 4326 from init string") {
|
||||
osmium::geom::Projection projection{"+init=epsg:4326"};
|
||||
REQUIRE(-1 == projection.epsg());
|
||||
REQUIRE("+init=epsg:4326" == projection.proj_string());
|
||||
|
||||
const osmium::Location loc(1.0, 2.0);
|
||||
const osmium::geom::Coordinates c {1.0, 2.0};
|
||||
const osmium::Location loc{1.0, 2.0};
|
||||
const osmium::geom::Coordinates c{1.0, 2.0};
|
||||
REQUIRE(c == projection(loc));
|
||||
}
|
||||
|
||||
SECTION("unknown_projection_string") {
|
||||
REQUIRE_THROWS_AS(osmium::geom::Projection projection("abc"), osmium::projection_error);
|
||||
TEST_CASE("Creating projection from unknown init string") {
|
||||
REQUIRE_THROWS_AS(osmium::geom::Projection projection{"abc"}, osmium::projection_error);
|
||||
}
|
||||
|
||||
SECTION("unknown_epsg_code") {
|
||||
REQUIRE_THROWS_AS(osmium::geom::Projection projection(9999999), osmium::projection_error);
|
||||
TEST_CASE("Creating projection from unknown EPSG code") {
|
||||
REQUIRE_THROWS_AS(osmium::geom::Projection projection{9999999}, osmium::projection_error);
|
||||
}
|
||||
|
||||
SECTION("project_location_3857") {
|
||||
osmium::geom::Projection projection(3857);
|
||||
TEST_CASE("Projection 3857") {
|
||||
osmium::geom::Projection projection{3857};
|
||||
REQUIRE(3857 == projection.epsg());
|
||||
REQUIRE("+init=epsg:3857" == projection.proj_string());
|
||||
|
||||
{
|
||||
const osmium::Location loc(0.0, 0.0);
|
||||
const osmium::geom::Coordinates c {0.0, 0.0};
|
||||
SECTION("Zero coordinates") {
|
||||
const osmium::Location loc{0.0, 0.0};
|
||||
const osmium::geom::Coordinates c{0.0, 0.0};
|
||||
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
|
||||
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
|
||||
}
|
||||
{
|
||||
const osmium::Location loc(180.0, 0.0);
|
||||
const osmium::geom::Coordinates c {20037508.34, 0.0};
|
||||
|
||||
SECTION("Max longitude") {
|
||||
const osmium::Location loc{180.0, 0.0};
|
||||
const osmium::geom::Coordinates c{20037508.34, 0.0};
|
||||
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
|
||||
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
|
||||
}
|
||||
{
|
||||
const osmium::Location loc(180.0, 0.0);
|
||||
const osmium::geom::Coordinates c {20037508.34, 0.0};
|
||||
|
||||
SECTION("Min longitude") {
|
||||
const osmium::Location loc{-180.0, 0.0};
|
||||
const osmium::geom::Coordinates c{-20037508.34, 0.0};
|
||||
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
|
||||
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
|
||||
}
|
||||
{
|
||||
const osmium::Location loc(0.0, 85.0511288);
|
||||
const osmium::geom::Coordinates c {0.0, 20037508.34};
|
||||
|
||||
SECTION("Max latitude") {
|
||||
const osmium::Location loc{0.0, 85.0511288};
|
||||
const osmium::geom::Coordinates c{0.0, 20037508.34};
|
||||
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
|
||||
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("project_location_mercator") {
|
||||
TEST_CASE("MercatorProjection") {
|
||||
osmium::geom::MercatorProjection projection;
|
||||
|
||||
{
|
||||
const osmium::Location loc(0.0, 0.0);
|
||||
const osmium::geom::Coordinates c {0.0, 0.0};
|
||||
SECTION("Zero coordinates") {
|
||||
const osmium::Location loc{0.0, 0.0};
|
||||
const osmium::geom::Coordinates c{0.0, 0.0};
|
||||
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
|
||||
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
|
||||
}
|
||||
{
|
||||
const osmium::Location loc(180.0, 0.0);
|
||||
const osmium::geom::Coordinates c {20037508.34, 0.0};
|
||||
|
||||
SECTION("Max longitude") {
|
||||
const osmium::Location loc{180.0, 0.0};
|
||||
const osmium::geom::Coordinates c{20037508.34, 0.0};
|
||||
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
|
||||
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
|
||||
}
|
||||
{
|
||||
const osmium::Location loc(180.0, 0.0);
|
||||
const osmium::geom::Coordinates c {20037508.34, 0.0};
|
||||
|
||||
SECTION("Min longitude") {
|
||||
const osmium::Location loc{-180.0, 0.0};
|
||||
const osmium::geom::Coordinates c{-20037508.34, 0.0};
|
||||
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
|
||||
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
|
||||
}
|
||||
{
|
||||
const osmium::Location loc(0.0, 85.0511288);
|
||||
const osmium::geom::Coordinates c {0.0, 20037508.34};
|
||||
|
||||
SECTION("Max latitude") {
|
||||
const osmium::Location loc{0.0, 85.0511288};
|
||||
const osmium::geom::Coordinates c{0.0, 20037508.34};
|
||||
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
|
||||
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("compare_mercators") {
|
||||
TEST_CASE("Compare mercator implementations") {
|
||||
osmium::geom::MercatorProjection projection_merc;
|
||||
osmium::geom::Projection projection_3857(3857);
|
||||
REQUIRE(3857 == projection_3857.epsg());
|
||||
REQUIRE("+init=epsg:3857" == projection_3857.proj_string());
|
||||
osmium::geom::Projection projection_3857{3857};
|
||||
|
||||
{
|
||||
const osmium::Location loc(4.2, 27.3);
|
||||
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
|
||||
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
|
||||
}
|
||||
{
|
||||
const osmium::Location loc(160.789, -42.42);
|
||||
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
|
||||
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
|
||||
}
|
||||
{
|
||||
const osmium::Location loc(-0.001, 0.001);
|
||||
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
|
||||
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
|
||||
}
|
||||
{
|
||||
const osmium::Location loc(-85.2, -85.2);
|
||||
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
|
||||
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
|
||||
}
|
||||
}
|
||||
SECTION("random coordinates") {
|
||||
std::random_device rd;
|
||||
std::mt19937 gen{rd()};
|
||||
std::uniform_real_distribution<> dis_x{-180.0, 180.0};
|
||||
std::uniform_real_distribution<> dis_y{-90.0, 90.0};
|
||||
|
||||
SECTION("compare_mercators") {
|
||||
osmium::geom::MercatorProjection projection_merc;
|
||||
osmium::geom::Projection projection_3857(3857);
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_real_distribution<> dis_x(-180.0, 180.0);
|
||||
std::uniform_real_distribution<> dis_y(-90.0, 90.0);
|
||||
|
||||
for (int n = 0; n < 100000; ++n) {
|
||||
const osmium::Location loc(dis_x(gen), dis_y(gen));
|
||||
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
|
||||
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
|
||||
for (int n = 0; n < 10000; ++n) {
|
||||
const osmium::Location loc{dis_x(gen), dis_y(gen)};
|
||||
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
|
||||
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
#include <osmium/geom/tile.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
|
||||
#include "test_tile_data.hpp"
|
||||
|
||||
TEST_CASE("Tile from x0.0 y0.0 at zoom 0") {
|
||||
|
@ -10,28 +10,28 @@ TEST_CASE("WKB geometry factory (byte-order-dependant), points") {
|
||||
const osmium::Location loc{3.2, 4.2};
|
||||
|
||||
SECTION("point") {
|
||||
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::WKBFactory<> factory{osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex};
|
||||
|
||||
const std::string wkb{factory.create_point(loc)};
|
||||
REQUIRE(wkb == "01010000009A99999999990940CDCCCCCCCCCC1040");
|
||||
}
|
||||
|
||||
SECTION("point in web mercator") {
|
||||
osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory{osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex};
|
||||
|
||||
const std::string wkb{factory.create_point(loc)};
|
||||
REQUIRE(wkb == "010100000028706E7BF9BD1541B03E0D93E48F1C41");
|
||||
}
|
||||
|
||||
SECTION("point in ewkb") {
|
||||
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::WKBFactory<> factory{osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex};
|
||||
|
||||
const std::string wkb{factory.create_point(loc)};
|
||||
REQUIRE(wkb == "0101000020E61000009A99999999990940CDCCCCCCCCCC1040");
|
||||
}
|
||||
|
||||
SECTION("point in ewkb in web mercator") {
|
||||
osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory{osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex};
|
||||
|
||||
const std::string wkb{factory.create_point(loc)};
|
||||
REQUIRE(wkb == "0101000020110F000028706E7BF9BD1541B03E0D93E48F1C41");
|
||||
@ -44,7 +44,7 @@ TEST_CASE("WKB geometry factory (byte-order-dependant)") {
|
||||
osmium::memory::Buffer buffer{10000};
|
||||
|
||||
SECTION("linestring") {
|
||||
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::WKBFactory<> factory{osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex};
|
||||
const auto& wnl = create_test_wnl_okay(buffer);
|
||||
|
||||
{
|
||||
@ -69,7 +69,7 @@ TEST_CASE("WKB geometry factory (byte-order-dependant)") {
|
||||
}
|
||||
|
||||
SECTION("linestring as ewkb") {
|
||||
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::WKBFactory<> factory{osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex};
|
||||
|
||||
const auto& wnl = create_test_wnl_okay(buffer);
|
||||
|
||||
@ -78,7 +78,7 @@ TEST_CASE("WKB geometry factory (byte-order-dependant)") {
|
||||
}
|
||||
|
||||
SECTION("linestring with two same locations") {
|
||||
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::WKBFactory<> factory{osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex};
|
||||
|
||||
const auto& wnl = create_test_wnl_same_location(buffer);
|
||||
|
||||
@ -102,7 +102,7 @@ TEST_CASE("WKB geometry factory (byte-order-dependant)") {
|
||||
}
|
||||
|
||||
SECTION("linestring with undefined location") {
|
||||
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::WKBFactory<> factory{osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex};
|
||||
|
||||
const auto& wnl = create_test_wnl_undefined_location(buffer);
|
||||
|
||||
@ -115,7 +115,7 @@ TEST_CASE("WKB geometry factory (byte-order-dependant)") {
|
||||
|
||||
TEST_CASE("WKB geometry (byte-order-independent)") {
|
||||
|
||||
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
|
||||
osmium::geom::WKBFactory<> factory{osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex};
|
||||
|
||||
SECTION("empty point") {
|
||||
REQUIRE_THROWS_AS(factory.create_point(osmium::Location{}), osmium::invalid_location);
|
||||
|
@ -6,7 +6,7 @@
|
||||
using namespace osmium::builder::attr;
|
||||
|
||||
inline const osmium::WayNodeList& create_test_wnl_okay(osmium::memory::Buffer& buffer) {
|
||||
auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
|
||||
const auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
|
||||
{1, {3.2, 4.2}},
|
||||
{3, {3.5, 4.7}},
|
||||
{4, {3.5, 4.7}},
|
||||
@ -25,7 +25,7 @@ inline const osmium::WayNodeList& create_test_wnl_empty(osmium::memory::Buffer&
|
||||
}
|
||||
|
||||
inline const osmium::WayNodeList& create_test_wnl_same_location(osmium::memory::Buffer& buffer) {
|
||||
auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
|
||||
const auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
|
||||
{1, {3.5, 4.7}},
|
||||
{2, {3.5, 4.7}}
|
||||
}));
|
||||
@ -34,7 +34,7 @@ inline const osmium::WayNodeList& create_test_wnl_same_location(osmium::memory::
|
||||
}
|
||||
|
||||
inline const osmium::WayNodeList& create_test_wnl_undefined_location(osmium::memory::Buffer& buffer) {
|
||||
auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
|
||||
const auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
|
||||
{1, {3.5, 4.7}},
|
||||
{2, osmium::Location()}
|
||||
}));
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user