From ce74c0dba277f55b80b917b70c80e49617190b20 Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Sun, 13 Oct 2024 13:52:26 +0200 Subject: [PATCH 01/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service --- DumpData/src/DumpData.cpp | 755 ++++----------- libosmscout/CMakeLists.txt | 6 + libosmscout/include/meson.build | 1 + .../osmscout/description/DescriptionService.h | 439 +++++++++ libosmscout/src/meson.build | 1 + .../description/DescriptionService.cpp | 902 ++++++++++++++++++ stylesheets/map.ost | 158 +-- 7 files changed, 1621 insertions(+), 641 deletions(-) create mode 100644 libosmscout/include/osmscout/description/DescriptionService.h create mode 100644 libosmscout/src/osmscout/description/DescriptionService.cpp diff --git a/DumpData/src/DumpData.cpp b/DumpData/src/DumpData.cpp index 3b5bf11e7..4f1ab2746 100644 --- a/DumpData/src/DumpData.cpp +++ b/DumpData/src/DumpData.cpp @@ -23,33 +23,19 @@ #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 +48,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,15 +61,20 @@ struct Job } }; -static const size_t IDENT=2; +struct Arguments +{ + std::string map; + std::set coordIds; + std::set routeNodeCoordIds; + std::set routeNodeIds; + std::list jobs; +}; + +static const size_t INDENT=2; static bool ParseArguments(int argc, char* argv[], - std::string& map, - std::set& coordIds, - std::set& routeNodeCoordIds, - std::set& routeNodeIds, - std::list& jobs) + Arguments& args) { if (argc<2) { std::cerr << "DumpData {Search arguments}" << std::endl; @@ -107,7 +98,7 @@ static bool ParseArguments(int argc, int arg=1; - map=argv[arg]; + args.map=argv[arg]; arg++; @@ -126,7 +117,7 @@ static bool ParseArguments(int argc, return false; } - coordIds.insert(id); + args.coordIds.insert(id); arg++; } @@ -149,7 +140,7 @@ static bool ParseArguments(int argc, return false; } - jobs.emplace_back(osmscout::osmRefNode,id); + args.jobs.emplace_back(osmscout::osmRefNode,id); arg++; } @@ -167,7 +158,7 @@ static bool ParseArguments(int argc, return false; } - jobs.emplace_back(osmscout::osmRefWay,id); + args.jobs.emplace_back(osmscout::osmRefWay,id); arg++; } @@ -185,7 +176,7 @@ static bool ParseArguments(int argc, return false; } - jobs.emplace_back(osmscout::osmRefRelation,id); + args.jobs.emplace_back(osmscout::osmRefRelation,id); arg++; } @@ -203,7 +194,7 @@ static bool ParseArguments(int argc, return false; } - routeNodeCoordIds.insert(id); + args.routeNodeCoordIds.insert(id); arg++; } @@ -221,7 +212,7 @@ static bool ParseArguments(int argc, return false; } - routeNodeIds.insert(id); + args.routeNodeIds.insert(id); arg++; } @@ -244,7 +235,7 @@ static bool ParseArguments(int argc, return false; } - jobs.emplace_back(osmscout::refNode,fileOffset); + args.jobs.emplace_back(osmscout::refNode,fileOffset); arg++; } @@ -262,7 +253,7 @@ static bool ParseArguments(int argc, return false; } - jobs.emplace_back(osmscout::refWay,fileOffset); + args.jobs.emplace_back(osmscout::refWay,fileOffset); arg++; } @@ -280,7 +271,7 @@ static bool ParseArguments(int argc, return false; } - jobs.emplace_back(osmscout::refArea,fileOffset); + args.jobs.emplace_back(osmscout::refArea,fileOffset); arg++; } @@ -295,27 +286,9 @@ static bool ParseArguments(int argc, 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--; - } - - return level; -} - static void DumpIndent(size_t indent) { + assert(indent<=10); for (size_t i=1; i<=indent; i++) { std::cout << " "; } @@ -383,556 +356,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; } } @@ -942,12 +567,9 @@ static void DumpArea(const osmscout::AreaRef& area, int main(int argc, char* argv[]) { - std::string map; - std::list jobs; - std::set coordIds; + Arguments args; - std::set routeNodeCoordIds; - std::set routeNodeIds; + // Try to initialize current locale try { std::locale::global(std::locale("")); @@ -958,11 +580,7 @@ int main(int argc, char* argv[]) if (!ParseArguments(argc, argv, - map, - coordIds, - routeNodeCoordIds, - routeNodeIds, - jobs)) { + args)) { return 1; } @@ -975,16 +593,18 @@ int main(int argc, char* argv[]) osmscout::RoutingService::GetDataFilename(osmscout::RoutingService::DEFAULT_FILENAME_BASE), 1000); - if (!database.Open(map)) { + osmscout::DescriptionService descriptionService; + + 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 +613,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 +656,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 +725,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 +752,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 +816,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 +825,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 +834,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 +857,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 +866,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 +875,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/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/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 From c20c3b4e3f18e84aff2f0daae99bd8a641258aaf Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Sun, 13 Oct 2024 13:58:23 +0200 Subject: [PATCH 02/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- DumpData/src/DumpData.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/DumpData/src/DumpData.cpp b/DumpData/src/DumpData.cpp index 4f1ab2746..5574d9c4d 100644 --- a/DumpData/src/DumpData.cpp +++ b/DumpData/src/DumpData.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -35,7 +34,6 @@ #include - /* * Example: * src/DumpData ../TravelJinni/ -n 25293125 -w 4290108 -w 26688152 -r 531985 From 64071e1b55c141fa9840488c72b2c3806c196886 Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Sun, 13 Oct 2024 14:08:00 +0200 Subject: [PATCH 03/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- .../build_and test_on_ubuntu_20_04.yml | 80 ------------------- .../workflows/sanitize_on_ubuntu_22_04.yml | 10 +-- .github/workflows/sonar.yml | 10 +-- 3 files changed, 10 insertions(+), 90 deletions(-) delete mode 100644 .github/workflows/build_and test_on_ubuntu_20_04.yml 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/sanitize_on_ubuntu_22_04.yml b/.github/workflows/sanitize_on_ubuntu_22_04.yml index a497bb657..5f53c41dc 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 @@ -66,14 +66,14 @@ 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 @@ -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..666120794 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -19,7 +19,7 @@ jobs: environment: SONAR steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Update package list @@ -27,7 +27,7 @@ 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-12 g++-12 libtbb-dev ccache libtool pkg-config - name: Install meson, ninja, lcov and gcovr via pip run: pip install meson ninja lcov gcovr==6.0 - name: Install libosmscout dependencies @@ -41,12 +41,12 @@ jobs: libglm-dev libglew-dev freeglut3 freeglut3-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++-12 + CC: gcc-12 - name: Build project run: build-wrapper-linux-x86-64 --out-dir sonar-build-output ninja -C debug all test coverage - name: Create gcov files From c3a73237a89eb36e6cefc479ec55a7ede2361ea0 Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Sun, 13 Oct 2024 14:20:08 +0200 Subject: [PATCH 04/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- .github/workflows/sanitize_on_ubuntu_22_04.yml | 4 ++-- Tests/src/HeaderCheckTest.cpp | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sanitize_on_ubuntu_22_04.yml b/.github/workflows/sanitize_on_ubuntu_22_04.yml index 5f53c41dc..bcda91564 100644 --- a/.github/workflows/sanitize_on_ubuntu_22_04.yml +++ b/.github/workflows/sanitize_on_ubuntu_22_04.yml @@ -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 @@ -79,7 +79,7 @@ jobs: 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 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", From 1a32107263c3d080bfca303f13656e7e5dd12a4f Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Sun, 13 Oct 2024 15:25:18 +0200 Subject: [PATCH 05/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- .github/workflows/sonar.yml | 10 +++++----- Tests/meson.build | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 666120794..65156a0ff 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -15,7 +15,7 @@ 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 @@ -27,7 +27,7 @@ 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-12 g++-12 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 - name: Install libosmscout dependencies @@ -38,15 +38,15 @@ jobs: 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@v3 - name: Configure build project run: meson setup --buildtype debugoptimized -Db_coverage=true --unity on debug env: - CXX: g++-12 - CC: gcc-12 + 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 diff --git a/Tests/meson.build b/Tests/meson.build index 92bc3d6a1..ecf34cb01 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: 60) WStringStringConversionTest = executable('WStringStringConversionTest', 'src/WStringStringConversionTest.cpp', From 500e1837db9e605fca59cbe2e2d466f2af5f15f9 Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Sun, 13 Oct 2024 15:28:58 +0200 Subject: [PATCH 06/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- .github/workflows/sonar.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 65156a0ff..cda84c1f2 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -27,9 +27,7 @@ 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 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: sudo apt-get -y install gcc g++ libtbb-dev ccache libtool pkg-config meson ninja lcov gcovr - name: Install libosmscout dependencies run: "sudo apt-get install -y libxml2-dev From 96c49d281393a31ef2388cc91a68448ea1323354 Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Sun, 13 Oct 2024 15:42:26 +0200 Subject: [PATCH 07/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- .github/workflows/sonar.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index cda84c1f2..9f73ec411 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -27,7 +27,7 @@ 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 g++ libtbb-dev ccache libtool pkg-config meson ninja lcov gcovr + run: sudo apt-get -y install gcc g++ libtbb-dev ccache libtool pkg-config meson ninja-build lcov gcovr - name: Install libosmscout dependencies run: "sudo apt-get install -y libxml2-dev From 7237e46425a83450ebfab8e72c041497bd536e79 Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Sun, 13 Oct 2024 15:49:57 +0200 Subject: [PATCH 08/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- .github/workflows/sonar.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 9f73ec411..a0bf5ceca 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -31,7 +31,7 @@ jobs: - name: Install libosmscout dependencies run: "sudo apt-get install -y 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 From 9fcdcc66d2128d0e6ef13bf5a9b7da38a70b3058 Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Sun, 13 Oct 2024 17:30:23 +0200 Subject: [PATCH 09/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- .github/workflows/build_and test_on_ubuntu_24_04.yml | 2 +- .github/workflows/sonar.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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/sonar.yml b/.github/workflows/sonar.yml index a0bf5ceca..09ee390e5 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -30,6 +30,7 @@ jobs: run: sudo apt-get -y install gcc g++ libtbb-dev ccache libtool pkg-config meson ninja-build lcov gcovr - name: Install libosmscout dependencies run: "sudo apt-get install -y + catch2 libxml2-dev libprotobuf-dev protobuf-compiler liblzma-dev libagg-dev From d873a381167e36b13ea0f03dcc4920365625e472 Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Sun, 13 Oct 2024 17:43:06 +0200 Subject: [PATCH 10/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- .github/workflows/sonar.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 09ee390e5..3d13351e5 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -48,6 +48,9 @@ jobs: CC: gcc - name: Build project run: build-wrapper-linux-x86-64 --out-dir sonar-build-output ninja -C debug all test coverage + env: + CXX: g++ + CC: gcc - name: Create gcov files run: mkdir gcov && cd gcov && gcov -p ../debug//*/*/* - name: SonarCloud Scan From 63aec394444f1d63567b1d953d74083f9a79d84a Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Sun, 13 Oct 2024 19:44:13 +0200 Subject: [PATCH 11/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- .github/workflows/sonar.yml | 6 ++---- Tests/meson.build | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 3d13351e5..bcc91581e 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -47,14 +47,12 @@ jobs: CXX: g++ CC: gcc - name: Build project - run: build-wrapper-linux-x86-64 --out-dir sonar-build-output ninja -C debug all test coverage + run: build-wrapper-linux-x86-64 --out-dir sonar-build-output ninja -C debug all test coverage-sonarqube env: CXX: g++ CC: gcc - - name: Create gcov files - run: mkdir gcov && cd gcov && gcov -p ../debug//*/*/* - 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.build-wrapper-output=sonar-build-output -Dsonar.verbose=true -Dsonar.coverageReportPaths=debug/meson-logs/sonarqube.xml -Dsonar.token=$SONAR_TOKEN env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/Tests/meson.build b/Tests/meson.build index ecf34cb01..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, timeout: 60) +test('Check implementation of work queue', WorkQueueTest, timeout: 120) WStringStringConversionTest = executable('WStringStringConversionTest', 'src/WStringStringConversionTest.cpp', From c115c0d4bb61fae7142058e453a4e6ce80f4ff91 Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Sun, 13 Oct 2024 20:02:43 +0200 Subject: [PATCH 12/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- .github/workflows/sonar.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index bcc91581e..badc2537a 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -27,7 +27,7 @@ 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 g++ libtbb-dev ccache libtool pkg-config meson ninja-build lcov gcovr + run: sudo apt-get -y install gcc g++ libtbb-dev ccache libtool pkg-config meson ninja-build lcov - name: Install libosmscout dependencies run: "sudo apt-get install -y catch2 From 0dc61f5e2959ddd85daf5a9fe2d8461e97e35078 Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Sun, 13 Oct 2024 20:21:42 +0200 Subject: [PATCH 13/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- .github/workflows/sonar.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index badc2537a..1c5945e22 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -27,7 +27,9 @@ 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 g++ libtbb-dev ccache libtool pkg-config meson ninja-build lcov + 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 --user meson ninja lcov gcovr --break-system-packages - name: Install libosmscout dependencies run: "sudo apt-get install -y catch2 From 5b591e2af644f476e1cc1385e88e953fd3512c8c Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Sun, 13 Oct 2024 21:59:16 +0200 Subject: [PATCH 14/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- .github/workflows/sonar.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 1c5945e22..c24c9260c 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -49,12 +49,12 @@ jobs: CXX: g++ CC: gcc - name: Build project - run: build-wrapper-linux-x86-64 --out-dir sonar-build-output ninja -C debug all test coverage-sonarqube + run: build-wrapper-linux-x86-64 --out-dir sonar-build-output ninja -C debug all test coverage env: CXX: g++ CC: gcc - name: SonarCloud Scan - run: sonar-scanner -Dsonar.cfamily.build-wrapper-output=sonar-build-output -Dsonar.verbose=true -Dsonar.coverageReportPaths=debug/meson-logs/sonarqube.xml -Dsonar.token=$SONAR_TOKEN + run: sonar-scanner -Dsonar.cfamily.compile-commands=sonar-build-output/compile_commands.json -Dsonar.coverageReportPaths=debug/meson-logs/sonarqube.xml -Dsonar.verbose=true -Dsonar.token=$SONAR_TOKEN env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From 408fb0e5f1a59003de1a8588764dd79d8528cf12 Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Mon, 14 Oct 2024 08:51:05 +0200 Subject: [PATCH 15/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- .github/workflows/sonar.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index c24c9260c..b4ea21a58 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -54,7 +54,12 @@ jobs: CXX: g++ CC: gcc - name: SonarCloud Scan - run: sonar-scanner -Dsonar.cfamily.compile-commands=sonar-build-output/compile_commands.json -Dsonar.coverageReportPaths=debug/meson-logs/sonarqube.xml -Dsonar.verbose=true -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 }} From b1b7b4bcd748cee1f4045aa6643c53362a0a6ab4 Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Mon, 14 Oct 2024 09:20:07 +0200 Subject: [PATCH 16/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- .github/workflows/sonar.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index b4ea21a58..e28c256e2 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -56,7 +56,7 @@ jobs: - name: SonarCloud Scan run: "sonar-scanner -Dsonar.cfamily.compile-commands=sonar-build-output/compile_commands.json - .Dsonar.cfamily.cppunit.reportsPath=debug/meson-logs/testlog.junit.xml + -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" From dde2c2b039b32f05effa429d42fe2fe4489069e2 Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Tue, 15 Oct 2024 08:08:17 +0200 Subject: [PATCH 17/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- DumpData/src/DumpData.cpp | 321 ++++++------------ .../include/osmscout/cli/CmdLineParsing.h | 12 + 2 files changed, 110 insertions(+), 223 deletions(-) diff --git a/DumpData/src/DumpData.cpp b/DumpData/src/DumpData.cpp index 5574d9c4d..f04b08120 100644 --- a/DumpData/src/DumpData.cpp +++ b/DumpData/src/DumpData.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -66,224 +67,11 @@ struct Arguments std::set routeNodeCoordIds; std::set routeNodeIds; std::list jobs; + bool help; }; static const size_t INDENT=2; -static bool ParseArguments(int argc, - char* argv[], - Arguments& args) -{ - 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; - - args.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; - } - - args.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; - } - - args.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; - } - - args.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; - } - - args.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; - } - - args.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; - } - - args.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; - } - - args.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; - } - - args.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; - } - - args.jobs.emplace_back(osmscout::refArea,fileOffset); - - arg++; - } - - - else { - std::cerr << "Unknown parameter '" << argv[arg] << "'!" << std::endl; - return false; - } - } - - return true; -} - static void DumpIndent(size_t indent) { assert(indent<=10); @@ -563,10 +351,93 @@ static void DumpArea(const osmscout::DescriptionService& descriptionService, std::cout << "}" << std::endl; } -int main(int argc, char* argv[]) +osmscout::CmdLineParseResult ParseArguments(int argc, char** argv, Arguments& args) { - Arguments args; + 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; +} + +int main(int argc, char* argv[]) +{ // Try to initialize current locale try { @@ -576,22 +447,26 @@ int main(int argc, char* argv[]) std::cerr << "ERROR: Cannot set locale" << std::endl; } - if (!ParseArguments(argc, - argv, - args)) { + 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; + osmscout::DescriptionService descriptionService; if (!database.Open(args.map)) { std::cerr << "Cannot open db" << std::endl; 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) { From 7789a28adf87ab6da4eee7446cae7767e49c2884 Mon Sep 17 00:00:00 2001 From: Tim Teulings Date: Tue, 15 Oct 2024 08:11:27 +0200 Subject: [PATCH 18/18] feat: New DescriptionService - New DescriptionService that offers structured object information - Adaption of DumpData to make use of the new service.ost to make use of more available Features --- webpage/content/documentation/concepts.md | 11 ++++++----- webpage/content/features/_index.md | 7 ++++--- 2 files changed, 10 insertions(+), 8 deletions(-) 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.