diff --git a/.github/workflows/build_and test_on_ubuntu_20_04.yml b/.github/workflows/build_and test_on_ubuntu_20_04.yml deleted file mode 100644 index fe02f6f01..000000000 --- a/.github/workflows/build_and test_on_ubuntu_20_04.yml +++ /dev/null @@ -1,80 +0,0 @@ -name: Ubuntu 20.04 - -on: - pull_request: - branches: - - master - push: - branches: - - master - paths-ignore: - - '.github/workflows/**' - -jobs: - build_gcc_meson: - name: gcc and meson - runs-on: ubuntu-20.04 - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Install software-properties-common - run: sudo apt-get install software-properties-common - - name: Install gcc compiler and Co - run: sudo apt-get -y install gcc-10 g++-10 libtbb-dev ccache libtool pkg-config - - name: Install meson and ninja via pip - run: "pip install meson ninja" - - name: Install libosmscout dependencies - run: "sudo apt-get update && sudo apt-get install -y - libxml2-dev - libprotobuf-dev protobuf-compiler - libagg-dev - libfreetype6-dev libcairo2-dev libpangocairo-1.0-0 libpango1.0-dev - qt5-default qtdeclarative5-dev libqt5svg5-dev qtlocation5-dev qtpositioning5-dev qttools5-dev-tools - qttools5-dev qtmultimedia5-dev - libglm-dev libglew-dev freeglut3 freeglut3-dev - libmarisa-dev" - - name: Configure build project - run: meson setup --buildtype debugoptimized --unity on debug - env: - CXX: g++-10 - CC: gcc-10 - - name: Build project - run: ninja -C debug - - name: Run tests - run: meson test -C debug --print-errorlogs - - build_gcc_cmake: - name: gcc and cmake - runs-on: ubuntu-20.04 - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Install software-properties-common - run: sudo apt-get install software-properties-common - - name: Install gcc compiler, cmake and ninja - run: sudo apt-get -y install gcc-10 g++-10 libtbb-dev ccache libtool pkg-config cmake ninja-build - - name: Install libosmscout dependencies - run: "sudo apt-get update && sudo apt-get install -y - libxml2-dev - libprotobuf-dev protobuf-compiler - libagg-dev - libfreetype6-dev libcairo2-dev libpangocairo-1.0-0 libpango1.0-dev - qt5-default qtdeclarative5-dev libqt5svg5-dev qtlocation5-dev qtpositioning5-dev qttools5-dev-tools - qttools5-dev qtmultimedia5-dev - libglm-dev libglew-dev freeglut3 freeglut3-dev libglfw3-dev libxrandr-dev libxcursor-dev libxinerama-dev libxi-dev libxxf86vm-dev - xvfb - libmarisa-dev" - - name: Configure build project - run: cmake -B build -DCMAKE_UNITY_BUILD=ON -Wno-dev -G "Ninja" - env: - CXX: g++-10 - CC: gcc-10 - - name: Build project - run: cmake --build build - - name: Install project - run: sudo cmake --install build - - name: Run tests - run: xvfb-run ctest -j 2 --output-on-failure - env: - QT_QPA_PLATFORM: offscreen - working-directory: build diff --git a/.github/workflows/build_and test_on_ubuntu_24_04.yml b/.github/workflows/build_and test_on_ubuntu_24_04.yml index 6fc53f964..8a066067a 100644 --- a/.github/workflows/build_and test_on_ubuntu_24_04.yml +++ b/.github/workflows/build_and test_on_ubuntu_24_04.yml @@ -56,7 +56,7 @@ jobs: run: sudo apt-get -y install gcc g++ libtbb-dev ccache libtool pkg-config meson ninja-build - name: Install libosmscout dependencies run: "sudo apt-get update && sudo apt-get install -y - catch2 + catch2 libxml2-dev libprotobuf-dev protobuf-compiler liblzma-dev libagg-dev diff --git a/.github/workflows/sanitize_on_ubuntu_22_04.yml b/.github/workflows/sanitize_on_ubuntu_22_04.yml index a497bb657..bcda91564 100644 --- a/.github/workflows/sanitize_on_ubuntu_22_04.yml +++ b/.github/workflows/sanitize_on_ubuntu_22_04.yml @@ -13,7 +13,7 @@ on: jobs: sanitize_clang: name: clang - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@v4 @@ -27,7 +27,7 @@ jobs: run: "sudo apt-get install -y libxml2-dev libprotobuf-dev protobuf-compiler - libglm-dev libglew-dev freeglut3 freeglut3-dev libglfw3-dev libxrandr-dev libxcursor-dev libxinerama-dev libxi-dev libxxf86vm-dev + libglm-dev libglew-dev libglut-dev libglfw3-dev libxrandr-dev libxcursor-dev libxinerama-dev libxi-dev libxxf86vm-dev libmarisa-dev xvfb" - name: Configure build project @@ -66,20 +66,20 @@ jobs: sanitize_gcc: name: gcc - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@v4 - name: Install software-properties-common run: sudo apt-get install software-properties-common - name: Install gcc compiler, cmake and ninja - run: sudo apt-get -y install gcc-12 g++-12 libtbb-dev ccache libtool pkg-config cmake ninja-build + run: sudo apt-get -y install gcc g++ libtbb-dev ccache libtool pkg-config cmake ninja-build - name: Install libosmscout dependencies run: "sudo apt-get update && sudo apt-get install -y libxml2-dev libprotobuf-dev protobuf-compiler libmarisa-dev - libglm-dev libglew-dev freeglut3 freeglut3-dev libglfw3-dev libxrandr-dev libxcursor-dev libxinerama-dev libxi-dev libxxf86vm-dev + libglm-dev libglew-dev libglut-dev libglfw3-dev libxrandr-dev libxcursor-dev libxinerama-dev libxi-dev libxxf86vm-dev xvfb" - name: Configure build project run: "cmake -B build @@ -100,8 +100,8 @@ jobs: -DCMAKE_EXE_LINKER_FLAGS=\"-fsanitize=address -fsanitize=undefined\" -DCMAKE_UNITY_BUILD=ON -Wno-dev -G \"Ninja\"" env: - CXX: g++-12 - CC: gcc-12 + CXX: g++ + CC: gcc - name: Build project run: cmake --build build - name: Install project diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index f5227c281..e28c256e2 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -15,11 +15,11 @@ on: jobs: sonar_gcc_meson: name: sonar, gcc and meson - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 environment: SONAR steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Update package list @@ -27,32 +27,39 @@ jobs: - name: Install software-properties-common run: sudo apt-get install software-properties-common - name: Install gcc compiler, meson and ninja - run: sudo apt-get -y install gcc-11 g++-11 libtbb-dev ccache libtool pkg-config + run: sudo apt-get -y install gcc g++ libtbb-dev ccache libtool pkg-config - name: Install meson, ninja, lcov and gcovr via pip - run: pip install meson ninja lcov gcovr==6.0 + run: pip install --user meson ninja lcov gcovr --break-system-packages - name: Install libosmscout dependencies run: "sudo apt-get install -y + catch2 libxml2-dev - libprotobuf-dev protobuf-compiler + libprotobuf-dev protobuf-compiler liblzma-dev libagg-dev libfreetype6-dev libcairo2-dev libpangocairo-1.0-0 libpango1.0-dev qtdeclarative5-dev libqt5svg5-dev qtlocation5-dev qtpositioning5-dev qttools5-dev-tools qttools5-dev qtmultimedia5-dev - libglm-dev libglew-dev freeglut3 freeglut3-dev + libglm-dev libglew-dev libglut-dev libmarisa-dev" - name: Install sonar-scanner and build-wrapper - uses: sonarsource/sonarcloud-github-c-cpp@v2 + uses: sonarsource/sonarcloud-github-c-cpp@v3 - name: Configure build project run: meson setup --buildtype debugoptimized -Db_coverage=true --unity on debug env: - CXX: g++-11 - CC: gcc-11 + CXX: g++ + CC: gcc - name: Build project run: build-wrapper-linux-x86-64 --out-dir sonar-build-output ninja -C debug all test coverage - - name: Create gcov files - run: mkdir gcov && cd gcov && gcov -p ../debug//*/*/* + env: + CXX: g++ + CC: gcc - name: SonarCloud Scan - run: sonar-scanner -Dsonar.cfamily.build-wrapper-output=sonar-build-output -Dsonar.cfamily.gcov.reportsPath=gcov -Dsonar.token=$SONAR_TOKEN + run: "sonar-scanner + -Dsonar.cfamily.compile-commands=sonar-build-output/compile_commands.json + -Dsonar.cfamily.cppunit.reportsPath=debug/meson-logs/testlog.junit.xml + -Dsonar.coverageReportPaths=debug/meson-logs/sonarqube.xml + -Dsonar.cfamily.cobertura.reportPaths=debug/meson-logs/coverage.xml + -Dsonar.token=$SONAR_TOKEN" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/DumpData/src/DumpData.cpp b/DumpData/src/DumpData.cpp index 3b5bf11e7..f04b08120 100644 --- a/DumpData/src/DumpData.cpp +++ b/DumpData/src/DumpData.cpp @@ -23,33 +23,18 @@ #include #include #include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include +#include + /* * Example: * src/DumpData ../TravelJinni/ -n 25293125 -w 4290108 -w 26688152 -r 531985 @@ -62,7 +47,7 @@ struct Job Job() = default; - Job(osmscout::OSMRefType type, osmscout::Id id) + Job(osmscout::OSMRefType type, osmscout::OSMId id) : osmRef(id,type) { // no code @@ -75,247 +60,21 @@ struct Job } }; -static const size_t IDENT=2; - -static bool ParseArguments(int argc, - char* argv[], - std::string& map, - std::set& coordIds, - std::set& routeNodeCoordIds, - std::set& routeNodeIds, - std::list& jobs) +struct Arguments { - if (argc<2) { - std::cerr << "DumpData {Search arguments}" << std::endl; - std::cerr << std::endl; - std::cerr << "Search arguments:" << std::endl; - std::cerr << " -c OSM coord ids" << std::endl; - std::cerr << std::endl; - std::cerr << " -n OSM node id" << std::endl; - std::cerr << " -no osmscout node file offset" << std::endl; - std::cerr << std::endl; - std::cerr << " -w OSM way id" << std::endl; - std::cerr << " -wo osmscout way file offset" << std::endl; - std::cerr << std::endl; - std::cerr << " -r OSM relation id" << std::endl; - std::cerr << " -ao osmscout area file offset" << std::endl; - std::cerr << std::endl; - std::cerr << " -rn route node by OSM node id" << std::endl; - std::cerr << " -ri osmscout route node id" << std::endl; - return false; - } - - int arg=1; - - map=argv[arg]; - - arg++; - - while (arg=argc) { - std::cerr << "Option -c requires parameter!" << std::endl; - return false; - } - - if (sscanf(argv[arg],"%ld",&id)!=1) { - std::cerr << "Node id is not numeric!" << std::endl; - return false; - } - - coordIds.insert(id); - - arg++; - } - - // - // OSM types (nodes, ways, relations) - // - - else if (strcmp(argv[arg],"-n")==0) { - unsigned long id; - - arg++; - if (arg>=argc) { - std::cerr << "Option -n requires parameter!" << std::endl; - return false; - } - - if (sscanf(argv[arg],"%lu",&id)!=1) { - std::cerr << "Node id is not numeric!" << std::endl; - return false; - } - - jobs.emplace_back(osmscout::osmRefNode,id); - - arg++; - } - else if (strcmp(argv[arg],"-w")==0) { - unsigned long id; - - arg++; - if (arg>=argc) { - std::cerr << "Option -w requires parameter!" << std::endl; - return false; - } - - if (sscanf(argv[arg],"%lu",&id)!=1) { - std::cerr << "Node id is not numeric!" << std::endl; - return false; - } - - jobs.emplace_back(osmscout::osmRefWay,id); - - arg++; - } - else if (strcmp(argv[arg],"-r")==0) { - unsigned long id; - - arg++; - if (arg>=argc) { - std::cerr << "Option -r requires parameter!" << std::endl; - return false; - } - - if (sscanf(argv[arg],"%lu",&id)!=1) { - std::cerr << "Relation id is not numeric!" << std::endl; - return false; - } - - jobs.emplace_back(osmscout::osmRefRelation,id); - - arg++; - } - else if (strcmp(argv[arg],"-rn")==0) { - unsigned long id; - - arg++; - if (arg>=argc) { - std::cerr << "Option -rn requires parameter!" << std::endl; - return false; - } - - if (sscanf(argv[arg],"%lu",&id)!=1) { - std::cerr << "Route node coord id is not numeric!" << std::endl; - return false; - } - - routeNodeCoordIds.insert(id); - - arg++; - } - else if (strcmp(argv[arg],"-ri")==0) { - unsigned long id; - - arg++; - if (arg>=argc) { - std::cerr << "Option -ri requires parameter!" << std::endl; - return false; - } - - if (sscanf(argv[arg],"%lu",&id)!=1) { - std::cerr << "Route node id is not numeric!" << std::endl; - return false; - } - - routeNodeIds.insert(id); - - arg++; - } - - // - // libosmscout types (nodes, ways, areas) - // - - else if (strcmp(argv[arg],"-no")==0) { - unsigned long fileOffset; - - arg++; - if (arg>=argc) { - std::cerr << "Option -no requires parameter!" << std::endl; - return false; - } - - if (sscanf(argv[arg],"%lu",&fileOffset)!=1) { - std::cerr << "Node id is not numeric!" << std::endl; - return false; - } - - jobs.emplace_back(osmscout::refNode,fileOffset); - - arg++; - } - else if (strcmp(argv[arg],"-wo")==0) { - unsigned long fileOffset; - - arg++; - if (arg>=argc) { - std::cerr << "Option -wo requires parameter!" << std::endl; - return false; - } - - if (sscanf(argv[arg],"%lu",&fileOffset)!=1) { - std::cerr << "Way file offset is not numeric!" << std::endl; - return false; - } - - jobs.emplace_back(osmscout::refWay,fileOffset); - - arg++; - } - else if (strcmp(argv[arg],"-ao")==0) { - unsigned long fileOffset; - - arg++; - if (arg>=argc) { - std::cerr << "Option -ao requires parameter!" << std::endl; - return false; - } - - if (sscanf(argv[arg],"%lu",&fileOffset)!=1) { - std::cerr << "Area file offset is not numeric!" << std::endl; - return false; - } - - jobs.emplace_back(osmscout::refArea,fileOffset); - - arg++; - } - - - else { - std::cerr << "Unknown parameter '" << argv[arg] << "'!" << std::endl; - return false; - } - } - - return true; -} - -static uint32_t CalculateCellLevel(const osmscout::GeoBox& boundingBox) -{ - uint32_t level=25; - while (true) { - if (boundingBox.GetWidth()<=osmscout::cellDimension[level].width && - boundingBox.GetHeight()<=osmscout::cellDimension[level].height) { - break; - } - - if (level==0) { - break; - } - - level--; - } + std::string map; + std::set coordIds; + std::set routeNodeCoordIds; + std::set routeNodeIds; + std::list jobs; + bool help; +}; - return level; -} +static const size_t INDENT=2; static void DumpIndent(size_t indent) { + assert(indent<=10); for (size_t i=1; i<=indent; i++) { std::cout << " "; } @@ -383,556 +142,208 @@ static void DumpRouteNode(const osmscout::RouteNode& routeNode) std::cout << "}" << std::endl; } -static void DumpAccessFeatureValue(const osmscout::AccessFeatureValue& accessValue, - size_t indent, - bool defaultValue) -{ - DumpIndent(indent); - - if (defaultValue) { - std::cout << "(Access) {" << std::endl; - } - else { - std::cout << "Access {" << std::endl; - } - - if (accessValue.IsOnewayForward()) { - DumpIndent(indent+2); - std::cout << "oneway: forward" << std::endl; - } - else if (accessValue.IsOnewayBackward()) { - DumpIndent(indent+2); - std::cout << "oneway: backward" << std::endl; - } - - if (accessValue.CanRouteFootForward() && accessValue.CanRouteFootBackward()) { - DumpIndent(indent+2); - std::cout << "foot: both" << std::endl; - } - else if (accessValue.CanRouteFootForward()) { - DumpIndent(indent+2); - std::cout << "foot: forward" << std::endl; - } - else if (accessValue.CanRouteFootBackward()) { - DumpIndent(indent+2); - std::cout << "foot: backward" << std::endl; - } - - if (accessValue.CanRouteBicycleForward() && accessValue.CanRouteBicycleBackward()) { - DumpIndent(indent+2); - std::cout << "bicycle: both" << std::endl; - } - else if (accessValue.CanRouteBicycleForward()) { - DumpIndent(indent+2); - std::cout << "bicycle: forward" << std::endl; - } - else if (accessValue.CanRouteBicycleBackward()) { - DumpIndent(indent+2); - std::cout << "bicycle: backward" << std::endl; - } - - if (accessValue.CanRouteCarForward() && accessValue.CanRouteCarBackward()) { - DumpIndent(indent+2); - std::cout << "car: both" << std::endl; - } - else if (accessValue.CanRouteCarForward()) { - DumpIndent(indent+2); - std::cout << "car: forward" << std::endl; - } - else if (accessValue.CanRouteCarBackward()) { - DumpIndent(indent+2); - std::cout << "car: backward" << std::endl; - } - - DumpIndent(indent); - std::cout << "}" << std::endl; -} - -static void DumpAccessRestrictedFeatureValue(const osmscout::AccessRestrictedFeatureValue& accessValue, - size_t indent) +static void DumpDescription(const osmscout::ObjectDescription& description, + size_t indent) { - DumpIndent(indent); - std::cout << "AccessRestricted {" << std::endl; - - if (!accessValue.CanAccessFoot()) { - DumpIndent(indent+2); - std::cout << "foot: restricted" << std::endl; - } - - if (!accessValue.CanAccessBicycle()) { - DumpIndent(indent+2); - std::cout << "bicycle: restricted" << std::endl; - } - - if (!accessValue.CanAccessCar()) { - DumpIndent(indent+2); - std::cout << "car: restricted" << std::endl; - } - - DumpIndent(indent); - std::cout << "}" << std::endl; -} + std::string previousSection; + std::string previousSubsection; + size_t previousIndex=std::numeric_limits::max(); + + for (const auto& entry : description.GetEntries()) { + // Close previous subsection, if subsection changes + if (!previousSubsection.empty() && + (entry.GetSubsectionKey()!=previousSubsection || !entry.HasSubsection())) { + assert(indent>=2); + indent-=2; + DumpIndent(indent); + std::cout << "}" << std::endl; + } -static void DumpSidewayFeatureValue(const osmscout::SidewayFeatureValue& sidewayValue, - size_t indent) -{ - DumpIndent(indent); - std::cout << "Sideway {" << std::endl; + // Close previous section, if section changes + if (!previousSection.empty() && + entry.GetSectionKey()!=previousSection) { + assert(indent>=2); + indent-=2; + DumpIndent(indent); + std::cout << "}" << std::endl; + } - if (sidewayValue.HasSidewalkTrackLeft() && - sidewayValue.HasSidewalkTrackRight()) { - DumpIndent(indent+2); - std::cout << "sidewalk: track both" << std::endl; - } - else if (sidewayValue.HasSidewalkTrackLeft()) { - DumpIndent(indent+2); - std::cout << "sidewalk: track left" << std::endl; - } - else if (sidewayValue.HasSidewalkTrackRight()) { - DumpIndent(indent+2); - std::cout << "sidewalk: track right" << std::endl; - } + if (entry.GetSectionKey()!=previousSection) { + if (!previousSection.empty()) { + std::cout << std::endl; + } - if (sidewayValue.HasCyclewayLaneLeft() && - sidewayValue.HasCyclewayLaneRight()) { - DumpIndent(indent+2); - std::cout << "cycleway: lane both" << std::endl; - } - else if (sidewayValue.HasCyclewayLaneLeft()) { - DumpIndent(indent+2); - std::cout << "cycleway: lane left" << std::endl; - } - else if (sidewayValue.HasCyclewayLaneRight()) { - DumpIndent(indent+2); - std::cout << "cycleway: lane right" << std::endl; - } + DumpIndent(indent); + std::cout << entry.GetSectionKey() << " {" << std::endl; + indent+=2; + } - if (sidewayValue.HasCyclewayTrackLeft() && - sidewayValue.HasCyclewayTrackRight()) { - DumpIndent(indent+2); - std::cout << "cycleway: track both" << std::endl; - } - else if (sidewayValue.HasCyclewayTrackLeft()) { - DumpIndent(indent+2); - std::cout << "cycleway: track left" << std::endl; - } - else if (sidewayValue.HasCyclewayTrackRight()) { - DumpIndent(indent+2); - std::cout << "cycleway: track right" << std::endl; - } + if (entry.HasSubsection() && entry.GetSubsectionKey()!=previousSubsection) { + DumpIndent(indent); + std::cout << entry.GetSubsectionKey() << " {" << std::endl; + indent+=2; + } - DumpIndent(indent); - std::cout << "}" << std::endl; -} -static void DumpLanesFeatureValue(const osmscout::LanesFeatureValue& lanesValue, - size_t indent) -{ - DumpIndent(indent); - std::cout << "Lanes {" << std::endl; + if (entry.HasIndex() && entry.GetIndex()>1 && entry.GetIndex()!=previousIndex) { + assert(indent>=2); + DumpIndent(indent-2); + std::cout << "}" << std::endl; + DumpIndent(indent-2); + std::cout << entry.GetSubsectionKey() << " {" << std::endl; + } - DumpIndent(indent+2); - std::cout << "Lanes: "; - if (lanesValue.HasSingleLane()) { - std::cout << "1" << std::endl; - } - else { - std::cout << (size_t)lanesValue.GetForwardLanes() << " " << (size_t)lanesValue.GetBackwardLanes() << std::endl; - } + previousSection=entry.GetSectionKey(); + previousSubsection=entry.GetSubsectionKey(); - if (!lanesValue.GetTurnForward().empty()) { - DumpIndent(indent+2); - std::cout << "TurnForward: "; - for (auto turn: lanesValue.GetTurnForward()) { - std::cout << LaneTurnString(turn); - std::cout << " "; + if (entry.HasIndex()) { + previousIndex=entry.GetIndex(); } - std::cout << std::endl; - } - - if (!lanesValue.GetTurnBackward().empty()) { - DumpIndent(indent+2); - std::cout << "TurnBackward: "; - for (auto turn: lanesValue.GetTurnForward()) { - std::cout << LaneTurnString(turn); - std::cout << " "; + else { + previousIndex=std::numeric_limits::max(); } - std::cout << std::endl; - } - if (!lanesValue.GetDestinationForward().empty()) { - DumpIndent(indent+2); - std::cout << "DestinationForward: " << lanesValue.GetDestinationForward() << std::endl; + DumpIndent(indent); + std::cout << entry.GetLabelKey() << ": "; + std::cout << entry.GetValue() << std::endl; } - if (!lanesValue.GetDestinationBackward().empty()) { - DumpIndent(indent+2); - std::cout << "DestinationBackward: " << lanesValue.GetDestinationBackward() << std::endl; + if (!previousSubsection.empty()) { + assert(indent>=2); + indent-=2; + DumpIndent(indent); + std::cout << "}" << std::endl; } - DumpIndent(indent); - std::cout << "}" << std::endl; -} - -static void DumpChargingStationFeatureValue(const osmscout::ChargingStationFeatureValue& chargingStationValue, - size_t indent) -{ - DumpIndent(indent); - std::cout << "ChargingStation {" << std::endl; - - for (const auto& socket : chargingStationValue.GetSockets()) { - DumpIndent(indent+2); - std::cout << "Socket {" << std::endl; - - DumpIndent(indent+4); - std::cout << "capacity: " << (unsigned int) socket.capacity << std::endl; - DumpIndent(indent+4); - std::cout << "type: " << osmscout::EnumToString(socket.type) << std::endl; - - if (!socket.output.empty()) { - DumpIndent(indent+4); - std::cout << "output: " << socket.output << std::endl; - } - - DumpIndent(indent+2); + if (!previousSection.empty()) { + assert(indent>=2); + indent-=2; + DumpIndent(indent); std::cout << "}" << std::endl; } - - DumpIndent(indent); - std::cout << "}" << std::endl; - } -static void DumpFeatureValueBuffer(const osmscout::FeatureValueBuffer& buffer, - size_t indent) -{ - for (size_t idx=0; idxHasValue()) { - osmscout::FeatureValue *value=buffer.GetValue(idx); - - if (const auto* nameValue = dynamic_cast(value); - nameValue != nullptr) { - - DumpIndent(indent); - std::cout << "Name: " << nameValue->GetName() << std::endl; - } - else if (const auto* nameAltValue = dynamic_cast(value); - nameAltValue != nullptr) { - - DumpIndent(indent); - std::cout << "NameAlt: " << nameAltValue->GetNameAlt() << std::endl; - } - else if (const auto* refValue = dynamic_cast(value); - refValue != nullptr) { - - DumpIndent(indent); - std::cout << "Ref: " << refValue->GetRef() << std::endl; - } - else if (const auto* locationValue = dynamic_cast(value); - locationValue != nullptr) { - - DumpIndent(indent); - std::cout << "Location: "<< locationValue->GetLocation() << std::endl; - } - else if (const auto* addressValue = dynamic_cast(value); - addressValue != nullptr) { - - DumpIndent(indent); - std::cout << "Address: " << addressValue->GetAddress() << std::endl; - } - else if (const auto* accessValue = dynamic_cast(value); - accessValue != nullptr) { - - DumpAccessFeatureValue(*accessValue, - indent, - false); - } - else if (const auto* accessValue=dynamic_cast(value); - accessValue != nullptr) { - - DumpAccessRestrictedFeatureValue(*accessValue, - indent); - } - else if (const auto* layerValue = dynamic_cast(value); - layerValue != nullptr) { - - DumpIndent(indent); - std::cout << "Layer: " << (int)layerValue->GetLayer() << std::endl; - } - else if (const auto* widthValue = dynamic_cast(value); - widthValue != nullptr) { - - DumpIndent(indent); - std::cout << "Width: " << (int)widthValue->GetWidth() << std::endl; - } - else if (const auto* maxSpeedValue = dynamic_cast(value); - maxSpeedValue != nullptr) { - - DumpIndent(indent); - std::cout << "MaxSpeed: " << (int)maxSpeedValue->GetMaxSpeed() << std::endl; - } - else if (const auto* gradeValue = dynamic_cast(value); - gradeValue != nullptr) { - - DumpIndent(indent); - std::cout << "Grade: " << (int)gradeValue->GetGrade() << std::endl; - } - else if (const auto* adminLevelValue = dynamic_cast(value); - adminLevelValue != nullptr) { - - DumpIndent(indent); - std::cout << "AdminLevel: " << (unsigned int)adminLevelValue->GetAdminLevel(); - - if (!adminLevelValue->GetIsIn().empty()) { - std::cout << " is in " << adminLevelValue->GetIsIn(); - } - - std::cout << std::endl; - } - else if (const auto* isInValue = dynamic_cast(value); - isInValue != nullptr) { - - DumpIndent(indent); - std::cout << "IsIn: " << isInValue->GetIsIn() << std::endl; - } - else if (const auto* brandValue = dynamic_cast(value); - brandValue != nullptr) { - - DumpIndent(indent); - std::cout << "Brand: " << brandValue->GetName() << std::endl; - } - else if (const auto* sidewayValue = dynamic_cast(value); - sidewayValue != nullptr) { - - DumpSidewayFeatureValue(*sidewayValue,indent); - } - else if (const auto* lanesValue = dynamic_cast(value); - lanesValue != nullptr) { - - DumpLanesFeatureValue(*lanesValue, - indent); - } - else if (const auto* chargingStationValue = dynamic_cast(value); - chargingStationValue != nullptr) { - - DumpChargingStationFeatureValue(*chargingStationValue,indent); - } - else if (const auto* maxStayValue = dynamic_cast(value); - maxStayValue != nullptr) { - DumpIndent(indent); - std::cout << "MaxStay {" << std::endl; - - DumpIndent(indent+2); - std::cout << "value: " << maxStayValue->GetValue() << std::endl; - - if (maxStayValue->HasCondition()) { - DumpIndent(indent+2); - std::cout << "condition: " << maxStayValue->GetCondition() << std::endl; - } - - DumpIndent(indent); - std::cout << "}" << std::endl; - } - else if (const auto* feeValue = dynamic_cast(value); - feeValue != nullptr) { - DumpIndent(indent); - std::cout << "Fee {" << std::endl; - - DumpIndent(indent+2); - std::cout << "value: " << EnumToString(feeValue->GetValue()) << std::endl; - - if (feeValue->HasCondition()) { - DumpIndent(indent+2); - std::cout << "condition: " << feeValue->GetCondition() << std::endl; - } - - DumpIndent(indent); - std::cout << "}" << std::endl; - - } - else if (meta.GetFeature()->HasLabel()) { - DumpIndent(indent); - std::cout << meta.GetFeature()->GetName() << ": "; - std::cout << value->GetLabel(osmscout::Locale(), 0); - std::cout << std::endl; - } - else { - DumpIndent(indent); - std::cout << meta.GetFeature()->GetName() << ": "; - std::cout << ""; - std::cout << std::endl; - } - } - // Flag-like Features - else { - // We are just a flag... - DumpIndent(indent); - std::cout << meta.GetFeature()->GetName() << ": true"; - std::cout << std::endl; - } - } - // Features with default value - else { - if (meta.GetFeature()->GetName()==osmscout::AccessFeature::NAME) { - osmscout::AccessFeatureValue accessValue(buffer.GetType()->GetDefaultAccess()); - - DumpAccessFeatureValue(accessValue, - indent, - true); - } - else if (!meta.GetFeature()->HasValue()) { - // We are just a flag... - DumpIndent(indent); - std::cout << "(" << meta.GetFeature()->GetName() << ")" << ": false"; - std::cout << std::endl; - } - } - } -} -static void DumpNode(const osmscout::NodeRef& node, +static void DumpNode(const osmscout::DescriptionService& descriptionService, + const osmscout::Node& node, osmscout::OSMId id) { + osmscout::ObjectDescription description=descriptionService.GetDescription(node); + std::cout << "Node {" << std::endl; std::cout << " OSM id: " << id << std::endl; - std::cout << " fileOffset: " << node->GetFileOffset() << std::endl; - std::cout << " type: " << node->GetType()->GetName() << std::endl; - std::cout << std::endl; - - DumpFeatureValueBuffer(node->GetFeatureValueBuffer(), - IDENT); + DumpDescription(description,2); std::cout << std::endl; - std::cout << " lat: " << node->GetCoords().GetLat() << std::endl; - std::cout << " lon: " << node->GetCoords().GetLon() << std::endl; + std::cout << " lat: " << node.GetCoords().GetLat() << std::endl; + std::cout << " lon: " << node.GetCoords().GetLon() << std::endl; std::cout << "}" << std::endl; - } -static void DumpWay(const osmscout::WayRef& way, - osmscout::OSMId id) +static void DumpWay(const osmscout::DescriptionService& descriptionService, + const osmscout::Way& way, + osmscout::OSMId id) { - osmscout::GeoBox boundingBox=way->GetBoundingBox(); + osmscout::ObjectDescription description=descriptionService.GetDescription(way); std::cout << "Way {" << std::endl; - std::cout << " OSM id: " << id << std::endl; - std::cout << " fileOffset: " << way->GetFileOffset() << std::endl; - std::cout << " type: " << way->GetType()->GetName() << std::endl; - std::cout << " boundingBox: " << boundingBox.GetDisplayText() << std::endl; - std::cout << " center: " << boundingBox.GetCenter().GetDisplayText() << std::endl; - std::cout << " cell level: " << CalculateCellLevel(boundingBox) << std::endl; - std::cout << std::endl; + DumpDescription(description,2); - DumpFeatureValueBuffer(way->GetFeatureValueBuffer(), - IDENT); - - if (!way->nodes.empty()) { + if (!way.nodes.empty()) { std::cout << std::endl; - for (size_t n=0; nnodes.size(); n++) { + for (size_t n=0; nGetSerial(n)!=0) { - std::cout << " serial: " << way->GetSerial(n); - std::cout << " id: " << way->GetId(n); + if (way.GetSerial(n)!=0) { + std::cout << " serial: " << way.GetSerial(n); + std::cout << " id: " << way.GetId(n); } - std::cout << " lat: " << way->GetCoord(n).GetLat() << " lon: "<< way->GetCoord(n).GetLon() << " }" << std::endl; + std::cout << " lat: " << way.GetCoord(n).GetLat() << " lon: "<< way.GetCoord(n).GetLon() << " }" << std::endl; } } std::cout << "}" << std::endl; } -static void DumpArea(const osmscout::AreaRef& area, +static void DumpArea(const osmscout::DescriptionService& descriptionService, + const osmscout::Area& area, osmscout::OSMId id) { - osmscout::GeoBox boundingBox=area->GetBoundingBox(); + osmscout::ObjectDescription description=descriptionService.GetDescription(area); std::cout << "Area {" << std::endl; - std::cout << " OSM id: " << id << std::endl; - std::cout << " fileOffset: " << area->GetFileOffset() << std::endl; - std::cout << " type: " << area->GetType()->GetName() << std::endl; - std::cout << " boundingBox: " << boundingBox.GetDisplayText() << std::endl; - std::cout << " center: " << boundingBox.GetCenter().GetDisplayText() << std::endl; - std::cout << " cell level: " << CalculateCellLevel(boundingBox) << std::endl; - std::cout << std::endl; - DumpFeatureValueBuffer(area->rings.front().GetFeatureValueBuffer(), - IDENT); + DumpDescription(description,2); - for (size_t r=0; rrings.size(); r++) { + for (size_t r=0; rrings[r].IsMaster()) { - ident=IDENT; + size_t indent; + if (area.rings[r].IsMaster()) { + indent=INDENT; } else { std::cout << " role[" << r << "] {" << std::endl; - ident=IDENT+2; + indent=INDENT+2; } - if (area->rings[r].IsMaster()) { - DumpIndent(ident); - std::cout << "master" << std::endl; + if (area.rings[r].IsMaster()) { + DumpIndent(indent); + std::cout << "role: master" << std::endl; } - else if (area->rings[r].IsTopOuter()) { - DumpIndent(ident); - std::cout << "outer" << std::endl; - DumpIndent(ident); - std::cout << "type: " << area->rings[r].GetType()->GetName() << std::endl; + else if (area.rings[r].IsTopOuter()) { + DumpIndent(indent); + std::cout << "role: outer" << std::endl; } else { - DumpIndent(ident); - std::cout << "ring: " << (size_t)area->rings[r].GetRing() << std::endl; - DumpIndent(ident); - std::cout << "type: " << area->rings[r].GetType()->GetName() << std::endl; + DumpIndent(indent); + std::cout << "ring: " << (size_t)area.rings[r].GetRing() << std::endl; } - if (!area->rings[r].nodes.empty()) { - DumpIndent(ident); + if (!area.rings[r].nodes.empty()) { + osmscout::GeoBox boundingBox=area.rings[r].GetBoundingBox(); + DumpIndent(indent); std::cout << "boundingBox: " << boundingBox.GetDisplayText() << std::endl; - DumpIndent(ident); + DumpIndent(indent); std::cout << "center of bounding box: " << boundingBox.GetCenter().GetDisplayText() << std::endl; - if (area->rings[r].center) { - DumpIndent(ident); - std::cout << "visual center: " << area->rings[r].center.value().GetDisplayText() << std::endl; + if (area.rings[r].center) { + DumpIndent(indent); + std::cout << "visual center: " << area.rings[r].center.value().GetDisplayText() << std::endl; } } - DumpFeatureValueBuffer(area->rings[r].GetFeatureValueBuffer(), - ident); + osmscout::ObjectDescription rinDescription=descriptionService.GetDescription(area.rings[r].GetFeatureValueBuffer()); - if (!area->rings[r].nodes.empty()) { + DumpDescription(rinDescription,indent); + + if (!area.rings[r].nodes.empty()) { std::cout << std::endl; - for (size_t n=0; nrings[r].nodes.size(); n++) { - DumpIndent(ident); + for (size_t n=0; nrings[r].GetSerial(n)!=0) { - std::cout << "serial: " << area->rings[r].GetSerial(n); + if (area.rings[r].GetSerial(n)!=0) { + std::cout << "serial: " << area.rings[r].GetSerial(n); } - std::cout << " lat: " << area->rings[r].nodes[n].GetLat() << " lon: "<< area->rings[r].nodes[n].GetLon() << " }" << std::endl; + std::cout << " lat: " << area.rings[r].nodes[n].GetLat() << " lon: "<< area.rings[r].nodes[n].GetLon() << " }" << std::endl; } } - if (!area->rings[r].IsMaster()) { - ident-=2; - DumpIndent(ident); + if (!area.rings[r].IsMaster()) { + indent-=2; + DumpIndent(indent); std::cout << "}" << std::endl; } } @@ -940,14 +351,94 @@ static void DumpArea(const osmscout::AreaRef& area, std::cout << "}" << std::endl; } -int main(int argc, char* argv[]) +osmscout::CmdLineParseResult ParseArguments(int argc, char** argv, Arguments& args) { - std::string map; - std::list jobs; - std::set coordIds; + osmscout::CmdLineParser argParser("DumpData", + argc, argv); + std::vector helpArgs{"h", "help"}; + + argParser.AddOption(osmscout::CmdLineFlag([&args](const bool& value) { + args.help=value; + }), + helpArgs, + "Return argument help", + true); + + argParser.AddPositional(osmscout::CmdLineStringOption([&args](const std::string& value) { + args.map=value; + }), + "map", + "Libosmscout map directory"); + + argParser.AddOption(osmscout::CmdLineInt64TOption([&args](const int64_t& value) { + args.coordIds.insert(value); + }), + "c", + "OSM coord id"); + + argParser.AddOption(osmscout::CmdLineInt64TOption([&args](const int64_t& value) { + args.jobs.emplace_back(osmscout::osmRefNode, value); + }), + "n", + "OSM node id"); + + argParser.AddOption(osmscout::CmdLineInt64TOption([&args](const int64_t& value) { + args.jobs.emplace_back(osmscout::osmRefWay, value); + }), + "w", + "OSM way id"); + + argParser.AddOption(osmscout::CmdLineInt64TOption([&args](const int64_t& value) { + args.jobs.emplace_back(osmscout::osmRefRelation, value); + }), + "r", + "OSM relation id"); + + argParser.AddOption(osmscout::CmdLineInt64TOption([&args](const int64_t& value) { + args.routeNodeCoordIds.insert(value); + }), + "rn", + "OSM routing node id"); + + argParser.AddOption(osmscout::CmdLineUInt64TOption([&args](const uint64_t& value) { + args.jobs.emplace_back(osmscout::refNode, value); + }), + "no", + "Libosmscout node fileoffset"); + + argParser.AddOption(osmscout::CmdLineUInt64TOption([&args](const uint64_t& value) { + args.jobs.emplace_back(osmscout::refWay, value); + }), + "wo", + "Libosmscout way fileoffset"); + + argParser.AddOption(osmscout::CmdLineUInt64TOption([&args](const uint64_t& value) { + args.jobs.emplace_back(osmscout::refArea, value); + }), + "ao", + "Libosmscout area fileoffset"); + + argParser.AddOption(osmscout::CmdLineUInt64TOption([&args](const uint64_t& value) { + args.routeNodeIds.insert(value); + }), + "ri", + "Libosmscout route node id"); + + osmscout::CmdLineParseResult result=argParser.Parse(); + if (result.HasError()) { + std::cerr << "ERROR: " << result.GetErrorDescription() << std::endl; + std::cout << argParser.GetHelp() << std::endl; + } + else if (args.help) { + std::cout << argParser.GetHelp() << std::endl; + } + + return result; +} - std::set routeNodeCoordIds; - std::set routeNodeIds; +int main(int argc, char* argv[]) +{ + // Try to initialize current locale try { std::locale::global(std::locale("")); @@ -956,35 +447,37 @@ int main(int argc, char* argv[]) std::cerr << "ERROR: Cannot set locale" << std::endl; } - if (!ParseArguments(argc, - argv, - map, - coordIds, - routeNodeCoordIds, - routeNodeIds, - jobs)) { + Arguments args; + + if (osmscout::CmdLineParseResult result=ParseArguments(argc, argv, args); + result.HasError()) { return 1; } + if (args.help) { + return 0; + } + osmscout::DatabaseParameter databaseParameter; osmscout::Database database(databaseParameter); osmscout::DebugDatabaseParameter debugDatabaseParameter; osmscout::DebugDatabase debugDatabase(debugDatabaseParameter); - osmscout::RouteNodeDataFile routeNodeDataFile( - osmscout::RoutingService::GetDataFilename(osmscout::RoutingService::DEFAULT_FILENAME_BASE), - 1000); + osmscout::RouteNodeDataFile routeNodeDataFile(osmscout::RoutingService::GetDataFilename(osmscout::RoutingService::DEFAULT_FILENAME_BASE), + 1000); + + osmscout::DescriptionService descriptionService; - if (!database.Open(map)) { + if (!database.Open(args.map)) { std::cerr << "Cannot open db" << std::endl; } - if (!debugDatabase.Open(map)) { + if (!debugDatabase.Open(args.map)) { std::cerr << "Cannot open debug db" << std::endl; } if (!routeNodeDataFile.Open(database.GetTypeConfig(), - map, + args.map, true)) { std::cerr << "Cannot open routing db" << std::endl; } @@ -993,7 +486,7 @@ int main(int argc, char* argv[]) std::set osmRefs; std::set fileRefs; - for (const auto& job : jobs) { + for (const auto& job : args.jobs) { switch (job.osmRef.GetType()) { case osmscout::osmRefNone: break; @@ -1036,17 +529,21 @@ int main(int argc, char* argv[]) osmscout::CoordDataFile::ResultMap routeCoordsMap; std::unordered_map routeNodeMap; - if (!coordIds.empty()) { + // + // Load data + // - if (!debugDatabase.GetCoords(coordIds, + if (!args.coordIds.empty()) { + + if (!debugDatabase.GetCoords(args.coordIds, coordsMap)) { std::cerr << "Error whole loading coords by id" << std::endl; } } - if (!routeNodeCoordIds.empty()) { + if (!args.routeNodeCoordIds.empty()) { - if (!debugDatabase.GetCoords(routeNodeCoordIds, + if (!debugDatabase.GetCoords(args.routeNodeCoordIds, routeCoordsMap)) { std::cerr << "Error whole loading route node coords by id" << std::endl; } @@ -1101,20 +598,20 @@ int main(int argc, char* argv[]) } } - for (const auto id : routeNodeCoordIds) { + for (const auto id : args.routeNodeCoordIds) { auto coordsEntry=routeCoordsMap.find(id); if (coordsEntry!=routeCoordsMap.end()) { - routeNodeIds.insert(coordsEntry->second.GetId()); + args.routeNodeIds.insert(coordsEntry->second.GetId()); } else { std::cerr << "Cannot find route node coord with id " << id << std::endl; } } - if (!routeNodeIds.empty() && + if (!args.routeNodeIds.empty() && routeNodeDataFile.IsOpen()) { - for (const osmscout::Id id:routeNodeIds){ + for (const osmscout::Id id : args.routeNodeIds){ osmscout::RouteNodeRef node; if (!routeNodeDataFile.Get(id,node)) { std::cerr << "Error loading route nodes by id" << std::endl; @@ -1128,52 +625,53 @@ int main(int argc, char* argv[]) } } - bool firstCoord=true; - for (const auto id : coordIds) { + // + // Start of dump + // + + size_t dumpCounter=0; + + for (const auto id : args.coordIds) { auto coordsEntry=coordsMap.find(id); if (coordsEntry!=coordsMap.end()) { - if (!firstCoord) { - std::cout << std::endl; + if (dumpCounter>0) { + std::cout << "---" << std::endl; } DumpPoint(coordsEntry->first, coordsEntry->second); + dumpCounter++; } else { std::cerr << "Cannot find coord with id " << id << std::endl; } - - firstCoord=false; } - bool firstRouteNode=true; - for (const auto id : routeNodeIds) { + for (const auto id : args.routeNodeIds) { auto routeNodeEntry=routeNodeMap.find(id); if (routeNodeEntry!=routeNodeMap.end()) { - if (!firstRouteNode) { - std::cout << std::endl; + if (dumpCounter>0) { + std::cout << "---" << std::endl; } DumpRouteNode(*routeNodeEntry->second); + dumpCounter++; } else { std::cerr << "Cannot find route node with id " << id << std::endl; } - - firstRouteNode=false; } std::streamsize oldPrecision=std::cout.precision(5); std::ios_base::fmtflags oldFlags=std::cout.setf(std::ios::fixed,std::ios::floatfield); - for (std::list::const_iterator job=jobs.begin(); - job!=jobs.end(); + for (std::list::const_iterator job=args.jobs.begin(); + job!=args.jobs.end(); ++job) { - if (job!=jobs.begin() || - !coordIds.empty()) { - std::cout << std::endl; + if (dumpCounter>0) { + std::cout << "---" << std::endl; } if (job->osmRef.GetType()!=osmscout::osmRefNone) { @@ -1191,7 +689,8 @@ int main(int argc, char* argv[]) case osmscout::refNode: for (const auto &node : nodes) { if (reference->second.GetFileOffset() == node->GetFileOffset()) { - DumpNode(node, reference->first.GetId()); + DumpNode(descriptionService, *node, reference->first.GetId()); + dumpCounter++; break; } } @@ -1199,7 +698,8 @@ int main(int argc, char* argv[]) case osmscout::refArea: for (const auto &area : areas) { if (reference->second.GetFileOffset() == area->GetFileOffset()) { - DumpArea(area, reference->first.GetId()); + DumpArea(descriptionService,*area, reference->first.GetId()); + dumpCounter++; break; } } @@ -1207,7 +707,8 @@ int main(int argc, char* argv[]) case osmscout::refWay: for (const auto &way : ways) { if (reference->second.GetFileOffset() == way->GetFileOffset()) { - DumpWay(way, reference->first.GetId()); + DumpWay(descriptionService, *way, reference->first.GetId()); + dumpCounter++; break; } } @@ -1229,7 +730,8 @@ int main(int argc, char* argv[]) case osmscout::refNode: for (const auto& node : nodes) { if (reference->first.GetFileOffset()==node->GetFileOffset()) { - DumpNode(node,reference->second.GetId()); + DumpNode(descriptionService,*node,reference->second.GetId()); + dumpCounter++; break; } } @@ -1237,7 +739,8 @@ int main(int argc, char* argv[]) case osmscout::refArea: for (const auto& area : areas) { if (reference->first.GetFileOffset()==area->GetFileOffset()) { - DumpArea(area,reference->second.GetId()); + DumpArea(descriptionService,*area, reference->second.GetId()); + dumpCounter++; break; } } @@ -1245,7 +748,8 @@ int main(int argc, char* argv[]) case osmscout::refWay: for (const auto& way : ways) { if (reference->first.GetFileOffset()==way->GetFileOffset()) { - DumpWay(way,reference->second.GetId()); + DumpWay(descriptionService, *way, reference->second.GetId()); + dumpCounter++; break; } } diff --git a/Tests/meson.build b/Tests/meson.build index 92bc3d6a1..628a1dac5 100644 --- a/Tests/meson.build +++ b/Tests/meson.build @@ -651,7 +651,7 @@ WorkQueueTest = executable('WorkQueueTest', install: true, install_dir: testInstallDir) -test('Check implementation of work queue', WorkQueueTest) +test('Check implementation of work queue', WorkQueueTest, timeout: 120) WStringStringConversionTest = executable('WStringStringConversionTest', 'src/WStringStringConversionTest.cpp', diff --git a/Tests/src/HeaderCheckTest.cpp b/Tests/src/HeaderCheckTest.cpp index 4a4c46606..c9f8892d0 100644 --- a/Tests/src/HeaderCheckTest.cpp +++ b/Tests/src/HeaderCheckTest.cpp @@ -139,6 +139,10 @@ static const std::set allowedDependencies{ "osmscout.navigation => osmscout.location", "osmscout.navigation => osmscout.routing", "osmscout.navigation => osmscout", // Fix this + "osmscout.description => osmscout.lib", + "osmscout.description => osmscout.system", + "osmscout.description => osmscout", + "osmscout.description => osmscout.feature", "osmscoutclient => osmscoutclient.json", "osmscoutclient => osmscoutclient.private", diff --git a/libosmscout/CMakeLists.txt b/libosmscout/CMakeLists.txt index 0815c4e01..22c4756e4 100644 --- a/libosmscout/CMakeLists.txt +++ b/libosmscout/CMakeLists.txt @@ -43,6 +43,10 @@ set(HEADER_FILES_ASYNC include/osmscout/async/Worker.h include/osmscout/async/WorkQueue.h) +set(HEADER_FILES_DESCRIPTION + include/osmscout/description/DescriptionService.h +) + set(HEADER_FILES_FEATURE include/osmscout/feature/AccessFeature.h include/osmscout/feature/AccessRestrictedFeature.h @@ -224,6 +228,7 @@ set(SOURCE_FILES src/osmscout/async/Thread.cpp src/osmscout/async/Worker.cpp src/osmscout/async/WorkQueue.cpp + src/osmscout/description/DescriptionService.cpp src/osmscout/feature/AccessFeature.cpp src/osmscout/feature/AccessRestrictedFeature.cpp src/osmscout/feature/AddressFeature.cpp @@ -385,6 +390,7 @@ set(HEADER_FILES ${HEADER_FILES_LOG} ${HEADER_FILES_CLI} ${HEADER_FILES_ASYNC} + ${HEADER_FILES_DESCRIPTION} ${HEADER_FILES_FEATURE} ${HEADER_FILES_IO} ${HEADER_FILES_DB} diff --git a/libosmscout/include/meson.build b/libosmscout/include/meson.build index 36491178e..c92fa2cb7 100644 --- a/libosmscout/include/meson.build +++ b/libosmscout/include/meson.build @@ -14,6 +14,7 @@ osmscoutHeader = [ 'osmscout/async/Thread.h', 'osmscout/async/Worker.h', 'osmscout/async/WorkQueue.h', + 'osmscout/description/DescriptionService.h', 'osmscout/feature/AccessFeature.h', 'osmscout/feature/AccessRestrictedFeature.h', 'osmscout/feature/AddressFeature.h', diff --git a/libosmscout/include/osmscout/cli/CmdLineParsing.h b/libosmscout/include/osmscout/cli/CmdLineParsing.h index aac3623cf..9688343ec 100644 --- a/libosmscout/include/osmscout/cli/CmdLineParsing.h +++ b/libosmscout/include/osmscout/cli/CmdLineParsing.h @@ -306,6 +306,18 @@ namespace osmscout { return std::make_shared>(std::forward(args)...); } + template + CmdLineArgParserRef CmdLineInt64TOption(Args&& ...args) + { + return std::make_shared>(std::forward(args)...); + } + + template + CmdLineArgParserRef CmdLineUInt64TOption(Args&& ...args) + { + return std::make_shared>(std::forward(args)...); + } + template CmdLineArgParserRef CmdLineDoubleOption(Args&& ...args) { diff --git a/libosmscout/include/osmscout/description/DescriptionService.h b/libosmscout/include/osmscout/description/DescriptionService.h new file mode 100644 index 000000000..d3bf5931a --- /dev/null +++ b/libosmscout/include/osmscout/description/DescriptionService.h @@ -0,0 +1,439 @@ +/* + This source is part of the libosmscout library + Copyright (C) 2024 Tim Teulings + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef OSMSCOUT_DESCRIPTIONSERVICE_H +#define OSMSCOUT_DESCRIPTIONSERVICE_H + +#include + +#include + +#include +#include +#include + +namespace osmscout { + /** + * \defgroup Description Description + * + * Classes and functions for structured descriptions of objects on the map. + */ + + /** + * ingroup Description + * + * An information set as part of the description + */ + class OSMSCOUT_API DescriptionEntry CLASS_FINAL + { + private: + std::string sectionKey; + std::string subsectionKey; + bool hasIndex; + size_t index; + std::string labelKey; + std::string value; + + public: + DescriptionEntry(const std::string& sectionKey, + const std::string& labelKey, + const std::string& value); + + DescriptionEntry(const std::string& sectionKey, + const std::string& subsectionKey, + const std::string& labelKey, + const std::string& value); + + DescriptionEntry(const std::string& sectionKey, + const std::string& subsectionKey, + size_t index, + const std::string& labelKey, + const std::string& value); + + std::string GetSectionKey() const { + return sectionKey; + } + + bool HasSubsection() const { + return !subsectionKey.empty(); + } + + bool HasIndex() const { + return hasIndex; + } + + size_t GetIndex() const { + return index; + } + + std::string GetSubsectionKey() const { + return subsectionKey; + } + + std::string GetLabelKey() const { + return labelKey; + } + + std::string GetValue() const { + return value; + } + }; + + /** + * ingroup Description + * + * Class, providing a number of information for an object + */ + class OSMSCOUT_API ObjectDescription CLASS_FINAL + { + private: + std::list entries; + + public: + ObjectDescription(); + + void AddEntry(const DescriptionEntry& entry) + { + entries.push_back(entry); + } + + const std::list& GetEntries() const + { + return entries; + } + }; + + /** + * ingroup Description + * + * Interface to be implemented by the individual processors. + */ + class OSMSCOUT_API FeatureToDescriptionProcessor + { + protected: + FeatureValue* GetFeatureValue(const FeatureValueBuffer& buffer, + const std::string& featureName) const; + public: + FeatureToDescriptionProcessor() = default; + virtual ~FeatureToDescriptionProcessor(); + + virtual void Process(const FeatureValueBuffer& buffer, + ObjectDescription& description) = 0; + }; + + /** + * ingroup Description + */ + using FeatureToDescriptionProcessorRef = std::shared_ptr; + + /** + * ingroup Description + * + * General information, likely available for most of the objects + */ + class GeneralDescriptionProcessor : public FeatureToDescriptionProcessor + { + public: + static const std::string SECTION_NAME_GENERAL; + + static const std::string LABEL_KEY_NAME_TYPE; + static const std::string LABEL_KEY_NAME_NAME; + static const std::string LABEL_KEY_NAME_NAME_ALT; + static const std::string LABEL_KEY_NAME_NAME_SHORT; + static const std::string LABEL_KEY_NAME_NAME_REF; + static const std::string LABEL_KEY_NAME_NAME_CONSTRUCTIONYEAR; + + public: + void Process(const FeatureValueBuffer& buffer, + ObjectDescription& description) override; + }; + + /** + * ingroup Description + * + * Geometric information + */ + class GeometryDescriptionProcessor : public FeatureToDescriptionProcessor + { + public: + static const std::string SECTION_NAME_GEOMETRY; + + static const std::string LABEL_KEY_GEOMETRY_COORDINATE; + static const std::string LABEL_KEY_GEOMETRY_BOUNDINGBOX; + static const std::string LABEL_KEY_GEOMETRY_CENTER; + static const std::string LABEL_KEY_GEOMETRY_CELLLEVEL; + static const std::string LABEL_KEY_GEOMETRY_LAYER; + static const std::string LABEL_KEY_GEOMETRY_ISIN; + + public: + void Process(const FeatureValueBuffer& buffer, + ObjectDescription& description) override; + }; + + /** + * ingroup Description + * + * Information regarding the human-defined location of the object + */ + class LocationDescriptionProcessor : public FeatureToDescriptionProcessor + { + public: + static const std::string SECTION_NAME_LOCATION; + + static const std::string SUBSECTION_NAME_LOCATION_ADMINLEVEL; + + static const std::string LABEL_KEY_LOCATION_ADDRESS; + static const std::string LABEL_KEY_LOCATION_LOCATION; + static const std::string LABEL_KEY_LOCATION_POSTALCODE; + + static const std::string LABEL_KEY_LOCATION_ADMINLEVEL_LEVEL; + static const std::string LABEL_KEY_LOCATION_ADMINLEVEL_ISIN; + + public: + void Process(const FeatureValueBuffer& buffer, + ObjectDescription& description) override; + }; + + /** + * ingroup Description + * + * All information regarding ways, their structure, grade and accessibility, + */ + class WayDescriptionProcessor : public FeatureToDescriptionProcessor + { + public: + static const std::string SECTION_NAME_WAY; + + static const std::string SUBSECTION_NAME_WAY_LANES; + static const std::string SUBSECTION_NAME_WAY_SIDEWAYS; + static const std::string SUBSECTION_NAME_WAY_ACCESS; + static const std::string SUBSECTION_NAME_WAY_ACCESSRESTRICTED; + + static const std::string LABEL_KEY_WAY_BRIDGE; + static const std::string LABEL_KEY_WAY_TUNNEL; + static const std::string LABEL_KEY_WAY_ROUNDABOUT; + static const std::string LABEL_KEY_WAY_EMBANKMENT; + static const std::string LABEL_KEY_WAY_MAXSPEED; + static const std::string LABEL_KEY_WAY_GRADE; + static const std::string LABEL_KEY_WAY_WIDTH; + static const std::string LABEL_KEY_WAY_CLOCKWISE; + + static const std::string LABEL_KEY_WAY_LANES_LANES; + static const std::string LABEL_KEY_WAY_LANES_LANESFORWARD; + static const std::string LABEL_KEY_WAY_LANES_LANESBACKWARD; + static const std::string LABEL_KEY_WAY_LANES_TURNFORWARD; + static const std::string LABEL_KEY_WAY_LANES_TURNBACKWARD; + static const std::string LABEL_KEY_WAY_LANES_DESTINATIONFORWARD; + static const std::string LABEL_KEY_WAY_LANES_DESTINATIONBACKWARD; + + static const std::string LABEL_KEY_WAY_SIDEWAYS_CYCLELANE; + static const std::string LABEL_KEY_WAY_SIDEWAYS_CYCLETRACK; + static const std::string LABEL_KEY_WAY_SIDEWAYS_WALKTRACK; + + static const std::string LABEL_KEY_WAY_ACCESS_ONEWAY; + static const std::string LABEL_KEY_WAY_ACCESS_FOOT; + static const std::string LABEL_KEY_WAY_ACCESS_BICYCLE; + static const std::string LABEL_KEY_WAY_ACCESS_CAR; + + static const std::string LABEL_KEY_WAY_ACCESSRESTRICTED_FOOT; + static const std::string LABEL_KEY_WAY_ACCESSRESTRICTED_BICYCLE; + static const std::string LABEL_KEY_WAY_ACCESSRESTRICTED_CAR; + + private: + void HandlesLanesFeature(const FeatureValueBuffer &buffer, ObjectDescription &description); + void HandleSidewayFeature(const FeatureValueBuffer &buffer, ObjectDescription &description); + void HandleAccessFeature(const FeatureValueBuffer &buffer, ObjectDescription &description); + void HandelAccessRestricted(const FeatureValueBuffer &buffer, ObjectDescription &description); + + public: + void Process(const FeatureValueBuffer& buffer, + ObjectDescription& description) override; + }; + + /** + * ingroup Description + * + * Information regarding following a defined route + */ + class RoutingDescriptionProcessor : public FeatureToDescriptionProcessor + { + public: + static const std::string SECTION_NAME_ROUTING; + + static const std::string LABEL_KEY_ROUTING_FROM; + static const std::string LABEL_KEY_ROUTING_TO; + static const std::string LABEL_KEY_ROUTING_DESTINATION; + + public: + void Process(const FeatureValueBuffer& buffer, + ObjectDescription& description) override; + }; + + /** + * ingroup Description + * + * Information regarding companies involved in the object + */ + class CommercialDescriptionProcessor : public FeatureToDescriptionProcessor + { + public: + static const std::string SECTION_NAME_COMMERCIAL; + + static const std::string LABEL_KEY_COMMERCIAL_BRAND; + static const std::string LABEL_KEY_COMMERCIAL_OPERATOR; + static const std::string LABEL_KEY_COMMERCIAL_NETWORK; + + public: + void Process(const FeatureValueBuffer& buffer, + ObjectDescription& description) override; + }; + + /** + * ingroup Description + * + * Information regarding payment + */ + class PaymentDescriptionProcessor : public FeatureToDescriptionProcessor + { + public: + static const std::string SECTION_NAME_PAYMENT; + + static const std::string SUBSECTION_NAME_PAYMENT_FEE; + + static const std::string LABEL_KEY_PAYMENT_FEE_VALUE; + static const std::string LABEL_KEY_PAYMENT_FEE_CONDITION; + + public: + void Process(const FeatureValueBuffer& buffer, + ObjectDescription& description) override; + }; + + /** + * ingroup Description + * + * Information regarding charging of cars, bikes and similar + */ + class ChargingStationDescriptionProcessor : public FeatureToDescriptionProcessor + { + public: + static const std::string SECTION_NAME_CHARGINGSTATION; + + static const std::string SUBSECTION_NAME_CHARGINGSTATION_SOCKET; + + static const std::string LABEL_KEY_CHARGINGSTATION_SOCKET_TYPE; + static const std::string LABEL_KEY_CHARGINGSTATION_SOCKET_CAPACITY; + static const std::string LABEL_KEY_CHARGINGSTATION_SOCKET_OUTPUT; + + public: + void Process(const FeatureValueBuffer& buffer, + ObjectDescription& description) override; + }; + + /** + * ingroup Description + * + * Information regarding staying at the object + */ + class PresenceDescriptionProcessor : public FeatureToDescriptionProcessor + { + public: + static const std::string SECTION_NAME_PRESENCE; + + static const std::string SUBSECTION_NAME_PRESENCE_MAXSTAY; + + static const std::string LABEL_KEY_PRESENCE_MAXSTAY_CONDITION; + static const std::string LABEL_KEY_PRESENCE_MAXSTAY_VALUE; + + static const std::string LABEL_KEY_PRESENCE_OPENINGHOURS; + + public: + void Process(const FeatureValueBuffer& buffer, + ObjectDescription& description) override; + }; + + /** + * ingroup Description + * + * Contact information + */ + class ContactDescriptionProcessor : public FeatureToDescriptionProcessor + { + public: + static const std::string SECTION_NAME_CONTACT; + + static const std::string LABEL_KEY_CONTACT_PHONE; + static const std::string LABEL_KEY_CONTACT_WEBSIZE; + + public: + void Process(const FeatureValueBuffer& buffer, + ObjectDescription& description) override; + }; + + /** + * Service,to get a structured description of an object on the map (Area, Way or Node). + * Explicitly designed, to offer information within map popup dialogs or similar. + * + * Information is return as an ObjectDescription object. + * + * The ObjectDescription is more or less a list of DescriptionEntry instances. + * + * Each DescriptionEntry holds the following information: + * * A Section name + * * An optional subsection name + * * An optional index, in case where a subsection has multiple instances + * * a name of a key + * * a value (always a string) + * + * Section, subsection and key names should be defined, that they represent english + * names and could be directly used in the UI. However, they could also be used as key + * into a localisation service. + * + * Information is gathered by a list of processors, inheriting the FeatureToDescriptionProcessor + * interface. + * + * The processors extract information mainly from the FeatureValueBuffer instance of the object. + */ + class OSMSCOUT_API DescriptionService CLASS_FINAL + { + public: + static const std::string SECTION_NAME_ID; + + static const std::string LABEL_KEY_ID_KIND; + static const std::string LABEL_KEY_ID_ID; + + private: + std::list featureProcessors; + + void GetDescription(const FeatureValueBuffer& buffer, + ObjectDescription& description) const; + + public: + DescriptionService(); + + ObjectDescription GetDescription(const FeatureValueBuffer& buffer) const; + + ObjectDescription GetDescription(const Area& area) const; + ObjectDescription GetDescription(const Way& way) const; + ObjectDescription GetDescription(const Node& node) const; + }; + + using DescriptionServiceRef = std::shared_ptr; +} + +#endif // OSMSCOUT_DESCRIPTIONSERVICE_H \ No newline at end of file diff --git a/libosmscout/src/meson.build b/libosmscout/src/meson.build index 25193058c..68edab192 100644 --- a/libosmscout/src/meson.build +++ b/libosmscout/src/meson.build @@ -9,6 +9,7 @@ osmscoutSrc = [ 'src/osmscout/async/Thread.cpp', 'src/osmscout/async/Worker.cpp', 'src/osmscout/async/WorkQueue.cpp', + 'src/osmscout/description/DescriptionService.cpp', 'src/osmscout/feature/AccessFeature.cpp', 'src/osmscout/feature/AccessRestrictedFeature.cpp', 'src/osmscout/feature/AddressFeature.cpp', diff --git a/libosmscout/src/osmscout/description/DescriptionService.cpp b/libosmscout/src/osmscout/description/DescriptionService.cpp new file mode 100644 index 000000000..67745a514 --- /dev/null +++ b/libosmscout/src/osmscout/description/DescriptionService.cpp @@ -0,0 +1,902 @@ +/* + This source is part of the libosmscout library + Copyright (C) 2024 Tim Teulings + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace osmscout { + static uint32_t CalculateCellLevel(const osmscout::GeoBox& boundingBox) + { + uint32_t level=25; + while (true) { + if (boundingBox.GetWidth()<=osmscout::cellDimension[level].width && + boundingBox.GetHeight()<=osmscout::cellDimension[level].height) { + break; + } + + if (level==0) { + break; + } + + level--; + } + + return level; + } + + DescriptionEntry::DescriptionEntry(const std::string& sectionKey, + const std::string& labelKey, + const std::string& value) + : sectionKey(sectionKey), + hasIndex(false), + index(0), + labelKey(labelKey), + value(value) + { + // no code + } + + DescriptionEntry::DescriptionEntry(const std::string& sectionKey, + const std::string& subsectionKey, + const std::string& labelKey, + const std::string& value) + : sectionKey(sectionKey), + subsectionKey(subsectionKey), + hasIndex(false), + index(0), + labelKey(labelKey), + value(value) + { + // no code + } + + DescriptionEntry::DescriptionEntry(const std::string& sectionKey, + const std::string& subsectionKey, + size_t index, + const std::string& labelKey, + const std::string& value) +: sectionKey(sectionKey), + subsectionKey(subsectionKey), + hasIndex(true), + index(index), + labelKey(labelKey), + value(value) + { + // no code + } + + ObjectDescription::ObjectDescription() + { + // no code + } + + FeatureToDescriptionProcessor::~FeatureToDescriptionProcessor() + { + // no code + } + + FeatureValue* FeatureToDescriptionProcessor::GetFeatureValue(const FeatureValueBuffer& buffer, + const std::string &featureName) const + { + if (size_t featureIdx=0; + buffer.GetType()->GetFeature(featureName,featureIdx) && + buffer.HasFeature(featureIdx)) { + return buffer.GetValue(featureIdx); + } + + return nullptr; + } + + + const std::string GeneralDescriptionProcessor::SECTION_NAME_GENERAL = "General"; + + const std::string GeneralDescriptionProcessor::LABEL_KEY_NAME_TYPE = "Type"; + const std::string GeneralDescriptionProcessor::LABEL_KEY_NAME_NAME = "Name"; + const std::string GeneralDescriptionProcessor::LABEL_KEY_NAME_NAME_ALT = "NameAlt"; + const std::string GeneralDescriptionProcessor::LABEL_KEY_NAME_NAME_SHORT = "NameShort"; + const std::string GeneralDescriptionProcessor::LABEL_KEY_NAME_NAME_REF = "NameRef"; + const std::string GeneralDescriptionProcessor::LABEL_KEY_NAME_NAME_CONSTRUCTIONYEAR = "ConstructionYear"; + + void GeneralDescriptionProcessor::Process(const FeatureValueBuffer &buffer, ObjectDescription &description) + { + description.AddEntry(DescriptionEntry(SECTION_NAME_GENERAL, + LABEL_KEY_NAME_TYPE, + buffer.GetType()->GetName())); + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,NameFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_GENERAL, + LABEL_KEY_NAME_NAME, + value->GetName())); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,NameAltFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_GENERAL, + LABEL_KEY_NAME_NAME_ALT, + value->GetNameAlt())); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,NameShortFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_GENERAL, + LABEL_KEY_NAME_NAME_SHORT, + value->GetNameShort())); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,RefFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_GENERAL, + LABEL_KEY_NAME_NAME_REF, + value->GetRef())); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,ConstructionYearFeature::NAME)); + value!=nullptr) { + std::string text; + + if (value->GetStartYear()==value->GetEndYear()) { + text=std::to_string(value->GetStartYear()); + } + else { + text=std::to_string(value->GetStartYear())+"-"+std::to_string(value->GetEndYear()); + } + + description.AddEntry(DescriptionEntry(SECTION_NAME_GENERAL, + LABEL_KEY_NAME_NAME_CONSTRUCTIONYEAR, + text)); + } + } + + const std::string GeometryDescriptionProcessor::SECTION_NAME_GEOMETRY = "Geometry"; + + const std::string GeometryDescriptionProcessor::LABEL_KEY_GEOMETRY_COORDINATE = "Coordinate"; + const std::string GeometryDescriptionProcessor::LABEL_KEY_GEOMETRY_BOUNDINGBOX = "BoundingBox"; + const std::string GeometryDescriptionProcessor::LABEL_KEY_GEOMETRY_CENTER = "Center"; + const std::string GeometryDescriptionProcessor::LABEL_KEY_GEOMETRY_CELLLEVEL = "CellLevel"; + const std::string GeometryDescriptionProcessor::LABEL_KEY_GEOMETRY_LAYER = "Layer"; + const std::string GeometryDescriptionProcessor::LABEL_KEY_GEOMETRY_ISIN = "IsIn"; + + void GeometryDescriptionProcessor::Process(const FeatureValueBuffer &buffer, ObjectDescription &description) { + if (const auto *value = dynamic_cast(GetFeatureValue(buffer, BrandFeature::NAME)); + value != nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_GEOMETRY, + LABEL_KEY_GEOMETRY_LAYER, + std::to_string(value->GetLayer()))); + } + + if (const auto *value = dynamic_cast(GetFeatureValue(buffer, IsInFeature::NAME)); + value != nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_GEOMETRY, + LABEL_KEY_GEOMETRY_ISIN, + value->GetIsIn())); + } + } + + const std::string WayDescriptionProcessor::SECTION_NAME_WAY = "Way"; + + const std::string WayDescriptionProcessor::SUBSECTION_NAME_WAY_LANES = "Lanes"; + const std::string WayDescriptionProcessor::SUBSECTION_NAME_WAY_SIDEWAYS = "Sideways"; + const std::string WayDescriptionProcessor::SUBSECTION_NAME_WAY_ACCESS = "Access"; + const std::string WayDescriptionProcessor::SUBSECTION_NAME_WAY_ACCESSRESTRICTED = "AccessRestricted"; + + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_BRIDGE = "Bridge"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_TUNNEL = "Tunnel"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_ROUNDABOUT = "Roundabout"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_EMBANKMENT = "Embankment"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_MAXSPEED = "MaxSpeed"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_GRADE = "Grade"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_WIDTH = "Width"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_CLOCKWISE = "Clockwise"; + + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_LANES_LANES = "Lanes"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_LANES_LANESFORWARD = "LanesForward"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_LANES_LANESBACKWARD = "LanesBackward"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_LANES_TURNFORWARD = "TurnForward"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_LANES_TURNBACKWARD = "TurnBackward"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_LANES_DESTINATIONFORWARD = "DestinationForward"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_LANES_DESTINATIONBACKWARD = "DestinationBackward"; + + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_SIDEWAYS_CYCLELANE = "CycleLane"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_SIDEWAYS_CYCLETRACK = "CycleTrack"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_SIDEWAYS_WALKTRACK = "WalkTrack"; + + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_ACCESS_ONEWAY = "Oneway"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_ACCESS_FOOT = "Foot"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_ACCESS_BICYCLE = "Bicycle"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_ACCESS_CAR = "Car"; + + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_ACCESSRESTRICTED_FOOT = "Foot"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_ACCESSRESTRICTED_BICYCLE = "Bicycle"; + const std::string WayDescriptionProcessor::LABEL_KEY_WAY_ACCESSRESTRICTED_CAR = "Car"; + + void WayDescriptionProcessor::HandlesLanesFeature(const FeatureValueBuffer &buffer, ObjectDescription &description) { + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,LanesFeature::NAME)); + value!=nullptr) { + if (value->HasSingleLane()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_LANES, + LABEL_KEY_WAY_LANES_LANES, + "1")); + } + else { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_LANES, + LABEL_KEY_WAY_LANES_LANESFORWARD, + std::to_string(value->GetForwardLanes()))); + + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_LANES, + LABEL_KEY_WAY_LANES_LANESBACKWARD, + std::to_string(value->GetBackwardLanes()))); + } + + if (!value->GetTurnForward().empty()) { + std::string text; + + for (const auto& turn : value->GetTurnForward() | + std::views::transform([](const auto& turn) {return LaneTurnString(turn);})) { + if (!text.empty()) { + text+=" "+turn; + } + else { + text=turn; + } + } + + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_LANES, + LABEL_KEY_WAY_LANES_TURNFORWARD, + text)); + + } + + if (!value->GetTurnBackward().empty()) { + std::string text; + + for (const auto& turn : value->GetTurnBackward() | + std::views::transform([](const auto& turn) {return LaneTurnString(turn);})) { + if (!text.empty()) { + text+=" "+turn; + } + else { + text=turn; + } + } + + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_LANES, + LABEL_KEY_WAY_LANES_TURNBACKWARD, + text)); + + } + + if (!value->GetDestinationForward().empty()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_LANES, + LABEL_KEY_WAY_LANES_DESTINATIONFORWARD, + value->GetDestinationForward())); + } + + if (!value->GetDestinationBackward().empty()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_LANES, + LABEL_KEY_WAY_LANES_DESTINATIONBACKWARD, + value->GetDestinationBackward())); + } + } + } + + void WayDescriptionProcessor::HandleSidewayFeature(const FeatureValueBuffer &buffer, ObjectDescription &description) { + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,SidewayFeature::NAME)); + value!=nullptr) { + if (value->HasCyclewayLaneLeft() || value->HasCyclewayLaneRight()) { + std::string text; + + if (value->HasCyclewayLaneLeft() && value->HasCyclewayLaneRight()) { + text="both"; + } + else if (value->HasCyclewayLaneLeft()) { + text="left"; + } + else { + text="right"; + } + + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_SIDEWAYS, + LABEL_KEY_WAY_SIDEWAYS_CYCLELANE, + text)); + } + + if (value->HasCyclewayTrackLeft() || value->HasCyclewayTrackRight()) { + std::string text; + + if (value->HasCyclewayTrackLeft() && value->HasCyclewayTrackRight()) { + text="both"; + } + else if (value->HasCyclewayTrackLeft()) { + text="left"; + } + else { + text="right"; + } + + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_SIDEWAYS, + LABEL_KEY_WAY_SIDEWAYS_CYCLETRACK, + text)); + } + + if (value->HasSidewalkTrackLeft() || value->HasSidewalkTrackRight()) { + std::string text; + + if (value->HasSidewalkTrackLeft() && value->HasSidewalkTrackRight()) { + text="both"; + } + else if (value->HasSidewalkTrackLeft()) { + text="left"; + } + else { + text="right"; + } + + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_SIDEWAYS, + LABEL_KEY_WAY_SIDEWAYS_WALKTRACK, + text)); + } + } + } + + void WayDescriptionProcessor::HandleAccessFeature(const FeatureValueBuffer &buffer, ObjectDescription &description) { + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,AccessFeature::NAME)); + value!=nullptr) { + std::string onewayText; + std::string footText; + std::string bicycleText; + std::string carText; + + if (value->IsOnewayForward()) { + onewayText="forward"; + } + else if (value->IsOnewayBackward()) { + onewayText="backward"; + } + + if (value->CanRouteFootForward() && value->CanRouteFootBackward()) { + footText="both"; + } + else if (value->CanRouteFootForward()) { + footText="forward"; + } + else if (value->CanRouteFootBackward()) { + footText="backward"; + } + + if (value->CanRouteBicycleForward() && value->CanRouteBicycleBackward()) { + bicycleText="both"; + } + else if (value->CanRouteBicycleForward()) { + bicycleText="forward"; + } + else if (value->CanRouteBicycleBackward()) { + bicycleText="backward"; + } + + if (value->CanRouteCarForward() && value->CanRouteCarBackward()) { + carText="both"; + } + else if (value->CanRouteCarForward()) { + carText="forward"; + } + else if (value->CanRouteCarBackward()) { + carText="backward"; + } + + if (!onewayText.empty()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_ACCESS, + LABEL_KEY_WAY_ACCESS_ONEWAY, + onewayText)); + } + + if (!footText.empty()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_ACCESS, + LABEL_KEY_WAY_ACCESS_FOOT, + footText)); + } + + if (!bicycleText.empty()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_ACCESS, + LABEL_KEY_WAY_ACCESS_BICYCLE, + bicycleText)); + } + + if (!carText.empty()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_ACCESS, + LABEL_KEY_WAY_ACCESS_CAR, + carText)); + } + } + } + + void WayDescriptionProcessor::HandelAccessRestricted(const FeatureValueBuffer &buffer, ObjectDescription &description) { + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,AccessRestrictedFeature::NAME)); + value!=nullptr) { + if (!value->CanAccessFoot()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_ACCESSRESTRICTED, + LABEL_KEY_WAY_ACCESSRESTRICTED_FOOT, + "true")); + } + if (!value->CanAccessBicycle()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_ACCESSRESTRICTED, + LABEL_KEY_WAY_ACCESSRESTRICTED_BICYCLE, + "true")); + } + if (!value->CanAccessCar()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + SUBSECTION_NAME_WAY_ACCESSRESTRICTED, + LABEL_KEY_WAY_ACCESSRESTRICTED_CAR, + "true")); + } + } + } + + void WayDescriptionProcessor::Process(const FeatureValueBuffer &buffer, ObjectDescription &description) { + if (GetFeatureValue(buffer,BridgeFeature::NAME)!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + LABEL_KEY_WAY_BRIDGE, + "true")); + } + + if (GetFeatureValue(buffer,TunnelFeature::NAME)!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + LABEL_KEY_WAY_TUNNEL, + "true")); + } + + if (GetFeatureValue(buffer,RoundaboutFeature::NAME)!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + LABEL_KEY_WAY_ROUNDABOUT, + "true")); + } + + if (GetFeatureValue(buffer,EmbankmentFeature::NAME)!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + LABEL_KEY_WAY_EMBANKMENT, + "true")); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,MaxSpeedFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + LABEL_KEY_WAY_MAXSPEED, + std::to_string(value->GetMaxSpeed()))); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,GradeFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + LABEL_KEY_WAY_GRADE, + std::to_string(value->GetGrade()))); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,WidthFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + LABEL_KEY_WAY_WIDTH, + std::to_string(value->GetWidth()))); + } + + if (GetFeatureValue(buffer,ClockwiseDirectionFeature::NAME)!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_WAY, + LABEL_KEY_WAY_CLOCKWISE, + "true")); + } + + HandlesLanesFeature(buffer, description); + HandleSidewayFeature(buffer, description); + HandleAccessFeature(buffer, description); + HandelAccessRestricted(buffer, description); + } + + const std::string LocationDescriptionProcessor::SECTION_NAME_LOCATION = "Location"; + + const std::string LocationDescriptionProcessor::SUBSECTION_NAME_LOCATION_ADMINLEVEL = "AdminLevel"; + + const std::string LocationDescriptionProcessor::LABEL_KEY_LOCATION_ADDRESS = "Address"; + const std::string LocationDescriptionProcessor::LABEL_KEY_LOCATION_LOCATION = "Location"; + const std::string LocationDescriptionProcessor::LABEL_KEY_LOCATION_POSTALCODE = "PostalCode"; + + const std::string LocationDescriptionProcessor::LABEL_KEY_LOCATION_ADMINLEVEL_LEVEL = "Level"; + const std::string LocationDescriptionProcessor::LABEL_KEY_LOCATION_ADMINLEVEL_ISIN = "IsIn"; + + void LocationDescriptionProcessor::Process(const FeatureValueBuffer &buffer, ObjectDescription &description) + { + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,AddressFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_LOCATION, + LABEL_KEY_LOCATION_ADDRESS, + value->GetAddress())); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,LocationFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_LOCATION, + LABEL_KEY_LOCATION_LOCATION, + value->GetLocation())); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,PostalCodeFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_LOCATION, + LABEL_KEY_LOCATION_POSTALCODE, + value->GetPostalCode())); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,AdminLevelFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_LOCATION, + SUBSECTION_NAME_LOCATION_ADMINLEVEL, + LABEL_KEY_LOCATION_ADMINLEVEL_LEVEL, + std::to_string(value->GetAdminLevel()))); + + if (!value->GetIsIn().empty()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_LOCATION, + SUBSECTION_NAME_LOCATION_ADMINLEVEL, + LABEL_KEY_LOCATION_ADMINLEVEL_ISIN, + value->GetIsIn())); + } + } + } + + const std::string RoutingDescriptionProcessor::SECTION_NAME_ROUTING = "Navigation"; + + const std::string RoutingDescriptionProcessor::LABEL_KEY_ROUTING_FROM = "From"; + const std::string RoutingDescriptionProcessor::LABEL_KEY_ROUTING_TO = "To"; + const std::string RoutingDescriptionProcessor::LABEL_KEY_ROUTING_DESTINATION = "Destination"; + + void RoutingDescriptionProcessor::Process(const FeatureValueBuffer &buffer, ObjectDescription &description) + { + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,FromToFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_ROUTING, + LABEL_KEY_ROUTING_FROM, + value->GetFrom())); + description.AddEntry(DescriptionEntry(SECTION_NAME_ROUTING, + LABEL_KEY_ROUTING_TO, + value->GetTo())); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,DestinationFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_ROUTING, + LABEL_KEY_ROUTING_DESTINATION, + value->GetDestination())); + } + } + + const std::string CommercialDescriptionProcessor::SECTION_NAME_COMMERCIAL = "Commercial"; + + const std::string CommercialDescriptionProcessor::LABEL_KEY_COMMERCIAL_BRAND = "Brand"; + const std::string CommercialDescriptionProcessor::LABEL_KEY_COMMERCIAL_OPERATOR = "Operator"; + const std::string CommercialDescriptionProcessor::LABEL_KEY_COMMERCIAL_NETWORK = "Network"; + + void CommercialDescriptionProcessor::Process(const FeatureValueBuffer &buffer, ObjectDescription &description) + { + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,BrandFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_COMMERCIAL, + LABEL_KEY_COMMERCIAL_BRAND, + value->GetName())); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,OperatorFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_COMMERCIAL, + LABEL_KEY_COMMERCIAL_OPERATOR, + value->GetOperator())); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,NetworkFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_COMMERCIAL, + LABEL_KEY_COMMERCIAL_NETWORK, + value->GetNetwork())); + } + } + + const std::string PaymentDescriptionProcessor::SECTION_NAME_PAYMENT = "Payment"; + + const std::string PaymentDescriptionProcessor::SUBSECTION_NAME_PAYMENT_FEE = "Fee"; + + const std::string PaymentDescriptionProcessor::LABEL_KEY_PAYMENT_FEE_VALUE = "Value"; + const std::string PaymentDescriptionProcessor::LABEL_KEY_PAYMENT_FEE_CONDITION = "Condition"; + + void PaymentDescriptionProcessor::Process(const FeatureValueBuffer &buffer, ObjectDescription &description) + { + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,FeeFeature::NAME)); + value!=nullptr) { + if (value->HasCondition()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_PAYMENT, + SUBSECTION_NAME_PAYMENT_FEE, + LABEL_KEY_PAYMENT_FEE_CONDITION, + value->GetCondition())); + } + + description.AddEntry(DescriptionEntry(SECTION_NAME_PAYMENT, + SUBSECTION_NAME_PAYMENT_FEE, + LABEL_KEY_PAYMENT_FEE_VALUE, + EnumToString(value->GetValue()))); + } + } + + const std::string ChargingStationDescriptionProcessor::SECTION_NAME_CHARGINGSTATION = "ChargingStation"; + + const std::string ChargingStationDescriptionProcessor::SUBSECTION_NAME_CHARGINGSTATION_SOCKET="Socket"; + + const std::string ChargingStationDescriptionProcessor::LABEL_KEY_CHARGINGSTATION_SOCKET_TYPE="Type"; + const std::string ChargingStationDescriptionProcessor::LABEL_KEY_CHARGINGSTATION_SOCKET_CAPACITY="Capacity"; + const std::string ChargingStationDescriptionProcessor::LABEL_KEY_CHARGINGSTATION_SOCKET_OUTPUT="Output"; + + void ChargingStationDescriptionProcessor::Process(const FeatureValueBuffer &buffer, ObjectDescription &description) { + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,ChargingStationFeature::NAME)); + value!=nullptr) { + if (value->HasSockets()) { + size_t index=0; + + for (const auto& socket : value->GetSockets()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_CHARGINGSTATION, + SUBSECTION_NAME_CHARGINGSTATION_SOCKET, + index, + LABEL_KEY_CHARGINGSTATION_SOCKET_TYPE, + EnumToString(socket.type))); + + if (socket.capacity!=0) { + description.AddEntry(DescriptionEntry(SECTION_NAME_CHARGINGSTATION, + SUBSECTION_NAME_CHARGINGSTATION_SOCKET, + index, + LABEL_KEY_CHARGINGSTATION_SOCKET_CAPACITY, + std::to_string(socket.capacity))); + } + + if (!socket.output.empty()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_CHARGINGSTATION, + SUBSECTION_NAME_CHARGINGSTATION_SOCKET, + index, + LABEL_KEY_CHARGINGSTATION_SOCKET_OUTPUT, + socket.output)); + } + } + } + } + } + + const std::string PresenceDescriptionProcessor::SECTION_NAME_PRESENCE = "Presence"; + + const std::string PresenceDescriptionProcessor::SUBSECTION_NAME_PRESENCE_MAXSTAY="MaxStay"; + + const std::string PresenceDescriptionProcessor::LABEL_KEY_PRESENCE_MAXSTAY_CONDITION="Condition"; + const std::string PresenceDescriptionProcessor::LABEL_KEY_PRESENCE_MAXSTAY_VALUE="Value"; + + const std::string PresenceDescriptionProcessor::LABEL_KEY_PRESENCE_OPENINGHOURS="OpeningHours"; + + void PresenceDescriptionProcessor::Process(const FeatureValueBuffer &buffer, ObjectDescription &description) { + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,MaxStayFeature::NAME)); + value!=nullptr) { + if (value->HasCondition()) { + description.AddEntry(DescriptionEntry(SECTION_NAME_PRESENCE, + SUBSECTION_NAME_PRESENCE_MAXSTAY, + LABEL_KEY_PRESENCE_MAXSTAY_CONDITION, + value->GetCondition())); + } + + description.AddEntry(DescriptionEntry(SECTION_NAME_PRESENCE, + SUBSECTION_NAME_PRESENCE_MAXSTAY, + LABEL_KEY_PRESENCE_MAXSTAY_VALUE, + value->GetValue())); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,OpeningHoursFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_PRESENCE, + LABEL_KEY_PRESENCE_OPENINGHOURS, + value->GetValue())); + } + } + + const std::string ContactDescriptionProcessor::SECTION_NAME_CONTACT = "Contact"; + + const std::string ContactDescriptionProcessor::LABEL_KEY_CONTACT_PHONE="Phone"; + const std::string ContactDescriptionProcessor::LABEL_KEY_CONTACT_WEBSIZE="Website"; + + void ContactDescriptionProcessor::Process(const FeatureValueBuffer &buffer, ObjectDescription &description) { + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,PhoneFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_CONTACT, + LABEL_KEY_CONTACT_PHONE, + value->GetPhone())); + } + + if (const auto* value=dynamic_cast(GetFeatureValue(buffer,WebsiteFeature::NAME)); + value!=nullptr) { + description.AddEntry(DescriptionEntry(SECTION_NAME_CONTACT, + LABEL_KEY_CONTACT_WEBSIZE, + value->GetWebsite())); + } + } + + DescriptionService::DescriptionService() + { + featureProcessors.push_back(std::make_shared()); + featureProcessors.push_back(std::make_shared()); + featureProcessors.push_back(std::make_shared()); + featureProcessors.push_back(std::make_shared()); + featureProcessors.push_back(std::make_shared()); + featureProcessors.push_back(std::make_shared()); + featureProcessors.push_back(std::make_shared()); + featureProcessors.push_back(std::make_shared()); + featureProcessors.push_back(std::make_shared()); + featureProcessors.push_back(std::make_shared()); + } + + void DescriptionService::GetDescription(const FeatureValueBuffer& buffer, + ObjectDescription& description) const + { + for (const auto& processor : featureProcessors) { + processor->Process(buffer,description); + } + } + + ObjectDescription DescriptionService::GetDescription(const FeatureValueBuffer& buffer) const + { + ObjectDescription description; + + GetDescription(buffer,description); + + return description; + } + + ObjectDescription DescriptionService::GetDescription(const Area& area) const + { + ObjectDescription description; + + osmscout::GeoBox boundingBox=area.GetBoundingBox(); + + description.AddEntry(DescriptionEntry(SECTION_NAME_ID, + LABEL_KEY_ID_KIND, + area.GetObjectFileRef().GetTypeName())); + + description.AddEntry(DescriptionEntry(SECTION_NAME_ID, + LABEL_KEY_ID_ID, + std::to_string(area.GetObjectFileRef().GetFileOffset()))); + + description.AddEntry(DescriptionEntry(GeometryDescriptionProcessor::SECTION_NAME_GEOMETRY, + GeometryDescriptionProcessor::LABEL_KEY_GEOMETRY_BOUNDINGBOX, + boundingBox.GetDisplayText())); + + description.AddEntry(DescriptionEntry(GeometryDescriptionProcessor::SECTION_NAME_GEOMETRY, + GeometryDescriptionProcessor::LABEL_KEY_GEOMETRY_CENTER, + boundingBox.GetCenter().GetDisplayText())); + + description.AddEntry(DescriptionEntry(GeometryDescriptionProcessor::SECTION_NAME_GEOMETRY, + GeometryDescriptionProcessor::LABEL_KEY_GEOMETRY_CELLLEVEL, + std::to_string(CalculateCellLevel(boundingBox)))); + + GetDescription(area.GetFeatureValueBuffer(),description); + + return description; + } + + ObjectDescription DescriptionService::GetDescription(const Way& way) const + { + ObjectDescription description; + + description.AddEntry(DescriptionEntry(SECTION_NAME_ID, + LABEL_KEY_ID_KIND, + way.GetObjectFileRef().GetTypeName())); + + description.AddEntry(DescriptionEntry(SECTION_NAME_ID, + LABEL_KEY_ID_ID, + std::to_string(way.GetObjectFileRef().GetFileOffset()))); + + osmscout::GeoBox boundingBox=way.GetBoundingBox(); + + description.AddEntry(DescriptionEntry(GeometryDescriptionProcessor::SECTION_NAME_GEOMETRY, + GeometryDescriptionProcessor::LABEL_KEY_GEOMETRY_BOUNDINGBOX, + boundingBox.GetDisplayText())); + + description.AddEntry(DescriptionEntry(GeometryDescriptionProcessor::SECTION_NAME_GEOMETRY, + GeometryDescriptionProcessor::LABEL_KEY_GEOMETRY_CENTER, + boundingBox.GetCenter().GetDisplayText())); + + description.AddEntry(DescriptionEntry(GeometryDescriptionProcessor::SECTION_NAME_GEOMETRY, + GeometryDescriptionProcessor::LABEL_KEY_GEOMETRY_CELLLEVEL, + std::to_string(CalculateCellLevel(boundingBox)))); + + GetDescription(way.GetFeatureValueBuffer(),description); + + return description; + } + + const std::string DescriptionService::SECTION_NAME_ID = "Id"; + const std::string DescriptionService::LABEL_KEY_ID_KIND = "Kind"; + const std::string DescriptionService::LABEL_KEY_ID_ID = "Id"; + + ObjectDescription DescriptionService::GetDescription(const Node& node) const + { + ObjectDescription description; + + description.AddEntry(DescriptionEntry(SECTION_NAME_ID, + LABEL_KEY_ID_KIND, + node.GetObjectFileRef().GetTypeName())); + + description.AddEntry(DescriptionEntry(SECTION_NAME_ID, + LABEL_KEY_ID_ID, + std::to_string(node.GetObjectFileRef().GetFileOffset()))); + + description.AddEntry(DescriptionEntry(GeometryDescriptionProcessor::SECTION_NAME_GEOMETRY, + GeometryDescriptionProcessor::LABEL_KEY_GEOMETRY_COORDINATE, + node.GetCoords().GetDisplayText())); + + GetDescription(node.GetFeatureValueBuffer(),description); + + return description; + } +} diff --git a/stylesheets/map.ost b/stylesheets/map.ost index 44d627f25..0b1923021 100644 --- a/stylesheets/map.ost +++ b/stylesheets/map.ost @@ -925,24 +925,24 @@ TYPES // These are currently special-cased in the style file TYPE amenity_atm = NODE AREA ("amenity"=="atm") - {Name, NameAlt} + {Name, NameAlt, OpeningHours} GROUP amenity TYPE amenity_bank_building = AREA ("amenity"=="bank" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} POI GROUP amenity, building TYPE amenity_bank = NODE AREA ("amenity"=="bank") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, routingPOI TYPE amenity_bicycle_parking_building = AREA ("amenity"=="bicycle_parking" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours} GROUP amenity, building TYPE amenity_bicycle_parking @@ -966,13 +966,13 @@ TYPES TYPE amenity_cafe_building = AREA ("amenity"=="cafe" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, building, routingPOI TYPE amenity_cafe = NODE AREA ("amenity"=="cafe") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, routingPOI @@ -997,25 +997,25 @@ TYPES TYPE amenity_fast_food_building = AREA ("amenity"=="fast_food" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, building, routingPOI TYPE amenity_fast_food = NODE AREA ("amenity"=="fast_food") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, routingPOI TYPE amenity_fuel_building = AREA ("amenity"=="fuel" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, building, routingPOI TYPE amenity_fuel = NODE ("amenity"=="fuel") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, routingPOI @@ -1032,43 +1032,43 @@ TYPES TYPE amenity_hospital_building = AREA ("amenity"=="hospital" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, Phone, Website} ADDRESS POI GROUP amenity, building, routingPOI TYPE amenity_hospital = NODE AREA ("amenity"=="hospital") - {Name, NameAlt} + {Name, NameAlt, Phone, Website} ADDRESS POI GROUP amenity, routingPOI TYPE amenity_kindergarten_building = AREA ("amenity"=="kindergarten" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, building, routingPOI TYPE amenity_kindergarten = NODE AREA ("amenity"=="kindergarten") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, routingPOI TYPE amenity_library_building = AREA ("amenity"=="library" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, routingPOI TYPE amenity_library = NODE AREA ("amenity"=="library") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, routingPOI TYPE amenity_parking_building = AREA ("amenity"=="parking" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt, Fee, OpeningHours} + {Name, NameAlt, Fee, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, building, routingPOI @@ -1084,13 +1084,13 @@ TYPES TYPE amenity_parking = NODE AREA ("amenity"=="parking") - {Name, NameAlt, Fee, OpeningHours} + {Name, NameAlt, Fee, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity TYPE amenity_pharmacy = NODE AREA ("amenity"=="pharmacy" OR "shop"=="pharmacy") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, routingPOI @@ -1101,13 +1101,13 @@ TYPES TYPE amenity_post_office_building = AREA ("amenity"=="post_office" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, building, routingPOI TYPE amenity_post_office = NODE ("amenity"=="post_office") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, routingPOI @@ -1117,37 +1117,37 @@ TYPES TYPE amenity_restaurant_building = AREA ("amenity"=="restaurant" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, building, routingPOI TYPE amenity_restaurant = NODE AREA ("amenity"=="restaurant") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, routingPOI TYPE amenity_pub_building = AREA ("amenity"=="pub" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, building, routingPOI TYPE amenity_pub = NODE AREA ("amenity"=="pub") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, routingPOI TYPE amenity_bar_building = AREA ("amenity"=="bar" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, building, routingPOI TYPE amenity_bar = NODE AREA ("amenity"=="bar") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, routingPOI @@ -1157,13 +1157,13 @@ TYPES TYPE amenity_school_building = AREA ("amenity"=="school" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, building, routingPOI TYPE amenity_school = NODE AREA ("amenity"=="school") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP amenity, routingPOI @@ -1280,13 +1280,13 @@ TYPES // Everything else is just an 'amenity' for now TYPE amenity_building = AREA (EXISTS "amenity" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS GROUP amenity, building, routingPOI TYPE amenity = NODE (EXISTS "amenity") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS GROUP amenity @@ -1296,13 +1296,13 @@ TYPES TYPE shop_building = AREA (EXISTS "shop" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS GROUP shop, building, routingPOI TYPE shop = NODE AREA (EXISTS "shop") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS GROUP shop, routingPOI @@ -1312,13 +1312,13 @@ TYPES TYPE office_building = AREA (EXISTS "office" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS GROUP office, building, routingPOI TYPE office = NODE AREA (EXISTS "office") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS GROUP office, routingPOI @@ -1328,49 +1328,49 @@ TYPES TYPE tourism_aquarium = NODE AREA ("tourism"=="aquarium") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, routingPOI TYPE tourism_attraction_building = NODE AREA ("tourism"=="attraction" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, building, routingPOI TYPE tourism_attraction = NODE AREA ("tourism"=="attraction") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, routingPOI TYPE tourism_artwork = NODE WAY AREA ("tourism"=="artwork") - {Name, NameAlt, Width, Grade, Bridge, Tunnel, Roundabout} + {Name, NameAlt, Width, Grade, Bridge, Tunnel, Roundabout, Phone, Website} ADDRESS POI GROUP tourism, routingPOI TYPE tourism_camp_site = NODE AREA ("tourism"=="camp_site") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, routingPOI TYPE tourism_caravan_site = NODE AREA ("tourism"=="caravan_site") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism TYPE tourism_picnic_site = NODE AREA ("tourism"=="picnic_site") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism TYPE tourism_theme_park = NODE AREA ("tourism"=="theme_park") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, routingPOI @@ -1381,120 +1381,120 @@ TYPES TYPE tourism_zoo = NODE AREA ("tourism"=="zoo") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, routingPOI TYPE tourism_alpine_hut_building = AREA ("tourism"=="alpine_hut" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS GROUP tourism, building TYPE tourism_alpine_hut = NODE AREA ("tourism"=="alpine_hut") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS GROUP tourism TYPE tourism_chalet_building = AREA ("tourism"=="chalet" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, building TYPE tourism_chalet = NODE AREA ("tourism"=="chalet") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism TYPE tourism_guest_house_building = AREA ("tourism"=="guest_house" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, building TYPE tourism_guest_house = NODE AREA ("tourism"=="guest_house") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism TYPE tourism_information_guidepost = NODE ("tourism"=="information" AND "information"=="guidepost") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} GROUP tourism TYPE tourism_hostel_building = AREA ("tourism"=="hostel" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, building, routingPOI TYPE tourism_hostel = NODE AREA ("tourism"=="hostel") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, routingPOI TYPE tourism_hotel_building = AREA ("tourism"=="hotel" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, building, routingPOI TYPE tourism_hotel = NODE AREA ("tourism"=="hotel") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, routingPOI TYPE tourism_information_building = AREA ("tourism"=="information" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt,OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, building TYPE tourism_information = NODE AREA ("tourism"=="information") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism TYPE tourism_motel_building = AREA ("tourism"=="motel" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, building, routingPOI TYPE tourism_motel = NODE AREA ("tourism"=="motel") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, routingPOI TYPE tourism_museum_building = AREA ("tourism"=="museum" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, building, routingPOI TYPE tourism_museum = NODE AREA ("tourism"=="museum") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, routingPOI TYPE tourism_building = AREA (EXISTS "tourism" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, building, routingPOI TYPE tourism = NODE AREA (EXISTS "tourism") - {Name, NameAlt} + {Name, NameAlt, OpeningHours, Phone, Website} ADDRESS POI GROUP tourism, routingPOI @@ -1504,97 +1504,97 @@ TYPES TYPE historic_castle_building = AREA ("historic"=="castle" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, ConstructionYear} ADDRESS POI GROUP historic, building, routingPOI TYPE historic_castle = NODE AREA ("historic"=="castle") - {Name, NameAlt} + {Name, NameAlt, ConstructionYear} ADDRESS POI GROUP historic, routingPOI TYPE historic_manor_building = AREA ("historic"=="manor" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, ConstructionYear} ADDRESS POI GROUP historic, building, routingPOI TYPE historic_manor = NODE AREA ("historic"=="manor") - {Name, NameAlt} + {Name, NameAlt, ConstructionYear} ADDRESS POI GROUP historic, routingPOI TYPE historic_monument_building = AREA ("historic"=="monument" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, ConstructionYear} ADDRESS POI GROUP historic, building, routingPOI TYPE historic_monument = NODE AREA ("historic"=="monument") - {Name, NameAlt} + {Name, NameAlt, ConstructionYear} ADDRESS POI GROUP historic, routingPOI TYPE historic_memorial_stolperstein IGNORE // only for "theme" maps? = NODE ("historic"=="memorial" AND "memorial:type"=="stolperstein") - {Name, NameAlt} + {Name, NameAlt, ConstructionYear} GROUP historic TYPE historic_memorial_building = AREA ("historic"=="memorial" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, ConstructionYear} ADDRESS POI GROUP historic, building, routingPOI TYPE historic_memorial = NODE AREA ("historic"=="memorial") - {Name, NameAlt} + {Name, NameAlt, ConstructionYear} ADDRESS POI GROUP historic, routingPOI TYPE historic_ruins_building = AREA ("historic"=="ruins" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, ConstructionYear} ADDRESS POI GROUP historic, building, routingPOI TYPE historic_ruins = NODE WAY AREA ("historic"=="ruins") - {Name, NameAlt, Width, Grade, Bridge, Tunnel, Roundabout} + {Name, NameAlt, Width, Grade, Bridge, Tunnel, Roundabout, ConstructionYear} ADDRESS POI GROUP historic, routingPOI TYPE historic_archaeological_site = NODE WAY AREA ("historic"=="archaeological_site") - {Name, NameAlt, Width, Grade, Bridge, Tunnel, Roundabout} + {Name, NameAlt, Width, Grade, Bridge, Tunnel, Roundabout, ConstructionYear} ADDRESS POI GROUP historic TYPE historic_battlefield = NODE AREA ("historic"=="battlefield") - {Name, NameAlt} + {Name, NameAlt, ConstructionYear} ADDRESS POI MERGE_AREAS GROUP historic TYPE historic_wreck = NODE AREA ("historic"=="wreck") - {Name, NameAlt} + {Name, NameAlt, ConstructionYear} ADDRESS POI GROUP historic TYPE historic_building = AREA (EXISTS "historic" AND EXISTS "building" AND !("building" IN ["no","false","0"])) - {Name, NameAlt} + {Name, NameAlt, ConstructionYear} ADDRESS POI GROUP historic, building, routingPOI TYPE historic = NODE AREA (EXISTS "historic" AND !("historic" IN ["citywalls"]) AND !("barrier"=="city_wall")) - {Name, NameAlt} + {Name, NameAlt, ConstructionYear} ADDRESS POI GROUP historic diff --git a/webpage/content/documentation/concepts.md b/webpage/content/documentation/concepts.md index b0223f2b5..ae15326bc 100644 --- a/webpage/content/documentation/concepts.md +++ b/webpage/content/documentation/concepts.md @@ -15,15 +15,15 @@ This article tries to explain some general concepts of libosmscout. ## Import Libosmscout has its own internal representation of OSM data. This is necssary -to offer fast access of the data and reduze the size of the data on disk. +to offer fast access of the data and reduce the size of the data on disk. Standard export formats like .osm or *.osm.pbf files are used as data dump from the OSM SQL database for further processing and are designed for fast, index random data access. For importing the data the `Import` tool is used. The import tool generates -a custom libosmsocut database from the raw data passed. +a custom libosmscout database from the raw data passed. -An import normally is restrictied to a certain area of the world. Normally +An import normally is restricted to a certain area of the world. Normally you find imports for countries or counties or bigger cities. Take a look at the [import tutorial]({{< ref "/tutorials/Importing.md" >}}) for @@ -38,7 +38,7 @@ act as index into data and still other files have index and actual data combined You can find a description of the individual database files [here]({{< ref "/documentation/database.md" >}}). -Libomssocut assumes (but does not enforce this) that all maps are stored under +Libomsscout assumes (but does not enforce this) that all maps are stored under the same directory. Each database has its own sub directory storing the individual files. @@ -48,7 +48,7 @@ The `Database` class allows easy to all database files. ## Services -To further hide the details or complexity o f the low level access code a number +To further hide the details or complexity of the low level access code, a number of Services have been defined that offer a more suitable API. Currently the following services exist: @@ -57,6 +57,7 @@ Currently the following services exist: * `LocationService` * `RoutingService` * `POIService` +* `DescriptionService` ## BasemapDatabase diff --git a/webpage/content/features/_index.md b/webpage/content/features/_index.md index 89f2833c6..a16e92c59 100644 --- a/webpage/content/features/_index.md +++ b/webpage/content/features/_index.md @@ -15,15 +15,16 @@ menu: All basic features for * importing OSM data -* quering the resulting database +* querying the resulting database * rendering fancy maps nobody have ever seen * finding locations no one else could find -* and routing you to all these strange places +* routing you to all these strange places +* and describing a object are implemented. You should be able to implement your application with all -basic features required for a navigation application. However there are still +basic features required for a navigation application. However, there are still corners, we have not yet visited, some ideas though of but not implemented yet. The following list of documents should give you an overview what is already there - and what is not.