diff --git a/.gitignore b/.gitignore index 880d38c..d65bbac 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ CMakeCache.txt *.a cmake_install.cmake *~ +cmake-build-* CMakeFiles *.cfg *.cmake diff --git a/.travis.yml b/.travis.yml index 81a0719..5fd7028 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,12 @@ language: cpp - +sudo: true os: - linux - osx +dist: bionic +osx_image: xcode12 + compiler: - gcc - clang @@ -14,9 +17,15 @@ addons: - ubuntu-toolchain-r-test packages: - cmake + - libosmium2-dev + homebrew: + packages: + - libosmium + - boost before_install: - export LD_LIBRARY_PATH=$(if [[ $CXX == "clang++" ]]; then echo -n '/usr/local/clang/lib'; fi) + - git clone https://github.com/mapbox/protozero.git && cd protozero && cmake . -DINSTALL_GDALCPP=ON -DINSTALL_UTFCPP=ON && sudo make -j4 install && cd .. before_script: - mkdir build diff --git a/CMakeLists.txt b/CMakeLists.txt index 008bd55..df5561a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,7 @@ enable_testing() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") set(EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/build") +find_package(Osmium REQUIRED COMPONENTS pbf xml io) find_package(OpenMP) if (OPENMP_FOUND) diff --git a/cmake/FindOsmium.cmake b/cmake/FindOsmium.cmake new file mode 100644 index 0000000..8c659f2 --- /dev/null +++ b/cmake/FindOsmium.cmake @@ -0,0 +1,357 @@ +#---------------------------------------------------------------------- +# +# 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 [version] REQUIRED COMPONENTS ) +# include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS}) +# +# The version number is optional. If it is not set, any version of +# libosmium will do. +# +# For the 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. +# +#---------------------------------------------------------------------- + +# This is the list of directories where we look for osmium includes. +set(_osmium_include_path + ../libosmium + ~/Library/Frameworks + /Library/Frameworks + /opt/local # DarwinPorts + /opt +) + +# Look for the header file. +find_path(OSMIUM_INCLUDE_DIR osmium/version.hpp + PATH_SUFFIXES include + PATHS ${_osmium_include_path} +) + +# Check libosmium version number +if(Osmium_FIND_VERSION) + if(NOT EXISTS "${OSMIUM_INCLUDE_DIR}/osmium/version.hpp") + message(FATAL_ERROR "Missing ${OSMIUM_INCLUDE_DIR}/osmium/version.hpp. Either your libosmium version is too old, or libosmium wasn't found in the place you said.") + endif() + file(STRINGS "${OSMIUM_INCLUDE_DIR}/osmium/version.hpp" _libosmium_version_define REGEX "#define LIBOSMIUM_VERSION_STRING") + if("${_libosmium_version_define}" MATCHES "#define LIBOSMIUM_VERSION_STRING \"([0-9.]+)\"") + set(_libosmium_version "${CMAKE_MATCH_1}") + else() + set(_libosmium_version "unknown") + endif() +endif() + +set(OSMIUM_INCLUDE_DIRS "${OSMIUM_INCLUDE_DIR}") + +#---------------------------------------------------------------------- +# +# 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(ZLIB) + find_package(Threads) + find_package(Protozero 1.6.3) + + list(APPEND OSMIUM_EXTRA_FIND_VARS ZLIB_FOUND Threads_FOUND PROTOZERO_INCLUDE_DIR) + if(ZLIB_FOUND AND Threads_FOUND AND PROTOZERO_FOUND) + list(APPEND OSMIUM_PBF_LIBRARIES + ${ZLIB_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + ) + list(APPEND OSMIUM_INCLUDE_DIRS + ${ZLIB_INCLUDE_DIR} + ${PROTOZERO_INCLUDE_DIR} + ) + else() + message(WARNING "Osmium: Can not find some libraries for PBF input/output, please install them or configure the paths.") + endif() +endif() + +#---------------------------------------------------------------------- +# Component 'xml' +if(Osmium_USE_XML) + find_package(EXPAT) + find_package(BZip2) + find_package(ZLIB) + find_package(Threads) + + list(APPEND OSMIUM_EXTRA_FIND_VARS EXPAT_FOUND BZIP2_FOUND ZLIB_FOUND Threads_FOUND) + 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() + 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) + + list(APPEND OSMIUM_EXTRA_FIND_VARS GEOS_INCLUDE_DIR GEOS_LIBRARY) + 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() + 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) + + list(APPEND OSMIUM_EXTRA_FIND_VARS GDAL_FOUND) + if(GDAL_FOUND) + list(APPEND OSMIUM_LIBRARIES ${GDAL_LIBRARIES}) + list(APPEND OSMIUM_INCLUDE_DIRS ${GDAL_INCLUDE_DIRS}) + else() + 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) + + list(APPEND OSMIUM_EXTRA_FIND_VARS PROJ_INCLUDE_DIR PROJ_LIBRARY) + 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() + 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) + + list(APPEND OSMIUM_EXTRA_FIND_VARS SPARSEHASH_INCLUDE_DIR) + if(SPARSEHASH_INCLUDE_DIR) + # Find size of sparsetable::size_type. This does not work on older + # CMake versions because they can do this check only in C, not in C++. + if(NOT CMAKE_VERSION VERSION_LESS 3.0) + include(CheckTypeSize) + set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR}) + set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable") + check_type_size("google::sparsetable::size_type" SPARSETABLE_SIZE_TYPE LANGUAGE CXX) + set(CMAKE_EXTRA_INCLUDE_FILES) + set(CMAKE_REQUIRED_INCLUDES) + else() + set(SPARSETABLE_SIZE_TYPE ${CMAKE_SIZEOF_VOID_P}) + 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() + 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_EXTRA_FIND_VARS) + list(REMOVE_DUPLICATES OSMIUM_EXTRA_FIND_VARS) +endif() +# Handle the QUIETLY and REQUIRED arguments and the optional version check +# and set OSMIUM_FOUND to TRUE if all listed variables are TRUE. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Osmium + REQUIRED_VARS OSMIUM_INCLUDE_DIR ${OSMIUM_EXTRA_FIND_VARS} + VERSION_VAR _libosmium_version) +unset(OSMIUM_EXTRA_FIND_VARS) + +#---------------------------------------------------------------------- +# +# A function for setting the -pthread option in compilers/linkers +# +#---------------------------------------------------------------------- +function(set_pthread_on_target _target) + if(NOT MSVC) + set_target_properties(${_target} PROPERTIES COMPILE_FLAGS "-pthread") + if(NOT APPLE) + set_target_properties(${_target} PROPERTIES LINK_FLAGS "-pthread") + endif() + endif() +endfunction() + +#---------------------------------------------------------------------- +# +# 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) + + # Disable warning C4503: "decorated name length exceeded, name was truncated" + # there are more than 150 of generated names in libosmium longer than 4096 symbols supported in MSVC + add_definitions(-wd4503) + + add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS) +endif() + +if(APPLE AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") +# 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" 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/FindProtozero.cmake b/cmake/FindProtozero.cmake new file mode 100644 index 0000000..ad16cab --- /dev/null +++ b/cmake/FindProtozero.cmake @@ -0,0 +1,63 @@ +#---------------------------------------------------------------------- +# +# FindProtozero.cmake +# +# Find the protozero headers. +# +#---------------------------------------------------------------------- +# +# 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(Protozero [version] [REQUIRED]) +# include_directories(SYSTEM ${PROTOZERO_INCLUDE_DIR}) +# +# The version number is optional. If it is not set, any version of +# protozero will do. +# +# if(NOT PROTOZERO_FOUND) +# message(WARNING "Protozero not found!\n") +# endif() +# +#---------------------------------------------------------------------- +# +# Variables: +# +# PROTOZERO_FOUND - True if Protozero was found. +# PROTOZERO_INCLUDE_DIR - Where to find include files. +# +#---------------------------------------------------------------------- + +# find include path +find_path(PROTOZERO_INCLUDE_DIR protozero/version.hpp + PATH_SUFFIXES include + PATHS ${CMAKE_SOURCE_DIR}/../protozero +) + +# Check version number +if(Protozero_FIND_VERSION) + file(STRINGS "${PROTOZERO_INCLUDE_DIR}/protozero/version.hpp" _version_define REGEX "#define PROTOZERO_VERSION_STRING") + if("${_version_define}" MATCHES "#define PROTOZERO_VERSION_STRING \"([0-9.]+)\"") + set(_version "${CMAKE_MATCH_1}") + else() + set(_version "unknown") + endif() +endif() + +#set(PROTOZERO_INCLUDE_DIRS "${PROTOZERO_INCLUDE_DIR}") + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Protozero + REQUIRED_VARS PROTOZERO_INCLUDE_DIR + VERSION_VAR _version) + + +#---------------------------------------------------------------------- diff --git a/cmake/cpplint.cmake b/cmake/cpplint.cmake index 6751f0f..185f84b 100644 --- a/cmake/cpplint.cmake +++ b/cmake/cpplint.cmake @@ -119,7 +119,9 @@ function(cpplint_add_subdirectory DIR) add_custom_target(${TARGET_NAME} COMMAND ${CPPLINT} "--extensions=${EXTENSIONS}" "--root=${CPPLINT_PROJECT_ROOT}" - "--quiet" + "--quiet" + "--linelength=120" + "--filter=-build/header_guard, -runtime/references, -whitespace/indent" ${LIST_OF_FILES} DEPENDS ${LIST_OF_FILES} COMMENT "cpplint: Checking source code style" diff --git a/src/pfaedle/CMakeLists.txt b/src/pfaedle/CMakeLists.txt index 22b083a..0d37dd6 100644 --- a/src/pfaedle/CMakeLists.txt +++ b/src/pfaedle/CMakeLists.txt @@ -17,4 +17,12 @@ add_executable(pfaedle ${pfaedle_main}) add_library(pfaedle_dep ${pfaedle_SRC}) include_directories(pfaedle_dep PUBLIC ${PROJECT_SOURCE_DIR}/src/cppgtfs/src) -target_link_libraries(pfaedle pfaedle_dep util configparser ad_cppgtfs -lpthread) +if (OSMIUM_FOUND) + include_directories(${OSMIUM_INCLUDE_DIRS}) + target_link_libraries(pfaedle pfaedle_dep util configparser ad_cppgtfs -lpthread + ${OSMIUM_IO_LIBRARIES}) + message("linking with osmium") +else () + target_link_libraries(pfaedle pfaedle_dep util configparser ad_cppgtfs -lpthread) +endif() + diff --git a/src/pfaedle/PfaedleMain.cpp b/src/pfaedle/PfaedleMain.cpp index 55bea77..9ed4e77 100644 --- a/src/pfaedle/PfaedleMain.cpp +++ b/src/pfaedle/PfaedleMain.cpp @@ -1,18 +1,17 @@ // Copyright 2018, University of Freiburg, // Chair of Algorithms and Data Structures. // Authors: Patrick Brosi - -#include #include -#include -#include #include -#include #include +#include +#include +#include #include #include #include #include + #include "ad/cppgtfs/Parser.h" #include "ad/cppgtfs/Writer.h" #include "pfaedle/config/ConfigReader.h" @@ -72,7 +71,7 @@ std::vector getCfgPaths(const Config& cfg); // _____________________________________________________________________________ int main(int argc, char** argv) { // disable output buffering for standard output - setbuf(stdout, NULL); + setbuf(stdout, nullptr); // initialize randomness srand(time(NULL) + rand()); // NOLINT @@ -80,8 +79,7 @@ int main(int argc, char** argv) { Config cfg; MotConfigReader motCfgReader; - ConfigReader cr; - cr.read(&cfg, argc, argv); + ConfigReader::read(&cfg, argc, argv); std::vector gtfs(cfg.feedPaths.size()); // feed containing the shapes in memory for evaluation @@ -102,7 +100,7 @@ int main(int argc, char** argv) { exit(static_cast(RetCode::NO_OSM_INPUT)); } - if (motCfgReader.getConfigs().size() == 0) { + if (motCfgReader.getConfigs().empty()) { LOG(ERROR) << "No MOT configurations specified and no implicit " "configurations found, see --help."; exit(static_cast(RetCode::NO_MOT_CFG)); @@ -125,7 +123,7 @@ int main(int argc, char** argv) { exit(static_cast(RetCode::GTFS_PARSE_ERR)); } if (!cfg.writeOverpass) LOG(INFO) << "Done."; - } else if (cfg.writeOsm.size() || cfg.writeOverpass) { + } else if (!cfg.writeOsm.empty() || cfg.writeOverpass) { for (size_t i = 0; i < cfg.feedPaths.size(); i++) { if (!cfg.writeOverpass) LOG(INFO) << "Reading " << cfg.feedPaths[i] << " ..."; @@ -147,10 +145,10 @@ int main(int argc, char** argv) { LOG(DEBUG) << "Read " << motCfgReader.getConfigs().size() << " unique MOT configs."; MOTs cmdCfgMots = cfg.mots; - pfaedle::gtfs::Trip* singleTrip = 0; + pfaedle::gtfs::Trip* singleTrip = nullptr; - if (cfg.shapeTripId.size()) { - if (!cfg.feedPaths.size()) { + if (!cfg.shapeTripId.empty()) { + if (cfg.feedPaths.empty()) { std::cout << "No input feed specified, see --help" << std::endl; exit(static_cast(RetCode::NO_INPUT_FEED)); } @@ -161,18 +159,16 @@ int main(int argc, char** argv) { } } - if (cfg.writeOsm.size()) { + if (!cfg.writeOsm.empty()) { LOG(INFO) << "Writing filtered XML to " << cfg.writeOsm << " ..."; BBoxIdx box(BOX_PADDING); for (size_t i = 0; i < cfg.feedPaths.size(); i++) { - ShapeBuilder::getGtfsBox(>fs[i], cmdCfgMots, cfg.shapeTripId, true, - &box); + ShapeBuilder::getGtfsBox(>fs[i], cmdCfgMots, cfg.shapeTripId, true, &box); } OsmBuilder osmBuilder; std::vector opts; for (const auto& o : motCfgReader.getConfigs()) { - if (std::find_first_of(o.mots.begin(), o.mots.end(), cmdCfgMots.begin(), - cmdCfgMots.end()) != o.mots.end()) { + if (std::find_first_of(o.mots.begin(), o.mots.end(), cmdCfgMots.begin(), cmdCfgMots.end()) != o.mots.end()) { opts.push_back(o.osmBuildOpts); } } @@ -187,33 +183,34 @@ int main(int argc, char** argv) { } else if (cfg.writeOverpass) { BBoxIdx box(BOX_PADDING); for (size_t i = 0; i < cfg.feedPaths.size(); i++) { - ShapeBuilder::getGtfsBox(>fs[i], cmdCfgMots, cfg.shapeTripId, true, - &box); + ShapeBuilder::getGtfsBox(>fs[i], cmdCfgMots, cfg.shapeTripId, true, &box); } OsmBuilder osmBuilder; std::vector opts; for (const auto& o : motCfgReader.getConfigs()) { - if (std::find_first_of(o.mots.begin(), o.mots.end(), cmdCfgMots.begin(), - cmdCfgMots.end()) != o.mots.end()) { + if (std::find_first_of(o.mots.begin(), o.mots.end(), cmdCfgMots.begin(), cmdCfgMots.end()) != o.mots.end()) { opts.push_back(o.osmBuildOpts); } } osmBuilder.overpassQryWrite(&std::cout, opts, box); exit(static_cast(RetCode::SUCCESS)); - } else if (!cfg.feedPaths.size()) { + } else if (cfg.feedPaths.empty()) { std::cout << "No input feed specified, see --help" << std::endl; exit(static_cast(RetCode::NO_INPUT_FEED)); } - std::vector dfBins; auto dfBinStrings = util::split(std::string(cfg.evalDfBins), ','); - for (auto st : dfBinStrings) dfBins.push_back(atof(st.c_str())); + std::vector dfBins(dfBinStrings.size()); + for (const auto& st : dfBinStrings) { + dfBins.push_back(atof(st.c_str())); + } Collector ecoll(cfg.evalPath, dfBins); for (const auto& motCfg : motCfgReader.getConfigs()) { std::string filePost; auto usedMots = pfaedle::router::motISect(motCfg.mots, cmdCfgMots); - if (!usedMots.size()) continue; + if (usedMots.empty()) + continue; if (singleTrip && !usedMots.count(singleTrip->getRoute()->getType())) continue; if (motCfgReader.getConfigs().size() > 1) @@ -234,9 +231,10 @@ int main(int argc, char** argv) { ShapeBuilder::getGtfsBox(>fs[0], cmdCfgMots, cfg.shapeTripId, cfg.dropShapes, &box); - if (fStops.size()) - osmBuilder.read(cfg.osmPath, motCfg.osmBuildOpts, &graph, box, - cfg.gridSize, &fStops, &restr); + if (!fStops.empty()) { + osmBuilder.read(cfg.osmPath, motCfg.osmBuildOpts, &graph, box, + cfg.gridSize, &fStops, &restr); + } // TODO(patrick): move this somewhere else for (auto& feedStop : fStops) { @@ -249,13 +247,12 @@ int main(int argc, char** argv) { } } - ShapeBuilder shapeBuilder(>fs[0], &evalFeed, cmdCfgMots, motCfg, &ecoll, - &graph, &fStops, &restr, cfg); + ShapeBuilder shapeBuilder(>fs[0], &evalFeed, cmdCfgMots, motCfg, &ecoll, &graph, &fStops, &restr, cfg); if (cfg.writeGraph) { LOG(INFO) << "Outputting graph.json..."; util::geo::output::GeoGraphJsonOutput out; - mkdir(cfg.dbgOutputPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + mkdir(cfg.dbgOutputPath.c_str(), 775); std::ofstream fstr(cfg.dbgOutputPath + "/graph.json"); out.printLatLng(*shapeBuilder.getGraph(), fstr); fstr.close(); @@ -263,7 +260,7 @@ int main(int argc, char** argv) { if (singleTrip) { LOG(INFO) << "Outputting path.json..."; - mkdir(cfg.dbgOutputPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + mkdir(cfg.dbgOutputPath.c_str(), 775); std::ofstream pstr(cfg.dbgOutputPath + "/path.json"); util::geo::output::GeoJsonOutput o(pstr); @@ -284,7 +281,7 @@ int main(int argc, char** argv) { if (cfg.buildTransitGraph) { util::geo::output::GeoGraphJsonOutput out; LOG(INFO) << "Outputting trgraph" + filePost + ".json..."; - mkdir(cfg.dbgOutputPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + mkdir(cfg.dbgOutputPath.c_str(), 775); std::ofstream fstr(cfg.dbgOutputPath + "/trgraph" + filePost + ".json"); out.printLatLng(ng, fstr); fstr.close(); @@ -296,11 +293,12 @@ int main(int argc, char** argv) { } } - if (cfg.evaluate) ecoll.printStats(&std::cout); + if (cfg.evaluate) + ecoll.printStats(&std::cout); - if (cfg.feedPaths.size()) { + if (!cfg.feedPaths.empty()) { try { - mkdir(cfg.outputPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + mkdir(cfg.outputPath.c_str(), 775); LOG(INFO) << "Writing output GTFS to " << cfg.outputPath << " ..."; pfaedle::gtfs::Writer w; w.write(>fs[0], cfg.outputPath); @@ -326,7 +324,9 @@ std::string getFileNameMotStr(const MOTs& mots) { // _____________________________________________________________________________ std::vector getCfgPaths(const Config& cfg) { - if (cfg.configPaths.size()) return cfg.configPaths; + if (!cfg.configPaths.empty()) { + return cfg.configPaths; + } std::vector ret; diff --git a/src/pfaedle/config/ConfigReader.cpp b/src/pfaedle/config/ConfigReader.cpp index c9ef614..e8b105d 100644 --- a/src/pfaedle/config/ConfigReader.cpp +++ b/src/pfaedle/config/ConfigReader.cpp @@ -19,9 +19,12 @@ using std::string; using std::exception; using std::vector; -static const char* YEAR = __DATE__ + 7; -static const char* COPY = - "University of Freiburg - Chair of Algorithms and Data Structures"; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstring-plus-int" +static auto YEAR = __DATE__ + 7; +#pragma clang diagnostic pop +static auto COPY = + "University of Freiburg - Chair of Algorithms and Data Structures"; static const char* AUTHORS = "Patrick Brosi "; // _____________________________________________________________________________ @@ -148,8 +151,7 @@ void ConfigReader::read(Config* cfg, int argc, char** argv) { {0, 0, 0, 0}}; char c; - while ((c = getopt_long(argc, argv, ":o:hvi:c:x:Dm:g:X:T:d:p", ops, 0)) != - -1) { + while ((c = getopt_long(argc, argv, ":o:hvi:c:x:Dm:g:X:T:d:p", ops, nullptr)) != -1) { switch (c) { case 1: cfg->writeGraph = true; diff --git a/src/pfaedle/osm/Osm.h b/src/pfaedle/osm/Osm.h index 2fd5bfa..07393ed 100644 --- a/src/pfaedle/osm/Osm.h +++ b/src/pfaedle/osm/Osm.h @@ -21,7 +21,9 @@ typedef std::pair Attr; typedef std::vector OsmIdList; struct OsmRel { - OsmRel() : id(0) {} + OsmRel() : id(0), + keepFlags(0), + dropFlags(0) {} osmid id; AttrMap attrs; std::vector nodes; @@ -35,7 +37,9 @@ struct OsmRel { }; struct OsmWay { - OsmWay() : id(0) {} + OsmWay() : id(0), + keepFlags(0), + dropFlags(0) {} osmid id; AttrMap attrs; std::vector nodes; @@ -45,7 +49,11 @@ struct OsmWay { }; struct OsmNode { - OsmNode() : id(0) {} + OsmNode() : id(0), + lat(0.f), + lng(0.f), + keepFlags(0), + dropFlags(0) {} osmid id; double lat; double lng; @@ -57,6 +65,11 @@ struct OsmNode { struct Restriction { osmid eFrom, eTo; + Restriction() = default; + Restriction(osmid from, osmid to): + eFrom(from), + eTo(to) + {} }; typedef std::unordered_map> RestrMap; diff --git a/src/pfaedle/osm/OsmBuilder.cpp b/src/pfaedle/osm/OsmBuilder.cpp index eaa4ab1..8eecec3 100644 --- a/src/pfaedle/osm/OsmBuilder.cpp +++ b/src/pfaedle/osm/OsmBuilder.cpp @@ -2,7 +2,11 @@ // Chair of Algorithms and Data Structures. // Authors: Patrick Brosi -#include +#include +#include +#include +#include + #include #include #include @@ -12,6 +16,7 @@ #include #include #include + #include "pfaedle/Def.h" #include "pfaedle/osm/BBoxIdx.h" #include "pfaedle/osm/Osm.h" @@ -47,291 +52,971 @@ using pfaedle::osm::EqSearch; using pfaedle::osm::BlockSearch; using ad::cppgtfs::gtfs::Stop; +class Handler: public osmium::handler::Handler +{ +public: + Handler(const pfaedle::osm::AttrKeySet& attributes): + _attributes(attributes) + {} + +protected: + template + void parseTags(T& obj, const osmium::TagList& tags) + { + for (const auto& tag : tags) { + if (_attributes.count(tag.key())) { + obj.attrs[tag.key()] = tag.value(); + } + } + } + + const pfaedle::osm::AttrKeySet& _attributes; + +}; +class NodeFilteringHandler : public osmium::handler::Handler +{ + const pfaedle::osm::OsmFilter &_filter; + const pfaedle::osm::BBoxIdx &_bbox; + pfaedle::osm::OsmIdSet &_bboxNodes; + pfaedle::osm::OsmIdSet &_noHupNodes; + +public: + NodeFilteringHandler(const pfaedle::osm::OsmFilter &filter, + const pfaedle::osm::BBoxIdx &bbox, + pfaedle::osm::OsmIdSet &bboxNodes, + pfaedle::osm::OsmIdSet &noHupNodes) : + _filter(filter), + _bbox(bbox), + _bboxNodes(bboxNodes), + _noHupNodes(noHupNodes) {} + + void node(const osmium::Node &node) + { + bool ignored = false; + + for (const auto &tag : node.tags()) { + if (_filter.nohup(tag.key(), tag.value())) { + _noHupNodes.add(node.id()); + ignored = true; + break; + } + } + + if (!ignored) { + Point point{node.location().lon(), node.location().lat()}; + if (_bbox.contains(point)) { + _bboxNodes.add(node.id()); + } + } + } +}; + +class RelationHandler: public osmium::handler::Handler { + const pfaedle::osm::OsmFilter& _filter; + const pfaedle::osm::BBoxIdx& _bbox; + const pfaedle::osm::AttrKeySet& _keepAttrs; + pfaedle::osm::RelLst& _rels; + pfaedle::osm::RelMap& _nodeRels; + pfaedle::osm::RelMap& _wayRels; + pfaedle::osm::Restrictions& _restrictions; + + public: + RelationHandler(const pfaedle::osm::OsmFilter& filter, + const pfaedle::osm::BBoxIdx& bbox, + const pfaedle::osm::AttrKeySet& keepAttrs, + pfaedle::osm::RelLst& rels, + pfaedle::osm::RelMap& nodeRels, + pfaedle::osm::RelMap& wayRels, + pfaedle::osm::Restrictions& restrictions) : + _filter(filter), + _bbox(bbox), + _keepAttrs(keepAttrs), + _rels(rels), + _nodeRels(nodeRels), + _wayRels(wayRels), + _restrictions(restrictions) + {} + + void relation(const osmium::Relation &relation) { + OsmRel rel; + rel.id = relation.id(); + + if (rel.id == 0) { + return; + } + + for (const auto& tag : relation.tags()) { + if (_keepAttrs.count(tag.key())) { + rel.attrs[tag.key()] = tag.value(); + } + } + + for (const auto& member : relation.members()) { + using osmium::item_type; + auto& obj = member.get_object(); + if (member.type() == item_type::node) { + rel.nodes.push_back(obj.id()); + rel.nodeRoles.emplace_back(member.role()); + } else if (member.type() == item_type::way) { + rel.ways.push_back(obj.id()); + rel.wayRoles.emplace_back(member.role()); + } + } + for (auto id : rel.nodes) { + _nodeRels[id].push_back(_rels.rels.size() - 1); + } + + for (auto id : rel.ways) { + _wayRels[id].push_back(_rels.rels.size() - 1); + } + + uint64_t keepFlags = _filter.keep(rel.attrs, pfaedle::osm::OsmFilter::REL); + uint64_t dropFlags = _filter.drop(rel.attrs, pfaedle::osm::OsmFilter::REL); + + if (rel.id && !rel.attrs.empty() && keepFlags && !dropFlags) { + rel.keepFlags = keepFlags; + rel.dropFlags = dropFlags; + } + + _rels.rels.push_back(rel.attrs); + if (rel.keepFlags & pfaedle::osm::REL_NO_DOWN) { + _rels.flat.insert(_rels.rels.size() - 1); + } + + // more processing + { + if (!rel.attrs.count("type")) return; + if (rel.attrs.find("type")->second != "restriction") return; + + bool pos = _filter.posRestr(rel.attrs); + bool neg = _filter.negRestr(rel.attrs); + + if (!pos && !neg) return; + + uint64_t from = 0; + uint64_t to = 0; + uint64_t via = 0; + + for (size_t i = 0; i < rel.ways.size(); i++) { + if (rel.wayRoles[i] == "from") { + if (from) return; // only one from member supported + from = rel.ways[i]; + } + if (rel.wayRoles[i] == "to") { + if (to) return; // only one to member supported + to = rel.ways[i]; + } + } + + for (size_t i = 0; i < rel.nodes.size(); i++) { + if (rel.nodeRoles[i] == "via") { + via = rel.nodes[i]; + break; + } + } + + if (from && to && via) { + if (pos) { + _restrictions.pos[via].emplace_back(from, to); + } else if (neg) { + _restrictions.neg[via].emplace_back(from, to); + } + } + } + } +}; + +class WayHandler: public osmium::handler::Handler { + pfaedle::trgraph::Graph& _graph; + const pfaedle::osm::RelLst& _rels; + const pfaedle::osm::RelMap& _wayRels; + const pfaedle::osm::OsmFilter& _filter; + const pfaedle::osm::OsmIdSet& _bBoxNodes; + pfaedle::osm::NIdMap& _nodes; + pfaedle::osm::NIdMultMap& _multiNodes; + const pfaedle::osm::OsmIdSet& _noHupNodes; + const pfaedle::osm::AttrKeySet& _keepAttrs; + const pfaedle::osm::Restrictions& _restrictions; + pfaedle::osm::Restrictor& _restrictor; + const pfaedle::osm::FlatRels& _fl; + pfaedle::osm::EdgTracks& _eTracks; + const pfaedle::osm::OsmReadOpts& _opts; + + + std::map _lines; + std::map _relLines; + + public: + WayHandler(pfaedle::trgraph::Graph &g, + const pfaedle::osm::RelLst &rels, + const pfaedle::osm::RelMap &wayRels, + const pfaedle::osm::OsmFilter &filter, + const pfaedle::osm::OsmIdSet &bBoxNodes, + pfaedle::osm::NIdMap &nodes, + pfaedle::osm::NIdMultMap &multiNodes, + const pfaedle::osm::OsmIdSet &noHupNodes, + const pfaedle::osm::AttrKeySet &keepAttrs, + const pfaedle::osm::Restrictions &rawRests, + pfaedle::osm::Restrictor &restor, + const pfaedle::osm::FlatRels &fl, + pfaedle::osm::EdgTracks &eTracks, + const pfaedle::osm::OsmReadOpts &opts) : + _graph(g), + _rels(rels), + _wayRels(wayRels), + _filter(filter), + _bBoxNodes(bBoxNodes), + _nodes(nodes), + _multiNodes(multiNodes), + _noHupNodes(noHupNodes), + _keepAttrs(keepAttrs), + _restrictions(rawRests), + _restrictor(restor), + _fl(fl), + _eTracks(eTracks), + _opts(opts) + {} + + void way(const osmium::Way &way) { + OsmWay w; + w.id = way.id(); + for (const auto &node : way.nodes()) { + w.nodes.emplace_back(node.ref()); + } + for (const auto &tag : way.tags()) { + if (_keepAttrs.count(tag.key())) { + w.attrs[tag.key()] = tag.value(); + } + } + + bool valid = false; + if (w.id && w.nodes.size() > 1 && + (relKeep(w.id, _wayRels, _fl) || _filter.keep(w.attrs, pfaedle::osm::OsmFilter::WAY)) && + !_filter.drop(w.attrs, pfaedle::osm::OsmFilter::WAY)) { + for (auto nid : w.nodes) { + if (_bBoxNodes.has(nid)) { + valid = true; + break; + } + } + } + + if (valid) { + Node *last = nullptr; + std::vector lines; + if (_wayRels.count(w.id)) { + lines = getLines(_wayRels.find(w.id)->second, _rels, _opts); + } + std::string track = + getAttrByFirstMatch(_opts.edgePlatformRules, w.id, w.attrs, _wayRels, _rels, _opts.trackNormzer); + + uint64_t lastnid = 0; + + for (auto nid : w.nodes) { + Node *n = nullptr; + + if (_noHupNodes.has(nid)) { + n = _graph.addNd(); + _multiNodes[nid].insert(n); + } else if (!_nodes.count(nid)) { + if (!_bBoxNodes.has(nid)) { + continue; + } + n = _graph.addNd(); + _nodes[nid] = n; + } else { + n = _nodes[nid]; + } + + if (last) { + auto e = _graph.addEdg(last, n, EdgePL()); + if (!e) + continue; + + processRestrictor(nid, w.id, _restrictions, e, n, &_restrictor); + processRestrictor(lastnid, w.id, _restrictions, e, last, &_restrictor); + + e->pl().addLines(lines); + e->pl().setLvl(_filter.level(w.attrs)); + if (!track.empty()) { + _eTracks[e] = track; + } + + if (_filter.oneway(w.attrs)) + e->pl().setOneWay(1); + if (_filter.onewayrev(w.attrs)) + e->pl().setOneWay(2); + } + lastnid = nid; + last = n; + } + } + } + + static bool relKeep(uint64_t id, const pfaedle::osm::RelMap &rels, const pfaedle::osm::FlatRels &fl) { + auto it = rels.find(id); + + if (it == rels.end()) + return false; + + return std::any_of(it->second.begin(), it->second.end(), [fl](decltype(*it->second.begin()) relId){ + return !fl.count(relId); + }); + } + + std::vector getLines(const std::vector &edgeRels, + const pfaedle::osm::RelLst &rels, + const pfaedle::osm::OsmReadOpts &ops) + { + std::vector ret; + for (size_t relId : edgeRels) { + TransitEdgeLine* transitEdgeLinePointer = nullptr; + + if (_relLines.count(relId)) { + transitEdgeLinePointer = _relLines[relId]; + } else { + TransitEdgeLine transitEdgeLine; + + bool found = false; + for (const auto &r : ops.relLinerules.sNameRule) { + for (const auto &relAttr : rels.rels[relId]) { + if (relAttr.first == r) { + transitEdgeLine.shortName = ops.lineNormzer(pfxml::file::decode(relAttr.second)); + if (!transitEdgeLine.shortName.empty()) found = true; + } + } + if (found) break; + } + + found = false; + for (const auto &r : ops.relLinerules.fromNameRule) { + for (const auto &relAttr : rels.rels[relId]) { + if (relAttr.first == r) { + transitEdgeLine.fromStr = ops.statNormzer(pfxml::file::decode(relAttr.second)); + if (!transitEdgeLine.fromStr.empty()) found = true; + } + } + if (found) break; + } + + found = false; + for (const auto &r : ops.relLinerules.toNameRule) { + for (const auto &relAttr : rels.rels[relId]) { + if (relAttr.first == r) { + transitEdgeLine.toStr = ops.statNormzer(pfxml::file::decode(relAttr.second)); + if (!transitEdgeLine.toStr.empty()) found = true; + } + } + if (found) break; + } + + if (transitEdgeLine.shortName.empty() && transitEdgeLine.fromStr.empty() && + transitEdgeLine.toStr.empty()) + continue; + + if (_lines.count(transitEdgeLine)) { + transitEdgeLinePointer = _lines[transitEdgeLine]; + _relLines[relId] = transitEdgeLinePointer; + } else { + transitEdgeLinePointer = new TransitEdgeLine(transitEdgeLine); + _lines[transitEdgeLine] = transitEdgeLinePointer; + _relLines[relId] = transitEdgeLinePointer; + } + } + ret.push_back(transitEdgeLinePointer); + } + + return ret; + } + + static void processRestrictor(uint64_t nid, uint64_t wid, + const pfaedle::osm::Restrictions &rawRests, + Edge *e, + Node *n, + pfaedle::osm::Restrictor *restor) { + if (rawRests.pos.count(nid)) { + for (const auto &kv : rawRests.pos.find(nid)->second) { + if (kv.eFrom == wid) { + e->pl().setRestricted(); + restor->add(e, kv.eTo, n, true); + } else if (kv.eTo == wid) { + e->pl().setRestricted(); + restor->relax(wid, n, e); + } + } + } + + if (rawRests.neg.count(nid)) { + for (const auto &kv : rawRests.neg.find(nid)->second) { + if (kv.eFrom == wid) { + e->pl().setRestricted(); + restor->add(e, kv.eTo, n, false); + } else if (kv.eTo == wid) { + e->pl().setRestricted(); + restor->relax(wid, n, e); + } + } + } + } + + static std::string getAttr(const pfaedle::osm::DeepAttrRule &s, uint64_t id, + const pfaedle::osm::AttrMap &attrs, + const pfaedle::osm::RelMap &entRels, + const pfaedle::osm::RelLst &rels) { + if (s.relRule.kv.first.empty()) { + if (attrs.find(s.attr) != attrs.end()) { + return attrs.find(s.attr)->second; + } + } else { + if (entRels.count(id)) { + for (const auto &relId : entRels.find(id)->second) { + if (pfaedle::osm::OsmFilter::contained(rels.rels[relId], s.relRule.kv)) { + if (rels.rels[relId].count(s.attr)) { + return rels.rels[relId].find(s.attr)->second; + } + } + } + } + } + return ""; + } + + static std::string getAttrByFirstMatch(const pfaedle::osm::DeepAttrLst &rule, uint64_t id, + const pfaedle::osm::AttrMap &attrs, + const pfaedle::osm::RelMap &entRels, + const pfaedle::osm::RelLst &rels, + const Normalizer &norm) { + std::string ret; + for (const auto &s : rule) { + ret = norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); + if (!ret.empty()) return ret; + } + + return ret; + } +}; + +class NodeHandler: public osmium::handler::Handler { + pfaedle::trgraph::Graph& _graph; + const pfaedle::osm::RelLst& rels; + const pfaedle::osm::RelMap& nodeRels; + const pfaedle::osm::OsmFilter& _filter; + const pfaedle::osm::OsmIdSet& bBoxNodes; + pfaedle::osm::NIdMap& nodes; + pfaedle::osm::NIdMultMap& multNodes; + pfaedle::osm::NodeSet& orphanStations; + const pfaedle::osm::AttrKeySet& keepAttrs; + const pfaedle::osm::FlatRels& fl; + const pfaedle::osm::OsmReadOpts& opts; + + public: + NodeHandler(Graph &g, + const pfaedle::osm::RelLst &rels, + const pfaedle::osm::RelMap &nodeRels, + const pfaedle::osm::OsmFilter &filter, + const pfaedle::osm::OsmIdSet &bBoxNodes, + pfaedle::osm::NIdMap &nodes, + pfaedle::osm::NIdMultMap &multNodes, + pfaedle::osm::NodeSet &orphanStations, + const pfaedle::osm::AttrKeySet &keepAttrs, + const pfaedle::osm::FlatRels &fl, + const pfaedle::osm::OsmReadOpts &opts) : + _graph(g), + rels(rels), + nodeRels(nodeRels), + _filter(filter), + bBoxNodes(bBoxNodes), + nodes(nodes), + multNodes(multNodes), + orphanStations(orphanStations), + keepAttrs(keepAttrs), + fl(fl), + opts(opts) + {} + + void node(const osmium::Node &node) { + OsmNode nd; + nd.id = node.id(); + nd.lat = node.location().lat(); + nd.lng = node.location().lon(); + + for (const auto &tag : node.tags()) { + if (keepAttrs.count(tag.key())) + nd.attrs[tag.key()] = tag.value(); + } + + bool valid = false; + if (nd.id && + (nodes.count(nd.id) || multNodes.count(nd.id) || + relKeep(nd.id, nodeRels, fl) || _filter.keep(nd.attrs, pfaedle::osm::OsmFilter::NODE)) && + (nodes.count(nd.id) || bBoxNodes.has(nd.id)) && + (nodes.count(nd.id) || multNodes.count(nd.id) || + !_filter.drop(nd.attrs, pfaedle::osm::OsmFilter::NODE))) { + valid = true; + } + + pfaedle::osm::StAttrGroups attrGroups; + if (valid) { + Node *n = nullptr; + auto pos = util::geo::latLngToWebMerc(nd.lat, nd.lng); + + if (nodes.count(nd.id)) { + n = nodes[nd.id]; + n->pl().setGeom(pos); + + if (_filter.station(nd.attrs)) { + auto si = getStatInfo(n, nd.id, pos, nd.attrs, &attrGroups, nodeRels, rels, opts); + + if (!si.isNull()) + n->pl().setSI(si); + } else if (_filter.blocker(nd.attrs)) { + n->pl().setBlocker(); + } + } else if (multNodes.count(nd.id)) { + for (auto *n : multNodes[nd.id]) { + n->pl().setGeom(pos); + if (_filter.station(nd.attrs)) { + auto si = getStatInfo(n, nd.id, pos, nd.attrs, &attrGroups, nodeRels, rels, opts); + + if (!si.isNull()) + n->pl().setSI(si); + } else if (_filter.blocker(nd.attrs)) { + n->pl().setBlocker(); + } + } + } else { + // these are nodes without any connected edges + if (_filter.station(nd.attrs)) { + auto tmp = _graph.addNd(NodePL(pos)); + auto si = getStatInfo(tmp, nd.id, pos, nd.attrs, &attrGroups, nodeRels, rels, opts); + + if (!si.isNull()) + tmp->pl().setSI(si); + + if (tmp->pl().getSI()) { + tmp->pl().getSI()->setIsFromOsm(false); + orphanStations.insert(tmp); + } + } + } + } + } + + + static bool relKeep(uint64_t id, const pfaedle::osm::RelMap &rels, const pfaedle::osm::FlatRels &fl) { + auto it = rels.find(id); + + if (it == rels.end()) + return false; + + for (uint64_t relId : it->second) { + // as soon as any of this entities relations is not flat, return true + if (!fl.count(relId)) + return true; + } + + return false; + } + + static Nullable getStatInfo(Node *node, uint64_t nid, + const POINT &pos, + const pfaedle::osm::AttrMap &m, + pfaedle::osm::StAttrGroups *groups, + const pfaedle::osm::RelMap &nodeRels, + const pfaedle::osm::RelLst &rels, + const pfaedle::osm::OsmReadOpts &ops) { + std::vector names = + getAttrMatchRanked(ops.statAttrRules.nameRule, nid, m, nodeRels, rels, ops.statNormzer); + std::string platform = + getAttrByFirstMatch(ops.statAttrRules.platformRule, nid, m, nodeRels, rels, ops.trackNormzer); + + if (names.empty()) { + return Nullable(); + } + + auto ret = StatInfo(names[0], platform, true); + +#ifdef PFAEDLE_STATION_IDS + ret.setId(getAttrByFirstMatch(ops.statAttrRules.idRule, nid, m, nodeRels, rels, ops.idNormzer)); +#endif + + for (size_t i = 1; i < names.size(); i++) { + ret.addAltName(names[i]); + } + bool groupFound = false; + + for (const auto &rule : ops.statGroupNAttrRules) { + if (groupFound) break; + std::string ruleVal = getAttr(rule.attr, nid, m, nodeRels, rels); + if (!ruleVal.empty()) { + // check if a matching group exists + for (auto *group : (*groups)[rule.attr.attr][ruleVal]) { + if (groupFound) break; + for (const auto *member : group->getNodes()) { + if (webMercMeterDist(*member->pl().getGeom(), pos) <= rule.maxDist) { + // ok, group is matching + groupFound = true; + if (node) group->addNode(node); + ret.setGroup(group); + break; + } + } + } + } + } + + if (!groupFound) { + for (const auto &rule : ops.statGroupNAttrRules) { + std::string ruleVal = getAttr(rule.attr, nid, m, nodeRels, rels); + if (!ruleVal.empty()) { + // add new group + auto *group = new StatGroup(); + if (node) group->addNode(node); + ret.setGroup(group); + (*groups)[rule.attr.attr][ruleVal].push_back(group); + break; + } + } + } + + return ret; + } + + static std::string getAttrByFirstMatch(const pfaedle::osm::DeepAttrLst &rule, + uint64_t id, + const pfaedle::osm::AttrMap &attrs, + const pfaedle::osm::RelMap &entRels, + const pfaedle::osm::RelLst &rels, + const Normalizer &norm) { + std::string ret; + for (const auto &s : rule) { + ret = norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); + if (!ret.empty()) { + break; + } + } + + return ret; + } + + static std::vector getAttrMatchRanked(const pfaedle::osm::DeepAttrLst &rule, + uint64_t id, + const pfaedle::osm::AttrMap &attrs, + const pfaedle::osm::RelMap &entRels, + const pfaedle::osm::RelLst &rels, + const Normalizer &norm) { + std::vector ret; + for (const auto &s : rule) { + std::string tmp = norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); + if (!tmp.empty()) { + ret.push_back(tmp); + } + } + + return ret; + } + + static std::string getAttr(const pfaedle::osm::DeepAttrRule &s, + uint64_t id, + const pfaedle::osm::AttrMap &attrs, + const pfaedle::osm::RelMap &entRels, + const pfaedle::osm::RelLst &rels) { + if (s.relRule.kv.first.empty()) { + if (attrs.find(s.attr) != attrs.end()) { + return attrs.find(s.attr)->second; + } + } else { + if (entRels.count(id)) { + for (const auto &relId : entRels.find(id)->second) { + if (pfaedle::osm::OsmFilter::contained(rels.rels[relId], s.relRule.kv)) { + if (rels.rels[relId].count(s.attr)) { + return rels.rels[relId].find(s.attr)->second; + } + } + } + } + } + return ""; + } +}; + // _____________________________________________________________________________ bool EqSearch::operator()(const Node* cand, const StatInfo* si) const { - if (orphanSnap && cand->pl().getSI() && - (!cand->pl().getSI()->getGroup() || - cand->pl().getSI()->getGroup()->getStops().size() == 0)) { - return true; - } - return cand->pl().getSI() && cand->pl().getSI()->simi(si) > minSimi; + if (orphanSnap && cand->pl().getSI() && + (!cand->pl().getSI()->getGroup() || cand->pl().getSI()->getGroup()->getStops().empty())) { + return true; + } + return cand->pl().getSI() && cand->pl().getSI()->simi(si) > minSimi; } // _____________________________________________________________________________ -OsmBuilder::OsmBuilder() {} +OsmBuilder::OsmBuilder() = default; // _____________________________________________________________________________ void OsmBuilder::read(const std::string& path, const OsmReadOpts& opts, Graph* g, const BBoxIdx& bbox, size_t gridSize, router::FeedStops* fs, Restrictor* res) { - if (!bbox.size()) return; + if (!bbox.size()) return; - LOG(INFO) << "Reading OSM file " << path << " ... "; + LOG(INFO) << "Reading OSM file " << path << " ... "; - NodeSet orphanStations; - EdgTracks eTracks; - { - OsmIdSet bboxNodes, noHupNodes; + NodeSet orphanStations; + EdgTracks eTracks; + { + OsmIdSet bboxNodes, noHupNodes; - NIdMap nodes; - NIdMultMap multNodes; - RelLst intmRels; - RelMap nodeRels, wayRels; + NIdMap nodes; + NIdMultMap multNodes; + RelLst intmRels; + RelMap nodeRels, wayRels; - Restrictions rawRests; + Restrictions rawRests; - AttrKeySet attrKeys[3] = {}; - getKeptAttrKeys(opts, attrKeys); - - OsmFilter filter(opts); - - pfxml::file xml(path); - - // we do four passes of the file here to be as memory creedy as possible: - // - the first pass collects all node IDs which are - // * inside the given bounding box - // * (TODO: maybe more filtering?) - // these nodes are stored on the HD via OsmIdSet (which implements a - // simple bloom filter / base 256 encoded id store - // - the second pass collects filtered relations - // - the third pass collects filtered ways which contain one of the nodes - // from pass 1 - // - the forth pass collects filtered nodes which were - // * collected as node ids in pass 1 - // * match the filter criteria - // * have been used in a way in pass 3 - - LOG(VDEBUG) << "Reading bounding box nodes..."; - skipUntil(&xml, "node"); - pfxml::parser_state nodeBeg = xml.state(); - pfxml::parser_state edgesBeg = - readBBoxNds(&xml, &bboxNodes, &noHupNodes, filter, bbox); + AttrKeySet attrKeys[3] = {}; + getKeptAttrKeys(opts, attrKeys); - LOG(VDEBUG) << "Reading relations..."; - skipUntil(&xml, "relation"); - readRels(&xml, &intmRels, &nodeRels, &wayRels, filter, attrKeys[2], - &rawRests); + OsmFilter filter(opts); - LOG(VDEBUG) << "Reading edges..."; - xml.set_state(edgesBeg); - readEdges(&xml, g, intmRels, wayRels, filter, bboxNodes, &nodes, &multNodes, - noHupNodes, attrKeys[1], rawRests, res, intmRels.flat, &eTracks, - opts); + osmium::io::Reader reader {path, + osmium::osm_entity_bits::node | + osmium::osm_entity_bits::way | + osmium::osm_entity_bits::relation}; + osmium::io::Reader reader_nodes{path, + osmium::osm_entity_bits::node}; - LOG(VDEBUG) << "Reading kept nodes..."; - xml.set_state(nodeBeg); - readNodes(&xml, g, intmRels, nodeRels, filter, bboxNodes, &nodes, - &multNodes, &orphanStations, attrKeys[0], intmRels.flat, opts); - } + NodeFilteringHandler filteringHandler(filter, bbox, bboxNodes, noHupNodes); + RelationHandler relationHandler(filter, bbox, attrKeys[2], intmRels, nodeRels, wayRels, rawRests); + WayHandler wayHandler(*g, intmRels, wayRels, filter, bboxNodes, nodes, multNodes, noHupNodes, + attrKeys[1], rawRests, *res, intmRels.flat, eTracks, opts); + + osmium::apply(reader, filteringHandler, relationHandler, wayHandler); + NodeHandler nodeHandler(*g, intmRels, nodeRels, filter, bboxNodes, nodes, multNodes, orphanStations, + attrKeys[0], intmRels.flat, opts); + osmium::apply(reader_nodes, nodeHandler); - LOG(VDEBUG) << "OSM ID set lookups: " << osm::OsmIdSet::LOOKUPS - << ", file lookups: " << osm::OsmIdSet::FLOOKUPS; + // we do four passes of the file here to be as memory creedy as possible: + // - the first pass collects all node IDs which are + // * inside the given bounding box + // * (TODO: maybe more filtering?) + // these nodes are stored on the HD via OsmIdSet (which implements a + // simple bloom filter / base 256 encoded id store + // - the second pass collects filtered relations + // - the third pass collects filtered ways which contain one of the nodes + // from pass 1 + // - the forth pass collects filtered nodes which were + // * collected as node ids in pass 1 + // * match the filter criteria + // * have been used in a way in pass 3 + } - LOG(VDEBUG) << "Applying edge track numbers..."; - writeEdgeTracks(eTracks); - eTracks.clear(); + LOG(VDEBUG) << "OSM ID set lookups: " << osm::OsmIdSet::LOOKUPS + << ", file lookups: " << osm::OsmIdSet::FLOOKUPS; - { - LOG(VDEBUG) << "Fixing gaps..."; - NodeGrid ng = buildNodeIdx(g, gridSize, bbox.getFullWebMercBox(), false); - fixGaps(g, &ng); - } + LOG(VDEBUG) << "Applying edge track numbers..."; + writeEdgeTracks(eTracks); + eTracks.clear(); - LOG(VDEBUG) << "Writing edge geoms..."; - writeGeoms(g); + { + LOG(VDEBUG) << "Fixing gaps..."; + NodeGrid ng = buildNodeIdx(g, gridSize, bbox.getFullWebMercBox(), false); + fixGaps(g, &ng); + } - LOG(VDEBUG) << "Snapping stations..."; - snapStats(opts, g, bbox, gridSize, fs, res, orphanStations); + LOG(VDEBUG) << "Writing edge geoms..."; + writeGeoms(g); - LOG(VDEBUG) << "Deleting orphan nodes..."; - deleteOrphNds(g); + LOG(VDEBUG) << "Snapping stations..."; + snapStats(opts, g, bbox, gridSize, fs, res, orphanStations); - LOG(VDEBUG) << "Deleting orphan edges..."; - deleteOrphEdgs(g, opts); + LOG(VDEBUG) << "Deleting orphan nodes..."; + deleteOrphNds(g); - LOG(VDEBUG) << "Collapsing edges..."; - collapseEdges(g); + LOG(VDEBUG) << "Deleting orphan edges..."; + deleteOrphEdgs(g, opts); - LOG(VDEBUG) << "Deleting orphan nodes..."; - deleteOrphNds(g); + LOG(VDEBUG) << "Collapsing edges..."; + collapseEdges(g); - LOG(VDEBUG) << "Deleting orphan edges..."; - deleteOrphEdgs(g, opts); + LOG(VDEBUG) << "Deleting orphan nodes..."; + deleteOrphNds(g); - LOG(VDEBUG) << "Writing graph components..."; - // the restrictor is needed here to prevent connections in the graph - // which are not possible in reality - uint32_t comps = writeComps(g); + LOG(VDEBUG) << "Deleting orphan edges..."; + deleteOrphEdgs(g, opts); - LOG(VDEBUG) << "Simplifying geometries..."; - simplifyGeoms(g); + LOG(VDEBUG) << "Writing graph components..."; + // the restrictor is needed here to prevent connections in the graph + // which are not possible in reality + uint32_t comps = writeComps(g); - LOG(VDEBUG) << "Writing other-direction edges..."; - writeODirEdgs(g, res); + LOG(VDEBUG) << "Simplifying geometries..."; + simplifyGeoms(g); - LOG(VDEBUG) << "Write dummy node self-edges..."; - writeSelfEdgs(g); + LOG(VDEBUG) << "Writing other-direction edges..."; + writeODirEdgs(g, res); - size_t numEdges = 0; + LOG(VDEBUG) << "Write dummy node self-edges..."; + writeSelfEdgs(g); - for (auto* n : *g->getNds()) { - numEdges += n->getAdjListOut().size(); - } + size_t numEdges = 0; - LOG(DEBUG) << "Graph has " << g->getNds()->size() << " nodes, " << numEdges - << " edges and " << comps << " connected component(s)"; + for (auto* n : *g->getNds()) { + numEdges += n->getAdjListOut().size(); + } + + LOG(DEBUG) << "Graph has " << g->getNds()->size() << " nodes, " << numEdges + << " edges and " << comps << " connected component(s)"; } // _____________________________________________________________________________ void OsmBuilder::overpassQryWrite(std::ostream* out, const std::vector& opts, const BBoxIdx& latLngBox) const { - OsmIdSet bboxNodes, noHupNodes; - MultAttrMap emptyF; - - RelLst rels; - OsmIdList ways; - RelMap nodeRels, wayRels; + OsmIdSet bboxNodes, noHupNodes; + MultAttrMap emptyF; - // TODO(patrick): not needed here! - Restrictions rests; + RelLst rels; + OsmIdList ways; + RelMap nodeRels, wayRels; - NIdMap nodes; + // TODO(patrick): not needed here! + Restrictions rests; - // always empty - NIdMultMap multNodes; - util::xml::XmlWriter wr(out, true, 4); + NIdMap nodes; - *out << "\n"; - wr.openComment(); - wr.writeText(" - written by pfaedle -"); - wr.closeTag(); - wr.openTag("osm-script"); + // always empty + NIdMultMap multNodes; + util::xml::XmlWriter wr(out, true, 4); - OsmFilter filter; + *out << "\n"; + wr.openComment(); + wr.writeText(" - written by pfaedle -"); + wr.closeTag(); + wr.openTag("osm-script"); + + OsmFilter filter; + + for (const OsmReadOpts& o : opts) { + filter = filter.merge(OsmFilter(o.keepFilter, o.dropFilter)); + } + + wr.openTag("union"); + size_t c = 0; + for (auto box : latLngBox.getLeafs()) { + if (box.getLowerLeft().getX() > box.getUpperRight().getX()) continue; + c++; + wr.openComment(); + wr.writeText(std::string("Bounding box #") + std::to_string(c) + " (" + + std::to_string(box.getLowerLeft().getY()) + ", " + + std::to_string(box.getLowerLeft().getX()) + ", " + + std::to_string(box.getUpperRight().getY()) + ", " + + std::to_string(box.getUpperRight().getX()) + ")"); + wr.closeTag(); + for (auto t : std::vector{"way", "node", "relation"}) { + for (auto r : filter.getKeepRules()) { + for (auto val : r.second) { + if (t == "way" && (val.second & OsmFilter::WAY)) continue; + if (t == "relation" && (val.second & OsmFilter::REL)) continue; + if (t == "node" && (val.second & OsmFilter::NODE)) continue; + + wr.openTag("query", {{"type", t}}); + if (val.first == "*") + wr.openTag("has-kv", {{"k", r.first}}); + else + wr.openTag("has-kv", {{"k", r.first}, {"v", val.first}}); + wr.closeTag(); + wr.openTag("bbox-query", + {{"s", std::to_string(box.getLowerLeft().getY())}, + {"w", std::to_string(box.getLowerLeft().getX())}, + {"n", std::to_string(box.getUpperRight().getY())}, + {"e", std::to_string(box.getUpperRight().getX())}}); + wr.closeTag(); + wr.closeTag(); + } + } + } + } - for (const OsmReadOpts& o : opts) { - filter = filter.merge(OsmFilter(o.keepFilter, o.dropFilter)); - } + wr.closeTag(); - wr.openTag("union"); - size_t c = 0; - for (auto box : latLngBox.getLeafs()) { - if (box.getLowerLeft().getX() > box.getUpperRight().getX()) continue; - c++; - wr.openComment(); - wr.writeText(std::string("Bounding box #") + std::to_string(c) + " (" + - std::to_string(box.getLowerLeft().getY()) + ", " + - std::to_string(box.getLowerLeft().getX()) + ", " + - std::to_string(box.getUpperRight().getY()) + ", " + - std::to_string(box.getUpperRight().getX()) + ")"); + wr.openTag("union"); + wr.openTag("item"); wr.closeTag(); - for (auto t : std::vector{"way", "node", "relation"}) { - for (auto r : filter.getKeepRules()) { - for (auto val : r.second) { - if (t == "way" && (val.second & OsmFilter::WAY)) continue; - if (t == "relation" && (val.second & OsmFilter::REL)) continue; - if (t == "node" && (val.second & OsmFilter::NODE)) continue; - - wr.openTag("query", {{"type", t}}); - if (val.first == "*") - wr.openTag("has-kv", {{"k", r.first}}); - else - wr.openTag("has-kv", {{"k", r.first}, {"v", val.first}}); - wr.closeTag(); - wr.openTag("bbox-query", - {{"s", std::to_string(box.getLowerLeft().getY())}, - {"w", std::to_string(box.getLowerLeft().getX())}, - {"n", std::to_string(box.getUpperRight().getY())}, - {"e", std::to_string(box.getUpperRight().getX())}}); - wr.closeTag(); - wr.closeTag(); - } - } - } - } - - wr.closeTag(); - - wr.openTag("union"); - wr.openTag("item"); - wr.closeTag(); - wr.openTag("recurse", {{"type", "down"}}); - wr.closeTag(); - wr.closeTag(); - wr.openTag("print"); - - wr.closeTags(); + wr.openTag("recurse", {{"type", "down"}}); + wr.closeTag(); + wr.closeTag(); + wr.openTag("print"); + + wr.closeTags(); } // _____________________________________________________________________________ void OsmBuilder::filterWrite(const std::string& in, const std::string& out, const std::vector& opts, const BBoxIdx& latLngBox) { - OsmIdSet bboxNodes, noHupNodes; - MultAttrMap emptyF; - - RelLst rels; - OsmIdList ways; - RelMap nodeRels, wayRels; - - // TODO(patrick): not needed here! - Restrictions rests; + OsmIdSet bboxNodes, noHupNodes; + MultAttrMap emptyF; - NIdMap nodes; + RelLst rels; + OsmIdList ways; + RelMap nodeRels, wayRels; - // always empty - NIdMultMap multNodes; + // TODO(patrick): not needed here! + Restrictions rests; - pfxml::file xml(in); - std::ofstream outstr; - outstr.open(out); + NIdMap nodes; - util::xml::XmlWriter wr(&outstr, true, 4); + // always empty + NIdMultMap multNodes; - outstr << "\n"; - wr.openTag("osm"); - wr.openTag( - "bounds", - {{"minlat", std::to_string(latLngBox.getFullBox().getLowerLeft().getY())}, - {"minlon", std::to_string(latLngBox.getFullBox().getLowerLeft().getX())}, - {"maxlat", - std::to_string(latLngBox.getFullBox().getUpperRight().getY())}, - {"maxlon", - std::to_string(latLngBox.getFullBox().getUpperRight().getX())}}); - wr.closeTag(); + pfxml::file xml(in); + std::ofstream outstr; + outstr.open(out); + + util::xml::XmlWriter wr(&outstr, true, 4); + + outstr << "\n"; + wr.openTag("osm"); + wr.openTag( + "bounds", + {{"minlat", std::to_string(latLngBox.getFullBox().getLowerLeft().getY())}, + {"minlon", std::to_string(latLngBox.getFullBox().getLowerLeft().getX())}, + {"maxlat", + std::to_string(latLngBox.getFullBox().getUpperRight().getY())}, + {"maxlon", + std::to_string(latLngBox.getFullBox().getUpperRight().getX())}}); + wr.closeTag(); - OsmFilter filter; - AttrKeySet attrKeys[3] = {}; + OsmFilter filter; + AttrKeySet attrKeys[3] = {}; - for (const OsmReadOpts& o : opts) { - getKeptAttrKeys(o, attrKeys); - filter = filter.merge(OsmFilter(o.keepFilter, o.dropFilter)); - } + for (const OsmReadOpts& o : opts) { + getKeptAttrKeys(o, attrKeys); + filter = filter.merge(OsmFilter(o.keepFilter, o.dropFilter)); + } - skipUntil(&xml, "node"); - pfxml::parser_state nodeBeg = xml.state(); - pfxml::parser_state edgesBeg = - readBBoxNds(&xml, &bboxNodes, &noHupNodes, filter, latLngBox); + skipUntil(&xml, "node"); + pfxml::parser_state nodeBeg = xml.state(); + pfxml::parser_state edgesBeg = + readBBoxNds(&xml, &bboxNodes, &noHupNodes, filter, latLngBox); - skipUntil(&xml, "relation"); - readRels(&xml, &rels, &nodeRels, &wayRels, filter, attrKeys[2], &rests); + skipUntil(&xml, "relation"); + readRels(&xml, &rels, &nodeRels, &wayRels, filter, attrKeys[2], &rests); - xml.set_state(edgesBeg); - readEdges(&xml, wayRels, filter, bboxNodes, attrKeys[1], &ways, &nodes, + xml.set_state(edgesBeg); + readEdges(&xml, wayRels, filter, bboxNodes, attrKeys[1], &ways, &nodes, rels.flat); - xml.set_state(nodeBeg); + xml.set_state(nodeBeg); - readWriteNds(&xml, &wr, nodeRels, filter, bboxNodes, &nodes, attrKeys[0], - rels.flat); - readWriteWays(&xml, &wr, &ways, attrKeys[1]); + readWriteNds(&xml, &wr, nodeRels, filter, bboxNodes, &nodes, attrKeys[0], + rels.flat); + readWriteWays(&xml, &wr, &ways, attrKeys[1]); - std::sort(ways.begin(), ways.end()); - skipUntil(&xml, "relation"); - readWriteRels(&xml, &wr, &ways, &nodes, filter, attrKeys[2]); + std::sort(ways.begin(), ways.end()); + skipUntil(&xml, "relation"); + readWriteRels(&xml, &wr, &ways, &nodes, filter, attrKeys[2]); - wr.closeTags(); + wr.closeTags(); } // _____________________________________________________________________________ @@ -339,193 +1024,193 @@ void OsmBuilder::readWriteRels(pfxml::file* i, util::xml::XmlWriter* o, OsmIdList* ways, NIdMap* nodes, const OsmFilter& filter, const AttrKeySet& keepAttrs) { - OsmRel rel; - while ((rel = nextRel(i, filter, keepAttrs)).id) { - OsmIdList realNodes, realWays; - std::vector realNodeRoles, realWayRoles; - - for (size_t j = 0; j < rel.ways.size(); j++) { - osmid wid = rel.ways[j]; - const auto& i = std::lower_bound(ways->begin(), ways->end(), wid); - if (i != ways->end() && *i == wid) { - realWays.push_back(wid); - realWayRoles.push_back(rel.wayRoles[j].c_str()); - } - } - - for (size_t j = 0; j < rel.nodes.size(); j++) { - osmid nid = rel.nodes[j]; - if (nodes->count(nid)) { - realNodes.push_back(nid); - realNodeRoles.push_back(rel.nodeRoles[j].c_str()); - } - } - - if (realNodes.size() || realWays.size()) { - o->openTag("relation", "id", std::to_string(rel.id)); - - for (size_t j = 0; j < realNodes.size(); j++) { - osmid nid = realNodes[j]; - std::map attrs; - attrs["type"] = "node"; - if (strlen(realNodeRoles[j])) attrs["role"] = realNodeRoles[j]; - attrs["ref"] = std::to_string(nid); - o->openTag("member", attrs); - o->closeTag(); - } - - for (size_t j = 0; j < realWays.size(); j++) { - osmid wid = realWays[j]; - std::map attrs; - attrs["type"] = "way"; - if (strlen(realWayRoles[j])) attrs["role"] = realWayRoles[j]; - attrs["ref"] = std::to_string(wid); - o->openTag("member", attrs); - o->closeTag(); - } + OsmRel rel; + while ((rel = nextRel(i, filter, keepAttrs)).id) { + OsmIdList realNodes, realWays; + std::vector realNodeRoles, realWayRoles; + + for (size_t j = 0; j < rel.ways.size(); j++) { + osmid wid = rel.ways[j]; + const auto& i = std::lower_bound(ways->begin(), ways->end(), wid); + if (i != ways->end() && *i == wid) { + realWays.push_back(wid); + realWayRoles.push_back(rel.wayRoles[j].c_str()); + } + } - for (const auto& kv : rel.attrs) { - std::map attrs = { - {"k", kv.first}, {"v", pfxml::file::decode(kv.second)}}; - o->openTag("tag", attrs); - o->closeTag(); - } + for (size_t j = 0; j < rel.nodes.size(); j++) { + osmid nid = rel.nodes[j]; + if (nodes->count(nid)) { + realNodes.push_back(nid); + realNodeRoles.push_back(rel.nodeRoles[j].c_str()); + } + } + + if (!realNodes.empty() || !realWays.empty()) { + o->openTag("relation", "id", std::to_string(rel.id)); + + for (size_t j = 0; j < realNodes.size(); j++) { + osmid nid = realNodes[j]; + std::map attrs; + attrs["type"] = "node"; + if (strlen(realNodeRoles[j])) attrs["role"] = realNodeRoles[j]; + attrs["ref"] = std::to_string(nid); + o->openTag("member", attrs); + o->closeTag(); + } - o->closeTag(); + for (size_t j = 0; j < realWays.size(); j++) { + osmid wid = realWays[j]; + std::map attrs; + attrs["type"] = "way"; + if (strlen(realWayRoles[j])) attrs["role"] = realWayRoles[j]; + attrs["ref"] = std::to_string(wid); + o->openTag("member", attrs); + o->closeTag(); + } + + for (const auto& kv : rel.attrs) { + std::map attrs = { + {"k", kv.first}, {"v", pfxml::file::decode(kv.second)}}; + o->openTag("tag", attrs); + o->closeTag(); + } + + o->closeTag(); + } } - } } // _____________________________________________________________________________ void OsmBuilder::readWriteWays(pfxml::file* i, util::xml::XmlWriter* o, OsmIdList* ways, const AttrKeySet& keepAttrs) const { - OsmWay w; - NIdMultMap empty; - for (auto wid : *ways) { - w = nextWayWithId(i, wid, keepAttrs); - assert(w.id); - o->openTag("way", "id", std::to_string(wid)); - for (osmid nid : w.nodes) { - o->openTag("nd", "ref", std::to_string(nid)); - o->closeTag(); - } - for (const auto& kv : w.attrs) { - std::map attrs; - attrs["k"] = kv.first; - attrs["v"] = pfxml::file::decode(kv.second); - o->openTag("tag", attrs); - o->closeTag(); - } - o->closeTag(); - } + OsmWay w; + NIdMultMap empty; + for (auto wid : *ways) { + w = nextWayWithId(i, wid, keepAttrs); + assert(w.id); + o->openTag("way", "id", std::to_string(wid)); + for (osmid nid : w.nodes) { + o->openTag("nd", "ref", std::to_string(nid)); + o->closeTag(); + } + for (const auto& kv : w.attrs) { + std::map attrs; + attrs["k"] = kv.first; + attrs["v"] = pfxml::file::decode(kv.second); + o->openTag("tag", attrs); + o->closeTag(); + } + o->closeTag(); + } } // _____________________________________________________________________________ NodePL OsmBuilder::plFromGtfs(const Stop* s, const OsmReadOpts& ops) { - NodePL ret( - util::geo::latLngToWebMerc(s->getLat(), s->getLng()), - StatInfo(ops.statNormzer(s->getName()), - ops.trackNormzer(s->getPlatformCode()), false)); + NodePL ret( + util::geo::latLngToWebMerc(s->getLat(), s->getLng()), + StatInfo(ops.statNormzer(s->getName()), ops.trackNormzer(s->getPlatformCode()), false)); #ifdef PFAEDLE_STATION_IDS - // debug feature, store station id from GTFS - ret.getSI()->setId(s->getId()); + // debug feature, store station id from GTFS + ret.getSI()->setId(s->getId()); #endif - if (s->getParentStation()) { - ret.getSI()->addAltName(ops.statNormzer(s->getParentStation()->getName())); - } + if (s->getParentStation()) { + ret.getSI()->addAltName(ops.statNormzer(s->getParentStation()->getName())); + } - return ret; + return ret; } // _____________________________________________________________________________ pfxml::parser_state OsmBuilder::readBBoxNds(pfxml::file* xml, OsmIdSet* nodes, - OsmIdSet* nohupNodes, - const OsmFilter& filter, - const BBoxIdx& bbox) const { - bool inNodeBlock = false; - uint64_t curId = 0; - - do { - const pfxml::tag& cur = xml->get(); - - if (inNodeBlock && xml->level() == 3 && curId && - strcmp(cur.name, "tag") == 0) { - if (filter.nohup(cur.attrs.find("k")->second, - cur.attrs.find("v")->second)) { - nohupNodes->add(curId); - } - } + OsmIdSet* nohupNodes, + const OsmFilter& filter, + const BBoxIdx& bbox) const { + bool inNodeBlock = false; + uint64_t curId = 0; + + do { + const pfxml::tag& cur = xml->get(); + + if (inNodeBlock && xml->level() == 3 && curId && + strcmp(cur.name, "tag") == 0) { + if (filter.nohup(cur.attrs.find("k")->second, + cur.attrs.find("v")->second)) { + nohupNodes->add(curId); + } + } - if (xml->level() != 2) continue; - if (!inNodeBlock && strcmp(cur.name, "node") == 0) inNodeBlock = true; + if (xml->level() != 2) continue; + if (!inNodeBlock && strcmp(cur.name, "node") == 0) inNodeBlock = true; - if (inNodeBlock) { - // block ended - if (strcmp(cur.name, "node")) return xml->state(); - double y = util::atof(cur.attrs.find("lat")->second, 7); - double x = util::atof(cur.attrs.find("lon")->second, 7); + if (inNodeBlock) { + // block ended + if (strcmp(cur.name, "node") != 0) + return xml->state(); + double y = util::atof(cur.attrs.find("lat")->second, 7); + double x = util::atof(cur.attrs.find("lon")->second, 7); - if (bbox.contains(Point(x, y))) { - curId = util::atoul(cur.attrs.find("id")->second); - nodes->add(curId); - } - } - } while (xml->next()); + if (bbox.contains(Point(x, y))) { + curId = util::atoul(cur.attrs.find("id")->second); + nodes->add(curId); + } + } + } while (xml->next()); - return xml->state(); + return xml->state(); } // _____________________________________________________________________________ OsmWay OsmBuilder::nextWayWithId(pfxml::file* xml, osmid wid, const AttrKeySet& keepAttrs) const { - OsmWay w; + OsmWay w; - do { - const pfxml::tag& cur = xml->get(); - if (xml->level() == 2 || xml->level() == 0) { - if (w.id || strcmp(cur.name, "way")) return w; + do { + const pfxml::tag& cur = xml->get(); + if (xml->level() == 2 || xml->level() == 0) { + if (w.id || strcmp(cur.name, "way") != 0) return w; - osmid id = util::atoul(cur.attrs.find("id")->second); - if (id == wid) w.id = id; - } + osmid id = util::atoul(cur.attrs.find("id")->second); + if (id == wid) w.id = id; + } - if (w.id && xml->level() == 3) { - if (strcmp(cur.name, "nd") == 0) { - w.nodes.push_back(util::atoul(cur.attrs.find("ref")->second)); - } else if (strcmp(cur.name, "tag") == 0) { - if (keepAttrs.count(cur.attrs.find("k")->second)) - w.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; - } - } - } while (xml->next()); + if (w.id && xml->level() == 3) { + if (strcmp(cur.name, "nd") == 0) { + w.nodes.push_back(util::atoul(cur.attrs.find("ref")->second)); + } else if (strcmp(cur.name, "tag") == 0) { + if (keepAttrs.count(cur.attrs.find("k")->second)) + w.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; + } + } + } while (xml->next()); - if (w.id) return w; + if (w.id) return w; - return OsmWay(); + return OsmWay(); } // _____________________________________________________________________________ void OsmBuilder::skipUntil(pfxml::file* xml, const std::string& s) const { - while (xml->next() && strcmp(xml->get().name, s.c_str())) { - } + while (xml->next() && strcmp(xml->get().name, s.c_str()) != 0) { + } } // _____________________________________________________________________________ bool OsmBuilder::relKeep(osmid id, const RelMap& rels, const FlatRels& fl) const { - auto it = rels.find(id); + auto it = rels.find(id); - if (it == rels.end()) return false; + if (it == rels.end()) return false; - for (osmid relId : it->second) { - // as soon as any of this entities relations is not flat, return true - if (!fl.count(relId)) return true; - } + for (osmid relId : it->second) { + // as soon as any of this entities relations is not flat, return true + if (!fl.count(relId)) return true; + } - return false; + return false; } // _____________________________________________________________________________ @@ -533,49 +1218,55 @@ OsmWay OsmBuilder::nextWay(pfxml::file* xml, const RelMap& wayRels, const OsmFilter& filter, const OsmIdSet& bBoxNodes, const AttrKeySet& keepAttrs, const FlatRels& fl) const { - OsmWay w; + OsmWay w; - do { - const pfxml::tag& cur = xml->get(); - if (xml->level() == 2 || xml->level() == 0) { - if (keepWay(w, wayRels, filter, bBoxNodes, fl)) return w; - if (strcmp(cur.name, "way")) return OsmWay(); + do { + const pfxml::tag& cur = xml->get(); + if (xml->level() == 2 || xml->level() == 0) { + if (keepWay(w, wayRels, filter, bBoxNodes, fl)) + return w; - w.id = util::atoul(cur.attrs.find("id")->second); - w.nodes.clear(); - w.attrs.clear(); - } + if (strcmp(cur.name, "way") != 0) + return OsmWay(); - if (w.id && xml->level() == 3) { - if (strcmp(cur.name, "nd") == 0) { - osmid nid = util::atoul(cur.attrs.find("ref")->second); - w.nodes.push_back(nid); - } else if (strcmp(cur.name, "tag") == 0) { - if (keepAttrs.count(cur.attrs.find("k")->second)) - w.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; - } - } - } while (xml->next()); + w.id = util::atoul(cur.attrs.find("id")->second); + w.nodes.clear(); + w.attrs.clear(); + } + + if (w.id && xml->level() == 3) { + if (strcmp(cur.name, "nd") == 0) { + osmid nid = util::atoul(cur.attrs.find("ref")->second); + w.nodes.push_back(nid); + } else if (strcmp(cur.name, "tag") == 0) { + if (keepAttrs.count(cur.attrs.find("k")->second)) { + w.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; + } + } + } + } while (xml->next()); - if (keepWay(w, wayRels, filter, bBoxNodes, fl)) return w; - return OsmWay(); + if (keepWay(w, wayRels, filter, bBoxNodes, fl)) + return w; + + return OsmWay(); } // _____________________________________________________________________________ bool OsmBuilder::keepWay(const OsmWay& w, const RelMap& wayRels, const OsmFilter& filter, const OsmIdSet& bBoxNodes, const FlatRels& fl) const { - if (w.id && w.nodes.size() > 1 && - (relKeep(w.id, wayRels, fl) || filter.keep(w.attrs, OsmFilter::WAY)) && - !filter.drop(w.attrs, OsmFilter::WAY)) { - for (osmid nid : w.nodes) { - if (bBoxNodes.has(nid)) { - return true; - } + if (w.id && w.nodes.size() > 1 && + (relKeep(w.id, wayRels, fl) || filter.keep(w.attrs, OsmFilter::WAY)) && + !filter.drop(w.attrs, OsmFilter::WAY)) { + for (osmid nid : w.nodes) { + if (bBoxNodes.has(nid)) { + return true; + } + } } - } - return false; + return false; } // _____________________________________________________________________________ @@ -583,13 +1274,13 @@ void OsmBuilder::readEdges(pfxml::file* xml, const RelMap& wayRels, const OsmFilter& filter, const OsmIdSet& bBoxNodes, const AttrKeySet& keepAttrs, OsmIdList* ret, NIdMap* nodes, const FlatRels& flat) { - OsmWay w; - while ((w = nextWay(xml, wayRels, filter, bBoxNodes, keepAttrs, flat)).id) { - ret->push_back(w.id); - for (auto n : w.nodes) { - (*nodes)[n] = 0; + OsmWay w; + while ((w = nextWay(xml, wayRels, filter, bBoxNodes, keepAttrs, flat)).id) { + ret->push_back(w.id); + for (auto n : w.nodes) { + (*nodes)[n] = nullptr; + } } - } } // _____________________________________________________________________________ @@ -601,77 +1292,77 @@ void OsmBuilder::readEdges(pfxml::file* xml, Graph* g, const RelLst& rels, const Restrictions& rawRests, Restrictor* restor, const FlatRels& fl, EdgTracks* eTracks, const OsmReadOpts& opts) { - OsmWay w; - while ((w = nextWay(xml, wayRels, filter, bBoxNodes, keepAttrs, fl)).id) { - Node* last = 0; - std::vector lines; - if (wayRels.count(w.id)) { - lines = getLines(wayRels.find(w.id)->second, rels, opts); - } - std::string track = - getAttrByFirstMatch(opts.edgePlatformRules, w.id, w.attrs, wayRels, - rels, opts.trackNormzer); - - osmid lastnid = 0; - for (osmid nid : w.nodes) { - Node* n = 0; - if (noHupNodes.has(nid)) { - n = g->addNd(); - (*multiNodes)[nid].insert(n); - } else if (!nodes->count(nid)) { - if (!bBoxNodes.has(nid)) continue; - n = g->addNd(); - (*nodes)[nid] = n; - } else { - n = (*nodes)[nid]; - } - if (last) { - auto e = g->addEdg(last, n, EdgePL()); - if (!e) continue; - - processRestr(nid, w.id, rawRests, e, n, restor); - processRestr(lastnid, w.id, rawRests, e, last, restor); - - e->pl().addLines(lines); - e->pl().setLvl(filter.level(w.attrs)); - if (!track.empty()) (*eTracks)[e] = track; - - if (filter.oneway(w.attrs)) e->pl().setOneWay(1); - if (filter.onewayrev(w.attrs)) e->pl().setOneWay(2); - } - lastnid = nid; - last = n; - } - } + OsmWay w; + while ((w = nextWay(xml, wayRels, filter, bBoxNodes, keepAttrs, fl)).id) { + Node* last = nullptr; + std::vector lines; + if (wayRels.count(w.id)) { + lines = getLines(wayRels.find(w.id)->second, rels, opts); + } + std::string track = + getAttrByFirstMatch(opts.edgePlatformRules, w.id, w.attrs, wayRels, + rels, opts.trackNormzer); + + osmid lastnid = 0; + for (osmid nid : w.nodes) { + Node* n = nullptr; + if (noHupNodes.has(nid)) { + n = g->addNd(); + (*multiNodes)[nid].insert(n); + } else if (!nodes->count(nid)) { + if (!bBoxNodes.has(nid)) continue; + n = g->addNd(); + (*nodes)[nid] = n; + } else { + n = (*nodes)[nid]; + } + if (last) { + auto e = g->addEdg(last, n, EdgePL()); + if (!e) continue; + + processRestr(nid, w.id, rawRests, e, n, restor); + processRestr(lastnid, w.id, rawRests, e, last, restor); + + e->pl().addLines(lines); + e->pl().setLvl(filter.level(w.attrs)); + if (!track.empty()) (*eTracks)[e] = track; + + if (filter.oneway(w.attrs)) e->pl().setOneWay(1); + if (filter.onewayrev(w.attrs)) e->pl().setOneWay(2); + } + lastnid = nid; + last = n; + } + } } // _____________________________________________________________________________ void OsmBuilder::processRestr(osmid nid, osmid wid, const Restrictions& rawRests, Edge* e, Node* n, Restrictor* restor) const { - if (rawRests.pos.count(nid)) { - for (const auto& kv : rawRests.pos.find(nid)->second) { - if (kv.eFrom == wid) { - e->pl().setRestricted(); - restor->add(e, kv.eTo, n, true); - } else if (kv.eTo == wid) { - e->pl().setRestricted(); - restor->relax(wid, n, e); - } - } - } - - if (rawRests.neg.count(nid)) { - for (const auto& kv : rawRests.neg.find(nid)->second) { - if (kv.eFrom == wid) { - e->pl().setRestricted(); - restor->add(e, kv.eTo, n, false); - } else if (kv.eTo == wid) { - e->pl().setRestricted(); - restor->relax(wid, n, e); - } - } - } + if (rawRests.pos.count(nid)) { + for (const auto& kv : rawRests.pos.find(nid)->second) { + if (kv.eFrom == wid) { + e->pl().setRestricted(); + restor->add(e, kv.eTo, n, true); + } else if (kv.eTo == wid) { + e->pl().setRestricted(); + restor->relax(wid, n, e); + } + } + } + + if (rawRests.neg.count(nid)) { + for (const auto& kv : rawRests.neg.find(nid)->second) { + if (kv.eFrom == wid) { + e->pl().setRestricted(); + restor->add(e, kv.eTo, n, false); + } else if (kv.eTo == wid) { + e->pl().setRestricted(); + restor->relax(wid, n, e); + } + } + } } // _____________________________________________________________________________ @@ -680,31 +1371,31 @@ OsmNode OsmBuilder::nextNode(pfxml::file* xml, NIdMap* nodes, const OsmFilter& filter, const OsmIdSet& bBoxNodes, const AttrKeySet& keepAttrs, const FlatRels& fl) const { - OsmNode n; - - do { - const pfxml::tag& cur = xml->get(); - if (xml->level() == 2 || xml->level() == 0) { - if (keepNode(n, *nodes, *multNodes, nodeRels, bBoxNodes, filter, fl)) - return n; - // block ended - if (strcmp(cur.name, "node")) return OsmNode(); - - n.attrs.clear(); - n.lat = util::atof(cur.attrs.find("lat")->second, 7); - n.lng = util::atof(cur.attrs.find("lon")->second, 7); - n.id = util::atoul(cur.attrs.find("id")->second); - } + OsmNode n; + + do { + const pfxml::tag& cur = xml->get(); + if (xml->level() == 2 || xml->level() == 0) { + if (keepNode(n, *nodes, *multNodes, nodeRels, bBoxNodes, filter, fl)) + return n; + // block ended + if (strcmp(cur.name, "node")) return OsmNode(); + + n.attrs.clear(); + n.lat = util::atof(cur.attrs.find("lat")->second, 7); + n.lng = util::atof(cur.attrs.find("lon")->second, 7); + n.id = util::atoul(cur.attrs.find("id")->second); + } - if (xml->level() == 3 && n.id && strcmp(cur.name, "tag") == 0) { - if (keepAttrs.count(cur.attrs.find("k")->second)) - n.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; - } - } while (xml->next()); + if (xml->level() == 3 && n.id && strcmp(cur.name, "tag") == 0) { + if (keepAttrs.count(cur.attrs.find("k")->second)) + n.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; + } + } while (xml->next()); - if (keepNode(n, *nodes, *multNodes, nodeRels, bBoxNodes, filter, fl)) - return n; - return OsmNode(); + if (keepNode(n, *nodes, *multNodes, nodeRels, bBoxNodes, filter, fl)) + return n; + return OsmNode(); } // _____________________________________________________________________________ @@ -712,16 +1403,16 @@ bool OsmBuilder::keepNode(const OsmNode& n, const NIdMap& nodes, const NIdMultMap& multNodes, const RelMap& nodeRels, const OsmIdSet& bBoxNodes, const OsmFilter& filter, const FlatRels& fl) const { - if (n.id && - (nodes.count(n.id) || multNodes.count(n.id) || - relKeep(n.id, nodeRels, fl) || filter.keep(n.attrs, OsmFilter::NODE)) && - (nodes.count(n.id) || bBoxNodes.has(n.id)) && - (nodes.count(n.id) || multNodes.count(n.id) || - !filter.drop(n.attrs, OsmFilter::NODE))) { - return true; - } + if (n.id && + (nodes.count(n.id) || multNodes.count(n.id) || + relKeep(n.id, nodeRels, fl) || filter.keep(n.attrs, OsmFilter::NODE)) && + (nodes.count(n.id) || bBoxNodes.has(n.id)) && + (nodes.count(n.id) || multNodes.count(n.id) || + !filter.drop(n.attrs, OsmFilter::NODE))) { + return true; + } - return false; + return false; } // _____________________________________________________________________________ @@ -730,20 +1421,20 @@ void OsmBuilder::readWriteNds(pfxml::file* i, util::xml::XmlWriter* o, const OsmIdSet& bBoxNds, NIdMap* nds, const AttrKeySet& keepAttrs, const FlatRels& f) const { - OsmNode nd; - NIdMultMap empt; - while ( - (nd = nextNode(i, nds, &empt, nRels, filter, bBoxNds, keepAttrs, f)).id) { - (*nds)[nd.id] = 0; - o->openTag("node", {{"id", std::to_string(nd.id)}, - {"lat", std::to_string(nd.lat)}, - {"lon", std::to_string(nd.lng)}}); - for (const auto& kv : nd.attrs) { - o->openTag("tag", {{"k", kv.first}, {"v", pfxml::file::decode(kv.second)}}); - o->closeTag(); - } - o->closeTag(); - } + OsmNode nd; + NIdMultMap empt; + while ( + (nd = nextNode(i, nds, &empt, nRels, filter, bBoxNds, keepAttrs, f)).id) { + (*nds)[nd.id] = 0; + o->openTag("node", {{"id", std::to_string(nd.id)}, + {"lat", std::to_string(nd.lat)}, + {"lon", std::to_string(nd.lng)}}); + for (const auto& kv : nd.attrs) { + o->openTag("tag", {{"k", kv.first}, {"v", pfxml::file::decode(kv.second)}}); + o->closeTag(); + } + o->closeTag(); + } } // _____________________________________________________________________________ @@ -753,123 +1444,127 @@ void OsmBuilder::readNodes(pfxml::file* xml, Graph* g, const RelLst& rels, NIdMultMap* multNodes, NodeSet* orphanStations, const AttrKeySet& keepAttrs, const FlatRels& fl, const OsmReadOpts& opts) const { - StAttrGroups attrGroups; - - OsmNode nd; - while ((nd = nextNode(xml, nodes, multNodes, nodeRels, filter, bBoxNodes, - keepAttrs, fl)) - .id) { - Node* n = 0; - auto pos = util::geo::latLngToWebMerc(nd.lat, nd.lng); - if (nodes->count(nd.id)) { - n = (*nodes)[nd.id]; - n->pl().setGeom(pos); - if (filter.station(nd.attrs)) { - auto si = getStatInfo(n, nd.id, pos, nd.attrs, &attrGroups, nodeRels, - rels, opts); - if (!si.isNull()) n->pl().setSI(si); - } else if (filter.blocker(nd.attrs)) { - n->pl().setBlocker(); - } - } else if ((*multNodes).count(nd.id)) { - for (auto* n : (*multNodes)[nd.id]) { - n->pl().setGeom(pos); - if (filter.station(nd.attrs)) { - auto si = getStatInfo(n, nd.id, pos, nd.attrs, &attrGroups, nodeRels, - rels, opts); - if (!si.isNull()) n->pl().setSI(si); - } else if (filter.blocker(nd.attrs)) { - n->pl().setBlocker(); - } - } - } else { - // these are nodes without any connected edges - if (filter.station(nd.attrs)) { - auto tmp = g->addNd(NodePL(pos)); - auto si = getStatInfo(tmp, nd.id, pos, nd.attrs, &attrGroups, nodeRels, - rels, opts); - if (!si.isNull()) tmp->pl().setSI(si); - if (tmp->pl().getSI()) { - tmp->pl().getSI()->setIsFromOsm(false); - orphanStations->insert(tmp); - } - } - } - } + StAttrGroups attrGroups; + + OsmNode nd; + while ((nd = nextNode(xml, nodes, multNodes, nodeRels, filter, bBoxNodes, + keepAttrs, fl)) + .id) { + Node* n = 0; + auto pos = util::geo::latLngToWebMerc(nd.lat, nd.lng); + if (nodes->count(nd.id)) { + n = (*nodes)[nd.id]; + n->pl().setGeom(pos); + if (filter.station(nd.attrs)) { + auto si = getStatInfo(n, nd.id, pos, nd.attrs, &attrGroups, nodeRels, + rels, opts); + if (!si.isNull()) n->pl().setSI(si); + } else if (filter.blocker(nd.attrs)) { + n->pl().setBlocker(); + } + } else if ((*multNodes).count(nd.id)) { + for (auto* n : (*multNodes)[nd.id]) { + n->pl().setGeom(pos); + if (filter.station(nd.attrs)) { + auto si = getStatInfo(n, nd.id, pos, nd.attrs, &attrGroups, nodeRels, + rels, opts); + if (!si.isNull()) n->pl().setSI(si); + } else if (filter.blocker(nd.attrs)) { + n->pl().setBlocker(); + } + } + } else { + // these are nodes without any connected edges + if (filter.station(nd.attrs)) { + auto tmp = g->addNd(NodePL(pos)); + auto si = getStatInfo(tmp, nd.id, pos, nd.attrs, &attrGroups, nodeRels, + rels, opts); + if (!si.isNull()) tmp->pl().setSI(si); + if (tmp->pl().getSI()) { + tmp->pl().getSI()->setIsFromOsm(false); + orphanStations->insert(tmp); + } + } + } + } } // _____________________________________________________________________________ OsmRel OsmBuilder::nextRel(pfxml::file* xml, const OsmFilter& filter, const AttrKeySet& keepAttrs) const { - OsmRel rel; - - do { - const pfxml::tag& cur = xml->get(); - if (xml->level() == 2 || xml->level() == 0) { - uint64_t keepFlags = 0; - uint64_t dropFlags = 0; - if (rel.id && rel.attrs.size() && - (keepFlags = filter.keep(rel.attrs, OsmFilter::REL)) && - !(dropFlags = filter.drop(rel.attrs, OsmFilter::REL))) { + OsmRel rel; + + do { + const pfxml::tag& cur = xml->get(); + if (xml->level() == 2 || xml->level() == 0) { + uint64_t keepFlags = 0; + uint64_t dropFlags = 0; + if (rel.id && !rel.attrs.empty() && + (keepFlags = filter.keep(rel.attrs, OsmFilter::REL)) && + !(dropFlags = filter.drop(rel.attrs, OsmFilter::REL))) { + rel.keepFlags = keepFlags; + rel.dropFlags = dropFlags; + return rel; + } + + // block ended + if (strcmp(cur.name, "relation") != 0) { + return OsmRel(); + } + + rel.attrs.clear(); + rel.nodes.clear(); + rel.ways.clear(); + rel.nodeRoles.clear(); + rel.wayRoles.clear(); + rel.keepFlags = 0; + rel.dropFlags = 0; + rel.id = util::atoul(cur.attrs.find("id")->second); + } + + if (xml->level() == 3 && rel.id) { + if (strcmp(cur.name, "member") == 0) { + if (strcmp(cur.attrs.find("type")->second, "node") == 0) { + osmid id = util::atoul(cur.attrs.find("ref")->second); + // TODO(patrick): no need to push IDs that have been filtered out by + // the bounding box!!!! + rel.nodes.push_back(id); + if (cur.attrs.count("role")) { + rel.nodeRoles.emplace_back(cur.attrs.find("role")->second); + } else { + rel.nodeRoles.emplace_back(""); + } + } + + if (strcmp(cur.attrs.find("type")->second, "way") == 0) { + osmid id = util::atoul(cur.attrs.find("ref")->second); + rel.ways.push_back(id); + if (cur.attrs.count("role")) { + rel.wayRoles.emplace_back(cur.attrs.find("role")->second); + } else { + rel.wayRoles.emplace_back(""); + } + } + + } else if (strcmp(cur.name, "tag") == 0) { + if (keepAttrs.count(cur.attrs.find("k")->second)) + rel.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; + } + } + } while (xml->next()); + + // dont forget last relation + uint64_t keepFlags = 0; + uint64_t dropFlags = 0; + if (rel.id && !rel.attrs.empty() && + (keepFlags = filter.keep(rel.attrs, OsmFilter::REL)) && + !(dropFlags = filter.drop(rel.attrs, OsmFilter::REL))) { rel.keepFlags = keepFlags; rel.dropFlags = dropFlags; return rel; - } - - // block ended - if (strcmp(cur.name, "relation")) return OsmRel(); - - rel.attrs.clear(); - rel.nodes.clear(); - rel.ways.clear(); - rel.nodeRoles.clear(); - rel.wayRoles.clear(); - rel.keepFlags = 0; - rel.dropFlags = 0; - rel.id = util::atoul(cur.attrs.find("id")->second); - } - - if (xml->level() == 3 && rel.id) { - if (strcmp(cur.name, "member") == 0) { - if (strcmp(cur.attrs.find("type")->second, "node") == 0) { - osmid id = util::atoul(cur.attrs.find("ref")->second); - // TODO(patrick): no need to push IDs that have been filtered out by - // the bounding box!!!! - rel.nodes.push_back(id); - if (cur.attrs.count("role")) { - rel.nodeRoles.push_back(cur.attrs.find("role")->second); - } else { - rel.nodeRoles.push_back(""); - } - } - if (strcmp(cur.attrs.find("type")->second, "way") == 0) { - osmid id = util::atoul(cur.attrs.find("ref")->second); - rel.ways.push_back(id); - if (cur.attrs.count("role")) { - rel.wayRoles.push_back(cur.attrs.find("role")->second); - } else { - rel.wayRoles.push_back(""); - } - } - } else if (strcmp(cur.name, "tag") == 0) { - if (keepAttrs.count(cur.attrs.find("k")->second)) - rel.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; - } - } - } while (xml->next()); - - // dont forget last relation - uint64_t keepFlags = 0; - uint64_t dropFlags = 0; - if (rel.id && rel.attrs.size() && - (keepFlags = filter.keep(rel.attrs, OsmFilter::REL)) && - !(dropFlags = filter.drop(rel.attrs, OsmFilter::REL))) { - rel.keepFlags = keepFlags; - rel.dropFlags = dropFlags; - return rel; - } - - return OsmRel(); + } + + return OsmRel(); } // _____________________________________________________________________________ @@ -877,59 +1572,59 @@ void OsmBuilder::readRels(pfxml::file* xml, RelLst* rels, RelMap* nodeRels, RelMap* wayRels, const OsmFilter& filter, const AttrKeySet& keepAttrs, Restrictions* rests) const { - OsmRel rel; - while ((rel = nextRel(xml, filter, keepAttrs)).id) { - rels->rels.push_back(rel.attrs); - if (rel.keepFlags & osm::REL_NO_DOWN) { - rels->flat.insert(rels->rels.size() - 1); - } - for (osmid id : rel.nodes) (*nodeRels)[id].push_back(rels->rels.size() - 1); - for (osmid id : rel.ways) (*wayRels)[id].push_back(rels->rels.size() - 1); - - // TODO(patrick): this is not needed for the filtering - remove it here! - readRestr(rel, rests, filter); - } + OsmRel rel; + while ((rel = nextRel(xml, filter, keepAttrs)).id) { + rels->rels.push_back(rel.attrs); + if (rel.keepFlags & osm::REL_NO_DOWN) { + rels->flat.insert(rels->rels.size() - 1); + } + for (osmid id : rel.nodes) (*nodeRels)[id].push_back(rels->rels.size() - 1); + for (osmid id : rel.ways) (*wayRels)[id].push_back(rels->rels.size() - 1); + + // TODO(patrick): this is not needed for the filtering - remove it here! + readRestr(rel, rests, filter); + } } // _____________________________________________________________________________ void OsmBuilder::readRestr(const OsmRel& rel, Restrictions* rests, const OsmFilter& filter) const { - if (!rel.attrs.count("type")) return; - if (rel.attrs.find("type")->second != "restriction") return; + if (!rel.attrs.count("type")) return; + if (rel.attrs.find("type")->second != "restriction") return; - bool pos = filter.posRestr(rel.attrs); - bool neg = filter.negRestr(rel.attrs); + bool pos = filter.posRestr(rel.attrs); + bool neg = filter.negRestr(rel.attrs); - if (!pos && !neg) return; + if (!pos && !neg) return; - osmid from = 0; - osmid to = 0; - osmid via = 0; + osmid from = 0; + osmid to = 0; + osmid via = 0; - for (size_t i = 0; i < rel.ways.size(); i++) { - if (rel.wayRoles[i] == "from") { - if (from) return; // only one from member supported - from = rel.ways[i]; - } - if (rel.wayRoles[i] == "to") { - if (to) return; // only one to member supported - to = rel.ways[i]; + for (size_t i = 0; i < rel.ways.size(); i++) { + if (rel.wayRoles[i] == "from") { + if (from) return; // only one from member supported + from = rel.ways[i]; + } + if (rel.wayRoles[i] == "to") { + if (to) return; // only one to member supported + to = rel.ways[i]; + } } - } - for (size_t i = 0; i < rel.nodes.size(); i++) { - if (rel.nodeRoles[i] == "via") { - via = rel.nodes[i]; - break; + for (size_t i = 0; i < rel.nodes.size(); i++) { + if (rel.nodeRoles[i] == "via") { + via = rel.nodes[i]; + break; + } } - } - if (from && to && via) { - if (pos) - rests->pos[via].push_back(Restriction{from, to}); - else if (neg) - rests->neg[via].push_back(Restriction{from, to}); - } + if (from && to && via) { + if (pos) + rests->pos[via].push_back(Restriction{from, to}); + else if (neg) + rests->neg[via].push_back(Restriction{from, to}); + } } // _____________________________________________________________________________ @@ -938,49 +1633,49 @@ std::string OsmBuilder::getAttrByFirstMatch(const DeepAttrLst& rule, osmid id, const RelMap& entRels, const RelLst& rels, const Normalizer& norm) const { - std::string ret; - for (const auto& s : rule) { - ret = norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); - if (!ret.empty()) return ret; - } + std::string ret; + for (const auto& s : rule) { + ret = norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); + if (!ret.empty()) return ret; + } - return ret; + return ret; } // _____________________________________________________________________________ std::vector OsmBuilder::getAttrMatchRanked( - const DeepAttrLst& rule, osmid id, const AttrMap& attrs, - const RelMap& entRels, const RelLst& rels, const Normalizer& norm) const { - std::vector ret; - for (const auto& s : rule) { - std::string tmp = - norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); - if (!tmp.empty()) ret.push_back(tmp); - } - - return ret; + const DeepAttrLst& rule, osmid id, const AttrMap& attrs, + const RelMap& entRels, const RelLst& rels, const Normalizer& norm) const { + std::vector ret; + for (const auto& s : rule) { + std::string tmp = + norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); + if (!tmp.empty()) ret.push_back(tmp); + } + + return ret; } // _____________________________________________________________________________ std::string OsmBuilder::getAttr(const DeepAttrRule& s, osmid id, const AttrMap& attrs, const RelMap& entRels, const RelLst& rels) const { - if (s.relRule.kv.first.empty()) { - if (attrs.find(s.attr) != attrs.end()) { - return attrs.find(s.attr)->second; - } - } else { - if (entRels.count(id)) { - for (const auto& relId : entRels.find(id)->second) { - if (OsmFilter::contained(rels.rels[relId], s.relRule.kv)) { - if (rels.rels[relId].count(s.attr)) { - return rels.rels[relId].find(s.attr)->second; - } - } - } - } - } - return ""; + if (s.relRule.kv.first.empty()) { + if (attrs.find(s.attr) != attrs.end()) { + return attrs.find(s.attr)->second; + } + } else { + if (entRels.count(id)) { + for (const auto& relId : entRels.find(id)->second) { + if (OsmFilter::contained(rels.rels[relId], s.relRule.kv)) { + if (rels.rels[relId].count(s.attr)) { + return rels.rels[relId].find(s.attr)->second; + } + } + } + } + } + return ""; } // _____________________________________________________________________________ @@ -990,297 +1685,297 @@ Nullable OsmBuilder::getStatInfo(Node* node, osmid nid, const RelMap& nodeRels, const RelLst& rels, const OsmReadOpts& ops) const { - std::string platform; - std::vector names; + std::string platform; + std::vector names; - names = getAttrMatchRanked(ops.statAttrRules.nameRule, nid, m, nodeRels, rels, - ops.statNormzer); - platform = getAttrByFirstMatch(ops.statAttrRules.platformRule, nid, m, - nodeRels, rels, ops.trackNormzer); + names = getAttrMatchRanked(ops.statAttrRules.nameRule, nid, m, nodeRels, rels, + ops.statNormzer); + platform = getAttrByFirstMatch(ops.statAttrRules.platformRule, nid, m, + nodeRels, rels, ops.trackNormzer); - if (!names.size()) return Nullable(); + if (!names.size()) return Nullable(); - auto ret = StatInfo(names[0], platform, true); + auto ret = StatInfo(names[0], platform, true); #ifdef PFAEDLE_STATION_IDS - ret.setId(getAttrByFirstMatch(ops.statAttrRules.idRule, nid, m, nodeRels, - rels, ops.idNormzer)); + ret.setId(getAttrByFirstMatch(ops.statAttrRules.idRule, nid, m, nodeRels, + rels, ops.idNormzer)); #endif - for (size_t i = 1; i < names.size(); i++) ret.addAltName(names[i]); + for (size_t i = 1; i < names.size(); i++) ret.addAltName(names[i]); - bool groupFound = false; + bool groupFound = false; - for (const auto& rule : ops.statGroupNAttrRules) { - if (groupFound) break; - std::string ruleVal = getAttr(rule.attr, nid, m, nodeRels, rels); - if (!ruleVal.empty()) { - // check if a matching group exists - for (auto* group : (*groups)[rule.attr.attr][ruleVal]) { + for (const auto& rule : ops.statGroupNAttrRules) { if (groupFound) break; - for (const auto* member : group->getNodes()) { - if (webMercMeterDist(*member->pl().getGeom(), pos) <= rule.maxDist) { - // ok, group is matching - groupFound = true; - if (node) group->addNode(node); - ret.setGroup(group); - break; - } + std::string ruleVal = getAttr(rule.attr, nid, m, nodeRels, rels); + if (!ruleVal.empty()) { + // check if a matching group exists + for (auto* group : (*groups)[rule.attr.attr][ruleVal]) { + if (groupFound) break; + for (const auto* member : group->getNodes()) { + if (webMercMeterDist(*member->pl().getGeom(), pos) <= rule.maxDist) { + // ok, group is matching + groupFound = true; + if (node) group->addNode(node); + ret.setGroup(group); + break; + } + } + } } - } } - } - if (!groupFound) { - for (const auto& rule : ops.statGroupNAttrRules) { - std::string ruleVal = getAttr(rule.attr, nid, m, nodeRels, rels); - if (!ruleVal.empty()) { - // add new group - StatGroup* g = new StatGroup(); - if (node) g->addNode(node); - ret.setGroup(g); - (*groups)[rule.attr.attr][ruleVal].push_back(g); - break; - } - } - } - - return ret; + if (!groupFound) { + for (const auto& rule : ops.statGroupNAttrRules) { + std::string ruleVal = getAttr(rule.attr, nid, m, nodeRels, rels); + if (!ruleVal.empty()) { + // add new group + StatGroup* g = new StatGroup(); + if (node) g->addNode(node); + ret.setGroup(g); + (*groups)[rule.attr.attr][ruleVal].push_back(g); + break; + } + } + } + + return ret; } // _____________________________________________________________________________ double OsmBuilder::dist(const Node* a, const Node* b) { - return webMercMeterDist(*a->pl().getGeom(), *b->pl().getGeom()); + return webMercMeterDist(*a->pl().getGeom(), *b->pl().getGeom()); } // _____________________________________________________________________________ double OsmBuilder::webMercDist(const Node* a, const Node* b) { - return webMercMeterDist(*a->pl().getGeom(), *b->pl().getGeom()); + return webMercMeterDist(*a->pl().getGeom(), *b->pl().getGeom()); } // _____________________________________________________________________________ void OsmBuilder::writeGeoms(Graph* g) { - for (auto* n : *g->getNds()) { - for (auto* e : n->getAdjListOut()) { - e->pl().addPoint(*e->getFrom()->pl().getGeom()); - e->pl().setLength(dist(e->getFrom(), e->getTo())); - e->pl().addPoint(*e->getTo()->pl().getGeom()); + for (auto* n : *g->getNds()) { + for (auto* e : n->getAdjListOut()) { + e->pl().addPoint(*e->getFrom()->pl().getGeom()); + e->pl().setLength(dist(e->getFrom(), e->getTo())); + e->pl().addPoint(*e->getTo()->pl().getGeom()); + } } - } } // _____________________________________________________________________________ void OsmBuilder::fixGaps(Graph* g, NodeGrid* ng) { - double METER = 1; - for (auto* n : *g->getNds()) { - if (n->getInDeg() + n->getOutDeg() == 1) { - // get all nodes in distance - std::set ret; - double distor = util::geo::webMercDistFactor(*n->pl().getGeom()); - ng->get(util::geo::pad(util::geo::getBoundingBox(*n->pl().getGeom()), - METER / distor), - &ret); - for (auto* nb : ret) { - if (nb != n && (nb->getInDeg() + nb->getOutDeg()) == 1 && - webMercDist(nb, n) <= METER / distor) { - // special case: both node are non-stations, move - // the end point nb to n and delete nb - if (!nb->pl().getSI() && !n->pl().getSI()) { - Node* otherN; - if (nb->getOutDeg()) - otherN = (*nb->getAdjListOut().begin())->getOtherNd(nb); - else - otherN = (*nb->getAdjListIn().begin())->getOtherNd(nb); - LINE l; - l.push_back(*otherN->pl().getGeom()); - l.push_back(*n->pl().getGeom()); - - Edge* e; - if (nb->getOutDeg()) - e = g->addEdg(otherN, n, (*nb->getAdjListOut().begin())->pl()); - else - e = g->addEdg(otherN, n, (*nb->getAdjListIn().begin())->pl()); - if (e) { - *e->pl().getGeom() = l; - g->delNd(nb); - ng->remove(nb); - } - } else { - // if one of the nodes is a station, just add an edge between them - if (nb->getOutDeg()) - g->addEdg(n, nb, (*nb->getAdjListOut().begin())->pl()); - else - g->addEdg(n, nb, (*nb->getAdjListIn().begin())->pl()); - } - } - } - } - } + double METER = 1; + for (auto* n : *g->getNds()) { + if (n->getInDeg() + n->getOutDeg() == 1) { + // get all nodes in distance + std::set ret; + double distor = util::geo::webMercDistFactor(*n->pl().getGeom()); + ng->get(util::geo::pad(util::geo::getBoundingBox(*n->pl().getGeom()), + METER / distor), + &ret); + for (auto* nb : ret) { + if (nb != n && (nb->getInDeg() + nb->getOutDeg()) == 1 && + webMercDist(nb, n) <= METER / distor) { + // special case: both node are non-stations, move + // the end point nb to n and delete nb + if (!nb->pl().getSI() && !n->pl().getSI()) { + Node* otherN; + if (nb->getOutDeg()) + otherN = (*nb->getAdjListOut().begin())->getOtherNd(nb); + else + otherN = (*nb->getAdjListIn().begin())->getOtherNd(nb); + LINE l; + l.push_back(*otherN->pl().getGeom()); + l.push_back(*n->pl().getGeom()); + + Edge* e; + if (nb->getOutDeg()) + e = g->addEdg(otherN, n, (*nb->getAdjListOut().begin())->pl()); + else + e = g->addEdg(otherN, n, (*nb->getAdjListIn().begin())->pl()); + if (e) { + *e->pl().getGeom() = l; + g->delNd(nb); + ng->remove(nb); + } + } else { + // if one of the nodes is a station, just add an edge between them + if (nb->getOutDeg()) + g->addEdg(n, nb, (*nb->getAdjListOut().begin())->pl()); + else + g->addEdg(n, nb, (*nb->getAdjListIn().begin())->pl()); + } + } + } + } + } } // _____________________________________________________________________________ EdgeGrid OsmBuilder::buildEdgeIdx(Graph* g, size_t size, const BOX& webMercBox) { - EdgeGrid ret(size, size, webMercBox, false); - for (auto* n : *g->getNds()) { - for (auto* e : n->getAdjListOut()) { - assert(e->pl().getGeom()); - ret.add(*e->pl().getGeom(), e); - } - } - return ret; + EdgeGrid ret(size, size, webMercBox, false); + for (auto* n : *g->getNds()) { + for (auto* e : n->getAdjListOut()) { + assert(e->pl().getGeom()); + ret.add(*e->pl().getGeom(), e); + } + } + return ret; } // _____________________________________________________________________________ NodeGrid OsmBuilder::buildNodeIdx(Graph* g, size_t size, const BOX& webMercBox, bool which) { - NodeGrid ret(size, size, webMercBox, false); - for (auto* n : *g->getNds()) { - if (!which && n->getInDeg() + n->getOutDeg() == 1) - ret.add(*n->pl().getGeom(), n); - else if (which && n->pl().getSI()) - ret.add(*n->pl().getGeom(), n); - } - return ret; + NodeGrid ret(size, size, webMercBox, false); + for (auto* n : *g->getNds()) { + if (!which && n->getInDeg() + n->getOutDeg() == 1) + ret.add(*n->pl().getGeom(), n); + else if (which && n->pl().getSI()) + ret.add(*n->pl().getGeom(), n); + } + return ret; } // _____________________________________________________________________________ Node* OsmBuilder::depthSearch(const Edge* e, const StatInfo* si, const POINT& p, double maxD, int maxFullTurns, double minAngle, const SearchFunc& sfunc) { - // shortcuts - double dFrom = webMercMeterDist(*e->getFrom()->pl().getGeom(), p); - double dTo = webMercMeterDist(*e->getTo()->pl().getGeom(), p); - if (dFrom > maxD && dTo > maxD) return 0; - - if (dFrom <= maxD && sfunc(e->getFrom(), si)) return e->getFrom(); - if (dTo <= maxD && sfunc(e->getTo(), si)) return e->getTo(); - - NodeCandPQ pq; - NodeSet closed; - pq.push(NodeCand{dFrom, e->getFrom(), e, 0}); - if (e->getFrom() != e->getTo()) pq.push(NodeCand{dTo, e->getTo(), e, 0}); - - while (!pq.empty()) { - auto cur = pq.top(); - pq.pop(); - if (closed.count(cur.node)) continue; - closed.insert(cur.node); - - for (size_t i = 0; i < cur.node->getInDeg() + cur.node->getOutDeg(); i++) { - trgraph::Node* cand; - trgraph::Edge* edg; - - if (i < cur.node->getInDeg()) { - edg = cur.node->getAdjListIn()[i]; - cand = edg->getFrom(); - } else { - edg = cur.node->getAdjListOut()[i - cur.node->getInDeg()]; - cand = edg->getTo(); - } - - if (cand == cur.node) continue; // dont follow self edges - - int fullTurn = 0; - - if (cur.fromEdge && - cur.node->getInDeg() + cur.node->getOutDeg() > - 2) { // only intersection angles - const POINT& toP = *cand->pl().getGeom(); - const POINT& fromP = - *cur.fromEdge->getOtherNd(cur.node)->pl().getGeom(); - const POINT& nodeP = *cur.node->pl().getGeom(); - - if (util::geo::innerProd(nodeP, fromP, toP) < minAngle) fullTurn = 1; - } - - if ((maxFullTurns < 0 || cur.fullTurns + fullTurn <= maxFullTurns) && - cur.dist + edg->pl().getLength() < maxD && !closed.count(cand)) { - if (sfunc(cand, si)) { - return cand; - } else { - pq.push(NodeCand{cur.dist + edg->pl().getLength(), cand, edg, - cur.fullTurns + fullTurn}); + // shortcuts + double dFrom = webMercMeterDist(*e->getFrom()->pl().getGeom(), p); + double dTo = webMercMeterDist(*e->getTo()->pl().getGeom(), p); + if (dFrom > maxD && dTo > maxD) return 0; + + if (dFrom <= maxD && sfunc(e->getFrom(), si)) return e->getFrom(); + if (dTo <= maxD && sfunc(e->getTo(), si)) return e->getTo(); + + NodeCandPQ pq; + NodeSet closed; + pq.push(NodeCand{dFrom, e->getFrom(), e, 0}); + if (e->getFrom() != e->getTo()) pq.push(NodeCand{dTo, e->getTo(), e, 0}); + + while (!pq.empty()) { + auto cur = pq.top(); + pq.pop(); + if (closed.count(cur.node)) continue; + closed.insert(cur.node); + + for (size_t i = 0; i < cur.node->getInDeg() + cur.node->getOutDeg(); i++) { + trgraph::Node* cand; + trgraph::Edge* edg; + + if (i < cur.node->getInDeg()) { + edg = cur.node->getAdjListIn()[i]; + cand = edg->getFrom(); + } else { + edg = cur.node->getAdjListOut()[i - cur.node->getInDeg()]; + cand = edg->getTo(); + } + + if (cand == cur.node) continue; // dont follow self edges + + int fullTurn = 0; + + if (cur.fromEdge && + cur.node->getInDeg() + cur.node->getOutDeg() > + 2) { // only intersection angles + const POINT& toP = *cand->pl().getGeom(); + const POINT& fromP = + *cur.fromEdge->getOtherNd(cur.node)->pl().getGeom(); + const POINT& nodeP = *cur.node->pl().getGeom(); + + if (util::geo::innerProd(nodeP, fromP, toP) < minAngle) fullTurn = 1; + } + + if ((maxFullTurns < 0 || cur.fullTurns + fullTurn <= maxFullTurns) && + cur.dist + edg->pl().getLength() < maxD && !closed.count(cand)) { + if (sfunc(cand, si)) { + return cand; + } else { + pq.push(NodeCand{cur.dist + edg->pl().getLength(), cand, edg, + cur.fullTurns + fullTurn}); + } + } } - } } - } - return 0; + return 0; } // _____________________________________________________________________________ bool OsmBuilder::isBlocked(const Edge* e, const StatInfo* si, const POINT& p, double maxD, int maxFullTurns, double minAngle) { - return depthSearch(e, si, p, maxD, maxFullTurns, minAngle, BlockSearch()); + return depthSearch(e, si, p, maxD, maxFullTurns, minAngle, BlockSearch()); } // _____________________________________________________________________________ Node* OsmBuilder::eqStatReach(const Edge* e, const StatInfo* si, const POINT& p, double maxD, int maxFullTurns, double minAngle, bool orphanSnap) { - return depthSearch(e, si, p, maxD, maxFullTurns, minAngle, - EqSearch(orphanSnap)); + return depthSearch(e, si, p, maxD, maxFullTurns, minAngle, + EqSearch(orphanSnap)); } // _____________________________________________________________________________ void OsmBuilder::getEdgCands(const POINT& geom, EdgeCandPQ* ret, EdgeGrid* eg, double d) { - double distor = util::geo::webMercDistFactor(geom); - std::set neighs; - BOX box = util::geo::pad(util::geo::getBoundingBox(geom), d / distor); - eg->get(box, &neighs); + double distor = util::geo::webMercDistFactor(geom); + std::set neighs; + BOX box = util::geo::pad(util::geo::getBoundingBox(geom), d / distor); + eg->get(box, &neighs); - for (auto* e : neighs) { - double dist = util::geo::distToSegment(*e->getFrom()->pl().getGeom(), - *e->getTo()->pl().getGeom(), geom); + for (auto* e : neighs) { + double dist = util::geo::distToSegment(*e->getFrom()->pl().getGeom(), + *e->getTo()->pl().getGeom(), geom); - if (dist * distor <= d) { - ret->push(EdgeCand(-dist, e)); + if (dist * distor <= d) { + ret->push(EdgeCand(-dist, e)); + } } - } } // _____________________________________________________________________________ std::set OsmBuilder::getMatchingNds(const NodePL& s, NodeGrid* ng, double d) { - std::set ret; - double distor = util::geo::webMercDistFactor(*s.getGeom()); - std::set neighs; - BOX box = util::geo::pad(util::geo::getBoundingBox(*s.getGeom()), d / distor); - ng->get(box, &neighs); - - for (auto* n : neighs) { - if (n->pl().getSI() && n->pl().getSI()->simi(s.getSI()) > 0.5) { - double dist = webMercMeterDist(*n->pl().getGeom(), *s.getGeom()); - if (dist < d) ret.insert(n); + std::set ret; + double distor = util::geo::webMercDistFactor(*s.getGeom()); + std::set neighs; + BOX box = util::geo::pad(util::geo::getBoundingBox(*s.getGeom()), d / distor); + ng->get(box, &neighs); + + for (auto* n : neighs) { + if (n->pl().getSI() && n->pl().getSI()->simi(s.getSI()) > 0.5) { + double dist = webMercMeterDist(*n->pl().getGeom(), *s.getGeom()); + if (dist < d) ret.insert(n); + } } - } - return ret; + return ret; } // _____________________________________________________________________________ Node* OsmBuilder::getMatchingNd(const NodePL& s, NodeGrid* ng, double d) { - double distor = util::geo::webMercDistFactor(*s.getGeom()); - std::set neighs; - BOX box = util::geo::pad(util::geo::getBoundingBox(*s.getGeom()), d / distor); - ng->get(box, &neighs); - - Node* ret = 0; - double bestD = std::numeric_limits::max(); - - for (auto* n : neighs) { - if (n->pl().getSI() && n->pl().getSI()->simi(s.getSI()) > 0.5) { - double dist = webMercMeterDist(*n->pl().getGeom(), *s.getGeom()); - if (dist < d && dist < bestD) { - bestD = dist; - ret = n; - } + double distor = util::geo::webMercDistFactor(*s.getGeom()); + std::set neighs; + BOX box = util::geo::pad(util::geo::getBoundingBox(*s.getGeom()), d / distor); + ng->get(box, &neighs); + + Node* ret = 0; + double bestD = std::numeric_limits::max(); + + for (auto* n : neighs) { + if (n->pl().getSI() && n->pl().getSI()->simi(s.getSI()) > 0.5) { + double dist = webMercMeterDist(*n->pl().getGeom(), *s.getGeom()); + if (dist < d && dist < bestD) { + bestD = dist; + ret = n; + } + } } - } - return ret; + return ret; } // _____________________________________________________________________________ @@ -1288,547 +1983,547 @@ std::set OsmBuilder::snapStation(Graph* g, NodePL* s, EdgeGrid* eg, NodeGrid* sng, const OsmReadOpts& opts, Restrictor* restor, bool surrHeur, bool orphSnap, double d) { - assert(s->getSI()); - std::set ret; + assert(s->getSI()); + std::set ret; - EdgeCandPQ pq; + EdgeCandPQ pq; - getEdgCands(*s->getGeom(), &pq, eg, d); + getEdgCands(*s->getGeom(), &pq, eg, d); - if (pq.empty() && surrHeur) { - // no station found in the first round, try again with the nearest - // surrounding station with matching name - const Node* best = getMatchingNd(*s, sng, opts.maxSnapFallbackHeurDistance); - if (best) { - getEdgCands(*best->pl().getGeom(), &pq, eg, d); - } else { - // if still no luck, get edge cands in fallback snap distance - getEdgCands(*s->getGeom(), &pq, eg, opts.maxSnapFallbackHeurDistance); - } - } - - while (!pq.empty()) { - auto* e = pq.top().second; - pq.pop(); - auto geom = - util::geo::projectOn(*e->getFrom()->pl().getGeom(), *s->getGeom(), - *e->getTo()->pl().getGeom()); - - Node* eq = 0; - if (!(eq = eqStatReach(e, s->getSI(), geom, 2 * d, 0, - opts.maxAngleSnapReach, orphSnap))) { - if (e->pl().lvl() > opts.maxSnapLevel) continue; - if (isBlocked(e, s->getSI(), geom, opts.maxBlockDistance, 0, - opts.maxAngleSnapReach)) { - continue; - } - - // if the projected position is near (< 2 meters) the end point of this - // way and the endpoint is not already a station, place the station there. - if (!e->getFrom()->pl().getSI() && - webMercMeterDist(geom, *e->getFrom()->pl().getGeom()) < 2) { - e->getFrom()->pl().setSI(*s->getSI()); - if (s->getSI()->getGroup()) - s->getSI()->getGroup()->addNode(e->getFrom()); - ret.insert(e->getFrom()); - } else if (!e->getTo()->pl().getSI() && - webMercMeterDist(geom, *e->getTo()->pl().getGeom()) < 2) { - e->getTo()->pl().setSI(*s->getSI()); - if (s->getSI()->getGroup()) s->getSI()->getGroup()->addNode(e->getTo()); - ret.insert(e->getTo()); - } else { - s->setGeom(geom); - Node* n = g->addNd(*s); - if (n->pl().getSI()->getGroup()) - n->pl().getSI()->getGroup()->addNode(n); - sng->add(geom, n); - - auto ne = g->addEdg(e->getFrom(), n, e->pl()); - ne->pl().setLength(webMercDist(n, e->getFrom())); - LINE l; - l.push_back(*e->getFrom()->pl().getGeom()); - l.push_back(*n->pl().getGeom()); - *ne->pl().getGeom() = l; - eg->add(l, ne); - - auto nf = g->addEdg(n, e->getTo(), e->pl()); - nf->pl().setLength(webMercDist(n, e->getTo())); - LINE ll; - ll.push_back(*n->pl().getGeom()); - ll.push_back(*e->getTo()->pl().getGeom()); - *nf->pl().getGeom() = ll; - eg->add(l, nf); - - // replace edge in restrictor - restor->replaceEdge(e, ne, nf); - - g->delEdg(e->getFrom(), e->getTo()); - eg->remove(e); - ret.insert(n); - } - } else { - // if the snapped station is very near to the original OSM station - // write additional info from this snap station to the equivalent stat - if (webMercMeterDist(*s->getGeom(), *eq->pl().getGeom()) < - opts.maxOsmStationDistance) { - if (eq->pl().getSI()->getTrack().empty()) - eq->pl().getSI()->setTrack(s->getSI()->getTrack()); - } - ret.insert(eq); - } - } - - return ret; + if (pq.empty() && surrHeur) { + // no station found in the first round, try again with the nearest + // surrounding station with matching name + const Node* best = getMatchingNd(*s, sng, opts.maxSnapFallbackHeurDistance); + if (best) { + getEdgCands(*best->pl().getGeom(), &pq, eg, d); + } else { + // if still no luck, get edge cands in fallback snap distance + getEdgCands(*s->getGeom(), &pq, eg, opts.maxSnapFallbackHeurDistance); + } + } + + while (!pq.empty()) { + auto* e = pq.top().second; + pq.pop(); + auto geom = + util::geo::projectOn(*e->getFrom()->pl().getGeom(), *s->getGeom(), + *e->getTo()->pl().getGeom()); + + Node* eq = 0; + if (!(eq = eqStatReach(e, s->getSI(), geom, 2 * d, 0, + opts.maxAngleSnapReach, orphSnap))) { + if (e->pl().lvl() > opts.maxSnapLevel) continue; + if (isBlocked(e, s->getSI(), geom, opts.maxBlockDistance, 0, + opts.maxAngleSnapReach)) { + continue; + } + + // if the projected position is near (< 2 meters) the end point of this + // way and the endpoint is not already a station, place the station there. + if (!e->getFrom()->pl().getSI() && + webMercMeterDist(geom, *e->getFrom()->pl().getGeom()) < 2) { + e->getFrom()->pl().setSI(*s->getSI()); + if (s->getSI()->getGroup()) + s->getSI()->getGroup()->addNode(e->getFrom()); + ret.insert(e->getFrom()); + } else if (!e->getTo()->pl().getSI() && + webMercMeterDist(geom, *e->getTo()->pl().getGeom()) < 2) { + e->getTo()->pl().setSI(*s->getSI()); + if (s->getSI()->getGroup()) s->getSI()->getGroup()->addNode(e->getTo()); + ret.insert(e->getTo()); + } else { + s->setGeom(geom); + Node* n = g->addNd(*s); + if (n->pl().getSI()->getGroup()) + n->pl().getSI()->getGroup()->addNode(n); + sng->add(geom, n); + + auto ne = g->addEdg(e->getFrom(), n, e->pl()); + ne->pl().setLength(webMercDist(n, e->getFrom())); + LINE l; + l.push_back(*e->getFrom()->pl().getGeom()); + l.push_back(*n->pl().getGeom()); + *ne->pl().getGeom() = l; + eg->add(l, ne); + + auto nf = g->addEdg(n, e->getTo(), e->pl()); + nf->pl().setLength(webMercDist(n, e->getTo())); + LINE ll; + ll.push_back(*n->pl().getGeom()); + ll.push_back(*e->getTo()->pl().getGeom()); + *nf->pl().getGeom() = ll; + eg->add(l, nf); + + // replace edge in restrictor + restor->replaceEdge(e, ne, nf); + + g->delEdg(e->getFrom(), e->getTo()); + eg->remove(e); + ret.insert(n); + } + } else { + // if the snapped station is very near to the original OSM station + // write additional info from this snap station to the equivalent stat + if (webMercMeterDist(*s->getGeom(), *eq->pl().getGeom()) < + opts.maxOsmStationDistance) { + if (eq->pl().getSI()->getTrack().empty()) + eq->pl().getSI()->setTrack(s->getSI()->getTrack()); + } + ret.insert(eq); + } + } + + return ret; } // _____________________________________________________________________________ StatGroup* OsmBuilder::groupStats(const NodeSet& s) { - if (!s.size()) return 0; - // reference group - StatGroup* ret = new StatGroup(); - bool used = false; - - for (auto* n : s) { - if (!n->pl().getSI()) continue; - used = true; - if (n->pl().getSI()->getGroup()) { - // this node is already in a group - merge this group with this one - ret->merge(n->pl().getSI()->getGroup()); - } else { - ret->addNode(n); - n->pl().getSI()->setGroup(ret); + if (!s.size()) return 0; + // reference group + StatGroup* ret = new StatGroup(); + bool used = false; + + for (auto* n : s) { + if (!n->pl().getSI()) continue; + used = true; + if (n->pl().getSI()->getGroup()) { + // this node is already in a group - merge this group with this one + ret->merge(n->pl().getSI()->getGroup()); + } else { + ret->addNode(n); + n->pl().getSI()->setGroup(ret); + } } - } - if (!used) { - delete ret; - return 0; - } + if (!used) { + delete ret; + return 0; + } - return ret; + return ret; } // _____________________________________________________________________________ std::vector OsmBuilder::getLines( - const std::vector& edgeRels, const RelLst& rels, - const OsmReadOpts& ops) { - std::vector ret; - for (size_t relId : edgeRels) { - TransitEdgeLine* elp = 0; - - if (_relLines.count(relId)) { - elp = _relLines[relId]; - } else { - TransitEdgeLine el; - - bool found = false; - for (const auto& r : ops.relLinerules.sNameRule) { - for (const auto& relAttr : rels.rels[relId]) { - if (relAttr.first == r) { - el.shortName = ops.lineNormzer(pfxml::file::decode(relAttr.second)); - if (!el.shortName.empty()) found = true; - } - } - if (found) break; - } - - found = false; - for (const auto& r : ops.relLinerules.fromNameRule) { - for (const auto& relAttr : rels.rels[relId]) { - if (relAttr.first == r) { - el.fromStr = ops.statNormzer(pfxml::file::decode(relAttr.second)); - if (!el.fromStr.empty()) found = true; - } - } - if (found) break; - } - - found = false; - for (const auto& r : ops.relLinerules.toNameRule) { - for (const auto& relAttr : rels.rels[relId]) { - if (relAttr.first == r) { - el.toStr = ops.statNormzer(pfxml::file::decode(relAttr.second)); - if (!el.toStr.empty()) found = true; - } - } - if (found) break; - } - - if (!el.shortName.size() && !el.fromStr.size() && !el.toStr.size()) - continue; - - if (_lines.count(el)) { - elp = _lines[el]; - _relLines[relId] = elp; - } else { - elp = new TransitEdgeLine(el); - _lines[el] = elp; - _relLines[relId] = elp; - } - } - ret.push_back(elp); - } - - return ret; + const std::vector& edgeRels, const RelLst& rels, + const OsmReadOpts& ops) { + std::vector ret; + for (size_t relId : edgeRels) { + TransitEdgeLine* elp = 0; + + if (_relLines.count(relId)) { + elp = _relLines[relId]; + } else { + TransitEdgeLine el; + + bool found = false; + for (const auto& r : ops.relLinerules.sNameRule) { + for (const auto& relAttr : rels.rels[relId]) { + if (relAttr.first == r) { + el.shortName = ops.lineNormzer(pfxml::file::decode(relAttr.second)); + if (!el.shortName.empty()) found = true; + } + } + if (found) break; + } + + found = false; + for (const auto& r : ops.relLinerules.fromNameRule) { + for (const auto& relAttr : rels.rels[relId]) { + if (relAttr.first == r) { + el.fromStr = ops.statNormzer(pfxml::file::decode(relAttr.second)); + if (!el.fromStr.empty()) found = true; + } + } + if (found) break; + } + + found = false; + for (const auto& r : ops.relLinerules.toNameRule) { + for (const auto& relAttr : rels.rels[relId]) { + if (relAttr.first == r) { + el.toStr = ops.statNormzer(pfxml::file::decode(relAttr.second)); + if (!el.toStr.empty()) found = true; + } + } + if (found) break; + } + + if (!el.shortName.size() && !el.fromStr.size() && !el.toStr.size()) + continue; + + if (_lines.count(el)) { + elp = _lines[el]; + _relLines[relId] = elp; + } else { + elp = new TransitEdgeLine(el); + _lines[el] = elp; + _relLines[relId] = elp; + } + } + ret.push_back(elp); + } + + return ret; } // _____________________________________________________________________________ void OsmBuilder::getKeptAttrKeys(const OsmReadOpts& opts, AttrKeySet sets[3]) const { - for (const auto& i : opts.statGroupNAttrRules) { - if (i.attr.relRule.kv.first.empty()) { - sets[0].insert(i.attr.attr); - } else { - sets[2].insert(i.attr.relRule.kv.first); - sets[2].insert(i.attr.attr); - } - } - - for (const auto& i : opts.keepFilter) { - for (size_t j = 0; j < 3; j++) sets[j].insert(i.first); - } - - for (const auto& i : opts.dropFilter) { - for (size_t j = 0; j < 3; j++) sets[j].insert(i.first); - } - - for (const auto& i : opts.noHupFilter) { - sets[0].insert(i.first); - } - - for (const auto& i : opts.oneWayFilter) { - sets[1].insert(i.first); - } - - for (const auto& i : opts.oneWayFilterRev) { - sets[1].insert(i.first); - } - - for (const auto& i : opts.twoWayFilter) { - sets[1].insert(i.first); - } - - for (const auto& i : opts.stationFilter) { - sets[0].insert(i.first); - sets[2].insert(i.first); - } - - for (const auto& i : opts.stationBlockerFilter) { - sets[0].insert(i.first); - } - - for (uint8_t j = 0; j < 7; j++) { - for (const auto& kv : *(opts.levelFilters + j)) { - sets[1].insert(kv.first); - } - } - - // restriction system - for (const auto& i : opts.restrPosRestr) { - sets[2].insert(i.first); - } - for (const auto& i : opts.restrNegRestr) { - sets[2].insert(i.first); - } - for (const auto& i : opts.noRestrFilter) { - sets[2].insert(i.first); - } - - sets[2].insert("from"); - sets[2].insert("via"); - sets[2].insert("to"); - - sets[2].insert(opts.relLinerules.toNameRule.begin(), - opts.relLinerules.toNameRule.end()); - sets[2].insert(opts.relLinerules.fromNameRule.begin(), - opts.relLinerules.fromNameRule.end()); - sets[2].insert(opts.relLinerules.sNameRule.begin(), - opts.relLinerules.sNameRule.end()); - - for (const auto& i : opts.statAttrRules.nameRule) { - if (i.relRule.kv.first.empty()) { - sets[0].insert(i.attr); - } else { - sets[2].insert(i.relRule.kv.first); - sets[2].insert(i.attr); + for (const auto& i : opts.statGroupNAttrRules) { + if (i.attr.relRule.kv.first.empty()) { + sets[0].insert(i.attr.attr); + } else { + sets[2].insert(i.attr.relRule.kv.first); + sets[2].insert(i.attr.attr); + } } - } - for (const auto& i : opts.edgePlatformRules) { - if (i.relRule.kv.first.empty()) { - sets[1].insert(i.attr); - } else { - sets[2].insert(i.relRule.kv.first); - sets[2].insert(i.attr); + for (const auto& i : opts.keepFilter) { + for (size_t j = 0; j < 3; j++) sets[j].insert(i.first); } - } - for (const auto& i : opts.statAttrRules.platformRule) { - if (i.relRule.kv.first.empty()) { - sets[0].insert(i.attr); - } else { - sets[2].insert(i.relRule.kv.first); - sets[2].insert(i.attr); + for (const auto& i : opts.dropFilter) { + for (size_t j = 0; j < 3; j++) sets[j].insert(i.first); } - } - for (const auto& i : opts.statAttrRules.idRule) { - if (i.relRule.kv.first.empty()) { - sets[0].insert(i.attr); - } else { - sets[2].insert(i.relRule.kv.first); - sets[2].insert(i.attr); + for (const auto& i : opts.noHupFilter) { + sets[0].insert(i.first); + } + + for (const auto& i : opts.oneWayFilter) { + sets[1].insert(i.first); + } + + for (const auto& i : opts.oneWayFilterRev) { + sets[1].insert(i.first); + } + + for (const auto& i : opts.twoWayFilter) { + sets[1].insert(i.first); + } + + for (const auto& i : opts.stationFilter) { + sets[0].insert(i.first); + sets[2].insert(i.first); + } + + for (const auto& i : opts.stationBlockerFilter) { + sets[0].insert(i.first); + } + + for (uint8_t j = 0; j < 7; j++) { + for (const auto& kv : *(opts.levelFilters + j)) { + sets[1].insert(kv.first); + } + } + + // restriction system + for (const auto& i : opts.restrPosRestr) { + sets[2].insert(i.first); + } + for (const auto& i : opts.restrNegRestr) { + sets[2].insert(i.first); + } + for (const auto& i : opts.noRestrFilter) { + sets[2].insert(i.first); + } + + sets[2].insert("from"); + sets[2].insert("via"); + sets[2].insert("to"); + + sets[2].insert(opts.relLinerules.toNameRule.begin(), + opts.relLinerules.toNameRule.end()); + sets[2].insert(opts.relLinerules.fromNameRule.begin(), + opts.relLinerules.fromNameRule.end()); + sets[2].insert(opts.relLinerules.sNameRule.begin(), + opts.relLinerules.sNameRule.end()); + + for (const auto& i : opts.statAttrRules.nameRule) { + if (i.relRule.kv.first.empty()) { + sets[0].insert(i.attr); + } else { + sets[2].insert(i.relRule.kv.first); + sets[2].insert(i.attr); + } + } + + for (const auto& i : opts.edgePlatformRules) { + if (i.relRule.kv.first.empty()) { + sets[1].insert(i.attr); + } else { + sets[2].insert(i.relRule.kv.first); + sets[2].insert(i.attr); + } + } + + for (const auto& i : opts.statAttrRules.platformRule) { + if (i.relRule.kv.first.empty()) { + sets[0].insert(i.attr); + } else { + sets[2].insert(i.relRule.kv.first); + sets[2].insert(i.attr); + } + } + + for (const auto& i : opts.statAttrRules.idRule) { + if (i.relRule.kv.first.empty()) { + sets[0].insert(i.attr); + } else { + sets[2].insert(i.relRule.kv.first); + sets[2].insert(i.attr); + } } - } } // _____________________________________________________________________________ void OsmBuilder::deleteOrphEdgs(Graph* g, const OsmReadOpts& opts) { - size_t ROUNDS = 3; - for (size_t c = 0; c < ROUNDS; c++) { - for (auto i = g->getNds()->begin(); i != g->getNds()->end();) { - if ((*i)->getInDeg() + (*i)->getOutDeg() != 1 || (*i)->pl().getSI()) { - ++i; - continue; - } - - // check if the removal of this edge would transform a steep angle - // full turn at an intersection into a node 2 eligible for contraction - // if so, dont delete - if (keepFullTurn(*i, opts.fullTurnAngle)) { - ++i; - continue; - } - - i = g->delNd(*i); - continue; - i++; - } - } + size_t ROUNDS = 3; + for (size_t c = 0; c < ROUNDS; c++) { + for (auto i = g->getNds()->begin(); i != g->getNds()->end();) { + if ((*i)->getInDeg() + (*i)->getOutDeg() != 1 || (*i)->pl().getSI()) { + ++i; + continue; + } + + // check if the removal of this edge would transform a steep angle + // full turn at an intersection into a node 2 eligible for contraction + // if so, dont delete + if (keepFullTurn(*i, opts.fullTurnAngle)) { + ++i; + continue; + } + + i = g->delNd(*i); + continue; + i++; + } + } } // _____________________________________________________________________________ void OsmBuilder::deleteOrphNds(Graph* g) { - for (auto i = g->getNds()->begin(); i != g->getNds()->end();) { - if ((*i)->getInDeg() + (*i)->getOutDeg() == 0 && - !((*i)->pl().getSI() && (*i)->pl().getSI()->getGroup())) { - i = g->delNd(i); - // TODO(patrick): maybe delete from node grid? - } else { - i++; + for (auto i = g->getNds()->begin(); i != g->getNds()->end();) { + if ((*i)->getInDeg() + (*i)->getOutDeg() == 0 && + !((*i)->pl().getSI() && (*i)->pl().getSI()->getGroup())) { + i = g->delNd(i); + // TODO(patrick): maybe delete from node grid? + } else { + i++; + } } - } } // _____________________________________________________________________________ bool OsmBuilder::edgesSim(const Edge* a, const Edge* b) { - if (static_cast(a->pl().oneWay()) ^ static_cast(b->pl().oneWay())) - return false; - if (a->pl().lvl() != b->pl().lvl()) return false; - if (a->pl().getLines().size() != b->pl().getLines().size()) return false; - if (a->pl().getLines() != b->pl().getLines()) return false; - if (a->pl().oneWay() && b->pl().oneWay()) { - if (a->getFrom() != b->getTo() && a->getTo() != b->getFrom()) return false; - } - if (a->pl().isRestricted() || b->pl().isRestricted()) return false; - - return true; + if (static_cast(a->pl().oneWay()) ^ static_cast(b->pl().oneWay())) + return false; + if (a->pl().lvl() != b->pl().lvl()) return false; + if (a->pl().getLines().size() != b->pl().getLines().size()) return false; + if (a->pl().getLines() != b->pl().getLines()) return false; + if (a->pl().oneWay() && b->pl().oneWay()) { + if (a->getFrom() != b->getTo() && a->getTo() != b->getFrom()) return false; + } + if (a->pl().isRestricted() || b->pl().isRestricted()) return false; + + return true; } // _____________________________________________________________________________ const EdgePL& OsmBuilder::mergeEdgePL(Edge* a, Edge* b) { - const Node* n = 0; - if (a->getFrom() == b->getFrom()) - n = a->getFrom(); - else if (a->getFrom() == b->getTo()) - n = a->getFrom(); - else - n = a->getTo(); - - if (a->getTo() == n && b->getTo() == n) { - // --> n <-- - a->pl().getGeom()->insert(a->pl().getGeom()->end(), - b->pl().getGeom()->rbegin(), - b->pl().getGeom()->rend()); - } else if (a->getTo() == n && b->getFrom() == n) { - // --> n --> - a->pl().getGeom()->insert(a->pl().getGeom()->end(), - b->pl().getGeom()->begin(), - b->pl().getGeom()->end()); - } else if (a->getFrom() == n && b->getTo() == n) { - // <-- n <-- - std::reverse(a->pl().getGeom()->begin(), a->pl().getGeom()->end()); - a->pl().getGeom()->insert(a->pl().getGeom()->end(), - b->pl().getGeom()->rbegin(), - b->pl().getGeom()->rend()); - } else { - // <-- n --> - std::reverse(a->pl().getGeom()->begin(), a->pl().getGeom()->end()); - a->pl().getGeom()->insert(a->pl().getGeom()->end(), - b->pl().getGeom()->begin(), - b->pl().getGeom()->end()); - } - - a->pl().setLength(a->pl().getLength() + b->pl().getLength()); - - return a->pl(); + const Node* n = 0; + if (a->getFrom() == b->getFrom()) + n = a->getFrom(); + else if (a->getFrom() == b->getTo()) + n = a->getFrom(); + else + n = a->getTo(); + + if (a->getTo() == n && b->getTo() == n) { + // --> n <-- + a->pl().getGeom()->insert(a->pl().getGeom()->end(), + b->pl().getGeom()->rbegin(), + b->pl().getGeom()->rend()); + } else if (a->getTo() == n && b->getFrom() == n) { + // --> n --> + a->pl().getGeom()->insert(a->pl().getGeom()->end(), + b->pl().getGeom()->begin(), + b->pl().getGeom()->end()); + } else if (a->getFrom() == n && b->getTo() == n) { + // <-- n <-- + std::reverse(a->pl().getGeom()->begin(), a->pl().getGeom()->end()); + a->pl().getGeom()->insert(a->pl().getGeom()->end(), + b->pl().getGeom()->rbegin(), + b->pl().getGeom()->rend()); + } else { + // <-- n --> + std::reverse(a->pl().getGeom()->begin(), a->pl().getGeom()->end()); + a->pl().getGeom()->insert(a->pl().getGeom()->end(), + b->pl().getGeom()->begin(), + b->pl().getGeom()->end()); + } + + a->pl().setLength(a->pl().getLength() + b->pl().getLength()); + + return a->pl(); } // _____________________________________________________________________________ void OsmBuilder::collapseEdges(Graph* g) { - for (auto* n : *g->getNds()) { - if (n->getOutDeg() + n->getInDeg() != 2 || n->pl().getSI()) continue; - - Edge* ea; - Edge* eb; - if (n->getOutDeg() == 2) { - ea = *n->getAdjListOut().begin(); - eb = *n->getAdjListOut().rbegin(); - } else if (n->getInDeg() == 2) { - ea = *n->getAdjListIn().begin(); - eb = *n->getAdjListIn().rbegin(); - } else { - ea = *n->getAdjListOut().begin(); - eb = *n->getAdjListIn().begin(); - } + for (auto* n : *g->getNds()) { + if (n->getOutDeg() + n->getInDeg() != 2 || n->pl().getSI()) continue; + + Edge* ea; + Edge* eb; + if (n->getOutDeg() == 2) { + ea = *n->getAdjListOut().begin(); + eb = *n->getAdjListOut().rbegin(); + } else if (n->getInDeg() == 2) { + ea = *n->getAdjListIn().begin(); + eb = *n->getAdjListIn().rbegin(); + } else { + ea = *n->getAdjListOut().begin(); + eb = *n->getAdjListIn().begin(); + } - // important, we don't have a multigraph! if the same edge - // will already exist, leave this node - if (g->getEdg(ea->getOtherNd(n), eb->getOtherNd(n))) continue; - if (g->getEdg(eb->getOtherNd(n), ea->getOtherNd(n))) continue; + // important, we don't have a multigraph! if the same edge + // will already exist, leave this node + if (g->getEdg(ea->getOtherNd(n), eb->getOtherNd(n))) continue; + if (g->getEdg(eb->getOtherNd(n), ea->getOtherNd(n))) continue; - if (edgesSim(ea, eb)) { - if (ea->pl().oneWay() && ea->getOtherNd(n) != ea->getFrom()) { - g->addEdg(eb->getOtherNd(n), ea->getOtherNd(n), mergeEdgePL(eb, ea)); - } else { - g->addEdg(ea->getOtherNd(n), eb->getOtherNd(n), mergeEdgePL(ea, eb)); - } - g->delEdg(ea->getFrom(), ea->getTo()); - g->delEdg(eb->getFrom(), eb->getTo()); + if (edgesSim(ea, eb)) { + if (ea->pl().oneWay() && ea->getOtherNd(n) != ea->getFrom()) { + g->addEdg(eb->getOtherNd(n), ea->getOtherNd(n), mergeEdgePL(eb, ea)); + } else { + g->addEdg(ea->getOtherNd(n), eb->getOtherNd(n), mergeEdgePL(ea, eb)); + } + g->delEdg(ea->getFrom(), ea->getTo()); + g->delEdg(eb->getFrom(), eb->getTo()); + } } - } } // _____________________________________________________________________________ void OsmBuilder::simplifyGeoms(Graph* g) { - for (auto* n : *g->getNds()) { - for (auto* e : n->getAdjListOut()) { - (*e->pl().getGeom()) = util::geo::simplify(*e->pl().getGeom(), 0.5); + for (auto* n : *g->getNds()) { + for (auto* e : n->getAdjListOut()) { + (*e->pl().getGeom()) = util::geo::simplify(*e->pl().getGeom(), 0.5); + } } - } } // _____________________________________________________________________________ uint32_t OsmBuilder::writeComps(Graph* g) { - Component* comp = new Component{7}; - uint32_t numC = 0; - - for (auto* n : *g->getNds()) { - if (!n->pl().getComp()) { - std::stack> q; - q.push(std::pair(n, 0)); - while (!q.empty()) { - std::pair cur = q.top(); - q.pop(); + Component* comp = new Component{7}; + uint32_t numC = 0; + + for (auto* n : *g->getNds()) { + if (!n->pl().getComp()) { + std::stack> q; + q.push(std::pair(n, 0)); + while (!q.empty()) { + std::pair cur = q.top(); + q.pop(); + + cur.first->pl().setComp(comp); + for (auto* e : cur.first->getAdjListOut()) { + if (e->pl().lvl() < comp->minEdgeLvl) + comp->minEdgeLvl = e->pl().lvl(); + if (!e->getOtherNd(cur.first)->pl().getComp()) + q.push(std::pair(e->getOtherNd(cur.first), e)); + } + for (auto* e : cur.first->getAdjListIn()) { + if (e->pl().lvl() < comp->minEdgeLvl) + comp->minEdgeLvl = e->pl().lvl(); + if (!e->getOtherNd(cur.first)->pl().getComp()) + q.push(std::pair(e->getOtherNd(cur.first), e)); + } + } - cur.first->pl().setComp(comp); - for (auto* e : cur.first->getAdjListOut()) { - if (e->pl().lvl() < comp->minEdgeLvl) - comp->minEdgeLvl = e->pl().lvl(); - if (!e->getOtherNd(cur.first)->pl().getComp()) - q.push(std::pair(e->getOtherNd(cur.first), e)); - } - for (auto* e : cur.first->getAdjListIn()) { - if (e->pl().lvl() < comp->minEdgeLvl) - comp->minEdgeLvl = e->pl().lvl(); - if (!e->getOtherNd(cur.first)->pl().getComp()) - q.push(std::pair(e->getOtherNd(cur.first), e)); + numC++; + comp = new Component{7}; } - } - - numC++; - comp = new Component{7}; } - } - // the last comp was not used - delete comp; + // the last comp was not used + delete comp; - return numC; + return numC; } // _____________________________________________________________________________ void OsmBuilder::writeEdgeTracks(const EdgTracks& tracks) { - for (const auto& tr : tracks) { - if (tr.first->getTo()->pl().getSI() && - tr.first->getTo()->pl().getSI()->getTrack().empty()) { - tr.first->getTo()->pl().getSI()->setTrack(tr.second); - } - if (tr.first->getFrom()->pl().getSI() && - tr.first->getFrom()->pl().getSI()->getTrack().empty()) { - tr.first->getFrom()->pl().getSI()->setTrack(tr.second); + for (const auto& tr : tracks) { + if (tr.first->getTo()->pl().getSI() && + tr.first->getTo()->pl().getSI()->getTrack().empty()) { + tr.first->getTo()->pl().getSI()->setTrack(tr.second); + } + if (tr.first->getFrom()->pl().getSI() && + tr.first->getFrom()->pl().getSI()->getTrack().empty()) { + tr.first->getFrom()->pl().getSI()->setTrack(tr.second); + } } - } } // _____________________________________________________________________________ void OsmBuilder::writeODirEdgs(Graph* g, Restrictor* restor) { - for (auto* n : *g->getNds()) { - for (auto* e : n->getAdjListOut()) { - if (g->getEdg(e->getTo(), e->getFrom())) continue; - auto newE = g->addEdg(e->getTo(), e->getFrom(), e->pl().revCopy()); - if (e->pl().isRestricted()) restor->duplicateEdge(e, newE); + for (auto* n : *g->getNds()) { + for (auto* e : n->getAdjListOut()) { + if (g->getEdg(e->getTo(), e->getFrom())) continue; + auto newE = g->addEdg(e->getTo(), e->getFrom(), e->pl().revCopy()); + if (e->pl().isRestricted()) restor->duplicateEdge(e, newE); + } } - } } // _____________________________________________________________________________ void OsmBuilder::writeSelfEdgs(Graph* g) { - for (auto* n : *g->getNds()) { - if (n->pl().getSI() && n->getAdjListOut().size() == 0) { - g->addEdg(n, n); + for (auto* n : *g->getNds()) { + if (n->pl().getSI() && n->getAdjListOut().size() == 0) { + g->addEdg(n, n); + } } - } } // _____________________________________________________________________________ bool OsmBuilder::keepFullTurn(const trgraph::Node* n, double ang) { - if (n->getInDeg() + n->getOutDeg() != 1) return false; - - const trgraph::Edge* e = 0; - if (n->getOutDeg()) - e = n->getAdjListOut().front(); - else - e = n->getAdjListIn().front(); + if (n->getInDeg() + n->getOutDeg() != 1) return false; + + const trgraph::Edge* e = 0; + if (n->getOutDeg()) + e = n->getAdjListOut().front(); + else + e = n->getAdjListIn().front(); + + auto other = e->getOtherNd(n); + + if (other->getInDeg() + other->getOutDeg() == 3) { + const trgraph::Edge* a = 0; + const trgraph::Edge* b = 0; + for (auto f : other->getAdjListIn()) { + if (f != e && !a) + a = f; + else if (f != e && !b) + b = f; + } - auto other = e->getOtherNd(n); + for (auto f : other->getAdjListOut()) { + if (f != e && !a) + a = f; + else if (f != e && !b) + b = f; + } - if (other->getInDeg() + other->getOutDeg() == 3) { - const trgraph::Edge* a = 0; - const trgraph::Edge* b = 0; - for (auto f : other->getAdjListIn()) { - if (f != e && !a) - a = f; - else if (f != e && !b) - b = f; - } + auto ap = a->pl().backHop(); + auto bp = b->pl().backHop(); + if (a->getTo() != other) ap = a->pl().frontHop(); + if (b->getTo() != other) bp = b->pl().frontHop(); - for (auto f : other->getAdjListOut()) { - if (f != e && !a) - a = f; - else if (f != e && !b) - b = f; + return router::angSmaller(ap, *other->pl().getGeom(), bp, ang); } - auto ap = a->pl().backHop(); - auto bp = b->pl().backHop(); - if (a->getTo() != other) ap = a->pl().frontHop(); - if (b->getTo() != other) bp = b->pl().frontHop(); - - return router::angSmaller(ap, *other->pl().getGeom(), bp, ang); - } - - return false; + return false; } // _____________________________________________________________________________ @@ -1836,117 +2531,117 @@ void OsmBuilder::snapStats(const OsmReadOpts& opts, Graph* g, const BBoxIdx& bbox, size_t gridSize, router::FeedStops* fs, Restrictor* res, const NodeSet& orphanStations) { - NodeGrid sng = buildNodeIdx(g, gridSize, bbox.getFullWebMercBox(), true); - EdgeGrid eg = buildEdgeIdx(g, gridSize, bbox.getFullWebMercBox()); - - LOG(DEBUG) << "Grid size of " << sng.getXWidth() << "x" << sng.getYHeight(); - - for (double d : opts.maxSnapDistances) { - for (auto s : orphanStations) { - POINT geom = *s->pl().getGeom(); - NodePL pl = s->pl(); - pl.getSI()->setIsFromOsm(false); - const auto& r = - snapStation(g, &pl, &eg, &sng, opts, res, false, false, d); - groupStats(r); - for (auto n : r) { - // if the snapped station is very near to the original OSM - // station, set is-from-osm to true - if (webMercMeterDist(geom, *n->pl().getGeom()) < - opts.maxOsmStationDistance) { - if (n->pl().getSI()) n->pl().getSI()->setIsFromOsm(true); - } - } - } - } - - if (!fs) return; - - std::vector notSnapped; - - for (auto& s : *fs) { - bool snapped = false; - auto pl = plFromGtfs(s.first, opts); - for (size_t i = 0; i < opts.maxSnapDistances.size(); i++) { - double d = opts.maxSnapDistances[i]; - - StatGroup* group = groupStats( - snapStation(g, &pl, &eg, &sng, opts, res, - i == opts.maxSnapDistances.size() - 1, false, d)); - - if (group) { - group->addStop(s.first); - (*fs)[s.first] = *group->getNodes().begin(); - snapped = true; - } - } - if (!snapped) { - LOG(VDEBUG) << "Could not snap station " - << "(" << pl.getSI()->getName() << ")" - << " (" << s.first->getLat() << "," << s.first->getLng() - << ") in normal run, trying again later in orphan mode."; - if (!bbox.contains(*pl.getGeom())) { - LOG(VDEBUG) << "Note: '" << pl.getSI()->getName() - << "' does not lie within the bounds for this graph and " - "may be a stray station"; - } - notSnapped.push_back(s.first); - } - } - - if (notSnapped.size()) - LOG(VDEBUG) << notSnapped.size() << " stations could not be snapped in " - "normal run, trying again in orphan " - "mode."; - - // try again, but aggressively snap to orphan OSM stations which have - // not been assigned to any GTFS stop yet - for (auto& s : notSnapped) { - bool snapped = false; - auto pl = plFromGtfs(s, opts); - for (size_t i = 0; i < opts.maxSnapDistances.size(); i++) { - double d = opts.maxSnapDistances[i]; - - StatGroup* group = groupStats( - snapStation(g, &pl, &eg, &sng, opts, res, - i == opts.maxSnapDistances.size() - 1, true, d)); - - if (group) { - group->addStop(s); - // add the added station name as an alt name to ensure future - // similarity - for (auto n : group->getNodes()) { - if (n->pl().getSI()) - n->pl().getSI()->addAltName(pl.getSI()->getName()); - } - (*fs)[s] = *group->getNodes().begin(); - snapped = true; - } - } - if (!snapped) { - // finally give up - - // add a group with only this stop in it - StatGroup* dummyGroup = new StatGroup(); - Node* dummyNode = g->addNd(pl); - - dummyNode->pl().getSI()->setGroup(dummyGroup); - dummyGroup->addNode(dummyNode); - dummyGroup->addStop(s); - (*fs)[s] = dummyNode; - if (!bbox.contains(*pl.getGeom())) { - LOG(VDEBUG) << "Could not snap station " - << "(" << pl.getSI()->getName() << ")" - << " (" << s->getLat() << "," << s->getLng() << ")"; - LOG(VDEBUG) << "Note: '" << pl.getSI()->getName() - << "' does not lie within the bounds for this graph and " - "may be a stray station"; - } else { - // only warn if it is contained in the BBOX for this graph - LOG(WARN) << "Could not snap station " - << "(" << pl.getSI()->getName() << ")" - << " (" << s->getLat() << "," << s->getLng() << ")"; - } - } - } + NodeGrid sng = buildNodeIdx(g, gridSize, bbox.getFullWebMercBox(), true); + EdgeGrid eg = buildEdgeIdx(g, gridSize, bbox.getFullWebMercBox()); + + LOG(DEBUG) << "Grid size of " << sng.getXWidth() << "x" << sng.getYHeight(); + + for (double d : opts.maxSnapDistances) { + for (auto s : orphanStations) { + POINT geom = *s->pl().getGeom(); + NodePL pl = s->pl(); + pl.getSI()->setIsFromOsm(false); + const auto& r = + snapStation(g, &pl, &eg, &sng, opts, res, false, false, d); + groupStats(r); + for (auto n : r) { + // if the snapped station is very near to the original OSM + // station, set is-from-osm to true + if (webMercMeterDist(geom, *n->pl().getGeom()) < + opts.maxOsmStationDistance) { + if (n->pl().getSI()) n->pl().getSI()->setIsFromOsm(true); + } + } + } + } + + if (!fs) return; + + std::vector notSnapped; + + for (auto& s : *fs) { + bool snapped = false; + auto pl = plFromGtfs(s.first, opts); + for (size_t i = 0; i < opts.maxSnapDistances.size(); i++) { + double d = opts.maxSnapDistances[i]; + + StatGroup* group = groupStats( + snapStation(g, &pl, &eg, &sng, opts, res, + i == opts.maxSnapDistances.size() - 1, false, d)); + + if (group) { + group->addStop(s.first); + (*fs)[s.first] = *group->getNodes().begin(); + snapped = true; + } + } + if (!snapped) { + LOG(VDEBUG) << "Could not snap station " + << "(" << pl.getSI()->getName() << ")" + << " (" << s.first->getLat() << "," << s.first->getLng() + << ") in normal run, trying again later in orphan mode."; + if (!bbox.contains(*pl.getGeom())) { + LOG(VDEBUG) << "Note: '" << pl.getSI()->getName() + << "' does not lie within the bounds for this graph and " + "may be a stray station"; + } + notSnapped.push_back(s.first); + } + } + + if (notSnapped.size()) + LOG(VDEBUG) << notSnapped.size() << " stations could not be snapped in " + "normal run, trying again in orphan " + "mode."; + + // try again, but aggressively snap to orphan OSM stations which have + // not been assigned to any GTFS stop yet + for (auto& s : notSnapped) { + bool snapped = false; + auto pl = plFromGtfs(s, opts); + for (size_t i = 0; i < opts.maxSnapDistances.size(); i++) { + double d = opts.maxSnapDistances[i]; + + StatGroup* group = groupStats( + snapStation(g, &pl, &eg, &sng, opts, res, + i == opts.maxSnapDistances.size() - 1, true, d)); + + if (group) { + group->addStop(s); + // add the added station name as an alt name to ensure future + // similarity + for (auto n : group->getNodes()) { + if (n->pl().getSI()) + n->pl().getSI()->addAltName(pl.getSI()->getName()); + } + (*fs)[s] = *group->getNodes().begin(); + snapped = true; + } + } + if (!snapped) { + // finally give up + + // add a group with only this stop in it + StatGroup* dummyGroup = new StatGroup(); + Node* dummyNode = g->addNd(pl); + + dummyNode->pl().getSI()->setGroup(dummyGroup); + dummyGroup->addNode(dummyNode); + dummyGroup->addStop(s); + (*fs)[s] = dummyNode; + if (!bbox.contains(*pl.getGeom())) { + LOG(VDEBUG) << "Could not snap station " + << "(" << pl.getSI()->getName() << ")" + << " (" << s->getLat() << "," << s->getLng() << ")"; + LOG(VDEBUG) << "Note: '" << pl.getSI()->getName() + << "' does not lie within the bounds for this graph and " + "may be a stray station"; + } else { + // only warn if it is contained in the BBOX for this graph + LOG(WARN) << "Could not snap station " + << "(" << pl.getSI()->getName() << ")" + << " (" << s->getLat() << "," << s->getLng() << ")"; + } + } + } } diff --git a/src/pfaedle/osm/OsmFilter.h b/src/pfaedle/osm/OsmFilter.h index daf353a..579d73a 100644 --- a/src/pfaedle/osm/OsmFilter.h +++ b/src/pfaedle/osm/OsmFilter.h @@ -16,7 +16,7 @@ namespace osm { class OsmFilter { public: enum Type : uint64_t { NODE = 16, WAY = 8, REL = 4, ALL = 0 }; - OsmFilter() {} + OsmFilter() = default; OsmFilter(const MultAttrMap& keep, const MultAttrMap& drop); explicit OsmFilter(const OsmReadOpts& o); uint64_t keep(const AttrMap& attrs, Type t) const; diff --git a/src/pfaedle/osm/OsmIdSet.cpp b/src/pfaedle/osm/OsmIdSet.cpp index 8b23bf9..bd81ab0 100644 --- a/src/pfaedle/osm/OsmIdSet.cpp +++ b/src/pfaedle/osm/OsmIdSet.cpp @@ -23,7 +23,8 @@ size_t OsmIdSet::FLOOKUPS = 0; // _____________________________________________________________________________ OsmIdSet::OsmIdSet() - : _closed(false), + : _element_size(0), + _closed(false), _sorted(true), _last(0), _smallest(-1), @@ -50,6 +51,7 @@ void OsmIdSet::add(osmid id) { if (_closed) throw std::exception(); diskAdd(id); + _element_size++; if (_last > id) _sorted = false; _last = id; if (id < _smallest) _smallest = id; diff --git a/src/pfaedle/osm/OsmIdSet.h b/src/pfaedle/osm/OsmIdSet.h index d19f9a1..bcf1a4c 100644 --- a/src/pfaedle/osm/OsmIdSet.h +++ b/src/pfaedle/osm/OsmIdSet.h @@ -42,11 +42,16 @@ class OsmIdSet { // Check if an OSM id is contained bool has(osmid id) const; + size_t size() const { + return _element_size; + } + // Count the number of lookups and file lookups for debugging static size_t LOOKUPS; static size_t FLOOKUPS; private: + mutable size_t _element_size; std::string _tmpPath; mutable bool _closed; mutable int _file; diff --git a/src/pfaedle/router/ShapeBuilder.cpp b/src/pfaedle/router/ShapeBuilder.cpp index 898b5c4..05b8734 100644 --- a/src/pfaedle/router/ShapeBuilder.cpp +++ b/src/pfaedle/router/ShapeBuilder.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include "ad/cppgtfs/gtfs/Feed.h" #include "pfaedle/Def.h" #include "pfaedle/eval/Collector.h" @@ -191,7 +192,9 @@ void ShapeBuilder::shape(pfaedle::netgraph::Graph* ng) { } // to avoid unfair load balance on threads - std::random_shuffle(clusters.begin(), clusters.end()); + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(clusters.begin(), clusters.end(), g); size_t iters = EDijkstra::ITERS; size_t totiters = EDijkstra::ITERS; diff --git a/src/util/geo/output/GeoJsonOutput.cpp b/src/util/geo/output/GeoJsonOutput.cpp index 6b638da..b6512dd 100644 --- a/src/util/geo/output/GeoJsonOutput.cpp +++ b/src/util/geo/output/GeoJsonOutput.cpp @@ -17,7 +17,7 @@ GeoJsonOutput::GeoJsonOutput(std::ostream& str) : _wr(&str, 10, true) { } // _____________________________________________________________________________ -GeoJsonOutput::GeoJsonOutput(std::ostream& str, json::Val attrs) +GeoJsonOutput::GeoJsonOutput(std::ostream& str, const json::Val& attrs) : _wr(&str, 10, true) { _wr.obj(); _wr.keyVal("type", "FeatureCollection"); diff --git a/src/util/geo/output/GeoJsonOutput.h b/src/util/geo/output/GeoJsonOutput.h index 701521b..4b12aa5 100644 --- a/src/util/geo/output/GeoJsonOutput.h +++ b/src/util/geo/output/GeoJsonOutput.h @@ -19,7 +19,7 @@ namespace output { class GeoJsonOutput { public: GeoJsonOutput(std::ostream& str); - GeoJsonOutput(std::ostream& str, json::Val attrs); + GeoJsonOutput(std::ostream& str, const json::Val& attrs); ~GeoJsonOutput(); template