This is an automated email from the git hooks/post-receive script. sebastic pushed a commit to branch master in repository osmium-contrib.
commit 3b146944868cfc09aae5646729b82cea17716a9e Author: Bas Couwenberg <sebas...@xs4all.nl> Date: Fri Mar 6 16:28:05 2015 +0100 Imported Upstream version 0.0~20150306-0c4f263 --- .gitignore | 2 + .travis.yml | 43 +++++ CMakeLists.txt | 44 +++++ Makefile | 18 ++ README.md | 41 +++++ amenity_list/.gitignore | 1 + amenity_list/CMakeLists.txt | 24 +++ amenity_list/Makefile | 12 ++ amenity_list/README.md | 47 +++++ amenity_list/amenity_list.cpp | 84 +++++++++ cmake/CppcheckTarget.cmake | 25 +++ cmake/FindOSMPBF.cmake | 50 ++++++ cmake/FindOsmium.cmake | 340 ++++++++++++++++++++++++++++++++++++ cmake/common.cmake | 90 ++++++++++ export_to_wkt/.gitignore | 1 + export_to_wkt/CMakeLists.txt | 24 +++ export_to_wkt/Makefile | 12 ++ export_to_wkt/README.md | 45 +++++ export_to_wkt/export_to_wkt.cpp | 77 ++++++++ mapolution/.gitignore | 3 + mapolution/CMakeLists.txt | 31 ++++ mapolution/Makefile | 12 ++ mapolution/README.md | 70 ++++++++ mapolution/cmdline_options.cpp | 105 +++++++++++ mapolution/cmdline_options.hpp | 35 ++++ mapolution/gdalcpp.hpp | 221 +++++++++++++++++++++++ mapolution/geom_handler.hpp | 63 +++++++ mapolution/handlers/buildings.hpp | 43 +++++ mapolution/handlers/restaurants.hpp | 59 +++++++ mapolution/handlers/roads.hpp | 42 +++++ mapolution/main.cpp | 253 +++++++++++++++++++++++++++ mapolution/rasterize.sh | 40 +++++ node_density/.gitignore | 3 + node_density/CMakeLists.txt | 24 +++ node_density/Makefile | 12 ++ node_density/README.md | 109 ++++++++++++ node_density/cmdline_options.cpp | 125 +++++++++++++ node_density/cmdline_options.hpp | 35 ++++ node_density/colors.txt | 5 + node_density/example.qlr | 49 ++++++ node_density/main.cpp | 197 +++++++++++++++++++++ pub_names/.gitignore | 1 + pub_names/CMakeLists.txt | 24 +++ pub_names/Makefile | 12 ++ pub_names/README.md | 45 +++++ pub_names/pub_names.cpp | 46 +++++ road_length/.gitignore | 1 + road_length/CMakeLists.txt | 24 +++ road_length/Makefile | 12 ++ road_length/README.md | 46 +++++ road_length/road_length.cpp | 45 +++++ 51 files changed, 2772 insertions(+) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fdb2c6c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.*.swp +build* diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f5dffb1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,43 @@ +language: cpp + +compiler: + - gcc + - clang + +env: + - CONFIGURATION=Dev + - CONFIGURATION=Release + +before_install: + # we need at least g++-4.8 for c++11 features + - sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test + - sudo apt-get update --yes --quiet + +install: + # upgrade compilers + - sudo apt-get install --yes gcc-4.8 g++-4.8 + # make sure 'cpp' is the just installed current one + - sudo rm /usr/bin/cpp + - sudo ln -s /usr/bin/cpp-4.8 /usr/bin/cpp + # upgrade libosmium dependencies + - sudo apt-get install --yes make libboost1.48-dev libboost-program-options1.48-dev libboost-filesystem1.48-dev libsparsehash-dev libgdal-dev libproj-dev libprotobuf-dev protobuf-compiler + - cd .. + - git clone https://github.com/osmcode/libosmium.git + # OSMPBF is too old, install from git + #- sudo apt-get install --yes libosmpbf-dev + - git clone https://github.com/scrosby/OSM-binary.git + - cd OSM-binary/src + - make + - sudo make install + +#before_script: +# - true + +script: + - cd $TRAVIS_BUILD_DIR + - if [ "${CXX}" = 'g++' ]; then export CXX=g++-4.8; fi; + - mkdir build + - cd build + - cmake -LA -DCMAKE_BUILD_TYPE=${CONFIGURATION} .. + - make VERBOSE=1 + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6e04c7e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,44 @@ +#----------------------------------------------------------------------------- +# +# CMake Config +# +# Osmium-contrib +# +#----------------------------------------------------------------------------- + +cmake_minimum_required(VERSION 2.8 FATAL_ERROR) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") + + +#----------------------------------------------------------------------------- +project(osmium-contrib) + +include(common) + +find_package(Boost REQUIRED COMPONENTS program_options system filesystem) +include_directories(${Boost_INCLUDE_DIRS}) + +find_package(Osmium REQUIRED COMPONENTS io gdal proj sparsehash) +include_directories(${OSMIUM_INCLUDE_DIRS}) + + +#----------------------------------------------------------------------------- +# +# Configure all subprojects on their own +# +#----------------------------------------------------------------------------- +macro(configure_subproject _subproject) + file(GLOB SOURCES ${_subproject}/*.cpp ${_subproject}/*.hpp) + add_executable(${_subproject} ${SOURCES}) + target_link_libraries(${_subproject} ${Boost_LIBRARIES} ${OSMIUM_LIBRARIES}) +endmacro() + +configure_subproject(amenity_list) +configure_subproject(pub_names) +configure_subproject(road_length) +configure_subproject(export_to_wkt) +configure_subproject(node_density) +configure_subproject(mapolution) + + +#----------------------------------------------------------------------------- diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..39bcc83 --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ + +PROJECTS := `find . -mindepth 2 -name Makefile | xargs dirname | cut -c3-` + +all: + for i in $(PROJECTS); do \ + $(MAKE) -C $$i; \ + done + +clean: + for i in $(PROJECTS); do \ + $(MAKE) -C $$i clean; \ + done + +distclean: + for i in $(PROJECTS); do \ + rm -fr $$i/build; \ + done + diff --git a/README.md b/README.md new file mode 100644 index 0000000..9dc720a --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ + +# Osmium Contrib + +This repository contains a mixed bunch of more or less useful examples of how +to work with the Osmium library. + +You have to set up Osmium first. See http://osmcode.org/libosmium . + + +## License + +All contributions have their own licenses. + + +## Building + +This will work easiest if you have Osmium installed in your normal include path +or if the libosmium git repository is checked out in the same directory as the +"osmium-contrib" repository. + +Osmium-contrib uses CMake for its builds. For Unix/Linux systems a simple +Makefile wrapper is provided to make the build even easier. + +### Building all projects + +In the main directory type `make`. Results will be in the `build` subdirectory. + +Or you can go the long route explicitly calling CMake as follows: + +``` +mkdir build +cd build +cmake .. +make +``` + +### Building a single project + +You can build each project by itself by changing into its directory and calling +`make` or `cmake` as described above. + diff --git a/amenity_list/.gitignore b/amenity_list/.gitignore new file mode 100644 index 0000000..e637b82 --- /dev/null +++ b/amenity_list/.gitignore @@ -0,0 +1 @@ +amenity_list diff --git a/amenity_list/CMakeLists.txt b/amenity_list/CMakeLists.txt new file mode 100644 index 0000000..034e06b --- /dev/null +++ b/amenity_list/CMakeLists.txt @@ -0,0 +1,24 @@ +#---------------------------------------------------------------------- +# +# Single example osmium-contrib CMakeLists.txt +# +#---------------------------------------------------------------------- +project(osmium-amenity-list) + +cmake_minimum_required(VERSION 2.8.5) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../cmake") + +find_package(Boost REQUIRED) +include_directories(${Boost_INCLUDE_DIRS}) + +find_package(Osmium REQUIRED COMPONENTS io sparsehash) +include_directories(${OSMIUM_INCLUDE_DIRS}) + +include(common) + +#---------------------------------------------------------------------- + +set(PROG amenity_list) +file(GLOB SOURCES *.cpp *.hpp) +add_executable(${PROG} ${SOURCES}) +target_link_libraries(${PROG} ${Boost_LIBRARIES} ${OSMIUM_LIBRARIES}) diff --git a/amenity_list/Makefile b/amenity_list/Makefile new file mode 100644 index 0000000..8f43712 --- /dev/null +++ b/amenity_list/Makefile @@ -0,0 +1,12 @@ + +all: + mkdir -p build && cd build && cmake .. && $(MAKE) + +clean: + if test -d build; then cd build && $(MAKE) clean; fi + +distclean: + rm -fr build + +.PHONY: clean distclean + diff --git a/amenity_list/README.md b/amenity_list/README.md new file mode 100644 index 0000000..cee67e1 --- /dev/null +++ b/amenity_list/README.md @@ -0,0 +1,47 @@ + +# Amenity List + +Prints a list of all amenities in the file with type, name and coordinates. +For amenities that are mapped as areas the centroid will be printed as +coordinate. + + +## Prerequisites + +You'll need libosmium (http://osmcode.org/libosmium) and its dependencies +installed first. + + +## Building + +Osmium-contrib uses CMake for its builds. For Unix/Linux systems a simple +Makefile wrapper is provided to make the build even easier. + +To build just type `make`. Results will be in the `build` subdirectory. + +Or you can go the long route explicitly calling CMake as follows: + +``` +mkdir build +cd build +cmake .. +make +``` + + +## Running + +Run the program with an OSM file as its only argument: + +`amenity_list switzerland.osm.pbf` + + +## License + +This program is released into the Public Domain. + + +## Author + +Jochen Topf (http://jochentopf.com/) + diff --git a/amenity_list/amenity_list.cpp b/amenity_list/amenity_list.cpp new file mode 100644 index 0000000..afcee5d --- /dev/null +++ b/amenity_list/amenity_list.cpp @@ -0,0 +1,84 @@ + +// The code in this file is released into the Public Domain. + +#include <cstdio> +#include <iostream> + +#include <osmium/index/map/sparse_mem_array.hpp> +#include <osmium/handler/node_locations_for_ways.hpp> +typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type; +typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type; + +#include <osmium/area/assembler.hpp> +#include <osmium/area/multipolygon_collector.hpp> +#include <osmium/io/any_input.hpp> +#include <osmium/visitor.hpp> + +class AmenityHandler : public osmium::handler::Handler { + + void print_amenity(const char* type, const char* name, double x, double y) { + printf("%8.4f,%8.4f %-15s %s\n", x, y, type, name ? name : ""); + } + +public: + + void node(const osmium::Node& node) { + const char* amenity = node.tags()["amenity"]; + if (amenity) { + print_amenity(amenity, node.tags()["name"], + node.location().lon(), node.location().lat()); + } + } + + void area(const osmium::Area& area) { + if (area.cbegin<osmium::OuterRing>() == area.cend<osmium::OuterRing>()) { + return; + } + const char* amenity = area.tags()["amenity"]; + if (amenity) { + // simply use the centroid of the first outer ring + const osmium::OuterRing &ring = *area.cbegin<osmium::OuterRing>(); + double x = 0; + double y = 0; + for (const auto& l : ring) { + x += l.lon(); + y += l.lat(); + } + x /= ring.size(); + y /= ring.size(); + + print_amenity(amenity, area.tags()["name"], x, y); + } + } + +}; // class AmenityHandler + +int main(int argc, char* argv[]) { + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " OSMFILE\n"; + exit(1); + } + + osmium::area::Assembler::config_type assembler_config; + osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config); + + std::cerr << "Pass 1...\n"; + osmium::io::Reader reader1(argv[1]); + collector.read_relations(reader1); + reader1.close(); + std::cerr << "Pass 1 done\n"; + + index_type index; + location_handler_type location_handler(index); + location_handler.ignore_errors(); + + AmenityHandler data_handler; + + std::cerr << "Pass 2...\n"; + osmium::io::Reader reader2(argv[1]); + + osmium::apply(reader2, location_handler, data_handler, collector.handler([&data_handler](const osmium::memory::Buffer& area_buffer) { + osmium::apply(area_buffer, data_handler); + })); +} + diff --git a/cmake/CppcheckTarget.cmake b/cmake/CppcheckTarget.cmake new file mode 100644 index 0000000..82be792 --- /dev/null +++ b/cmake/CppcheckTarget.cmake @@ -0,0 +1,25 @@ +#---------------------------------------------------------------------- +# +# Optional "cppcheck" target that checks C++ code +# +#---------------------------------------------------------------------- +function(add_cppcheck_target _var) + + message(STATUS "Looking for cppcheck") + find_program(CPPCHECK cppcheck) + + if(CPPCHECK) + message(STATUS "Looking for cppcheck - found") + set(CPPCHECK_OPTIONS --enable=warning,style,performance,portability,information,missingInclude) + + # cpp doesn't find system includes for some reason, suppress that report + set(CPPCHECK_OPTIONS ${CPPCHECK_OPTIONS} --suppress=missingIncludeSystem) + + file(GLOB SOURCES ${_var}) + add_custom_target(cppcheck ${CPPCHECK} --std=c++11 ${CPPCHECK_OPTIONS} ${SOURCES}) + else() + message(STATUS "Looking for cppcheck - not found") + message(STATUS " Make target cppcheck not available") + endif(CPPCHECK) + +endfunction() diff --git a/cmake/FindOSMPBF.cmake b/cmake/FindOSMPBF.cmake new file mode 100644 index 0000000..deeebd8 --- /dev/null +++ b/cmake/FindOSMPBF.cmake @@ -0,0 +1,50 @@ +# +# Locate OSMPBF library +# +# This module defines +# OSMPBF_FOUND - if false, do not try to link to OSMPBF +# OSMPBF_LIBRARIES - full library path name +# OSMPBF_INCLUDE_DIRS - where to find OSMPBF.hpp +# +# Note that the expected include convention is +# #include <osmpbf/osmpbf.h> +# and not +# #include <osmpbf.h> +# + +find_path(OSMPBF_INCLUDE_DIR osmpbf/osmpbf.h + HINTS $ENV{OSMPBF_DIR} + PATH_SUFFIXES include + PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr + /opt/local # DarwinPorts + /opt +) + +find_library(OSMPBF_LIBRARY + NAMES osmpbf + HINTS $ENV{OSMPBF_DIR} + PATH_SUFFIXES lib64 lib + PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr + /opt/local + /opt +) + +# Handle the QUIETLY and REQUIRED arguments and set OSMPBF_FOUND to TRUE if +# all listed variables are TRUE. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(OSMPBF DEFAULT_MSG OSMPBF_LIBRARY OSMPBF_INCLUDE_DIR) + +# Copy the results to the output variables. +if(OSMPBF_FOUND) + set(OSMPBF_INCLUDE_DIRS ${OSMPBF_INCLUDE_DIR}) + set(OSMPBF_LIBRARIES ${OSMPBF_LIBRARY}) +endif() + diff --git a/cmake/FindOsmium.cmake b/cmake/FindOsmium.cmake new file mode 100644 index 0000000..1de41a0 --- /dev/null +++ b/cmake/FindOsmium.cmake @@ -0,0 +1,340 @@ +#---------------------------------------------------------------------- +# +# FindOsmium.cmake +# +# Find the Libosmium headers and, optionally, several components needed for +# different Libosmium functions. +# +#---------------------------------------------------------------------- +# +# Usage: +# +# Copy this file somewhere into your project directory, where cmake can +# find it. Usually this will be a directory called "cmake" which you can +# add to the CMake module search path with the following line in your +# CMakeLists.txt: +# +# list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") +# +# Then add the following in your CMakeLists.txt: +# +# find_package(Osmium REQUIRED COMPONENTS <XXX>) +# include_directories(${OSMIUM_INCLUDE_DIRS}) +# +# For the <XXX> substitute a space separated list of one or more of the +# following components: +# +# pbf - include libraries needed for PBF input and output +# xml - include libraries needed for XML input and output +# io - include libraries needed for any type of input/output +# geos - include if you want to use any of the GEOS functions +# gdal - include if you want to use any of the OGR functions +# proj - include if you want to use any of the Proj.4 functions +# sparsehash - include if you use the sparsehash index +# +# You can check for success with something like this: +# +# if(NOT OSMIUM_FOUND) +# message(WARNING "Libosmium not found!\n") +# endif() +# +#---------------------------------------------------------------------- +# +# Variables: +# +# OSMIUM_FOUND - True if Osmium found. +# OSMIUM_INCLUDE_DIRS - Where to find include files. +# OSMIUM_XML_LIBRARIES - Libraries needed for XML I/O. +# OSMIUM_PBF_LIBRARIES - Libraries needed for PBF I/O. +# OSMIUM_IO_LIBRARIES - Libraries needed for XML or PBF I/O. +# OSMIUM_LIBRARIES - All libraries Osmium uses somewhere. +# +#---------------------------------------------------------------------- + +# Look for the header file. +find_path(OSMIUM_INCLUDE_DIR osmium/osm.hpp + PATH_SUFFIXES include + PATHS + ../libosmium + ../../libosmium + libosmium + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr/ + /opt/local # DarwinPorts + /opt +) + +# Handle the QUIETLY and REQUIRED arguments and set OSMIUM_FOUND to TRUE if +# all listed variables are TRUE. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(OSMIUM REQUIRED_VARS OSMIUM_INCLUDE_DIR) + +# Copy the results to the output variables. +if(OSMIUM_FOUND) + set(OSMIUM_INCLUDE_DIRS ${OSMIUM_INCLUDE_DIR}) +else() + set(OSMIUM_INCLUDE_DIRS "") +endif() + +if(Osmium_FIND_REQUIRED AND NOT OSMIUM_FOUND) + message(FATAL_ERROR "Can not find libosmium headers, please install them or configure the paths") +endif() + +#---------------------------------------------------------------------- +# +# Check for optional components +# +#---------------------------------------------------------------------- +if(Osmium_FIND_COMPONENTS) + foreach(_component ${Osmium_FIND_COMPONENTS}) + string(TOUPPER ${_component} _component_uppercase) + set(Osmium_USE_${_component_uppercase} TRUE) + endforeach() +endif() + +#---------------------------------------------------------------------- +# Component 'io' is an alias for 'pbf' and 'xml' +if(Osmium_USE_IO) + set(Osmium_USE_PBF TRUE) + set(Osmium_USE_XML TRUE) +endif() + +#---------------------------------------------------------------------- +# Component 'ogr' is an alias for 'gdal' +if(Osmium_USE_OGR) + set(Osmium_USE_GDAL TRUE) +endif() + +#---------------------------------------------------------------------- +# Component 'pbf' +if(Osmium_USE_PBF) + find_package(OSMPBF) + find_package(Protobuf) + find_package(ZLIB) + find_package(Threads) + + if(OSMPBF_FOUND AND PROTOBUF_FOUND AND ZLIB_FOUND AND Threads_FOUND) + list(APPEND OSMIUM_PBF_LIBRARIES + ${OSMPBF_LIBRARIES} + ${PROTOBUF_LITE_LIBRARY} + ${ZLIB_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + ) + if(WIN32) + list(APPEND OSMIUM_PBF_LIBRARIES ws2_32) + endif() + list(APPEND OSMIUM_INCLUDE_DIRS + ${OSMPBF_INCLUDE_DIRS} + ${PROTOBUF_INCLUDE_DIR} + ${ZLIB_INCLUDE_DIR} + ) + else() + set(_missing_libraries 1) + message(WARNING "Osmium: Can not find some libraries for PBF input/output, please install them or configure the paths.") + endif() +endif() + +#---------------------------------------------------------------------- +# Component 'xml' +if(Osmium_USE_XML) + find_package(EXPAT) + find_package(BZip2) + find_package(ZLIB) + find_package(Threads) + + if(EXPAT_FOUND AND BZIP2_FOUND AND ZLIB_FOUND AND Threads_FOUND) + list(APPEND OSMIUM_XML_LIBRARIES + ${EXPAT_LIBRARIES} + ${BZIP2_LIBRARIES} + ${ZLIB_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + ) + list(APPEND OSMIUM_INCLUDE_DIRS + ${EXPAT_INCLUDE_DIR} + ${BZIP2_INCLUDE_DIR} + ${ZLIB_INCLUDE_DIR} + ) + else() + set(_missing_libraries 1) + message(WARNING "Osmium: Can not find some libraries for XML input/output, please install them or configure the paths.") + endif() +endif() + +#---------------------------------------------------------------------- +list(APPEND OSMIUM_IO_LIBRARIES + ${OSMIUM_PBF_LIBRARIES} + ${OSMIUM_XML_LIBRARIES} +) + +list(APPEND OSMIUM_LIBRARIES + ${OSMIUM_IO_LIBRARIES} +) + +#---------------------------------------------------------------------- +# Component 'geos' +if(Osmium_USE_GEOS) + find_path(GEOS_INCLUDE_DIR geos/geom.h) + find_library(GEOS_LIBRARY NAMES geos) + + if(GEOS_INCLUDE_DIR AND GEOS_LIBRARY) + SET(GEOS_FOUND 1) + list(APPEND OSMIUM_LIBRARIES ${GEOS_LIBRARY}) + list(APPEND OSMIUM_INCLUDE_DIRS ${GEOS_INCLUDE_DIR}) + else() + set(_missing_libraries 1) + message(WARNING "Osmium: GEOS library is required but not found, please install it or configure the paths.") + endif() +endif() + +#---------------------------------------------------------------------- +# Component 'gdal' (alias 'ogr') +if(Osmium_USE_GDAL) + find_package(GDAL) + + if(GDAL_FOUND) + list(APPEND OSMIUM_LIBRARIES ${GDAL_LIBRARIES}) + list(APPEND OSMIUM_INCLUDE_DIRS ${GDAL_INCLUDE_DIRS}) + else() + set(_missing_libraries 1) + message(WARNING "Osmium: GDAL library is required but not found, please install it or configure the paths.") + endif() +endif() + +#---------------------------------------------------------------------- +# Component 'proj' +if(Osmium_USE_PROJ) + find_path(PROJ_INCLUDE_DIR proj_api.h) + find_library(PROJ_LIBRARY NAMES proj) + + if(PROJ_INCLUDE_DIR AND PROJ_LIBRARY) + set(PROJ_FOUND 1) + list(APPEND OSMIUM_LIBRARIES ${PROJ_LIBRARY}) + list(APPEND OSMIUM_INCLUDE_DIRS ${PROJ_INCLUDE_DIR}) + else() + set(_missing_libraries 1) + message(WARNING "Osmium: PROJ.4 library is required but not found, please install it or configure the paths.") + endif() +endif() + +#---------------------------------------------------------------------- +# Component 'sparsehash' +if(Osmium_USE_SPARSEHASH) + find_path(SPARSEHASH_INCLUDE_DIR google/sparsetable) + + if(SPARSEHASH_INCLUDE_DIR) + # Find size of sparsetable::size_type. This does not work on older + # CMake versions because they can do this check only in C, not in C++. + include(CheckTypeSize) + set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR}) + set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable") + check_type_size("google::sparsetable<int>::size_type" SPARSETABLE_SIZE_TYPE LANGUAGE CXX) + set(CMAKE_EXTRA_INCLUDE_FILES) + set(CMAKE_REQUIRED_INCLUDES) + + # Falling back to checking size_t if google::sparsetable<int>::size_type + # could not be checked. + if(SPARSETABLE_SIZE_TYPE STREQUAL "") + check_type_size("void*" VOID_PTR_SIZE) + set(SPARSETABLE_SIZE_TYPE ${VOID_PTR_SIZE}) + endif() + + # Sparsetable::size_type must be at least 8 bytes (64bit), otherwise + # OSM object IDs will not fit. + if(SPARSETABLE_SIZE_TYPE GREATER 7) + set(SPARSEHASH_FOUND 1) + add_definitions(-DOSMIUM_WITH_SPARSEHASH=${SPARSEHASH_FOUND}) + list(APPEND OSMIUM_INCLUDE_DIRS ${SPARSEHASH_INCLUDE_DIR}) + else() + message(WARNING "Osmium: Disabled Google SparseHash library on 32bit system (size_type=${SPARSETABLE_SIZE_TYPE}).") + endif() + else() + set(_missing_libraries 1) + message(WARNING "Osmium: Google SparseHash library is required but not found, please install it or configure the paths.") + endif() +endif() + +#---------------------------------------------------------------------- + +list(REMOVE_DUPLICATES OSMIUM_INCLUDE_DIRS) + +if(OSMIUM_XML_LIBRARIES) + list(REMOVE_DUPLICATES OSMIUM_XML_LIBRARIES) +endif() + +if(OSMIUM_PBF_LIBRARIES) + list(REMOVE_DUPLICATES OSMIUM_PBF_LIBRARIES) +endif() + +if(OSMIUM_IO_LIBRARIES) + list(REMOVE_DUPLICATES OSMIUM_IO_LIBRARIES) +endif() + +if(OSMIUM_LIBRARIES) + list(REMOVE_DUPLICATES OSMIUM_LIBRARIES) +endif() + +#---------------------------------------------------------------------- +# +# Check that all required libraries are available +# +#---------------------------------------------------------------------- +if(Osmium_FIND_REQUIRED AND _missing_libraries) + message(FATAL_ERROR "Required library or libraries missing. Aborting.") +endif() + +#---------------------------------------------------------------------- +# +# Add compiler flags +# +#---------------------------------------------------------------------- +add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64) + +if(MSVC) + add_definitions(-wd4996) + + # Disable warning C4068: "unknown pragma" because we want it to ignore + # pragmas for other compilers. + add_definitions(-wd4068) + + # Disable warning C4715: "not all control paths return a value" because + # it generates too many false positives. + add_definitions(-wd4715) + + # Disable warning C4351: new behavior: elements of array '...' will be + # default initialized. The new behaviour is correct and we don't support + # old compilers anyway. + add_definitions(-wd4351) + + add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS) +endif() + +if(APPLE) +# following only available from cmake 2.8.12: +# add_compile_options(-stdlib=libc++) +# so using this instead: + add_definitions(-stdlib=libc++) + set(LDFLAGS ${LDFLAGS} -stdlib=libc++) +endif() + +#---------------------------------------------------------------------- + +# This is a set of recommended warning options that can be added when compiling +# libosmium code. +if(MSVC) + set(OSMIUM_WARNING_OPTIONS "/W3 /wd4514" CACHE STRING "Recommended warning options for libosmium") +else() + set(OSMIUM_WARNING_OPTIONS "-Wall -Wextra -pedantic -Wredundant-decls -Wdisabled-optimization -Wctor-dtor-privacy -Wnon-virtual-dtor -Woverloaded-virtual -Wsign-promo -Wold-style-cast -Wno-return-type" CACHE STRING "Recommended warning options for libosmium") +endif() + +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") + +if(Osmium_DEBUG) + message(STATUS "OSMIUM_XML_LIBRARIES=" ${OSMIUM_XML_LIBRARIES}) + message(STATUS "OSMIUM_PBF_LIBRARIES=" ${OSMIUM_PBF_LIBRARIES}) + message(STATUS "OSMIUM_IO_LIBRARIES=" ${OSMIUM_IO_LIBRARIES}) + message(STATUS "OSMIUM_LIBRARIES=" ${OSMIUM_LIBRARIES}) + message(STATUS "OSMIUM_INCLUDE_DIRS=" ${OSMIUM_INCLUDE_DIRS}) +endif() + diff --git a/cmake/common.cmake b/cmake/common.cmake new file mode 100644 index 0000000..e8b2205 --- /dev/null +++ b/cmake/common.cmake @@ -0,0 +1,90 @@ +#----------------------------------------------------------------------------- +# +# CMake config used in all projects in this repository. +# +#----------------------------------------------------------------------------- + +include(CppcheckTarget) +add_cppcheck_target(*.*pp) + + +#----------------------------------------------------------------------------- +# +# Decide which C++ version to use (Minimum/default: C++11). +# +#----------------------------------------------------------------------------- + +if(NOT MSVC) + if(NOT USE_CPP_VERSION) + set(USE_CPP_VERSION c++11) + endif() + message(STATUS "Use C++ version: ${USE_CPP_VERSION}") + # following only available from cmake 2.8.12: + # add_compile_options(-std=${USE_CPP_VERSION}) + # so using this instead: + add_definitions(-std=${USE_CPP_VERSION}) +endif() + + +#----------------------------------------------------------------------------- +# +# Compiler and Linker flags +# +#----------------------------------------------------------------------------- +if(MSVC) + set(USUAL_COMPILE_OPTIONS "/Ox") +else() + set(USUAL_COMPILE_OPTIONS "-O3 -g") +endif() + +if(WIN32) + add_definitions(-DWIN32 -D_WIN32 -DMSWIN32 -DBGDWIN32 + -DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -D_WIN32_IE=0x0600) +endif() + +set(CMAKE_CXX_FLAGS_DEV "${USUAL_COMPILE_OPTIONS}" + CACHE STRING "Flags used by the compiler during developer builds." + FORCE) + +set(CMAKE_EXE_LINKER_FLAGS_DEV "" + CACHE STRING "Flags used by the linker during developer builds." + FORCE) +mark_as_advanced( + CMAKE_CXX_FLAGS_DEV + CMAKE_EXE_LINKER_FLAGS_DEV +) + +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${USUAL_COMPILE_OPTIONS}" + CACHE STRING "Flags used by the compiler during RELWITHDEBINFO builds." + FORCE) + + +#----------------------------------------------------------------------------- +# +# Build Type +# +#----------------------------------------------------------------------------- +set(CMAKE_CONFIGURATION_TYPES "Debug Release RelWithDebInfo MinSizeRel Dev") + +# In 'Dev' mode: compile with very strict warnings and turn them into errors. +if(CMAKE_BUILD_TYPE STREQUAL "Dev") + if(NOT MSVC) + add_definitions(-Werror) + endif() + add_definitions(${OSMIUM_WARNING_OPTIONS}) +endif() + +# Force RelWithDebInfo build type if none was given +if(CMAKE_BUILD_TYPE) + set(build_type ${CMAKE_BUILD_TYPE}) +else() + set(build_type "RelWithDebInfo") +endif() + +set(CMAKE_BUILD_TYPE ${build_type} + CACHE STRING + "Choose the type of build, options are: ${CMAKE_CONFIGURATION_TYPES}." + FORCE) + + +#----------------------------------------------------------------------------- diff --git a/export_to_wkt/.gitignore b/export_to_wkt/.gitignore new file mode 100644 index 0000000..362f003 --- /dev/null +++ b/export_to_wkt/.gitignore @@ -0,0 +1 @@ +export_to_wkt diff --git a/export_to_wkt/CMakeLists.txt b/export_to_wkt/CMakeLists.txt new file mode 100644 index 0000000..3e08e79 --- /dev/null +++ b/export_to_wkt/CMakeLists.txt @@ -0,0 +1,24 @@ +#---------------------------------------------------------------------- +# +# Single example osmium-contrib CMakeLists.txt +# +#---------------------------------------------------------------------- +project(osmium-amenity-list) + +cmake_minimum_required(VERSION 2.8.5) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../cmake") + +find_package(Boost REQUIRED) +include_directories(${Boost_INCLUDE_DIRS}) + +find_package(Osmium REQUIRED COMPONENTS io sparsehash) +include_directories(${OSMIUM_INCLUDE_DIRS}) + +include(common) + +#---------------------------------------------------------------------- + +set(PROG export_to_wkt) +file(GLOB SOURCES *.cpp *.hpp) +add_executable(${PROG} ${SOURCES}) +target_link_libraries(${PROG} ${Boost_LIBRARIES} ${OSMIUM_LIBRARIES}) diff --git a/export_to_wkt/Makefile b/export_to_wkt/Makefile new file mode 100644 index 0000000..8f43712 --- /dev/null +++ b/export_to_wkt/Makefile @@ -0,0 +1,12 @@ + +all: + mkdir -p build && cd build && cmake .. && $(MAKE) + +clean: + if test -d build; then cd build && $(MAKE) clean; fi + +distclean: + rm -fr build + +.PHONY: clean distclean + diff --git a/export_to_wkt/README.md b/export_to_wkt/README.md new file mode 100644 index 0000000..83658d6 --- /dev/null +++ b/export_to_wkt/README.md @@ -0,0 +1,45 @@ + +# Export to WKT + +Write all node, way, and area geometries out in WKT format. + + +## Prerequisites + +You'll need libosmium (http://osmcode.org/libosmium) and its dependencies +installed first. + + +## Building + +Osmium-contrib uses CMake for its builds. For Unix/Linux systems a simple +Makefile wrapper is provided to make the build even easier. + +To build just type `make`. Results will be in the `build` subdirectory. + +Or you can go the long route explicitly calling CMake as follows: + +``` +mkdir build +cd build +cmake .. +make +``` + + +## Running + +Run the program with an OSM file as its only argument: + +`export_to_wkt berlin.osm.pbf` + + +## License + +This program is released into the Public Domain. + + +## Author + +Jochen Topf (http://jochentopf.com/) + diff --git a/export_to_wkt/export_to_wkt.cpp b/export_to_wkt/export_to_wkt.cpp new file mode 100755 index 0000000..e8c71ee --- /dev/null +++ b/export_to_wkt/export_to_wkt.cpp @@ -0,0 +1,77 @@ + +// The code in this file is released into the Public Domain. + +#include <iostream> +#include <string> + +#include <osmium/area/assembler.hpp> +#include <osmium/area/multipolygon_collector.hpp> +#include <osmium/geom/wkt.hpp> +#include <osmium/handler.hpp> +#include <osmium/io/any_input.hpp> +#include <osmium/visitor.hpp> + +#include <osmium/index/map/sparse_mem_array.hpp> +#include <osmium/handler/node_locations_for_ways.hpp> +typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type; +typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type; + +class ExportToWKTHandler : public osmium::handler::Handler { + + osmium::geom::WKTFactory<> m_factory; + +public: + + void node(const osmium::Node& node) { + std::cout << 'n' << node.id() << ' ' << m_factory.create_point(node) << "\n"; + } + + void way(const osmium::Way& way) { + try { + std::cout << 'w' << way.id() << ' ' << m_factory.create_linestring(way) << "\n"; + } catch (osmium::geometry_error&) { + // ignore broken geometries (such as ways with only a single node) + } + } + + void area(const osmium::Area& area) { + try { + std::cout << 'a' << area.id() << ' ' << m_factory.create_multipolygon(area) << "\n"; + } catch (osmium::geometry_error&) { + // ignore broken geometries (such as illegal multipolygons) + } + } + +}; // class ExportToWKTHandler + +int main(int argc, char* argv[]) { + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " OSMFILE\n"; + exit(1); + } + + std::string input_filename {argv[1]}; + + osmium::area::Assembler::config_type assembler_config; + osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config); + + std::cerr << "Pass 1...\n"; + osmium::io::Reader reader1(input_filename); + collector.read_relations(reader1); + std::cerr << "Pass 1 done\n"; + + index_type index; + location_handler_type location_handler(index); + + std::cerr << "Pass 2...\n"; + ExportToWKTHandler export_handler; + osmium::io::Reader reader2(input_filename); + osmium::apply(reader2, location_handler, export_handler, collector.handler([&export_handler](const osmium::memory::Buffer& buffer) { + osmium::apply(buffer, export_handler); + })); + std::cerr << "Pass 2 done\n"; + + google::protobuf::ShutdownProtobufLibrary(); + +} + diff --git a/mapolution/.gitignore b/mapolution/.gitignore new file mode 100644 index 0000000..95afeea --- /dev/null +++ b/mapolution/.gitignore @@ -0,0 +1,3 @@ +mapolution +*.o +anim.gif diff --git a/mapolution/CMakeLists.txt b/mapolution/CMakeLists.txt new file mode 100644 index 0000000..2e45839 --- /dev/null +++ b/mapolution/CMakeLists.txt @@ -0,0 +1,31 @@ +#---------------------------------------------------------------------- +# +# Single example osmium-contrib CMakeLists.txt +# +#---------------------------------------------------------------------- +project(osmium-mapolution) + +cmake_minimum_required(VERSION 2.8.5) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../cmake") + +find_package(Boost REQUIRED COMPONENTS program_options filesystem system) +include_directories(${Boost_INCLUDE_DIRS}) + +find_package(Osmium REQUIRED COMPONENTS io gdal proj sparsehash) +include_directories(${OSMIUM_INCLUDE_DIRS}) + +include(common) + +#---------------------------------------------------------------------- + +if(HANDLER) + add_definitions(-DHANDLER=${HANDLER}) + message(STATUS "Using handler: ${HANDLER}") +endif() + +#---------------------------------------------------------------------- + +set(PROG mapolution) +file(GLOB SOURCES *.cpp *.hpp) +add_executable(${PROG} ${SOURCES}) +target_link_libraries(${PROG} ${Boost_LIBRARIES} ${OSMIUM_LIBRARIES}) diff --git a/mapolution/Makefile b/mapolution/Makefile new file mode 100644 index 0000000..8f43712 --- /dev/null +++ b/mapolution/Makefile @@ -0,0 +1,12 @@ + +all: + mkdir -p build && cd build && cmake .. && $(MAKE) + +clean: + if test -d build; then cd build && $(MAKE) clean; fi + +distclean: + rm -fr build + +.PHONY: clean distclean + diff --git a/mapolution/README.md b/mapolution/README.md new file mode 100644 index 0000000..a44918c --- /dev/null +++ b/mapolution/README.md @@ -0,0 +1,70 @@ + +# Mapolution + +Show evolution of OSM map. + +## Prerequisites + +You'll need: + +* libosmium (http://osmcode.org/libosmium) and its dependencies. +* gdal (http://gdal.org/) library, more specifically the `gdal_rasterize` + command. (On Debian/Ubuntu install `libgdal-dev` and `gdal-bin` packages.) +* `boost_filesystem` and `boost_program_options` + (http://boost.org/) version 1.48 or later. + (On Debian/Ubuntu install `libboost-filesystem-dev`, + and `libboost-program-options-dev` packages.) + + +## Building + +Osmium-contrib uses CMake for its builds. For Unix/Linux systems a simple +Makefile wrapper is provided to make the build even easier. + +To build just type `make`. Results will be in the `build` subdirectory. + +Or you can go the long route explicitly calling CMake as follows: + + mkdir build + cd build + cmake .. + make + +You can switch to a different handler: + + cmake -DHANDLER=RoadsHandler + +Available handlers are `BuildingsHandler`, `RestaurantsHandler`, and +`RoadsHandler`. See the `handlers` directory. You can write you own handler +easily. + + +# Running + +First you need a full history dump extract of a city or so. The area +can't be too large, because everything has to fit into memory. See +http://osm.personalwerk.de/full-history-extracts/ for some downloads. + +Run + + ./mapolution -S 30 OSMFILE + +This will create shapefiles in `out` directory with building data for +every 30 days. + +Then run + + ./rasterize.sh + +This will create an animated GIF called `anim.gif` with the result. + + +# Customizing + +See `./mapolution --help` for more parameters. + +See the beginning of the `rasterize.sh` script for some parameters. + +See the `handlers` directory for how to create handlers and create +your own. You have to add an include directive to `main.cpp`. + diff --git a/mapolution/cmdline_options.cpp b/mapolution/cmdline_options.cpp new file mode 100644 index 0000000..ce64a62 --- /dev/null +++ b/mapolution/cmdline_options.cpp @@ -0,0 +1,105 @@ + +#include "cmdline_options.hpp" + +#include <boost/program_options.hpp> + +osmium::Timestamp Options::parse_time(std::string t) { + try { + t.append("T00:00:00Z"); + osmium::Timestamp ts(t.c_str()); + + if (ts < osmium::Timestamp("2005-01-01T00:00:00Z")) { + std::cerr << "Dates before 2005 don't make sense, because OSM didn't exist then.\n"; + exit(return_code::fatal); + } + + return ts; + } catch (std::invalid_argument&) { + std::cerr << "Can't understand the date, format should be YYYY-MM-DD.\n"; + exit(return_code::fatal); + } +} + +Options::Options(int argc, char* argv[]) { + namespace po = boost::program_options; + + po::variables_map vm; + + try { + po::options_description cmdline("Allowed options"); + cmdline.add_options() + ("help,h", "Print this help message") + ("quiet,q", "Suppress verbose output messages") + ("output,o", po::value<std::string>(), "Output directory") + ("output-format,f", po::value<std::string>(), "OGR format of output files") + ("input-format,F", po::value<std::string>(), "Format of input file") + ("crs,c", po::value<int>(), "EPSG code of Coordinate Reference System") + ("start-time,s", po::value<std::string>(), "Start time (yyyy-mm-dd)") + ("end-time,e", po::value<std::string>(), "End time (yyyy-mm-dd)") + ("time-step,S", po::value<int>(), "Time step in days (default: 7 days)") + ; + + po::options_description hidden("Hidden options"); + hidden.add_options() + ("input-filename", po::value<std::string>(), "Input file") + ; + + po::options_description desc("Usage: mapolution [OPTIONS] OSMFILE"); + desc.add(cmdline); + + po::options_description all; + all.add(cmdline).add(hidden); + + po::positional_options_description positional; + positional.add("input-filename", 1); + + po::store(po::command_line_parser(argc, argv).options(all).positional(positional).run(), vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << desc << "\n"; + exit(0); + } + + if (vm.count("quiet")) { + vout.verbose(false); + } + + if (vm.count("output")) { + output_directory = vm["output"].as<std::string>(); + } + + if (vm.count("input-filename")) { + input_filename = vm["input-filename"].as<std::string>(); + } + + if (vm.count("input-format")) { + input_format = vm["input-format"].as<std::string>(); + } + + if (vm.count("output-format")) { + output_format = vm["output-format"].as<std::string>(); + } + + if (vm.count("crs")) { + epsg = vm["crs"].as<int>(); + } + + if (vm.count("start-time")) { + start_time = parse_time(vm["start-time"].as<std::string>()); + } + + if (vm.count("end-time")) { + end_time = parse_time(vm["end-time"].as<std::string>()); + } + + if (vm.count("time-step")) { + time_step = vm["time-step"].as<int>(); + } + + } catch (boost::program_options::error& e) { + std::cerr << "Error parsing command line: " << e.what() << std::endl; + exit(return_code::fatal); + } +} + diff --git a/mapolution/cmdline_options.hpp b/mapolution/cmdline_options.hpp new file mode 100644 index 0000000..3482a21 --- /dev/null +++ b/mapolution/cmdline_options.hpp @@ -0,0 +1,35 @@ +#ifndef CMDLINE_OPTIONS_HPP +#define CMDLINE_OPTIONS_HPP + +#include <string> + +#include <osmium/osm/timestamp.hpp> +#include <osmium/util/verbose_output.hpp> + +enum return_code : int { + okay = 0, + error = 1, + fatal = 2 +}; + +struct Options { + + osmium::util::VerboseOutput vout {true}; + + std::string input_filename {"-"}; + std::string output_directory {"out"}; + std::string input_format; + std::string output_format {"ESRI Shapefile"}; + int epsg = 4326; + + osmium::Timestamp start_time; + osmium::Timestamp end_time; + int time_step = 7; // default is 7 days == one week + + Options(int argc, char* argv[]); + + osmium::Timestamp parse_time(std::string); + +}; // struct Options + +#endif // CMDLINE_OPTIONS_HPP diff --git a/mapolution/gdalcpp.hpp b/mapolution/gdalcpp.hpp new file mode 100644 index 0000000..82dcd65 --- /dev/null +++ b/mapolution/gdalcpp.hpp @@ -0,0 +1,221 @@ +#ifndef GDALCPP_HPP +#define GDALCPP_HPP + +#include <algorithm> +#include <memory> +#include <stdexcept> +#include <string> +#include <vector> + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable : 4458) +#else +# pragma GCC diagnostic push +# ifdef __clang__ +# pragma GCC diagnostic ignored "-Wdocumentation-unknown-command" +# endif +# pragma GCC diagnostic ignored "-Wfloat-equal" +# pragma GCC diagnostic ignored "-Wold-style-cast" +# pragma GCC diagnostic ignored "-Wpadded" +# pragma GCC diagnostic ignored "-Wredundant-decls" +# pragma GCC diagnostic ignored "-Wshadow" +#endif + +#include <gdal_priv.h> +#include <gdal_version.h> +#include <ogr_api.h> +#include <ogrsf_frmts.h> + +#ifdef _MSC_VER +# pragma warning(pop) +#else +# pragma GCC diagnostic pop +#endif + +/** + * C++11 convenience wrapper classes for GDAL/OGR. + */ +namespace gdalcpp { + +#if GDAL_VERSION_MAJOR >= 2 + typedef GDALDriver gdal_driver_type; + typedef GDALDataset gdal_dataset_type; +#else + typedef OGRSFDriver gdal_driver_type; + typedef OGRDataSource gdal_dataset_type; +#endif + + namespace detail { + + struct init_wrapper { + init_wrapper() { OGRRegisterAll(); } + ~init_wrapper() { OGRCleanupAll(); } + }; + + struct init_library { + init_library() { + static init_wrapper iw; + } + }; + + class Driver : private init_library { + + gdal_driver_type* m_driver; + + public: + + Driver(const std::string& name) : + init_library(), + m_driver(OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(name.c_str())) { + if (!m_driver) { + throw std::runtime_error("unknown driver: " + name); + } + } + + gdal_driver_type& get() const { + return *m_driver; + } + + }; // struct Driver + + struct Options { + + std::vector<std::string> m_options; + std::unique_ptr<const char*[]> m_ptrs; + + Options(const std::vector<std::string>& options) : + m_options(options), + m_ptrs(new const char*[options.size()+1]) { + std::transform(m_options.begin(), m_options.end(), m_ptrs.get(), [&](const std::string& s) { + return s.data(); + }); + m_ptrs[options.size()] = nullptr; + } + + char** get() const { + return const_cast<char**>(m_ptrs.get()); + } + + }; // struct Options + + } // namespace detail + + class Dataset { + + struct gdal_dataset_deleter { + void operator()(gdal_dataset_type* ds) { +#if GDAL_VERSION_MAJOR >= 2 + GDALClose(ds); +#else + OGRDataSource::DestroyDataSource(ds); +#endif + } + }; // struct gdal_dataset_deleter + + detail::Options m_options; + std::unique_ptr<gdal_dataset_type, gdal_dataset_deleter> m_dataset; + OGRSpatialReference m_spatial_reference; + + public: + + Dataset(const std::string& driver, const std::string& name, const std::string& proj, const std::vector<std::string>& options = {}) : + m_options(options), +#if GDAL_VERSION_MAJOR >= 2 + m_dataset(detail::Driver(driver).get().Create(name.c_str(), 0, 0, 0, GDT_Unknown, m_options.get())) { +#else + m_dataset(detail::Driver(driver).get().CreateDataSource(name.c_str(), m_options.get())) { +#endif + if (!m_dataset) { + throw std::runtime_error("creating data source '" + name + "' failed"); + } + m_spatial_reference.importFromProj4(proj.c_str()); + } + + gdal_dataset_type& get() const { + return *m_dataset; + } + + OGRSpatialReference* spatial_reference() { + return &m_spatial_reference; + } + + }; // class Dataset + + class Layer { + + OGRLayer* m_layer; + + public: + + Layer(Dataset& dataset, const std::string& name, OGRwkbGeometryType type) : + m_layer(dataset.get().CreateLayer(name.c_str(), dataset.spatial_reference(), type)) { + if (!m_layer) { + throw std::runtime_error("layer creation failed"); + } + } + + OGRLayer* get() const { + return m_layer; + } + + Layer& add_field(const std::string& name, OGRFieldType type, int width, int precision=0) { + OGRFieldDefn field(name.c_str(), type); + field.SetWidth(width); + field.SetPrecision(precision); + + if (m_layer->CreateField(&field) != OGRERR_NONE) { + throw std::runtime_error("field creation failed"); + } + + return *this; + } + + Layer& StartTransaction() { + m_layer->StartTransaction(); + return *this; + } + + Layer& CommitTransaction() { + m_layer->CommitTransaction(); + return *this; + } + + }; // class Layer + + class Feature { + + OGRLayer* m_layer; + OGRFeature m_feature; + + public: + + Feature(Layer& layer, std::unique_ptr<OGRGeometry>&& geometry) : + m_layer(layer.get()), + m_feature(m_layer->GetLayerDefn()) { + m_feature.SetGeometry(geometry.get()); + } + + void add_to_layer() { + if (m_layer->CreateFeature(&m_feature) != OGRERR_NONE) { + std::runtime_error("feature creation failed"); + } + } + + template <class T> + Feature& set_field(int n, 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)); + return *this; + } + + }; // class Feature + +} // namespace gdalcpp + +#endif // GDALCPP_HPP diff --git a/mapolution/geom_handler.hpp b/mapolution/geom_handler.hpp new file mode 100644 index 0000000..ec3b994 --- /dev/null +++ b/mapolution/geom_handler.hpp @@ -0,0 +1,63 @@ +#ifndef GEOM_HANDLER_HPP +#define GEOM_HANDLER_HPP + +#include "gdalcpp.hpp" + +#include <osmium/geom/ogr.hpp> +#include <osmium/geom/projection.hpp> + +class GeomHandler : public osmium::handler::Handler { + +public: + + typedef osmium::geom::OGRFactory<osmium::geom::Projection> factory_type; + +private: + + factory_type& m_factory; + OGREnvelope m_envelope; + + gdalcpp::Dataset& m_dataset; + +public: + + GeomHandler(factory_type& factory, gdalcpp::Dataset& dataset) : + m_factory(factory), + m_dataset(dataset) { + } + + gdalcpp::Dataset& dataset() const { + return m_dataset; + } + + OGREnvelope envelope() const { + return m_envelope; + } + + std::unique_ptr<OGRPoint> create_point(const osmium::Node& node) { + std::unique_ptr<OGRPoint> geom = m_factory.create_point(node); + OGREnvelope env; + geom->getEnvelope(&env); + m_envelope.Merge(env); + return geom; + } + + std::unique_ptr<OGRLineString> create_linestring(const osmium::Way& way) { + std::unique_ptr<OGRLineString> geom = m_factory.create_linestring(way); + OGREnvelope env; + geom->getEnvelope(&env); + m_envelope.Merge(env); + return geom; + } + + std::unique_ptr<OGRMultiPolygon> create_multipolygon(const osmium::Area& area) { + std::unique_ptr<OGRMultiPolygon> geom = m_factory.create_multipolygon(area); + OGREnvelope env; + geom->getEnvelope(&env); + m_envelope.Merge(env); + return geom; + } + +}; // class GeomHandler + +#endif // GEOM_HANDLER_HPP diff --git a/mapolution/handlers/buildings.hpp b/mapolution/handlers/buildings.hpp new file mode 100644 index 0000000..505abb2 --- /dev/null +++ b/mapolution/handlers/buildings.hpp @@ -0,0 +1,43 @@ +#ifndef HANDLERS_BUILDINGS_HPP +#define HANDLERS_BUILDINGS_HPP + +class BuildingsHandler : public GeomHandler { + + gdalcpp::Layer m_layer; + +public: + + BuildingsHandler(factory_type& factory, gdalcpp::Dataset& ds, const std::string& date) : + GeomHandler(factory, ds), + m_layer(dataset(), "buildings_" + date, wkbMultiPolygon) { + m_layer.add_field("id", OFTInteger, 10); + m_layer.StartTransaction(); + } + + ~BuildingsHandler() { + m_layer.CommitTransaction(); + if (m_layer.get()->GetFeatureCount() == 0) { + std::cerr << "WARNING: No features in layer '" << m_layer.get()->GetName() << "'.\n"; + } + } + + void area(const osmium::Area& area) { + try { + const char* building = area.tags()["building"]; + if (building) { + gdalcpp::Feature f(m_layer, create_multipolygon(area)); + f.set_field("id", static_cast<int>(area.id())); + f.add_to_layer(); + } + } catch (osmium::not_found&) { + // ignore missing node locations + } catch (osmium::invalid_location&) { + // ignore missing node locations + } catch (osmium::geometry_error&) { + // ignore broken geometries (such as illegal multipolygons) + } + } + +}; // class BuildingsHandler + +#endif // HANDLERS_BUILDINGS_HPP diff --git a/mapolution/handlers/restaurants.hpp b/mapolution/handlers/restaurants.hpp new file mode 100644 index 0000000..a98ba70 --- /dev/null +++ b/mapolution/handlers/restaurants.hpp @@ -0,0 +1,59 @@ +#ifndef HANDLERS_RESTAURANTS_HPP +#define HANDLERS_RESTAURANTS_HPP + +class RestaurantsHandler : public GeomHandler { + + gdalcpp::Layer m_layer; + +public: + + RestaurantsHandler(factory_type& factory, gdalcpp::Dataset& ds, const std::string& date) : + GeomHandler(factory, ds), + m_layer(dataset(), "restaurants_" + date, wkbPoint) { + m_layer.add_field("id", OFTReal, 10); + m_layer.StartTransaction(); + } + + ~RestaurantsHandler() { + m_layer.CommitTransaction(); + } + + void node(const osmium::Node& node) { + try { + const char* amenity = node.tags()["amenity"]; + if (amenity && !strcmp(amenity, "restaurant")) { + gdalcpp::Feature f(m_layer, create_point(node)); + f.set_field("id", static_cast<double>(node.id())); + f.add_to_layer(); + } + } catch (osmium::not_found&) { + // ignore missing node locations + } catch (osmium::invalid_location&) { + // ignore missing node locations + } catch (osmium::geometry_error&) { + // ignore broken geometries (such as illegal multipolygons) + } + } + +#if 0 + void area(const osmium::Area& area) { + try { + const char* amenity = area.tags()["amenity"]; + if (amenity && !strcmp(amenity, "restaurant")) { + gdalcpp::Feature f(m_layer, create_point(area.)); // get one node XXX + f.set_field("id", static_cast<int>(area.id())); + f.add_to_layer(); + } + } catch (osmium::not_found&) { + // ignore missing node locations + } catch (osmium::invalid_location&) { + // ignore missing node locations + } catch (osmium::geometry_error&) { + // ignore broken geometries (such as illegal multipolygons) + } + } +#endif + +}; // class RestaurantsHandler + +#endif // HANDLERS_RESTAURANTS_HPP diff --git a/mapolution/handlers/roads.hpp b/mapolution/handlers/roads.hpp new file mode 100644 index 0000000..70cad85 --- /dev/null +++ b/mapolution/handlers/roads.hpp @@ -0,0 +1,42 @@ +#ifndef HANDLERS_ROADS_HPP +#define HANDLERS_ROADS_HPP + +class RoadsHandler : public GeomHandler { + + gdalcpp::Layer m_layer; + +public: + + RoadsHandler(factory_type& factory, gdalcpp::Dataset& ds, const std::string& date) : + GeomHandler(factory, ds), + m_layer(dataset(), "roads_" + date, wkbLineString) { + m_layer.add_field("id", OFTInteger, 10); + m_layer.add_field("type", OFTString, 30); + m_layer.StartTransaction(); + } + + ~RoadsHandler() { + m_layer.CommitTransaction(); + } + + void way(const osmium::Way& way) { + try { + const char* highway = way.tags()["highway"]; + if (highway) { + gdalcpp::Feature f(m_layer, create_linestring(way)); + f.set_field("id", static_cast<int>(way.id())); + f.set_field("type", highway); + f.add_to_layer(); + } + } catch (osmium::not_found&) { + // ignore missing node locations + } catch (osmium::invalid_location&) { + // ignore missing node locations + } catch (osmium::geometry_error&) { + // ignore broken geometries (such as ways with only a single node) + } + } + +}; // class RoadsHandler + +#endif // HANDLERS_ROADS_HPP diff --git a/mapolution/main.cpp b/mapolution/main.cpp new file mode 100644 index 0000000..24ac894 --- /dev/null +++ b/mapolution/main.cpp @@ -0,0 +1,253 @@ + +#include <numeric> +#include <fstream> + +#include <boost/filesystem.hpp> + +#include <osmium/area/assembler.hpp> +#include <osmium/area/multipolygon_collector.hpp> +#include <osmium/diff_iterator.hpp> +#include <osmium/handler.hpp> +#include <osmium/io/any_input.hpp> +#include <osmium/visitor.hpp> + +#include <osmium/index/map/sparse_mem_array.hpp> +#include <osmium/handler/node_locations_for_ways.hpp> +typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type; +typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type; + +#include "cmdline_options.hpp" +#include "geom_handler.hpp" + +#include "handlers/buildings.hpp" +#include "handlers/restaurants.hpp" +#include "handlers/roads.hpp" + +constexpr size_t initial_buffer_size = 10 * 1024 * 1024; + +OGREnvelope extract( + Options& options, + osmium::geom::OGRFactory<osmium::geom::Projection>& factory, + osmium::memory::Buffer::t_iterator<osmium::OSMObject> begin, + osmium::memory::Buffer::t_iterator<osmium::OSMObject> relations, + osmium::memory::Buffer::t_iterator<osmium::OSMObject> end, + osmium::Timestamp point_in_time) { + + options.vout << "Working on " << point_in_time << "...\n"; + options.vout << " Filtering data...\n"; + + // nodes and ways + typedef osmium::DiffIterator<osmium::memory::Buffer::t_iterator<osmium::OSMObject>> diff_iterator; + osmium::memory::Buffer fbuffer(initial_buffer_size, osmium::memory::Buffer::auto_grow::yes); + { + auto dbegin = diff_iterator(begin, relations); + auto dend = diff_iterator(relations, relations); + + std::for_each(dbegin, dend, [point_in_time, &fbuffer](const osmium::DiffObject& d) { + if (((d.end_time() == 0 || d.end_time() > point_in_time) && + d.start_time() <= point_in_time) && + d.curr().visible()) { + fbuffer.add_item(d.curr()); + fbuffer.commit(); + } + }); + } + options.vout << " Done. Filtered data needs " + << (fbuffer.committed() / (1024 * 1024)) + << " MBytes.\n"; + + // relations + osmium::memory::Buffer rbuffer(initial_buffer_size, osmium::memory::Buffer::auto_grow::yes); + { + auto dbegin = diff_iterator(relations, end); + auto dend = diff_iterator(end, end); + + std::for_each(dbegin, dend, [point_in_time, &rbuffer](const osmium::DiffObject& d) { + if (((d.end_time() == 0 || d.end_time() > point_in_time) && + d.start_time() <= point_in_time) && + d.curr().visible()) { + rbuffer.add_item(d.curr()); + rbuffer.commit(); + } + }); + } + + osmium::area::Assembler::config_type assembler_config; + osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config); + + options.vout << " Reading relations...\n"; + collector.read_relations(rbuffer.cbegin(), rbuffer.cend()); + + index_type index_pos; + location_handler_type location_handler(index_pos); + location_handler.ignore_errors(); + + options.vout << " Creating geometries...\n"; + std::string date = point_in_time.to_iso().substr(0, 10); + + std::vector<std::string> datasource_options; + std::string datasource_name = options.output_directory + "/" + date; + if (options.output_format == "GeoJSON") { + datasource_name += ".json"; + } else if (options.output_format == "SQLite") { + datasource_name += ".db"; + datasource_options.push_back("SPATIALITE=TRUE"); + CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE"); + CPLSetConfigOption("OGR_SQLITE_CACHE", "512"); + } + + gdalcpp::Dataset dataset(options.output_format, datasource_name, factory.proj_string(), datasource_options); + +#ifdef HANDLER + HANDLER geom_handler(factory, dataset, date); +#else + BuildingsHandler geom_handler(factory, dataset, date); +#endif + osmium::apply(fbuffer.begin(), + fbuffer.end(), + location_handler, + geom_handler, + collector.handler([&geom_handler](const osmium::memory::Buffer& buffer) { + osmium::apply(buffer, geom_handler); + })); + + return geom_handler.envelope(); +} + +typedef std::pair<osmium::Timestamp, osmium::Timestamp> tspair; +template <class TIter> +tspair min_max_timestamp(TIter begin, TIter end) { + tspair init = std::make_pair(osmium::end_of_time(), osmium::start_of_time()); + return std::accumulate(begin, end, init, [](tspair start_end, const osmium::OSMObject& obj) -> tspair { + if (obj.timestamp() < start_end.first) { + start_end.first = obj.timestamp(); + } + if (obj.timestamp() > start_end.second) { + start_end.second = obj.timestamp(); + } + return start_end; + }); +} + +void check_and_create_directory(const std::string& directory) { + boost::filesystem::path dir(directory); + + try { + boost::filesystem::create_directories(dir); + } catch (boost::filesystem::filesystem_error& e) { + std::cerr << "Error creating output directory '" + << directory + << "': " + << e.what() + << ".\n"; + exit(return_code::fatal); + } + + int num_entries = std::distance(boost::filesystem::directory_iterator(dir), + boost::filesystem::directory_iterator()); + + if (num_entries != 0) { + std::cerr << "Output directory '" << directory << "' is not empty.\n"; + exit(return_code::fatal); + } +} + +int main(int argc, char* argv[]) { + Options options(argc, argv); + + options.vout << "Options from command line or defaults:\n"; + options.vout << " Input file: " << options.input_filename << "\n"; + if (!options.input_format.empty()) { + options.vout << " Input format: " << options.input_format << "\n"; + } + options.vout << " Coordinate Reference System: " << options.epsg << "\n"; + options.vout << " Output directory: " << options.output_directory << "\n"; + options.vout << " Output OGR format: " << options.output_format << "\n"; + if (options.start_time) { + options.vout << " Start time: " << options.start_time << "\n"; + } + if (options.end_time) { + options.vout << " End time: " << options.end_time << "\n"; + } + options.vout << " Time steps: " << options.time_step << " day(s)\n"; + + if (options.start_time && options.end_time && options.start_time > options.end_time) { + options.vout << "Your end time is before the start time. Switching them around.\n"; + std::swap(options.start_time, options.end_time); + } + + check_and_create_directory(options.output_directory); + + options.vout << "Reading input file into memory...\n"; + osmium::io::File file(options.input_filename, options.input_format); + osmium::memory::Buffer ibuffer = osmium::io::read_file(file, osmium::osm_entity_bits::object); + options.vout << "Done. Input data needs " << (ibuffer.committed() / (1024 * 1024)) << " MBytes.\n"; + + auto first_relation = std::find_if(ibuffer.begin<osmium::OSMObject>(), + ibuffer.end<osmium::OSMObject>(), + [](const osmium::OSMObject& obj){ + return obj.type() == osmium::item_type::relation; + }); + + const int seconds_per_day = 24 * 60 * 60; + + osmium::Timestamp start_time = options.start_time; + osmium::Timestamp end_time = options.end_time; + if (!start_time || !end_time) { + tspair min_max = min_max_timestamp(ibuffer.cbegin<osmium::OSMObject>(), + ibuffer.cend<osmium::OSMObject>()); + + if (!start_time) { + options.vout << "No start time on command line, got it from file contents\n"; + start_time = min_max.first / seconds_per_day * seconds_per_day; + } + if (!end_time) { + options.vout << "No end time on command line, got it from file contents\n"; + end_time = min_max.second / seconds_per_day * seconds_per_day; + } + } + + options.vout << "Start time: " << start_time << "\n"; + options.vout << "End time : " << end_time << "\n"; + + osmium::geom::OGRFactory<osmium::geom::Projection> factory(osmium::geom::Projection(options.epsg)); + + OGREnvelope envelope_all; + auto step = options.time_step * seconds_per_day; + for (osmium::Timestamp t = start_time; t <= end_time; t += step) { + OGREnvelope env = extract( + options, + factory, + ibuffer.begin<osmium::OSMObject>(), + first_relation, + ibuffer.end<osmium::OSMObject>(), + t + ); + envelope_all.Merge(env); + } + + std::ofstream env_out(options.output_directory + "/bbox", std::ofstream::out); + env_out << std::fixed + << "XMIN=" << envelope_all.MinX << "\n" + << "YMIN=" << envelope_all.MinY << "\n" + << "XMAX=" << envelope_all.MaxX << "\n" + << "YMAX=" << envelope_all.MaxY << "\n"; + + options.vout << "Bounding box calculated from output data: (" + << std::fixed + << envelope_all.MinX + << ',' + << envelope_all.MinY + << ") (" + << envelope_all.MaxX + << ',' + << envelope_all.MaxY + << ")\n"; + + options.vout << "Done.\n"; + + google::protobuf::ShutdownProtobufLibrary(); + + return return_code::okay; +} + diff --git a/mapolution/rasterize.sh b/mapolution/rasterize.sh new file mode 100755 index 0000000..55e1a0e --- /dev/null +++ b/mapolution/rasterize.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# +# rasterize.sh +# + +set -e + +RED=255 +GREEN=255 +BLUE=255 + +DELAY=10 + +WIDTH=1024 + +# ------------------------ + +DIR=out + +. $DIR/bbox + +geo_width=`echo "$XMAX - $XMIN" | bc -q | tail -1` +geo_height=`echo "$YMAX - $YMIN" | bc -q | tail -1` + +ratio=`echo "$WIDTH / $geo_width" | bc -q | tail -1` +HEIGHT=`echo "$geo_height * $ratio" | bc -q | tail -1 | cut -d. -f1` + +echo "Rasterizing vector data..." +for i in out/????-??-??; do + date=`basename $i` + echo " $date..." + gdal_rasterize -q -ot Byte -te $XMIN $YMIN $XMAX $YMAX -burn $RED -burn $GREEN -burn $BLUE -ts $WIDTH $HEIGHT $DIR/$date/*.shp $DIR/$date.tif + convert -quiet $DIR/$date.tif $DIR/$date.gif +done + +echo "Creating GIF animation..." +gifsicle --delay=$DELAY --optimize=3 --loop $DIR/*.gif > anim.gif + +echo "Done." + diff --git a/node_density/.gitignore b/node_density/.gitignore new file mode 100644 index 0000000..7597305 --- /dev/null +++ b/node_density/.gitignore @@ -0,0 +1,3 @@ +node_density +*.o +*.tif diff --git a/node_density/CMakeLists.txt b/node_density/CMakeLists.txt new file mode 100644 index 0000000..d40f275 --- /dev/null +++ b/node_density/CMakeLists.txt @@ -0,0 +1,24 @@ +#---------------------------------------------------------------------- +# +# Single example osmium-contrib CMakeLists.txt +# +#---------------------------------------------------------------------- +project(osmium-node-density) + +cmake_minimum_required(VERSION 2.8.5) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../cmake") + +find_package(Boost REQUIRED COMPONENTS program_options) +include_directories(${Boost_INCLUDE_DIRS}) + +find_package(Osmium REQUIRED COMPONENTS io gdal proj sparsehash) +include_directories(${OSMIUM_INCLUDE_DIRS}) + +include(common) + +#---------------------------------------------------------------------- + +set(PROG node_density) +file(GLOB SOURCES *.cpp *.hpp) +add_executable(${PROG} ${SOURCES}) +target_link_libraries(${PROG} ${Boost_LIBRARIES} ${OSMIUM_LIBRARIES}) diff --git a/node_density/Makefile b/node_density/Makefile new file mode 100644 index 0000000..8f43712 --- /dev/null +++ b/node_density/Makefile @@ -0,0 +1,12 @@ + +all: + mkdir -p build && cd build && cmake .. && $(MAKE) + +clean: + if test -d build; then cd build && $(MAKE) clean; fi + +distclean: + rm -fr build + +.PHONY: clean distclean + diff --git a/node_density/README.md b/node_density/README.md new file mode 100644 index 0000000..86a632d --- /dev/null +++ b/node_density/README.md @@ -0,0 +1,109 @@ + +# Node Density + +Visualize the node density in a given OSM file. + + +## Prerequisites + +You'll need libosmium (http://osmcode.org/libosmium) and its dependencies +installed first. + +You'll need the following libraries: + +GDAL + http://www.gdal.org/ + Debian/Ubuntu: libgdal-dev, gdal-bin + +Proj + http://trac.osgeo.org/proj/ + Debian/Ubuntu: libproj-dev + + +## Building + +Osmium-contrib uses CMake for its builds. For Unix/Linux systems a simple +Makefile wrapper is provided to make the build even easier. + +To build just type `make`. Results will be in the `build` subdirectory. + +Or you can go the long route explicitly calling CMake as follows: + +``` +mkdir build +cd build +cmake .. +make +``` + + +## Running + +Run the program with an OSM dump as its only argument: + +`node_density planet.osm.pbf` + +This will use some sensible default settings that are displayed after the +program start. Depending on the settings this will run for several minutes. + +For available options see + +`node_density --help` + + +## Viewing results + +The output of this program is a GeoTIFF file with 32bit integer values for each +pixel. Your usual image viewers might not be able to display it. There are +various ways to view it. The following descriptions expect the output to have +the default name `out.tif`. + +### With QGIS + +Run [qgis](http://qgis.org/) and open the output file with it, either through +the "Layer -> Add Raster Layer.." menu or by dragging the file onto the QGIS +window. Open the "Layer Properties" dialogue, choose the "Style" tab and change +the "Min" and "Max" values to "0" and "1000", respectively. You should see the +result. Play around with the settings. + +If you have QGIS 2.4 or newer you can drag the `example.qlr` file onto your +QGIS window. The `out.tif` file should be opened with some sample settings. +(Currently this only works if qgis was started from the same directory the +`example.qlr` and `out.tif` files are in.) + +To improve rendering speed in QGIS for large files add overview images by +calling `node_density` with `--build-overviews`. + + +### With GDAL + +There are several programs in the GDAL suite that can help with converting +the GeoTIFF file in various ways. + +Convert into b/w PNG: + +``` +gdal_translate -ot Byte -of PNG -scale 0 200 out.tif out-bw.png +``` + +Try out different `-scale` settings. See the `gdal_translate` man page for +details. + +To convert into a color PNG: + +``` +gdaldem color-relief out.tif colors.txt -of PNG out-color.png +``` + +An example `colors.txt` is part of the `node_density` distribution. + + +## License + +This program is released into the Public Domain. + + +## Author + +Jochen Topf (http://jochentopf.com/) + diff --git a/node_density/cmdline_options.cpp b/node_density/cmdline_options.cpp new file mode 100644 index 0000000..f164b22 --- /dev/null +++ b/node_density/cmdline_options.cpp @@ -0,0 +1,125 @@ + +#include "cmdline_options.hpp" + +#include <boost/program_options.hpp> + +Options::Options(int argc, char* argv[]) { + namespace po = boost::program_options; + + po::variables_map vm; + + try { + po::options_description cmdline("Options"); + cmdline.add_options() + ("help,h", "Print this help message") + ("quiet,q", "Suppress verbose output messages") + ("format,f", po::value<std::string>(), "Format of input file (default: autodetect)") + ("output,o", po::value<std::string>(), "Name of output image") + ("epsg,e", po::value<int>(), "EPSG code of spatial reference system (default: 4326)") + ("srs,s", po::value<std::string>(), "Spatial reference system in proj format") + ("width,W", po::value<size_t>(), "Pixel width of output image") + ("height,H", po::value<size_t>(), "Pixel height of output image") + ("left,x", po::value<double>(), "Left edge of bounding box (default: -180)") + ("right,X", po::value<double>(), "Right edge of bounding box (default: 180)") + ("bottom,y", po::value<double>(), "Bottom edge of bounding box (default: -90)") + ("top,Y", po::value<double>(), "Top edge of bounding box (default: 90)") + ("compression", po::value<std::string>(), "Compression format (NONE, DEFLATE, or LZW (default: LZW))") + ("build-overviews", "Build overview images") + ; + + po::options_description hidden("Hidden options"); + hidden.add_options() + ("input-filename", po::value<std::string>(), "Input file") + ; + + po::options_description desc("Usage: node_density [OPTIONS] OSMFILE\nCreate GeoTIFF with node density in OSM data"); + desc.add(cmdline); + + po::options_description all; + all.add(cmdline).add(hidden); + + po::positional_options_description positional; + positional.add("input-filename", 1); + + po::store(po::command_line_parser(argc, argv).options(all).positional(positional).run(), vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << desc << "\n"; + exit(0); + } + + if (vm.count("quiet")) { + vout.verbose(false); + } + + if (vm.count("input-filename")) { + input_filename = vm["input-filename"].as<std::string>(); + } + + if (vm.count("format")) { + input_format = vm["format"].as<std::string>(); + } + + if (vm.count("output")) { + output_filename = vm["output"].as<std::string>(); + } + + if (vm.count("srs") && vm.count("epsg")) { + std::cerr << "Use at most one of the options --epsg,-e and --srs,-s\n"; + exit(return_code::fatal); + } + + if (vm.count("srs")) { + srs = vm["srs"].as<std::string>(); + epsg = -1; + } + + if (vm.count("epsg")) { + epsg = vm["epsg"].as<int>(); + srs = "+init=epsg:" + std::to_string(epsg); + } + + if (vm.count("width")) { + width = vm["width"].as<size_t>(); + } + + if (vm.count("height")) { + height = vm["height"].as<size_t>(); + } + + if (vm.count("top")) { + box.top_right().set_lat(vm["top"].as<double>()); + } + + if (vm.count("right")) { + box.top_right().set_lon(vm["right"].as<double>()); + } + + if (vm.count("bottom")) { + box.bottom_left().set_lat(vm["bottom"].as<double>()); + } + + if (vm.count("left")) { + box.bottom_left().set_lon(vm["left"].as<double>()); + } + + if (vm.count("build-overviews")) { + build_overview = true; + } + + if (vm.count("compression")) { + std::string c = vm["compression"].as<std::string>(); + if (c == "NONE" || c == "LZW" || c == "DEFLATE") { + compression_format = c; + } else { + std::cerr << "Unknown compression format '" << c << "'\n"; + exit(return_code::fatal); + } + } + } catch (boost::program_options::error& e) { + std::cerr << "Error parsing command line: " << e.what() << std::endl; + exit(return_code::fatal); + } +} + diff --git a/node_density/cmdline_options.hpp b/node_density/cmdline_options.hpp new file mode 100644 index 0000000..6811ce4 --- /dev/null +++ b/node_density/cmdline_options.hpp @@ -0,0 +1,35 @@ +#ifndef CMDLINE_OPTIONS_HPP +#define CMDLINE_OPTIONS_HPP + +#include <string> + +#include <osmium/osm/box.hpp> +#include <osmium/osm/timestamp.hpp> +#include <osmium/util/verbose_output.hpp> + +enum return_code : int { + okay = 0, + error = 1, + fatal = 2 +}; + +struct Options { + + osmium::util::VerboseOutput vout {true}; + + std::string input_filename {"-"}; + std::string output_filename {"out.tif"}; + std::string input_format; + std::string compression_format {"LZW"}; + bool build_overview = false; + std::string srs {"+init=epsg:4326"}; + int epsg = 4326; + size_t width = 1024; + size_t height = 512; + osmium::Box box {-180, -90, 180, 90}; + + Options(int argc, char* argv[]); + +}; // struct Options + +#endif // CMDLINE_OPTIONS_HPP diff --git a/node_density/colors.txt b/node_density/colors.txt new file mode 100644 index 0000000..711a853 --- /dev/null +++ b/node_density/colors.txt @@ -0,0 +1,5 @@ +0 0 0 0 +1 68 0 0 +3000 255 0 0 +8000 255 255 0 +10000 255 255 255 diff --git a/node_density/example.qlr b/node_density/example.qlr new file mode 100644 index 0000000..c2a6477 --- /dev/null +++ b/node_density/example.qlr @@ -0,0 +1,49 @@ +<!DOCTYPE qgis-layer-definition> +<maplayers> + <maplayer minimumScale="-4.65661e-10" maximumScale="1e+08" type="raster" hasScaleBasedVisibilityFlag="0"> + <datasource>out.tif</datasource> + <title></title> + <abstract></abstract> + <keywordList> + <value></value> + </keywordList> + <layername>OSM node density</layername> + <srs> + <spatialrefsys> + <proj4>+proj=longlat +datum=WGS84 +no_defs</proj4> + <srsid>3452</srsid> + <srid>4326</srid> + <authid>EPSG:4326</authid> + <description>WGS 84</description> + <projectionacronym>longlat</projectionacronym> + <ellipsoidacronym>WGS84</ellipsoidacronym> + <geographicflag>true</geographicflag> + </spatialrefsys> + </srs> + <customproperties> + <property key="identify/format" value="Value"/> + </customproperties> + <provider>gdal</provider> + <noData> + <noDataList bandNo="1" useSrcNoData="0"/> + </noData> + <pipe> + <rasterrenderer opacity="1" alphaBand="0" classificationMax="120000" classificationMinMaxOrigin="User" band="1" classificationMin="0" type="singlebandpseudocolor"> + <rasterTransparency/> + <rastershader> + <colorrampshader colorRampType="INTERPOLATED" clip="0"> + <item alpha="255" value="0" label="0" color="#000000"/> + <item alpha="255" value="1" label="1" color="#440000"/> + <item alpha="255" value="3000" label="3000" color="#ff0000"/> + <item alpha="255" value="12000" label="12000" color="#ffff00"/> + <item alpha="255" value="120000" label="120000" color="#ffffff"/> + </colorrampshader> + </rastershader> + </rasterrenderer> + <brightnesscontrast brightness="0" contrast="0"/> + <huesaturation colorizeGreen="128" colorizeOn="0" colorizeRed="255" colorizeBlue="128" grayscaleMode="0" saturation="0" colorizeStrength="100"/> + <rasterresampler maxOversampling="0" zoomedOutResampler="bilinear"/> + </pipe> + <blendMode>0</blendMode> + </maplayer> +</maplayers> diff --git a/node_density/main.cpp b/node_density/main.cpp new file mode 100644 index 0000000..0dac5ff --- /dev/null +++ b/node_density/main.cpp @@ -0,0 +1,197 @@ + +// The code in this file is released into the Public Domain. + +#include <algorithm> +#include <cassert> +#include <cmath> +#include <cstdio> +#include <iostream> +#include <limits> + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wredundant-decls" +#include <cpl_conv.h> +#include <cpl_string.h> +#include <gdal_priv.h> +#include <ogr_spatialref.h> +#pragma GCC diagnostic pop + +#include <osmium/io/any_input.hpp> +#include <osmium/handler.hpp> +#include <osmium/visitor.hpp> +#include <osmium/geom/mercator_projection.hpp> +#include <osmium/geom/projection.hpp> + +#include "cmdline_options.hpp" + +typedef uint32_t node_count_type; + +class NodeDensityHandler : public osmium::handler::Handler { + + Options& m_options; + + osmium::geom::Projection m_projection; + + const int m_width; + const int m_height; + + const osmium::geom::Coordinates m_bottom_left; + const osmium::geom::Coordinates m_top_right; + + const double m_factor_x; + const double m_factor_y; + + std::unique_ptr<node_count_type[]> m_node_count; + + template <typename T> + static T in_range(T min, T value, T max) { + return std::min(std::max(value, min), max); + } + + void record_location(const osmium::Location& location) { + if (m_options.box.contains(location)) { + osmium::geom::Coordinates c = m_projection(location); + const int x = in_range(0, static_cast<int>((c.x - m_bottom_left.x) * m_factor_x), m_width - 1); + const int y = in_range(0, static_cast<int>((c.y - m_top_right.y) * m_factor_y), m_height - 1); + const int n = y * m_width + x; + ++m_node_count[n]; + } + } + +public: + + NodeDensityHandler(Options& options) : + m_options(options), + m_projection(options.srs), + m_width(options.width), + m_height(options.height), + m_bottom_left(m_projection(options.box.bottom_left())), + m_top_right(m_projection(options.box.top_right())), + m_factor_x(m_width / (m_top_right.x - m_bottom_left.x)), + m_factor_y(- m_height / (m_top_right.y - m_bottom_left.y)), + m_node_count(new node_count_type[m_width * m_height]) { + } + + void node(const osmium::Node& node) { + record_location(node.location()); + } + + void write_to_file() { + m_options.vout << "Maximum node count per pixel: " << *std::max_element(&m_node_count[0], &m_node_count[m_width * m_height]) << "\n"; + + GDALAllRegister(); + + GDALDriver* driver = GetGDALDriverManager()->GetDriverByName("GTiff"); + if (!driver) { + std::cerr << "Can't initalize GDAL GTiff driver.\n"; + exit(return_code::fatal); + } + + std::vector<std::string> options; + options.push_back("COMPRESS=" + m_options.compression_format); + options.push_back("TILED=YES"); + + auto dataset_options = std::unique_ptr<char*[]>(new char*[options.size()+1]); + std::transform(options.begin(), options.end(), dataset_options.get(), [&](const std::string& s) { + return const_cast<char*>(s.data()); + }); + dataset_options[options.size()] = nullptr; + + GDALDataset* dataset = driver->Create(m_options.output_filename.c_str(), m_width, m_height, 1, GDT_UInt32, dataset_options.get()); + if (!dataset) { + std::cerr << "Can't create output file '" << m_options.output_filename <<"'.\n"; + exit(return_code::error); + } + + dataset->SetMetadataItem("TIFFTAG_IMAGEDESCRIPTION", "OpenStreetMap node density"); + dataset->SetMetadataItem("TIFFTAG_COPYRIGHT", "Copyright OpenStreetMap contributors (http://www.openstreetmap.org/copyright), License: CC-BY-SA (http://creativecommons.org/licenses/by-sa/2.0/)"); + dataset->SetMetadataItem("TIFFTAG_SOFTWARE", "node_density"); + + double geo_transform[6] = {m_bottom_left.x, 1/m_factor_x, 0, m_top_right.y, 0, 1/m_factor_y}; + dataset->SetGeoTransform(geo_transform); + + { + OGRSpatialReference srs; + srs.importFromProj4(m_projection.proj_string().c_str()); + char* wkt = nullptr; + srs.exportToWkt(&wkt); + dataset->SetProjection(wkt); + CPLFree(wkt); + } + + GDALRasterBand* band = dataset->GetRasterBand(1); + assert(band); + if (band->RasterIO(GF_Write, 0, 0, m_width, m_height, m_node_count.get(), m_width, m_height, GDT_UInt32, 0, 0) != CE_None) { + std::cerr << "Error writing to output file '" << m_options.output_filename <<"'.\n"; + exit(return_code::error); + } + + if (m_options.build_overview) { + int num = std::min(static_cast<int>(std::log2(m_width / 256.0)), 8); + int overview_list[] = { 2, 4, 8, 16, 32, 64, 128, 256 }; + dataset->BuildOverviews("AVERAGE", num, overview_list, 0, nullptr, nullptr, nullptr); + } + + GDALClose(dataset); + } + +}; // class NodeDensityHandler + +int main(int argc, char* argv[]) { + Options options(argc, argv); + + if (options.input_filename == "-" && options.input_format.empty()) { + std::cerr << "When reading from STDIN you have to give the input format with --format, -f.\n"; + std::cerr << "Use one of: 'pbf', 'osm' (uncompressed XML format), 'osm.bz2' (bz2-compressed XML).\n"; + exit(return_code::fatal); + } + + if (options.epsg == 3857) { + bool warning = false; + if (options.box.bottom_left().lat() < -osmium::geom::MERCATOR_MAX_LAT) { + options.box.bottom_left().set_lat(-osmium::geom::MERCATOR_MAX_LAT); + warning = true; + } + if (options.box.top_right().lat() > osmium::geom::MERCATOR_MAX_LAT) { + options.box.top_right().set_lat(osmium::geom::MERCATOR_MAX_LAT); + warning = true; + } + if (warning) { + std::cerr << "Warning: Reduced size of bounding box to valid area for Web Mercator (EPSG:3857).\n"; + } + } + + options.vout << "Set to verbose output. (Suppress with --quiet, -q.)\n"; + options.vout << "Options from command line or defaults:\n"; + options.vout << " Input file: " << options.input_filename << "\n"; + if (!options.input_format.empty()) { + options.vout << " Input format: " << options.input_format << "\n"; + } + options.vout << " Output file: " << options.output_filename << "\n"; + if (options.epsg > 0) { + options.vout << " EPSG code for SRS: " << options.epsg << "\n"; + } + options.vout << " Spatial reference system: " << options.srs << "\n"; + options.vout << " Pixel width: " << options.width << "\n"; + options.vout << " Pixel height: " << options.height << "\n"; + options.vout << " Bounding box: " << options.box << "\n"; + options.vout << " Compression: " << options.compression_format << "\n"; + options.vout << " Build overviews: " << (options.build_overview ? "yes" : "no") << "\n"; + + NodeDensityHandler handler(options); + + osmium::io::File file(options.input_filename, options.input_format); + osmium::io::Reader reader(file, osmium::osm_entity_bits::node); + + options.vout << "Counting nodes...\n"; + osmium::apply(reader, handler); + options.vout << "Done.\n"; + + options.vout << "Writing image to output file...\n"; + handler.write_to_file(); + options.vout << "Done.\n"; + + google::protobuf::ShutdownProtobufLibrary(); +} + diff --git a/pub_names/.gitignore b/pub_names/.gitignore new file mode 100644 index 0000000..04d86f0 --- /dev/null +++ b/pub_names/.gitignore @@ -0,0 +1 @@ +pub_names diff --git a/pub_names/CMakeLists.txt b/pub_names/CMakeLists.txt new file mode 100644 index 0000000..e961a4b --- /dev/null +++ b/pub_names/CMakeLists.txt @@ -0,0 +1,24 @@ +#---------------------------------------------------------------------- +# +# Single example osmium-contrib CMakeLists.txt +# +#---------------------------------------------------------------------- +project(osmium-pub-names) + +cmake_minimum_required(VERSION 2.8.5) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../cmake") + +find_package(Boost REQUIRED) +include_directories(${Boost_INCLUDE_DIRS}) + +find_package(Osmium REQUIRED COMPONENTS io sparsehash) +include_directories(${OSMIUM_INCLUDE_DIRS}) + +include(common) + +#---------------------------------------------------------------------- + +set(PROG pub_names) +file(GLOB SOURCES *.cpp *.hpp) +add_executable(${PROG} ${SOURCES}) +target_link_libraries(${PROG} ${Boost_LIBRARIES} ${OSMIUM_LIBRARIES}) diff --git a/pub_names/Makefile b/pub_names/Makefile new file mode 100644 index 0000000..8f43712 --- /dev/null +++ b/pub_names/Makefile @@ -0,0 +1,12 @@ + +all: + mkdir -p build && cd build && cmake .. && $(MAKE) + +clean: + if test -d build; then cd build && $(MAKE) clean; fi + +distclean: + rm -fr build + +.PHONY: clean distclean + diff --git a/pub_names/README.md b/pub_names/README.md new file mode 100644 index 0000000..87cfd6a --- /dev/null +++ b/pub_names/README.md @@ -0,0 +1,45 @@ + +# Pub Names + +A simple program to show the names of all pubs from the given OSM file. + + +## Prerequisites + +You'll need libosmium (http://osmcode.org/libosmium) and its dependencies +installed first. + + +## Building + +Osmium-contrib uses CMake for its builds. For Unix/Linux systems a simple +Makefile wrapper is provided to make the build even easier. + +To build just type `make`. Results will be in the `build` subdirectory. + +Or you can go the long route explicitly calling CMake as follows: + +``` +mkdir build +cd build +cmake .. +make +``` + + +## Running + +Run the program with an OSM file as its only argument: + +`pub_names ireland.osm.pbf` + + +## License + +This program is released into the Public Domain. + + +## Author + +Jochen Topf (http://jochentopf.com/) + diff --git a/pub_names/pub_names.cpp b/pub_names/pub_names.cpp new file mode 100755 index 0000000..a5bfa16 --- /dev/null +++ b/pub_names/pub_names.cpp @@ -0,0 +1,46 @@ + +// The code in this file is released into the Public Domain. + +#include <iostream> + +#include <osmium/io/any_input.hpp> +#include <osmium/handler.hpp> +#include <osmium/visitor.hpp> + +class NamesHandler : public osmium::handler::Handler { + + void output_pubs(const osmium::OSMObject& object) { + const char* amenity = object.tags()["amenity"]; + if (amenity && !strcmp(amenity, "pub")) { + const char* name = object.tags()["name"]; + if (name) { + std::cout << name << std::endl; + } + } + } + +public: + + void node(const osmium::Node& node) { + output_pubs(node); + } + + void way(const osmium::Way& way) { + output_pubs(way); + } + +}; + +int main(int argc, char* argv[]) { + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " OSMFILE\n"; + exit(1); + } + + NamesHandler names_handler; + + osmium::io::Reader reader(argv[1], osmium::osm_entity_bits::node | osmium::osm_entity_bits::way); + + osmium::apply(reader, names_handler); +} + diff --git a/road_length/.gitignore b/road_length/.gitignore new file mode 100644 index 0000000..aef0618 --- /dev/null +++ b/road_length/.gitignore @@ -0,0 +1 @@ +road_length diff --git a/road_length/CMakeLists.txt b/road_length/CMakeLists.txt new file mode 100644 index 0000000..e23d190 --- /dev/null +++ b/road_length/CMakeLists.txt @@ -0,0 +1,24 @@ +#---------------------------------------------------------------------- +# +# Single example osmium-contrib CMakeLists.txt +# +#---------------------------------------------------------------------- +project(osmium-road-length) + +cmake_minimum_required(VERSION 2.8.5) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../cmake") + +find_package(Boost REQUIRED) +include_directories(${Boost_INCLUDE_DIRS}) + +find_package(Osmium REQUIRED COMPONENTS io sparsehash) +include_directories(${OSMIUM_INCLUDE_DIRS}) + +include(common) + +#---------------------------------------------------------------------- + +set(PROG road_length) +file(GLOB SOURCES *.cpp *.hpp) +add_executable(${PROG} ${SOURCES}) +target_link_libraries(${PROG} ${Boost_LIBRARIES} ${OSMIUM_LIBRARIES}) diff --git a/road_length/Makefile b/road_length/Makefile new file mode 100644 index 0000000..8f43712 --- /dev/null +++ b/road_length/Makefile @@ -0,0 +1,12 @@ + +all: + mkdir -p build && cd build && cmake .. && $(MAKE) + +clean: + if test -d build; then cd build && $(MAKE) clean; fi + +distclean: + rm -fr build + +.PHONY: clean distclean + diff --git a/road_length/README.md b/road_length/README.md new file mode 100644 index 0000000..f266e62 --- /dev/null +++ b/road_length/README.md @@ -0,0 +1,46 @@ + +# Road Length + +A simple program to calculate the length of the road network (everything tagged +highway=*) from the given OSM file. + + +## Prerequisites + +You'll need libosmium (http://osmcode.org/libosmium) and its dependencies +installed first. + + +## Building + +Osmium-contrib uses CMake for its builds. For Unix/Linux systems a simple +Makefile wrapper is provided to make the build even easier. + +To build just type `make`. Results will be in the `build` subdirectory. + +Or you can go the long route explicitly calling CMake as follows: + +``` +mkdir build +cd build +cmake .. +make +``` + + +## Running + +Run the program with an OSM file as its only argument: + +`road_length germany.osm.pbf` + + +## License + +This program is released into the Public Domain. + + +## Author + +Jochen Topf (http://jochentopf.com/) + diff --git a/road_length/road_length.cpp b/road_length/road_length.cpp new file mode 100755 index 0000000..36e3349 --- /dev/null +++ b/road_length/road_length.cpp @@ -0,0 +1,45 @@ + +// The code in this file is released into the Public Domain. + +#include <iostream> + +#include <osmium/io/any_input.hpp> +#include <osmium/geom/haversine.hpp> +#include <osmium/visitor.hpp> + +#include <osmium/index/map/sparse_mem_array.hpp> +#include <osmium/handler/node_locations_for_ways.hpp> +typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type; +typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type; + +struct RoadLengthHandler : public osmium::handler::Handler { + + double length = 0; + + void way(const osmium::Way& way) { + const char* highway = way.tags()["highway"]; + if (highway) { + length += osmium::geom::haversine::distance(way.nodes()); + } + } + +}; + +int main(int argc, char* argv[]) { + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " OSMFILE\n"; + exit(1); + } + + osmium::io::Reader reader(argv[1], osmium::osm_entity_bits::node | osmium::osm_entity_bits::way); + + index_type index; + location_handler_type location_handler(index); + + RoadLengthHandler road_length_handler; + + osmium::apply(reader, location_handler, road_length_handler); + + std::cout << "Length: " << road_length_handler.length / 1000 << " km\n"; +} + -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/osmium-contrib.git _______________________________________________ Pkg-grass-devel mailing list Pkg-grass-devel@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel