Merge commit '879f7eb04200d7d2c28af565229bf6e3d54274fd' into retry/libosmium
This commit is contained in:
commit
5b4e2950d9
2
third_party/libosmium/.gitignore
vendored
2
third_party/libosmium/.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
*.swp
|
||||
.ycm_extra_conf.pyc
|
||||
/build
|
||||
/libosmium-deps
|
||||
|
96
third_party/libosmium/.travis.yml
vendored
96
third_party/libosmium/.travis.yml
vendored
@ -4,24 +4,34 @@
|
||||
#
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
language: cpp
|
||||
language: generic
|
||||
|
||||
sudo: false
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.ccache
|
||||
|
||||
env:
|
||||
global:
|
||||
- CCACHE_TEMPDIR=/tmp/.ccache-temp
|
||||
- CCACHE_COMPRESS=1
|
||||
- CASHER_TIME_OUT=1000
|
||||
|
||||
matrix:
|
||||
include:
|
||||
|
||||
# 1/ Linux Clang Builds
|
||||
- os: linux
|
||||
compiler: clang
|
||||
compiler: linux-clang35-release
|
||||
addons:
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.5', 'ubuntu-toolchain-r-test', 'boost-latest']
|
||||
packages: ['clang-3.5', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin']
|
||||
packages: ['clang-3.5', 'cmake', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin']
|
||||
env: COMPILER='clang++-3.5' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
compiler: linux-clang35-dev
|
||||
addons:
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.5', 'ubuntu-toolchain-r-test', 'boost-latest']
|
||||
@ -30,24 +40,7 @@ matrix:
|
||||
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.6', 'ubuntu-toolchain-r-test', 'boost-latest']
|
||||
packages: ['clang-3.6', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin']
|
||||
env: COMPILER='clang++-3.6' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.6', 'ubuntu-toolchain-r-test', 'boost-latest']
|
||||
packages: ['clang-3.6', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin']
|
||||
env: COMPILER='clang++-3.6' BUILD_TYPE='Dev'
|
||||
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
compiler: linux-clang37-release
|
||||
addons:
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.7', 'ubuntu-toolchain-r-test', 'boost-latest']
|
||||
@ -55,7 +48,7 @@ matrix:
|
||||
env: COMPILER='clang++-3.7' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
compiler: linux-clang37-dev
|
||||
addons:
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.7', 'ubuntu-toolchain-r-test', 'boost-latest']
|
||||
@ -63,9 +56,26 @@ matrix:
|
||||
env: COMPILER='clang++-3.7' BUILD_TYPE='Dev'
|
||||
|
||||
|
||||
- os: linux
|
||||
compiler: linux-clang38-release
|
||||
addons:
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.8', 'ubuntu-toolchain-r-test', 'boost-latest']
|
||||
packages: ['clang-3.8', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin']
|
||||
env: COMPILER='clang++-3.8' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: linux-clang38-dev
|
||||
addons:
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.8', 'ubuntu-toolchain-r-test', 'boost-latest']
|
||||
packages: ['clang-3.8', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin']
|
||||
env: COMPILER='clang++-3.8' BUILD_TYPE='Dev'
|
||||
|
||||
|
||||
# 2/ Linux GCC Builds
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
compiler: linux-gcc48-release
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'boost-latest']
|
||||
@ -73,7 +83,7 @@ matrix:
|
||||
env: COMPILER='g++-4.8' COMPILER_FLAGS='-Wno-return-type' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
compiler: linux-gcc48-dev
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'boost-latest']
|
||||
@ -82,7 +92,7 @@ matrix:
|
||||
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
compiler: linux-gcc49-release
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'boost-latest']
|
||||
@ -90,7 +100,7 @@ matrix:
|
||||
env: COMPILER='g++-4.9' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
compiler: linux-gcc49-dev
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'boost-latest']
|
||||
@ -99,7 +109,7 @@ matrix:
|
||||
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
compiler: linux-gcc50-release
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'boost-latest']
|
||||
@ -107,7 +117,7 @@ matrix:
|
||||
env: COMPILER='g++-5' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
compiler: linux-gcc50-dev
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'boost-latest']
|
||||
@ -118,25 +128,25 @@ matrix:
|
||||
# 3/ OSX Clang Builds
|
||||
- os: osx
|
||||
osx_image: xcode6.4
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' BUILD_TYPE='Dev'
|
||||
compiler: xcode64-clang-release
|
||||
env: COMPILER='clang++' BUILD_TYPE='Release'
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode6.4
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' BUILD_TYPE='Release'
|
||||
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode7
|
||||
compiler: clang
|
||||
compiler: xcode64-clang-dev
|
||||
env: COMPILER='clang++' BUILD_TYPE='Dev'
|
||||
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode7
|
||||
compiler: clang
|
||||
compiler: xcode7-clang-release
|
||||
env: COMPILER='clang++' BUILD_TYPE='Release'
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode7
|
||||
compiler: xcode7-clang-dev
|
||||
env: COMPILER='clang++' BUILD_TYPE='Dev'
|
||||
|
||||
|
||||
install:
|
||||
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
|
||||
@ -145,15 +155,15 @@ install:
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||
brew remove gdal
|
||||
brew install cmake boost google-sparsehash gdal
|
||||
brew install cmake boost google-sparsehash gdal || true
|
||||
fi
|
||||
- cmake --version
|
||||
|
||||
before_script:
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
- mkdir build && cd build
|
||||
- CXX=${COMPILER} CXXFLAGS=${COMPILER_FLAGS} cmake -LA .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DOSM_TESTDATA="${TRAVIS_BUILD_DIR}/deps/osm-testdata"
|
||||
- CXX=${COMPILER} CXXFLAGS=${COMPILER_FLAGS} cmake -LA .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILD_WITH_CCACHE=1 -DOSM_TESTDATA="${TRAVIS_BUILD_DIR}/deps/osm-testdata"
|
||||
|
||||
script:
|
||||
- make VERBOSE=1
|
||||
- ctest --output-on-failure
|
||||
- make VERBOSE=1 && ctest --output-on-failure
|
||||
|
||||
|
5
third_party/libosmium/.ycm_extra_conf.py
vendored
5
third_party/libosmium/.ycm_extra_conf.py
vendored
@ -29,6 +29,11 @@ flags = [
|
||||
'-x',
|
||||
'c++',
|
||||
|
||||
# workaround for https://github.com/Valloric/YouCompleteMe/issues/303
|
||||
# also see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=800618
|
||||
'-isystem',
|
||||
'/usr/lib/ycmd/clang_includes/',
|
||||
|
||||
# libosmium include dirs
|
||||
'-I%s/include' % basedir,
|
||||
'-I%s/test/include' % basedir,
|
||||
|
141
third_party/libosmium/CHANGELOG.md
vendored
141
third_party/libosmium/CHANGELOG.md
vendored
@ -13,6 +13,140 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
### Fixed
|
||||
|
||||
|
||||
## [2.9.0] - 2016-09-15
|
||||
|
||||
### Added
|
||||
|
||||
- Support for reading OPL files.
|
||||
- For diff output OSM objects in buffers can be marked as only in one or the
|
||||
other file. The OPL and debug output formats support diff output based on
|
||||
this.
|
||||
- Add documentation and range checks to `Tile` struct.
|
||||
- More documentation.
|
||||
- More examples and more extensive comments on examples.
|
||||
- Support for a progress report in `osmium::io::Reader()` and a `ProgressBar`
|
||||
utility class to use it.
|
||||
- New `OSMObject::set_timestamp(const char*)` function.
|
||||
|
||||
### Changed
|
||||
|
||||
- Parse coordinates in scientific notations ourselves.
|
||||
- Updated included protozero version to 1.4.2.
|
||||
- Lots of one-argument constructors are now explicit.
|
||||
- Timestamp parser now uses our own implementation instead of strptime.
|
||||
This is faster and independant of locale settings.
|
||||
- More cases of invalid areas with duplicate segments are reported as
|
||||
errors.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed a problem limiting cache file sizes on Windows to 32 bit.
|
||||
- Fixed includes.
|
||||
- Exception messages for invalid areas do not report "area contains no rings"
|
||||
any more, but "invalid area".
|
||||
|
||||
|
||||
## [2.8.0] - 2016-08-04
|
||||
|
||||
### Added
|
||||
|
||||
- EWKT support.
|
||||
- Track `pop` type calls and queue underruns when `OSMIUM_DEBUG_QUEUE_SIZE`
|
||||
environment variable is set.
|
||||
|
||||
### Changed
|
||||
|
||||
- Switched to newest protozero v1.4.0. This should deliver some speedups
|
||||
when parsing PBF files. This also removes the DeltaEncodeIterator class,
|
||||
which isn't needed any more.
|
||||
- Uses `std::unordered_map` instead of `std::map` in PBF string table code
|
||||
speeding up writing of PBF files considerably.
|
||||
- Uses less memory when writing PBF files (smaller string table by default).
|
||||
- Removes dependency on sparsehash and boost program options libraries for
|
||||
examples.
|
||||
- Cleaned up threaded queue code.
|
||||
|
||||
### Fixed
|
||||
|
||||
- A potentially very bad bug was fixed: When there are many and/or long strings
|
||||
in tag keys and values and/or user names and/or relation roles, the string
|
||||
table inside a PBF block would overflow. I have never seen this happen for
|
||||
normal OSM data, but that doesn't mean it can't happen. The result is that
|
||||
the strings will all be mixed up, keys for values, values for user names or
|
||||
whatever.
|
||||
- Automatically set correct SRID when creating WKB and GEOS geometries.
|
||||
Note that this changes the behaviour of libosmium when creating GEOS
|
||||
geometries. Before we created them with -1 as SRID unless set otherwise.
|
||||
Manual setting of the SRID on the GEOSGeometryFactory is now deprecated.
|
||||
- Allow coordinates of nodes in scientific notation when reading XML files.
|
||||
This shouldn't be used really, but sometimes you can find them.
|
||||
|
||||
|
||||
## [2.7.2] - 2016-06-08
|
||||
|
||||
### Changed
|
||||
|
||||
- Much faster output of OSM files in XML, OPL, or debug formats.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Parsing and output of coordinates now faster and always uses decimal dot
|
||||
independant of locale setting.
|
||||
- Do not output empty discussion elements in changeset XML output.
|
||||
- Data corruption regression in mmap based indexes.
|
||||
|
||||
|
||||
## [2.7.1] - 2016-06-01
|
||||
|
||||
### Fixes
|
||||
|
||||
- Update version number in version.hpp.
|
||||
|
||||
|
||||
## [2.7.0] - 2016-06-01
|
||||
|
||||
### Added
|
||||
|
||||
- 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()`).
|
||||
- Debug output optionally prints CRC32 when `add_crc32` file option is set.
|
||||
|
||||
### Changed
|
||||
|
||||
- XML parser will not allow any XML entities which are usually not used in OSM
|
||||
files anyway. This can help avoiding DOS attacks.
|
||||
- Removed SortedQueue implementation which was never used.
|
||||
- Also incorporate Locations in NodeRefs into CRC32 checksums. This means
|
||||
all checksums will be different compared to earlier versions of libosmium.
|
||||
- The completely new algorithm for assembling multipolygons is much faster,
|
||||
has better error reporting, generates statistics and can build more complex
|
||||
multipolygons correctly. The ProblemReporter classes have changed to make
|
||||
this happen, if you have written your own, you have to fix it.
|
||||
- Sparse node location stores are now only sorted if needed, ie. when nodes
|
||||
come in unordered.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Output operator for Location shows full precision.
|
||||
- Undefined behaviour in WKB writer and `types_from_string()` function.
|
||||
- Fix unsigned overflow in pool.hpp.
|
||||
- OSM objects are now ordered by type (nodes, then ways, then relations),
|
||||
then ID, then version, then timestamp. Ordering by timestamp is normally
|
||||
not necessary, because there can't be two objects with same type, ID, and
|
||||
version but different timestamp. But this can happen when diffs are
|
||||
created from OSM extracts, so we check for this here. This change also
|
||||
makes sure IDs are always ordered by absolute IDs, positives first, so
|
||||
order is 0, 1, -1, 2, -2, ...
|
||||
- Data corruption bug fixed in disk based indexes (used for the node
|
||||
location store for instance). This only affected you, if you created
|
||||
and index, closed it, and re-opened it (possibly in a different process)
|
||||
and if there were missing nodes. If you looked up those nodes, you got
|
||||
location (0,0) back instead of an error.
|
||||
- Memory corruption bug showing up with GDAL 2.
|
||||
|
||||
|
||||
## [2.6.1] - 2016-02-22
|
||||
|
||||
### Added
|
||||
@ -276,7 +410,12 @@ 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.6.1...HEAD
|
||||
[unreleased]: https://github.com/osmcode/libosmium/compare/v2.9.0...HEAD
|
||||
[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
|
||||
[2.7.1]: https://github.com/osmcode/libosmium/compare/v2.7.0...v2.7.1
|
||||
[2.7.0]: https://github.com/osmcode/libosmium/compare/v2.6.1...v2.7.0
|
||||
[2.6.1]: https://github.com/osmcode/libosmium/compare/v2.6.0...v2.6.1
|
||||
[2.6.0]: https://github.com/osmcode/libosmium/compare/v2.5.4...v2.6.0
|
||||
[2.5.4]: https://github.com/osmcode/libosmium/compare/v2.5.3...v2.5.4
|
||||
|
25
third_party/libosmium/CMakeLists.txt
vendored
25
third_party/libosmium/CMakeLists.txt
vendored
@ -24,8 +24,8 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel;Dev;Cover
|
||||
project(libosmium)
|
||||
|
||||
set(LIBOSMIUM_VERSION_MAJOR 2)
|
||||
set(LIBOSMIUM_VERSION_MINOR 6)
|
||||
set(LIBOSMIUM_VERSION_PATCH 1)
|
||||
set(LIBOSMIUM_VERSION_MINOR 9)
|
||||
set(LIBOSMIUM_VERSION_PATCH 0)
|
||||
|
||||
set(LIBOSMIUM_VERSION
|
||||
"${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}")
|
||||
@ -61,6 +61,27 @@ option(INSTALL_UTFCPP "also install utfcpp headers" OFF)
|
||||
option(WITH_PROFILING "add flags needed for profiling" OFF)
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
# CCache support
|
||||
#
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
option(BUILD_WITH_CCACHE "build using ccache" OFF)
|
||||
|
||||
if(BUILD_WITH_CCACHE)
|
||||
find_program(CCACHE_PROGRAM ccache)
|
||||
if(CCACHE_PROGRAM)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "CCACHE_CPP2=1 ${CCACHE_PROGRAM}")
|
||||
|
||||
# workaround for some clang versions
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
add_definitions(-Qunused-arguments)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
# Coverage support
|
||||
|
147
third_party/libosmium/CONTRIBUTING.md
vendored
147
third_party/libosmium/CONTRIBUTING.md
vendored
@ -1,143 +1,12 @@
|
||||
|
||||
# Notes for Developers
|
||||
Some rules for contributing to this project:
|
||||
|
||||
Read this if you want to contribute to Libosmium.
|
||||
* Please open a separate issue for each problem, question, or comment you have.
|
||||
Do not re-use existing issues for other topics, even if they are similar. This
|
||||
keeps issues small and manageable and makes it much easier to follow through
|
||||
and make sure each problem is taken care of.
|
||||
|
||||
|
||||
## Versioning
|
||||
|
||||
Osmium is currently considered in beta and doesn't use versioning yet. Proper
|
||||
versions will be introduced as soon as it is somewhat stable.
|
||||
|
||||
|
||||
## Namespace
|
||||
|
||||
All Osmium code MUST be in the `osmium` namespace or one of its sub-namespaces.
|
||||
|
||||
|
||||
## Include-Only
|
||||
|
||||
Osmium is a include-only library. You can't compile the library itself. There
|
||||
is no libosmium.so.
|
||||
|
||||
One drawback ist that you can't have static data in classes, because there
|
||||
is no place to put this data.
|
||||
|
||||
All free functions must be declared `inline`.
|
||||
|
||||
|
||||
## Coding Conventions
|
||||
|
||||
These coding conventions have been changing over time and some code is still
|
||||
different.
|
||||
|
||||
* All include files have `#ifdef` guards around them, macros are the path name
|
||||
in all uppercase where the slashes (`/`) have been changed to underscore (`_`).
|
||||
* Class names begin with uppercase chars and use CamelCase. Smaller helper
|
||||
classes are usually defined as struct and have lowercase names.
|
||||
* Macros (and only macros) are all uppercase. Use macros sparingly, usually
|
||||
a simple (maybe constexpr) inline function is better. Undef macros after use
|
||||
if possible.
|
||||
* Macros should only be used for controlling which parts of the code should be
|
||||
included when compiling or to avoid major code repetitions.
|
||||
* Variables, attributes, and function names are lowercase with
|
||||
`underscores_between_words`.
|
||||
* Class attribute names start with `m_` (member).
|
||||
* Use `descriptive_variable_names`, exceptions are well-established conventions
|
||||
like `i` for a loop variable. Iterators are usually called `it`.
|
||||
* Declare variables where they are first used (C++ style), not at the beginning
|
||||
of a function (old C style).
|
||||
* Names from external namespaces (even `std`) are always mentioned explicitly.
|
||||
Do not use `using` (except for `std::swap`). This way we can't even by
|
||||
accident pollute the namespace of the code using Osmium.
|
||||
* Always use the standard swap idiom: `using std::swap; swap(foo, bar);`.
|
||||
* `#include` directives appear in three "blocks" after the copyright notice.
|
||||
The blocks are separated by blank lines. First block contains `#include`s for
|
||||
standard C/C++ includes, second block for any external libs used, third
|
||||
block for osmium internal includes. Within each block `#include`s are usually
|
||||
sorted by path name. All `#include`s use `<>` syntax not `""`.
|
||||
* Names not to be used from outside the library should be in a namespace
|
||||
called `detail` under the namespace where they would otherwise appear. If
|
||||
whole include files are never meant to be included from outside they should
|
||||
be in a subdirectory called `detail`.
|
||||
* All files have suffix `.hpp`.
|
||||
* Closing } of all classes and namespaces should have a trailing comment
|
||||
with the name of the class/namespace.
|
||||
* All constructors with one (or more arguments if they have a default) should
|
||||
be declared "explicit" unless there is a reason for them not to be. Document
|
||||
that reason.
|
||||
* If a class has any of the special methods (copy/move constructor/assigment,
|
||||
destructor) it should have all of them, possibly marking them as default or
|
||||
deleted.
|
||||
* Typedefs have `names_like_this_type` which end in `_type`. Typedefs should
|
||||
use the new `using foo_type = bar` syntax instead of the old
|
||||
`typedef bar foo_type`.
|
||||
* Template parameters are single uppercase letters or start with uppercase `T`
|
||||
and use CamelCase.
|
||||
* Always use `typename` in templates, not `class`: `template <typename T>`.
|
||||
* The ellipsis in variadic template never has a space to the left of it and
|
||||
always has a space to the right: `template <typename... TArgs>` etc.
|
||||
|
||||
Keep to the indentation and other styles used in the code. Use `make indent`
|
||||
in the toplevel directory to fix indentation and styling. It calls `astyle`
|
||||
with the right parameters. This program is in the `astyle` Debian package.
|
||||
|
||||
|
||||
## C++11
|
||||
|
||||
Osmium uses C++11 and you can use its features such as auto, lambdas,
|
||||
threading, etc. There are a few features we do not use, because even modern
|
||||
compilers don't support them yet. This list might change as we get more data
|
||||
about which compilers support which feature and what operating system versions
|
||||
or distributions have which versions of these compilers installed.
|
||||
|
||||
GCC 4.6 - too old, not supported (Ubuntu 12.04 LTS)
|
||||
GCC 4.7.2 - can probably not be supported (Debian wheezy)
|
||||
GCC 4.7.3 - probably works
|
||||
GCC 4.8 - works and is supported from here on
|
||||
clang 3.0 - too old, not supported (Debian wheezy, Ubuntu 12.04 LTS)
|
||||
clang 3.2 - probably works
|
||||
clang 3.5 - works and is supported from here on
|
||||
|
||||
Use `include/osmium/util/compatibility.hpp` if there are compatibility problems
|
||||
between compilers due to different C++11 support.
|
||||
|
||||
|
||||
## Checking your code
|
||||
|
||||
The Osmium makefiles use pretty draconian warning options for the compiler.
|
||||
This is good. Code MUST never produce any warnings, even with those settings.
|
||||
If absolutely necessary pragmas can be used to disable certain warnings in
|
||||
specific areas of the code.
|
||||
|
||||
If the static code checker `cppcheck` is installed, the CMake configuration
|
||||
will add a new build target `cppcheck` that will check all `.cpp` and `.hpp`
|
||||
files. Cppcheck finds some bugs that gcc/clang doesn't. But take the result
|
||||
with a grain of salt, it also sometimes produces wrong warnings.
|
||||
|
||||
Set `BUILD_HEADERS=ON` in the CMake config to enable compiling all include
|
||||
files on their own to check whether dependencies are all okay. All include
|
||||
files MUST include all other include files they depend on.
|
||||
|
||||
Call `cmake/iwyu.sh` to check for proper includes and forward declarations.
|
||||
This uses the clang-based `include-what-you-use` program. Note that it does
|
||||
produce some false reports and crashes often. The `osmium.imp` file can be
|
||||
used to define mappings for iwyu. See the IWYU tool at
|
||||
<http://code.google.com/p/include-what-you-use/>.
|
||||
|
||||
|
||||
## Testing
|
||||
|
||||
There are a unit tests using the Catch Unit Test Framework in the `test`
|
||||
directory and some data tests in `test/osm-testdata`. They are built by the
|
||||
default cmake config. Run `ctest` to run them. Many more tests are needed.
|
||||
|
||||
|
||||
## Documenting the code
|
||||
|
||||
All namespaces, classes, functions, attributes, etc. should be documented.
|
||||
|
||||
Osmium uses the Doxygen (www.doxygen.org) source code documentation system.
|
||||
If it is installed, the CMake configuration will add a new build target, so
|
||||
you can build it with `make doc`.
|
||||
* We'd love for you to send pull requests for fixes you have made or new features
|
||||
you have added. Please read the [notes for developers](NOTES_FOR_DEVELOPERS.md)
|
||||
beforehand which contain some coding guidelines.
|
||||
|
||||
|
143
third_party/libosmium/NOTES_FOR_DEVELOPERS.md
vendored
Normal file
143
third_party/libosmium/NOTES_FOR_DEVELOPERS.md
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
|
||||
# Notes for Developers
|
||||
|
||||
Read this if you want to contribute to Libosmium.
|
||||
|
||||
|
||||
## Namespace
|
||||
|
||||
All Osmium code MUST be in the `osmium` namespace or one of its sub-namespaces.
|
||||
|
||||
|
||||
## Include-Only
|
||||
|
||||
Osmium is a include-only library. You can't compile the library itself. There
|
||||
is no libosmium.so.
|
||||
|
||||
One drawback ist that you can't have static data in classes, because there
|
||||
is no place to put this data.
|
||||
|
||||
All free functions must be declared `inline`.
|
||||
|
||||
|
||||
## Coding Conventions
|
||||
|
||||
These coding conventions have been changing over time and some code is still
|
||||
different.
|
||||
|
||||
* All include files have `#ifdef` guards around them, macros are the path name
|
||||
in all uppercase where the slashes (`/`) have been changed to underscore (`_`).
|
||||
* Class names begin with uppercase chars and use CamelCase. Smaller helper
|
||||
classes are usually defined as struct and have lowercase names.
|
||||
* Macros (and only macros) are all uppercase. Use macros sparingly, usually
|
||||
a simple (maybe constexpr) inline function is better. Undef macros after use
|
||||
if possible.
|
||||
* Macros should only be used for controlling which parts of the code should be
|
||||
included when compiling or to avoid major code repetitions.
|
||||
* Variables, attributes, and function names are lowercase with
|
||||
`underscores_between_words`.
|
||||
* Class attribute names start with `m_` (member).
|
||||
* Use `descriptive_variable_names`, exceptions are well-established conventions
|
||||
like `i` for a loop variable. Iterators are usually called `it`.
|
||||
* Declare variables where they are first used (C++ style), not at the beginning
|
||||
of a function (old C style).
|
||||
* Names from external namespaces (even `std`) are always mentioned explicitly.
|
||||
Do not use `using` (except for `std::swap`). This way we can't even by
|
||||
accident pollute the namespace of the code using Osmium.
|
||||
* Always use the standard swap idiom: `using std::swap; swap(foo, bar);`.
|
||||
* `#include` directives appear in three "blocks" after the copyright notice.
|
||||
The blocks are separated by blank lines. First block contains `#include`s for
|
||||
standard C/C++ includes, second block for any external libs used, third
|
||||
block for osmium internal includes. Within each block `#include`s are usually
|
||||
sorted by path name. All `#include`s use `<>` syntax not `""`.
|
||||
* Names not to be used from outside the library should be in a namespace
|
||||
called `detail` under the namespace where they would otherwise appear. If
|
||||
whole include files are never meant to be included from outside they should
|
||||
be in a subdirectory called `detail`.
|
||||
* All files have suffix `.hpp`.
|
||||
* Closing } of all classes and namespaces should have a trailing comment
|
||||
with the name of the class/namespace.
|
||||
* All constructors with one (or more arguments if they have a default) should
|
||||
be declared "explicit" unless there is a reason for them not to be. Document
|
||||
that reason.
|
||||
* If a class has any of the special methods (copy/move constructor/assigment,
|
||||
destructor) it should have all of them, possibly marking them as default or
|
||||
deleted.
|
||||
* Typedefs have `names_like_this_type` which end in `_type`. Typedefs should
|
||||
use the new `using foo_type = bar` syntax instead of the old
|
||||
`typedef bar foo_type`.
|
||||
* Template parameters are single uppercase letters or start with uppercase `T`
|
||||
and use CamelCase.
|
||||
* Always use `typename` in templates, not `class`: `template <typename T>`.
|
||||
* The ellipsis in variadic template never has a space to the left of it and
|
||||
always has a space to the right: `template <typename... TArgs>` etc.
|
||||
|
||||
Keep to the indentation and other styles used in the code. Use `make indent`
|
||||
in the toplevel directory to fix indentation and styling. It calls `astyle`
|
||||
with the right parameters. This program is in the `astyle` Debian package.
|
||||
|
||||
|
||||
## C++11
|
||||
|
||||
Osmium uses C++11 and you can use its features such as auto, lambdas,
|
||||
threading, etc. There are a few features we do not use, because even modern
|
||||
compilers don't support them yet. This list might change as we get more data
|
||||
about which compilers support which feature and what operating system versions
|
||||
or distributions have which versions of these compilers installed.
|
||||
|
||||
GCC 4.6 - too old, not supported (Ubuntu 12.04 LTS)
|
||||
GCC 4.7.2 - can probably not be supported (Debian wheezy)
|
||||
GCC 4.7.3 - probably works
|
||||
GCC 4.8 - works and is supported from here on
|
||||
clang 3.0 - too old, not supported (Debian wheezy, Ubuntu 12.04 LTS)
|
||||
clang 3.2 - probably works
|
||||
clang 3.5 - works and is supported from here on
|
||||
|
||||
Use `include/osmium/util/compatibility.hpp` if there are compatibility problems
|
||||
between compilers due to different C++11 support.
|
||||
|
||||
|
||||
## Operating systems
|
||||
|
||||
Usually all code must work on Linux, OSX, and Windows. Execptions are allowed
|
||||
for some minor functionality, but please discuss this first.
|
||||
|
||||
|
||||
## Checking your code
|
||||
|
||||
The Osmium makefiles use pretty draconian warning options for the compiler.
|
||||
This is good. Code MUST never produce any warnings, even with those settings.
|
||||
If absolutely necessary pragmas can be used to disable certain warnings in
|
||||
specific areas of the code.
|
||||
|
||||
If the static code checker `cppcheck` is installed, the CMake configuration
|
||||
will add a new build target `cppcheck` that will check all `.cpp` and `.hpp`
|
||||
files. Cppcheck finds some bugs that gcc/clang doesn't. But take the result
|
||||
with a grain of salt, it also sometimes produces wrong warnings.
|
||||
|
||||
Set `BUILD_HEADERS=ON` in the CMake config to enable compiling all include
|
||||
files on their own to check whether dependencies are all okay. All include
|
||||
files MUST include all other include files they depend on.
|
||||
|
||||
Call `cmake/iwyu.sh` to check for proper includes and forward declarations.
|
||||
This uses the clang-based `include-what-you-use` program. Note that it does
|
||||
produce some false reports and crashes often. The `osmium.imp` file can be
|
||||
used to define mappings for iwyu. See the IWYU tool at
|
||||
<http://code.google.com/p/include-what-you-use/>.
|
||||
|
||||
|
||||
## Testing
|
||||
|
||||
There are a unit tests using the Catch Unit Test Framework in the `test`
|
||||
directory and some data tests in `test/osm-testdata`. They are built by the
|
||||
default cmake config. Run `ctest` to run them. Many more tests are needed.
|
||||
|
||||
|
||||
## Documenting the code
|
||||
|
||||
All namespaces, classes, functions, attributes, etc. should be documented.
|
||||
|
||||
Osmium uses the Doxygen (www.doxygen.org) source code documentation system.
|
||||
If it is installed, the CMake configuration will add a new build target, so
|
||||
you can build it with `make doc`.
|
||||
|
85
third_party/libosmium/appveyor.yml
vendored
85
third_party/libosmium/appveyor.yml
vendored
@ -22,88 +22,5 @@ clone_folder: c:\projects\libosmium
|
||||
|
||||
platform: x64
|
||||
|
||||
install:
|
||||
# show all available env vars
|
||||
- set
|
||||
- echo cmake on AppVeyor
|
||||
- cmake -version
|
||||
- call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
|
||||
- set PATH=c:\projects\libosmium\cmake-3.1.0-win32-x86\bin;%PATH%
|
||||
- set LODEPSDIR=c:\projects\libosmium\libosmium-deps
|
||||
- set PROJ_LIB=%LODEPSDIR%\proj\share
|
||||
- set GDAL_DATA=%LODEPSDIR%\gdal\data
|
||||
#geos.dll
|
||||
- set PATH=%LODEPSDIR%\geos\lib;%PATH%
|
||||
#gdal.dll
|
||||
- set PATH=%LODEPSDIR%\gdal\lib;%PATH%
|
||||
#libexpat.dll
|
||||
- set PATH=%LODEPSDIR%\expat\lib;%PATH%
|
||||
#libtiff.dll
|
||||
- set PATH=%LODEPSDIR%\libtiff\lib;%PATH%
|
||||
#jpeg.dll
|
||||
- set PATH=%LODEPSDIR%\jpeg\lib;%PATH%
|
||||
#zlibwapi.dll
|
||||
- set PATH=%LODEPSDIR%\zlib\lib;%PATH%
|
||||
#convert backslashes in bzip2 path to forward slashes
|
||||
#cmake cannot find it otherwise
|
||||
- set LIBBZIP2=%LODEPSDIR%\bzip2\lib\libbz2.lib
|
||||
- set LIBBZIP2=%LIBBZIP2:\=/%
|
||||
- ps: Start-FileDownload https://mapbox.s3.amazonaws.com/windows-builds/windows-build-deps/cmake-3.1.0-win32-x86.7z -FileName cm.7z
|
||||
- ps: Start-FileDownload https://mapbox.s3.amazonaws.com/windows-builds/windows-build-deps/libosmium-deps-win-14.0-x64.7z -FileName lodeps.7z
|
||||
- 7z x cm.7z | %windir%\system32\find "ing archive"
|
||||
- 7z x lodeps.7z | %windir%\system32\find "ing archive"
|
||||
- echo %LODEPSDIR%
|
||||
- dir %LODEPSDIR%
|
||||
- echo our own cmake
|
||||
- cmake -version
|
||||
- cd c:\projects
|
||||
- git clone --depth 1 https://github.com/osmcode/osm-testdata.git
|
||||
|
||||
build_script:
|
||||
- cd c:\projects\libosmium
|
||||
- mkdir build
|
||||
- cd build
|
||||
- echo %config%
|
||||
# This will produce lots of LNK4099 warnings which can be ignored.
|
||||
# Unfortunately they can't be disabled, see
|
||||
# http://stackoverflow.com/questions/661606/visual-c-how-to-disable-specific-linker-warnings
|
||||
- cmake -LA -G "Visual Studio 14 Win64"
|
||||
-DOsmium_DEBUG=TRUE
|
||||
-DCMAKE_BUILD_TYPE=%config%
|
||||
-DBUILD_HEADERS=OFF
|
||||
-DBOOST_ROOT=%LODEPSDIR%\boost
|
||||
-DBoost_PROGRAM_OPTIONS_LIBRARY=%LODEPSDIR%\boost\lib\libboost_program_options-vc140-mt-1_58.lib
|
||||
-DZLIB_LIBRARY=%LODEPSDIR%\zlib\lib\zlibwapi.lib
|
||||
-DBZIP2_LIBRARY_RELEASE=%LIBBZIP2%
|
||||
-DCMAKE_PREFIX_PATH=%LODEPSDIR%\zlib;%LODEPSDIR%\expat;%LODEPSDIR%\bzip2;%LODEPSDIR%\geos;%LODEPSDIR%\gdal;%LODEPSDIR%\proj;%LODEPSDIR%\sparsehash;%LODEPSDIR%\wingetopt
|
||||
..
|
||||
- msbuild libosmium.sln /p:Configuration=%config% /toolsversion:14.0 /p:Platform=x64 /p:PlatformToolset=v140
|
||||
#- cmake .. -LA -G "NMake Makefiles"
|
||||
# -DOsmium_DEBUG=TRUE
|
||||
# -DCMAKE_BUILD_TYPE=%config%
|
||||
# -DBOOST_ROOT=%LODEPSDIR%\boost
|
||||
# -DBoost_PROGRAM_OPTIONS_LIBRARY=%LODEPSDIR%\boost\lib\libboost_program_options-vc140-mt-1_57.lib
|
||||
# -DZLIB_LIBRARY=%LODEPSDIR%\zlib\lib\zlibwapi.lib
|
||||
# -DZLIB_INCLUDE_DIR=%LODEPSDIR%\zlib\include
|
||||
# -DEXPAT_LIBRARY=%LODEPSDIR%\expat\lib\libexpat.lib
|
||||
# -DEXPAT_INCLUDE_DIR=%LODEPSDIR%\expat\include
|
||||
# -DBZIP2_LIBRARIES=%LIBBZIP2%
|
||||
# -DBZIP2_INCLUDE_DIR=%LODEPSDIR%\bzip2\include
|
||||
# -DGDAL_LIBRARY=%LODEPSDIR%\gdal\lib\gdal_i.lib
|
||||
# -DGDAL_INCLUDE_DIR=%LODEPSDIR%\gdal\include
|
||||
# -DGEOS_LIBRARY=%LODEPSDIR%\geos\lib\geos.lib
|
||||
# -DGEOS_INCLUDE_DIR=%LODEPSDIR%\geos\include
|
||||
# -DPROJ_LIBRARY=%LODEPSDIR%\proj\lib\proj.lib
|
||||
# -DPROJ_INCLUDE_DIR=%LODEPSDIR%\proj\include
|
||||
# -DSPARSEHASH_INCLUDE_DIR=%LODEPSDIR%\sparsehash\include
|
||||
# -DGETOPT_LIBRARY=%LODEPSDIR%\wingetopt\lib\wingetopt.lib
|
||||
# -DGETOPT_INCLUDE_DIR=%LODEPSDIR%\wingetopt\include
|
||||
#- nmake
|
||||
|
||||
test_script:
|
||||
# "-E testdata-overview" exempts one test we know fails on Appveyor
|
||||
# because we currently don't have spatialite support.
|
||||
- ctest --output-on-failure
|
||||
-C %config%
|
||||
-E testdata-overview
|
||||
|
||||
- build-appveyor.bat
|
||||
|
@ -5,7 +5,9 @@
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <osmium/io/any_input.hpp>
|
||||
#include <osmium/handler.hpp>
|
||||
@ -35,12 +37,12 @@ struct CountHandler : public osmium::handler::Handler {
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
std::string input_filename = argv[1];
|
||||
const std::string input_filename{argv[1]};
|
||||
|
||||
osmium::io::Reader reader(input_filename);
|
||||
osmium::io::Reader reader{input_filename};
|
||||
|
||||
CountHandler handler;
|
||||
osmium::apply(reader, handler);
|
||||
|
@ -5,7 +5,9 @@
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <osmium/io/any_input.hpp>
|
||||
#include <osmium/handler.hpp>
|
||||
@ -38,12 +40,12 @@ struct CountHandler : public osmium::handler::Handler {
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
std::string input_filename = argv[1];
|
||||
const std::string input_filename{argv[1]};
|
||||
|
||||
osmium::io::Reader reader(input_filename);
|
||||
osmium::io::Reader reader{input_filename};
|
||||
|
||||
CountHandler handler;
|
||||
osmium::apply(reader, handler);
|
||||
|
@ -4,7 +4,9 @@
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <osmium/index/map/all.hpp>
|
||||
#include <osmium/handler/node_locations_for_ways.hpp>
|
||||
@ -13,24 +15,24 @@
|
||||
#include <osmium/io/any_input.hpp>
|
||||
#include <osmium/handler.hpp>
|
||||
|
||||
typedef osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location> index_type;
|
||||
using index_type = osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>;
|
||||
|
||||
typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type;
|
||||
using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE FORMAT\n";
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
std::string input_filename = argv[1];
|
||||
std::string location_store = argv[2];
|
||||
const std::string input_filename{argv[1]};
|
||||
const std::string location_store{argv[2]};
|
||||
|
||||
osmium::io::Reader reader(input_filename);
|
||||
osmium::io::Reader reader{input_filename};
|
||||
|
||||
const auto& map_factory = osmium::index::MapFactory<osmium::unsigned_object_id_type, osmium::Location>::instance();
|
||||
std::unique_ptr<index_type> index = map_factory.create_map(location_store);
|
||||
location_handler_type location_handler(*index);
|
||||
location_handler_type location_handler{*index};
|
||||
location_handler.ignore_errors();
|
||||
|
||||
osmium::apply(reader, location_handler);
|
||||
|
@ -19,8 +19,10 @@
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include <osmium/index/map/all.hpp>
|
||||
#include <osmium/handler/node_locations_for_ways.hpp>
|
||||
@ -29,23 +31,23 @@
|
||||
#include <osmium/io/any_input.hpp>
|
||||
#include <osmium/handler.hpp>
|
||||
|
||||
typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> static_index_type;
|
||||
const std::string location_store="sparse_mem_array";
|
||||
using static_index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
|
||||
const std::string location_store{"sparse_mem_array"};
|
||||
|
||||
typedef osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location> dynamic_index_type;
|
||||
using dynamic_index_type = osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>;
|
||||
|
||||
typedef osmium::handler::NodeLocationsForWays<static_index_type> static_location_handler_type;
|
||||
typedef osmium::handler::NodeLocationsForWays<dynamic_index_type> dynamic_location_handler_type;
|
||||
using static_location_handler_type = osmium::handler::NodeLocationsForWays<static_index_type>;
|
||||
using dynamic_location_handler_type = osmium::handler::NodeLocationsForWays<dynamic_index_type>;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
std::string input_filename = argv[1];
|
||||
const std::string input_filename{argv[1]};
|
||||
|
||||
osmium::memory::Buffer buffer = osmium::io::read_file(input_filename);
|
||||
osmium::memory::Buffer buffer{osmium::io::read_file(input_filename)};
|
||||
|
||||
const auto& map_factory = osmium::index::MapFactory<osmium::unsigned_object_id_type, osmium::Location>::instance();
|
||||
|
||||
@ -67,20 +69,20 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
{
|
||||
// static index
|
||||
osmium::memory::Buffer tmp_buffer(buffer.committed());
|
||||
osmium::memory::Buffer tmp_buffer{buffer.committed()};
|
||||
for (const auto& item : buffer) {
|
||||
tmp_buffer.add_item(item);
|
||||
tmp_buffer.commit();
|
||||
}
|
||||
|
||||
static_index_type static_index;
|
||||
static_location_handler_type static_location_handler(static_index);
|
||||
static_location_handler_type static_location_handler{static_index};
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
osmium::apply(tmp_buffer, static_location_handler);
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
const auto end = std::chrono::steady_clock::now();
|
||||
|
||||
double duration = std::chrono::duration<double, std::milli>(end-start).count();
|
||||
const double duration = std::chrono::duration<double, std::milli>(end-start).count();
|
||||
|
||||
if (duration < static_min) static_min = duration;
|
||||
if (duration > static_max) static_max = duration;
|
||||
@ -89,21 +91,21 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
{
|
||||
// dynamic index
|
||||
osmium::memory::Buffer tmp_buffer(buffer.committed());
|
||||
osmium::memory::Buffer tmp_buffer{buffer.committed()};
|
||||
for (const auto& item : buffer) {
|
||||
tmp_buffer.add_item(item);
|
||||
tmp_buffer.commit();
|
||||
}
|
||||
|
||||
std::unique_ptr<dynamic_index_type> index = map_factory.create_map(location_store);
|
||||
dynamic_location_handler_type dynamic_location_handler(*index);
|
||||
dynamic_location_handler_type dynamic_location_handler{*index};
|
||||
dynamic_location_handler.ignore_errors();
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
osmium::apply(tmp_buffer, dynamic_location_handler);
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
const auto end = std::chrono::steady_clock::now();
|
||||
|
||||
double duration = std::chrono::duration<double, std::milli>(end-start).count();
|
||||
const double duration = std::chrono::duration<double, std::milli>(end-start).count();
|
||||
|
||||
if (duration < dynamic_min) dynamic_min = duration;
|
||||
if (duration > dynamic_max) dynamic_max = duration;
|
||||
@ -111,21 +113,21 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
double static_avg = static_sum/runs;
|
||||
double dynamic_avg = dynamic_sum/runs;
|
||||
const double static_avg = static_sum/runs;
|
||||
const double dynamic_avg = dynamic_sum/runs;
|
||||
|
||||
std::cout << "static min=" << static_min << "ms avg=" << static_avg << "ms max=" << static_max << "ms\n";
|
||||
std::cout << "dynamic min=" << dynamic_min << "ms avg=" << dynamic_avg << "ms max=" << dynamic_max << "ms\n";
|
||||
|
||||
double rfactor = 100.0;
|
||||
double diff_min = std::round((dynamic_min - static_min) * rfactor) / rfactor;
|
||||
double diff_avg = std::round((dynamic_avg - static_avg) * rfactor) / rfactor;
|
||||
double diff_max = std::round((dynamic_max - static_max) * rfactor) / rfactor;
|
||||
const double rfactor = 100.0;
|
||||
const double diff_min = std::round((dynamic_min - static_min) * rfactor) / rfactor;
|
||||
const double diff_avg = std::round((dynamic_avg - static_avg) * rfactor) / rfactor;
|
||||
const double diff_max = std::round((dynamic_max - static_max) * rfactor) / rfactor;
|
||||
|
||||
double prfactor = 10.0;
|
||||
double percent_min = std::round((100.0 * diff_min / static_min) * prfactor) / prfactor;
|
||||
double percent_avg = std::round((100.0 * diff_avg / static_avg) * prfactor) / prfactor;
|
||||
double percent_max = std::round((100.0 * diff_max / static_max) * prfactor) / prfactor;
|
||||
const double prfactor = 10.0;
|
||||
const double percent_min = std::round((100.0 * diff_min / static_min) * prfactor) / prfactor;
|
||||
const double percent_avg = std::round((100.0 * diff_avg / static_avg) * prfactor) / prfactor;
|
||||
const double percent_max = std::round((100.0 * diff_max / static_max) * prfactor) / prfactor;
|
||||
|
||||
std::cout << "difference:";
|
||||
std::cout << " min=" << diff_min << "ms (" << percent_min << "%)";
|
||||
|
@ -4,8 +4,9 @@
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <osmium/io/any_input.hpp>
|
||||
#include <osmium/io/any_output.hpp>
|
||||
@ -13,16 +14,16 @@
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " INPUT-FILE OUTPUT-FILE\n";
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
std::string input_filename = argv[1];
|
||||
std::string output_filename = argv[2];
|
||||
std::string input_filename{argv[1]};
|
||||
std::string output_filename{argv[2]};
|
||||
|
||||
osmium::io::Reader reader(input_filename);
|
||||
osmium::io::File output_file(output_filename, "pbf");
|
||||
osmium::io::Reader reader{input_filename};
|
||||
osmium::io::File output_file{output_filename, "pbf"};
|
||||
osmium::io::Header header;
|
||||
osmium::io::Writer writer(output_file, header, osmium::io::overwrite::allow);
|
||||
osmium::io::Writer writer{output_file, header, osmium::io::overwrite::allow};
|
||||
|
||||
while (osmium::memory::Buffer buffer = reader.read()) {
|
||||
writer(std::move(buffer));
|
||||
|
123
third_party/libosmium/build-appveyor.bat
vendored
Normal file
123
third_party/libosmium/build-appveyor.bat
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
@ECHO OFF
|
||||
SETLOCAL
|
||||
SET EL=0
|
||||
|
||||
ECHO ~~~~~~ %~f0 ~~~~~~
|
||||
|
||||
SET CUSTOM_CMAKE=cmake-3.6.2-win64-x64
|
||||
::show all available env vars
|
||||
SET
|
||||
ECHO cmake on AppVeyor
|
||||
cmake -version
|
||||
|
||||
ECHO activating VS cmd prompt && CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
|
||||
SET lodir=%CD%
|
||||
SET PATH=%lodir%\%CUSTOM_CMAKE%\bin;%PATH%
|
||||
SET LODEPSDIR=%lodir%\libosmium-deps
|
||||
SET PROJ_LIB=%LODEPSDIR%\proj\share
|
||||
SET GDAL_DATA=%LODEPSDIR%\gdal\data
|
||||
::gdal.dll
|
||||
SET PATH=%LODEPSDIR%\gdal\lib;%PATH%
|
||||
::geos.dll
|
||||
SET PATH=%LODEPSDIR%\geos\lib;%PATH%
|
||||
::libtiff.dll
|
||||
SET PATH=%LODEPSDIR%\libtiff\lib;%PATH%
|
||||
::jpeg.dll
|
||||
SET PATH=%LODEPSDIR%\jpeg\lib;%PATH%
|
||||
::libexpat.dll
|
||||
SET PATH=%LODEPSDIR%\expat\lib;%PATH%
|
||||
::zlibwapi.dll
|
||||
SET PATH=%LODEPSDIR%\zlib\lib;%PATH%
|
||||
::convert backslashes in bzip2 path to forward slashes
|
||||
::cmake cannot find it otherwise
|
||||
SET LIBBZIP2=%LODEPSDIR%\bzip2\lib\libbz2.lib
|
||||
SET LIBBZIP2=%LIBBZIP2:\=/%
|
||||
|
||||
IF NOT EXIST cm.7z ECHO downloading cmake %CUSTOM_CMAKE% ... && powershell Invoke-WebRequest https://mapbox.s3.amazonaws.com/windows-builds/windows-build-deps/%CUSTOM_CMAKE%.7z -OutFile cm.7z
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
|
||||
IF NOT EXIST lodeps.7z ECHO downloading binary dependencies... && powershell Invoke-WebRequest https://mapbox.s3.amazonaws.com/windows-builds/windows-build-deps/libosmium-deps-win-14.0-x64.7z -OutFile lodeps.7z
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
|
||||
IF NOT EXIST %CUSTOM_CMAKE% ECHO extracting cmake... && 7z x cm.7z | %windir%\system32\find "ing archive"
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
|
||||
IF NOT EXIST %LODEPSDIR% ECHO extracting binary dependencies... && 7z x lodeps.7z | %windir%\system32\find "ing archive"
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
|
||||
ECHO %LODEPSDIR%
|
||||
DIR %LODEPSDIR%
|
||||
::TREE %LODEPSDIR%
|
||||
|
||||
::powershell (Get-ChildItem $env:LODEPSDIR\boost\lib -Filter *boost*.dll)[0].BaseName.split('_')[-1]
|
||||
FOR /F "tokens=1 usebackq" %%i in (`powershell ^(Get-ChildItem %LODEPSDIR%\boost\lib -Filter *boost*.dll^)[0].BaseName.split^('_'^)[-1]`) DO SET BOOST_VERSION=%%i
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
|
||||
ECHO BOOST_VERSION^: %BOOST_VERSION%
|
||||
|
||||
ECHO our own cmake
|
||||
cmake -version
|
||||
|
||||
CD %lodir%\..
|
||||
|
||||
IF NOT EXIST osm-testdata ECHO cloning osm-testdata && git clone --depth 1 https://github.com/osmcode/osm-testdata.git
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
CD osm-testdata
|
||||
git fetch
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
git pull
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
|
||||
CD %lodir%
|
||||
IF EXIST build ECHO deleting build dir... && RD /Q /S build
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
|
||||
MKDIR build
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
|
||||
CD build
|
||||
ECHO config^: %config%
|
||||
|
||||
::This will produce lots of LNK4099 warnings which can be ignored.
|
||||
::Unfortunately they can't be disabled, see
|
||||
::http://stackoverflow.com/questions/661606/visual-c-how-to-disable-specific-linker-warnings
|
||||
SET CMAKE_CMD=cmake .. ^
|
||||
-LA -G "Visual Studio 14 Win64" ^
|
||||
-DOsmium_DEBUG=TRUE ^
|
||||
-DCMAKE_BUILD_TYPE=%config% ^
|
||||
-DBUILD_HEADERS=OFF ^
|
||||
-DBOOST_ROOT=%LODEPSDIR%\boost ^
|
||||
-DZLIB_LIBRARY=%LODEPSDIR%\zlib\lib\zlibwapi.lib ^
|
||||
-DBZIP2_LIBRARY_RELEASE=%LIBBZIP2% ^
|
||||
-DCMAKE_PREFIX_PATH=%LODEPSDIR%\zlib;%LODEPSDIR%\expat;%LODEPSDIR%\bzip2;%LODEPSDIR%\geos;%LODEPSDIR%\gdal;%LODEPSDIR%\proj;%LODEPSDIR%\sparsehash;%LODEPSDIR%\wingetopt
|
||||
|
||||
ECHO calling^: %CMAKE_CMD%
|
||||
%CMAKE_CMD%
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
|
||||
msbuild libosmium.sln ^
|
||||
/p:Configuration=%config% ^
|
||||
/toolsversion:14.0 ^
|
||||
/p:Platform=x64 ^
|
||||
/p:PlatformToolset=v140
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
|
||||
ctest --output-on-failure ^
|
||||
-C %config% ^
|
||||
-E testdata-overview
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
|
||||
|
||||
GOTO DONE
|
||||
|
||||
:ERROR
|
||||
ECHO ~~~~~~ ERROR %~f0 ~~~~~~
|
||||
SET EL=%ERRORLEVEL%
|
||||
|
||||
:DONE
|
||||
IF %EL% NEQ 0 ECHO. && ECHO !!! ERRORLEVEL^: %EL% !!! && ECHO.
|
||||
ECHO ~~~~~~ DONE %~f0 ~~~~~~
|
||||
|
||||
EXIT /b %EL%
|
43
third_party/libosmium/build-local.bat
vendored
Normal file
43
third_party/libosmium/build-local.bat
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
@ECHO OFF
|
||||
SETLOCAL
|
||||
SET EL=0
|
||||
|
||||
ECHO ~~~~~~ %~f0 ~~~~~~
|
||||
|
||||
ECHO.
|
||||
ECHO build-local ["config=Dev"]
|
||||
ECHO default config^: RelWithDebInfo
|
||||
ECHO.
|
||||
|
||||
SET platform=x64
|
||||
SET config=RelWithDebInfo
|
||||
|
||||
:: OVERRIDE PARAMETERS >>>>>>>>
|
||||
:NEXT-ARG
|
||||
|
||||
IF '%1'=='' GOTO ARGS-DONE
|
||||
ECHO setting %1
|
||||
SET %1
|
||||
SHIFT
|
||||
GOTO NEXT-ARG
|
||||
|
||||
:ARGS-DONE
|
||||
::<<<<< OVERRIDE PARAMETERS
|
||||
|
||||
WHERE 7z
|
||||
IF %ERRORLEVEL% NEQ 0 ECHO 7zip not on PATH && GOTO ERROR
|
||||
|
||||
CALL build-appveyor.bat
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||
|
||||
GOTO DONE
|
||||
|
||||
:ERROR
|
||||
ECHO ~~~~~~ ERROR %~f0 ~~~~~~
|
||||
SET EL=%ERRORLEVEL%
|
||||
|
||||
:DONE
|
||||
IF %EL% NEQ 0 ECHO. && ECHO !!! ERRORLEVEL^: %EL% !!! && ECHO.
|
||||
ECHO ~~~~~~ DONE %~f0 ~~~~~~
|
||||
|
||||
EXIT /b %EL%
|
5
third_party/libosmium/cmake/iwyu.sh
vendored
5
third_party/libosmium/cmake/iwyu.sh
vendored
@ -6,6 +6,11 @@
|
||||
# TODO: This script should be integrated with cmake in some way...
|
||||
#
|
||||
|
||||
# If these are set, the wrong compiler is used by iwyu and there will be
|
||||
# errors about missing includes.
|
||||
unset CC
|
||||
unset CXX
|
||||
|
||||
cmdline="iwyu -Xiwyu --mapping_file=osmium.imp -std=c++11 -I include"
|
||||
|
||||
log=build/iwyu.log
|
||||
|
40
third_party/libosmium/examples/CMakeLists.txt
vendored
40
third_party/libosmium/examples/CMakeLists.txt
vendored
@ -12,13 +12,17 @@ set(EXAMPLES
|
||||
area_test
|
||||
convert
|
||||
count
|
||||
create_node_cache
|
||||
debug
|
||||
filter_discussions
|
||||
index
|
||||
location_cache_create
|
||||
location_cache_use
|
||||
pub_names
|
||||
read
|
||||
read_with_progress
|
||||
road_length
|
||||
serdump
|
||||
use_node_cache
|
||||
tiles
|
||||
CACHE STRING "Example programs"
|
||||
)
|
||||
|
||||
@ -28,7 +32,7 @@ set(EXAMPLES
|
||||
# Examples depending on wingetopt
|
||||
#
|
||||
#-----------------------------------------------------------------------------
|
||||
set(GETOPT_EXAMPLES area_test convert serdump)
|
||||
set(GETOPT_EXAMPLES area_test convert index serdump)
|
||||
if(NOT GETOPT_MISSING)
|
||||
foreach(example ${GETOPT_EXAMPLES})
|
||||
list(APPEND EXAMPLE_LIBS_${example} ${GETOPT_LIBRARY})
|
||||
@ -42,36 +46,6 @@ else()
|
||||
endif()
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
# Examples depending on SparseHash
|
||||
#
|
||||
#-----------------------------------------------------------------------------
|
||||
if(NOT SPARSEHASH_FOUND)
|
||||
list(REMOVE_ITEM EXAMPLES area_test)
|
||||
message(STATUS "Configuring examples - Skipping examples because Google SparseHash not found:")
|
||||
message(STATUS " - osmium_area_test")
|
||||
endif()
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
# Examples depending on Boost Program Options
|
||||
#
|
||||
#-----------------------------------------------------------------------------
|
||||
unset(Boost_LIBRARIES)
|
||||
unset(Boost_FOUND)
|
||||
find_package(Boost 1.38 COMPONENTS program_options)
|
||||
|
||||
if(Boost_PROGRAM_OPTIONS_FOUND)
|
||||
list(APPEND EXAMPLE_LIBS_index ${Boost_PROGRAM_OPTIONS_LIBRARY})
|
||||
else()
|
||||
list(REMOVE_ITEM EXAMPLES index)
|
||||
message(STATUS "Configuring examples - Skipping examples because Boost program_options not found:")
|
||||
message(STATUS " - osmium_index")
|
||||
endif()
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
# Configure examples
|
||||
|
32
third_party/libosmium/examples/README.md
vendored
Normal file
32
third_party/libosmium/examples/README.md
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
# Osmium example programs
|
||||
|
||||
The programs in this directory are intended as examples for developers. They
|
||||
contain extensive comments explaining what's going on. Note that the examples
|
||||
only cover a small part of what Osmium can do, you should also read the
|
||||
documentation and API documentation.
|
||||
|
||||
All programs can be run without arguments and they will tell you how to run
|
||||
them.
|
||||
|
||||
## Very simple examples
|
||||
|
||||
* `osmium_read`
|
||||
* `osmium_count`
|
||||
* `osmium_debug`
|
||||
* `osmium_tiles`
|
||||
|
||||
## Still reasonably simple examples
|
||||
|
||||
* `osmium_filter_discussions`
|
||||
* `osmium_convert`
|
||||
|
||||
## More advanced examples
|
||||
|
||||
* `osmium_area_test`
|
||||
|
||||
## License
|
||||
|
||||
The code in these example files is released into the Public Domain. Feel free
|
||||
to copy the code and build on it.
|
||||
|
129
third_party/libosmium/examples/osmium_area_test.cpp
vendored
129
third_party/libosmium/examples/osmium_area_test.cpp
vendored
@ -1,48 +1,81 @@
|
||||
/*
|
||||
|
||||
This is an example tool that creates multipolygons from OSM data
|
||||
and dumps them to stdout.
|
||||
EXAMPLE osmium_area_test
|
||||
|
||||
Create multipolygons from OSM data and dump them to stdout in one of two
|
||||
formats: WKT or using the built-in Dump format.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input
|
||||
* location indexes and the NodeLocationsForWays handler
|
||||
* the MultipolygonCollector and Assembler to assemble areas (multipolygons)
|
||||
* your own handler that works with areas (multipolygons)
|
||||
* the WKTFactory to write geometries in WKT format
|
||||
* the Dump handler
|
||||
* the DynamicHandler
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
* osmium_debug
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <getopt.h>
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <getopt.h> // for getopt_long
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
|
||||
// For assembling multipolygons
|
||||
#include <osmium/area/assembler.hpp>
|
||||
#include <osmium/area/multipolygon_collector.hpp>
|
||||
|
||||
// For the DynamicHandler class
|
||||
#include <osmium/dynamic_handler.hpp>
|
||||
|
||||
// For the WKT factory
|
||||
#include <osmium/geom/wkt.hpp>
|
||||
|
||||
// For the Dump handler
|
||||
#include <osmium/handler/dump.hpp>
|
||||
|
||||
// For the NodeLocationForWays handler
|
||||
#include <osmium/handler/node_locations_for_ways.hpp>
|
||||
#include <osmium/index/map/dummy.hpp>
|
||||
#include <osmium/index/map/sparse_mem_array.hpp>
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// For osmium::apply()
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
|
||||
typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
|
||||
typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
|
||||
// For the location index. There are different types of indexes available.
|
||||
// This will work for small and medium sized input files.
|
||||
#include <osmium/index/map/sparse_mem_array.hpp>
|
||||
|
||||
// The type of index used. This must match the include file above
|
||||
using index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
|
||||
|
||||
// The location handler always depends on the index type
|
||||
using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
|
||||
|
||||
// This handler writes all area geometries out in WKT (Well Known Text) format.
|
||||
class WKTDump : public osmium::handler::Handler {
|
||||
|
||||
osmium::geom::WKTFactory<> m_factory ;
|
||||
|
||||
std::ostream& m_out;
|
||||
// This factory is used to create a geometry in WKT format from OSM
|
||||
// objects. The template parameter is empty here, because we output WGS84
|
||||
// coordinates, but could be used for a projection.
|
||||
osmium::geom::WKTFactory<> m_factory;
|
||||
|
||||
public:
|
||||
|
||||
WKTDump(std::ostream& out) :
|
||||
m_out(out) {
|
||||
}
|
||||
|
||||
// This callback is called by osmium::apply for each area in the data.
|
||||
void area(const osmium::Area& area) {
|
||||
try {
|
||||
m_out << m_factory.create_multipolygon(area) << "\n";
|
||||
} catch (osmium::geometry_error& e) {
|
||||
m_out << "GEOMETRY ERROR: " << e.what() << "\n";
|
||||
std::cout << m_factory.create_multipolygon(area) << "\n";
|
||||
} catch (const osmium::geometry_error& e) {
|
||||
std::cout << "GEOMETRY ERROR: " << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,8 +98,13 @@ int main(int argc, char* argv[]) {
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
// Initialize an empty DynamicHandler. Later it will be associated
|
||||
// with one of the handlers. You can think of the DynamicHandler as
|
||||
// a kind of "variant handler" or a "pointer handler" pointing to the
|
||||
// real handler.
|
||||
osmium::handler::DynamicHandler handler;
|
||||
|
||||
// Read options from command line.
|
||||
while (true) {
|
||||
int c = getopt_long(argc, argv, "hwo", long_options, 0);
|
||||
if (c == -1) {
|
||||
@ -76,54 +114,81 @@ int main(int argc, char* argv[]) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
print_help();
|
||||
exit(0);
|
||||
std::exit(0);
|
||||
case 'w':
|
||||
handler.set<WKTDump>(std::cout);
|
||||
handler.set<WKTDump>();
|
||||
break;
|
||||
case 'o':
|
||||
handler.set<osmium::handler::Dump>(std::cout);
|
||||
break;
|
||||
default:
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int remaining_args = argc - optind;
|
||||
if (remaining_args != 1) {
|
||||
std::cerr << "Usage: " << argv[0] << " [OPTIONS] OSMFILE\n";
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
osmium::io::File infile(argv[optind]);
|
||||
osmium::io::File input_file{argv[optind]};
|
||||
|
||||
// Configuration for the multipolygon assembler. Here the default settings
|
||||
// are used, but you could change multiple settings.
|
||||
osmium::area::Assembler::config_type assembler_config;
|
||||
osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config);
|
||||
|
||||
// Initialize the MultipolygonCollector. Its job is to collect all
|
||||
// relations and member ways needed for each area. It then calls an
|
||||
// instance of the osmium::area::Assembler class (with the given config)
|
||||
// to actually assemble one area.
|
||||
osmium::area::MultipolygonCollector<osmium::area::Assembler> collector{assembler_config};
|
||||
|
||||
// We read the input file twice. In the first pass, only relations are
|
||||
// read and fed into the multipolygon collector.
|
||||
std::cerr << "Pass 1...\n";
|
||||
osmium::io::Reader reader1(infile, osmium::osm_entity_bits::relation);
|
||||
osmium::io::Reader reader1{input_file, osmium::osm_entity_bits::relation};
|
||||
collector.read_relations(reader1);
|
||||
reader1.close();
|
||||
std::cerr << "Pass 1 done\n";
|
||||
|
||||
// Output the amount of main memory used so far. All multipolygon relations
|
||||
// are in memory now.
|
||||
std::cerr << "Memory:\n";
|
||||
collector.used_memory();
|
||||
|
||||
index_pos_type index_pos;
|
||||
index_neg_type index_neg;
|
||||
location_handler_type location_handler(index_pos, index_neg);
|
||||
location_handler.ignore_errors(); // XXX
|
||||
// The index storing all node locations.
|
||||
index_type index;
|
||||
|
||||
// The handler that stores all node locations in the index and adds them
|
||||
// to the ways.
|
||||
location_handler_type location_handler{index};
|
||||
|
||||
// If a location is not available in the index, we ignore it. It might
|
||||
// not be needed (if it is not part of a multipolygon relation), so why
|
||||
// create an error?
|
||||
location_handler.ignore_errors();
|
||||
|
||||
// On the second pass we read all objects and run them first through the
|
||||
// node location handler and then the multipolygon collector. The collector
|
||||
// will put the areas it has created into the "buffer" which are then
|
||||
// fed through our "handler".
|
||||
std::cerr << "Pass 2...\n";
|
||||
osmium::io::Reader reader2(infile);
|
||||
osmium::io::Reader reader2{input_file};
|
||||
osmium::apply(reader2, location_handler, collector.handler([&handler](osmium::memory::Buffer&& buffer) {
|
||||
osmium::apply(buffer, handler);
|
||||
}));
|
||||
reader2.close();
|
||||
std::cerr << "Pass 2 done\n";
|
||||
|
||||
// Output the amount of main memory used so far. All complete multipolygon
|
||||
// relations have been cleaned up.
|
||||
std::cerr << "Memory:\n";
|
||||
collector.used_memory();
|
||||
|
||||
// If there were multipolgyon relations in the input, but some of their
|
||||
// members are not in the input file (which often happens for extracts)
|
||||
// this will write the IDs of the incomplete relations to stderr.
|
||||
std::vector<const osmium::Relation*> incomplete_relations = collector.get_incomplete_relations();
|
||||
if (!incomplete_relations.empty()) {
|
||||
std::cerr << "Warning! Some member ways missing for these multipolygon relations:";
|
||||
|
@ -1,16 +1,32 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_convert
|
||||
|
||||
Convert OSM files from one format into another.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input and output
|
||||
* file types
|
||||
* Osmium buffers
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <getopt.h>
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <exception> // for std::exception
|
||||
#include <getopt.h> // for getopt_long
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
#include <string> // for std::string
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// Allow any format of output files (XML, PBF, ...)
|
||||
#include <osmium/io/any_output.hpp>
|
||||
|
||||
void print_help() {
|
||||
@ -43,9 +59,13 @@ int main(int argc, char* argv[]) {
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
// Input and output format are empty by default. Later this will mean that
|
||||
// the format should be taken from the input and output file suffix,
|
||||
// respectively.
|
||||
std::string input_format;
|
||||
std::string output_format;
|
||||
|
||||
// Read options from command line.
|
||||
while (true) {
|
||||
int c = getopt_long(argc, argv, "dhf:t:", long_options, 0);
|
||||
if (c == -1) {
|
||||
@ -55,7 +75,7 @@ int main(int argc, char* argv[]) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
print_help();
|
||||
exit(0);
|
||||
std::exit(0);
|
||||
case 'f':
|
||||
input_format = optarg;
|
||||
break;
|
||||
@ -63,49 +83,73 @@ int main(int argc, char* argv[]) {
|
||||
output_format = optarg;
|
||||
break;
|
||||
default:
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
std::string input;
|
||||
std::string output;
|
||||
int remaining_args = argc - optind;
|
||||
if (remaining_args > 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]" << std::endl;
|
||||
exit(1);
|
||||
} else if (remaining_args == 2) {
|
||||
input = argv[optind];
|
||||
output = argv[optind+1];
|
||||
} else if (remaining_args == 1) {
|
||||
input = argv[optind];
|
||||
std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
osmium::io::File infile(input, input_format);
|
||||
// Get input file name from command line.
|
||||
std::string input_file_name;
|
||||
if (remaining_args >= 1) {
|
||||
input_file_name = argv[optind];
|
||||
}
|
||||
|
||||
osmium::io::File outfile(output, output_format);
|
||||
// Get output file name from command line.
|
||||
std::string output_file_name;
|
||||
if (remaining_args == 2) {
|
||||
output_file_name = argv[optind+1];
|
||||
}
|
||||
|
||||
if (infile.has_multiple_object_versions() && !outfile.has_multiple_object_versions()) {
|
||||
// This declares the input and output files using either the suffix of
|
||||
// the file names or the format in the 2nd argument. It does not yet open
|
||||
// the files.
|
||||
osmium::io::File input_file{input_file_name, input_format};
|
||||
osmium::io::File output_file{output_file_name, output_format};
|
||||
|
||||
// Input and output files can be OSM data files (without history) or
|
||||
// OSM history files. History files are detected if they use the '.osh'
|
||||
// file suffix.
|
||||
if ( input_file.has_multiple_object_versions() &&
|
||||
!output_file.has_multiple_object_versions()) {
|
||||
std::cerr << "Warning! You are converting from an OSM file with (potentially) several versions of the same object to one that is not marked as such.\n";
|
||||
}
|
||||
|
||||
int exit_code = 0;
|
||||
|
||||
try {
|
||||
osmium::io::Reader reader(infile);
|
||||
// Initialize Reader
|
||||
osmium::io::Reader reader{input_file};
|
||||
|
||||
// Get header from input file and change the "generator" setting to
|
||||
// outselves.
|
||||
osmium::io::Header header = reader.header();
|
||||
header.set("generator", "osmium_convert");
|
||||
|
||||
osmium::io::Writer writer(outfile, header, osmium::io::overwrite::allow);
|
||||
// Initialize Writer using the header from above and tell it that it
|
||||
// is allowed to overwrite a possibly existing file.
|
||||
osmium::io::Writer writer(output_file, header, osmium::io::overwrite::allow);
|
||||
|
||||
// Copy the contents from the input to the output file one buffer at
|
||||
// a time. This is much easier and faster than copying each object
|
||||
// in the file. Buffers are moved around, so there is no cost for
|
||||
// copying in memory.
|
||||
while (osmium::memory::Buffer buffer = reader.read()) {
|
||||
writer(std::move(buffer));
|
||||
}
|
||||
|
||||
// Explicitly close the writer and reader. Will throw an exception if
|
||||
// there is a problem. If you wait for the destructor to close the writer
|
||||
// and reader, you will not notice the problem, because destructors must
|
||||
// not throw.
|
||||
writer.close();
|
||||
reader.close();
|
||||
} catch (std::exception& e) {
|
||||
} catch (const std::exception& e) {
|
||||
// All exceptions used by the Osmium library derive from std::exception.
|
||||
std::cerr << e.what() << "\n";
|
||||
exit_code = 1;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
|
69
third_party/libosmium/examples/osmium_count.cpp
vendored
69
third_party/libosmium/examples/osmium_count.cpp
vendored
@ -1,56 +1,95 @@
|
||||
/*
|
||||
|
||||
This is a small tool that counts the number of nodes, ways, and relations in
|
||||
the input file.
|
||||
EXAMPLE osmium_count
|
||||
|
||||
Counts the number of nodes, ways, and relations in the input file.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* OSM file input
|
||||
* your own handler
|
||||
* the memory usage utility class
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <cstdint> // for std::uint64_t
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// We want to use the handler interface
|
||||
#include <osmium/handler.hpp>
|
||||
|
||||
// Utility class gives us access to memory usage information
|
||||
#include <osmium/util/memory.hpp>
|
||||
|
||||
// For osmium::apply()
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
// Handler derive from the osmium::handler::Handler base class. Usually you
|
||||
// overwrite functions node(), way(), and relation(). Other functions are
|
||||
// available, too. Read the API documentation for details.
|
||||
struct CountHandler : public osmium::handler::Handler {
|
||||
|
||||
uint64_t nodes = 0;
|
||||
uint64_t ways = 0;
|
||||
uint64_t relations = 0;
|
||||
std::uint64_t nodes = 0;
|
||||
std::uint64_t ways = 0;
|
||||
std::uint64_t relations = 0;
|
||||
|
||||
void node(osmium::Node&) {
|
||||
// This callback is called by osmium::apply for each node in the data.
|
||||
void node(const osmium::Node&) noexcept {
|
||||
++nodes;
|
||||
}
|
||||
|
||||
void way(osmium::Way&) {
|
||||
// This callback is called by osmium::apply for each way in the data.
|
||||
void way(const osmium::Way&) noexcept {
|
||||
++ways;
|
||||
}
|
||||
|
||||
void relation(osmium::Relation&) {
|
||||
// This callback is called by osmium::apply for each relation in the data.
|
||||
void relation(const osmium::Relation&) noexcept {
|
||||
++relations;
|
||||
}
|
||||
|
||||
};
|
||||
}; // struct CountHandler
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
osmium::io::File infile(argv[1]);
|
||||
osmium::io::Reader reader(infile);
|
||||
// The Reader is initialized here with an osmium::io::File, but could
|
||||
// also be directly initialized with a file name.
|
||||
osmium::io::File input_file{argv[1]};
|
||||
osmium::io::Reader reader{input_file};
|
||||
|
||||
// Create an instance of our own CountHandler and push the data from the
|
||||
// input file through it.
|
||||
CountHandler handler;
|
||||
osmium::apply(reader, handler);
|
||||
|
||||
// You do not have to close the Reader explicitly, but because the
|
||||
// destructor can't throw, you will not see any errors otherwise.
|
||||
reader.close();
|
||||
|
||||
std::cout << "Nodes: " << handler.nodes << "\n";
|
||||
std::cout << "Ways: " << handler.ways << "\n";
|
||||
std::cout << "Relations: " << handler.relations << "\n";
|
||||
|
||||
// Because of the huge amount of OSM data, some Osmium-based programs
|
||||
// (though not this one) can use huge amounts of data. So checking actual
|
||||
// memore usage is often useful and can be done easily with this class.
|
||||
// (Currently only works on Linux, not OSX and Windows.)
|
||||
osmium::MemoryUsage memory;
|
||||
|
||||
std::cout << "\nMemory used: " << memory.peak() << " MBytes\n";
|
||||
}
|
||||
|
||||
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
|
||||
This reads an OSM file and writes out the node locations to a cache
|
||||
file.
|
||||
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
#include <osmium/index/map/dummy.hpp>
|
||||
#include <osmium/index/map/dense_mmap_array.hpp>
|
||||
#include <osmium/index/map/dense_file_array.hpp>
|
||||
|
||||
#include <osmium/handler/node_locations_for_ways.hpp>
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
|
||||
//typedef osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
|
||||
typedef osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
|
||||
|
||||
typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSM_FILE CACHE_FILE\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string input_filename(argv[1]);
|
||||
osmium::io::Reader reader(input_filename, osmium::osm_entity_bits::node);
|
||||
|
||||
int fd = open(argv[2], O_RDWR | O_CREAT, 0666);
|
||||
if (fd == -1) {
|
||||
std::cerr << "Can not open node cache file '" << argv[2] << "': " << strerror(errno) << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
index_pos_type index_pos {fd};
|
||||
index_neg_type index_neg;
|
||||
location_handler_type location_handler(index_pos, index_neg);
|
||||
location_handler.ignore_errors();
|
||||
|
||||
osmium::apply(reader, location_handler);
|
||||
reader.close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
46
third_party/libosmium/examples/osmium_debug.cpp
vendored
46
third_party/libosmium/examples/osmium_debug.cpp
vendored
@ -1,27 +1,46 @@
|
||||
/*
|
||||
|
||||
This is a small tool to dump the contents of the input file.
|
||||
EXAMPLE osmium_debug
|
||||
|
||||
Dump the contents of the input file in a debug format.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input reading only some types
|
||||
* the dump handler
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
#include <string> // for std::string
|
||||
|
||||
// The Dump handler
|
||||
#include <osmium/handler/dump.hpp>
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Speed up output (not Osmium-specific)
|
||||
std::ios_base::sync_with_stdio(false);
|
||||
|
||||
if (argc < 2 || argc > 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE [TYPES]\n";
|
||||
std::cerr << "TYPES can be any combination of 'n', 'w', 'r', and 'c' to indicate what types of OSM entities you want (default: all).\n";
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Default is all entity types: nodes, ways, relations, and changesets
|
||||
osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all;
|
||||
|
||||
// Get entity types from command line if there is a 2nd argument.
|
||||
if (argc == 3) {
|
||||
read_types = osmium::osm_entity_bits::nothing;
|
||||
std::string types = argv[2];
|
||||
@ -31,20 +50,27 @@ int main(int argc, char* argv[]) {
|
||||
if (types.find('c') != std::string::npos) read_types |= osmium::osm_entity_bits::changeset;
|
||||
}
|
||||
|
||||
osmium::io::Reader reader(argv[1], read_types);
|
||||
osmium::io::Header header = reader.header();
|
||||
// Initialize Reader with file name and the types of entities we want to
|
||||
// read.
|
||||
osmium::io::Reader reader{argv[1], read_types};
|
||||
|
||||
// The file header can contain metadata such as the program that generated
|
||||
// the file and the bounding box of the data.
|
||||
osmium::io::Header header = reader.header();
|
||||
std::cout << "HEADER:\n generator=" << header.get("generator") << "\n";
|
||||
|
||||
for (auto& bbox : header.boxes()) {
|
||||
for (const auto& bbox : header.boxes()) {
|
||||
std::cout << " bbox=" << bbox << "\n";
|
||||
}
|
||||
|
||||
osmium::handler::Dump dump(std::cout);
|
||||
while (osmium::memory::Buffer buffer = reader.read()) {
|
||||
osmium::apply(buffer, dump);
|
||||
}
|
||||
// Initialize Dump handler.
|
||||
osmium::handler::Dump dump{std::cout};
|
||||
|
||||
// Read from input and send everything to Dump handler.
|
||||
osmium::apply(reader, dump);
|
||||
|
||||
// You do not have to close the Reader explicitly, but because the
|
||||
// destructor can't throw, you will not see any errors otherwise.
|
||||
reader.close();
|
||||
}
|
||||
|
||||
|
@ -1,53 +1,73 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_filter_discussions
|
||||
|
||||
Read OSM changesets with discussions from a changeset dump like the one
|
||||
you get from http://planet.osm.org/planet/discussions-latest.osm.bz2
|
||||
and write out only those changesets which have discussions (ie comments).
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input and output
|
||||
* setting file formats using the osmium::io::File class
|
||||
* OSM file headers
|
||||
* input and output iterators
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <algorithm> // for std::copy_if
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
|
||||
// we want to read OSM files in XML format
|
||||
// (other formats don't support full changesets, so only XML is needed here)
|
||||
// We want to read OSM files in XML format
|
||||
// (other formats don't support full changesets, so only XML is needed here).
|
||||
#include <osmium/io/xml_input.hpp>
|
||||
#include <osmium/io/input_iterator.hpp>
|
||||
|
||||
// we want to write OSM files in XML format
|
||||
// We want to write OSM files in XML format.
|
||||
#include <osmium/io/xml_output.hpp>
|
||||
|
||||
// We want to use input and output iterators for easy integration with the
|
||||
// algorithms of the standard library.
|
||||
#include <osmium/io/input_iterator.hpp>
|
||||
#include <osmium/io/output_iterator.hpp>
|
||||
|
||||
// we want to support any compressioon (.gz2 and .bz2)
|
||||
// We want to support any compression (none, gzip, and bzip2).
|
||||
#include <osmium/io/any_compression.hpp>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
std::cout << "Usage: " << argv[0] << " INFILE OUTFILE\n";
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// The input file, deduce file format from file suffix
|
||||
osmium::io::File infile(argv[1]);
|
||||
// The input file, deduce file format from file suffix.
|
||||
osmium::io::File input_file{argv[1]};
|
||||
|
||||
// The output file, force class XML OSM file format
|
||||
osmium::io::File outfile(argv[2], "osm");
|
||||
// The output file, force XML OSM file format.
|
||||
osmium::io::File output_file{argv[2], "osm"};
|
||||
|
||||
// Initialize Reader for the input file.
|
||||
// Read only changesets (will ignore nodes, ways, and
|
||||
// relations if there are any).
|
||||
osmium::io::Reader reader(infile, osmium::osm_entity_bits::changeset);
|
||||
osmium::io::Reader reader{input_file, osmium::osm_entity_bits::changeset};
|
||||
|
||||
// Get the header from the input file
|
||||
// Get the header from the input file.
|
||||
osmium::io::Header header = reader.header();
|
||||
|
||||
// Set the "generator" on the header to ourselves.
|
||||
header.set("generator", "osmium_filter_discussions");
|
||||
|
||||
// Initialize writer for the output file. Use the header from the input
|
||||
// file for the output file. This will copy over some header information.
|
||||
// The last parameter will tell the writer that it is allowed to overwrite
|
||||
// an existing file. Without it, it will refuse to do so.
|
||||
osmium::io::Writer writer(outfile, 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".
|
||||
|
147
third_party/libosmium/examples/osmium_index.cpp
vendored
147
third_party/libosmium/examples/osmium_index.cpp
vendored
@ -12,7 +12,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <getopt.h>
|
||||
|
||||
#include <osmium/index/map/dense_file_array.hpp>
|
||||
#include <osmium/index/map/sparse_file_array.hpp>
|
||||
@ -31,7 +31,7 @@ class IndexSearch {
|
||||
void dump_dense() {
|
||||
dense_index_type index(m_fd);
|
||||
|
||||
for (size_t i = 0; i < index.size(); ++i) {
|
||||
for (std::size_t i = 0; i < index.size(); ++i) {
|
||||
if (index.get(i) != TValue()) {
|
||||
std::cout << i << " " << index.get(i) << "\n";
|
||||
}
|
||||
@ -51,9 +51,9 @@ class IndexSearch {
|
||||
|
||||
try {
|
||||
TValue value = index.get(key);
|
||||
std::cout << key << " " << value << std::endl;
|
||||
std::cout << key << " " << value << "\n";
|
||||
} catch (...) {
|
||||
std::cout << key << " not found" << std::endl;
|
||||
std::cout << key << " not found\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ class IndexSearch {
|
||||
return lhs.first < rhs.first;
|
||||
});
|
||||
if (positions.first == positions.second) {
|
||||
std::cout << key << " not found" << std::endl;
|
||||
std::cout << key << " not found\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -103,7 +103,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool search(std::vector<TKey> keys) {
|
||||
bool search(const std::vector<TKey>& keys) {
|
||||
bool found_all = true;
|
||||
|
||||
for (const auto key : keys) {
|
||||
@ -124,82 +124,105 @@ enum return_code : int {
|
||||
fatal = 3
|
||||
};
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
class Options {
|
||||
|
||||
po::variables_map vm;
|
||||
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[]) {
|
||||
try {
|
||||
po::options_description desc("Allowed options");
|
||||
desc.add_options()
|
||||
("help,h", "Print this help message")
|
||||
("array,a", po::value<std::string>(), "Read given index file in array format")
|
||||
("list,l", po::value<std::string>(), "Read given index file in list format")
|
||||
("dump,d", "Dump contents of index file to STDOUT")
|
||||
("search,s", po::value<std::vector<osmium::unsigned_object_id_type>>(), "Search for given id (Option can appear multiple times)")
|
||||
("type,t", po::value<std::string>(), "Type of value ('location' or 'offset')")
|
||||
;
|
||||
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}
|
||||
};
|
||||
|
||||
po::store(po::parse_command_line(argc, argv, desc), vm);
|
||||
po::notify(vm);
|
||||
|
||||
if (vm.count("help")) {
|
||||
std::cout << desc << "\n";
|
||||
exit(return_code::okay);
|
||||
while (true) {
|
||||
int c = getopt_long(argc, argv, "a:dhl:s:t:", long_options, 0);
|
||||
if (c == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (vm.count("array") && vm.count("list")) {
|
||||
std::cerr << "Only option --array or --list allowed." << std::endl;
|
||||
exit(return_code::fatal);
|
||||
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);
|
||||
}
|
||||
|
||||
if (!vm.count("array") && !vm.count("list")) {
|
||||
std::cerr << "Need one of option --array or --list." << std::endl;
|
||||
exit(return_code::fatal);
|
||||
}
|
||||
|
||||
if (!vm.count("type")) {
|
||||
std::cerr << "Need --type argument." << std::endl;
|
||||
exit(return_code::fatal);
|
||||
}
|
||||
|
||||
const std::string& type = vm["type"].as<std::string>();
|
||||
if (type != "location" && type != "offset") {
|
||||
std::cerr << "Unknown type '" << type << "'. Must be 'location' or 'offset'." << std::endl;
|
||||
exit(return_code::fatal);
|
||||
}
|
||||
} catch (boost::program_options::error& e) {
|
||||
std::cerr << "Error parsing command line: " << e.what() << std::endl;
|
||||
exit(return_code::fatal);
|
||||
break;
|
||||
default:
|
||||
std::exit(return_code::fatal);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& filename() const {
|
||||
if (vm.count("array")) {
|
||||
return vm["array"].as<std::string>();
|
||||
} else {
|
||||
return vm["list"].as<std::string>();
|
||||
}
|
||||
if (m_array_format == m_list_format) {
|
||||
std::cerr << "Need option --array or --list, but not both\n";
|
||||
std::exit(return_code::fatal);
|
||||
}
|
||||
|
||||
bool dense_format() const {
|
||||
return vm.count("array") != 0;
|
||||
if (m_type.empty()) {
|
||||
std::cerr << "Need --type argument.\n";
|
||||
std::exit(return_code::fatal);
|
||||
}
|
||||
|
||||
bool do_dump() const {
|
||||
return vm.count("dump") != 0;
|
||||
}
|
||||
|
||||
std::vector<osmium::unsigned_object_id_type> search_keys() const {
|
||||
return vm["search"].as<std::vector<osmium::unsigned_object_id_type>>();
|
||||
const std::string& filename() const noexcept {
|
||||
return m_filename;
|
||||
}
|
||||
|
||||
bool type_is(const char* type) const {
|
||||
return vm["type"].as<std::string>() == type;
|
||||
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
|
||||
@ -232,6 +255,6 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
exit(result_okay ? return_code::okay : return_code::not_found);
|
||||
std::exit(result_okay ? return_code::okay : return_code::not_found);
|
||||
}
|
||||
|
||||
|
87
third_party/libosmium/examples/osmium_location_cache_create.cpp
vendored
Normal file
87
third_party/libosmium/examples/osmium_location_cache_create.cpp
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_location_cache_create
|
||||
|
||||
Reads nodes from an OSM file and writes out their locations to a cache
|
||||
file. The cache file can then be read with osmium_location_cache_use.
|
||||
|
||||
Warning: The locations cache file will get huge (>32GB) if you are using
|
||||
the DenseFileArray index even if the input file is small, because
|
||||
it depends on the *largest* node ID, not the number of nodes.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input
|
||||
* location indexes and the NodeLocationsForWays handler
|
||||
* location indexes on disk
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
* osmium_road_length
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cerrno> // for errno
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <cstring> // for strerror
|
||||
#include <fcntl.h> // for open
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
#include <string> // for std::string
|
||||
#include <sys/stat.h> // for open
|
||||
#include <sys/types.h> // for open
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// For the location index. There are different types of index implementation
|
||||
// available. These implementations put the index on disk. See below.
|
||||
#include <osmium/index/map/sparse_file_array.hpp>
|
||||
#include <osmium/index/map/dense_file_array.hpp>
|
||||
|
||||
// For the NodeLocationForWays handler
|
||||
#include <osmium/handler/node_locations_for_ways.hpp>
|
||||
|
||||
// For osmium::apply()
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
// Chose one of these two. "sparse" is best used for small and medium extracts,
|
||||
// the "dense" index for large extracts or the whole planet.
|
||||
using index_type = osmium::index::map::SparseFileArray<osmium::unsigned_object_id_type, osmium::Location>;
|
||||
//using index_type = osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, osmium::Location>;
|
||||
|
||||
// The location handler always depends on the index type
|
||||
using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSM_FILE CACHE_FILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
const std::string input_filename{argv[1]};
|
||||
const std::string cache_filename{argv[2]};
|
||||
|
||||
// Construct Reader reading only nodes
|
||||
osmium::io::Reader reader{input_filename, osmium::osm_entity_bits::node};
|
||||
|
||||
// Initialize location index on disk creating a new file.
|
||||
const int fd = open(cache_filename.c_str(), O_RDWR | O_CREAT, 0666);
|
||||
if (fd == -1) {
|
||||
std::cerr << "Can not open location cache file '" << cache_filename << "': " << std::strerror(errno) << "\n";
|
||||
std::exit(1);
|
||||
}
|
||||
index_type index{fd};
|
||||
|
||||
// The handler that stores all node locations in the index.
|
||||
location_handler_type location_handler{index};
|
||||
|
||||
// Feed all nodes through the location handler.
|
||||
osmium::apply(reader, location_handler);
|
||||
|
||||
// Explicitly close input so we get notified of any errors.
|
||||
reader.close();
|
||||
}
|
||||
|
101
third_party/libosmium/examples/osmium_location_cache_use.cpp
vendored
Normal file
101
third_party/libosmium/examples/osmium_location_cache_use.cpp
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_location_cache_use
|
||||
|
||||
This reads ways from an OSM file and writes out the way node locations
|
||||
it got from a location cache generated with osmium_location_cache_create.
|
||||
|
||||
Warning: The locations cache file will get huge (>32GB) if you are using
|
||||
the DenseFileArray index even if the input file is small, because
|
||||
it depends on the *largest* node ID, not the number of nodes.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input
|
||||
* location indexes and the NodeLocationsForWays handler
|
||||
* location indexes on disk
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
* osmium_road_length
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cerrno> // for errno
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <cstring> // for strerror
|
||||
#include <fcntl.h> // for open
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
#include <string> // for std::string
|
||||
#include <sys/stat.h> // for open
|
||||
#include <sys/types.h> // for open
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// For the location index. There are different types of index implementation
|
||||
// available. These implementations put the index on disk. See below.
|
||||
#include <osmium/index/map/dense_file_array.hpp>
|
||||
#include <osmium/index/map/sparse_file_array.hpp>
|
||||
|
||||
// For the NodeLocationForWays handler
|
||||
#include <osmium/handler/node_locations_for_ways.hpp>
|
||||
|
||||
// For osmium::apply()
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
// Chose one of these two. "sparse" is best used for small and medium extracts,
|
||||
// the "dense" index for large extracts or the whole planet.
|
||||
using index_type = osmium::index::map::SparseFileArray<osmium::unsigned_object_id_type, osmium::Location>;
|
||||
//using index_type = osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, osmium::Location>;
|
||||
|
||||
// The location handler always depends on the index type
|
||||
using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
|
||||
|
||||
// This handler only implements the way() function which prints out the way
|
||||
// ID and all nodes IDs and locations in those ways.
|
||||
struct MyHandler : public osmium::handler::Handler {
|
||||
|
||||
void way(const osmium::Way& way) {
|
||||
std::cout << "way " << way.id() << "\n";
|
||||
for (const auto& nr : way.nodes()) {
|
||||
std::cout << " node " << nr.ref() << " " << nr.location() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
}; // struct MyHandler
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSM_FILE CACHE_FILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
const std::string input_filename{argv[1]};
|
||||
const std::string cache_filename{argv[2]};
|
||||
|
||||
// Construct Reader reading only ways
|
||||
osmium::io::Reader reader{input_filename, osmium::osm_entity_bits::way};
|
||||
|
||||
// Initialize location index on disk using an existing file
|
||||
const int fd = open(cache_filename.c_str(), O_RDWR);
|
||||
if (fd == -1) {
|
||||
std::cerr << "Can not open location cache file '" << cache_filename << "': " << std::strerror(errno) << "\n";
|
||||
return 1;
|
||||
}
|
||||
index_type index{fd};
|
||||
|
||||
// The handler that adds node locations from the index to the ways.
|
||||
location_handler_type location_handler{index};
|
||||
|
||||
// Feed all ways through the location handler and then our own handler.
|
||||
MyHandler handler;
|
||||
osmium::apply(reader, location_handler, handler);
|
||||
|
||||
// Explicitly close input so we get notified of any errors.
|
||||
reader.close();
|
||||
}
|
||||
|
89
third_party/libosmium/examples/osmium_pub_names.cpp
vendored
Executable file
89
third_party/libosmium/examples/osmium_pub_names.cpp
vendored
Executable file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_pub_names
|
||||
|
||||
Show the names and addresses of all pubs found in an OSM file.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input
|
||||
* your own handler
|
||||
* access to tags
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <cstring> // for std::strncmp
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// We want to use the handler interface
|
||||
#include <osmium/handler.hpp>
|
||||
|
||||
// For osmium::apply()
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
class NamesHandler : public osmium::handler::Handler {
|
||||
|
||||
void output_pubs(const osmium::OSMObject& object) {
|
||||
const osmium::TagList& tags = object.tags();
|
||||
if (tags.has_tag("amenity", "pub")) {
|
||||
|
||||
// Print name of the pub if it is set.
|
||||
const char* name = tags["name"];
|
||||
if (name) {
|
||||
std::cout << name << "\n";
|
||||
} else {
|
||||
std::cout << "pub with unknown name\n";
|
||||
}
|
||||
|
||||
// Iterate over all tags finding those which start with "addr:"
|
||||
// and print them.
|
||||
for (const osmium::Tag& tag : tags) {
|
||||
if (!std::strncmp(tag.key(), "addr:", 5)) {
|
||||
std::cout << " " << tag.key() << ": " << tag.value() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// Nodes can be tagged amenity=pub.
|
||||
void node(const osmium::Node& node) {
|
||||
output_pubs(node);
|
||||
}
|
||||
|
||||
// Ways can be tagged amenity=pub, too (typically buildings).
|
||||
void way(const osmium::Way& way) {
|
||||
output_pubs(way);
|
||||
}
|
||||
|
||||
}; // class NamesHandler
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Construct the handler defined above
|
||||
NamesHandler names_handler;
|
||||
|
||||
// Initialize the reader with the filename from the command line and
|
||||
// tell it to only read nodes and ways. We are ignoring multipolygon
|
||||
// relations in this simple example.
|
||||
osmium::io::Reader reader{argv[1], osmium::osm_entity_bits::node | osmium::osm_entity_bits::way};
|
||||
|
||||
// Apply input data to our own handler
|
||||
osmium::apply(reader, names_handler);
|
||||
}
|
||||
|
26
third_party/libosmium/examples/osmium_read.cpp
vendored
26
third_party/libosmium/examples/osmium_read.cpp
vendored
@ -1,30 +1,42 @@
|
||||
/*
|
||||
|
||||
This is a small tool that reads and discards the contents of the input file.
|
||||
(Used for timing.)
|
||||
EXAMPLE osmium_read
|
||||
|
||||
Reads and discards the contents of the input file.
|
||||
(It can be used for timing.)
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <iostream> // for std::cerr
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
osmium::io::File infile(argv[1]);
|
||||
osmium::io::Reader reader(infile);
|
||||
// The Reader is initialized here with an osmium::io::File, but could
|
||||
// also be directly initialized with a file name.
|
||||
osmium::io::File input_file{argv[1]};
|
||||
osmium::io::Reader reader{input_file};
|
||||
|
||||
// OSM data comes in buffers, read until there are no more.
|
||||
while (osmium::memory::Buffer buffer = reader.read()) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// You do not have to close the Reader explicitly, but because the
|
||||
// destructor can't throw, you will not see any errors otherwise.
|
||||
reader.close();
|
||||
}
|
||||
|
||||
|
56
third_party/libosmium/examples/osmium_read_with_progress.cpp
vendored
Normal file
56
third_party/libosmium/examples/osmium_read_with_progress.cpp
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_read_with_progress
|
||||
|
||||
Reads the contents of the input file showing a progress bar.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input
|
||||
* ProgressBar utility function
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <iostream> // for std::cerr
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// Get access to isatty utility function and progress bar utility class.
|
||||
#include <osmium/util/file.hpp>
|
||||
#include <osmium/util/progress_bar.hpp>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// The Reader is initialized here with an osmium::io::File, but could
|
||||
// also be directly initialized with a file name.
|
||||
osmium::io::File input_file{argv[1]};
|
||||
osmium::io::Reader reader{input_file};
|
||||
|
||||
// Initialize progress bar, enable it only if STDERR is a TTY.
|
||||
osmium::ProgressBar progress{reader.file_size(), osmium::util::isatty(2)};
|
||||
|
||||
// OSM data comes in buffers, read until there are no more.
|
||||
while (osmium::memory::Buffer buffer = reader.read()) {
|
||||
// Update progress bar for each buffer.
|
||||
progress.update(reader.offset());
|
||||
}
|
||||
|
||||
// Progress bar is done.
|
||||
progress.done();
|
||||
|
||||
// You do not have to close the Reader explicitly, but because the
|
||||
// destructor can't throw, you will not see any errors otherwise.
|
||||
reader.close();
|
||||
}
|
||||
|
92
third_party/libosmium/examples/osmium_road_length.cpp
vendored
Executable file
92
third_party/libosmium/examples/osmium_road_length.cpp
vendored
Executable file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_road_length
|
||||
|
||||
Calculate the length of the road network (everything tagged `highway=*`)
|
||||
from the given OSM file.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* file input
|
||||
* location indexes and the NodeLocationsForWays handler
|
||||
* length calculation on the earth using the haversine function
|
||||
|
||||
SIMPLER EXAMPLES you might want to understand first:
|
||||
* osmium_read
|
||||
* osmium_count
|
||||
* osmium_pub_names
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
|
||||
// Allow any format of input files (XML, PBF, ...)
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
// For the osmium::geom::haversine::distance() function
|
||||
#include <osmium/geom/haversine.hpp>
|
||||
|
||||
// For osmium::apply()
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
// For the location index. There are different types of indexes available.
|
||||
// This will work for small and medium sized input files.
|
||||
#include <osmium/index/map/sparse_mem_array.hpp>
|
||||
|
||||
// For the NodeLocationForWays handler
|
||||
#include <osmium/handler/node_locations_for_ways.hpp>
|
||||
|
||||
// The type of index used. This must match the include file above
|
||||
using index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
|
||||
|
||||
// The location handler always depends on the index type
|
||||
using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
|
||||
|
||||
// This handler only implements the way() function, we are not interested in
|
||||
// any other objects.
|
||||
struct RoadLengthHandler : public osmium::handler::Handler {
|
||||
|
||||
double length = 0;
|
||||
|
||||
// If the way has a "highway" tag, find its length and add it to the
|
||||
// overall length.
|
||||
void way(const osmium::Way& way) {
|
||||
const char* highway = way.tags()["highway"];
|
||||
if (highway) {
|
||||
length += osmium::geom::haversine::distance(way.nodes());
|
||||
}
|
||||
}
|
||||
|
||||
}; // struct RoadLengthHandler
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Initialize the reader with the filename from the command line and
|
||||
// tell it to only read nodes and ways.
|
||||
osmium::io::Reader reader{argv[1], osmium::osm_entity_bits::node | osmium::osm_entity_bits::way};
|
||||
|
||||
// The index to hold node locations.
|
||||
index_type index;
|
||||
|
||||
// The location handler will add the node locations to the index and then
|
||||
// to the ways
|
||||
location_handler_type location_handler{index};
|
||||
|
||||
// Our handler defined above
|
||||
RoadLengthHandler road_length_handler;
|
||||
|
||||
// Apply input data to first the location handler and then our own handler
|
||||
osmium::apply(reader, location_handler, road_length_handler);
|
||||
|
||||
// Output the length. The haversine function calculates it in meters,
|
||||
// so we first devide by 1000 to get kilometers.
|
||||
std::cout << "Length: " << road_length_handler.length / 1000 << " km\n";
|
||||
}
|
||||
|
@ -69,9 +69,9 @@ int main(int argc, char* argv[]) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
print_help();
|
||||
exit(0);
|
||||
std::exit(0);
|
||||
default:
|
||||
exit(2);
|
||||
std::exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
if (remaining_args != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSMFILE DIR\n";
|
||||
exit(2);
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
std::string dir(argv[optind+1]);
|
||||
@ -90,14 +90,14 @@ int main(int argc, char* argv[]) {
|
||||
#endif
|
||||
if (result == -1 && errno != EEXIST) {
|
||||
std::cerr << "Problem creating directory '" << dir << "': " << strerror(errno) << "\n";
|
||||
exit(2);
|
||||
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";
|
||||
exit(2);
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
offset_index_type node_index;
|
||||
@ -127,7 +127,7 @@ int main(int argc, char* argv[]) {
|
||||
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";
|
||||
exit(2);
|
||||
std::exit(2);
|
||||
}
|
||||
node_index.dump_as_list(fd);
|
||||
close(fd);
|
||||
@ -138,7 +138,7 @@ int main(int argc, char* argv[]) {
|
||||
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";
|
||||
exit(2);
|
||||
std::exit(2);
|
||||
}
|
||||
way_index.dump_as_list(fd);
|
||||
close(fd);
|
||||
@ -149,7 +149,7 @@ int main(int argc, char* argv[]) {
|
||||
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";
|
||||
exit(2);
|
||||
std::exit(2);
|
||||
}
|
||||
relation_index.dump_as_list(fd);
|
||||
close(fd);
|
||||
@ -161,7 +161,7 @@ int main(int argc, char* argv[]) {
|
||||
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";
|
||||
exit(2);
|
||||
std::exit(2);
|
||||
}
|
||||
map_node2way.dump_as_list(fd);
|
||||
close(fd);
|
||||
@ -173,7 +173,7 @@ int main(int argc, char* argv[]) {
|
||||
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";
|
||||
exit(2);
|
||||
std::exit(2);
|
||||
}
|
||||
map_node2relation.dump_as_list(fd);
|
||||
close(fd);
|
||||
@ -185,7 +185,7 @@ int main(int argc, char* argv[]) {
|
||||
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";
|
||||
exit(2);
|
||||
std::exit(2);
|
||||
}
|
||||
map_way2relation.dump_as_list(fd);
|
||||
close(fd);
|
||||
@ -197,7 +197,7 @@ int main(int argc, char* argv[]) {
|
||||
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";
|
||||
exit(2);
|
||||
std::exit(2);
|
||||
}
|
||||
map_relation2relation.dump_as_list(fd);
|
||||
close(fd);
|
||||
|
72
third_party/libosmium/examples/osmium_tiles.cpp
vendored
Normal file
72
third_party/libosmium/examples/osmium_tiles.cpp
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
|
||||
EXAMPLE osmium_tiles
|
||||
|
||||
Convert WGS84 longitude and latitude to Mercator coordinates and tile
|
||||
coordinates.
|
||||
|
||||
DEMONSTRATES USE OF:
|
||||
* the Location and Coordinates classes
|
||||
* the Mercator projection function
|
||||
* the Tile class
|
||||
|
||||
LICENSE
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdlib> // for std::exit, std::atoi, std::atof
|
||||
#include <iostream> // for std::cout, std::cerr
|
||||
|
||||
// The Location contains a longitude and latitude and is usually used inside
|
||||
// a node to store its location in the world.
|
||||
#include <osmium/osm/location.hpp>
|
||||
|
||||
// Needed for the Mercator projection function. Osmium supports the Mercator
|
||||
// projection out of the box, or pretty much any projection using the Proj.4
|
||||
// library (with the osmium::geom::Projection class).
|
||||
#include <osmium/geom/mercator_projection.hpp>
|
||||
|
||||
// The Tile class handles tile coordinates and zoom levels.
|
||||
#include <osmium/geom/tile.hpp>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 4) {
|
||||
std::cerr << "Usage: " << argv[0] << " ZOOM LON LAT\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
const int zoom = std::atoi(argv[1]);
|
||||
|
||||
if (zoom < 0 || zoom > 30) {
|
||||
std::cerr << "ERROR: Zoom must be between 0 and 30\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
const double lon = std::atof(argv[2]);
|
||||
const double lat = std::atof(argv[3]);
|
||||
|
||||
// Create location from WGS84 coordinates. In Osmium the order of
|
||||
// coordinate values is always x/longitude first, then y/latitude.
|
||||
const osmium::Location location{lon, lat};
|
||||
|
||||
std::cout << "WGS84: lon=" << lon << " lat=" << lat << "\n";
|
||||
|
||||
// A location can store some invalid locations, ie locations outside the
|
||||
// -180 to 180 and -90 to 90 degree range. This function checks for that.
|
||||
if (!location.valid()) {
|
||||
std::cerr << "ERROR: Location is invalid\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Project the coordinates using a helper function. You can also use the
|
||||
// osmium::geom::MercatorProjection class.
|
||||
const osmium::geom::Coordinates c = osmium::geom::lonlat_to_mercator(location);
|
||||
std::cout << "Mercator: x=" << c.x << " y=" << c.y << "\n";
|
||||
|
||||
// Create a tile at this location. This will also internally use the
|
||||
// Mercator projection and then calculate the tile coordinates.
|
||||
const osmium::geom::Tile tile{uint32_t(zoom), location};
|
||||
std::cout << "Tile: zoom=" << tile.z << " x=" << tile.x << " y=" << tile.y << "\n";
|
||||
}
|
||||
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
|
||||
This reads ways from an OSM file and writes out the node locations
|
||||
it got from a node cache generated with osmium_create_node_cache.
|
||||
|
||||
The code in this example file is released into the Public Domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <osmium/io/any_input.hpp>
|
||||
|
||||
#include <osmium/index/map/dummy.hpp>
|
||||
#include <osmium/index/map/dense_file_array.hpp>
|
||||
#include <osmium/index/map/dense_mmap_array.hpp>
|
||||
|
||||
#include <osmium/handler/node_locations_for_ways.hpp>
|
||||
#include <osmium/visitor.hpp>
|
||||
|
||||
typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
|
||||
//typedef osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
|
||||
typedef osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
|
||||
|
||||
typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
|
||||
|
||||
class MyHandler : public osmium::handler::Handler {
|
||||
|
||||
public:
|
||||
|
||||
void way(osmium::Way& way) {
|
||||
for (auto& nr : way.nodes()) {
|
||||
std::cout << nr << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
}; // class MyHandler
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " OSM_FILE CACHE_FILE\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string input_filename(argv[1]);
|
||||
osmium::io::Reader reader(input_filename, osmium::osm_entity_bits::way);
|
||||
|
||||
int fd = open(argv[2], O_RDWR);
|
||||
if (fd == -1) {
|
||||
std::cerr << "Can not open node cache file '" << argv[2] << "': " << strerror(errno) << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
index_pos_type index_pos {fd};
|
||||
index_neg_type index_neg;
|
||||
location_handler_type location_handler(index_pos, index_neg);
|
||||
location_handler.ignore_errors();
|
||||
|
||||
MyHandler handler;
|
||||
osmium::apply(reader, location_handler, handler);
|
||||
reader.close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
91
third_party/libosmium/include/gdalcpp.hpp
vendored
91
third_party/libosmium/include/gdalcpp.hpp
vendored
@ -110,8 +110,12 @@ namespace gdalcpp {
|
||||
namespace detail {
|
||||
|
||||
struct init_wrapper {
|
||||
#if GDAL_VERSION_MAJOR >= 2
|
||||
init_wrapper() { GDALAllRegister(); }
|
||||
#else
|
||||
init_wrapper() { OGRRegisterAll(); }
|
||||
~init_wrapper() { OGRCleanupAll(); }
|
||||
#endif
|
||||
};
|
||||
|
||||
struct init_library {
|
||||
@ -237,6 +241,8 @@ namespace gdalcpp {
|
||||
detail::Options m_options;
|
||||
SRS m_srs;
|
||||
std::unique_ptr<gdal_dataset_type, gdal_dataset_deleter> m_dataset;
|
||||
uint64_t m_edit_count = 0;
|
||||
uint64_t m_max_edit_count = 0;
|
||||
|
||||
public:
|
||||
|
||||
@ -255,6 +261,15 @@ namespace gdalcpp {
|
||||
}
|
||||
}
|
||||
|
||||
~Dataset() {
|
||||
try {
|
||||
if (m_edit_count > 0) {
|
||||
commit_transaction();
|
||||
}
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& driver_name() const {
|
||||
return m_driver_name;
|
||||
}
|
||||
@ -282,10 +297,14 @@ namespace gdalcpp {
|
||||
exec(sql.c_str());
|
||||
}
|
||||
|
||||
|
||||
Dataset& start_transaction() {
|
||||
#if GDAL_VERSION_MAJOR >= 2
|
||||
m_dataset->StartTransaction();
|
||||
#else
|
||||
OGRLayer* layer = m_dataset->GetLayer(0);
|
||||
if (layer) {
|
||||
layer->StartTransaction();
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
@ -293,7 +312,38 @@ namespace gdalcpp {
|
||||
Dataset& commit_transaction() {
|
||||
#if GDAL_VERSION_MAJOR >= 2
|
||||
m_dataset->CommitTransaction();
|
||||
#else
|
||||
OGRLayer* layer = m_dataset->GetLayer(0);
|
||||
if (layer) {
|
||||
layer->CommitTransaction();
|
||||
}
|
||||
#endif
|
||||
m_edit_count = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void prepare_edit() {
|
||||
if (m_max_edit_count != 0 && m_edit_count == 0) {
|
||||
start_transaction();
|
||||
}
|
||||
}
|
||||
|
||||
void finalize_edit() {
|
||||
if (m_max_edit_count != 0 && ++m_edit_count > m_max_edit_count) {
|
||||
commit_transaction();
|
||||
}
|
||||
}
|
||||
|
||||
Dataset& enable_auto_transactions(uint64_t edits = 100000) {
|
||||
m_max_edit_count = edits;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Dataset& disable_auto_transactions() {
|
||||
if (m_max_edit_count != 0 && m_edit_count > 0) {
|
||||
commit_transaction();
|
||||
}
|
||||
m_max_edit_count = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -346,19 +396,32 @@ namespace gdalcpp {
|
||||
return *this;
|
||||
}
|
||||
|
||||
void create_feature(OGRFeature* feature) {
|
||||
dataset().prepare_edit();
|
||||
OGRErr result = m_layer->CreateFeature(feature);
|
||||
if (result != OGRERR_NONE) {
|
||||
throw gdal_error(std::string("creating feature in layer '") + name() + "' failed", result, dataset().driver_name(), dataset().dataset_name());
|
||||
}
|
||||
dataset().finalize_edit();
|
||||
}
|
||||
|
||||
Layer& start_transaction() {
|
||||
#if GDAL_VERSION_MAJOR < 2
|
||||
OGRErr result = m_layer->StartTransaction();
|
||||
if (result != OGRERR_NONE) {
|
||||
throw gdal_error(std::string("starting transaction on layer '") + name() + "' failed", result, m_dataset.driver_name(), m_dataset.dataset_name(), name());
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
Layer& commit_transaction() {
|
||||
#if GDAL_VERSION_MAJOR < 2
|
||||
OGRErr result = m_layer->CommitTransaction();
|
||||
if (result != OGRERR_NONE) {
|
||||
throw gdal_error(std::string("committing transaction on layer '") + name() + "' failed", result, m_dataset.driver_name(), m_dataset.dataset_name(), name());
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -366,36 +429,44 @@ namespace gdalcpp {
|
||||
|
||||
class Feature {
|
||||
|
||||
struct ogr_feature_deleter {
|
||||
|
||||
void operator()(OGRFeature* feature) {
|
||||
OGRFeature::DestroyFeature(feature);
|
||||
}
|
||||
|
||||
}; // struct ogr_feature_deleter
|
||||
|
||||
Layer& m_layer;
|
||||
OGRFeature m_feature;
|
||||
std::unique_ptr<OGRFeature, ogr_feature_deleter> m_feature;
|
||||
|
||||
public:
|
||||
|
||||
Feature(Layer& layer, std::unique_ptr<OGRGeometry>&& geometry) :
|
||||
m_layer(layer),
|
||||
m_feature(m_layer.get().GetLayerDefn()) {
|
||||
OGRErr result = m_feature.SetGeometryDirectly(geometry.release());
|
||||
m_feature(OGRFeature::CreateFeature(m_layer.get().GetLayerDefn())) {
|
||||
if (!m_feature) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
OGRErr result = m_feature->SetGeometryDirectly(geometry.release());
|
||||
if (result != OGRERR_NONE) {
|
||||
throw gdal_error(std::string("setting feature geometry in layer '") + m_layer.name() + "' failed", result, m_layer.dataset().driver_name(), m_layer.dataset().dataset_name());
|
||||
}
|
||||
}
|
||||
|
||||
void add_to_layer() {
|
||||
OGRErr result = m_layer.get().CreateFeature(&m_feature);
|
||||
if (result != OGRERR_NONE) {
|
||||
throw gdal_error(std::string("creating feature in layer '") + m_layer.name() + "' failed", result, m_layer.dataset().driver_name(), m_layer.dataset().dataset_name());
|
||||
}
|
||||
m_layer.create_feature(m_feature.get());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Feature& set_field(int n, T&& arg) {
|
||||
m_feature.SetField(n, std::forward<T>(arg));
|
||||
m_feature->SetField(n, std::forward<T>(arg));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Feature& set_field(const char* name, T&& arg) {
|
||||
m_feature.SetField(name, std::forward<T>(arg));
|
||||
m_feature->SetField(name, std::forward<T>(arg));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
1760
third_party/libosmium/include/osmium/area/assembler.hpp
vendored
1760
third_party/libosmium/include/osmium/area/assembler.hpp
vendored
File diff suppressed because it is too large
Load Diff
@ -34,11 +34,12 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iosfwd>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/area/detail/vector.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
|
||||
@ -53,108 +54,178 @@ namespace osmium {
|
||||
*/
|
||||
namespace detail {
|
||||
|
||||
class ProtoRing;
|
||||
|
||||
enum class role_type : uint8_t {
|
||||
unknown = 0,
|
||||
outer = 1,
|
||||
inner = 2,
|
||||
empty = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* This helper class for the Assembler class models a segment.
|
||||
* Segments are the connection between
|
||||
* two nodes and they all have their smaller coordinate at the
|
||||
* beginning of the segment. Smaller, in this case, means smaller x
|
||||
* coordinate, and if they are the same smaller y coordinate.
|
||||
* This helper class for the Assembler class models a segment,
|
||||
* the connection between two nodes.
|
||||
*
|
||||
* Internally segments have their smaller coordinate at the
|
||||
* beginning of the segment. Smaller, in this case, means smaller
|
||||
* x coordinate, and, if they are the same, smaller y coordinate.
|
||||
*/
|
||||
class NodeRefSegment {
|
||||
|
||||
// First node in order described above.
|
||||
osmium::NodeRef m_first;
|
||||
|
||||
// Second node in order described above.
|
||||
osmium::NodeRef m_second;
|
||||
|
||||
/// Role of the member this segment was from.
|
||||
const char* m_role;
|
||||
|
||||
/// Way this segment was from.
|
||||
// Way this segment was from.
|
||||
const osmium::Way* m_way;
|
||||
|
||||
// The ring this segment is part of. Initially nullptr, this
|
||||
// will be filled in once we know which ring the segment is in.
|
||||
ProtoRing* m_ring;
|
||||
|
||||
// The role of this segment from the member role.
|
||||
role_type m_role;
|
||||
|
||||
// Nodes have to be reversed to get the intended order.
|
||||
bool m_reverse = false;
|
||||
|
||||
// We found the right direction for this segment in the ring.
|
||||
// (This depends on whether it is an inner or outer ring.)
|
||||
bool m_direction_done = false;
|
||||
|
||||
public:
|
||||
|
||||
void swap_locations() {
|
||||
NodeRefSegment() noexcept :
|
||||
m_first(),
|
||||
m_second(),
|
||||
m_way(nullptr),
|
||||
m_ring(nullptr),
|
||||
m_role(role_type::unknown) {
|
||||
}
|
||||
|
||||
NodeRefSegment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2, role_type role = role_type::unknown, const osmium::Way* way = nullptr) noexcept :
|
||||
m_first(nr1),
|
||||
m_second(nr2),
|
||||
m_way(way),
|
||||
m_ring(nullptr),
|
||||
m_role(role) {
|
||||
if (nr2.location() < nr1.location()) {
|
||||
using std::swap;
|
||||
swap(m_first, m_second);
|
||||
}
|
||||
|
||||
explicit NodeRefSegment() noexcept :
|
||||
m_first(),
|
||||
m_second(),
|
||||
m_role(nullptr),
|
||||
m_way(nullptr) {
|
||||
}
|
||||
|
||||
explicit NodeRefSegment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2, const char* role, const osmium::Way* way) :
|
||||
m_first(nr1),
|
||||
m_second(nr2),
|
||||
m_role(role),
|
||||
m_way(way) {
|
||||
if (nr2.location() < nr1.location()) {
|
||||
swap_locations();
|
||||
}
|
||||
/**
|
||||
* The ring this segment is a part of. nullptr if we don't
|
||||
* have the ring yet.
|
||||
*/
|
||||
ProtoRing* ring() const noexcept {
|
||||
return m_ring;
|
||||
}
|
||||
|
||||
NodeRefSegment(const NodeRefSegment&) = default;
|
||||
NodeRefSegment(NodeRefSegment&&) = default;
|
||||
/**
|
||||
* Returns true if the segment has already been placed in a
|
||||
* ring.
|
||||
*/
|
||||
bool is_done() const noexcept {
|
||||
return m_ring != nullptr;
|
||||
}
|
||||
|
||||
NodeRefSegment& operator=(const NodeRefSegment&) = default;
|
||||
NodeRefSegment& operator=(NodeRefSegment&&) = default;
|
||||
void set_ring(ProtoRing* ring) noexcept {
|
||||
assert(ring);
|
||||
m_ring = ring;
|
||||
}
|
||||
|
||||
~NodeRefSegment() = default;
|
||||
bool is_reverse() const noexcept {
|
||||
return m_reverse;
|
||||
}
|
||||
|
||||
/// Return first NodeRef of Segment according to sorting order (bottom left to top right).
|
||||
void reverse() noexcept {
|
||||
m_reverse = !m_reverse;
|
||||
}
|
||||
|
||||
bool is_direction_done() const noexcept {
|
||||
return m_direction_done;
|
||||
}
|
||||
|
||||
void mark_direction_done() noexcept {
|
||||
m_direction_done = true;
|
||||
}
|
||||
|
||||
void mark_direction_not_done() noexcept {
|
||||
m_direction_done = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return first NodeRef of Segment according to sorting
|
||||
* order (bottom left to top right).
|
||||
*/
|
||||
const osmium::NodeRef& first() const noexcept {
|
||||
return m_first;
|
||||
}
|
||||
|
||||
/// Return second NodeRef of Segment according to sorting order (bottom left to top right).
|
||||
/**
|
||||
* Return second NodeRef of Segment according to sorting
|
||||
* order (bottom left to top right).
|
||||
*/
|
||||
const osmium::NodeRef& second() const noexcept {
|
||||
return m_second;
|
||||
}
|
||||
|
||||
bool to_left_of(const osmium::Location& location) const {
|
||||
// std::cerr << "segment " << first() << "--" << second() << " to_left_of(" << location << "\n";
|
||||
|
||||
if (first().location() == location || second().location() == location) {
|
||||
return false;
|
||||
/**
|
||||
* Return real first NodeRef of Segment.
|
||||
*/
|
||||
const osmium::NodeRef& start() const noexcept {
|
||||
return m_reverse ? m_second : m_first;
|
||||
}
|
||||
|
||||
const std::pair<osmium::Location, osmium::Location> mm = std::minmax(first().location(), second().location(), [](const osmium::Location a, const osmium::Location b) {
|
||||
return a.y() < b.y();
|
||||
});
|
||||
|
||||
if (mm.first.y() >= location.y() || mm.second.y() < location.y() || first().location().x() > location.x()) {
|
||||
// std::cerr << " false\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t ax = mm.first.x();
|
||||
int64_t bx = mm.second.x();
|
||||
int64_t lx = location.x();
|
||||
int64_t ay = mm.first.y();
|
||||
int64_t by = mm.second.y();
|
||||
int64_t ly = location.y();
|
||||
return ((bx - ax)*(ly - ay) - (by - ay)*(lx - ax)) <= 0;
|
||||
/**
|
||||
* Return real second NodeRef of Segment.
|
||||
*/
|
||||
const osmium::NodeRef& stop() const noexcept {
|
||||
return m_reverse ? m_first : m_second;
|
||||
}
|
||||
|
||||
bool role_outer() const noexcept {
|
||||
return !strcmp(m_role, "outer");
|
||||
return m_role == role_type::outer;
|
||||
}
|
||||
|
||||
bool role_inner() const noexcept {
|
||||
return !strcmp(m_role, "inner");
|
||||
return m_role == role_type::inner;
|
||||
}
|
||||
|
||||
bool role_empty() const noexcept {
|
||||
return m_role == role_type::empty;
|
||||
}
|
||||
|
||||
const char* role_name() const noexcept {
|
||||
static const char* names[] = { "unknown", "outer", "inner", "empty" };
|
||||
return names[int(m_role)];
|
||||
}
|
||||
|
||||
const osmium::Way* way() const noexcept {
|
||||
return m_way;
|
||||
}
|
||||
|
||||
/**
|
||||
* The "determinant" of this segment. Used for calculating
|
||||
* the winding order or a ring.
|
||||
*/
|
||||
int64_t det() const noexcept {
|
||||
const vec a{start()};
|
||||
const vec b{stop()};
|
||||
return a * b;
|
||||
}
|
||||
|
||||
}; // class NodeRefSegment
|
||||
|
||||
/// NodeRefSegments are equal if both their locations are equal
|
||||
inline bool operator==(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
|
||||
return lhs.first().location() == rhs.first().location() && lhs.second().location() == rhs.second().location();
|
||||
return lhs.first().location() == rhs.first().location() &&
|
||||
lhs.second().location() == rhs.second().location();
|
||||
}
|
||||
|
||||
inline bool operator!=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
|
||||
@ -162,12 +233,33 @@ namespace osmium {
|
||||
}
|
||||
|
||||
/**
|
||||
* NodeRefSegments are "smaller" if they are to the left and down of another
|
||||
* segment. The first() location is checked first() and only if they have the
|
||||
* same first() location the second() location is taken into account.
|
||||
* A NodeRefSegment is "smaller" if the first point is to the
|
||||
* left and down of the first point of the second segment.
|
||||
* If both first points are the same, the segment with the higher
|
||||
* slope comes first. If the slope is the same, the shorter
|
||||
* segment comes first.
|
||||
*/
|
||||
inline bool operator<(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
|
||||
return (lhs.first().location() == rhs.first().location() && lhs.second().location() < rhs.second().location()) || lhs.first().location() < rhs.first().location();
|
||||
if (lhs.first().location() == rhs.first().location()) {
|
||||
const vec p0{lhs.first().location()};
|
||||
const vec p1{lhs.second().location()};
|
||||
const vec q0{rhs.first().location()};
|
||||
const vec q1{rhs.second().location()};
|
||||
const vec p = p1 - p0;
|
||||
const vec q = q1 - q0;
|
||||
|
||||
if (p.x == 0 && q.x == 0) {
|
||||
return p.y < q.y;
|
||||
}
|
||||
|
||||
const auto a = p.y * q.x;
|
||||
const auto b = q.y * p.x;
|
||||
if (a == b) {
|
||||
return p.x < q.x;
|
||||
}
|
||||
return a > b;
|
||||
}
|
||||
return lhs.first().location() < rhs.first().location();
|
||||
}
|
||||
|
||||
inline bool operator>(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
|
||||
@ -184,7 +276,10 @@ namespace osmium {
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const NodeRefSegment& segment) {
|
||||
return out << segment.first() << "--" << segment.second();
|
||||
return out << segment.start() << "--" << segment.stop()
|
||||
<< "[" << (segment.is_reverse() ? 'R' : '_')
|
||||
<< (segment.is_done() ? 'd' : '_')
|
||||
<< (segment.is_direction_done() ? 'D' : '_') << "]";
|
||||
}
|
||||
|
||||
inline bool outside_x_range(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
|
||||
@ -194,7 +289,7 @@ namespace osmium {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) {
|
||||
inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
|
||||
const std::pair<int32_t, int32_t> m1 = std::minmax(s1.first().location().y(), s1.second().location().y());
|
||||
const std::pair<int32_t, int32_t> m2 = std::minmax(s2.first().location().y(), s2.second().location().y());
|
||||
if (m1.first > m2.second || m2.first > m1.second) {
|
||||
@ -210,55 +305,94 @@ namespace osmium {
|
||||
* might be slightly different than the numerically correct
|
||||
* location.
|
||||
*
|
||||
* This function uses integer arithmentic as much as possible and
|
||||
* This function uses integer arithmetic as much as possible and
|
||||
* will not work if the segments are longer than about half the
|
||||
* planet. This shouldn't happen with real data, so it isn't a big
|
||||
* problem.
|
||||
*
|
||||
* If the segments touch in one of their endpoints, it doesn't
|
||||
* count as an intersection.
|
||||
* If the segments touch in one or both of their endpoints, it
|
||||
* doesn't count as an intersection.
|
||||
*
|
||||
* If the segments intersect not in a single point but in multiple
|
||||
* points, ie if they overlap, this is NOT detected.
|
||||
* points, ie if they are collinear and overlap, the smallest
|
||||
* of the endpoints that is in the overlapping section is returned.
|
||||
*
|
||||
* @returns Undefined osmium::Location if there is no intersection
|
||||
* or a defined Location if the segments intersect.
|
||||
*/
|
||||
inline osmium::Location calculate_intersection(const NodeRefSegment& s1, const NodeRefSegment& s2) {
|
||||
if (s1.first().location() == s2.first().location() ||
|
||||
s1.first().location() == s2.second().location() ||
|
||||
s1.second().location() == s2.first().location() ||
|
||||
s1.second().location() == s2.second().location()) {
|
||||
inline osmium::Location calculate_intersection(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
|
||||
// See http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
|
||||
// for some hints about how the algorithm works.
|
||||
const vec p0{s1.first()};
|
||||
const vec p1{s1.second()};
|
||||
const vec q0{s2.first()};
|
||||
const vec q1{s2.second()};
|
||||
|
||||
if ((p0 == q0 && p1 == q1) ||
|
||||
(p0 == q1 && p1 == q0)) {
|
||||
// segments are the same
|
||||
return osmium::Location();
|
||||
}
|
||||
|
||||
int64_t s1ax = s1.first().x();
|
||||
int64_t s1ay = s1.first().y();
|
||||
int64_t s1bx = s1.second().x();
|
||||
int64_t s1by = s1.second().y();
|
||||
int64_t s2ax = s2.first().x();
|
||||
int64_t s2ay = s2.first().y();
|
||||
int64_t s2bx = s2.second().x();
|
||||
int64_t s2by = s2.second().y();
|
||||
|
||||
int64_t d = (s2by - s2ay) * (s1bx - s1ax) -
|
||||
(s2bx - s2ax) * (s1by - s1ay);
|
||||
const vec pd = p1 - p0;
|
||||
const int64_t d = pd * (q1 - q0);
|
||||
|
||||
if (d != 0) {
|
||||
int64_t na = (s2bx - s2ax) * (s1ay - s2ay) -
|
||||
(s2by - s2ay) * (s1ax - s2ax);
|
||||
// segments are not collinear
|
||||
|
||||
int64_t nb = (s1bx - s1ax) * (s1ay - s2ay) -
|
||||
(s1by - s1ay) * (s1ax - s2ax);
|
||||
if (p0 == q0 || p0 == q1 || p1 == q0 || p1 == q1) {
|
||||
// touching at an end point
|
||||
return osmium::Location();
|
||||
}
|
||||
|
||||
// intersection in a point
|
||||
|
||||
const int64_t na = (q1.x - q0.x) * (p0.y - q0.y) -
|
||||
(q1.y - q0.y) * (p0.x - q0.x);
|
||||
|
||||
const int64_t nb = (p1.x - p0.x) * (p0.y - q0.y) -
|
||||
(p1.y - p0.y) * (p0.x - q0.x);
|
||||
|
||||
if ((d > 0 && na >= 0 && na <= d && nb >= 0 && nb <= d) ||
|
||||
(d < 0 && na <= 0 && na >= d && nb <= 0 && nb >= d)) {
|
||||
const double ua = double(na) / d;
|
||||
const vec i = p0 + ua * (p1 - p0);
|
||||
return osmium::Location(int32_t(i.x), int32_t(i.y));
|
||||
}
|
||||
|
||||
double ua = double(na) / d;
|
||||
int32_t ix = int32_t(s1ax + ua*(s1bx - s1ax));
|
||||
int32_t iy = int32_t(s1ay + ua*(s1by - s1ay));
|
||||
return osmium::Location();
|
||||
}
|
||||
|
||||
return osmium::Location(ix, iy);
|
||||
// segments are collinear
|
||||
|
||||
if (pd * (q0 - p0) == 0) {
|
||||
// segments are on the same line
|
||||
|
||||
struct seg_loc {
|
||||
int segment;
|
||||
osmium::Location location;
|
||||
};
|
||||
|
||||
seg_loc sl[4];
|
||||
sl[0] = {0, s1.first().location() };
|
||||
sl[1] = {0, s1.second().location()};
|
||||
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;
|
||||
});
|
||||
|
||||
if (sl[1].location == sl[2].location) {
|
||||
return osmium::Location();
|
||||
}
|
||||
|
||||
if (sl[0].segment != sl[1].segment) {
|
||||
if (sl[0].location == sl[1].location) {
|
||||
return sl[2].location;
|
||||
} else {
|
||||
return sl[1].location;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,10 +34,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
@ -47,6 +46,8 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class Way;
|
||||
|
||||
namespace area {
|
||||
|
||||
namespace detail {
|
||||
@ -58,214 +59,155 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::vector<NodeRefSegment> segments_type;
|
||||
using segments_type = std::vector<NodeRefSegment*>;
|
||||
|
||||
private:
|
||||
|
||||
// segments in this ring
|
||||
// Segments in this ring.
|
||||
segments_type m_segments;
|
||||
|
||||
bool m_outer {true};
|
||||
|
||||
// if this is an outer ring, these point to it's inner rings (if any)
|
||||
// If this is an outer ring, these point to it's inner rings
|
||||
// (if any).
|
||||
std::vector<ProtoRing*> m_inner;
|
||||
|
||||
// The smallest segment. Will be kept current whenever a new
|
||||
// segment is added to the ring.
|
||||
NodeRefSegment* m_min_segment;
|
||||
|
||||
// If this is an inner ring, points to the outer ring.
|
||||
ProtoRing* m_outer_ring;
|
||||
|
||||
int64_t m_sum;
|
||||
|
||||
public:
|
||||
|
||||
explicit ProtoRing(const NodeRefSegment& segment) noexcept :
|
||||
m_segments() {
|
||||
explicit ProtoRing(NodeRefSegment* segment) noexcept :
|
||||
m_segments(),
|
||||
m_inner(),
|
||||
m_min_segment(segment),
|
||||
m_outer_ring(nullptr),
|
||||
m_sum(0) {
|
||||
add_segment_back(segment);
|
||||
}
|
||||
|
||||
explicit ProtoRing(segments_type::const_iterator sbegin, segments_type::const_iterator send) :
|
||||
m_segments(static_cast<size_t>(std::distance(sbegin, send))) {
|
||||
std::copy(sbegin, send, m_segments.begin());
|
||||
void add_segment_back(NodeRefSegment* segment) {
|
||||
assert(segment);
|
||||
if (*segment < *m_min_segment) {
|
||||
m_min_segment = segment;
|
||||
}
|
||||
m_segments.push_back(segment);
|
||||
segment->set_ring(this);
|
||||
m_sum += segment->det();
|
||||
}
|
||||
|
||||
bool outer() const noexcept {
|
||||
return m_outer;
|
||||
NodeRefSegment* min_segment() const noexcept {
|
||||
return m_min_segment;
|
||||
}
|
||||
|
||||
void set_inner() noexcept {
|
||||
m_outer = false;
|
||||
ProtoRing* outer_ring() const noexcept {
|
||||
return m_outer_ring;
|
||||
}
|
||||
|
||||
segments_type& segments() noexcept {
|
||||
return m_segments;
|
||||
void set_outer_ring(ProtoRing* outer_ring) noexcept {
|
||||
assert(outer_ring);
|
||||
assert(m_inner.empty());
|
||||
m_outer_ring = outer_ring;
|
||||
}
|
||||
|
||||
const std::vector<ProtoRing*>& inner_rings() const noexcept {
|
||||
return m_inner;
|
||||
}
|
||||
|
||||
void add_inner_ring(ProtoRing* ring) {
|
||||
assert(ring);
|
||||
assert(!m_outer_ring);
|
||||
m_inner.push_back(ring);
|
||||
}
|
||||
|
||||
bool is_outer() const noexcept {
|
||||
return !m_outer_ring;
|
||||
}
|
||||
|
||||
const segments_type& segments() const noexcept {
|
||||
return m_segments;
|
||||
}
|
||||
|
||||
void remove_segments(segments_type::iterator sbegin, segments_type::iterator send) {
|
||||
m_segments.erase(sbegin, send);
|
||||
const NodeRef& get_node_ref_start() const noexcept {
|
||||
return m_segments.front()->start();
|
||||
}
|
||||
|
||||
void add_segment_front(const NodeRefSegment& segment) {
|
||||
m_segments.insert(m_segments.begin(), segment);
|
||||
const NodeRef& get_node_ref_stop() const noexcept {
|
||||
return m_segments.back()->stop();
|
||||
}
|
||||
|
||||
void add_segment_back(const NodeRefSegment& segment) {
|
||||
m_segments.push_back(segment);
|
||||
bool closed() const noexcept {
|
||||
return get_node_ref_start().location() == get_node_ref_stop().location();
|
||||
}
|
||||
|
||||
const NodeRefSegment& get_segment_front() const {
|
||||
return m_segments.front();
|
||||
void reverse() {
|
||||
std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment* segment) {
|
||||
segment->reverse();
|
||||
});
|
||||
std::reverse(m_segments.begin(), m_segments.end());
|
||||
m_sum = -m_sum;
|
||||
}
|
||||
|
||||
NodeRefSegment& get_segment_front() {
|
||||
return m_segments.front();
|
||||
void mark_direction_done() {
|
||||
std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment* segment) {
|
||||
segment->mark_direction_done();
|
||||
});
|
||||
}
|
||||
|
||||
const NodeRef& get_node_ref_front() const {
|
||||
return get_segment_front().first();
|
||||
bool is_cw() const noexcept {
|
||||
return m_sum <= 0;
|
||||
}
|
||||
|
||||
const NodeRefSegment& get_segment_back() const {
|
||||
return m_segments.back();
|
||||
int64_t sum() const noexcept {
|
||||
return m_sum;
|
||||
}
|
||||
|
||||
NodeRefSegment& get_segment_back() {
|
||||
return m_segments.back();
|
||||
void fix_direction() noexcept {
|
||||
if (is_cw() == is_outer()) {
|
||||
reverse();
|
||||
}
|
||||
}
|
||||
|
||||
const NodeRef& get_node_ref_back() const {
|
||||
return get_segment_back().second();
|
||||
void reset() {
|
||||
m_inner.clear();
|
||||
m_outer_ring = nullptr;
|
||||
std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment* segment) {
|
||||
segment->mark_direction_not_done();
|
||||
});
|
||||
}
|
||||
|
||||
bool closed() const {
|
||||
return m_segments.front().first().location() == m_segments.back().second().location();
|
||||
}
|
||||
|
||||
int64_t sum() const {
|
||||
int64_t sum = 0;
|
||||
|
||||
void get_ways(std::set<const osmium::Way*>& ways) const {
|
||||
for (const auto& segment : m_segments) {
|
||||
sum += static_cast<int64_t>(segment.first().location().x()) * static_cast<int64_t>(segment.second().location().y()) -
|
||||
static_cast<int64_t>(segment.second().location().x()) * static_cast<int64_t>(segment.first().location().y());
|
||||
ways.insert(segment->way());
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
void join_forward(ProtoRing& other) {
|
||||
for (NodeRefSegment* segment : other.m_segments) {
|
||||
add_segment_back(segment);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_cw() const {
|
||||
return sum() <= 0;
|
||||
void join_backward(ProtoRing& other) {
|
||||
for (auto it = other.m_segments.rbegin(); it != other.m_segments.rend(); ++it) {
|
||||
(*it)->reverse();
|
||||
add_segment_back(*it);
|
||||
}
|
||||
|
||||
int64_t area() const {
|
||||
return std::abs(sum()) / 2;
|
||||
}
|
||||
|
||||
void swap_segments(ProtoRing& other) {
|
||||
using std::swap;
|
||||
swap(m_segments, other.m_segments);
|
||||
}
|
||||
|
||||
void add_inner_ring(ProtoRing* ring) {
|
||||
m_inner.push_back(ring);
|
||||
}
|
||||
|
||||
const std::vector<ProtoRing*>& inner_rings() const {
|
||||
return m_inner;
|
||||
}
|
||||
|
||||
void print(std::ostream& out) const {
|
||||
out << "[";
|
||||
bool first = true;
|
||||
if (!m_segments.empty()) {
|
||||
out << m_segments.front()->start().ref();
|
||||
}
|
||||
for (const auto& segment : m_segments) {
|
||||
if (first) {
|
||||
out << segment.first().ref();
|
||||
out << ',' << segment->stop().ref();
|
||||
}
|
||||
out << ',' << segment.second().ref();
|
||||
first = false;
|
||||
}
|
||||
out << "]";
|
||||
}
|
||||
|
||||
void reverse() {
|
||||
std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment& segment) {
|
||||
segment.swap_locations();
|
||||
});
|
||||
std::reverse(m_segments.begin(), m_segments.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge other ring to end of this ring.
|
||||
*/
|
||||
void merge_ring(const ProtoRing& other, bool debug) {
|
||||
if (debug) {
|
||||
std::cerr << " MERGE rings ";
|
||||
print(std::cerr);
|
||||
std::cerr << " to ";
|
||||
other.print(std::cerr);
|
||||
std::cerr << "\n";
|
||||
}
|
||||
m_segments.insert(m_segments.end(), other.m_segments.begin(), other.m_segments.end());
|
||||
if (debug) {
|
||||
std::cerr << " result ring: ";
|
||||
print(std::cerr);
|
||||
std::cerr << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void merge_ring_reverse(const ProtoRing& other, bool debug) {
|
||||
if (debug) {
|
||||
std::cerr << " MERGE rings (reverse) ";
|
||||
print(std::cerr);
|
||||
std::cerr << " to ";
|
||||
other.print(std::cerr);
|
||||
std::cerr << "\n";
|
||||
}
|
||||
size_t n = m_segments.size();
|
||||
m_segments.resize(n + other.m_segments.size());
|
||||
std::transform(other.m_segments.rbegin(), other.m_segments.rend(), m_segments.begin() + static_cast<segments_type::difference_type>(n), [](NodeRefSegment segment) {
|
||||
segment.swap_locations();
|
||||
return segment;
|
||||
});
|
||||
if (debug) {
|
||||
std::cerr << " result ring: ";
|
||||
print(std::cerr);
|
||||
std::cerr << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
const NodeRef& min_node() const {
|
||||
auto it = std::min_element(m_segments.begin(), m_segments.end());
|
||||
if (location_less()(it->first(), it->second())) {
|
||||
return it->first();
|
||||
} else {
|
||||
return it->second();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_in(ProtoRing* outer) {
|
||||
osmium::Location testpoint = segments().front().first().location();
|
||||
bool is_in = false;
|
||||
|
||||
for (size_t i = 0, j = outer->segments().size()-1; i < outer->segments().size(); j = i++) {
|
||||
if (((outer->segments()[i].first().location().y() > testpoint.y()) != (outer->segments()[j].first().location().y() > testpoint.y())) &&
|
||||
(testpoint.x() < (outer->segments()[j].first().location().x() - outer->segments()[i].first().location().x()) * (testpoint.y() - outer->segments()[i].first().location().y()) / (outer->segments()[j].first().location().y() - outer->segments()[i].first().location().y()) + outer->segments()[i].first().location().x()) ) {
|
||||
is_in = !is_in;
|
||||
}
|
||||
}
|
||||
|
||||
return is_in;
|
||||
}
|
||||
|
||||
void get_ways(std::set<const osmium::Way*>& ways) {
|
||||
for (const auto& segment : m_segments) {
|
||||
ways.insert(segment.way());
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(const NodeRefSegment& segment) const {
|
||||
for (const auto& s : m_segments) {
|
||||
if (s == segment || (s.first() == segment.second() && s.second() == segment.first())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
out << "]-" << (is_outer() ? "OUTER" : "INNER");
|
||||
}
|
||||
|
||||
}; // class ProtoRing
|
||||
|
@ -35,12 +35,16 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
#include <osmium/area/problem_reporter.hpp>
|
||||
#include <osmium/area/detail/node_ref_segment.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/area/problem_reporter.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
@ -52,6 +56,24 @@ namespace osmium {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Iterate over all relation members and the vector of ways at the
|
||||
* same time and call given function with the relation member and
|
||||
* way as parameter. This takes into account that there might be
|
||||
* non-way members in the relation.
|
||||
*/
|
||||
template <typename F>
|
||||
inline void for_each_member(const osmium::Relation& relation, const std::vector<const osmium::Way*>& ways, F&& func) {
|
||||
auto way_it = ways.cbegin();
|
||||
for (const osmium::RelationMember& member : relation.members()) {
|
||||
if (member.type() == osmium::item_type::way) {
|
||||
assert(way_it != ways.cend());
|
||||
func(member, **way_it);
|
||||
++way_it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper class for the area assembler. It models
|
||||
* a list of segments.
|
||||
@ -64,6 +86,51 @@ namespace osmium {
|
||||
|
||||
bool m_debug;
|
||||
|
||||
static role_type parse_role(const char* role) noexcept {
|
||||
if (role[0] == '\0') {
|
||||
return role_type::empty;
|
||||
} else if (!std::strcmp(role, "outer")) {
|
||||
return role_type::outer;
|
||||
} else if (!std::strcmp(role, "inner")) {
|
||||
return role_type::inner;
|
||||
}
|
||||
return role_type::unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
if (way->nodes().empty()) {
|
||||
return sum;
|
||||
} else {
|
||||
return sum + way->nodes().size() - 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
uint32_t extract_segments_from_way_impl(osmium::area::ProblemReporter* problem_reporter, const osmium::Way& way, role_type role) {
|
||||
uint32_t duplicate_nodes = 0;
|
||||
|
||||
osmium::NodeRef previous_nr;
|
||||
for (const osmium::NodeRef& nr : way.nodes()) {
|
||||
if (previous_nr.location()) {
|
||||
if (previous_nr.location() != nr.location()) {
|
||||
m_segments.emplace_back(previous_nr, nr, role, &way);
|
||||
} else {
|
||||
++duplicate_nodes;
|
||||
if (problem_reporter) {
|
||||
problem_reporter->report_duplicate_node(previous_nr.ref(), nr.ref(), nr.location());
|
||||
}
|
||||
}
|
||||
}
|
||||
previous_nr = nr;
|
||||
}
|
||||
|
||||
return duplicate_nodes;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
explicit SegmentList(bool debug) noexcept :
|
||||
@ -84,12 +151,31 @@ namespace osmium {
|
||||
return m_segments.size();
|
||||
}
|
||||
|
||||
/// Is the segment list empty?
|
||||
bool empty() const noexcept {
|
||||
return m_segments.empty();
|
||||
}
|
||||
|
||||
typedef slist_type::const_iterator const_iterator;
|
||||
typedef slist_type::iterator iterator;
|
||||
using const_iterator = slist_type::const_iterator;
|
||||
using iterator = slist_type::iterator;
|
||||
|
||||
NodeRefSegment& front() {
|
||||
return m_segments.front();
|
||||
}
|
||||
|
||||
NodeRefSegment& back() {
|
||||
return m_segments.back();
|
||||
}
|
||||
|
||||
const NodeRefSegment& operator[](size_t n) const noexcept {
|
||||
assert(n < m_segments.size());
|
||||
return m_segments[n];
|
||||
}
|
||||
|
||||
NodeRefSegment& operator[](size_t n) noexcept {
|
||||
assert(n < m_segments.size());
|
||||
return m_segments[n];
|
||||
}
|
||||
|
||||
iterator begin() noexcept {
|
||||
return m_segments.begin();
|
||||
@ -115,11 +201,6 @@ namespace osmium {
|
||||
m_debug = debug;
|
||||
}
|
||||
|
||||
/// Clear the list of segments. All segments are removed.
|
||||
void clear() {
|
||||
m_segments.clear();
|
||||
}
|
||||
|
||||
/// Sort the list of segments.
|
||||
void sort() {
|
||||
std::sort(m_segments.begin(), m_segments.end());
|
||||
@ -128,32 +209,37 @@ namespace osmium {
|
||||
/**
|
||||
* Extract segments from given way and add them to the list.
|
||||
*
|
||||
* Segments connecting two nodes with the same location (ie same
|
||||
* node or different node with same location) are removed.
|
||||
*
|
||||
* XXX should two nodes with same location be reported?
|
||||
* Segments connecting two nodes with the same location (ie
|
||||
* same node or different nodes with same location) are
|
||||
* removed after reporting the duplicate node.
|
||||
*/
|
||||
void extract_segments_from_way(const osmium::Way& way, const char* role) {
|
||||
osmium::NodeRef last_nr;
|
||||
for (const osmium::NodeRef& nr : way.nodes()) {
|
||||
if (last_nr.location() && last_nr.location() != nr.location()) {
|
||||
m_segments.emplace_back(last_nr, nr, role, &way);
|
||||
}
|
||||
last_nr = nr;
|
||||
uint32_t extract_segments_from_way(osmium::area::ProblemReporter* problem_reporter, const osmium::Way& way) {
|
||||
if (way.nodes().empty()) {
|
||||
return 0;
|
||||
}
|
||||
m_segments.reserve(way.nodes().size() - 1);
|
||||
return extract_segments_from_way_impl(problem_reporter, way, role_type::outer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract all segments from all ways that make up this
|
||||
* multipolygon relation and add them to the list.
|
||||
*/
|
||||
void extract_segments_from_ways(const osmium::Relation& relation, const std::vector<size_t>& members, const osmium::memory::Buffer& in_buffer) {
|
||||
auto member_it = relation.members().begin();
|
||||
for (size_t offset : members) {
|
||||
const osmium::Way& way = in_buffer.get<const osmium::Way>(offset);
|
||||
extract_segments_from_way(way, member_it->role());
|
||||
++member_it;
|
||||
uint32_t extract_segments_from_ways(osmium::area::ProblemReporter* problem_reporter, const osmium::Relation& relation, const std::vector<const osmium::Way*>& members) {
|
||||
assert(relation.members().size() >= members.size());
|
||||
|
||||
const size_t num_segments = get_num_segments(members);
|
||||
if (problem_reporter) {
|
||||
problem_reporter->set_nodes(num_segments);
|
||||
}
|
||||
m_segments.reserve(num_segments);
|
||||
|
||||
uint32_t duplicate_nodes = 0;
|
||||
for_each_member(relation, members, [this, &problem_reporter, &duplicate_nodes](const osmium::RelationMember& member, const osmium::Way& way) {
|
||||
duplicate_nodes += extract_segments_from_way_impl(problem_reporter, way, parse_role(member.role()));
|
||||
});
|
||||
|
||||
return duplicate_nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -162,17 +248,35 @@ namespace osmium {
|
||||
* same segment. So if there are three, for instance, two will
|
||||
* be removed and one will be left.
|
||||
*/
|
||||
void erase_duplicate_segments() {
|
||||
uint32_t erase_duplicate_segments(osmium::area::ProblemReporter* problem_reporter) {
|
||||
uint32_t duplicate_segments = 0;
|
||||
|
||||
while (true) {
|
||||
auto it = std::adjacent_find(m_segments.begin(), m_segments.end());
|
||||
if (it == m_segments.end()) {
|
||||
return;
|
||||
break;
|
||||
}
|
||||
if (m_debug) {
|
||||
std::cerr << " erase duplicate segment: " << *it << "\n";
|
||||
}
|
||||
|
||||
// Only count and report duplicate segments if they
|
||||
// belong to the same way or if they don't both have
|
||||
// the role "inner". Those cases are definitely wrong.
|
||||
// If the duplicate segments belong to different
|
||||
// "inner" ways, they could be touching inner rings
|
||||
// which are perfectly okay. Note that for this check
|
||||
// the role has to be correct in the member data.
|
||||
if (it->way() == std::next(it)->way() || !it->role_inner() || !std::next(it)->role_inner()) {
|
||||
++duplicate_segments;
|
||||
if (problem_reporter) {
|
||||
problem_reporter->report_duplicate_segment(it->first(), it->second());
|
||||
}
|
||||
}
|
||||
m_segments.erase(it, it+2);
|
||||
}
|
||||
|
||||
return duplicate_segments;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -182,14 +286,14 @@ namespace osmium {
|
||||
* reported to this object.
|
||||
* @returns true if there are intersections.
|
||||
*/
|
||||
bool find_intersections(osmium::area::ProblemReporter* problem_reporter) const {
|
||||
uint32_t find_intersections(osmium::area::ProblemReporter* problem_reporter) const {
|
||||
if (m_segments.empty()) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool found_intersections = false;
|
||||
uint32_t found_intersections = 0;
|
||||
|
||||
for (auto it1 = m_segments.begin(); it1 != m_segments.end()-1; ++it1) {
|
||||
for (auto it1 = m_segments.cbegin(); it1 != m_segments.cend()-1; ++it1) {
|
||||
const NodeRefSegment& s1 = *it1;
|
||||
for (auto it2 = it1+1; it2 != m_segments.end(); ++it2) {
|
||||
const NodeRefSegment& s2 = *it2;
|
||||
@ -203,12 +307,13 @@ namespace osmium {
|
||||
if (y_range_overlap(s1, s2)) {
|
||||
osmium::Location intersection = calculate_intersection(s1, s2);
|
||||
if (intersection) {
|
||||
found_intersections = true;
|
||||
++found_intersections;
|
||||
if (m_debug) {
|
||||
std::cerr << " segments " << s1 << " and " << s2 << " intersecting at " << intersection << "\n";
|
||||
}
|
||||
if (problem_reporter) {
|
||||
problem_reporter->report_intersection(s1.way()->id(), s1.first().location(), s1.second().location(), s2.way()->id(), s2.first().location(), s2.second().location(), intersection);
|
||||
problem_reporter->report_intersection(s1.way()->id(), s1.first().location(), s1.second().location(),
|
||||
s2.way()->id(), s2.first().location(), s2.second().location(), intersection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
121
third_party/libosmium/include/osmium/area/detail/vector.hpp
vendored
Normal file
121
third_party/libosmium/include/osmium/area/detail/vector.hpp
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
#ifndef OSMIUM_AREA_DETAIL_VECTOR_HPP
|
||||
#define OSMIUM_AREA_DETAIL_VECTOR_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 <cstdint>
|
||||
#include <iosfwd>
|
||||
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace area {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* This helper class models a 2D vector in the mathematical sense.
|
||||
* It uses 64 bit integers internally which has enough precision
|
||||
* for most operations with inputs based on 32 bit locations.
|
||||
*/
|
||||
struct vec {
|
||||
|
||||
int64_t x;
|
||||
int64_t y;
|
||||
|
||||
constexpr vec(int64_t a, int64_t b) noexcept :
|
||||
x(a),
|
||||
y(b) {
|
||||
}
|
||||
|
||||
constexpr explicit vec(const osmium::Location& l) noexcept :
|
||||
x(l.x()),
|
||||
y(l.y()) {
|
||||
}
|
||||
|
||||
constexpr explicit vec(const osmium::NodeRef& nr) noexcept :
|
||||
x(nr.x()),
|
||||
y(nr.y()) {
|
||||
}
|
||||
|
||||
}; // struct vec
|
||||
|
||||
// addition
|
||||
constexpr inline vec operator+(const vec& a, const vec& b) noexcept {
|
||||
return vec{a.x + b.x, a.y + b.y};
|
||||
}
|
||||
|
||||
// subtraction
|
||||
constexpr inline vec operator-(const vec& a, const vec& b) noexcept {
|
||||
return vec{a.x - b.x, a.y - b.y};
|
||||
}
|
||||
|
||||
// cross product
|
||||
constexpr inline int64_t operator*(const vec& a, const vec& b) noexcept {
|
||||
return a.x * b.y - a.y * b.x;
|
||||
}
|
||||
|
||||
// scale vector
|
||||
constexpr inline vec operator*(double s, const vec& v) noexcept {
|
||||
return vec{int64_t(s * v.x), int64_t(s * v.y)};
|
||||
}
|
||||
|
||||
// scale vector
|
||||
constexpr inline vec operator*(const vec& v, double s) noexcept {
|
||||
return vec{int64_t(s * v.x), int64_t(s * v.y)};
|
||||
}
|
||||
|
||||
// equality
|
||||
constexpr inline bool operator==(const vec& a, const vec& b) noexcept {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
}
|
||||
|
||||
// inequality
|
||||
constexpr inline bool operator!=(const vec& a, const vec& b) noexcept {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const vec& v) {
|
||||
return out << '(' << v.x << ',' << v.y << ')';
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace area
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_AREA_DETAIL_VECTOR_HPP
|
@ -34,11 +34,11 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include <osmium/area/stats.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
@ -47,7 +47,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/osm/tag.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/relations/collector.hpp>
|
||||
#include <osmium/relations/detail/member_meta.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@ -74,13 +73,15 @@ namespace osmium {
|
||||
template <typename TAssembler>
|
||||
class MultipolygonCollector : public osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> {
|
||||
|
||||
typedef typename osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> collector_type;
|
||||
using collector_type = osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false>;
|
||||
|
||||
typedef typename TAssembler::config_type assembler_config_type;
|
||||
using assembler_config_type = typename TAssembler::config_type;
|
||||
const assembler_config_type m_assembler_config;
|
||||
|
||||
osmium::memory::Buffer m_output_buffer;
|
||||
|
||||
osmium::area::area_stats m_stats;
|
||||
|
||||
static constexpr size_t initial_output_buffer_size = 1024 * 1024;
|
||||
static constexpr size_t max_buffer_size_for_flush = 100 * 1024;
|
||||
|
||||
@ -107,6 +108,10 @@ namespace osmium {
|
||||
m_output_buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes) {
|
||||
}
|
||||
|
||||
const osmium::area::area_stats& stats() const noexcept {
|
||||
return m_stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* We are interested in all relations tagged with type=multipolygon
|
||||
* or type=boundary.
|
||||
@ -121,7 +126,7 @@ namespace osmium {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((!strcmp(type, "multipolygon")) || (!strcmp(type, "boundary"))) {
|
||||
if ((!std::strcmp(type, "multipolygon")) || (!std::strcmp(type, "boundary"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -155,26 +160,32 @@ namespace osmium {
|
||||
// way is closed and has enough nodes, build simple multipolygon
|
||||
TAssembler assembler(m_assembler_config);
|
||||
assembler(way, m_output_buffer);
|
||||
m_stats += assembler.stats();
|
||||
possibly_flush_output_buffer();
|
||||
}
|
||||
} catch (osmium::invalid_location&) {
|
||||
} catch (const osmium::invalid_location&) {
|
||||
// XXX ignore
|
||||
}
|
||||
}
|
||||
|
||||
void complete_relation(osmium::relations::RelationMeta& relation_meta) {
|
||||
const osmium::Relation& relation = this->get_relation(relation_meta);
|
||||
std::vector<size_t> offsets;
|
||||
const osmium::memory::Buffer& buffer = this->members_buffer();
|
||||
|
||||
std::vector<const osmium::Way*> ways;
|
||||
for (const auto& member : relation.members()) {
|
||||
if (member.ref() != 0) {
|
||||
offsets.push_back(this->get_offset(member.type(), member.ref()));
|
||||
const size_t offset = this->get_offset(member.type(), member.ref());
|
||||
ways.push_back(&buffer.get<const osmium::Way>(offset));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
TAssembler assembler(m_assembler_config);
|
||||
assembler(relation, offsets, this->members_buffer(), m_output_buffer);
|
||||
assembler(relation, ways, m_output_buffer);
|
||||
m_stats += assembler.stats();
|
||||
possibly_flush_output_buffer();
|
||||
} catch (osmium::invalid_location&) {
|
||||
} catch (const osmium::invalid_location&) {
|
||||
// XXX ignore
|
||||
}
|
||||
}
|
||||
|
@ -33,12 +33,17 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class NodeRef;
|
||||
class Way;
|
||||
|
||||
namespace area {
|
||||
|
||||
/**
|
||||
@ -62,6 +67,9 @@ namespace osmium {
|
||||
// ID of the relation/way we are currently working on
|
||||
osmium::object_id_type m_object_id;
|
||||
|
||||
// Number of nodes in the area
|
||||
size_t m_nodes;
|
||||
|
||||
public:
|
||||
|
||||
ProblemReporter() = default;
|
||||
@ -79,6 +87,10 @@ namespace osmium {
|
||||
m_object_id = object_id;
|
||||
}
|
||||
|
||||
void set_nodes(size_t nodes) noexcept {
|
||||
m_nodes = nodes;
|
||||
}
|
||||
|
||||
// Disable "unused-parameter" warning, so that the compiler will not complain.
|
||||
// We can't remove the parameter names, because then doxygen will complain.
|
||||
#pragma GCC diagnostic push
|
||||
@ -94,6 +106,16 @@ namespace osmium {
|
||||
virtual void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a node/location where rings touch. This is often wrong,
|
||||
* but not necessarily so.
|
||||
*
|
||||
* @param node_id ID of the node.
|
||||
* @param location Location of the node.
|
||||
*/
|
||||
virtual void report_touching_ring(osmium::object_id_type node_id, osmium::Location location) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an intersection between two segments.
|
||||
*
|
||||
@ -109,13 +131,25 @@ namespace osmium {
|
||||
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a duplicate segments. Two or more segments are directly
|
||||
* on top of each other. This can be a problem, if there is a
|
||||
* spike for instance, or it could be okay, if there are touching
|
||||
* inner rings.
|
||||
*
|
||||
* @param nr1 NodeRef of one end of the segment.
|
||||
* @param nr2 NodeRef of the other end of the segment.
|
||||
*/
|
||||
virtual void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an open ring.
|
||||
*
|
||||
* @param end1 Location of the first open end.
|
||||
* @param end2 Location of the second open end.
|
||||
* @param nr NodeRef of one end of the ring.
|
||||
* @param way Optional pointer to way the end node is in.
|
||||
*/
|
||||
virtual void report_ring_not_closed(osmium::Location end1, osmium::Location end2) {
|
||||
virtual void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) {
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,6 +172,32 @@ namespace osmium {
|
||||
virtual void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a way that is in multiple rings.
|
||||
*
|
||||
* @param way The way.
|
||||
*/
|
||||
virtual void report_way_in_multiple_rings(const osmium::Way& way) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a way with role inner that has the same tags as the
|
||||
* relation or outer ways.
|
||||
*
|
||||
* @param way The way.
|
||||
*/
|
||||
virtual void report_inner_with_same_tags(const osmium::Way& way) {
|
||||
}
|
||||
|
||||
/**
|
||||
* In addition to reporting specific problems, this is used to
|
||||
* report all ways belonging to areas having problems.
|
||||
*
|
||||
* @param way The way
|
||||
*/
|
||||
virtual void report_way(const osmium::Way& way) {
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
}; // class ProblemReporter
|
||||
|
@ -42,6 +42,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class NodeRef;
|
||||
class Way;
|
||||
|
||||
namespace area {
|
||||
|
||||
class ProblemReporterException : public ProblemReporterStream {
|
||||
@ -62,6 +65,12 @@ namespace osmium {
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
void report_touching_ring(osmium::object_id_type node_id, osmium::Location location) override {
|
||||
m_sstream.str();
|
||||
ProblemReporterStream::report_touching_ring(node_id, location);
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
|
||||
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
|
||||
m_sstream.str();
|
||||
@ -69,9 +78,15 @@ namespace osmium {
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
|
||||
void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
|
||||
m_sstream.str();
|
||||
ProblemReporterStream::report_ring_not_closed(end1, end2);
|
||||
ProblemReporterStream::report_duplicate_segment(nr1, nr2);
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
|
||||
m_sstream.str();
|
||||
ProblemReporterStream::report_ring_not_closed(nr, way);
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
@ -87,6 +102,18 @@ namespace osmium {
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
void report_way_in_multiple_rings(const osmium::Way& way) override {
|
||||
m_sstream.str();
|
||||
ProblemReporterStream::report_way_in_multiple_rings(way);
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
void report_inner_with_same_tags(const osmium::Way& way) override {
|
||||
m_sstream.str();
|
||||
ProblemReporterStream::report_inner_with_same_tags(way);
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
}; // class ProblemReporterException
|
||||
|
||||
} // namespace area
|
||||
|
@ -49,8 +49,12 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/area/problem_reporter.hpp>
|
||||
#include <osmium/geom/factory.hpp>
|
||||
#include <osmium/geom/ogr.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
#include <osmium/osm/node_ref_list.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@ -66,26 +70,34 @@ namespace osmium {
|
||||
|
||||
gdalcpp::Layer m_layer_perror;
|
||||
gdalcpp::Layer m_layer_lerror;
|
||||
gdalcpp::Layer m_layer_ways;
|
||||
|
||||
void set_object(gdalcpp::Feature& feature) {
|
||||
const char t[2] = { osmium::item_type_to_char(m_object_type), '\0' };
|
||||
feature.set_field("obj_type", t);
|
||||
feature.set_field("obj_id", int32_t(m_object_id));
|
||||
feature.set_field("nodes", int32_t(m_nodes));
|
||||
}
|
||||
|
||||
void write_point(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location location) {
|
||||
gdalcpp::Feature feature(m_layer_perror, m_ogr_factory.create_point(location));
|
||||
feature.set_field("id1", static_cast<double>(id1));
|
||||
feature.set_field("id2", static_cast<double>(id2));
|
||||
feature.set_field("problem_type", problem_type);
|
||||
set_object(feature);
|
||||
feature.set_field("id1", double(id1));
|
||||
feature.set_field("id2", double(id2));
|
||||
feature.set_field("problem", problem_type);
|
||||
feature.add_to_layer();
|
||||
}
|
||||
|
||||
void write_line(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location loc1, osmium::Location loc2) {
|
||||
std::unique_ptr<OGRPoint> ogr_point1 = m_ogr_factory.create_point(loc1);
|
||||
std::unique_ptr<OGRPoint> ogr_point2 = m_ogr_factory.create_point(loc2);
|
||||
std::unique_ptr<OGRLineString> ogr_linestring = std::unique_ptr<OGRLineString>(new OGRLineString());
|
||||
ogr_linestring->addPoint(ogr_point1.get());
|
||||
ogr_linestring->addPoint(ogr_point2.get());
|
||||
auto ogr_linestring = std::unique_ptr<OGRLineString>{new OGRLineString{}};
|
||||
ogr_linestring->addPoint(loc1.lon(), loc1.lat());
|
||||
ogr_linestring->addPoint(loc2.lon(), loc2.lat());
|
||||
|
||||
gdalcpp::Feature feature(m_layer_lerror, std::move(ogr_linestring));
|
||||
set_object(feature);
|
||||
feature.set_field("id1", static_cast<double>(id1));
|
||||
feature.set_field("id2", static_cast<double>(id2));
|
||||
feature.set_field("problem_type", problem_type);
|
||||
feature.set_field("problem", problem_type);
|
||||
feature.add_to_layer();
|
||||
}
|
||||
|
||||
@ -93,15 +105,36 @@ namespace osmium {
|
||||
|
||||
explicit ProblemReporterOGR(gdalcpp::Dataset& dataset) :
|
||||
m_layer_perror(dataset, "perrors", wkbPoint),
|
||||
m_layer_lerror(dataset, "lerrors", wkbLineString) {
|
||||
m_layer_lerror(dataset, "lerrors", wkbLineString),
|
||||
m_layer_ways(dataset, "ways", wkbLineString) {
|
||||
|
||||
m_layer_perror.add_field("id1", OFTReal, 10);
|
||||
m_layer_perror.add_field("id2", OFTReal, 10);
|
||||
m_layer_perror.add_field("problem_type", OFTString, 30);
|
||||
// 64bit integers are not supported in GDAL < 2, so we
|
||||
// are using a workaround here in fields where we expect
|
||||
// node IDs, we use real numbers.
|
||||
m_layer_perror
|
||||
.add_field("obj_type", OFTString, 1)
|
||||
.add_field("obj_id", OFTInteger, 10)
|
||||
.add_field("nodes", OFTInteger, 8)
|
||||
.add_field("id1", OFTReal, 12, 1)
|
||||
.add_field("id2", OFTReal, 12, 1)
|
||||
.add_field("problem", OFTString, 30)
|
||||
;
|
||||
|
||||
m_layer_lerror.add_field("id1", OFTReal, 10);
|
||||
m_layer_lerror.add_field("id2", OFTReal, 10);
|
||||
m_layer_lerror.add_field("problem_type", OFTString, 30);
|
||||
m_layer_lerror
|
||||
.add_field("obj_type", OFTString, 1)
|
||||
.add_field("obj_id", OFTInteger, 10)
|
||||
.add_field("nodes", OFTInteger, 8)
|
||||
.add_field("id1", OFTReal, 12, 1)
|
||||
.add_field("id2", OFTReal, 12, 1)
|
||||
.add_field("problem", OFTString, 30)
|
||||
;
|
||||
|
||||
m_layer_ways
|
||||
.add_field("obj_type", OFTString, 1)
|
||||
.add_field("obj_id", OFTInteger, 10)
|
||||
.add_field("way_id", OFTInteger, 10)
|
||||
.add_field("nodes", OFTInteger, 8)
|
||||
;
|
||||
}
|
||||
|
||||
~ProblemReporterOGR() override = default;
|
||||
@ -110,24 +143,82 @@ namespace osmium {
|
||||
write_point("duplicate_node", node_id1, node_id2, location);
|
||||
}
|
||||
|
||||
void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
|
||||
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
|
||||
write_point("intersection", m_object_id, 0, intersection);
|
||||
write_line("intersection", m_object_id, way1_id, way1_seg_start, way1_seg_end);
|
||||
write_line("intersection", m_object_id, way2_id, way2_seg_start, way2_seg_end);
|
||||
void report_touching_ring(osmium::object_id_type node_id, osmium::Location location) override {
|
||||
write_point("touching_ring", node_id, 0, location);
|
||||
}
|
||||
|
||||
void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
|
||||
write_point("ring_not_closed", m_object_id, 0, end1);
|
||||
write_point("ring_not_closed", m_object_id, 0, end2);
|
||||
void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
|
||||
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
|
||||
write_point("intersection", way1_id, way2_id, intersection);
|
||||
write_line("intersection", way1_id, way2_id, way1_seg_start, way1_seg_end);
|
||||
write_line("intersection", way2_id, way1_id, way2_seg_start, way2_seg_end);
|
||||
}
|
||||
|
||||
void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
|
||||
write_line("duplicate_segment", nr1.ref(), nr2.ref(), nr1.location(), nr2.location());
|
||||
}
|
||||
|
||||
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
|
||||
write_point("ring_not_closed", nr.ref(), way ? way->id() : 0, nr.location());
|
||||
}
|
||||
|
||||
void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
|
||||
write_line("role_should_be_outer", m_object_id, way_id, seg_start, seg_end);
|
||||
write_line("role_should_be_outer", way_id, 0, seg_start, seg_end);
|
||||
}
|
||||
|
||||
void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
|
||||
write_line("role_should_be_inner", m_object_id, way_id, seg_start, seg_end);
|
||||
write_line("role_should_be_inner", way_id, 0, seg_start, seg_end);
|
||||
}
|
||||
|
||||
void report_way_in_multiple_rings(const osmium::Way& way) override {
|
||||
if (way.nodes().size() < 2) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
gdalcpp::Feature feature(m_layer_lerror, m_ogr_factory.create_linestring(way));
|
||||
set_object(feature);
|
||||
feature.set_field("id1", int32_t(way.id()));
|
||||
feature.set_field("id2", 0);
|
||||
feature.set_field("problem", "way_in_multiple_rings");
|
||||
feature.add_to_layer();
|
||||
} catch (const osmium::geometry_error&) {
|
||||
// XXX
|
||||
}
|
||||
}
|
||||
|
||||
void report_inner_with_same_tags(const osmium::Way& way) override {
|
||||
if (way.nodes().size() < 2) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
gdalcpp::Feature feature(m_layer_lerror, m_ogr_factory.create_linestring(way));
|
||||
set_object(feature);
|
||||
feature.set_field("id1", int32_t(way.id()));
|
||||
feature.set_field("id2", 0);
|
||||
feature.set_field("problem", "inner_with_same_tags");
|
||||
feature.add_to_layer();
|
||||
} catch (const osmium::geometry_error&) {
|
||||
// XXX
|
||||
}
|
||||
}
|
||||
|
||||
void report_way(const osmium::Way& way) override {
|
||||
if (way.nodes().empty()) {
|
||||
return;
|
||||
}
|
||||
if (way.nodes().size() == 1) {
|
||||
const auto& first_nr = way.nodes()[0];
|
||||
write_point("single_node_in_way", way.id(), first_nr.ref(), first_nr.location());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
gdalcpp::Feature feature(m_layer_ways, m_ogr_factory.create_linestring(way));
|
||||
set_object(feature);
|
||||
feature.set_field("way_id", int32_t(way.id()));
|
||||
feature.add_to_layer();
|
||||
} catch (const osmium::geometry_error&) {
|
||||
// XXX
|
||||
}
|
||||
}
|
||||
|
||||
}; // class ProblemReporterOGR
|
||||
|
@ -38,7 +38,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/area/problem_reporter.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@ -57,7 +59,7 @@ namespace osmium {
|
||||
~ProblemReporterStream() override = default;
|
||||
|
||||
void header(const char* msg) {
|
||||
*m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << ": ";
|
||||
*m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << " (with " << m_nodes << " nodes): ";
|
||||
}
|
||||
|
||||
void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
|
||||
@ -65,6 +67,11 @@ namespace osmium {
|
||||
*m_out << "node_id1=" << node_id1 << " node_id2=" << node_id2 << " location=" << location << "\n";
|
||||
}
|
||||
|
||||
void report_touching_ring(osmium::object_id_type node_id, osmium::Location location) override {
|
||||
header("touching ring");
|
||||
*m_out << "node_id=" << node_id << " location=" << location << "\n";
|
||||
}
|
||||
|
||||
void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
|
||||
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
|
||||
header("intersection");
|
||||
@ -72,9 +79,19 @@ namespace osmium {
|
||||
<< " way2_id=" << way2_id << " way2_seg_start=" << way2_seg_start << " way2_seg_end=" << way2_seg_end << " intersection=" << intersection << "\n";
|
||||
}
|
||||
|
||||
void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
|
||||
void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
|
||||
header("duplicate segment");
|
||||
*m_out << "node_id1=" << nr1.ref() << " location1=" << nr1.location()
|
||||
<< " node_id2=" << nr2.ref() << " location2=" << nr2.location() << "\n";
|
||||
}
|
||||
|
||||
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
|
||||
header("ring not closed");
|
||||
*m_out << "end1=" << end1 << " end2=" << end2 << "\n";
|
||||
*m_out << "node_id=" << nr.ref() << " location=" << nr.location();
|
||||
if (way) {
|
||||
*m_out << " on way " << way->id();
|
||||
}
|
||||
*m_out << "\n";
|
||||
}
|
||||
|
||||
void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
|
||||
@ -87,6 +104,16 @@ namespace osmium {
|
||||
*m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n";
|
||||
}
|
||||
|
||||
void report_way_in_multiple_rings(const osmium::Way& way) override {
|
||||
header("way in multiple rings");
|
||||
*m_out << "way_id=" << way.id() << '\n';
|
||||
}
|
||||
|
||||
void report_inner_with_same_tags(const osmium::Way& way) override {
|
||||
header("inner way with same tags as relation or outer");
|
||||
*m_out << "way_id=" << way.id() << '\n';
|
||||
}
|
||||
|
||||
}; // class ProblemReporterStream
|
||||
|
||||
} // namespace area
|
||||
|
128
third_party/libosmium/include/osmium/area/stats.hpp
vendored
Normal file
128
third_party/libosmium/include/osmium/area/stats.hpp
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
#ifndef OSMIUM_AREA_STATS_HPP
|
||||
#define OSMIUM_AREA_STATS_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 <cstdint>
|
||||
#include <ostream>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace area {
|
||||
|
||||
/**
|
||||
* These statistics are generated by the area assembler code. They
|
||||
* tell the user of the assembler a lot about the objects this area
|
||||
* is made out of, what happened during the assembly, and what errors
|
||||
* there were.
|
||||
*/
|
||||
struct area_stats {
|
||||
uint64_t area_really_complex_case = 0; ///< Most difficult case with rings touching in multiple points
|
||||
uint64_t area_simple_case = 0; ///< Simple case, no touching rings
|
||||
uint64_t area_touching_rings_case = 0; ///< More difficult case with touching rings
|
||||
uint64_t duplicate_nodes = 0; ///< Consecutive identical nodes or consecutive nodes with same location
|
||||
uint64_t duplicate_segments = 0; ///< Segments duplicated (going back and forth)
|
||||
uint64_t from_relations = 0; ///< Area created from multipolygon relation
|
||||
uint64_t from_ways = 0; ///< Area created from way
|
||||
uint64_t inner_rings = 0; ///< Number of inner rings
|
||||
uint64_t inner_with_same_tags = 0; ///< Number of inner ways with same tags as area
|
||||
uint64_t intersections = 0; ///< Number of intersections between segments
|
||||
uint64_t member_ways = 0; ///< Number of ways in the area
|
||||
uint64_t no_tags_on_relation = 0; ///< No tags on relation (old-style multipolygon with tags on outer ways)
|
||||
uint64_t no_way_in_mp_relation = 0; ///< Multipolygon relation with no way members
|
||||
uint64_t nodes = 0; ///< Number of nodes in the area
|
||||
uint64_t open_rings = 0; ///< Number of open rings in the area
|
||||
uint64_t outer_rings = 0; ///< Number of outer rings in the area
|
||||
uint64_t short_ways = 0; ///< Number of ways with less than two nodes
|
||||
uint64_t single_way_in_mp_relation = 0; ///< Multipolygon relation containing a single way
|
||||
uint64_t touching_rings = 0; ///< Rings touching in a node
|
||||
uint64_t ways_in_multiple_rings = 0; ///< Different segments of a way ended up in different rings
|
||||
uint64_t wrong_role = 0; ///< Member has wrong role (not "outer", "inner", or empty)
|
||||
|
||||
area_stats& operator+=(const area_stats& other) noexcept {
|
||||
area_really_complex_case += other.area_really_complex_case;
|
||||
area_simple_case += other.area_simple_case;
|
||||
area_touching_rings_case += other.area_touching_rings_case;
|
||||
duplicate_nodes += other.duplicate_nodes;
|
||||
duplicate_segments += other.duplicate_segments;
|
||||
from_relations += other.from_relations;
|
||||
from_ways += other.from_ways;
|
||||
inner_rings += other.inner_rings;
|
||||
inner_with_same_tags += other.inner_with_same_tags;
|
||||
intersections += other.intersections;
|
||||
member_ways += other.member_ways;
|
||||
no_tags_on_relation += other.no_tags_on_relation;
|
||||
no_way_in_mp_relation += other.no_way_in_mp_relation;
|
||||
nodes += other.nodes;
|
||||
open_rings += other.open_rings;
|
||||
outer_rings += other.outer_rings;
|
||||
short_ways += other.short_ways;
|
||||
single_way_in_mp_relation += other.single_way_in_mp_relation;
|
||||
touching_rings += other.touching_rings;
|
||||
ways_in_multiple_rings += other.ways_in_multiple_rings;
|
||||
wrong_role += other.wrong_role;
|
||||
return *this;
|
||||
}
|
||||
|
||||
}; // struct area_stats
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const area_stats& s) {
|
||||
return out << " area_really_complex_case=" << s.area_really_complex_case
|
||||
<< " area_simple_case=" << s.area_simple_case
|
||||
<< " area_touching_rings_case=" << s.area_touching_rings_case
|
||||
<< " duplicate_nodes=" << s.duplicate_nodes
|
||||
<< " duplicate_segments=" << s.duplicate_segments
|
||||
<< " from_relations=" << s.from_relations
|
||||
<< " from_ways=" << s.from_ways
|
||||
<< " inner_rings=" << s.inner_rings
|
||||
<< " inner_with_same_tags=" << s.inner_with_same_tags
|
||||
<< " intersections=" << s.intersections
|
||||
<< " member_ways=" << s.member_ways
|
||||
<< " no_tags_on_relation=" << s.no_tags_on_relation
|
||||
<< " no_way_in_mp_relation=" << s.no_way_in_mp_relation
|
||||
<< " nodes=" << s.nodes
|
||||
<< " open_rings=" << s.open_rings
|
||||
<< " outer_rings=" << s.outer_rings
|
||||
<< " short_ways=" << s.short_ways
|
||||
<< " single_way_in_mp_relation=" << s.single_way_in_mp_relation
|
||||
<< " touching_rings=" << s.touching_rings
|
||||
<< " ways_in_multiple_rings=" << s.ways_in_multiple_rings
|
||||
<< " wrong_role=" << s.wrong_role;
|
||||
}
|
||||
|
||||
} // namespace area
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_AREA_STATS_HPP
|
@ -46,8 +46,15 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/builder/builder.hpp>
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/changeset.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/relation.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@ -261,6 +268,34 @@ namespace osmium {
|
||||
|
||||
}; // class member_type
|
||||
|
||||
class member_type_string {
|
||||
|
||||
osmium::item_type m_type;
|
||||
osmium::object_id_type m_ref;
|
||||
std::string m_role;
|
||||
|
||||
public:
|
||||
|
||||
member_type_string(osmium::item_type type, osmium::object_id_type ref, std::string&& role) :
|
||||
m_type(type),
|
||||
m_ref(ref),
|
||||
m_role(std::move(role)) {
|
||||
}
|
||||
|
||||
osmium::item_type type() const noexcept {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
osmium::object_id_type ref() const noexcept {
|
||||
return m_ref;
|
||||
}
|
||||
|
||||
const char* role() const noexcept {
|
||||
return m_role.c_str();
|
||||
}
|
||||
|
||||
}; // class member_type_string
|
||||
|
||||
class comment_type {
|
||||
|
||||
osmium::Timestamp m_date;
|
||||
|
@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
@ -101,7 +100,7 @@ namespace osmium {
|
||||
*
|
||||
*/
|
||||
void add_padding(bool self = false) {
|
||||
auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
|
||||
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);
|
||||
if (self) {
|
||||
|
@ -56,7 +56,7 @@ namespace osmium {
|
||||
* Use osmium::builder::add_way_node_list() instead.
|
||||
*/
|
||||
OSMIUM_DEPRECATED inline const osmium::WayNodeList& build_way_node_list(osmium::memory::Buffer& buffer, const std::initializer_list<osmium::NodeRef>& nodes) {
|
||||
size_t pos = buffer.committed();
|
||||
const size_t pos = buffer.committed();
|
||||
{
|
||||
osmium::builder::WayNodeListBuilder wnl_builder(buffer);
|
||||
for (const auto& node_ref : nodes) {
|
||||
@ -72,7 +72,7 @@ namespace osmium {
|
||||
* Use osmium::builder::add_tag_list() instead.
|
||||
*/
|
||||
inline const osmium::TagList& build_tag_list(osmium::memory::Buffer& buffer, const std::initializer_list<std::pair<const char*, const char*>>& tags) {
|
||||
size_t pos = buffer.committed();
|
||||
const size_t pos = buffer.committed();
|
||||
{
|
||||
osmium::builder::TagListBuilder tl_builder(buffer);
|
||||
for (const auto& p : tags) {
|
||||
@ -88,7 +88,7 @@ namespace osmium {
|
||||
* Use osmium::builder::add_tag_list() instead.
|
||||
*/
|
||||
inline const osmium::TagList& build_tag_list_from_map(osmium::memory::Buffer& buffer, const std::map<const char*, const char*>& tags) {
|
||||
size_t pos = buffer.committed();
|
||||
const size_t pos = buffer.committed();
|
||||
{
|
||||
osmium::builder::TagListBuilder tl_builder(buffer);
|
||||
for (const auto& p : tags) {
|
||||
@ -104,7 +104,7 @@ namespace osmium {
|
||||
* Use osmium::builder::add_tag_list() instead.
|
||||
*/
|
||||
inline const osmium::TagList& build_tag_list_from_func(osmium::memory::Buffer& buffer, std::function<void(osmium::builder::TagListBuilder&)> func) {
|
||||
size_t pos = buffer.committed();
|
||||
const size_t pos = buffer.committed();
|
||||
{
|
||||
osmium::builder::TagListBuilder tl_builder(buffer);
|
||||
func(tl_builder);
|
||||
|
@ -34,7 +34,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
@ -44,16 +43,23 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/builder/builder.hpp>
|
||||
#include <osmium/osm.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/tag.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/memory/item.hpp>
|
||||
#include <osmium/osm/area.hpp>
|
||||
#include <osmium/osm/changeset.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class Node;
|
||||
|
||||
namespace memory {
|
||||
class Buffer;
|
||||
} // namespace memory
|
||||
@ -186,9 +192,9 @@ namespace osmium {
|
||||
|
||||
}; // class NodeRefListBuilder
|
||||
|
||||
typedef NodeRefListBuilder<WayNodeList> WayNodeListBuilder;
|
||||
typedef NodeRefListBuilder<OuterRing> OuterRingBuilder;
|
||||
typedef NodeRefListBuilder<InnerRing> InnerRingBuilder;
|
||||
using WayNodeListBuilder = NodeRefListBuilder<WayNodeList>;
|
||||
using OuterRingBuilder = NodeRefListBuilder<OuterRing>;
|
||||
using InnerRingBuilder = NodeRefListBuilder<InnerRing>;
|
||||
|
||||
class RelationMemberListBuilder : public ObjectBuilder<RelationMemberList> {
|
||||
|
||||
@ -353,8 +359,8 @@ namespace osmium {
|
||||
|
||||
}; // class OSMObjectBuilder
|
||||
|
||||
typedef OSMObjectBuilder<osmium::Node> NodeBuilder;
|
||||
typedef OSMObjectBuilder<osmium::Relation> RelationBuilder;
|
||||
using NodeBuilder = OSMObjectBuilder<osmium::Node>;
|
||||
using RelationBuilder = OSMObjectBuilder<osmium::Relation>;
|
||||
|
||||
class WayBuilder : public OSMObjectBuilder<osmium::Way> {
|
||||
|
||||
@ -398,7 +404,7 @@ namespace osmium {
|
||||
|
||||
}; // class AreaBuilder
|
||||
|
||||
typedef ObjectBuilder<osmium::Changeset> ChangesetBuilder;
|
||||
using ChangesetBuilder = ObjectBuilder<osmium::Changeset>;
|
||||
|
||||
} // namespace builder
|
||||
|
||||
|
@ -34,8 +34,10 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/osm/diff_object.hpp>
|
||||
|
||||
@ -49,7 +51,7 @@ namespace osmium {
|
||||
* underlying OSMObjects.
|
||||
*/
|
||||
template <typename TBasicIterator>
|
||||
class DiffIterator : public std::iterator<std::input_iterator_tag, const osmium::DiffObject> {
|
||||
class DiffIterator {
|
||||
|
||||
static_assert(std::is_base_of<osmium::OSMObject, typename TBasicIterator::value_type>::value, "TBasicIterator::value_type must derive from osmium::OSMObject");
|
||||
|
||||
@ -76,6 +78,12 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = const osmium::DiffObject;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
DiffIterator(TBasicIterator begin, TBasicIterator end) :
|
||||
m_prev(begin),
|
||||
m_curr(begin),
|
||||
|
@ -36,11 +36,16 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/fwd.hpp>
|
||||
#include <osmium/handler.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class Node;
|
||||
class Way;
|
||||
class Relation;
|
||||
class Area;
|
||||
class Changeset;
|
||||
|
||||
namespace handler {
|
||||
|
||||
namespace detail {
|
||||
@ -143,7 +148,7 @@ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) ->
|
||||
|
||||
class DynamicHandler : public osmium::handler::Handler {
|
||||
|
||||
typedef std::unique_ptr<osmium::handler::detail::HandlerWrapperBase> impl_ptr;
|
||||
using impl_ptr = std::unique_ptr<osmium::handler::detail::HandlerWrapperBase>;
|
||||
impl_ptr m_impl;
|
||||
|
||||
public:
|
||||
|
@ -34,11 +34,12 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <osmium/area/assembler.hpp>
|
||||
#include <osmium/area/multipolygon_collector.hpp>
|
||||
#include <osmium/handler/node_locations_for_ways.hpp>
|
||||
#include <osmium/handler/node_locations_for_ways.hpp> // IWYU pragma: keep
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/io/reader.hpp>
|
||||
|
@ -46,6 +46,8 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
#include <osmium/osm/node_ref_list.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
|
||||
namespace osmium {
|
||||
@ -148,7 +150,7 @@ namespace osmium {
|
||||
/**
|
||||
* Add all points of an outer or inner ring to a multipolygon.
|
||||
*/
|
||||
void add_points(const osmium::OuterRing& nodes) {
|
||||
void add_points(const osmium::NodeRefList& nodes) {
|
||||
osmium::Location last_location;
|
||||
for (const osmium::NodeRef& node_ref : nodes) {
|
||||
if (last_location != node_ref.location()) {
|
||||
@ -169,7 +171,7 @@ namespace osmium {
|
||||
template <typename... TArgs>
|
||||
explicit GeometryFactory<TGeomImpl, TProjection>(TArgs&&... args) :
|
||||
m_projection(),
|
||||
m_impl(std::forward<TArgs>(args)...) {
|
||||
m_impl(m_projection.epsg(), std::forward<TArgs>(args)...) {
|
||||
}
|
||||
|
||||
/**
|
||||
@ -179,15 +181,16 @@ namespace osmium {
|
||||
template <typename... TArgs>
|
||||
explicit GeometryFactory<TGeomImpl, TProjection>(TProjection&& projection, TArgs&&... args) :
|
||||
m_projection(std::move(projection)),
|
||||
m_impl(std::forward<TArgs>(args)...) {
|
||||
m_impl(m_projection.epsg(), std::forward<TArgs>(args)...) {
|
||||
}
|
||||
|
||||
typedef TProjection projection_type;
|
||||
typedef typename TGeomImpl::point_type point_type;
|
||||
typedef typename TGeomImpl::linestring_type linestring_type;
|
||||
typedef typename TGeomImpl::polygon_type polygon_type;
|
||||
typedef typename TGeomImpl::multipolygon_type multipolygon_type;
|
||||
typedef typename TGeomImpl::ring_type ring_type;
|
||||
using projection_type = TProjection;
|
||||
|
||||
using point_type = typename TGeomImpl::point_type;
|
||||
using linestring_type = typename TGeomImpl::linestring_type;
|
||||
using polygon_type = typename TGeomImpl::polygon_type;
|
||||
using multipolygon_type = typename TGeomImpl::multipolygon_type;
|
||||
using ring_type = typename TGeomImpl::ring_type;
|
||||
|
||||
int epsg() const {
|
||||
return m_projection.epsg();
|
||||
@ -280,13 +283,13 @@ namespace osmium {
|
||||
}
|
||||
|
||||
if (num_points < 2) {
|
||||
throw osmium::geometry_error("need at least two points for linestring");
|
||||
throw osmium::geometry_error{"need at least two points for linestring"};
|
||||
}
|
||||
|
||||
return linestring_finish(num_points);
|
||||
}
|
||||
|
||||
linestring_type create_linestring(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir=direction::forward) {
|
||||
linestring_type create_linestring(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir = direction::forward) {
|
||||
try {
|
||||
return create_linestring(way.nodes(), un, dir);
|
||||
} catch (osmium::geometry_error& e) {
|
||||
@ -354,13 +357,13 @@ namespace osmium {
|
||||
}
|
||||
|
||||
if (num_points < 4) {
|
||||
throw osmium::geometry_error("need at least four points for polygon");
|
||||
throw osmium::geometry_error{"need at least four points for polygon"};
|
||||
}
|
||||
|
||||
return polygon_finish(num_points);
|
||||
}
|
||||
|
||||
polygon_type create_polygon(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir=direction::forward) {
|
||||
polygon_type create_polygon(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir = direction::forward) {
|
||||
try {
|
||||
return create_polygon(way.nodes(), un, dir);
|
||||
} catch (osmium::geometry_error& e) {
|
||||
@ -378,8 +381,8 @@ namespace osmium {
|
||||
m_impl.multipolygon_start();
|
||||
|
||||
for (auto it = area.cbegin(); it != area.cend(); ++it) {
|
||||
const osmium::OuterRing& ring = static_cast<const osmium::OuterRing&>(*it);
|
||||
if (it->type() == osmium::item_type::outer_ring) {
|
||||
auto& ring = static_cast<const osmium::OuterRing&>(*it);
|
||||
if (num_polygons > 0) {
|
||||
m_impl.multipolygon_polygon_finish();
|
||||
}
|
||||
@ -390,6 +393,7 @@ namespace osmium {
|
||||
++num_rings;
|
||||
++num_polygons;
|
||||
} else if (it->type() == osmium::item_type::inner_ring) {
|
||||
auto& ring = static_cast<const osmium::InnerRing&>(*it);
|
||||
m_impl.multipolygon_inner_ring_start();
|
||||
add_points(ring);
|
||||
m_impl.multipolygon_inner_ring_finish();
|
||||
@ -399,7 +403,7 @@ namespace osmium {
|
||||
|
||||
// if there are no rings, this area is invalid
|
||||
if (num_rings == 0) {
|
||||
throw osmium::geometry_error("area contains no rings");
|
||||
throw osmium::geometry_error{"invalid area"};
|
||||
}
|
||||
|
||||
m_impl.multipolygon_polygon_finish();
|
||||
|
@ -34,6 +34,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@ -53,13 +54,13 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::string point_type;
|
||||
typedef std::string linestring_type;
|
||||
typedef std::string polygon_type;
|
||||
typedef std::string multipolygon_type;
|
||||
typedef std::string ring_type;
|
||||
using point_type = std::string;
|
||||
using linestring_type = std::string;
|
||||
using polygon_type = std::string;
|
||||
using multipolygon_type = std::string;
|
||||
using ring_type = std::string;
|
||||
|
||||
GeoJSONFactoryImpl(int precision = 7) :
|
||||
GeoJSONFactoryImpl(int /* srid */, int precision = 7) :
|
||||
m_precision(precision) {
|
||||
}
|
||||
|
||||
|
@ -42,9 +42,14 @@ DEALINGS IN THE SOFTWARE.
|
||||
* @attention If you include this file, you'll need to link with `libgeos`.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <geos/geom/Coordinate.h>
|
||||
#include <geos/geom/CoordinateSequence.h>
|
||||
@ -59,11 +64,13 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <osmium/geom/factory.hpp>
|
||||
#include <osmium/geom/coordinates.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
|
||||
// MSVC doesn't support throw_with_nested yet
|
||||
#ifdef _MSC_VER
|
||||
# define THROW throw
|
||||
#else
|
||||
# include <exception>
|
||||
# define THROW std::throw_with_nested
|
||||
#endif
|
||||
|
||||
@ -71,8 +78,8 @@ namespace osmium {
|
||||
|
||||
struct geos_geometry_error : public geometry_error {
|
||||
|
||||
geos_geometry_error(const char* message) :
|
||||
geometry_error(std::string("geometry creation failed in GEOS library: ") + message) {
|
||||
explicit geos_geometry_error(const char* message) :
|
||||
geometry_error(std::string{"geometry creation failed in GEOS library: "} + message) {
|
||||
}
|
||||
|
||||
}; // struct geos_geometry_error
|
||||
@ -93,19 +100,29 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::unique_ptr<geos::geom::Point> point_type;
|
||||
typedef std::unique_ptr<geos::geom::LineString> linestring_type;
|
||||
typedef std::unique_ptr<geos::geom::Polygon> polygon_type;
|
||||
typedef std::unique_ptr<geos::geom::MultiPolygon> multipolygon_type;
|
||||
typedef std::unique_ptr<geos::geom::LinearRing> ring_type;
|
||||
using point_type = std::unique_ptr<geos::geom::Point>;
|
||||
using linestring_type = std::unique_ptr<geos::geom::LineString>;
|
||||
using polygon_type = std::unique_ptr<geos::geom::Polygon>;
|
||||
using multipolygon_type = std::unique_ptr<geos::geom::MultiPolygon>;
|
||||
using ring_type = std::unique_ptr<geos::geom::LinearRing>;
|
||||
|
||||
explicit GEOSFactoryImpl(geos::geom::GeometryFactory& geos_factory) :
|
||||
explicit GEOSFactoryImpl(int /* srid */, geos::geom::GeometryFactory& geos_factory) :
|
||||
m_precision_model(nullptr),
|
||||
m_our_geos_factory(nullptr),
|
||||
m_geos_factory(&geos_factory) {
|
||||
}
|
||||
|
||||
explicit GEOSFactoryImpl(int srid = -1) :
|
||||
/**
|
||||
* @deprecated Do not set SRID explicitly. It will be set to the
|
||||
* correct value automatically.
|
||||
*/
|
||||
OSMIUM_DEPRECATED explicit GEOSFactoryImpl(int /* srid */, int srid) :
|
||||
m_precision_model(new geos::geom::PrecisionModel),
|
||||
m_our_geos_factory(new geos::geom::GeometryFactory(m_precision_model.get(), srid)),
|
||||
m_geos_factory(m_our_geos_factory.get()) {
|
||||
}
|
||||
|
||||
explicit GEOSFactoryImpl(int srid) :
|
||||
m_precision_model(new geos::geom::PrecisionModel),
|
||||
m_our_geos_factory(new geos::geom::GeometryFactory(m_precision_model.get(), srid)),
|
||||
m_geos_factory(m_our_geos_factory.get()) {
|
||||
@ -116,7 +133,7 @@ namespace osmium {
|
||||
point_type make_point(const osmium::geom::Coordinates& xy) const {
|
||||
try {
|
||||
return point_type(m_geos_factory->createPoint(geos::geom::Coordinate(xy.x, xy.y)));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@ -126,7 +143,7 @@ namespace osmium {
|
||||
void linestring_start() {
|
||||
try {
|
||||
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@ -134,7 +151,7 @@ namespace osmium {
|
||||
void linestring_add_location(const osmium::geom::Coordinates& xy) {
|
||||
try {
|
||||
m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@ -142,7 +159,7 @@ namespace osmium {
|
||||
linestring_type linestring_finish(size_t /* num_points */) {
|
||||
try {
|
||||
return linestring_type(m_geos_factory->createLineString(m_coordinate_sequence.release()));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@ -166,7 +183,7 @@ namespace osmium {
|
||||
});
|
||||
m_polygons.emplace_back(m_geos_factory->createPolygon(m_rings[0].release(), inner_rings));
|
||||
m_rings.clear();
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@ -174,7 +191,7 @@ namespace osmium {
|
||||
void multipolygon_outer_ring_start() {
|
||||
try {
|
||||
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@ -182,7 +199,7 @@ namespace osmium {
|
||||
void multipolygon_outer_ring_finish() {
|
||||
try {
|
||||
m_rings.emplace_back(m_geos_factory->createLinearRing(m_coordinate_sequence.release()));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@ -190,7 +207,7 @@ namespace osmium {
|
||||
void multipolygon_inner_ring_start() {
|
||||
try {
|
||||
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@ -198,7 +215,7 @@ namespace osmium {
|
||||
void multipolygon_inner_ring_finish() {
|
||||
try {
|
||||
m_rings.emplace_back(m_geos_factory->createLinearRing(m_coordinate_sequence.release()));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@ -206,7 +223,7 @@ namespace osmium {
|
||||
void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
|
||||
try {
|
||||
m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@ -219,7 +236,7 @@ namespace osmium {
|
||||
});
|
||||
m_polygons.clear();
|
||||
return multipolygon_type(m_geos_factory->createMultiPolygon(polygons));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ namespace osmium {
|
||||
namespace haversine {
|
||||
|
||||
/// @brief Earth's quadratic mean radius for WGS84
|
||||
constexpr double EARTH_RADIUS_IN_METERS = 6372797.560856;
|
||||
constexpr const double EARTH_RADIUS_IN_METERS = 6372797.560856;
|
||||
|
||||
/**
|
||||
* Calculate distance in meters between two sets of coordinates.
|
||||
|
@ -62,33 +62,34 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::unique_ptr<OGRPoint> point_type;
|
||||
typedef std::unique_ptr<OGRLineString> linestring_type;
|
||||
typedef std::unique_ptr<OGRPolygon> polygon_type;
|
||||
typedef std::unique_ptr<OGRMultiPolygon> multipolygon_type;
|
||||
typedef std::unique_ptr<OGRLinearRing> ring_type;
|
||||
using point_type = std::unique_ptr<OGRPoint>;
|
||||
using linestring_type = std::unique_ptr<OGRLineString>;
|
||||
using polygon_type = std::unique_ptr<OGRPolygon>;
|
||||
using multipolygon_type = std::unique_ptr<OGRMultiPolygon>;
|
||||
using ring_type = std::unique_ptr<OGRLinearRing>;
|
||||
|
||||
private:
|
||||
|
||||
linestring_type m_linestring;
|
||||
multipolygon_type m_multipolygon;
|
||||
polygon_type m_polygon;
|
||||
ring_type m_ring;
|
||||
linestring_type m_linestring{nullptr};
|
||||
multipolygon_type m_multipolygon{nullptr};
|
||||
polygon_type m_polygon{nullptr};
|
||||
ring_type m_ring{nullptr};
|
||||
|
||||
public:
|
||||
|
||||
OGRFactoryImpl() = default;
|
||||
explicit OGRFactoryImpl(int /* srid */) {
|
||||
}
|
||||
|
||||
/* Point */
|
||||
|
||||
point_type make_point(const osmium::geom::Coordinates& xy) const {
|
||||
return point_type(new OGRPoint(xy.x, xy.y));
|
||||
return point_type{new OGRPoint{xy.x, xy.y}};
|
||||
}
|
||||
|
||||
/* LineString */
|
||||
|
||||
void linestring_start() {
|
||||
m_linestring = std::unique_ptr<OGRLineString>(new OGRLineString());
|
||||
m_linestring.reset(new OGRLineString{});
|
||||
}
|
||||
|
||||
void linestring_add_location(const osmium::geom::Coordinates& xy) {
|
||||
@ -97,13 +98,14 @@ namespace osmium {
|
||||
}
|
||||
|
||||
linestring_type linestring_finish(size_t /* num_points */) {
|
||||
assert(!!m_linestring);
|
||||
return std::move(m_linestring);
|
||||
}
|
||||
|
||||
/* Polygon */
|
||||
|
||||
void polygon_start() {
|
||||
m_ring = std::unique_ptr<OGRLinearRing>(new OGRLinearRing());
|
||||
m_ring.reset(new OGRLinearRing{});
|
||||
}
|
||||
|
||||
void polygon_add_location(const osmium::geom::Coordinates& xy) {
|
||||
@ -112,7 +114,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
polygon_type polygon_finish(size_t /* num_points */) {
|
||||
std::unique_ptr<OGRPolygon> polygon = std::unique_ptr<OGRPolygon>(new OGRPolygon());
|
||||
auto polygon = std::unique_ptr<OGRPolygon>{new OGRPolygon{}};
|
||||
polygon->addRingDirectly(m_ring.release());
|
||||
return polygon;
|
||||
}
|
||||
@ -120,11 +122,11 @@ namespace osmium {
|
||||
/* MultiPolygon */
|
||||
|
||||
void multipolygon_start() {
|
||||
m_multipolygon.reset(new OGRMultiPolygon());
|
||||
m_multipolygon.reset(new OGRMultiPolygon{});
|
||||
}
|
||||
|
||||
void multipolygon_polygon_start() {
|
||||
m_polygon.reset(new OGRPolygon());
|
||||
m_polygon.reset(new OGRPolygon{});
|
||||
}
|
||||
|
||||
void multipolygon_polygon_finish() {
|
||||
@ -134,7 +136,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void multipolygon_outer_ring_start() {
|
||||
m_ring.reset(new OGRLinearRing());
|
||||
m_ring.reset(new OGRLinearRing{});
|
||||
}
|
||||
|
||||
void multipolygon_outer_ring_finish() {
|
||||
@ -144,7 +146,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void multipolygon_inner_ring_start() {
|
||||
m_ring.reset(new OGRLinearRing());
|
||||
m_ring.reset(new OGRLinearRing{});
|
||||
}
|
||||
|
||||
void multipolygon_inner_ring_finish() {
|
||||
|
@ -70,15 +70,19 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
CRS(const std::string& crs) :
|
||||
explicit CRS(const std::string& crs) :
|
||||
m_crs(pj_init_plus(crs.c_str()), ProjCRSDeleter()) {
|
||||
if (!m_crs) {
|
||||
throw osmium::projection_error(std::string("creation of CRS failed: ") + pj_strerrno(*pj_get_errno_ref()));
|
||||
throw osmium::projection_error(std::string{"creation of CRS failed: "} + pj_strerrno(*pj_get_errno_ref()));
|
||||
}
|
||||
}
|
||||
|
||||
CRS(int epsg) :
|
||||
CRS(std::string("+init=epsg:") + std::to_string(epsg)) {
|
||||
explicit CRS(const char* crs) :
|
||||
CRS(std::string{crs}) {
|
||||
}
|
||||
|
||||
explicit CRS(int epsg) :
|
||||
CRS(std::string{"+init=epsg:"} + std::to_string(epsg)) {
|
||||
}
|
||||
|
||||
/**
|
||||
@ -127,13 +131,19 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
Projection(const std::string& proj_string) :
|
||||
explicit Projection(const std::string& proj_string) :
|
||||
m_epsg(-1),
|
||||
m_proj_string(proj_string),
|
||||
m_crs_user(proj_string) {
|
||||
}
|
||||
|
||||
Projection(int epsg) :
|
||||
explicit Projection(const char* proj_string) :
|
||||
m_epsg(-1),
|
||||
m_proj_string(proj_string),
|
||||
m_crs_user(proj_string) {
|
||||
}
|
||||
|
||||
explicit Projection(int epsg) :
|
||||
m_epsg(epsg),
|
||||
m_proj_string(std::string("+init=epsg:") + std::to_string(epsg)),
|
||||
m_crs_user(epsg) {
|
||||
|
@ -33,6 +33,8 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <osmium/geom/coordinates.hpp>
|
||||
#include <osmium/geom/factory.hpp>
|
||||
|
||||
@ -53,13 +55,13 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef void point_type;
|
||||
typedef void linestring_type;
|
||||
typedef void polygon_type;
|
||||
typedef void multipolygon_type;
|
||||
typedef void ring_type;
|
||||
using point_type = void;
|
||||
using linestring_type = void;
|
||||
using polygon_type = void;
|
||||
using multipolygon_type = void;
|
||||
using ring_type = void;
|
||||
|
||||
RapidGeoJSONFactoryImpl(TWriter& writer) :
|
||||
RapidGeoJSONFactoryImpl(int /* srid */, TWriter& writer) :
|
||||
m_writer(&writer) {
|
||||
}
|
||||
|
||||
|
@ -33,9 +33,12 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include <osmium/geom/coordinates.hpp>
|
||||
#include <osmium/geom/mercator_projection.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@ -57,24 +60,64 @@ namespace osmium {
|
||||
*/
|
||||
struct Tile {
|
||||
|
||||
/// x coordinate
|
||||
uint32_t x;
|
||||
|
||||
/// y coordinate
|
||||
uint32_t y;
|
||||
|
||||
/// Zoom level
|
||||
uint32_t z;
|
||||
|
||||
/**
|
||||
* Create a tile with the given zoom level and x any y tile
|
||||
* coordinates.
|
||||
*
|
||||
* The values are not checked for validity.
|
||||
*
|
||||
* @pre @code zoom <= 30 && x < 2^zoom && y < 2^zoom @endcode
|
||||
*/
|
||||
explicit Tile(uint32_t zoom, uint32_t tx, uint32_t ty) noexcept : x(tx), y(ty), z(zoom) {
|
||||
assert(zoom <= 30u);
|
||||
assert(x < (1u << zoom));
|
||||
assert(y < (1u << zoom));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tile with the given zoom level that contains the given
|
||||
* location.
|
||||
*
|
||||
* The values are not checked for validity.
|
||||
*
|
||||
* @pre @code location.valid() && zoom <= 30 @endcode
|
||||
*/
|
||||
explicit Tile(uint32_t zoom, const osmium::Location& location) :
|
||||
z(zoom) {
|
||||
osmium::geom::Coordinates c = lonlat_to_mercator(location);
|
||||
assert(zoom <= 30u);
|
||||
assert(location.valid());
|
||||
const osmium::geom::Coordinates c = lonlat_to_mercator(location);
|
||||
const int32_t n = 1 << zoom;
|
||||
const double scale = detail::max_coordinate_epsg3857 * 2 / n;
|
||||
x = uint32_t(detail::restrict_to_range<int32_t>(int32_t((c.x + detail::max_coordinate_epsg3857) / scale), 0, n-1));
|
||||
y = uint32_t(detail::restrict_to_range<int32_t>(int32_t((detail::max_coordinate_epsg3857 - c.y) / scale), 0, n-1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this tile is valid. For a tile to be valid the
|
||||
* zoom level must be between 0 and 30 and the coordinates must
|
||||
* each be between 0 and 2^zoom-1.
|
||||
*/
|
||||
bool valid() const noexcept {
|
||||
if (z > 30) {
|
||||
return false;
|
||||
}
|
||||
const uint32_t max = 1 << z;
|
||||
return x < max && y < max;
|
||||
}
|
||||
|
||||
}; // 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;
|
||||
}
|
||||
|
@ -44,11 +44,11 @@ namespace osmium {
|
||||
*/
|
||||
struct projection_error : public std::runtime_error {
|
||||
|
||||
projection_error(const std::string& what) :
|
||||
explicit projection_error(const std::string& what) :
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
projection_error(const char* what) :
|
||||
explicit projection_error(const char* what) :
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
@ -60,14 +61,13 @@ namespace osmium {
|
||||
|
||||
template <typename T>
|
||||
inline void str_push(std::string& str, T data) {
|
||||
size_t size = str.size();
|
||||
str.resize(size + sizeof(T));
|
||||
std::copy_n(reinterpret_cast<char*>(&data), sizeof(T), &str[size]);
|
||||
str.append(reinterpret_cast<const char*>(&data), sizeof(T));
|
||||
}
|
||||
|
||||
inline std::string convert_to_hex(const std::string& str) {
|
||||
static const char* lookup_hex = "0123456789ABCDEF";
|
||||
std::string out;
|
||||
out.reserve(str.size() * 2);
|
||||
|
||||
for (char c : str) {
|
||||
out += lookup_hex[(c >> 4) & 0xf];
|
||||
@ -79,9 +79,6 @@ namespace osmium {
|
||||
|
||||
class WKBFactoryImpl {
|
||||
|
||||
/// OSM data always uses SRID 4326 (WGS84).
|
||||
static constexpr uint32_t srid = 4326;
|
||||
|
||||
/**
|
||||
* Type of WKB geometry.
|
||||
* These definitions are from
|
||||
@ -112,6 +109,7 @@ namespace osmium {
|
||||
|
||||
std::string m_data;
|
||||
uint32_t m_points {0};
|
||||
int m_srid;
|
||||
wkb_type m_wkb_type;
|
||||
out_type m_out_type;
|
||||
|
||||
@ -130,11 +128,11 @@ namespace osmium {
|
||||
#endif
|
||||
if (m_wkb_type == wkb_type::ewkb) {
|
||||
str_push(str, type | wkbSRID);
|
||||
str_push(str, srid);
|
||||
str_push(str, m_srid);
|
||||
} else {
|
||||
str_push(str, type);
|
||||
}
|
||||
size_t offset = str.size();
|
||||
const size_t offset = str.size();
|
||||
if (add_length) {
|
||||
str_push(str, static_cast<uint32_t>(0));
|
||||
}
|
||||
@ -142,18 +140,20 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void set_size(const size_t offset, const size_t size) {
|
||||
*reinterpret_cast<uint32_t*>(&m_data[offset]) = static_cast_with_assert<uint32_t>(size);
|
||||
uint32_t s = static_cast_with_assert<uint32_t>(size);
|
||||
std::copy_n(reinterpret_cast<char*>(&s), sizeof(uint32_t), &m_data[offset]);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
typedef std::string point_type;
|
||||
typedef std::string linestring_type;
|
||||
typedef std::string polygon_type;
|
||||
typedef std::string multipolygon_type;
|
||||
typedef std::string ring_type;
|
||||
using point_type = std::string;
|
||||
using linestring_type = std::string;
|
||||
using polygon_type = std::string;
|
||||
using multipolygon_type = std::string;
|
||||
using ring_type = std::string;
|
||||
|
||||
explicit WKBFactoryImpl(wkb_type wtype = wkb_type::wkb, out_type otype = out_type::binary) :
|
||||
explicit WKBFactoryImpl(int srid, wkb_type wtype = wkb_type::wkb, out_type otype = out_type::binary) :
|
||||
m_srid(srid),
|
||||
m_wkb_type(wtype),
|
||||
m_out_type(otype) {
|
||||
}
|
||||
|
@ -45,29 +45,44 @@ namespace osmium {
|
||||
|
||||
namespace geom {
|
||||
|
||||
enum class wkt_type : bool {
|
||||
wkt = false,
|
||||
ewkt = true
|
||||
}; // enum class wkt_type
|
||||
|
||||
namespace detail {
|
||||
|
||||
class WKTFactoryImpl {
|
||||
|
||||
std::string m_srid_prefix;
|
||||
std::string m_str;
|
||||
int m_precision;
|
||||
wkt_type m_wkt_type;
|
||||
|
||||
public:
|
||||
|
||||
typedef std::string point_type;
|
||||
typedef std::string linestring_type;
|
||||
typedef std::string polygon_type;
|
||||
typedef std::string multipolygon_type;
|
||||
typedef std::string ring_type;
|
||||
using point_type = std::string;
|
||||
using linestring_type = std::string;
|
||||
using polygon_type = std::string;
|
||||
using multipolygon_type = std::string;
|
||||
using ring_type = std::string;
|
||||
|
||||
WKTFactoryImpl(int precision = 7) :
|
||||
m_precision(precision) {
|
||||
WKTFactoryImpl(int srid, int precision = 7, wkt_type wtype = wkt_type::wkt) :
|
||||
m_srid_prefix(),
|
||||
m_precision(precision),
|
||||
m_wkt_type(wtype) {
|
||||
if (m_wkt_type == wkt_type::ewkt) {
|
||||
m_srid_prefix = "SRID=";
|
||||
m_srid_prefix += std::to_string(srid);
|
||||
m_srid_prefix += ';';
|
||||
}
|
||||
}
|
||||
|
||||
/* Point */
|
||||
|
||||
point_type make_point(const osmium::geom::Coordinates& xy) const {
|
||||
std::string str {"POINT"};
|
||||
std::string str {m_srid_prefix};
|
||||
str += "POINT";
|
||||
xy.append_to_string(str, '(', ' ', ')', m_precision);
|
||||
return str;
|
||||
}
|
||||
@ -75,7 +90,8 @@ namespace osmium {
|
||||
/* LineString */
|
||||
|
||||
void linestring_start() {
|
||||
m_str = "LINESTRING(";
|
||||
m_str = m_srid_prefix;
|
||||
m_str += "LINESTRING(";
|
||||
}
|
||||
|
||||
void linestring_add_location(const osmium::geom::Coordinates& xy) {
|
||||
@ -97,7 +113,8 @@ namespace osmium {
|
||||
/* MultiPolygon */
|
||||
|
||||
void multipolygon_start() {
|
||||
m_str = "MULTIPOLYGON(";
|
||||
m_str = m_srid_prefix;
|
||||
m_str += "MULTIPOLYGON(";
|
||||
}
|
||||
|
||||
void multipolygon_polygon_start() {
|
||||
|
56
third_party/libosmium/include/osmium/handler.hpp
vendored
56
third_party/libosmium/include/osmium/handler.hpp
vendored
@ -33,56 +33,82 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osmium/fwd.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class Area;
|
||||
class Changeset;
|
||||
class ChangesetDiscussion;
|
||||
class InnerRing;
|
||||
class Node;
|
||||
class OSMObject;
|
||||
class OuterRing;
|
||||
class Relation;
|
||||
class RelationMemberList;
|
||||
class TagList;
|
||||
class Way;
|
||||
class WayNodeList;
|
||||
|
||||
/**
|
||||
* @brief Osmium handlers provide callbacks for OSM objects
|
||||
*/
|
||||
namespace handler {
|
||||
|
||||
/**
|
||||
* Handler base class. Never used directly. Derive your own class from
|
||||
* this class and "overwrite" the functions. Your functions must be
|
||||
* named the same, but don't have to be const or noexcept or take
|
||||
* their argument as const.
|
||||
*
|
||||
* Usually you will overwrite the node(), way(), and relation()
|
||||
* functions. If your program supports multipolygons, also the area()
|
||||
* function. You can also use the osm_object() function which is
|
||||
* called for all OSM objects (nodes, ways, relations, and areas)
|
||||
* right before each of their specific callbacks is called.
|
||||
*
|
||||
* If you are working with changesets, implement the changeset()
|
||||
* function.
|
||||
*/
|
||||
class Handler {
|
||||
|
||||
public:
|
||||
|
||||
void osm_object(const osmium::OSMObject&) const {
|
||||
void osm_object(const osmium::OSMObject&) const noexcept {
|
||||
}
|
||||
|
||||
void node(const osmium::Node&) const {
|
||||
void node(const osmium::Node&) const noexcept {
|
||||
}
|
||||
|
||||
void way(const osmium::Way&) const {
|
||||
void way(const osmium::Way&) const noexcept {
|
||||
}
|
||||
|
||||
void relation(const osmium::Relation&) const {
|
||||
void relation(const osmium::Relation&) const noexcept {
|
||||
}
|
||||
|
||||
void area(const osmium::Area&) const {
|
||||
void area(const osmium::Area&) const noexcept {
|
||||
}
|
||||
|
||||
void changeset(const osmium::Changeset&) const {
|
||||
void changeset(const osmium::Changeset&) const noexcept {
|
||||
}
|
||||
|
||||
void tag_list(const osmium::TagList&) const {
|
||||
void tag_list(const osmium::TagList&) const noexcept {
|
||||
}
|
||||
|
||||
void way_node_list(const osmium::WayNodeList&) const {
|
||||
void way_node_list(const osmium::WayNodeList&) const noexcept {
|
||||
}
|
||||
|
||||
void relation_member_list(const osmium::RelationMemberList&) const {
|
||||
void relation_member_list(const osmium::RelationMemberList&) const noexcept {
|
||||
}
|
||||
|
||||
void outer_ring(const osmium::OuterRing&) const {
|
||||
void outer_ring(const osmium::OuterRing&) const noexcept {
|
||||
}
|
||||
|
||||
void inner_ring(const osmium::InnerRing&) const {
|
||||
void inner_ring(const osmium::InnerRing&) const noexcept {
|
||||
}
|
||||
|
||||
void changeset_discussion(const osmium::ChangesetDiscussion&) const {
|
||||
void changeset_discussion(const osmium::ChangesetDiscussion&) const noexcept {
|
||||
}
|
||||
|
||||
void flush() const {
|
||||
void flush() const noexcept {
|
||||
}
|
||||
|
||||
}; // class Handler
|
||||
|
@ -67,7 +67,7 @@ namespace osmium {
|
||||
template <typename... THandler>
|
||||
class ChainHandler : public osmium::handler::Handler {
|
||||
|
||||
typedef std::tuple<THandler&...> handlers_type;
|
||||
using handlers_type = std::tuple<THandler&...>;
|
||||
handlers_type m_handlers;
|
||||
|
||||
template <int N, int SIZE, typename THandlers>
|
||||
|
@ -51,11 +51,11 @@ namespace osmium {
|
||||
*/
|
||||
struct out_of_order_error : public std::runtime_error {
|
||||
|
||||
out_of_order_error(const std::string& what) :
|
||||
explicit out_of_order_error(const std::string& what) :
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
out_of_order_error(const char* what) :
|
||||
explicit out_of_order_error(const char* what) :
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ namespace osmium {
|
||||
*/
|
||||
class DiskStore : public osmium::handler::Handler {
|
||||
|
||||
typedef osmium::index::map::Map<unsigned_object_id_type, size_t> offset_index_type;
|
||||
using offset_index_type = osmium::index::map::Map<unsigned_object_id_type, size_t>;
|
||||
|
||||
size_t m_offset = 0;
|
||||
int m_data_fd;
|
||||
|
@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include <osmium/handler.hpp>
|
||||
@ -50,7 +51,7 @@ namespace osmium {
|
||||
|
||||
namespace handler {
|
||||
|
||||
typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> dummy_type;
|
||||
using dummy_type = osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location>;
|
||||
|
||||
/**
|
||||
* Handler to retrieve locations from nodes and add them to ways.
|
||||
@ -69,8 +70,8 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef TStoragePosIDs index_pos_type;
|
||||
typedef TStorageNegIDs index_neg_type;
|
||||
using index_pos_type = TStoragePosIDs;
|
||||
using index_neg_type = TStorageNegIDs;
|
||||
|
||||
private:
|
||||
|
||||
@ -80,6 +81,8 @@ namespace osmium {
|
||||
/// Object that handles the actual storage of the node locations (with negative IDs).
|
||||
TStorageNegIDs& m_storage_neg;
|
||||
|
||||
osmium::unsigned_object_id_type m_last_id{0};
|
||||
|
||||
bool m_ignore_errors {false};
|
||||
|
||||
bool m_must_sort {false};
|
||||
@ -115,7 +118,11 @@ namespace osmium {
|
||||
* Store the location of the node in the storage.
|
||||
*/
|
||||
void node(const osmium::Node& node) {
|
||||
if (node.positive_id() < m_last_id) {
|
||||
m_must_sort = true;
|
||||
}
|
||||
m_last_id = node.positive_id();
|
||||
|
||||
const osmium::object_id_type id = node.id();
|
||||
if (id >= 0) {
|
||||
m_storage_pos.set(static_cast<osmium::unsigned_object_id_type>( id), node.location());
|
||||
@ -144,6 +151,7 @@ namespace osmium {
|
||||
m_storage_pos.sort();
|
||||
m_storage_neg.sort();
|
||||
m_must_sort = false;
|
||||
m_last_id = std::numeric_limits<osmium::unsigned_object_id_type>::max();
|
||||
}
|
||||
bool error = false;
|
||||
for (auto& node_ref : way.nodes()) {
|
||||
@ -152,7 +160,7 @@ namespace osmium {
|
||||
if (!node_ref.location()) {
|
||||
error = true;
|
||||
}
|
||||
} catch (osmium::not_found&) {
|
||||
} catch (const osmium::not_found&) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ namespace osmium {
|
||||
*/
|
||||
class ObjectRelations : public osmium::handler::Handler {
|
||||
|
||||
typedef osmium::index::multimap::Multimap<unsigned_object_id_type, unsigned_object_id_type> index_type;
|
||||
using index_type = osmium::index::multimap::Multimap<unsigned_object_id_type, unsigned_object_id_type>;
|
||||
|
||||
index_type& m_index_n2w;
|
||||
index_type& m_index_n2r;
|
||||
|
@ -54,9 +54,9 @@ namespace osmium {
|
||||
}
|
||||
assert(config.size() > 1);
|
||||
const std::string& filename = config[1];
|
||||
int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644);
|
||||
const int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644);
|
||||
if (fd == -1) {
|
||||
throw std::runtime_error(std::string("can't open file '") + filename + "': " + strerror(errno));
|
||||
throw std::runtime_error(std::string("can't open file '") + filename + "': " + std::strerror(errno));
|
||||
}
|
||||
return new T(fd);
|
||||
}
|
||||
|
@ -33,10 +33,13 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <new> // IWYU pragma: keep
|
||||
#include <stdexcept>
|
||||
|
||||
#include <osmium/index/index.hpp>
|
||||
#include <osmium/util/memory_mapping.hpp>
|
||||
|
||||
namespace osmium {
|
||||
@ -63,22 +66,26 @@ namespace osmium {
|
||||
mmap_vector_base(int fd, size_t capacity, size_t size = 0) :
|
||||
m_size(size),
|
||||
m_mapping(capacity, osmium::util::MemoryMapping::mapping_mode::write_shared, fd) {
|
||||
assert(size <= capacity);
|
||||
std::fill(data() + size, data() + capacity, osmium::index::empty_value<T>());
|
||||
shrink_to_fit();
|
||||
}
|
||||
|
||||
explicit mmap_vector_base(size_t capacity = mmap_vector_size_increment) :
|
||||
m_size(0),
|
||||
m_mapping(capacity) {
|
||||
std::fill_n(data(), capacity, osmium::index::empty_value<T>());
|
||||
}
|
||||
|
||||
~mmap_vector_base() noexcept = default;
|
||||
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
using value_type = T;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using iterator = value_type*;
|
||||
using const_iterator = const value_type*;
|
||||
|
||||
void close() {
|
||||
m_mapping.unmap();
|
||||
@ -105,6 +112,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
T& operator[](size_t n) {
|
||||
assert(n < m_size);
|
||||
return data()[n];
|
||||
}
|
||||
|
||||
@ -120,20 +128,21 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void shrink_to_fit() {
|
||||
// XXX do something here
|
||||
while (m_size > 0 && data()[m_size - 1] == osmium::index::empty_value<T>()) {
|
||||
--m_size;
|
||||
}
|
||||
}
|
||||
|
||||
void push_back(const T& value) {
|
||||
if (m_size >= capacity()) {
|
||||
resize(m_size+1);
|
||||
}
|
||||
data()[m_size] = value;
|
||||
++m_size;
|
||||
data()[m_size-1] = value;
|
||||
}
|
||||
|
||||
void reserve(size_t new_capacity) {
|
||||
if (new_capacity > capacity()) {
|
||||
const size_t old_capacity = capacity();
|
||||
m_mapping.resize(new_capacity);
|
||||
std::fill(data() + old_capacity, data() + new_capacity, osmium::index::empty_value<T>());
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,9 +150,6 @@ namespace osmium {
|
||||
if (new_size > capacity()) {
|
||||
reserve(new_size + osmium::detail::mmap_vector_size_increment);
|
||||
}
|
||||
if (new_size > size()) {
|
||||
new (data() + size()) T[new_size - size()];
|
||||
}
|
||||
m_size = new_size;
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,11 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <osmium/index/detail/mmap_vector_base.hpp>
|
||||
#include <osmium/index/detail/tmpfile.hpp>
|
||||
#include <osmium/util/file.hpp>
|
||||
@ -48,6 +53,16 @@ namespace osmium {
|
||||
template <typename T>
|
||||
class mmap_vector_file : public mmap_vector_base<T> {
|
||||
|
||||
size_t filesize(int fd) const {
|
||||
const size_t size = osmium::util::file_size(fd);
|
||||
|
||||
if (size % sizeof(T) != 0) {
|
||||
throw std::runtime_error("Index file has wrong size (must be multiple of " + std::to_string(sizeof(T)) + ").");
|
||||
}
|
||||
|
||||
return size / sizeof(T);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
mmap_vector_file() :
|
||||
@ -59,8 +74,8 @@ namespace osmium {
|
||||
explicit mmap_vector_file(int fd) :
|
||||
mmap_vector_base<T>(
|
||||
fd,
|
||||
osmium::util::file_size(fd) / sizeof(T),
|
||||
osmium::util::file_size(fd) / sizeof(T)) {
|
||||
std::max(osmium::detail::mmap_vector_size_increment, filesize(fd)),
|
||||
filesize(fd)) {
|
||||
}
|
||||
|
||||
~mmap_vector_file() noexcept = default;
|
||||
|
@ -55,10 +55,10 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef TValue element_type;
|
||||
typedef TVector vector_type;
|
||||
typedef typename vector_type::iterator iterator;
|
||||
typedef typename vector_type::const_iterator const_iterator;
|
||||
using element_type = TValue;
|
||||
using vector_type = TVector;
|
||||
using iterator = typename vector_type::iterator;
|
||||
using const_iterator = typename vector_type::const_iterator;
|
||||
|
||||
VectorBasedDenseMap() :
|
||||
m_vector() {
|
||||
@ -88,7 +88,7 @@ namespace osmium {
|
||||
not_found_error(id);
|
||||
}
|
||||
return value;
|
||||
} catch (std::out_of_range&) {
|
||||
} catch (const std::out_of_range&) {
|
||||
not_found_error(id);
|
||||
}
|
||||
}
|
||||
@ -146,10 +146,10 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef typename std::pair<TId, TValue> element_type;
|
||||
typedef TVector<element_type> vector_type;
|
||||
typedef typename vector_type::iterator iterator;
|
||||
typedef typename vector_type::const_iterator const_iterator;
|
||||
using element_type = typename std::pair<TId, TValue>;
|
||||
using vector_type = TVector<element_type>;
|
||||
using iterator = typename vector_type::iterator;
|
||||
using const_iterator = typename vector_type::const_iterator;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -52,10 +52,10 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef typename std::pair<TId, TValue> element_type;
|
||||
typedef TVector<element_type> vector_type;
|
||||
typedef typename vector_type::iterator iterator;
|
||||
typedef typename vector_type::const_iterator const_iterator;
|
||||
using element_type = typename std::pair<TId, TValue>;
|
||||
using vector_type = TVector<element_type>;
|
||||
using iterator = typename vector_type::iterator;
|
||||
using const_iterator = typename vector_type::const_iterator;
|
||||
|
||||
private:
|
||||
|
||||
@ -127,7 +127,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void remove(const TId id, const TValue value) {
|
||||
auto r = get_all(id);
|
||||
const auto r = get_all(id);
|
||||
for (auto it = r.first; it != r.second; ++it) {
|
||||
if (it->second == value) {
|
||||
it->second = 0;
|
||||
|
@ -49,11 +49,11 @@ namespace osmium {
|
||||
*/
|
||||
struct not_found : public std::runtime_error {
|
||||
|
||||
not_found(const std::string& what) :
|
||||
explicit not_found(const std::string& what) :
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
not_found(const char* what) :
|
||||
explicit not_found(const char* what) :
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
|
@ -98,10 +98,10 @@ namespace osmium {
|
||||
public:
|
||||
|
||||
/// The "key" type, usually osmium::unsigned_object_id_type.
|
||||
typedef TId key_type;
|
||||
using key_type = TId;
|
||||
|
||||
/// The "value" type, usually a Location or size_t.
|
||||
typedef TValue value_type;
|
||||
using value_type = TValue;
|
||||
|
||||
Map() = default;
|
||||
|
||||
@ -171,10 +171,10 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef TId id_type;
|
||||
typedef TValue value_type;
|
||||
typedef osmium::index::map::Map<id_type, value_type> map_type;
|
||||
typedef std::function<map_type*(const std::vector<std::string>&)> create_map_func;
|
||||
using id_type = TId;
|
||||
using value_type = TValue;
|
||||
using map_type = osmium::index::map::Map<id_type, value_type>;
|
||||
using create_map_func = std::function<map_type*(const std::vector<std::string>&)>;
|
||||
|
||||
private:
|
||||
|
||||
@ -207,7 +207,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
bool has_map_type(const std::string& map_type_name) const {
|
||||
return m_callbacks.count(map_type_name);
|
||||
return m_callbacks.count(map_type_name) != 0;
|
||||
}
|
||||
|
||||
std::vector<std::string> map_types() const {
|
||||
|
@ -37,7 +37,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include <osmium/index/map.hpp>
|
||||
@ -98,7 +97,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void dump_as_list(const int fd) final {
|
||||
typedef typename std::map<TId, TValue>::value_type t;
|
||||
using t = typename std::map<TId, TValue>::value_type;
|
||||
std::vector<t> v;
|
||||
v.reserve(m_elements.size());
|
||||
std::copy(m_elements.cbegin(), m_elements.cend(), std::back_inserter(v));
|
||||
|
@ -52,7 +52,7 @@ namespace osmium {
|
||||
|
||||
static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value, "TId template parameter for class Multimap must be unsigned integral type");
|
||||
|
||||
typedef typename std::pair<TId, TValue> element_type;
|
||||
using element_type = typename std::pair<TId, TValue>;
|
||||
|
||||
Multimap(const Multimap&) = delete;
|
||||
Multimap& operator=(const Multimap&) = delete;
|
||||
@ -65,10 +65,10 @@ namespace osmium {
|
||||
public:
|
||||
|
||||
/// The "key" type, usually osmium::unsigned_object_id_type.
|
||||
typedef TId key_type;
|
||||
using key_type = TId;
|
||||
|
||||
/// The "value" type, usually a Location or size_t.
|
||||
typedef TValue value_type;
|
||||
using value_type = TValue;
|
||||
|
||||
Multimap() = default;
|
||||
|
||||
@ -77,7 +77,7 @@ namespace osmium {
|
||||
/// Set the field with id to value.
|
||||
virtual void set(const TId id, const TValue value) = 0;
|
||||
|
||||
typedef element_type* iterator;
|
||||
using iterator = element_type*;
|
||||
|
||||
// virtual std::pair<iterator, iterator> get_all(const TId id) const = 0;
|
||||
|
||||
|
@ -50,10 +50,10 @@ namespace osmium {
|
||||
template <typename TId, typename TValue>
|
||||
class HybridIterator {
|
||||
|
||||
typedef SparseMemArray<TId, TValue> main_map_type;
|
||||
typedef SparseMemMultimap<TId, TValue> extra_map_type;
|
||||
using main_map_type = SparseMemArray<TId, TValue>;
|
||||
using extra_map_type = SparseMemMultimap<TId, TValue>;
|
||||
|
||||
typedef typename std::pair<TId, TValue> element_type;
|
||||
using element_type = typename std::pair<TId, TValue>;
|
||||
|
||||
typename main_map_type::iterator m_begin_main;
|
||||
typename main_map_type::iterator m_end_main;
|
||||
@ -120,16 +120,16 @@ namespace osmium {
|
||||
template <typename TId, typename TValue>
|
||||
class Hybrid : public Multimap<TId, TValue> {
|
||||
|
||||
typedef SparseMemArray<TId, TValue> main_map_type;
|
||||
typedef SparseMemMultimap<TId, TValue> extra_map_type;
|
||||
using main_map_type = SparseMemArray<TId, TValue>;
|
||||
using extra_map_type = SparseMemMultimap<TId, TValue>;
|
||||
|
||||
main_map_type m_main;
|
||||
extra_map_type m_extra;
|
||||
|
||||
public:
|
||||
|
||||
typedef HybridIterator<TId, TValue> iterator;
|
||||
typedef const HybridIterator<TId, TValue> const_iterator;
|
||||
using iterator = HybridIterator<TId, TValue>;
|
||||
using const_iterator = const HybridIterator<TId, TValue>;
|
||||
|
||||
Hybrid() :
|
||||
m_main(),
|
||||
|
@ -63,12 +63,11 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef typename std::multimap<const TId, TValue> collection_type;
|
||||
typedef typename collection_type::iterator iterator;
|
||||
typedef typename collection_type::const_iterator const_iterator;
|
||||
typedef typename collection_type::value_type value_type;
|
||||
|
||||
typedef typename std::pair<TId, TValue> element_type;
|
||||
using collection_type = typename std::multimap<const TId, TValue>;
|
||||
using iterator = typename collection_type::iterator;
|
||||
using const_iterator = typename collection_type::const_iterator;
|
||||
using value_type = typename collection_type::value_type;
|
||||
using element_type = typename std::pair<TId, TValue>;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -45,8 +45,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <osmium/io/any_compression.hpp> // IWYU pragma: export
|
||||
|
||||
#include <osmium/io/o5m_input.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/opl_input.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/pbf_input.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/xml_input.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/o5m_input.hpp> // IWYU pragma: export
|
||||
|
||||
#endif // OSMIUM_IO_ANY_INPUT_HPP
|
||||
|
@ -43,10 +43,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
#include <bzlib.h>
|
||||
|
||||
@ -55,6 +54,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
#endif
|
||||
|
||||
#include <osmium/io/compression.hpp>
|
||||
#include <osmium/io/detail/read_write.hpp>
|
||||
#include <osmium/io/error.hpp>
|
||||
#include <osmium/io/file_compression.hpp>
|
||||
#include <osmium/io/writer_options.hpp>
|
||||
@ -109,7 +109,7 @@ namespace osmium {
|
||||
|
||||
explicit Bzip2Compressor(int fd, fsync sync) :
|
||||
Compressor(sync),
|
||||
m_file(fdopen(dup(fd), "wb")),
|
||||
m_file(fdopen(::dup(fd), "wb")),
|
||||
m_bzerror(BZ_OK),
|
||||
m_bzfile(::BZ2_bzWriteOpen(&m_bzerror, m_file, 6, 0, 0)) {
|
||||
if (!m_bzfile) {
|
||||
@ -165,7 +165,7 @@ namespace osmium {
|
||||
|
||||
explicit Bzip2Decompressor(int fd) :
|
||||
Decompressor(),
|
||||
m_file(fdopen(dup(fd), "rb")),
|
||||
m_file(fdopen(::dup(fd), "rb")),
|
||||
m_bzerror(BZ_OK),
|
||||
m_bzfile(::BZ2_bzReadOpen(&m_bzerror, m_file, 0, 0, nullptr, 0)) {
|
||||
if (!m_bzfile) {
|
||||
@ -215,6 +215,8 @@ namespace osmium {
|
||||
buffer.resize(static_cast<std::string::size_type>(nread));
|
||||
}
|
||||
|
||||
set_offset(size_t(ftell(m_file)));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@ -33,11 +33,12 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <atomic>
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <tuple>
|
||||
@ -54,6 +55,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/io/file_compression.hpp>
|
||||
#include <osmium/io/writer_options.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
#include <osmium/util/file.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@ -86,6 +88,9 @@ namespace osmium {
|
||||
|
||||
class Decompressor {
|
||||
|
||||
std::atomic<size_t> m_file_size {0};
|
||||
std::atomic<size_t> m_offset {0};
|
||||
|
||||
public:
|
||||
|
||||
static constexpr unsigned int input_buffer_size = 1024 * 1024;
|
||||
@ -105,6 +110,22 @@ namespace osmium {
|
||||
|
||||
virtual void close() = 0;
|
||||
|
||||
size_t file_size() const noexcept {
|
||||
return m_file_size;
|
||||
}
|
||||
|
||||
void set_file_size(size_t size) noexcept {
|
||||
m_file_size = size;
|
||||
}
|
||||
|
||||
size_t offset() const noexcept {
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
void set_offset(size_t offset) noexcept {
|
||||
m_offset = offset;
|
||||
}
|
||||
|
||||
}; // class Decompressor
|
||||
|
||||
/**
|
||||
@ -118,16 +139,16 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::function<osmium::io::Compressor*(int, fsync)> create_compressor_type;
|
||||
typedef std::function<osmium::io::Decompressor*(int)> create_decompressor_type_fd;
|
||||
typedef std::function<osmium::io::Decompressor*(const char*, size_t)> create_decompressor_type_buffer;
|
||||
using create_compressor_type = std::function<osmium::io::Compressor*(int, fsync)>;
|
||||
using create_decompressor_type_fd = std::function<osmium::io::Decompressor*(int)>;
|
||||
using create_decompressor_type_buffer = std::function<osmium::io::Decompressor*(const char*, size_t)>;
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<const osmium::io::file_compression,
|
||||
using compression_map_type = std::map<const osmium::io::file_compression,
|
||||
std::tuple<create_compressor_type,
|
||||
create_decompressor_type_fd,
|
||||
create_decompressor_type_buffer>> compression_map_type;
|
||||
create_decompressor_type_buffer>>;
|
||||
|
||||
compression_map_type m_callbacks;
|
||||
|
||||
@ -182,7 +203,9 @@ namespace osmium {
|
||||
auto it = m_callbacks.find(compression);
|
||||
|
||||
if (it != m_callbacks.end()) {
|
||||
return std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd));
|
||||
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);
|
||||
@ -241,6 +264,7 @@ namespace osmium {
|
||||
int m_fd;
|
||||
const char *m_buffer;
|
||||
size_t m_buffer_size;
|
||||
size_t m_offset = 0;
|
||||
|
||||
public:
|
||||
|
||||
@ -284,6 +308,9 @@ namespace osmium {
|
||||
buffer.resize(std::string::size_type(nread));
|
||||
}
|
||||
|
||||
m_offset += buffer.size();
|
||||
set_offset(m_offset);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@ -34,29 +34,35 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <future>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/crc.hpp>
|
||||
|
||||
#include <osmium/io/detail/output_format.hpp>
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
#include <osmium/io/detail/string_util.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/memory/collection.hpp>
|
||||
#include <osmium/memory/item_iterator.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/changeset.hpp>
|
||||
#include <osmium/osm/crc.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/relation.hpp>
|
||||
#include <osmium/osm/tag.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/thread/pool.hpp>
|
||||
#include <osmium/util/minmax.hpp>
|
||||
@ -66,8 +72,6 @@ namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
class File;
|
||||
|
||||
namespace detail {
|
||||
|
||||
constexpr const char* color_bold = "\x1b[1m";
|
||||
@ -80,6 +84,10 @@ namespace osmium {
|
||||
constexpr const char* color_magenta = "\x1b[35m";
|
||||
constexpr const char* color_cyan = "\x1b[36m";
|
||||
constexpr const char* color_white = "\x1b[37m";
|
||||
|
||||
constexpr const char* color_backg_red = "\x1b[41m";
|
||||
constexpr const char* color_backg_green = "\x1b[42m";
|
||||
|
||||
constexpr const char* color_reset = "\x1b[0m";
|
||||
|
||||
struct debug_output_options {
|
||||
@ -90,6 +98,11 @@ namespace osmium {
|
||||
/// Output with ANSI colors?
|
||||
bool use_color;
|
||||
|
||||
/// Add CRC32 checksum to each object?
|
||||
bool add_crc32;
|
||||
|
||||
/// Write in form of a diff file?
|
||||
bool format_as_diff;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -102,16 +115,47 @@ namespace osmium {
|
||||
const char* m_utf8_prefix = "";
|
||||
const char* m_utf8_suffix = "";
|
||||
|
||||
char m_diff_char = '\0';
|
||||
|
||||
void append_encoded_string(const char* data) {
|
||||
append_debug_encoded_string(*m_out, data, m_utf8_prefix, m_utf8_suffix);
|
||||
}
|
||||
|
||||
template <typename... TArgs>
|
||||
void output_formatted(const char* format, TArgs&&... args) {
|
||||
append_printf_formatted_string(*m_out, format, std::forward<TArgs>(args)...);
|
||||
}
|
||||
|
||||
void write_color(const char* color) {
|
||||
if (m_options.use_color) {
|
||||
*m_out += color;
|
||||
}
|
||||
}
|
||||
|
||||
void write_diff() {
|
||||
if (!m_diff_char) {
|
||||
return;
|
||||
}
|
||||
if (m_options.use_color) {
|
||||
if (m_diff_char == '-') {
|
||||
*m_out += color_backg_red;
|
||||
*m_out += color_white;
|
||||
*m_out += color_bold;
|
||||
*m_out += '-';
|
||||
*m_out += color_reset;
|
||||
return;
|
||||
} else if (m_diff_char == '+') {
|
||||
*m_out += color_backg_green;
|
||||
*m_out += color_white;
|
||||
*m_out += color_bold;
|
||||
*m_out += '+';
|
||||
*m_out += color_reset;
|
||||
return;
|
||||
}
|
||||
}
|
||||
*m_out += m_diff_char;
|
||||
}
|
||||
|
||||
void write_string(const char* string) {
|
||||
*m_out += '"';
|
||||
write_color(color_blue);
|
||||
@ -121,6 +165,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void write_object_type(const char* object_type, bool visible = true) {
|
||||
write_diff();
|
||||
if (visible) {
|
||||
write_color(color_bold);
|
||||
} else {
|
||||
@ -132,6 +177,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void write_fieldname(const char* name) {
|
||||
write_diff();
|
||||
*m_out += " ";
|
||||
write_color(color_cyan);
|
||||
*m_out += name;
|
||||
@ -161,7 +207,9 @@ namespace osmium {
|
||||
void write_timestamp(const osmium::Timestamp& timestamp) {
|
||||
if (timestamp.valid()) {
|
||||
*m_out += timestamp.to_iso();
|
||||
output_formatted(" (%d)", timestamp.seconds_since_epoch());
|
||||
*m_out += " (";
|
||||
output_int(timestamp.seconds_since_epoch());
|
||||
*m_out += ')';
|
||||
} else {
|
||||
write_error("NOT SET");
|
||||
}
|
||||
@ -169,37 +217,47 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void write_meta(const osmium::OSMObject& object) {
|
||||
output_formatted("%" PRId64 "\n", object.id());
|
||||
output_int(object.id());
|
||||
*m_out += '\n';
|
||||
if (m_options.add_metadata) {
|
||||
write_fieldname("version");
|
||||
output_formatted(" %d", object.version());
|
||||
*m_out += " ";
|
||||
output_int(object.version());
|
||||
if (object.visible()) {
|
||||
*m_out += " visible\n";
|
||||
} else {
|
||||
write_error(" deleted\n");
|
||||
}
|
||||
write_fieldname("changeset");
|
||||
output_formatted("%d\n", object.changeset());
|
||||
output_int(object.changeset());
|
||||
*m_out += '\n';
|
||||
write_fieldname("timestamp");
|
||||
write_timestamp(object.timestamp());
|
||||
write_fieldname("user");
|
||||
output_formatted(" %d ", object.uid());
|
||||
*m_out += " ";
|
||||
output_int(object.uid());
|
||||
*m_out += ' ';
|
||||
write_string(object.user());
|
||||
*m_out += '\n';
|
||||
}
|
||||
}
|
||||
|
||||
void write_tags(const osmium::TagList& tags, const char* padding="") {
|
||||
if (!tags.empty()) {
|
||||
if (tags.empty()) {
|
||||
return;
|
||||
}
|
||||
write_fieldname("tags");
|
||||
*m_out += padding;
|
||||
output_formatted(" %d\n", tags.size());
|
||||
*m_out += " ";
|
||||
output_int(tags.size());
|
||||
*m_out += '\n';
|
||||
|
||||
osmium::max_op<size_t> max;
|
||||
for (const auto& tag : tags) {
|
||||
max.update(std::strlen(tag.key()));
|
||||
}
|
||||
for (const auto& tag : tags) {
|
||||
write_diff();
|
||||
*m_out += " ";
|
||||
write_string(tag.key());
|
||||
auto spacing = max() - std::strlen(tag.key());
|
||||
@ -211,11 +269,11 @@ namespace osmium {
|
||||
*m_out += '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void write_location(const osmium::Location& location) {
|
||||
write_fieldname("lon/lat");
|
||||
output_formatted(" %.7f,%.7f", location.lon_without_check(), location.lat_without_check());
|
||||
*m_out += " ";
|
||||
location.as_string_without_check(std::back_inserter(*m_out));
|
||||
if (!location.valid()) {
|
||||
write_error(" INVALID LOCATION!");
|
||||
}
|
||||
@ -230,13 +288,30 @@ namespace osmium {
|
||||
}
|
||||
const auto& bl = box.bottom_left();
|
||||
const auto& tr = box.top_right();
|
||||
output_formatted("%.7f,%.7f %.7f,%.7f", bl.lon_without_check(), bl.lat_without_check(), tr.lon_without_check(), tr.lat_without_check());
|
||||
bl.as_string(std::back_inserter(*m_out));
|
||||
*m_out += ' ';
|
||||
tr.as_string(std::back_inserter(*m_out));
|
||||
if (!box.valid()) {
|
||||
write_error(" INVALID BOX!");
|
||||
}
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write_crc32(const T& object) {
|
||||
write_fieldname("crc32");
|
||||
osmium::CRC<boost::crc_32_type> crc32;
|
||||
crc32.update(object);
|
||||
output_formatted(" %x\n", crc32().checksum());
|
||||
}
|
||||
|
||||
void write_crc32(const osmium::Changeset& object) {
|
||||
write_fieldname("crc32");
|
||||
osmium::CRC<boost::crc_32_type> crc32;
|
||||
crc32.update(object);
|
||||
output_formatted(" %x\n", crc32().checksum());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
DebugOutputBlock(osmium::memory::Buffer&& buffer, const debug_output_options& options) :
|
||||
@ -265,6 +340,8 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void node(const osmium::Node& node) {
|
||||
m_diff_char = m_options.format_as_diff ? node.diff_as_char() : '\0';
|
||||
|
||||
write_object_type("node", node.visible());
|
||||
write_meta(node);
|
||||
|
||||
@ -274,17 +351,24 @@ namespace osmium {
|
||||
|
||||
write_tags(node.tags());
|
||||
|
||||
if (m_options.add_crc32) {
|
||||
write_crc32(node);
|
||||
}
|
||||
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
void way(const osmium::Way& way) {
|
||||
m_diff_char = m_options.format_as_diff ? way.diff_as_char() : '\0';
|
||||
|
||||
write_object_type("way", way.visible());
|
||||
write_meta(way);
|
||||
write_tags(way.tags());
|
||||
|
||||
write_fieldname("nodes");
|
||||
|
||||
output_formatted(" %d", way.nodes().size());
|
||||
*m_out += " ";
|
||||
output_int(way.nodes().size());
|
||||
if (way.nodes().size() < 2) {
|
||||
write_error(" LESS THAN 2 NODES!\n");
|
||||
} else if (way.nodes().size() > 2000) {
|
||||
@ -295,32 +379,45 @@ namespace osmium {
|
||||
*m_out += " (open)\n";
|
||||
}
|
||||
|
||||
int width = int(log10(way.nodes().size())) + 1;
|
||||
const int width = int(std::log10(way.nodes().size())) + 1;
|
||||
int n = 0;
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
write_diff();
|
||||
write_counter(width, n++);
|
||||
output_formatted("%10" PRId64, node_ref.ref());
|
||||
if (node_ref.location().valid()) {
|
||||
output_formatted(" (%.7f,%.7f)", node_ref.location().lon_without_check(), node_ref.location().lat_without_check());
|
||||
*m_out += " (";
|
||||
node_ref.location().as_string(std::back_inserter(*m_out));
|
||||
*m_out += ')';
|
||||
}
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
if (m_options.add_crc32) {
|
||||
write_crc32(way);
|
||||
}
|
||||
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
void relation(const osmium::Relation& relation) {
|
||||
static const char* short_typename[] = { "node", "way ", "rel " };
|
||||
|
||||
m_diff_char = m_options.format_as_diff ? relation.diff_as_char() : '\0';
|
||||
|
||||
write_object_type("relation", relation.visible());
|
||||
write_meta(relation);
|
||||
write_tags(relation.tags());
|
||||
|
||||
write_fieldname("members");
|
||||
output_formatted(" %d\n", relation.members().size());
|
||||
*m_out += " ";
|
||||
output_int(relation.members().size());
|
||||
*m_out += '\n';
|
||||
|
||||
int width = int(log10(relation.members().size())) + 1;
|
||||
const int width = int(std::log10(relation.members().size())) + 1;
|
||||
int n = 0;
|
||||
for (const auto& member : relation.members()) {
|
||||
write_diff();
|
||||
write_counter(width, n++);
|
||||
*m_out += short_typename[item_type_to_nwr_index(member.type())];
|
||||
output_formatted(" %10" PRId64 " ", member.ref());
|
||||
@ -328,15 +425,20 @@ namespace osmium {
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
if (m_options.add_crc32) {
|
||||
write_crc32(relation);
|
||||
}
|
||||
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
void changeset(const osmium::Changeset& changeset) {
|
||||
write_object_type("changeset");
|
||||
output_formatted("%d\n", changeset.id());
|
||||
output_int(changeset.id());
|
||||
*m_out += '\n';
|
||||
|
||||
write_fieldname("num changes");
|
||||
output_formatted("%d", changeset.num_changes());
|
||||
output_int(changeset.num_changes());
|
||||
if (changeset.num_changes() == 0) {
|
||||
write_error(" NO CHANGES!");
|
||||
}
|
||||
@ -355,7 +457,9 @@ namespace osmium {
|
||||
}
|
||||
|
||||
write_fieldname("user");
|
||||
output_formatted(" %d ", changeset.uid());
|
||||
*m_out += " ";
|
||||
output_int(changeset.uid());
|
||||
*m_out += ' ';
|
||||
write_string(changeset.user());
|
||||
*m_out += '\n';
|
||||
|
||||
@ -364,9 +468,11 @@ namespace osmium {
|
||||
|
||||
if (changeset.num_comments() > 0) {
|
||||
write_fieldname("comments");
|
||||
output_formatted(" %d\n", changeset.num_comments());
|
||||
*m_out += " ";
|
||||
output_int(changeset.num_comments());
|
||||
*m_out += '\n';
|
||||
|
||||
int width = int(log10(changeset.num_comments())) + 1;
|
||||
const int width = int(std::log10(changeset.num_comments())) + 1;
|
||||
int n = 0;
|
||||
for (const auto& comment : changeset.discussion()) {
|
||||
write_counter(width, n++);
|
||||
@ -376,7 +482,8 @@ namespace osmium {
|
||||
output_formatted(" %*s", width, "");
|
||||
|
||||
write_comment_field("user");
|
||||
output_formatted("%d ", comment.uid());
|
||||
output_int(comment.uid());
|
||||
*m_out += ' ';
|
||||
write_string(comment.user());
|
||||
output_formatted("\n %*s", width, "");
|
||||
|
||||
@ -386,6 +493,10 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
if (m_options.add_crc32) {
|
||||
write_crc32(changeset);
|
||||
}
|
||||
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
@ -414,6 +525,8 @@ namespace osmium {
|
||||
m_options() {
|
||||
m_options.add_metadata = file.is_not_false("add_metadata");
|
||||
m_options.use_color = file.is_true("color");
|
||||
m_options.add_crc32 = file.is_true("add_crc32");
|
||||
m_options.format_as_diff = file.is_true("diff");
|
||||
}
|
||||
|
||||
DebugOutputFormat(const DebugOutputFormat&) = delete;
|
||||
@ -422,6 +535,10 @@ namespace osmium {
|
||||
~DebugOutputFormat() noexcept final = default;
|
||||
|
||||
void write_header(const osmium::io::Header& header) final {
|
||||
if (m_options.format_as_diff) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string out;
|
||||
|
||||
if (m_options.use_color) {
|
||||
@ -439,9 +556,9 @@ namespace osmium {
|
||||
out += '\n';
|
||||
for (const auto& box : header.boxes()) {
|
||||
out += " ";
|
||||
box.bottom_left().as_string(std::back_inserter(out), ',');
|
||||
out += " ";
|
||||
box.top_right().as_string(std::back_inserter(out), ',');
|
||||
box.bottom_left().as_string(std::back_inserter(out));
|
||||
out += ' ';
|
||||
box.top_right().as_string(std::back_inserter(out));
|
||||
out += '\n';
|
||||
}
|
||||
write_fieldname(out, "options");
|
||||
|
@ -38,11 +38,11 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
#include <osmium/io/error.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
@ -154,18 +154,14 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::function<
|
||||
std::unique_ptr<Parser>(
|
||||
future_string_queue_type&,
|
||||
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
|
||||
)
|
||||
> create_parser_type;
|
||||
osmium::osm_entity_bits::type read_which_entities)>;
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<osmium::io::file_format, create_parser_type> map_type;
|
||||
using map_type = std::map<osmium::io::file_format, create_parser_type>;
|
||||
|
||||
map_type m_callbacks;
|
||||
|
||||
|
@ -42,9 +42,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <protozero/exception.hpp>
|
||||
#include <protozero/varint.hpp>
|
||||
|
||||
#include <osmium/builder/builder.hpp>
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
#include <osmium/io/detail/input_format.hpp>
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
@ -52,19 +52,26 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/thread/util.hpp>
|
||||
#include <osmium/util/cast.hpp>
|
||||
#include <osmium/util/delta.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace builder {
|
||||
class Builder;
|
||||
} // namespace builder
|
||||
|
||||
/**
|
||||
* Exception thrown when the o5m deocder failed. The exception contains
|
||||
* (if available) information about the place where the error happened
|
||||
@ -529,7 +536,7 @@ namespace osmium {
|
||||
uint64_t length = 0;
|
||||
try {
|
||||
length = protozero::decode_varint(&m_data, m_end);
|
||||
} catch (protozero::end_of_buffer_exception&) {
|
||||
} catch (const protozero::end_of_buffer_exception&) {
|
||||
throw o5m_error("premature end of file");
|
||||
}
|
||||
|
||||
|
156
third_party/libosmium/include/osmium/io/detail/opl_input_format.hpp
vendored
Normal file
156
third_party/libosmium/include/osmium/io/detail/opl_input_format.hpp
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_OPL_INPUT_FORMAT_HPP
|
||||
#define OSMIUM_IO_DETAIL_OPL_INPUT_FORMAT_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 <cstdlib>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/io/detail/input_format.hpp>
|
||||
#include <osmium/io/detail/opl_parser_functions.hpp>
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/thread/util.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class OPLParser : public Parser {
|
||||
|
||||
osmium::memory::Buffer m_buffer{1024*1024};
|
||||
const char* m_data = nullptr;
|
||||
uint64_t m_line_count = 0;
|
||||
|
||||
void maybe_flush() {
|
||||
if (m_buffer.committed() > 800*1024) {
|
||||
osmium::memory::Buffer buffer{1024*1024};
|
||||
using std::swap;
|
||||
swap(m_buffer, buffer);
|
||||
send_to_output_queue(std::move(buffer));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void parse_line() {
|
||||
if (opl_parse_line(m_line_count, m_data, m_buffer, read_types())) {
|
||||
maybe_flush();
|
||||
}
|
||||
++m_line_count;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
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) {
|
||||
set_header_value(osmium::io::Header{});
|
||||
}
|
||||
|
||||
~OPLParser() noexcept final = default;
|
||||
|
||||
void run() final {
|
||||
osmium::thread::set_thread_name("_osmium_opl_in");
|
||||
|
||||
std::string rest;
|
||||
while (!input_done()) {
|
||||
std::string input = get_input();
|
||||
std::string::size_type ppos = 0;
|
||||
|
||||
if (!rest.empty()) {
|
||||
ppos = input.find('\n');
|
||||
if (ppos == std::string::npos) {
|
||||
rest.append(input);
|
||||
continue;
|
||||
}
|
||||
rest.append(input.substr(0, ppos));
|
||||
m_data = rest.data();
|
||||
parse_line();
|
||||
rest.clear();
|
||||
}
|
||||
|
||||
std::string::size_type pos = input.find('\n', ppos);
|
||||
while (pos != std::string::npos) {
|
||||
m_data = &input[ppos];
|
||||
input[pos] = '\0';
|
||||
parse_line();
|
||||
ppos = pos + 1;
|
||||
if (ppos >= input.size()) {
|
||||
break;
|
||||
}
|
||||
pos = input.find('\n', ppos);
|
||||
}
|
||||
rest = input.substr(ppos);
|
||||
}
|
||||
|
||||
if (m_buffer.committed() > 0) {
|
||||
send_to_output_queue(std::move(m_buffer));
|
||||
}
|
||||
}
|
||||
|
||||
}; // class OPLParser
|
||||
|
||||
// we want the register_parser() function to run, setting
|
||||
// the variable is only a side-effect, it will never be used
|
||||
const bool registered_opl_parser = ParserFactory::instance().register_parser(
|
||||
file_format::opl,
|
||||
[](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));
|
||||
});
|
||||
|
||||
// dummy function to silence the unused variable warning from above
|
||||
inline bool get_registered_opl_parser() noexcept {
|
||||
return registered_opl_parser;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_OPL_INPUT_FORMAT_HPP
|
@ -33,26 +33,26 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <future>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/io/detail/output_format.hpp>
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
#include <osmium/io/detail/string_util.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/memory/collection.hpp>
|
||||
#include <osmium/memory/item_iterator.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/changeset.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/relation.hpp>
|
||||
#include <osmium/osm/tag.hpp>
|
||||
@ -65,8 +65,6 @@ namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
class File;
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct opl_output_options {
|
||||
@ -74,6 +72,12 @@ namespace osmium {
|
||||
/// Should metadata of objects be added?
|
||||
bool add_metadata;
|
||||
|
||||
/// Should node locations be added to ways?
|
||||
bool locations_on_ways;
|
||||
|
||||
/// Write in form of a diff file?
|
||||
bool format_as_diff;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@ -87,38 +91,71 @@ namespace osmium {
|
||||
osmium::io::detail::append_utf8_encoded_string(*m_out, data);
|
||||
}
|
||||
|
||||
void write_meta(const osmium::OSMObject& object) {
|
||||
output_formatted("%" PRId64, object.id());
|
||||
if (m_options.add_metadata) {
|
||||
output_formatted(" v%d d", object.version());
|
||||
*m_out += (object.visible() ? 'V' : 'D');
|
||||
output_formatted(" c%d t", object.changeset());
|
||||
*m_out += object.timestamp().to_iso();
|
||||
output_formatted(" i%d u", object.uid());
|
||||
append_encoded_string(object.user());
|
||||
void write_field_int(char c, int64_t value) {
|
||||
*m_out += c;
|
||||
output_int(value);
|
||||
}
|
||||
|
||||
void write_field_timestamp(char c, const osmium::Timestamp& timestamp) {
|
||||
*m_out += c;
|
||||
*m_out += timestamp.to_iso();
|
||||
}
|
||||
|
||||
void write_tags(const osmium::TagList& tags) {
|
||||
*m_out += " T";
|
||||
bool first = true;
|
||||
for (const auto& tag : object.tags()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
*m_out += ',';
|
||||
|
||||
if (tags.empty()) {
|
||||
return;
|
||||
}
|
||||
append_encoded_string(tag.key());
|
||||
|
||||
auto it = tags.begin();
|
||||
append_encoded_string(it->key());
|
||||
*m_out += '=';
|
||||
append_encoded_string(tag.value());
|
||||
append_encoded_string(it->value());
|
||||
|
||||
for (++it; it != tags.end(); ++it) {
|
||||
*m_out += ',';
|
||||
append_encoded_string(it->key());
|
||||
*m_out += '=';
|
||||
append_encoded_string(it->value());
|
||||
}
|
||||
}
|
||||
|
||||
void write_meta(const osmium::OSMObject& object) {
|
||||
output_int(object.id());
|
||||
if (m_options.add_metadata) {
|
||||
*m_out += ' ';
|
||||
write_field_int('v', object.version());
|
||||
*m_out += " d";
|
||||
*m_out += (object.visible() ? 'V' : 'D');
|
||||
*m_out += ' ';
|
||||
write_field_int('c', object.changeset());
|
||||
*m_out += ' ';
|
||||
write_field_timestamp('t', object.timestamp());
|
||||
*m_out += ' ';
|
||||
write_field_int('i', object.uid());
|
||||
*m_out += " u";
|
||||
append_encoded_string(object.user());
|
||||
}
|
||||
write_tags(object.tags());
|
||||
}
|
||||
|
||||
void write_location(const osmium::Location& location, const char x, const char y) {
|
||||
if (location) {
|
||||
output_formatted(" %c%.7f %c%.7f", x, location.lon_without_check(), y, location.lat_without_check());
|
||||
} else {
|
||||
*m_out += ' ';
|
||||
*m_out += x;
|
||||
if (location) {
|
||||
osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.x());
|
||||
}
|
||||
*m_out += ' ';
|
||||
*m_out += y;
|
||||
if (location) {
|
||||
osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.y());
|
||||
}
|
||||
}
|
||||
|
||||
void write_diff(const osmium::OSMObject& object) {
|
||||
if (m_options.format_as_diff) {
|
||||
*m_out += object.diff_as_char();
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,70 +185,93 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void node(const osmium::Node& node) {
|
||||
write_diff(node);
|
||||
*m_out += 'n';
|
||||
write_meta(node);
|
||||
write_location(node.location(), 'x', 'y');
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
void write_field_ref(const osmium::NodeRef& node_ref) {
|
||||
write_field_int('n', node_ref.ref());
|
||||
*m_out += 'x';
|
||||
if (node_ref.location()) {
|
||||
node_ref.location().as_string(std::back_inserter(*m_out), 'y');
|
||||
} else {
|
||||
*m_out += 'y';
|
||||
}
|
||||
}
|
||||
|
||||
void way(const osmium::Way& way) {
|
||||
write_diff(way);
|
||||
*m_out += 'w';
|
||||
write_meta(way);
|
||||
|
||||
*m_out += " N";
|
||||
bool first = true;
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
|
||||
if (!way.nodes().empty()) {
|
||||
auto it = way.nodes().begin();
|
||||
if (m_options.locations_on_ways) {
|
||||
write_field_ref(*it);
|
||||
for (++it; it != way.nodes().end(); ++it) {
|
||||
*m_out += ',';
|
||||
write_field_ref(*it);
|
||||
}
|
||||
output_formatted("n%" PRId64, node_ref.ref());
|
||||
} else {
|
||||
write_field_int('n', it->ref());
|
||||
for (++it; it != way.nodes().end(); ++it) {
|
||||
*m_out += ',';
|
||||
write_field_int('n', it->ref());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
void relation_member(const osmium::RelationMember& member) {
|
||||
*m_out += item_type_to_char(member.type());
|
||||
output_int(member.ref());
|
||||
*m_out += '@';
|
||||
append_encoded_string(member.role());
|
||||
}
|
||||
|
||||
void relation(const osmium::Relation& relation) {
|
||||
write_diff(relation);
|
||||
*m_out += 'r';
|
||||
write_meta(relation);
|
||||
|
||||
*m_out += " M";
|
||||
bool first = true;
|
||||
for (const auto& member : relation.members()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
|
||||
if (!relation.members().empty()) {
|
||||
auto it = relation.members().begin();
|
||||
relation_member(*it);
|
||||
for (++it; it != relation.members().end(); ++it) {
|
||||
*m_out += ',';
|
||||
relation_member(*it);
|
||||
}
|
||||
*m_out += item_type_to_char(member.type());
|
||||
output_formatted("%" PRId64 "@", member.ref());
|
||||
append_encoded_string(member.role());
|
||||
}
|
||||
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
void changeset(const osmium::Changeset& changeset) {
|
||||
output_formatted("c%d k%d s", changeset.id(), changeset.num_changes());
|
||||
*m_out += changeset.created_at().to_iso();
|
||||
*m_out += " e";
|
||||
*m_out += changeset.closed_at().to_iso();
|
||||
output_formatted(" d%d i%d u", changeset.num_comments(), changeset.uid());
|
||||
write_field_int('c', changeset.id());
|
||||
*m_out += ' ';
|
||||
write_field_int('k', changeset.num_changes());
|
||||
*m_out += ' ';
|
||||
write_field_timestamp('s', changeset.created_at());
|
||||
*m_out += ' ';
|
||||
write_field_timestamp('e', changeset.closed_at());
|
||||
*m_out += ' ';
|
||||
write_field_int('d', changeset.num_comments());
|
||||
*m_out += ' ';
|
||||
write_field_int('i', changeset.uid());
|
||||
*m_out += " u";
|
||||
append_encoded_string(changeset.user());
|
||||
write_location(changeset.bounds().bottom_left(), 'x', 'y');
|
||||
write_location(changeset.bounds().top_right(), 'X', 'Y');
|
||||
*m_out += " T";
|
||||
bool first = true;
|
||||
for (const auto& tag : changeset.tags()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
*m_out += ',';
|
||||
}
|
||||
append_encoded_string(tag.key());
|
||||
*m_out += '=';
|
||||
append_encoded_string(tag.value());
|
||||
}
|
||||
|
||||
write_tags(changeset.tags());
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
@ -227,6 +287,8 @@ namespace osmium {
|
||||
OutputFormat(output_queue),
|
||||
m_options() {
|
||||
m_options.add_metadata = file.is_not_false("add_metadata");
|
||||
m_options.locations_on_ways = file.is_true("locations_on_ways");
|
||||
m_options.format_as_diff = file.is_true("diff");
|
||||
}
|
||||
|
||||
OPLOutputFormat(const OPLOutputFormat&) = delete;
|
||||
|
747
third_party/libosmium/include/osmium/io/detail/opl_parser_functions.hpp
vendored
Normal file
747
third_party/libosmium/include/osmium/io/detail/opl_parser_functions.hpp
vendored
Normal file
@ -0,0 +1,747 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_OPL_PARSER_FUNCTIONS_HPP
|
||||
#define OSMIUM_IO_DETAIL_OPL_PARSER_FUNCTIONS_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 <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <utf8.h>
|
||||
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
#include <osmium/io/error.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/changeset.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace builder {
|
||||
class Builder;
|
||||
} // namespace builder
|
||||
|
||||
/**
|
||||
* Exception thrown when there was a problem with parsing the OPL format
|
||||
* of a file.
|
||||
*/
|
||||
struct opl_error : public io_error {
|
||||
|
||||
uint64_t line = 0;
|
||||
uint64_t column = 0;
|
||||
const char* data;
|
||||
std::string msg;
|
||||
|
||||
explicit opl_error(const std::string& what, const char* d = nullptr) :
|
||||
io_error(std::string("OPL error: ") + what),
|
||||
data(d),
|
||||
msg("OPL error: ") {
|
||||
msg.append(what);
|
||||
}
|
||||
|
||||
explicit opl_error(const char* what, const char* d = nullptr) :
|
||||
io_error(std::string("OPL error: ") + what),
|
||||
data(d),
|
||||
msg("OPL error: ") {
|
||||
msg.append(what);
|
||||
}
|
||||
|
||||
void set_pos(uint64_t l, uint64_t col) {
|
||||
line = l;
|
||||
column = col;
|
||||
msg.append(" on line ");
|
||||
msg.append(std::to_string(line));
|
||||
msg.append(" column ");
|
||||
msg.append(std::to_string(column));
|
||||
}
|
||||
|
||||
const char* what() const noexcept override {
|
||||
return msg.c_str();
|
||||
}
|
||||
|
||||
}; // struct opl_error
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Consume consecutive space and tab characters. There must be
|
||||
* at least one.
|
||||
*/
|
||||
inline void opl_parse_space(const char** s) {
|
||||
if (**s != ' ' && **s != '\t') {
|
||||
throw opl_error{"expected space or tab character", *s};
|
||||
}
|
||||
do {
|
||||
++*s;
|
||||
} while (**s == ' ' || **s == '\t');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether s points to something else than the end of the
|
||||
* string or a space or tab.
|
||||
*/
|
||||
inline bool opl_non_empty(const char *s) {
|
||||
return *s != '\0' && *s != ' ' && *s != '\t';
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip to the next space or tab character or the end of the
|
||||
* string.
|
||||
*/
|
||||
inline const char* opl_skip_section(const char** s) noexcept {
|
||||
while (opl_non_empty(*s)) {
|
||||
++*s;
|
||||
}
|
||||
return *s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse OPL-escaped strings with hex code with a '%' at the end.
|
||||
* Appends resulting unicode character to the result string.
|
||||
*
|
||||
* Returns a pointer to next character that needs to be consumed.
|
||||
*/
|
||||
inline void opl_parse_escaped(const char** data, std::string& result) {
|
||||
const char* s = *data;
|
||||
uint32_t value = 0;
|
||||
const int max_length = sizeof(value) * 2 /* hex chars per byte */;
|
||||
int length = 0;
|
||||
while (++length <= max_length) {
|
||||
if (*s == '\0') {
|
||||
throw opl_error{"eol", s};
|
||||
}
|
||||
if (*s == '%') {
|
||||
++s;
|
||||
utf8::utf32to8(&value, &value + 1, std::back_inserter(result));
|
||||
*data = s;
|
||||
return;
|
||||
}
|
||||
value <<= 4;
|
||||
if (*s >= '0' && *s <= '9') {
|
||||
value += *s - '0';
|
||||
} else if (*s >= 'a' && *s <= 'f') {
|
||||
value += *s - 'a' + 10;
|
||||
} else if (*s >= 'A' && *s <= 'F') {
|
||||
value += *s - 'A' + 10;
|
||||
} else {
|
||||
throw opl_error{"not a hex char", s};
|
||||
}
|
||||
++s;
|
||||
}
|
||||
throw opl_error{"hex escape too long", s};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a string up to end of string or next space, tab, comma, or
|
||||
* equal sign.
|
||||
*
|
||||
* Appends characters to the result string.
|
||||
*
|
||||
* Returns a pointer to next character that needs to be consumed.
|
||||
*/
|
||||
inline void opl_parse_string(const char** data, std::string& result) {
|
||||
const char* s = *data;
|
||||
while (true) {
|
||||
if (*s == '\0' || *s == ' ' || *s == '\t' || *s == ',' || *s == '=') {
|
||||
break;
|
||||
} else if (*s == '%') {
|
||||
++s;
|
||||
opl_parse_escaped(&s, result);
|
||||
} else {
|
||||
result += *s;
|
||||
++s;
|
||||
}
|
||||
}
|
||||
*data = s;
|
||||
}
|
||||
|
||||
// Arbitrary limit how long integers can get
|
||||
constexpr const int max_int_len = 16;
|
||||
|
||||
template <typename T>
|
||||
inline T opl_parse_int(const char** s) {
|
||||
if (**s == '\0') {
|
||||
throw opl_error{"expected integer", *s};
|
||||
}
|
||||
const bool negative = (**s == '-');
|
||||
if (negative) {
|
||||
++*s;
|
||||
}
|
||||
|
||||
int64_t value = 0;
|
||||
|
||||
int n = max_int_len;
|
||||
while (**s >= '0' && **s <= '9') {
|
||||
if (--n == 0) {
|
||||
throw opl_error{"integer too long", *s};
|
||||
}
|
||||
value *= 10;
|
||||
value += **s - '0';
|
||||
++*s;
|
||||
}
|
||||
|
||||
if (n == max_int_len) {
|
||||
throw opl_error{"expected integer", *s};
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
value = -value;
|
||||
if (value < std::numeric_limits<T>::min()) {
|
||||
throw opl_error{"integer too long", *s};
|
||||
}
|
||||
} else {
|
||||
if (value > std::numeric_limits<T>::max()) {
|
||||
throw opl_error{"integer too long", *s};
|
||||
}
|
||||
}
|
||||
|
||||
return T(value);
|
||||
}
|
||||
|
||||
inline osmium::object_id_type opl_parse_id(const char** s) {
|
||||
return opl_parse_int<osmium::object_id_type>(s);
|
||||
}
|
||||
|
||||
inline osmium::changeset_id_type opl_parse_changeset_id(const char** s) {
|
||||
return opl_parse_int<osmium::changeset_id_type>(s);
|
||||
}
|
||||
|
||||
inline osmium::object_version_type opl_parse_version(const char** s) {
|
||||
return opl_parse_int<osmium::object_version_type>(s);
|
||||
}
|
||||
|
||||
inline bool opl_parse_visible(const char** data) {
|
||||
if (**data == 'V') {
|
||||
++*data;
|
||||
return true;
|
||||
}
|
||||
if (**data == 'D') {
|
||||
++*data;
|
||||
return false;
|
||||
}
|
||||
throw opl_error{"invalid visible flag", *data};
|
||||
}
|
||||
|
||||
inline osmium::user_id_type opl_parse_uid(const char** s) {
|
||||
return opl_parse_int<osmium::user_id_type>(s);
|
||||
}
|
||||
|
||||
inline osmium::Timestamp opl_parse_timestamp(const char** s) {
|
||||
try {
|
||||
if (**s == '\0' || **s == ' ' || **s == '\t') {
|
||||
return osmium::Timestamp{};
|
||||
}
|
||||
osmium::Timestamp timestamp{*s};
|
||||
*s += 20;
|
||||
return timestamp;
|
||||
} catch (const std::invalid_argument&) {
|
||||
throw opl_error{"can not parse timestamp", *s};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if data points to given character and consume it.
|
||||
* Throw error otherwise.
|
||||
*/
|
||||
inline void opl_parse_char(const char** data, char c) {
|
||||
if (**data == c) {
|
||||
++*data;
|
||||
return;
|
||||
}
|
||||
std::string msg = "expected '";
|
||||
msg += c;
|
||||
msg += "'";
|
||||
throw opl_error{msg, *data};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a list of tags in the format 'key=value,key=value,...'
|
||||
*
|
||||
* Tags will be added to the buffer using a TagListBuilder.
|
||||
*/
|
||||
inline void opl_parse_tags(const char* s, osmium::memory::Buffer& buffer, osmium::builder::Builder* parent_builder = nullptr) {
|
||||
osmium::builder::TagListBuilder builder{buffer, parent_builder};
|
||||
std::string key;
|
||||
std::string value;
|
||||
while (true) {
|
||||
opl_parse_string(&s, key);
|
||||
opl_parse_char(&s, '=');
|
||||
opl_parse_string(&s, value);
|
||||
builder.add_tag(key, value);
|
||||
if (*s == ' ' || *s == '\t' || *s == '\0') {
|
||||
break;
|
||||
}
|
||||
opl_parse_char(&s, ',');
|
||||
key.clear();
|
||||
value.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a number of nodes in the format "nID,nID,nID..."
|
||||
*
|
||||
* Nodes will be added to the buffer using a WayNodeListBuilder.
|
||||
*/
|
||||
inline void opl_parse_way_nodes(const char* s, const char* e, osmium::memory::Buffer& buffer, osmium::builder::WayBuilder* parent_builder = nullptr) {
|
||||
if (s == e) {
|
||||
return;
|
||||
}
|
||||
osmium::builder::WayNodeListBuilder builder{buffer, parent_builder};
|
||||
|
||||
while (s < e) {
|
||||
opl_parse_char(&s, 'n');
|
||||
if (s == e) {
|
||||
throw opl_error{"expected integer", s};
|
||||
}
|
||||
|
||||
const osmium::object_id_type ref = opl_parse_id(&s);
|
||||
if (s == e) {
|
||||
builder.add_node_ref(ref);
|
||||
return;
|
||||
}
|
||||
|
||||
osmium::Location location;
|
||||
if (*s == 'x') {
|
||||
++s;
|
||||
location.set_lon_partial(&s);
|
||||
if (*s == 'y') {
|
||||
++s;
|
||||
location.set_lat_partial(&s);
|
||||
}
|
||||
}
|
||||
|
||||
builder.add_node_ref(ref, location);
|
||||
|
||||
if (s == e) {
|
||||
return;
|
||||
}
|
||||
|
||||
opl_parse_char(&s, ',');
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
const char* tags_begin = nullptr;
|
||||
|
||||
std::string user;
|
||||
osmium::Location location;
|
||||
while (**data) {
|
||||
opl_parse_space(data);
|
||||
const char c = **data;
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
++(*data);
|
||||
switch (c) {
|
||||
case 'v':
|
||||
node.set_version(opl_parse_version(data));
|
||||
break;
|
||||
case 'd':
|
||||
node.set_visible(opl_parse_visible(data));
|
||||
break;
|
||||
case 'c':
|
||||
node.set_changeset(opl_parse_changeset_id(data));
|
||||
break;
|
||||
case 't':
|
||||
node.set_timestamp(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'i':
|
||||
node.set_uid(opl_parse_uid(data));
|
||||
break;
|
||||
case 'u':
|
||||
opl_parse_string(data, user);
|
||||
break;
|
||||
case 'T':
|
||||
if (opl_non_empty(*data)) {
|
||||
tags_begin = *data;
|
||||
opl_skip_section(data);
|
||||
}
|
||||
break;
|
||||
case 'x':
|
||||
if (opl_non_empty(*data)) {
|
||||
location.set_lon_partial(data);
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
if (opl_non_empty(*data)) {
|
||||
location.set_lat_partial(data);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
--(*data);
|
||||
throw opl_error{"unknown attribute", *data};
|
||||
}
|
||||
}
|
||||
|
||||
if (location.valid()) {
|
||||
node.set_location(location);
|
||||
}
|
||||
|
||||
builder.add_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));
|
||||
|
||||
const char* tags_begin = nullptr;
|
||||
|
||||
const char* nodes_begin = nullptr;
|
||||
const char* nodes_end = nullptr;
|
||||
|
||||
std::string user;
|
||||
while (**data) {
|
||||
opl_parse_space(data);
|
||||
const char c = **data;
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
++(*data);
|
||||
switch (c) {
|
||||
case 'v':
|
||||
way.set_version(opl_parse_version(data));
|
||||
break;
|
||||
case 'd':
|
||||
way.set_visible(opl_parse_visible(data));
|
||||
break;
|
||||
case 'c':
|
||||
way.set_changeset(opl_parse_changeset_id(data));
|
||||
break;
|
||||
case 't':
|
||||
way.set_timestamp(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'i':
|
||||
way.set_uid(opl_parse_uid(data));
|
||||
break;
|
||||
case 'u':
|
||||
opl_parse_string(data, user);
|
||||
break;
|
||||
case 'T':
|
||||
if (opl_non_empty(*data)) {
|
||||
tags_begin = *data;
|
||||
opl_skip_section(data);
|
||||
}
|
||||
break;
|
||||
case 'N':
|
||||
nodes_begin = *data;
|
||||
nodes_end = opl_skip_section(data);
|
||||
break;
|
||||
default:
|
||||
--(*data);
|
||||
throw opl_error{"unknown attribute", *data};
|
||||
}
|
||||
}
|
||||
|
||||
builder.add_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) {
|
||||
if (s == e) {
|
||||
return;
|
||||
}
|
||||
osmium::builder::RelationMemberListBuilder builder{buffer, parent_builder};
|
||||
|
||||
while (s < e) {
|
||||
osmium::item_type type = osmium::char_to_item_type(*s);
|
||||
if (type != osmium::item_type::node &&
|
||||
type != osmium::item_type::way &&
|
||||
type != osmium::item_type::relation) {
|
||||
throw opl_error{"unknown object type", s};
|
||||
}
|
||||
++s;
|
||||
|
||||
if (s == e) {
|
||||
throw opl_error{"expected integer", s};
|
||||
}
|
||||
osmium::object_id_type ref = opl_parse_id(&s);
|
||||
opl_parse_char(&s, '@');
|
||||
if (s == e) {
|
||||
builder.add_member(type, ref, "");
|
||||
return;
|
||||
}
|
||||
std::string role;
|
||||
opl_parse_string(&s, role);
|
||||
builder.add_member(type, ref, role);
|
||||
|
||||
if (s == e) {
|
||||
return;
|
||||
}
|
||||
opl_parse_char(&s, ',');
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
const char* tags_begin = nullptr;
|
||||
|
||||
const char* members_begin = nullptr;
|
||||
const char* members_end = nullptr;
|
||||
|
||||
std::string user;
|
||||
while (**data) {
|
||||
opl_parse_space(data);
|
||||
const char c = **data;
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
++(*data);
|
||||
switch (c) {
|
||||
case 'v':
|
||||
relation.set_version(opl_parse_version(data));
|
||||
break;
|
||||
case 'd':
|
||||
relation.set_visible(opl_parse_visible(data));
|
||||
break;
|
||||
case 'c':
|
||||
relation.set_changeset(opl_parse_changeset_id(data));
|
||||
break;
|
||||
case 't':
|
||||
relation.set_timestamp(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'i':
|
||||
relation.set_uid(opl_parse_uid(data));
|
||||
break;
|
||||
case 'u':
|
||||
opl_parse_string(data, user);
|
||||
break;
|
||||
case 'T':
|
||||
if (opl_non_empty(*data)) {
|
||||
tags_begin = *data;
|
||||
opl_skip_section(data);
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
members_begin = *data;
|
||||
members_end = opl_skip_section(data);
|
||||
break;
|
||||
default:
|
||||
--(*data);
|
||||
throw opl_error{"unknown attribute", *data};
|
||||
}
|
||||
}
|
||||
|
||||
builder.add_user(user);
|
||||
|
||||
if (tags_begin) {
|
||||
opl_parse_tags(tags_begin, buffer, &builder);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
const char* tags_begin = nullptr;
|
||||
|
||||
osmium::Location location1;
|
||||
osmium::Location location2;
|
||||
std::string user;
|
||||
while (**data) {
|
||||
opl_parse_space(data);
|
||||
const char c = **data;
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
++(*data);
|
||||
switch (c) {
|
||||
case 'k':
|
||||
changeset.set_num_changes(opl_parse_int<osmium::num_changes_type>(data));
|
||||
break;
|
||||
case 's':
|
||||
changeset.set_created_at(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'e':
|
||||
changeset.set_closed_at(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'd':
|
||||
changeset.set_num_comments(opl_parse_int<osmium::num_comments_type>(data));
|
||||
break;
|
||||
case 'i':
|
||||
changeset.set_uid(opl_parse_uid(data));
|
||||
break;
|
||||
case 'u':
|
||||
opl_parse_string(data, user);
|
||||
break;
|
||||
case 'x':
|
||||
if (opl_non_empty(*data)) {
|
||||
location1.set_lon_partial(data);
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
if (opl_non_empty(*data)) {
|
||||
location1.set_lat_partial(data);
|
||||
}
|
||||
break;
|
||||
case 'X':
|
||||
if (opl_non_empty(*data)) {
|
||||
location2.set_lon_partial(data);
|
||||
}
|
||||
break;
|
||||
case 'Y':
|
||||
if (opl_non_empty(*data)) {
|
||||
location2.set_lat_partial(data);
|
||||
}
|
||||
break;
|
||||
case 'T':
|
||||
if (opl_non_empty(*data)) {
|
||||
tags_begin = *data;
|
||||
opl_skip_section(data);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
--(*data);
|
||||
throw opl_error{"unknown attribute", *data};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (location1.valid() && location2.valid()) {
|
||||
changeset.bounds().extend(location1);
|
||||
changeset.bounds().extend(location2);
|
||||
}
|
||||
|
||||
builder.add_user(user);
|
||||
|
||||
if (tags_begin) {
|
||||
opl_parse_tags(tags_begin, buffer, &builder);
|
||||
}
|
||||
|
||||
buffer.commit();
|
||||
}
|
||||
|
||||
inline bool opl_parse_line(uint64_t line_count,
|
||||
const char* data,
|
||||
osmium::memory::Buffer& buffer,
|
||||
osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) {
|
||||
const char* start_of_line = data;
|
||||
try {
|
||||
switch (*data) {
|
||||
case '\0':
|
||||
// ignore empty lines
|
||||
break;
|
||||
case '#':
|
||||
// ignore lines starting with #
|
||||
break;
|
||||
case 'n':
|
||||
if (read_types & osmium::osm_entity_bits::node) {
|
||||
++data;
|
||||
opl_parse_node(&data, buffer);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'w':
|
||||
if (read_types & osmium::osm_entity_bits::way) {
|
||||
++data;
|
||||
opl_parse_way(&data, buffer);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (read_types & osmium::osm_entity_bits::relation) {
|
||||
++data;
|
||||
opl_parse_relation(&data, buffer);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
if (read_types & osmium::osm_entity_bits::changeset) {
|
||||
++data;
|
||||
opl_parse_changeset(&data, buffer);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw opl_error{"unknown type", data};
|
||||
}
|
||||
} catch (opl_error& e) {
|
||||
e.set_pos(line_count, e.data ? e.data - start_of_line : 0);
|
||||
throw;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_OPL_PARSER_FUNCTIONS_HPP
|
@ -33,16 +33,16 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/handler.hpp>
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
#include <osmium/io/detail/string_util.hpp>
|
||||
#include <osmium/io/error.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
@ -70,9 +70,28 @@ namespace osmium {
|
||||
m_out(std::make_shared<std::string>()) {
|
||||
}
|
||||
|
||||
template <typename... TArgs>
|
||||
void output_formatted(const char* format, TArgs&&... args) {
|
||||
append_printf_formatted_string(*m_out, format, std::forward<TArgs>(args)...);
|
||||
// Simple function to convert integer to string. This is much
|
||||
// faster than using sprintf, but could be further optimized.
|
||||
// See https://github.com/miloyip/itoa-benchmark .
|
||||
void output_int(int64_t value) {
|
||||
if (value < 0) {
|
||||
*m_out += '-';
|
||||
value = -value;
|
||||
}
|
||||
|
||||
char temp[20];
|
||||
char *t = temp;
|
||||
do {
|
||||
*t++ = char(value % 10) + '0';
|
||||
value /= 10;
|
||||
} while (value > 0);
|
||||
|
||||
const auto old_size = m_out->size();
|
||||
m_out->resize(old_size + (t - temp));
|
||||
char* data = &(*m_out)[old_size];
|
||||
do {
|
||||
*data++ += *--t;
|
||||
} while (t != temp);
|
||||
}
|
||||
|
||||
}; // class OutputBlock;
|
||||
@ -133,11 +152,11 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, future_string_queue_type&)> create_output_type;
|
||||
using create_output_type = std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, future_string_queue_type&)>;
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<osmium::io::file_format, create_output_type> map_type;
|
||||
using map_type = std::map<osmium::io::file_format, create_output_type>;
|
||||
|
||||
map_type m_callbacks;
|
||||
|
||||
|
@ -78,7 +78,7 @@ namespace osmium {
|
||||
// between representation as double and as int
|
||||
const int64_t lonlat_resolution = 1000 * 1000 * 1000;
|
||||
|
||||
const int64_t resolution_convert = lonlat_resolution / osmium::Location::coordinate_precision;
|
||||
const int64_t resolution_convert = lonlat_resolution / osmium::detail::coordinate_precision;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
@ -33,10 +33,8 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
@ -44,35 +42,47 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <protozero/iterators.hpp>
|
||||
#include <protozero/pbf_message.hpp>
|
||||
#include <protozero/types.hpp>
|
||||
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
#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/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/util/cast.hpp>
|
||||
#include <osmium/util/delta.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace builder {
|
||||
class Builder;
|
||||
} // namespace builder
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
using ptr_len_type = std::pair<const char*, size_t>;
|
||||
using protozero::data_view;
|
||||
using osm_string_len_type = std::pair<const char*, osmium::string_size_type>;
|
||||
|
||||
class PBFPrimitiveBlockDecoder {
|
||||
|
||||
static constexpr size_t initial_buffer_size = 2 * 1024 * 1024;
|
||||
static constexpr const size_t initial_buffer_size = 2 * 1024 * 1024;
|
||||
|
||||
ptr_len_type m_data;
|
||||
data_view m_data;
|
||||
std::vector<osm_string_len_type> m_stringtable;
|
||||
|
||||
int64_t m_lon_offset = 0;
|
||||
@ -84,18 +94,18 @@ namespace osmium {
|
||||
|
||||
osmium::memory::Buffer m_buffer { initial_buffer_size };
|
||||
|
||||
void decode_stringtable(const ptr_len_type& data) {
|
||||
void decode_stringtable(const data_view& data) {
|
||||
if (!m_stringtable.empty()) {
|
||||
throw osmium::pbf_error("more than one stringtable in pbf file");
|
||||
}
|
||||
|
||||
protozero::pbf_message<OSMFormat::StringTable> pbf_string_table(data);
|
||||
while (pbf_string_table.next(OSMFormat::StringTable::repeated_bytes_s)) {
|
||||
auto str_len = pbf_string_table.get_data();
|
||||
if (str_len.second > osmium::max_osm_string_length) {
|
||||
const auto str_view = pbf_string_table.get_view();
|
||||
if (str_view.size() > osmium::max_osm_string_length) {
|
||||
throw osmium::pbf_error("overlong string in string table");
|
||||
}
|
||||
m_stringtable.emplace_back(str_len.first, osmium::string_size_type(str_len.second));
|
||||
m_stringtable.emplace_back(str_view.data(), osmium::string_size_type(str_view.size()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +114,7 @@ namespace osmium {
|
||||
while (pbf_primitive_block.next()) {
|
||||
switch (pbf_primitive_block.tag()) {
|
||||
case OSMFormat::PrimitiveBlock::required_StringTable_stringtable:
|
||||
decode_stringtable(pbf_primitive_block.get_data());
|
||||
decode_stringtable(pbf_primitive_block.get_view());
|
||||
break;
|
||||
case OSMFormat::PrimitiveBlock::optional_int32_granularity:
|
||||
m_granularity = pbf_primitive_block.get_int32();
|
||||
@ -132,28 +142,28 @@ namespace osmium {
|
||||
switch (pbf_primitive_group.tag()) {
|
||||
case OSMFormat::PrimitiveGroup::repeated_Node_nodes:
|
||||
if (m_read_types & osmium::osm_entity_bits::node) {
|
||||
decode_node(pbf_primitive_group.get_data());
|
||||
decode_node(pbf_primitive_group.get_view());
|
||||
} 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_data());
|
||||
decode_dense_nodes(pbf_primitive_group.get_view());
|
||||
} else {
|
||||
pbf_primitive_group.skip();
|
||||
}
|
||||
break;
|
||||
case OSMFormat::PrimitiveGroup::repeated_Way_ways:
|
||||
if (m_read_types & osmium::osm_entity_bits::way) {
|
||||
decode_way(pbf_primitive_group.get_data());
|
||||
decode_way(pbf_primitive_group.get_view());
|
||||
} else {
|
||||
pbf_primitive_group.skip();
|
||||
}
|
||||
break;
|
||||
case OSMFormat::PrimitiveGroup::repeated_Relation_relations:
|
||||
if (m_read_types & osmium::osm_entity_bits::relation) {
|
||||
decode_relation(pbf_primitive_group.get_data());
|
||||
decode_relation(pbf_primitive_group.get_view());
|
||||
} else {
|
||||
pbf_primitive_group.skip();
|
||||
}
|
||||
@ -165,7 +175,7 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
osm_string_len_type decode_info(const ptr_len_type& data, osmium::OSMObject& object) {
|
||||
osm_string_len_type decode_info(const data_view& data, osmium::OSMObject& object) {
|
||||
osm_string_len_type user = std::make_pair("", 0);
|
||||
|
||||
protozero::pbf_message<OSMFormat::Info> pbf_info(data);
|
||||
@ -173,7 +183,7 @@ namespace osmium {
|
||||
switch (pbf_info.tag()) {
|
||||
case OSMFormat::Info::optional_int32_version:
|
||||
{
|
||||
auto version = pbf_info.get_int32();
|
||||
const auto version = pbf_info.get_int32();
|
||||
if (version < 0) {
|
||||
throw osmium::pbf_error("object version must not be negative");
|
||||
}
|
||||
@ -185,7 +195,7 @@ namespace osmium {
|
||||
break;
|
||||
case OSMFormat::Info::optional_int64_changeset:
|
||||
{
|
||||
auto changeset_id = pbf_info.get_int64();
|
||||
const auto changeset_id = pbf_info.get_int64();
|
||||
if (changeset_id < 0) {
|
||||
throw osmium::pbf_error("object changeset_id must not be negative");
|
||||
}
|
||||
@ -209,15 +219,15 @@ namespace osmium {
|
||||
return user;
|
||||
}
|
||||
|
||||
using kv_type = std::pair<protozero::pbf_reader::const_uint32_iterator, protozero::pbf_reader::const_uint32_iterator>;
|
||||
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) {
|
||||
if (keys.first != keys.second) {
|
||||
if (!keys.empty()) {
|
||||
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
|
||||
auto kit = keys.first;
|
||||
auto vit = vals.first;
|
||||
while (kit != keys.second) {
|
||||
if (vit == vals.second) {
|
||||
auto kit = keys.begin();
|
||||
auto vit = vals.begin();
|
||||
while (kit != keys.end()) {
|
||||
if (vit == vals.end()) {
|
||||
// this is against the spec, must have same number of elements
|
||||
throw osmium::pbf_error("PBF format error");
|
||||
}
|
||||
@ -232,7 +242,7 @@ namespace osmium {
|
||||
return int32_t((c * m_granularity + m_lon_offset) / resolution_convert);
|
||||
}
|
||||
|
||||
void decode_node(const ptr_len_type& data) {
|
||||
void decode_node(const data_view& data) {
|
||||
osmium::builder::NodeBuilder builder(m_buffer);
|
||||
osmium::Node& node = builder.object();
|
||||
|
||||
@ -256,7 +266,7 @@ namespace osmium {
|
||||
vals = pbf_node.get_packed_uint32();
|
||||
break;
|
||||
case OSMFormat::Node::optional_Info_info:
|
||||
user = decode_info(pbf_node.get_data(), builder.object());
|
||||
user = decode_info(pbf_node.get_view(), builder.object());
|
||||
break;
|
||||
case OSMFormat::Node::required_sint64_lat:
|
||||
lat = pbf_node.get_sint64();
|
||||
@ -287,12 +297,14 @@ namespace osmium {
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
void decode_way(const ptr_len_type& data) {
|
||||
void decode_way(const data_view& data) {
|
||||
osmium::builder::WayBuilder builder(m_buffer);
|
||||
|
||||
kv_type keys;
|
||||
kv_type vals;
|
||||
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> refs;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> refs;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lats;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lons;
|
||||
|
||||
osm_string_len_type user = { "", 0 };
|
||||
|
||||
@ -309,11 +321,17 @@ namespace osmium {
|
||||
vals = pbf_way.get_packed_uint32();
|
||||
break;
|
||||
case OSMFormat::Way::optional_Info_info:
|
||||
user = decode_info(pbf_way.get_data(), builder.object());
|
||||
user = decode_info(pbf_way.get_view(), builder.object());
|
||||
break;
|
||||
case OSMFormat::Way::packed_sint64_refs:
|
||||
refs = pbf_way.get_packed_sint64();
|
||||
break;
|
||||
case OSMFormat::Way::packed_sint64_lat:
|
||||
lats = pbf_way.get_packed_sint64();
|
||||
break;
|
||||
case OSMFormat::Way::packed_sint64_lon:
|
||||
lons = pbf_way.get_packed_sint64();
|
||||
break;
|
||||
default:
|
||||
pbf_way.skip();
|
||||
}
|
||||
@ -321,11 +339,26 @@ namespace osmium {
|
||||
|
||||
builder.add_user(user.first, user.second);
|
||||
|
||||
if (refs.first != refs.second) {
|
||||
if (!refs.empty()) {
|
||||
osmium::builder::WayNodeListBuilder wnl_builder(m_buffer, &builder);
|
||||
osmium::util::DeltaDecode<int64_t> ref;
|
||||
while (refs.first != refs.second) {
|
||||
wnl_builder.add_node_ref(ref.update(*refs.first++));
|
||||
if (lats.empty()) {
|
||||
for (const auto& ref_value : refs) {
|
||||
wnl_builder.add_node_ref(ref.update(ref_value));
|
||||
}
|
||||
} else {
|
||||
osmium::util::DeltaDecode<int64_t> lon;
|
||||
osmium::util::DeltaDecode<int64_t> lat;
|
||||
while (!refs.empty() && !lons.empty() && !lats.empty()) {
|
||||
wnl_builder.add_node_ref(
|
||||
ref.update(refs.front()),
|
||||
osmium::Location{convert_pbf_coordinate(lon.update(lons.front())),
|
||||
convert_pbf_coordinate(lat.update(lats.front()))}
|
||||
);
|
||||
refs.drop_front();
|
||||
lons.drop_front();
|
||||
lats.drop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,14 +367,14 @@ namespace osmium {
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
void decode_relation(const ptr_len_type& data) {
|
||||
void decode_relation(const data_view& data) {
|
||||
osmium::builder::RelationBuilder builder(m_buffer);
|
||||
|
||||
kv_type keys;
|
||||
kv_type vals;
|
||||
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> roles;
|
||||
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> refs;
|
||||
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> types;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> roles;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> refs;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> types;
|
||||
|
||||
osm_string_len_type user = { "", 0 };
|
||||
|
||||
@ -358,7 +391,7 @@ namespace osmium {
|
||||
vals = pbf_relation.get_packed_uint32();
|
||||
break;
|
||||
case OSMFormat::Relation::optional_Info_info:
|
||||
user = decode_info(pbf_relation.get_data(), builder.object());
|
||||
user = decode_info(pbf_relation.get_view(), builder.object());
|
||||
break;
|
||||
case OSMFormat::Relation::packed_int32_roles_sid:
|
||||
roles = pbf_relation.get_packed_int32();
|
||||
@ -376,21 +409,24 @@ namespace osmium {
|
||||
|
||||
builder.add_user(user.first, user.second);
|
||||
|
||||
if (refs.first != refs.second) {
|
||||
if (!refs.empty()) {
|
||||
osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder);
|
||||
osmium::util::DeltaDecode<int64_t> ref;
|
||||
while (roles.first != roles.second && refs.first != refs.second && types.first != types.second) {
|
||||
const auto& r = m_stringtable.at(*roles.first++);
|
||||
int type = *types.first++;
|
||||
while (!roles.empty() && !refs.empty() && !types.empty()) {
|
||||
const auto& r = m_stringtable.at(roles.front());
|
||||
const int type = types.front();
|
||||
if (type < 0 || type > 2) {
|
||||
throw osmium::pbf_error("unknown relation member type");
|
||||
}
|
||||
rml_builder.add_member(
|
||||
osmium::item_type(type + 1),
|
||||
ref.update(*refs.first++),
|
||||
ref.update(refs.front()),
|
||||
r.first,
|
||||
r.second
|
||||
);
|
||||
roles.drop_front();
|
||||
refs.drop_front();
|
||||
types.drop_front();
|
||||
}
|
||||
}
|
||||
|
||||
@ -399,22 +435,22 @@ namespace osmium {
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
void decode_dense_nodes(const ptr_len_type& data) {
|
||||
void decode_dense_nodes(const data_view& data) {
|
||||
bool has_info = false;
|
||||
bool has_visibles = false;
|
||||
|
||||
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> ids;
|
||||
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> lats;
|
||||
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> lons;
|
||||
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;
|
||||
|
||||
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> tags;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> tags;
|
||||
|
||||
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> versions;
|
||||
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> timestamps;
|
||||
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> changesets;
|
||||
std::pair<protozero::pbf_reader::const_sint32_iterator, protozero::pbf_reader::const_sint32_iterator> uids;
|
||||
std::pair<protozero::pbf_reader::const_sint32_iterator, protozero::pbf_reader::const_sint32_iterator> user_sids;
|
||||
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> visibles;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> versions;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> timestamps;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> changesets;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint32_iterator> uids;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint32_iterator> user_sids;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> visibles;
|
||||
|
||||
protozero::pbf_message<OSMFormat::DenseNodes> pbf_dense_nodes(data);
|
||||
while (pbf_dense_nodes.next()) {
|
||||
@ -475,11 +511,11 @@ namespace osmium {
|
||||
osmium::util::DeltaDecode<int64_t> dense_changeset;
|
||||
osmium::util::DeltaDecode<int64_t> dense_timestamp;
|
||||
|
||||
auto tag_it = tags.first;
|
||||
auto tag_it = tags.begin();
|
||||
|
||||
while (ids.first != ids.second) {
|
||||
if (lons.first == lons.second ||
|
||||
lats.first == lats.second) {
|
||||
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");
|
||||
}
|
||||
@ -489,43 +525,50 @@ namespace osmium {
|
||||
osmium::builder::NodeBuilder builder(m_buffer);
|
||||
osmium::Node& node = builder.object();
|
||||
|
||||
node.set_id(dense_id.update(*ids.first++));
|
||||
node.set_id(dense_id.update(ids.front()));
|
||||
ids.drop_front();
|
||||
|
||||
if (has_info) {
|
||||
if (versions.first == versions.second ||
|
||||
changesets.first == changesets.second ||
|
||||
timestamps.first == timestamps.second ||
|
||||
uids.first == uids.second ||
|
||||
user_sids.first == user_sids.second) {
|
||||
if (versions.empty() ||
|
||||
changesets.empty() ||
|
||||
timestamps.empty() ||
|
||||
uids.empty() ||
|
||||
user_sids.empty()) {
|
||||
// this is against the spec, must have same number of elements
|
||||
throw osmium::pbf_error("PBF format error");
|
||||
}
|
||||
|
||||
auto version = *versions.first++;
|
||||
const auto version = versions.front();
|
||||
versions.drop_front();
|
||||
if (version < 0) {
|
||||
throw osmium::pbf_error("object version must not be negative");
|
||||
}
|
||||
node.set_version(static_cast<osmium::object_version_type>(version));
|
||||
|
||||
auto changeset_id = dense_changeset.update(*changesets.first++);
|
||||
const auto changeset_id = dense_changeset.update(changesets.front());
|
||||
changesets.drop_front();
|
||||
if (changeset_id < 0) {
|
||||
throw osmium::pbf_error("object changeset_id must not be negative");
|
||||
}
|
||||
node.set_changeset(static_cast<osmium::changeset_id_type>(changeset_id));
|
||||
|
||||
node.set_timestamp(dense_timestamp.update(*timestamps.first++) * m_date_factor / 1000);
|
||||
node.set_uid_from_signed(static_cast<osmium::signed_user_id_type>(dense_uid.update(*uids.first++)));
|
||||
node.set_timestamp(dense_timestamp.update(timestamps.front()) * m_date_factor / 1000);
|
||||
timestamps.drop_front();
|
||||
node.set_uid_from_signed(static_cast<osmium::signed_user_id_type>(dense_uid.update(uids.front())));
|
||||
uids.drop_front();
|
||||
|
||||
if (has_visibles) {
|
||||
if (visibles.first == visibles.second) {
|
||||
if (visibles.empty()) {
|
||||
// this is against the spec, must have same number of elements
|
||||
throw osmium::pbf_error("PBF format error");
|
||||
}
|
||||
visible = (*visibles.first++) != 0;
|
||||
visible = (visibles.front() != 0);
|
||||
visibles.drop_front();
|
||||
}
|
||||
node.set_visible(visible);
|
||||
|
||||
const auto& u = m_stringtable.at(dense_user_sid.update(*user_sids.first++));
|
||||
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("");
|
||||
@ -533,8 +576,10 @@ namespace osmium {
|
||||
|
||||
// even if the node isn't visible, there's still a record
|
||||
// of its lat/lon in the dense arrays.
|
||||
const auto lon = dense_longitude.update(*lons.first++);
|
||||
const auto lat = dense_latitude.update(*lats.first++);
|
||||
const auto lon = dense_longitude.update(lons.front());
|
||||
lons.drop_front();
|
||||
const auto lat = dense_latitude.update(lats.front());
|
||||
lats.drop_front();
|
||||
if (visible) {
|
||||
builder.object().set_location(osmium::Location(
|
||||
convert_pbf_coordinate(lon),
|
||||
@ -542,18 +587,18 @@ namespace osmium {
|
||||
));
|
||||
}
|
||||
|
||||
if (tag_it != tags.second) {
|
||||
if (tag_it != tags.end()) {
|
||||
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
|
||||
while (tag_it != tags.second && *tag_it != 0) {
|
||||
while (tag_it != tags.end() && *tag_it != 0) {
|
||||
const auto& k = m_stringtable.at(*tag_it++);
|
||||
if (tag_it == tags.second) {
|
||||
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.second) {
|
||||
if (tag_it != tags.end()) {
|
||||
++tag_it;
|
||||
}
|
||||
}
|
||||
@ -565,7 +610,7 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
PBFPrimitiveBlockDecoder(const ptr_len_type& data, osmium::osm_entity_bits::type read_types) :
|
||||
PBFPrimitiveBlockDecoder(const data_view& data, osmium::osm_entity_bits::type read_types) :
|
||||
m_data(data),
|
||||
m_read_types(read_types) {
|
||||
}
|
||||
@ -582,7 +627,7 @@ namespace osmium {
|
||||
try {
|
||||
decode_primitive_block_metadata();
|
||||
decode_primitive_block_data();
|
||||
} catch (std::out_of_range&) {
|
||||
} catch (const std::out_of_range&) {
|
||||
throw osmium::pbf_error("string id out of range");
|
||||
}
|
||||
|
||||
@ -591,17 +636,17 @@ namespace osmium {
|
||||
|
||||
}; // class PBFPrimitiveBlockDecoder
|
||||
|
||||
inline ptr_len_type decode_blob(const std::string& blob_data, std::string& output) {
|
||||
inline data_view decode_blob(const std::string& blob_data, std::string& output) {
|
||||
int32_t raw_size = 0;
|
||||
std::pair<const char*, protozero::pbf_length_type> zlib_data = {nullptr, 0};
|
||||
protozero::data_view zlib_data;
|
||||
|
||||
protozero::pbf_message<FileFormat::Blob> pbf_blob(blob_data);
|
||||
while (pbf_blob.next()) {
|
||||
switch (pbf_blob.tag()) {
|
||||
case FileFormat::Blob::optional_bytes_raw:
|
||||
{
|
||||
auto data_len = pbf_blob.get_data();
|
||||
if (data_len.second > max_uncompressed_blob_size) {
|
||||
auto data_len = pbf_blob.get_view();
|
||||
if (data_len.size() > max_uncompressed_blob_size) {
|
||||
throw osmium::pbf_error("illegal blob size");
|
||||
}
|
||||
return data_len;
|
||||
@ -613,7 +658,7 @@ namespace osmium {
|
||||
}
|
||||
break;
|
||||
case FileFormat::Blob::optional_bytes_zlib_data:
|
||||
zlib_data = pbf_blob.get_data();
|
||||
zlib_data = pbf_blob.get_view();
|
||||
break;
|
||||
case FileFormat::Blob::optional_bytes_lzma_data:
|
||||
throw osmium::pbf_error("lzma blobs not implemented");
|
||||
@ -622,10 +667,10 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
if (zlib_data.second != 0 && raw_size != 0) {
|
||||
if (zlib_data.size() != 0 && raw_size != 0) {
|
||||
return osmium::io::detail::zlib_uncompress_string(
|
||||
zlib_data.first,
|
||||
static_cast<unsigned long>(zlib_data.second),
|
||||
zlib_data.data(),
|
||||
static_cast<unsigned long>(zlib_data.size()),
|
||||
static_cast<unsigned long>(raw_size),
|
||||
output
|
||||
);
|
||||
@ -634,7 +679,7 @@ namespace osmium {
|
||||
throw osmium::pbf_error("blob contains no data");
|
||||
}
|
||||
|
||||
inline osmium::Box decode_header_bbox(const ptr_len_type& data) {
|
||||
inline osmium::Box decode_header_bbox(const data_view& data) {
|
||||
int64_t left = std::numeric_limits<int64_t>::max();
|
||||
int64_t right = std::numeric_limits<int64_t>::max();
|
||||
int64_t top = std::numeric_limits<int64_t>::max();
|
||||
@ -674,7 +719,7 @@ namespace osmium {
|
||||
return box;
|
||||
}
|
||||
|
||||
inline osmium::io::Header decode_header_block(const ptr_len_type& data) {
|
||||
inline osmium::io::Header decode_header_block(const data_view& data) {
|
||||
osmium::io::Header header;
|
||||
int i = 0;
|
||||
|
||||
@ -682,20 +727,20 @@ namespace osmium {
|
||||
while (pbf_header_block.next()) {
|
||||
switch (pbf_header_block.tag()) {
|
||||
case OSMFormat::HeaderBlock::optional_HeaderBBox_bbox:
|
||||
header.add_box(decode_header_bbox(pbf_header_block.get_data()));
|
||||
header.add_box(decode_header_bbox(pbf_header_block.get_view()));
|
||||
break;
|
||||
case OSMFormat::HeaderBlock::repeated_string_required_features:
|
||||
{
|
||||
auto feature = pbf_header_block.get_data();
|
||||
if (!strncmp("OsmSchema-V0.6", feature.first, feature.second)) {
|
||||
auto feature = pbf_header_block.get_view();
|
||||
if (!std::strncmp("OsmSchema-V0.6", feature.data(), feature.size())) {
|
||||
// intentionally left blank
|
||||
} else if (!strncmp("DenseNodes", feature.first, feature.second)) {
|
||||
} else if (!std::strncmp("DenseNodes", feature.data(), feature.size())) {
|
||||
header.set("pbf_dense_nodes", true);
|
||||
} else if (!strncmp("HistoricalInformation", feature.first, feature.second)) {
|
||||
} else if (!std::strncmp("HistoricalInformation", feature.data(), feature.size())) {
|
||||
header.set_has_multiple_object_versions(true);
|
||||
} else {
|
||||
std::string msg("required feature not supported: ");
|
||||
msg.append(feature.first, feature.second);
|
||||
msg.append(feature.data(), feature.size());
|
||||
throw osmium::pbf_error(msg);
|
||||
}
|
||||
}
|
||||
@ -708,7 +753,7 @@ namespace osmium {
|
||||
break;
|
||||
case OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp:
|
||||
{
|
||||
auto timestamp = osmium::Timestamp(pbf_header_block.get_int64()).to_iso();
|
||||
const auto timestamp = osmium::Timestamp(pbf_header_block.get_int64()).to_iso();
|
||||
header.set("osmosis_replication_timestamp", timestamp);
|
||||
header.set("timestamp", timestamp);
|
||||
}
|
||||
|
@ -38,25 +38,22 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
|
||||
#include <protozero/pbf_message.hpp>
|
||||
#include <protozero/types.hpp>
|
||||
|
||||
#include <osmium/io/detail/input_format.hpp>
|
||||
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/detail/pbf_decoder.hpp>
|
||||
#include <osmium/io/detail/protobuf_tags.hpp>
|
||||
#include <osmium/io/error.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/osm.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/thread/pool.hpp>
|
||||
#include <osmium/thread/util.hpp>
|
||||
#include <osmium/util/config.hpp>
|
||||
@ -80,7 +77,7 @@ namespace osmium {
|
||||
*/
|
||||
std::string read_from_input_queue(size_t size) {
|
||||
while (m_input_buffer.size() < size) {
|
||||
std::string new_data = get_input();
|
||||
const std::string new_data = get_input();
|
||||
if (input_done()) {
|
||||
throw osmium::pbf_error("truncated data (EOF encountered)");
|
||||
}
|
||||
@ -106,7 +103,7 @@ namespace osmium {
|
||||
try {
|
||||
const std::string input_data = read_from_input_queue(sizeof(size_in_network_byte_order));
|
||||
size_in_network_byte_order = *reinterpret_cast<const uint32_t*>(input_data.data());
|
||||
} catch (osmium::pbf_error&) {
|
||||
} catch (const osmium::pbf_error&) {
|
||||
return 0; // EOF
|
||||
}
|
||||
|
||||
@ -123,13 +120,13 @@ namespace osmium {
|
||||
* type. Return the size of the following Blob.
|
||||
*/
|
||||
size_t decode_blob_header(protozero::pbf_message<FileFormat::BlobHeader>&& pbf_blob_header, const char* expected_type) {
|
||||
std::pair<const char*, size_t> blob_header_type;
|
||||
protozero::data_view blob_header_type;
|
||||
size_t blob_header_datasize = 0;
|
||||
|
||||
while (pbf_blob_header.next()) {
|
||||
switch (pbf_blob_header.tag()) {
|
||||
case FileFormat::BlobHeader::required_string_type:
|
||||
blob_header_type = pbf_blob_header.get_data();
|
||||
blob_header_type = pbf_blob_header.get_view();
|
||||
break;
|
||||
case FileFormat::BlobHeader::required_int32_datasize:
|
||||
blob_header_datasize = pbf_blob_header.get_int32();
|
||||
@ -143,7 +140,7 @@ namespace osmium {
|
||||
throw osmium::pbf_error("PBF format error: BlobHeader.datasize missing or zero.");
|
||||
}
|
||||
|
||||
if (strncmp(expected_type, blob_header_type.first, blob_header_type.second)) {
|
||||
if (std::strncmp(expected_type, blob_header_type.data(), blob_header_type.size())) {
|
||||
throw osmium::pbf_error("blob does not have expected type (OSMHeader in first blob, OSMData in following blobs)");
|
||||
}
|
||||
|
||||
|
@ -41,30 +41,34 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
#include <utility>
|
||||
|
||||
#include <protozero/pbf_builder.hpp>
|
||||
#include <protozero/pbf_writer.hpp>
|
||||
#include <protozero/types.hpp>
|
||||
|
||||
#include <osmium/handler.hpp>
|
||||
#include <osmium/io/detail/output_format.hpp>
|
||||
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/detail/protobuf_tags.hpp>
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
#include <osmium/io/detail/string_table.hpp>
|
||||
#include <osmium/io/detail/zlib.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/memory/collection.hpp>
|
||||
#include <osmium/memory/item_iterator.hpp>
|
||||
#include <osmium/osm/box.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/relation.hpp>
|
||||
#include <osmium/osm/tag.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/thread/pool.hpp>
|
||||
#include <osmium/util/cast.hpp>
|
||||
@ -101,6 +105,9 @@ namespace osmium {
|
||||
/// Should the visible flag be added to all OSM objects?
|
||||
bool add_visible_flag;
|
||||
|
||||
/// Should node locations be added to ways?
|
||||
bool locations_on_ways;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@ -483,6 +490,7 @@ namespace osmium {
|
||||
m_options.add_metadata = file.is_not_false("pbf_add_metadata") && file.is_not_false("add_metadata");
|
||||
m_options.add_historical_information_flag = file.has_multiple_object_versions();
|
||||
m_options.add_visible_flag = file.has_multiple_object_versions();
|
||||
m_options.locations_on_ways = file.is_true("locations_on_ways");
|
||||
}
|
||||
|
||||
PBFOutputFormat(const PBFOutputFormat&) = delete;
|
||||
@ -514,20 +522,24 @@ namespace osmium {
|
||||
pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_required_features, "HistoricalInformation");
|
||||
}
|
||||
|
||||
if (m_options.locations_on_ways) {
|
||||
pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_optional_features, "LocationsOnWays");
|
||||
}
|
||||
|
||||
pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_writingprogram, header.get("generator"));
|
||||
|
||||
std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp");
|
||||
const std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp");
|
||||
if (!osmosis_replication_timestamp.empty()) {
|
||||
osmium::Timestamp ts(osmosis_replication_timestamp.c_str());
|
||||
pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp, uint32_t(ts));
|
||||
}
|
||||
|
||||
std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number");
|
||||
const std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number");
|
||||
if (!osmosis_replication_sequence_number.empty()) {
|
||||
pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_sequence_number, std::atoll(osmosis_replication_sequence_number.c_str()));
|
||||
}
|
||||
|
||||
std::string osmosis_replication_base_url = header.get("osmosis_replication_base_url");
|
||||
const std::string osmosis_replication_base_url = header.get("osmosis_replication_base_url");
|
||||
if (!osmosis_replication_base_url.empty()) {
|
||||
pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_osmosis_replication_base_url, osmosis_replication_base_url);
|
||||
}
|
||||
@ -571,15 +583,30 @@ namespace osmium {
|
||||
pbf_way.add_int64(OSMFormat::Way::required_int64_id, way.id());
|
||||
add_meta(way, pbf_way);
|
||||
|
||||
static auto map_node_ref = [](osmium::NodeRefList::const_iterator node_ref) noexcept -> osmium::object_id_type {
|
||||
return node_ref->ref();
|
||||
};
|
||||
typedef osmium::util::DeltaEncodeIterator<osmium::NodeRefList::const_iterator, decltype(map_node_ref), osmium::object_id_type> it_type;
|
||||
{
|
||||
osmium::util::DeltaEncode<object_id_type, int64_t> delta_id;
|
||||
protozero::packed_field_sint64 field{pbf_way, protozero::pbf_tag_type(OSMFormat::Way::packed_sint64_refs)};
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
field.add_element(delta_id.update(node_ref.ref()));
|
||||
}
|
||||
}
|
||||
|
||||
const auto& nodes = way.nodes();
|
||||
it_type first { nodes.cbegin(), nodes.cend(), map_node_ref };
|
||||
it_type last { nodes.cend(), nodes.cend(), map_node_ref };
|
||||
pbf_way.add_packed_sint64(OSMFormat::Way::packed_sint64_refs, first, last);
|
||||
if (m_options.locations_on_ways) {
|
||||
{
|
||||
osmium::util::DeltaEncode<int64_t, int64_t> delta_id;
|
||||
protozero::packed_field_sint64 field{pbf_way, protozero::pbf_tag_type(OSMFormat::Way::packed_sint64_lon)};
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
field.add_element(delta_id.update(lonlat2int(node_ref.location().lon_without_check())));
|
||||
}
|
||||
}
|
||||
{
|
||||
osmium::util::DeltaEncode<int64_t, int64_t> delta_id;
|
||||
protozero::packed_field_sint64 field{pbf_way, protozero::pbf_tag_type(OSMFormat::Way::packed_sint64_lat)};
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
field.add_element(delta_id.update(lonlat2int(node_ref.location().lat_without_check())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void relation(const osmium::Relation& relation) {
|
||||
@ -596,14 +623,13 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
static auto map_member_ref = [](osmium::RelationMemberList::const_iterator member) noexcept -> osmium::object_id_type {
|
||||
return member->ref();
|
||||
};
|
||||
typedef osmium::util::DeltaEncodeIterator<osmium::RelationMemberList::const_iterator, decltype(map_member_ref), osmium::object_id_type> it_type;
|
||||
const auto& members = relation.members();
|
||||
it_type first { members.cbegin(), members.cend(), map_member_ref };
|
||||
it_type last { members.cend(), members.cend(), map_member_ref };
|
||||
pbf_relation.add_packed_sint64(OSMFormat::Relation::packed_sint64_memids, first, last);
|
||||
{
|
||||
osmium::util::DeltaEncode<object_id_type, int64_t> delta_id;
|
||||
protozero::packed_field_sint64 field{pbf_relation, protozero::pbf_tag_type(OSMFormat::Relation::packed_sint64_memids)};
|
||||
for (const auto& member : relation.members()) {
|
||||
field.add_element(delta_id.update(member.ref()));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
protozero::packed_field_int32 field{pbf_relation, protozero::pbf_tag_type(OSMFormat::Relation::packed_MemberType_types)};
|
||||
|
@ -146,7 +146,9 @@ namespace osmium {
|
||||
packed_uint32_keys = 2,
|
||||
packed_uint32_vals = 3,
|
||||
optional_Info_info = 4,
|
||||
packed_sint64_refs = 8
|
||||
packed_sint64_refs = 8,
|
||||
packed_sint64_lat = 9,
|
||||
packed_sint64_lon = 10
|
||||
};
|
||||
|
||||
enum class Relation : protozero::pbf_tag_type {
|
||||
|
@ -47,6 +47,9 @@ namespace osmium {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
using future_queue_type = osmium::thread::Queue<std::future<T>>;
|
||||
|
||||
/**
|
||||
* This type of queue contains buffers with OSM data in them.
|
||||
* The "end of file" is marked by an invalid Buffer.
|
||||
@ -54,7 +57,7 @@ namespace osmium {
|
||||
* transport exceptions. The future also helps with keeping the
|
||||
* data in order.
|
||||
*/
|
||||
using future_buffer_queue_type = osmium::thread::Queue<std::future<osmium::memory::Buffer>>;
|
||||
using future_buffer_queue_type = future_queue_type<osmium::memory::Buffer>;
|
||||
|
||||
/**
|
||||
* This type of queue contains OSM file data in the form it is
|
||||
@ -71,24 +74,24 @@ namespace osmium {
|
||||
* transport exceptions. The future also helps with keeping the
|
||||
* data in order.
|
||||
*/
|
||||
using future_string_queue_type = osmium::thread::Queue<std::future<std::string>>;
|
||||
using future_string_queue_type = future_queue_type<std::string>;
|
||||
|
||||
template <typename T>
|
||||
inline void add_to_queue(osmium::thread::Queue<std::future<T>>& queue, T&& data) {
|
||||
inline void add_to_queue(future_queue_type<T>& queue, T&& data) {
|
||||
std::promise<T> promise;
|
||||
queue.push(promise.get_future());
|
||||
promise.set_value(std::forward<T>(data));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void add_to_queue(osmium::thread::Queue<std::future<T>>& queue, std::exception_ptr&& exception) {
|
||||
inline void add_to_queue(future_queue_type<T>& queue, std::exception_ptr&& exception) {
|
||||
std::promise<T> promise;
|
||||
queue.push(promise.get_future());
|
||||
promise.set_exception(std::move(exception));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void add_end_of_data_to_queue(osmium::thread::Queue<std::future<T>>& queue) {
|
||||
inline void add_end_of_data_to_queue(future_queue_type<T>& queue) {
|
||||
add_to_queue<T>(queue, T{});
|
||||
}
|
||||
|
||||
@ -103,14 +106,12 @@ namespace osmium {
|
||||
template <typename T>
|
||||
class queue_wrapper {
|
||||
|
||||
using queue_type = osmium::thread::Queue<std::future<T>>;
|
||||
|
||||
queue_type& m_queue;
|
||||
future_queue_type<T>& m_queue;
|
||||
bool m_has_reached_end_of_data;
|
||||
|
||||
public:
|
||||
|
||||
explicit queue_wrapper(queue_type& queue) :
|
||||
explicit queue_wrapper(future_queue_type<T>& queue) :
|
||||
m_queue(queue),
|
||||
m_has_reached_end_of_data(false) {
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
@ -84,7 +83,7 @@ namespace osmium {
|
||||
#ifdef _WIN32
|
||||
flags |= O_BINARY;
|
||||
#endif
|
||||
int fd = ::open(filename.c_str(), flags, 0666);
|
||||
const int fd = ::open(filename.c_str(), flags, 0666);
|
||||
if (fd < 0) {
|
||||
throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
|
||||
}
|
||||
@ -108,7 +107,7 @@ namespace osmium {
|
||||
#ifdef _WIN32
|
||||
flags |= O_BINARY;
|
||||
#endif
|
||||
int fd = ::open(filename.c_str(), flags);
|
||||
const int fd = ::open(filename.c_str(), flags);
|
||||
if (fd < 0) {
|
||||
throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
|
||||
}
|
||||
@ -133,7 +132,7 @@ namespace osmium {
|
||||
if (write_count > max_write) {
|
||||
write_count = max_write;
|
||||
}
|
||||
auto length = ::write(fd, output_buffer + offset, static_cast<unsigned int>(write_count));
|
||||
const auto length = ::write(fd, output_buffer + offset, static_cast<unsigned int>(write_count));
|
||||
if (length < 0) {
|
||||
throw std::system_error(errno, std::system_category(), "Write failed");
|
||||
}
|
||||
|
@ -34,13 +34,14 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/io/detail/pbf.hpp>
|
||||
|
||||
@ -69,8 +70,8 @@ namespace osmium {
|
||||
std::list<std::string> m_chunks;
|
||||
|
||||
void add_chunk() {
|
||||
m_chunks.push_front(std::string());
|
||||
m_chunks.front().reserve(m_chunk_size);
|
||||
m_chunks.emplace_back();
|
||||
m_chunks.back().reserve(m_chunk_size);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -82,6 +83,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void clear() noexcept {
|
||||
assert(!m_chunks.empty());
|
||||
m_chunks.erase(std::next(m_chunks.begin()), m_chunks.end());
|
||||
m_chunks.front().clear();
|
||||
}
|
||||
@ -93,31 +95,38 @@ namespace osmium {
|
||||
* allocated.
|
||||
*/
|
||||
const char* add(const char* string) {
|
||||
size_t len = std::strlen(string) + 1;
|
||||
const size_t len = std::strlen(string) + 1;
|
||||
|
||||
assert(len <= m_chunk_size);
|
||||
|
||||
size_t chunk_len = m_chunks.front().size();
|
||||
if (chunk_len + len > m_chunks.front().capacity()) {
|
||||
size_t chunk_len = m_chunks.back().size();
|
||||
if (chunk_len + len > m_chunks.back().capacity()) {
|
||||
add_chunk();
|
||||
chunk_len = 0;
|
||||
}
|
||||
|
||||
m_chunks.front().append(string);
|
||||
m_chunks.front().append(1, '\0');
|
||||
m_chunks.back().append(string);
|
||||
m_chunks.back().append(1, '\0');
|
||||
|
||||
return m_chunks.front().c_str() + chunk_len;
|
||||
return m_chunks.back().c_str() + chunk_len;
|
||||
}
|
||||
|
||||
class const_iterator : public std::iterator<std::forward_iterator_tag, const char*> {
|
||||
class const_iterator {
|
||||
|
||||
using it_type = std::list<std::string>::const_iterator;
|
||||
|
||||
typedef std::list<std::string>::const_iterator it_type;
|
||||
it_type m_it;
|
||||
const it_type m_last;
|
||||
const char* m_pos;
|
||||
|
||||
public:
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = const char*;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
const_iterator(it_type it, it_type last) :
|
||||
m_it(it),
|
||||
m_last(last),
|
||||
@ -126,7 +135,7 @@ namespace osmium {
|
||||
|
||||
const_iterator& operator++() {
|
||||
assert(m_it != m_last);
|
||||
auto last_pos = m_it->c_str() + m_it->size();
|
||||
const auto last_pos = m_it->c_str() + m_it->size();
|
||||
while (m_pos != last_pos && *m_pos) ++m_pos;
|
||||
if (m_pos != last_pos) ++m_pos;
|
||||
if (m_pos == last_pos) {
|
||||
@ -184,18 +193,33 @@ namespace osmium {
|
||||
}
|
||||
|
||||
size_t get_used_bytes_in_last_chunk() const noexcept {
|
||||
return m_chunks.front().size();
|
||||
return m_chunks.back().size();
|
||||
}
|
||||
|
||||
}; // class StringStore
|
||||
|
||||
struct StrComp {
|
||||
struct str_equal {
|
||||
|
||||
bool operator()(const char* lhs, const char* rhs) const {
|
||||
return strcmp(lhs, rhs) < 0;
|
||||
bool operator()(const char* lhs, const char* rhs) const noexcept {
|
||||
return lhs == rhs || std::strcmp(lhs, rhs) == 0;
|
||||
}
|
||||
|
||||
}; // struct StrComp
|
||||
}; // struct str_equal
|
||||
|
||||
struct djb2_hash {
|
||||
|
||||
size_t operator()(const char* str) const noexcept {
|
||||
size_t hash = 5381;
|
||||
int c;
|
||||
|
||||
while ((c = *str++)) {
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
}; // struct djb2_hash
|
||||
|
||||
class StringTable {
|
||||
|
||||
@ -206,14 +230,23 @@ namespace osmium {
|
||||
// Blob.
|
||||
static constexpr const uint32_t max_entries = max_uncompressed_blob_size;
|
||||
|
||||
// There is one string table per PBF primitive block. Most of
|
||||
// them are really small, because most blocks are full of nodes
|
||||
// with no tags. But string tables can get really large for
|
||||
// ways with many tags or for large relations.
|
||||
// The chosen size is enough so that 99% of all string tables
|
||||
// in typical OSM files will only need a single memory
|
||||
// allocation.
|
||||
static constexpr const size_t default_stringtable_chunk_size = 100 * 1024;
|
||||
|
||||
StringStore m_strings;
|
||||
std::map<const char*, size_t, StrComp> m_index;
|
||||
std::unordered_map<const char*, size_t, djb2_hash, str_equal> m_index;
|
||||
uint32_t m_size;
|
||||
|
||||
public:
|
||||
|
||||
StringTable() :
|
||||
m_strings(1024 * 1024),
|
||||
explicit StringTable(size_t size = default_stringtable_chunk_size) :
|
||||
m_strings(size),
|
||||
m_index(),
|
||||
m_size(0) {
|
||||
m_strings.add("");
|
||||
@ -231,7 +264,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
uint32_t add(const char* s) {
|
||||
auto f = m_index.find(s);
|
||||
const auto f = m_index.find(s);
|
||||
if (f != m_index.end()) {
|
||||
return uint32_t(f->second);
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@ -100,9 +101,9 @@ namespace osmium {
|
||||
static const size_t max_size = 0;
|
||||
#endif
|
||||
|
||||
size_t old_size = out.size();
|
||||
const size_t old_size = out.size();
|
||||
|
||||
int len = string_snprintf(out,
|
||||
const int len = string_snprintf(out,
|
||||
old_size,
|
||||
max_size,
|
||||
format,
|
||||
@ -111,7 +112,7 @@ namespace osmium {
|
||||
|
||||
if (size_t(len) >= max_size) {
|
||||
#ifndef NDEBUG
|
||||
int len2 =
|
||||
const int len2 =
|
||||
#endif
|
||||
string_snprintf(out,
|
||||
old_size,
|
||||
@ -124,12 +125,33 @@ namespace osmium {
|
||||
out.resize(old_size + size_t(len));
|
||||
}
|
||||
|
||||
// Write out the value with exactly two hex digits.
|
||||
inline void append_2_hex_digits(std::string& out, uint32_t value, const char* const hex_digits) {
|
||||
out += hex_digits[(value >> 4) & 0xf];
|
||||
out += hex_digits[ value & 0xf];
|
||||
}
|
||||
|
||||
// Write out the value with four or more hex digits.
|
||||
inline void append_min_4_hex_digits(std::string& out, uint32_t value, const char* const hex_digits) {
|
||||
auto
|
||||
v = value & 0xf0000000; if (v) out += hex_digits[v >> 28];
|
||||
v = value & 0x0f000000; if (v) out += hex_digits[v >> 24];
|
||||
v = value & 0x00f00000; if (v) out += hex_digits[v >> 20];
|
||||
v = value & 0x000f0000; if (v) out += hex_digits[v >> 16];
|
||||
|
||||
out += hex_digits[(value >> 12) & 0xf];
|
||||
out += hex_digits[(value >> 8) & 0xf];
|
||||
out += hex_digits[(value >> 4) & 0xf];
|
||||
out += hex_digits[ value & 0xf];
|
||||
}
|
||||
|
||||
inline void append_utf8_encoded_string(std::string& out, const char* data) {
|
||||
static const char* lookup_hex = "0123456789abcdef";
|
||||
const char* end = data + std::strlen(data);
|
||||
|
||||
while (data != end) {
|
||||
const char* last = data;
|
||||
uint32_t c = utf8::next(data, end);
|
||||
const uint32_t c = utf8::next(data, end);
|
||||
|
||||
// This is a list of Unicode code points that we let
|
||||
// through instead of escaping them. It is incomplete
|
||||
@ -148,9 +170,9 @@ namespace osmium {
|
||||
} else {
|
||||
out += '%';
|
||||
if (c <= 0xff) {
|
||||
append_printf_formatted_string(out, "%02x", c);
|
||||
append_2_hex_digits(out, c, lookup_hex);
|
||||
} else {
|
||||
append_printf_formatted_string(out, "%04x", c);
|
||||
append_min_4_hex_digits(out, c, lookup_hex);
|
||||
}
|
||||
out += '%';
|
||||
}
|
||||
@ -174,6 +196,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
inline void append_debug_encoded_string(std::string& out, const char* data, const char* prefix, const char* suffix) {
|
||||
static const char* lookup_hex = "0123456789ABCDEF";
|
||||
const char* end = data + std::strlen(data);
|
||||
|
||||
while (data != end) {
|
||||
@ -194,7 +217,9 @@ namespace osmium {
|
||||
out.append(last, data);
|
||||
} else {
|
||||
out.append(prefix);
|
||||
append_printf_formatted_string(out, "<U+%04X>", c);
|
||||
out.append("<U+");
|
||||
append_min_4_hex_digits(out, c, lookup_hex);
|
||||
out.append(">");
|
||||
out.append(suffix);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user