diff --git a/libosmscout/include/osmscout/routing/RoutePostprocessor.h b/libosmscout/include/osmscout/routing/RoutePostprocessor.h index a2796e846..9a573c606 100644 --- a/libosmscout/include/osmscout/routing/RoutePostprocessor.h +++ b/libosmscout/include/osmscout/routing/RoutePostprocessor.h @@ -385,7 +385,9 @@ namespace osmscout { * @param node * @param backBuffer buffer of traveled nodes, recent node at back */ - void EvaluateLaneSuggestion(const RouteDescription::Node &node, const std::list &backBuffer) const; + void EvaluateLaneSuggestion(const RoutePostprocessor& postprocessor, + const RouteDescription::Node &node, + const std::list &backBuffer) const; private: Distance distanceBefore; @@ -466,6 +468,8 @@ namespace osmscout { uint8_t GetMaxSpeed(const RouteDescription::Node& node) const; + RouteDescription::LaneDescription GetLanes(const DatabaseId& dbId, const WayRef& way, bool forward) const; + RouteDescription::LaneDescriptionRef GetLanes(const RouteDescription::Node& node) const; Id GetNodeId(const RouteDescription::Node& node) const; diff --git a/libosmscout/include/osmscout/util/Bearing.h b/libosmscout/include/osmscout/util/Bearing.h index d41b05934..af547ad1e 100644 --- a/libosmscout/include/osmscout/util/Bearing.h +++ b/libosmscout/include/osmscout/util/Bearing.h @@ -116,6 +116,26 @@ namespace osmscout { return radians != o.radians; } + bool operator<(const Bearing& o) const + { + return radians(const Bearing& o) const + { + return radians>o.radians; + } + + bool operator<=(const Bearing& o) const + { + return radians<=o.radians; + } + + bool operator>=(const Bearing& o) const + { + return radians>=o.radians; + } + inline static Bearing Radians(double radians) { return Bearing(radians); diff --git a/libosmscout/src/osmscout/routing/RoutePostprocessor.cpp b/libosmscout/src/osmscout/routing/RoutePostprocessor.cpp index ed87578fe..8606b3756 100644 --- a/libosmscout/src/osmscout/routing/RoutePostprocessor.cpp +++ b/libosmscout/src/osmscout/routing/RoutePostprocessor.cpp @@ -1591,18 +1591,89 @@ namespace osmscout { return true; } - void RoutePostprocessor::SuggestedLanesPostprocessor::EvaluateLaneSuggestion(const RouteDescription::Node &node, const std::list &backBuffer) const + void RoutePostprocessor::SuggestedLanesPostprocessor::EvaluateLaneSuggestion(const RoutePostprocessor& postprocessor, + const RouteDescription::Node &node, + const std::list &backBuffer) const { + if (node.GetPathObject().GetType()!=refWay) { + return; // areas not considered now + } + + assert(!backBuffer.empty()); + const RouteDescription::Node &prevNode=*backBuffer.back(); + DatabaseId dbId = node.GetDatabaseId(); + if (prevNode.GetDatabaseId() != dbId) { + return; // we consider nodes just from the same database for simplicity + } + + assert(dbIdGetId(prevNode.GetCurrentNodeIndex()); + // bearing from current node to previous + Bearing prevNodeBearing = GetSphericalBearingInitial(prevWay->nodes[prevNode.GetTargetNodeIndex()].GetCoord(), + prevWay->nodes[prevNode.GetCurrentNodeIndex()].GetCoord()); + + WayRef way = postprocessor.GetWay(node.GetDBFileOffset()); + Id nextNodeId = way->GetId(node.GetTargetNodeIndex()); + Bearing nextNodeBearing = GetSphericalBearingInitial(way->nodes[node.GetCurrentNodeIndex()].GetCoord(), + way->nodes[node.GetTargetNodeIndex()].GetCoord()); + + struct JunctionExit { + Id nextId; + Bearing bearing; + RouteDescription::LaneDescription lanes; + }; + std::vector junctionExits; // excluding incoming and outgoing way + junctionExits.reserve(node.GetObjects().size()); + + for (const auto &o: node.GetObjects()){ + if (!o.IsWay()) { + continue; // areas not considered now + } + + way=postprocessor.GetWay(DBFileOffset(node.GetDatabaseId(), o.GetFileOffset())); + for (size_t i = 0; i < way->nodes.size(); i++) { + if (way->nodes[i].GetId() == nodeId) { + if (i < way->nodes.size()-1 && profile->CanUseForward(*way)) { + Id junctionNodeId = way->nodes[i+1].GetId(); + if (junctionNodeId!=prevNodeId && junctionNodeId!=nextNodeId) { + auto bearing = GetSphericalBearingInitial(way->nodes[i].GetCoord(), way->nodes[i + 1].GetCoord()); + auto wayLanes = postprocessor.GetLanes(node.GetDatabaseId(), way, true); + junctionExits.push_back({junctionNodeId, bearing, wayLanes}); + } + } + if (i > 0 && profile->CanUseBackward(*way)) { + Id junctionNodeId = way->nodes[i-1].GetId(); + if (junctionNodeId!=prevNodeId && junctionNodeId!=nextNodeId) { + auto bearing = GetSphericalBearingInitial(way->nodes[i].GetCoord(), way->nodes[i - 1].GetCoord()); + auto wayLanes = postprocessor.GetLanes(node.GetDatabaseId(), way, false); + junctionExits.push_back({junctionNodeId, bearing, wayLanes}); + } + } + break; + } + } } - // TODO: read lanes on the ALL junction ways, use heuristics what lanes we can use to move forward + // sort by bearing + std::sort(junctionExits.begin(), junctionExits.end(), [](const JunctionExit &j1, const JunctionExit &j2) -> bool { + return j1.bearing < j2.bearing; + }); + + + + + RouteDescription::DirectionDescriptionRef direction = std::dynamic_pointer_cast(node.GetDescription(RouteDescription::DIRECTION_DESC)); @@ -1720,7 +1791,7 @@ namespace osmscout { return std::dynamic_pointer_cast(node.GetDescription(RouteDescription::LANES_DESC)); } - bool RoutePostprocessor::SuggestedLanesPostprocessor::Process(const RoutePostprocessor& /*postprocessor*/, + bool RoutePostprocessor::SuggestedLanesPostprocessor::Process(const RoutePostprocessor& postprocessor, RouteDescription& description) { using namespace std::string_view_literals; @@ -1745,7 +1816,7 @@ namespace osmscout { assert(prevLanes); if (prevLanes->GetLaneCount() > lanes->GetLaneCount()) { // lane count was decreased - EvaluateLaneSuggestion(node, backBuffer); + EvaluateLaneSuggestion(postprocessor, node, backBuffer); backBuffer.clear(); } @@ -2144,40 +2215,46 @@ namespace osmscout { return speed; } + RouteDescription::LaneDescription RoutePostprocessor::GetLanes(const DatabaseId& dbId, const WayRef& way, bool forward) const + { + auto lanesReader=lanesReaders.find(dbId); + auto accessReader=accessReaders.find(dbId); + assert(lanesReader != lanesReaders.end()); + assert(accessReader != accessReaders.end()); + + AccessFeatureValue *accessValue=accessReader->second->GetValue(way->GetFeatureValueBuffer()); + bool oneway=accessValue!=nullptr && accessValue->IsOneway(); + + uint8_t laneCount; + std::vector laneTurns; + LanesFeatureValue *lanesValue=lanesReader->second->GetValue(way->GetFeatureValueBuffer()); + if (lanesValue!=nullptr) { + laneCount=std::max((uint8_t)1,forward ? lanesValue->GetForwardLanes() : lanesValue->GetBackwardLanes()); + laneTurns=forward ? lanesValue->GetTurnForward() : lanesValue->GetTurnBackward(); + while (laneTurns.size() < laneCount) { + laneTurns.push_back(LaneTurn::None); + } + } else { + // default lane count by object type + if (oneway) { + laneCount=way->GetType()->GetOnewayLanes(); + } else { + laneCount=std::max(1,way->GetType()->GetLanes()/2); + } + } + + return RouteDescription::LaneDescription(oneway, laneCount, laneTurns); + } + RouteDescription::LaneDescriptionRef RoutePostprocessor::GetLanes(const RouteDescription::Node& node) const { RouteDescription::LaneDescriptionRef lanes; if (node.GetPathObject().GetType()==refWay) { - auto lanesReader=lanesReaders.find(node.GetDatabaseId()); - auto accessReader=accessReaders.find(node.GetDatabaseId()); - assert(lanesReader != lanesReaders.end()); - assert(accessReader != accessReaders.end()); WayRef way=GetWay(node.GetDBFileOffset()); - bool forward = node.GetCurrentNodeIndex() < node.GetTargetNodeIndex(); - AccessFeatureValue *accessValue=accessReader->second->GetValue(way->GetFeatureValueBuffer()); - bool oneway=accessValue!=nullptr && accessValue->IsOneway(); - - uint8_t laneCount; - std::vector laneTurns; - LanesFeatureValue *lanesValue=lanesReader->second->GetValue(way->GetFeatureValueBuffer()); - if (lanesValue!=nullptr) { - laneCount=std::max((uint8_t)1,forward ? lanesValue->GetForwardLanes() : lanesValue->GetBackwardLanes()); - laneTurns=forward ? lanesValue->GetTurnForward() : lanesValue->GetTurnBackward(); - while (laneTurns.size() < laneCount) { - laneTurns.push_back(LaneTurn::None); - } - } else { - // default lane count by object type - if (oneway) { - laneCount=way->GetType()->GetOnewayLanes(); - } else { - laneCount=std::max(1,way->GetType()->GetLanes()/2); - } - } - lanes=std::make_shared(oneway, laneCount, laneTurns); + lanes=std::make_shared(GetLanes(node.GetDatabaseId(), way, forward)); } return lanes; }