├── .clang-format ├── .gitignore ├── CMakeLists.txt ├── README.md ├── cmake └── FindOsmium.cmake └── src ├── CMakeLists.txt ├── adminhandler.hpp ├── options.cpp ├── options.hpp ├── osmborder.cpp ├── osmborder_filter.cpp ├── return_codes.hpp ├── stats.hpp └── util.hpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: LLVM 4 | AccessModifierOffset: -4 5 | BreakBeforeBraces: Mozilla 6 | IndentWidth: 4 7 | ConstructorInitializerIndentWidth: 0 8 | ReflowComments: false 9 | AlwaysBreakTemplateDeclarations: true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # 3 | # CMake Config 4 | # 5 | # OSMBorders, based on OSMCoastline 6 | # 7 | #----------------------------------------------------------------------------- 8 | 9 | cmake_minimum_required(VERSION 2.8 FATAL_ERROR) 10 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") 11 | 12 | 13 | #----------------------------------------------------------------------------- 14 | # 15 | # Project version 16 | # 17 | #----------------------------------------------------------------------------- 18 | 19 | project(osmborder) 20 | 21 | set(OSMBORDER_VERSION_MAJOR 0) 22 | set(OSMBORDER_VERSION_MINOR 0) 23 | set(OSMBORDER_VERSION_PATCH 1) 24 | 25 | set(OSMBORDER_VERSION 26 | ${OSMBORDER_VERSION_MAJOR}.${OSMBORDER_VERSION_MINOR}.${OSMBORDER_VERSION_PATCH}) 27 | 28 | add_definitions(-DOSMBORDER_VERSION="${OSMBORDER_VERSION}") 29 | 30 | set(AUTHOR "Paul Norman ") 31 | 32 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 33 | 34 | 35 | #----------------------------------------------------------------------------- 36 | # 37 | # Find external dependencies 38 | # 39 | #----------------------------------------------------------------------------- 40 | 41 | include_directories(include) 42 | 43 | find_package(Osmium 2.7.0 COMPONENTS io) 44 | include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS}) 45 | 46 | if(MSVC) 47 | find_path(GETOPT_INCLUDE_DIR getopt.h) 48 | find_library(GETOPT_LIBRARY NAMES wingetopt) 49 | if(GETOPT_INCLUDE_DIR AND GETOPT_LIBRARY) 50 | include_directories(${GETOPT_INCLUDE_DIR}) 51 | else() 52 | set(GETOPT_MISSING 1) 53 | endif() 54 | endif() 55 | 56 | #----------------------------------------------------------------------------- 57 | # 58 | # Decide which C++ version to use (Minimum/default: C++11). 59 | # 60 | #----------------------------------------------------------------------------- 61 | if(NOT MSVC) 62 | if(NOT USE_CPP_VERSION) 63 | set(USE_CPP_VERSION c++11) 64 | endif() 65 | message(STATUS "Use C++ version: ${USE_CPP_VERSION}") 66 | # following only available from cmake 2.8.12: 67 | # add_compile_options(-std=${USE_CPP_VERSION}) 68 | # so using this instead: 69 | add_definitions(-std=${USE_CPP_VERSION}) 70 | endif() 71 | 72 | 73 | #----------------------------------------------------------------------------- 74 | # 75 | # Compiler and Linker flags 76 | # 77 | #----------------------------------------------------------------------------- 78 | 79 | if(MSVC) 80 | set(USUAL_COMPILE_OPTIONS "/Ox") 81 | else() 82 | set(USUAL_COMPILE_OPTIONS "-O3 -g") 83 | endif() 84 | 85 | if(WIN32) 86 | add_definitions(-DWIN32 -D_WIN32 -DMSWIN32 -DBGDWIN32 87 | -DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -D_WIN32_IE=0x0600) 88 | endif() 89 | 90 | set(CMAKE_CXX_FLAGS_DEV "${USUAL_COMPILE_OPTIONS}" 91 | CACHE STRING "Flags used by the compiler during developer builds." 92 | FORCE) 93 | 94 | set(CMAKE_EXE_LINKER_FLAGS_DEV "" 95 | CACHE STRING "Flags used by the linker during developer builds." 96 | FORCE) 97 | mark_as_advanced( 98 | CMAKE_CXX_FLAGS_DEV 99 | CMAKE_EXE_LINKER_FLAGS_DEV 100 | ) 101 | 102 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${USUAL_COMPILE_OPTIONS}" 103 | CACHE STRING "Flags used by the compiler during RELWITHDEBINFO builds." 104 | FORCE) 105 | 106 | 107 | #----------------------------------------------------------------------------- 108 | # 109 | # Build Type 110 | # 111 | #----------------------------------------------------------------------------- 112 | set(CMAKE_CONFIGURATION_TYPES "Debug Release RelWithDebInfo MinSizeRel Dev") 113 | 114 | # In 'Dev' mode: compile with very strict warnings and turn them into errors. 115 | if(CMAKE_BUILD_TYPE STREQUAL "Dev") 116 | if(NOT MSVC) 117 | add_definitions(-Werror -Wall -fno-omit-frame-pointer) 118 | endif() 119 | add_definitions(${OSMIUM_WARNING_OPTIONS}) 120 | endif() 121 | 122 | # Force RelWithDebInfo build type if none was given 123 | if(CMAKE_BUILD_TYPE) 124 | set(build_type ${CMAKE_BUILD_TYPE}) 125 | else() 126 | set(build_type "RelWithDebInfo") 127 | endif() 128 | 129 | set(CMAKE_BUILD_TYPE ${build_type} 130 | CACHE STRING 131 | "Choose the type of build, options are: ${CMAKE_CONFIGURATION_TYPES}." 132 | FORCE) 133 | 134 | 135 | #----------------------------------------------------------------------------- 136 | # 137 | # Optional "cppcheck" target that checks C++ code 138 | # 139 | #----------------------------------------------------------------------------- 140 | message(STATUS "Looking for cppcheck") 141 | find_program(CPPCHECK cppcheck) 142 | 143 | if(CPPCHECK) 144 | message(STATUS "Looking for cppcheck - found") 145 | set(CPPCHECK_OPTIONS --enable=all) 146 | 147 | # cpp doesn't find system includes for some reason, suppress that report 148 | set(CPPCHECK_OPTIONS ${CPPCHECK_OPTIONS} --suppress=missingIncludeSystem) 149 | 150 | file(GLOB ALL_CODE src/*.cpp) 151 | 152 | set(CPPCHECK_FILES ${ALL_CODE}) 153 | 154 | add_custom_target(cppcheck 155 | ${CPPCHECK} 156 | --std=c++11 ${CPPCHECK_OPTIONS} 157 | ${CPPCHECK_FILES} 158 | ) 159 | else() 160 | message(STATUS "Looking for cppcheck - not found") 161 | message(STATUS " Build target 'cppcheck' will not be available.") 162 | endif(CPPCHECK) 163 | 164 | 165 | #----------------------------------------------------------------------------- 166 | # 167 | # Optional "iwyu" target to check headers 168 | # http://include-what-you-use.org/ 169 | # 170 | #----------------------------------------------------------------------------- 171 | find_program(IWYU_TOOL iwyu_tool.py) 172 | 173 | if(IWYU_TOOL) 174 | message(STATUS "Looking for iwyu_tool.py - found") 175 | add_custom_target(iwyu ${IWYU_TOOL} -p ${CMAKE_BINARY_DIR}) 176 | else() 177 | message(STATUS "Looking for iwyu_tool.py - not found") 178 | message(STATUS " Make target iwyu not available") 179 | endif() 180 | 181 | #----------------------------------------------------------------------------- 182 | 183 | add_subdirectory(src) 184 | 185 | #----------------------------------------------------------------------------- 186 | # 187 | # Packaging 188 | # 189 | #----------------------------------------------------------------------------- 190 | 191 | set(CPACK_PACKAGE_VERSION_MAJOR ${OSMBORDER_VERSION_MAJOR}) 192 | set(CPACK_PACKAGE_VERSION_MINOR ${OSMBORDER_VERSION_MINOR}) 193 | set(CPACK_PACKAGE_VERSION_PATCH ${OSMBORDER_VERSION_PATCH}) 194 | 195 | if(WIN32) 196 | set(CPACK_GENERATOR ZIP) 197 | else() 198 | set(CPACK_GENERATOR TGZ) 199 | endif() 200 | 201 | include(CPack) 202 | 203 | 204 | #----------------------------------------------------------------------------- 205 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # OSMBorder 3 | 4 | OSMBorder extracts the admin boundary data from an OSM planet file and assembles 5 | all the pieces into linestrings for use in map renderers etc. 6 | 7 | ## Prerequisites 8 | 9 | ### Libosmium 10 | 11 | https://github.com/osmcode/libosmium 12 | http://osmcode.org/libosmium 13 | At least version 2.7.0 is needed. 14 | 15 | ### zlib (for PBF support) 16 | 17 | http://www.zlib.net/ 18 | Debian/Ubuntu: zlib1g-dev 19 | 20 | ### Pandoc (optional, to build documentation) 21 | 22 | http://johnmacfarlane.net/pandoc/ 23 | Debian/Ubuntu: pandoc 24 | (If pandoc is found by CMake, the manpages will automatically be built.) 25 | 26 | 27 | ## Building 28 | 29 | You'll need the prerequisites including `libosmium` installed. 30 | 31 | OSMBorder uses CMake for building: 32 | 33 | mkdir build 34 | cd build 35 | cmake .. 36 | make 37 | 38 | Call `make doc` to build the Doxygen API documentation which will be available 39 | in the `doc/html` directory. 40 | 41 | 42 | ## Testing 43 | 44 | ## Running 45 | 1. Filter the planet with osmborder_filter 46 | ```sh 47 | osmborder_filter -o filtered.osm.pbf planet-latest.osm.pbf 48 | ``` 49 | 2. Create linestrings with osmborder 50 | ```sh 51 | osmborder -o osmborder_lines.csv filtered.osm.pbf 52 | ``` 53 | 54 | ## Output 55 | OSMBorder outputs a tab-delimited file that can be loaded directly into PostgreSQL. This requires a suitable table, which can be created, loaded, optimized, and indexed with 56 | 57 | ```sql 58 | CREATE TABLE osmborder_lines ( 59 | osm_id bigint, 60 | admin_level int, 61 | dividing_line bool, 62 | disputed bool, 63 | maritime bool, 64 | way Geometry(LineString, 3857)); 65 | \copy osmborder_lines FROM osmborder_lines.csv 66 | 67 | CREATE INDEX osmborder_lines_way_idx ON osmborder_lines USING gist (way) WITH (fillfactor=100); 68 | CLUSTER osmborder_lines USING osmborder_lines_way_idx; 69 | CREATE INDEX osmborder_lines_way_low_idx ON osmborder_lines USING gist (way) WITH (fillfactor=100) WHERE admin_level <= 4; 70 | ``` 71 | 72 | The indexes are optional, but useful if rendering maps. 73 | 74 | ## Tags used 75 | 76 | OSMBorder uses tags on the way and its parent relations. It does **not** consider geometry, relation roles, or non-way 77 | relation members. 78 | 79 | ### admin_level 80 | 81 | The admin_level is the lowest `admin_level` value of the parent relations. The way tags are not considered. 82 | 83 | ### disputed 84 | The presence of `disputed=yes`, `dispute=yes`, `border_status=dispute` or `disputed_by=*` on the ways is used to indicate part of a border is disputed. All the tags function the same, but `disputed=yes` is my preference. Relation tags are not considered. 85 | 86 | ### maritime 87 | `maritime=yes`, `natural=coastline` or `boundary_type=maritime` indicates a maritime border for the purposes of rendering. Relations are not considered, nor intersection with water areas. 88 | 89 | ## Options 90 | 91 | -v, --verbose 92 | 93 | Gives you detailed information on what osmborder is doing, including timing. 94 | 95 | Run `osmborder --help` to see all options. 96 | 97 | ## License 98 | 99 | OSMBorder is available under the GNU GPL version 3 or later. 100 | 101 | ## Authors 102 | 103 | Paul Norman (penorman@mac.com) 104 | Based on OSMCoastline by Jochen Topf (jochen@topf.org) 105 | -------------------------------------------------------------------------------- /cmake/FindOsmium.cmake: -------------------------------------------------------------------------------- 1 | #---------------------------------------------------------------------- 2 | # 3 | # FindOsmium.cmake 4 | # 5 | # Find the Libosmium headers and, optionally, several components needed 6 | # for different Libosmium functions. 7 | # 8 | #---------------------------------------------------------------------- 9 | # 10 | # Usage: 11 | # 12 | # Copy this file somewhere into your project directory, where cmake can 13 | # find it. Usually this will be a directory called "cmake" which you can 14 | # add to the CMake module search path with the following line in your 15 | # CMakeLists.txt: 16 | # 17 | # list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") 18 | # 19 | # Then add the following in your CMakeLists.txt: 20 | # 21 | # find_package(Osmium [version] REQUIRED COMPONENTS ) 22 | # include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS}) 23 | # 24 | # The version number is optional. If it is not set, any version of 25 | # libosmium will do. 26 | # 27 | # For the substitute a space separated list of one or more of the 28 | # following components: 29 | # 30 | # pbf - include libraries needed for PBF input and output 31 | # xml - include libraries needed for XML input and output 32 | # io - include libraries needed for any type of input/output 33 | # geos - include if you want to use any of the GEOS functions 34 | # gdal - include if you want to use any of the OGR functions 35 | # proj - include if you want to use any of the Proj.4 functions 36 | # sparsehash - include if you use the sparsehash index 37 | # 38 | # You can check for success with something like this: 39 | # 40 | # if(NOT OSMIUM_FOUND) 41 | # message(WARNING "Libosmium not found!\n") 42 | # endif() 43 | # 44 | #---------------------------------------------------------------------- 45 | # 46 | # Variables: 47 | # 48 | # OSMIUM_FOUND - True if Osmium found. 49 | # OSMIUM_INCLUDE_DIRS - Where to find include files. 50 | # OSMIUM_XML_LIBRARIES - Libraries needed for XML I/O. 51 | # OSMIUM_PBF_LIBRARIES - Libraries needed for PBF I/O. 52 | # OSMIUM_IO_LIBRARIES - Libraries needed for XML or PBF I/O. 53 | # OSMIUM_LIBRARIES - All libraries Osmium uses somewhere. 54 | # 55 | #---------------------------------------------------------------------- 56 | 57 | # This is the list of directories where we look for osmium and protozero 58 | # includes. 59 | list(APPEND _osmium_include_path 60 | ../libosmium 61 | ~/Library/Frameworks 62 | /Library/Frameworks 63 | /opt/local # DarwinPorts 64 | /opt 65 | ) 66 | 67 | # Look for the header file. 68 | find_path(OSMIUM_INCLUDE_DIR osmium/version.hpp 69 | PATH_SUFFIXES include 70 | PATHS ${_osmium_include_path} 71 | ) 72 | 73 | # Check libosmium version number 74 | if(Osmium_FIND_VERSION) 75 | file(STRINGS "${OSMIUM_INCLUDE_DIR}/osmium/version.hpp" _libosmium_version_define REGEX "#define LIBOSMIUM_VERSION_STRING") 76 | if("${_libosmium_version_define}" MATCHES "#define LIBOSMIUM_VERSION_STRING \"([0-9.]+)\"") 77 | set(_libosmium_version "${CMAKE_MATCH_1}") 78 | else() 79 | set(_libosmium_version "unknown") 80 | endif() 81 | endif() 82 | 83 | set(OSMIUM_INCLUDE_DIRS "${OSMIUM_INCLUDE_DIR}") 84 | 85 | #---------------------------------------------------------------------- 86 | # 87 | # Check for optional components 88 | # 89 | #---------------------------------------------------------------------- 90 | if(Osmium_FIND_COMPONENTS) 91 | foreach(_component ${Osmium_FIND_COMPONENTS}) 92 | string(TOUPPER ${_component} _component_uppercase) 93 | set(Osmium_USE_${_component_uppercase} TRUE) 94 | endforeach() 95 | endif() 96 | 97 | #---------------------------------------------------------------------- 98 | # Component 'io' is an alias for 'pbf' and 'xml' 99 | if(Osmium_USE_IO) 100 | set(Osmium_USE_PBF TRUE) 101 | set(Osmium_USE_XML TRUE) 102 | endif() 103 | 104 | #---------------------------------------------------------------------- 105 | # Component 'ogr' is an alias for 'gdal' 106 | if(Osmium_USE_OGR) 107 | set(Osmium_USE_GDAL TRUE) 108 | endif() 109 | 110 | #---------------------------------------------------------------------- 111 | # Component 'pbf' 112 | if(Osmium_USE_PBF) 113 | find_package(ZLIB) 114 | find_package(Threads) 115 | 116 | message(STATUS "Looking for protozero") 117 | find_path(PROTOZERO_INCLUDE_DIR protozero/version.hpp 118 | PATH_SUFFIXES include 119 | PATHS ${_osmium_include_path} 120 | ) 121 | if(PROTOZERO_INCLUDE_DIR) 122 | message(STATUS "Looking for protozero - found") 123 | else() 124 | message(STATUS "Looking for protozero - not found") 125 | endif() 126 | 127 | list(APPEND OSMIUM_EXTRA_FIND_VARS ZLIB_FOUND Threads_FOUND PROTOZERO_INCLUDE_DIR) 128 | if(ZLIB_FOUND AND Threads_FOUND AND PROTOZERO_INCLUDE_DIR) 129 | list(APPEND OSMIUM_PBF_LIBRARIES 130 | ${ZLIB_LIBRARIES} 131 | ${CMAKE_THREAD_LIBS_INIT} 132 | ) 133 | if(WIN32) 134 | # This is needed for the ntohl() function 135 | list(APPEND OSMIUM_PBF_LIBRARIES ws2_32) 136 | endif() 137 | list(APPEND OSMIUM_INCLUDE_DIRS 138 | ${ZLIB_INCLUDE_DIR} 139 | ${PROTOZERO_INCLUDE_DIR} 140 | ) 141 | else() 142 | message(WARNING "Osmium: Can not find some libraries for PBF input/output, please install them or configure the paths.") 143 | endif() 144 | endif() 145 | 146 | #---------------------------------------------------------------------- 147 | # Component 'xml' 148 | if(Osmium_USE_XML) 149 | find_package(EXPAT) 150 | find_package(BZip2) 151 | find_package(ZLIB) 152 | find_package(Threads) 153 | 154 | list(APPEND OSMIUM_EXTRA_FIND_VARS EXPAT_FOUND BZIP2_FOUND ZLIB_FOUND Threads_FOUND) 155 | if(EXPAT_FOUND AND BZIP2_FOUND AND ZLIB_FOUND AND Threads_FOUND) 156 | list(APPEND OSMIUM_XML_LIBRARIES 157 | ${EXPAT_LIBRARIES} 158 | ${BZIP2_LIBRARIES} 159 | ${ZLIB_LIBRARIES} 160 | ${CMAKE_THREAD_LIBS_INIT} 161 | ) 162 | list(APPEND OSMIUM_INCLUDE_DIRS 163 | ${EXPAT_INCLUDE_DIR} 164 | ${BZIP2_INCLUDE_DIR} 165 | ${ZLIB_INCLUDE_DIR} 166 | ) 167 | else() 168 | message(WARNING "Osmium: Can not find some libraries for XML input/output, please install them or configure the paths.") 169 | endif() 170 | endif() 171 | 172 | #---------------------------------------------------------------------- 173 | list(APPEND OSMIUM_IO_LIBRARIES 174 | ${OSMIUM_PBF_LIBRARIES} 175 | ${OSMIUM_XML_LIBRARIES} 176 | ) 177 | 178 | list(APPEND OSMIUM_LIBRARIES 179 | ${OSMIUM_IO_LIBRARIES} 180 | ) 181 | 182 | #---------------------------------------------------------------------- 183 | # Component 'geos' 184 | if(Osmium_USE_GEOS) 185 | find_path(GEOS_INCLUDE_DIR geos/geom.h) 186 | find_library(GEOS_LIBRARY NAMES geos) 187 | 188 | list(APPEND OSMIUM_EXTRA_FIND_VARS GEOS_INCLUDE_DIR GEOS_LIBRARY) 189 | if(GEOS_INCLUDE_DIR AND GEOS_LIBRARY) 190 | SET(GEOS_FOUND 1) 191 | list(APPEND OSMIUM_LIBRARIES ${GEOS_LIBRARY}) 192 | list(APPEND OSMIUM_INCLUDE_DIRS ${GEOS_INCLUDE_DIR}) 193 | else() 194 | message(WARNING "Osmium: GEOS library is required but not found, please install it or configure the paths.") 195 | endif() 196 | endif() 197 | 198 | #---------------------------------------------------------------------- 199 | # Component 'gdal' (alias 'ogr') 200 | if(Osmium_USE_GDAL) 201 | find_package(GDAL) 202 | 203 | list(APPEND OSMIUM_EXTRA_FIND_VARS GDAL_FOUND) 204 | if(GDAL_FOUND) 205 | list(APPEND OSMIUM_LIBRARIES ${GDAL_LIBRARIES}) 206 | list(APPEND OSMIUM_INCLUDE_DIRS ${GDAL_INCLUDE_DIRS}) 207 | else() 208 | message(WARNING "Osmium: GDAL library is required but not found, please install it or configure the paths.") 209 | endif() 210 | endif() 211 | 212 | #---------------------------------------------------------------------- 213 | # Component 'proj' 214 | if(Osmium_USE_PROJ) 215 | find_path(PROJ_INCLUDE_DIR proj_api.h) 216 | find_library(PROJ_LIBRARY NAMES proj) 217 | 218 | list(APPEND OSMIUM_EXTRA_FIND_VARS PROJ_INCLUDE_DIR PROJ_LIBRARY) 219 | if(PROJ_INCLUDE_DIR AND PROJ_LIBRARY) 220 | set(PROJ_FOUND 1) 221 | list(APPEND OSMIUM_LIBRARIES ${PROJ_LIBRARY}) 222 | list(APPEND OSMIUM_INCLUDE_DIRS ${PROJ_INCLUDE_DIR}) 223 | else() 224 | message(WARNING "Osmium: PROJ.4 library is required but not found, please install it or configure the paths.") 225 | endif() 226 | endif() 227 | 228 | #---------------------------------------------------------------------- 229 | # Component 'sparsehash' 230 | if(Osmium_USE_SPARSEHASH) 231 | find_path(SPARSEHASH_INCLUDE_DIR google/sparsetable) 232 | 233 | list(APPEND OSMIUM_EXTRA_FIND_VARS SPARSEHASH_INCLUDE_DIR) 234 | if(SPARSEHASH_INCLUDE_DIR) 235 | # Find size of sparsetable::size_type. This does not work on older 236 | # CMake versions because they can do this check only in C, not in C++. 237 | if(NOT CMAKE_VERSION VERSION_LESS 3.0) 238 | include(CheckTypeSize) 239 | set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR}) 240 | set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable") 241 | check_type_size("google::sparsetable::size_type" SPARSETABLE_SIZE_TYPE LANGUAGE CXX) 242 | set(CMAKE_EXTRA_INCLUDE_FILES) 243 | set(CMAKE_REQUIRED_INCLUDES) 244 | else() 245 | set(SPARSETABLE_SIZE_TYPE ${CMAKE_SIZEOF_VOID_P}) 246 | endif() 247 | 248 | # Sparsetable::size_type must be at least 8 bytes (64bit), otherwise 249 | # OSM object IDs will not fit. 250 | if(SPARSETABLE_SIZE_TYPE GREATER 7) 251 | set(SPARSEHASH_FOUND 1) 252 | add_definitions(-DOSMIUM_WITH_SPARSEHASH=${SPARSEHASH_FOUND}) 253 | list(APPEND OSMIUM_INCLUDE_DIRS ${SPARSEHASH_INCLUDE_DIR}) 254 | else() 255 | message(WARNING "Osmium: Disabled Google SparseHash library on 32bit system (size_type=${SPARSETABLE_SIZE_TYPE}).") 256 | endif() 257 | else() 258 | message(WARNING "Osmium: Google SparseHash library is required but not found, please install it or configure the paths.") 259 | endif() 260 | endif() 261 | 262 | #---------------------------------------------------------------------- 263 | 264 | list(REMOVE_DUPLICATES OSMIUM_INCLUDE_DIRS) 265 | 266 | if(OSMIUM_XML_LIBRARIES) 267 | list(REMOVE_DUPLICATES OSMIUM_XML_LIBRARIES) 268 | endif() 269 | 270 | if(OSMIUM_PBF_LIBRARIES) 271 | list(REMOVE_DUPLICATES OSMIUM_PBF_LIBRARIES) 272 | endif() 273 | 274 | if(OSMIUM_IO_LIBRARIES) 275 | list(REMOVE_DUPLICATES OSMIUM_IO_LIBRARIES) 276 | endif() 277 | 278 | if(OSMIUM_LIBRARIES) 279 | list(REMOVE_DUPLICATES OSMIUM_LIBRARIES) 280 | endif() 281 | 282 | #---------------------------------------------------------------------- 283 | # 284 | # Check that all required libraries are available 285 | # 286 | #---------------------------------------------------------------------- 287 | if(OSMIUM_EXTRA_FIND_VARS) 288 | list(REMOVE_DUPLICATES OSMIUM_EXTRA_FIND_VARS) 289 | endif() 290 | # Handle the QUIETLY and REQUIRED arguments and the optional version check 291 | # and set OSMIUM_FOUND to TRUE if all listed variables are TRUE. 292 | include(FindPackageHandleStandardArgs) 293 | find_package_handle_standard_args(Osmium 294 | REQUIRED_VARS OSMIUM_INCLUDE_DIR ${OSMIUM_EXTRA_FIND_VARS} 295 | VERSION_VAR _libosmium_version) 296 | unset(OSMIUM_EXTRA_FIND_VARS) 297 | 298 | #---------------------------------------------------------------------- 299 | # 300 | # Add compiler flags 301 | # 302 | #---------------------------------------------------------------------- 303 | add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64) 304 | 305 | if(MSVC) 306 | add_definitions(-wd4996) 307 | 308 | # Disable warning C4068: "unknown pragma" because we want it to ignore 309 | # pragmas for other compilers. 310 | add_definitions(-wd4068) 311 | 312 | # Disable warning C4715: "not all control paths return a value" because 313 | # it generates too many false positives. 314 | add_definitions(-wd4715) 315 | 316 | # Disable warning C4351: new behavior: elements of array '...' will be 317 | # default initialized. The new behaviour is correct and we don't support 318 | # old compilers anyway. 319 | add_definitions(-wd4351) 320 | 321 | add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS) 322 | endif() 323 | 324 | if(APPLE) 325 | # following only available from cmake 2.8.12: 326 | # add_compile_options(-stdlib=libc++) 327 | # so using this instead: 328 | add_definitions(-stdlib=libc++) 329 | set(LDFLAGS ${LDFLAGS} -stdlib=libc++) 330 | endif() 331 | 332 | #---------------------------------------------------------------------- 333 | 334 | # This is a set of recommended warning options that can be added when compiling 335 | # libosmium code. 336 | if(MSVC) 337 | set(OSMIUM_WARNING_OPTIONS "/W3 /wd4514" CACHE STRING "Recommended warning options for libosmium") 338 | else() 339 | set(OSMIUM_WARNING_OPTIONS "-Wall -Wextra -pedantic -Wredundant-decls -Wdisabled-optimization -Wctor-dtor-privacy -Wnon-virtual-dtor -Woverloaded-virtual -Wsign-promo -Wold-style-cast" CACHE STRING "Recommended warning options for libosmium") 340 | endif() 341 | 342 | set(OSMIUM_DRACONIC_CLANG_OPTIONS "-Wdocumentation -Wunused-exception-parameter -Wmissing-declarations -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-unused-macros -Wno-exit-time-destructors -Wno-global-constructors -Wno-padded -Wno-switch-enum -Wno-missing-prototypes -Wno-weak-vtables -Wno-cast-align -Wno-float-equal") 343 | 344 | if(Osmium_DEBUG) 345 | message(STATUS "OSMIUM_XML_LIBRARIES=" ${OSMIUM_XML_LIBRARIES}) 346 | message(STATUS "OSMIUM_PBF_LIBRARIES=" ${OSMIUM_PBF_LIBRARIES}) 347 | message(STATUS "OSMIUM_IO_LIBRARIES=" ${OSMIUM_IO_LIBRARIES}) 348 | message(STATUS "OSMIUM_LIBRARIES=" ${OSMIUM_LIBRARIES}) 349 | message(STATUS "OSMIUM_INCLUDE_DIRS=" ${OSMIUM_INCLUDE_DIRS}) 350 | endif() 351 | 352 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # 3 | # CMake Config 4 | # 5 | # OSMBorder 6 | # 7 | #----------------------------------------------------------------------------- 8 | 9 | add_executable(osmborder osmborder.cpp options.cpp) 10 | target_link_libraries(osmborder ${OSMIUM_IO_LIBRARIES} ${GETOPT_LIBRARY}) 11 | install(TARGETS osmborder DESTINATION bin) 12 | 13 | add_executable(osmborder_filter osmborder_filter.cpp) 14 | target_link_libraries(osmborder_filter ${OSMIUM_IO_LIBRARIES} ${GETOPT_LIBRARY}) 15 | install(TARGETS osmborder_filter DESTINATION bin) 16 | -------------------------------------------------------------------------------- /src/adminhandler.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ADMINHANDLER_HPP 2 | #define ADMINHANDLER_HPP 3 | /* 4 | 5 | Copyright 2016 Paul Norman . 6 | 7 | This file is part of OSMBorder. 8 | 9 | OSMBorder is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | OSMBorder is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with OSMBorder. If not, see . 21 | 22 | */ 23 | #include 24 | 25 | class AdminHandler : public osmium::handler::Handler 26 | { 27 | private: 28 | // p1 29 | // All relations we are interested in will be kept in this buffer 30 | osmium::memory::Buffer m_relations_buffer; 31 | // Mapping of way IDs to the offset to the parent relation 32 | typedef std::vector RelationParents; 33 | typedef std::map 34 | WayRelations; 35 | WayRelations m_way_rels; 36 | 37 | // p2 38 | // All ways we're interested in 39 | osmium::memory::Buffer m_ways_buffer; 40 | 41 | osmium::geom::WKBFactory m_factory{ 42 | osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex}; 43 | static constexpr size_t initial_buffer_size = 1024 * 1024; 44 | 45 | static const std::map admin_levels; 46 | 47 | // Based on osm2pgsql escaping 48 | std::string escape(const std::string &src) 49 | { 50 | std::string dst; 51 | for (const char c : src) { 52 | switch (c) { 53 | case '\\': 54 | dst.append("\\\\"); 55 | break; 56 | //case 8: dst.append("\\\b"); break; 57 | //case 12: dst.append("\\\f"); break; 58 | case '\n': 59 | dst.append("\\\n"); 60 | break; 61 | case '\r': 62 | dst.append("\\\r"); 63 | break; 64 | case '\t': 65 | dst.append("\\\t"); 66 | break; 67 | //case 11: dst.append("\\\v"); break; 68 | default: 69 | dst.push_back(c); 70 | break; 71 | } 72 | } 73 | return dst; 74 | } 75 | 76 | std::ostream &m_out; 77 | 78 | public: 79 | /** 80 | * This handler operates on the ways-only pass and extracts way information, but can't 81 | * yet do geometries since it doesn't have node information 82 | */ 83 | class HandlerPass2 : public osmium::handler::Handler 84 | { 85 | public: 86 | osmium::memory::Buffer &m_ways_buffer; 87 | const WayRelations &m_way_rels; 88 | 89 | explicit HandlerPass2(osmium::memory::Buffer &ways_buffer, 90 | const WayRelations &way_rels) 91 | : m_ways_buffer(ways_buffer), m_way_rels(way_rels) 92 | { 93 | } 94 | 95 | void way(const osmium::Way &way) 96 | { 97 | if (m_way_rels.count(way.id()) > 0) { 98 | m_ways_buffer.add_item(way); 99 | } 100 | } 101 | }; 102 | 103 | AdminHandler(std::ostream &out) 104 | : m_ways_buffer(initial_buffer_size, 105 | osmium::memory::Buffer::auto_grow::yes), 106 | m_relations_buffer(initial_buffer_size, 107 | osmium::memory::Buffer::auto_grow::yes), 108 | m_handler_pass2(m_ways_buffer, m_way_rels), m_out(out) 109 | { 110 | } 111 | 112 | /* This is where the logic that handles tagging lives, getting tags from the way and parent rels */ 113 | void way(const osmium::Way &way) 114 | { 115 | std::vector parent_admin_levels; 116 | bool disputed = false; 117 | bool maritime = false; 118 | 119 | // Tags on the way itself 120 | disputed = disputed || way.tags().has_tag("disputed", "yes"); 121 | disputed = disputed || way.tags().has_tag("dispute", "yes"); 122 | disputed = disputed || way.tags().has_tag("border_status", "dispute"); 123 | disputed = disputed || way.tags().has_key("disputed_by"); 124 | 125 | maritime = maritime || way.tags().has_tag("maritime", "yes"); 126 | maritime = maritime || way.tags().has_tag("natural", "coastline"); 127 | maritime = maritime || way.tags().has_tag("boundary_type", "maritime"); 128 | 129 | // Tags on the parent relations 130 | for (const auto &rel_offset : m_way_rels[way.id()]) { 131 | const osmium::TagList &tags = 132 | m_relations_buffer.get(rel_offset) 133 | .tags(); 134 | const char *admin_level = tags.get_value_by_key("admin_level", ""); 135 | /* can't use admin_levels[] because [] is non-const, but there must be a better way? */ 136 | auto admin_it = admin_levels.find(admin_level); 137 | if (admin_it != admin_levels.end()) { 138 | parent_admin_levels.push_back(admin_it->second); 139 | } 140 | } 141 | 142 | if (parent_admin_levels.size() > 0) { 143 | try { 144 | // Sort for both min parent admin level and if it divides areas 145 | std::sort(parent_admin_levels.begin(), 146 | parent_admin_levels.end()); 147 | const int min_parent_admin_level = parent_admin_levels[0]; 148 | 149 | // Checks if two parents are the same admin level 150 | const bool dividing_line = 151 | std::adjacent_find(parent_admin_levels.begin(), 152 | parent_admin_levels.end()) != 153 | parent_admin_levels.end(); 154 | 155 | // Convert here to ensure errors don't result in partial output lines. 156 | const std::string linestring = m_factory.create_linestring(way); 157 | 158 | m_out << way.id() << "\t" 159 | // parent_admin_levels is already escaped. 160 | << min_parent_admin_level << "\t" 161 | << ((dividing_line) ? ("true") : ("false")) << "\t" 162 | << ((disputed) ? ("true") : ("false")) << "\t" 163 | << ((maritime) ? ("true") : ("false")) << "\t" 164 | << linestring << "\n"; 165 | } catch (osmium::geometry_error &e) { 166 | std::cerr << "Geometry error on way " << way.id() << ": " 167 | << e.what() << "\n"; 168 | } 169 | } 170 | } 171 | 172 | void relation(const osmium::Relation &relation) 173 | { 174 | if (relation.tags().has_tag("boundary", "administrative")) { 175 | m_relations_buffer.add_item(relation); 176 | auto relation_offset = m_relations_buffer.commit(); 177 | for (const auto &rm : relation.members()) { 178 | if (rm.type() == osmium::item_type::way) { 179 | // Calls the default constructor if it doesn't exist, otherwise add to the back 180 | // TODO: Can this call the constructor to create a vector of size N, where N=2? 181 | m_way_rels[rm.ref()].push_back(relation_offset); 182 | } 183 | } 184 | } 185 | } 186 | 187 | osmium::memory::Buffer &get_ways() { return m_ways_buffer; } 188 | 189 | void flush() {} 190 | // Handler for the pass2 ways 191 | HandlerPass2 m_handler_pass2; 192 | }; 193 | #endif // ADMINHANDLER_HPP -------------------------------------------------------------------------------- /src/options.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright 2012-2016 Jochen Topf . 4 | 5 | This file is part of OSMBorder. 6 | 7 | OSMBorder is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | OSMBorder is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with OSMBorder. If not, see . 19 | 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "options.hpp" 27 | #include "return_codes.hpp" 28 | 29 | #ifdef _MSC_VER 30 | #define strcasecmp _stricmp 31 | #endif 32 | 33 | Options::Options(int argc, char *argv[]) 34 | : inputfile(), debug(false), output_file(), overwrite_output(false), 35 | verbose(false) 36 | { 37 | static struct option long_options[] = { 38 | {"debug", no_argument, 0, 'd'}, 39 | {"help", no_argument, 0, 'h'}, 40 | {"output-file", required_argument, 0, 'o'}, 41 | {"overwrite", no_argument, 0, 'f'}, 42 | {"verbose", no_argument, 0, 'v'}, 43 | {"version", no_argument, 0, 'V'}, 44 | {0, 0, 0, 0}}; 45 | 46 | while (1) { 47 | int c = getopt_long(argc, argv, "dho:fvV", long_options, 0); 48 | if (c == -1) 49 | break; 50 | 51 | switch (c) { 52 | case 'd': 53 | debug = true; 54 | std::cerr << "Enabled debug option\n"; 55 | break; 56 | case 'h': 57 | print_help(); 58 | std::exit(return_code_ok); 59 | case 'o': 60 | output_file = optarg; 61 | break; 62 | case 'f': 63 | overwrite_output = true; 64 | break; 65 | case 'v': 66 | verbose = true; 67 | break; 68 | case 'V': 69 | std::cout 70 | << "osmborder version " OSMBORDER_VERSION "\n" 71 | << "Copyright (C) 2012-2016 Jochen Topf \n" 72 | << "License: GNU GENERAL PUBLIC LICENSE Version 3 " 73 | ".\n" 74 | << "This is free software: you are free to change and " 75 | "redistribute it.\n" 76 | << "There is NO WARRANTY, to the extent permitted by law.\n"; 77 | std::exit(return_code_ok); 78 | default: 79 | std::exit(return_code_cmdline); 80 | } 81 | } 82 | 83 | if (optind != argc - 1) { 84 | std::cerr << "Usage: " << argv[0] << " [OPTIONS] OSMFILE\n"; 85 | std::exit(return_code_cmdline); 86 | } 87 | 88 | if (output_file.empty()) { 89 | std::cerr << "Missing --output-file/-o option.\n"; 90 | std::exit(return_code_cmdline); 91 | } 92 | 93 | inputfile = argv[optind]; 94 | } 95 | 96 | void Options::print_help() const 97 | { 98 | std::cout << "osmborder [OPTIONS] OSMFILE\n" 99 | << "\nOptions:\n" 100 | << " -h, --help - This help message\n" 101 | << " -d, --debug - Enable debugging output\n" 102 | << " -f, --overwrite - Overwrite output file if it " 103 | "already exists\n" 104 | << " -o, --output-file=FILE - file for output\n" 105 | << " -v, --verbose - Verbose output\n" 106 | << " -V, --version - Show version and exit\n" 107 | << "\n"; 108 | } 109 | -------------------------------------------------------------------------------- /src/options.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OPTIONS_HPP 2 | #define OPTIONS_HPP 3 | 4 | /* 5 | 6 | Copyright 2012-2016 Jochen Topf . 7 | 8 | This file is part of OSMBorder. 9 | 10 | OSMBorder is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | OSMBorder is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with OSMBorder. If not, see . 22 | 23 | */ 24 | 25 | #include 26 | 27 | /** 28 | * This class encapsulates the command line parsing. 29 | */ 30 | class Options 31 | { 32 | 33 | public: 34 | /// Input OSM file name. 35 | std::string inputfile; 36 | 37 | /// Show debug output? 38 | bool debug; 39 | 40 | /// Output file name. 41 | std::string output_file; 42 | 43 | /// Should output database be overwritten 44 | bool overwrite_output; 45 | 46 | /// EPSG code of output SRS. 47 | int epsg; 48 | 49 | /// Verbose output? 50 | bool verbose; 51 | 52 | Options(int argc, char *argv[]); 53 | 54 | private: 55 | /** 56 | * Get EPSG code from text. This method knows about a few common cases 57 | * of specifying WGS84 or the "Google mercator" SRS. More are currently 58 | * not supported. 59 | */ 60 | int get_epsg(const char *text); 61 | 62 | void print_help() const; 63 | 64 | }; // class Options 65 | 66 | #endif // OPTIONS_HPP 67 | -------------------------------------------------------------------------------- /src/osmborder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright 2012-2016 Jochen Topf . 4 | Copyright 2016 Paul Norman . 5 | 6 | This file is part of OSMBorder. 7 | 8 | OSMBorder is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | OSMBorder is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with OSMBorder. If not, see . 20 | 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #ifndef _MSC_VER 28 | #include 29 | #else 30 | #include 31 | #endif 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | namespace osmium { 45 | class Area; 46 | } 47 | namespace osmium { 48 | class Node; 49 | } 50 | namespace osmium { 51 | class Relation; 52 | } 53 | namespace osmium { 54 | class Way; 55 | } 56 | 57 | #include "adminhandler.hpp" 58 | #include "options.hpp" 59 | #include "return_codes.hpp" 60 | #include "stats.hpp" 61 | 62 | // Global debug marker 63 | bool debug; 64 | 65 | // If there are more than this many warnings, the program exit code will indicate an error. 66 | const unsigned int max_warnings = 500; 67 | 68 | /* ================================================== */ 69 | 70 | std::string memory_usage() 71 | { 72 | osmium::MemoryUsage mem; 73 | std::ostringstream s; 74 | s << "Memory used: current: " << mem.current() 75 | << " MBytes, peak: " << mem.peak() << " MBytes\n"; 76 | return s.str(); 77 | } 78 | 79 | /* ================================================== */ 80 | 81 | // This class acts like NodeLocationsForWays but only stores specific nodes 82 | // Also, only positive. TODO: Add in negative support 83 | template 84 | class SpecificNodeLocationsForWays 85 | : public osmium::handler::NodeLocationsForWays 86 | { 87 | 88 | // some var for a set of IDs to keep 89 | public: 90 | explicit SpecificNodeLocationsForWays(TStoragePosIDs &storage_pos) 91 | : osmium::handler::NodeLocationsForWays(storage_pos) 92 | { 93 | } 94 | 95 | void node(const osmium::Node &node) 96 | { 97 | if (true) { 98 | osmium::handler::NodeLocationsForWays::node(node); 99 | } 100 | } 101 | void way(osmium::Way &way) 102 | { 103 | osmium::handler::NodeLocationsForWays::way(way); 104 | } 105 | }; 106 | 107 | // TODO: Cover all admin_levels 108 | // This is a map instead of something like an array of chars because admin_levels can extend past 9 109 | const std::map AdminHandler::admin_levels = { 110 | {"2", 2}, {"3", 3}, {"4", 4}, {"5", 5}, {"6", 6}, {"7", 7}, 111 | {"8", 8}, {"9", 9}, {"10", 10}, {"11", 11}, {"12", 12}}; 112 | 113 | int main(int argc, char *argv[]) 114 | { 115 | Stats stats; 116 | unsigned int warnings = 0; 117 | unsigned int errors = 0; 118 | 119 | // Parse command line and setup 'options' object with them. 120 | Options options(argc, argv); 121 | 122 | // The vout object is an output stream we can write to instead of 123 | // std::cerr. Nothing is written if we are not in verbose mode. 124 | // The running time will be prepended to output lines. 125 | osmium::util::VerboseOutput vout(options.verbose); 126 | 127 | debug = options.debug; 128 | 129 | vout << "Writing to file '" << options.output_file << "'.\n"; 130 | 131 | std::ofstream output(options.output_file); 132 | 133 | osmium::io::File infile{argv[optind]}; 134 | 135 | AdminHandler admin_handler(output); 136 | 137 | { 138 | vout << "Reading relations in pass 1.\n"; 139 | osmium::io::Reader reader(infile, osmium::osm_entity_bits::relation); 140 | osmium::apply(reader, admin_handler); 141 | reader.close(); 142 | vout << memory_usage(); 143 | } 144 | { 145 | vout << "Reading ways pass 2.\n"; 146 | osmium::io::Reader reader(infile, osmium::osm_entity_bits::way); 147 | osmium::apply(reader, admin_handler.m_handler_pass2); 148 | reader.close(); 149 | vout << memory_usage(); 150 | } 151 | typedef osmium::index::map::SparseMemArray 153 | index_type; 154 | typedef SpecificNodeLocationsForWays location_handler_type; 155 | index_type index; 156 | location_handler_type location_handler{index}; 157 | { 158 | vout << "Reading nodes pass 3.\n"; 159 | osmium::io::Reader reader(infile, osmium::osm_entity_bits::node); 160 | osmium::apply(reader, location_handler); 161 | reader.close(); 162 | vout << memory_usage(); 163 | } 164 | vout << "Building linestrings.\n"; 165 | osmium::io::Reader reader(infile, osmium::osm_entity_bits::way); 166 | osmium::apply(reader, location_handler, admin_handler); 167 | 168 | vout << "All done.\n"; 169 | vout << memory_usage(); 170 | 171 | std::cerr << "There were " << warnings << " warnings.\n"; 172 | std::cerr << "There were " << errors << " errors.\n"; 173 | 174 | if (errors || warnings > max_warnings) { 175 | return return_code_error; 176 | } else if (warnings) { 177 | return return_code_warning; 178 | } else { 179 | return return_code_ok; 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/osmborder_filter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright 2012-2016 Jochen Topf . 4 | Copyright 2016 Paul Norman . 5 | 6 | This file is part of OSMBorder, and is based on osmborder_filter.cpp 7 | from OSMCoastline 8 | 9 | OSMBorder is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | OSMBorder is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with OSMBorder. If not, see . 21 | 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include "return_codes.hpp" 45 | 46 | void print_help() 47 | { 48 | std::cout 49 | << "osmborder_filter [OPTIONS] OSMFILE\n" 50 | << "\nOptions:\n" 51 | << " -h, --help - This help message\n" 52 | << " -o, --output=OSMFILE - Where to write output (default: none)\n" 53 | << " -v, --verbose - Verbose output\n" 54 | << " -V, --version - Show version and exit\n" 55 | << "\n"; 56 | } 57 | 58 | int main(int argc, char *argv[]) 59 | { 60 | std::string output_filename; 61 | bool verbose = false; 62 | 63 | static struct option long_options[] = { 64 | {"help", no_argument, 0, 'h'}, 65 | {"output", required_argument, 0, 'o'}, 66 | {"verbose", no_argument, 0, 'v'}, 67 | {"version", no_argument, 0, 'V'}, 68 | {0, 0, 0, 0}}; 69 | 70 | while (1) { 71 | int c = getopt_long(argc, argv, "ho:vV", long_options, 0); 72 | if (c == -1) 73 | break; 74 | 75 | switch (c) { 76 | case 'h': 77 | print_help(); 78 | std::exit(return_code_ok); 79 | case 'o': 80 | output_filename = optarg; 81 | break; 82 | case 'v': 83 | verbose = true; 84 | break; 85 | case 'V': 86 | std::cout 87 | << "osmborder_filter version " OSMBORDER_VERSION "\n" 88 | << "Copyright (C) 2012-2016 Jochen Topf \n" 89 | << "License: GNU GENERAL PUBLIC LICENSE Version 3 " 90 | ".\n" 91 | << "This is free software: you are free to change and " 92 | "redistribute it.\n" 93 | << "There is NO WARRANTY, to the extent permitted by law.\n"; 94 | std::exit(return_code_ok); 95 | default: 96 | std::exit(return_code_fatal); 97 | } 98 | } 99 | 100 | // The vout object is an output stream we can write to instead of 101 | // std::cerr. Nothing is written if we are not in verbose mode. 102 | // The running time will be prepended to output lines. 103 | osmium::util::VerboseOutput vout(verbose); 104 | 105 | if (output_filename.empty()) { 106 | std::cerr << "Missing -o/--output=OSMFILE option\n"; 107 | std::exit(return_code_cmdline); 108 | } 109 | 110 | if (optind != argc - 1) { 111 | std::cerr << "Usage: osmborder_filter [OPTIONS] OSMFILE\n"; 112 | std::exit(return_code_cmdline); 113 | } 114 | 115 | osmium::io::Header header; 116 | header.set("generator", "osmborder_filter"); 117 | header.add_box(osmium::Box{-180.0, -90.0, 180.0, 90.0}); 118 | 119 | osmium::io::File infile{argv[optind]}; 120 | 121 | try { 122 | osmium::io::Writer writer{output_filename, header}; 123 | auto output_it = osmium::io::make_output_iterator(writer); 124 | 125 | std::vector way_ids; 126 | std::vector node_ids; 127 | 128 | vout << "Reading relations (1st pass through input file)...\n"; 129 | { 130 | osmium::io::Reader reader{infile, 131 | osmium::osm_entity_bits::relation}; 132 | auto relations = 133 | osmium::io::make_input_iterator_range( 134 | reader); 135 | for (const osmium::Relation &relation : relations) { 136 | if (relation.tags().has_tag("boundary", "administrative")) { 137 | *output_it++ = relation; 138 | for (const auto &rm : relation.members()) { 139 | if (rm.type() == osmium::item_type::way) { 140 | way_ids.push_back(rm.ref()); 141 | } 142 | } 143 | } 144 | } 145 | reader.close(); 146 | } 147 | 148 | vout << "Preparing way ID list...\n"; 149 | std::sort(way_ids.begin(), way_ids.end()); 150 | 151 | vout << "Reading ways (2nd pass through input file)...\n"; 152 | 153 | { 154 | osmium::io::Reader reader{infile, osmium::osm_entity_bits::way}; 155 | auto ways = 156 | osmium::io::make_input_iterator_range( 157 | reader); 158 | 159 | auto first = way_ids.begin(); 160 | auto last = std::unique(way_ids.begin(), way_ids.end()); 161 | 162 | for (const osmium::Way &way : ways) { 163 | // Advance the target list to the first possible way 164 | while (*first < way.id() && first != last) { 165 | ++first; 166 | } 167 | 168 | if (way.id() == *first) { 169 | *output_it++ = way; 170 | for (const auto &nr : way.nodes()) { 171 | node_ids.push_back(nr.ref()); 172 | } 173 | if (first != last) { 174 | ++first; 175 | } 176 | } 177 | } 178 | } 179 | 180 | vout << "Preparing node ID list...\n"; 181 | std::sort(node_ids.begin(), node_ids.end()); 182 | auto last = std::unique(node_ids.begin(), node_ids.end()); 183 | 184 | vout << "Reading nodes (3rd pass through input file)...\n"; 185 | { 186 | osmium::io::Reader reader{infile, osmium::osm_entity_bits::node}; 187 | auto nodes = 188 | osmium::io::make_input_iterator_range( 189 | reader); 190 | 191 | auto first = node_ids.begin(); 192 | std::copy_if(nodes.cbegin(), nodes.cend(), output_it, 193 | [&first, &last](const osmium::Node &node) { 194 | while (*first < node.id() && first != last) { 195 | ++first; 196 | } 197 | 198 | if (node.id() == *first) { 199 | if (first != last) { 200 | ++first; 201 | } 202 | return true; 203 | } 204 | return false; 205 | }); 206 | 207 | reader.close(); 208 | } 209 | 210 | writer.close(); 211 | } catch (const osmium::io_error &e) { 212 | std::cerr << "io error: " << e.what() << "'\n"; 213 | std::exit(return_code_fatal); 214 | } 215 | 216 | vout << "All done.\n"; 217 | osmium::MemoryUsage mem; 218 | if (mem.current() > 0) { 219 | vout << "Memory used: current: " << mem.current() << " MBytes\n" 220 | << " peak: " << mem.peak() << " MBytes\n"; 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /src/return_codes.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OSMBORDER_HPP 2 | #define OSMBORDER_HPP 3 | 4 | /* 5 | 6 | Copyright 2012-2016 Jochen Topf . 7 | 8 | This file is part of OSMBorder. 9 | 10 | OSMBorder is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | OSMBorder is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with OSMBorder. If not, see . 22 | 23 | */ 24 | 25 | enum return_codes 26 | { 27 | return_code_ok = 0, 28 | return_code_warning = 1, 29 | return_code_error = 2, 30 | return_code_fatal = 3, 31 | return_code_cmdline = 4 32 | }; 33 | 34 | #endif // OSMBORDER_HPP 35 | -------------------------------------------------------------------------------- /src/stats.hpp: -------------------------------------------------------------------------------- 1 | #ifndef STATS_HPP 2 | #define STATS_HPP 3 | 4 | /* 5 | 6 | Copyright 2012-2016 Jochen Topf . 7 | 8 | This file is part of OSMBorder. 9 | 10 | OSMBorder is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | OSMBorder is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with OSMBorder. If not, see . 22 | 23 | */ 24 | 25 | struct Stats 26 | { 27 | unsigned int ways; 28 | unsigned int unconnected_nodes; 29 | unsigned int rings; 30 | unsigned int rings_from_single_way; 31 | unsigned int rings_fixed; 32 | unsigned int rings_turned_around; 33 | unsigned int land_polygons_before_split; 34 | unsigned int land_polygons_after_split; 35 | }; 36 | 37 | #endif // STATS_HPP 38 | -------------------------------------------------------------------------------- /src/util.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_HPP 2 | #define UTIL_HPP 3 | 4 | /* 5 | 6 | Copyright 2012-2016 Jochen Topf . 7 | 8 | This file is part of OSMBorder. 9 | 10 | OSMBorder is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | OSMBorder is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with OSMBorder. If not, see . 22 | 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | template 29 | std::unique_ptr make_unique_ptr_clone(const T *source) 30 | { 31 | static_assert(std::is_convertible::value, 32 | "T* must be convertible to R*"); 33 | return std::unique_ptr(static_cast(source->clone())); 34 | } 35 | 36 | template 37 | std::unique_ptr static_cast_unique_ptr(std::unique_ptr &&ptr) 38 | { 39 | static_assert(std::is_base_of::value, 40 | "TDerived must be derived from TBase"); 41 | return std::unique_ptr(static_cast(ptr.release())); 42 | } 43 | 44 | #endif // UTIL_HPP 45 | --------------------------------------------------------------------------------