forked from organicmaps/organicmaps
Merge pull request #3025 from bykoianko/master-bicycle-directions-first-appr2
Bicycle turn generation.
This commit is contained in:
commit
b803754b1b
27 changed files with 781 additions and 293 deletions
|
@ -4,11 +4,105 @@
|
|||
#include "indexer/feature_data.hpp"
|
||||
#include "indexer/classificator.hpp"
|
||||
|
||||
#include "std/map.hpp"
|
||||
#include "std/sstream.hpp"
|
||||
#include "std/utility.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
class HighwayClasses
|
||||
{
|
||||
map<uint32_t, ftypes::HighwayClass> m_map;
|
||||
|
||||
public:
|
||||
HighwayClasses()
|
||||
{
|
||||
auto const & c = classif();
|
||||
m_map[c.GetTypeByPath({"highway", "motorway"})] = ftypes::HighwayClass::Trunk;
|
||||
m_map[c.GetTypeByPath({"highway", "motorway_link"})] = ftypes::HighwayClass::Trunk;
|
||||
m_map[c.GetTypeByPath({"highway", "trunk"})] = ftypes::HighwayClass::Trunk;
|
||||
m_map[c.GetTypeByPath({"highway", "trunk_link"})] = ftypes::HighwayClass::Trunk;
|
||||
m_map[c.GetTypeByPath({"route", "ferry"})] = ftypes::HighwayClass::Trunk;
|
||||
|
||||
m_map[c.GetTypeByPath({"highway", "primary"})] = ftypes::HighwayClass::Primary;
|
||||
m_map[c.GetTypeByPath({"highway", "primary_link"})] = ftypes::HighwayClass::Primary;
|
||||
|
||||
m_map[c.GetTypeByPath({"highway", "secondary"})] = ftypes::HighwayClass::Secondary;
|
||||
m_map[c.GetTypeByPath({"highway", "secondary_link"})] = ftypes::HighwayClass::Secondary;
|
||||
|
||||
m_map[c.GetTypeByPath({"highway", "tertiary"})] = ftypes::HighwayClass::Tertiary;
|
||||
m_map[c.GetTypeByPath({"highway", "tertiary_link"})] = ftypes::HighwayClass::Tertiary;
|
||||
|
||||
m_map[c.GetTypeByPath({"highway", "unclassified"})] = ftypes::HighwayClass::LivingStreet;
|
||||
m_map[c.GetTypeByPath({"highway", "residential"})] = ftypes::HighwayClass::LivingStreet;
|
||||
m_map[c.GetTypeByPath({"highway", "living_street"})] = ftypes::HighwayClass::LivingStreet;
|
||||
m_map[c.GetTypeByPath({"highway", "road"})] = ftypes::HighwayClass::LivingStreet;
|
||||
|
||||
m_map[c.GetTypeByPath({"highway", "service"})] = ftypes::HighwayClass::Service;
|
||||
m_map[c.GetTypeByPath({"highway", "track"})] = ftypes::HighwayClass::Service;
|
||||
|
||||
m_map[c.GetTypeByPath({"highway", "pedestrian"})] = ftypes::HighwayClass::Pedestrian;
|
||||
m_map[c.GetTypeByPath({"highway", "footway"})] = ftypes::HighwayClass::Pedestrian;
|
||||
m_map[c.GetTypeByPath({"highway", "bridleway"})] = ftypes::HighwayClass::Pedestrian;
|
||||
m_map[c.GetTypeByPath({"highway", "steps"})] = ftypes::HighwayClass::Pedestrian;
|
||||
m_map[c.GetTypeByPath({"highway", "cycleway"})] = ftypes::HighwayClass::Pedestrian;
|
||||
m_map[c.GetTypeByPath({"highway", "path"})] = ftypes::HighwayClass::Pedestrian;
|
||||
}
|
||||
|
||||
ftypes::HighwayClass Get(uint32_t t) const
|
||||
{
|
||||
auto const it = m_map.find(t);
|
||||
if (it == m_map.cend())
|
||||
return ftypes::HighwayClass::Error;
|
||||
return it->second;
|
||||
}
|
||||
};
|
||||
|
||||
char const * HighwayClassToString(ftypes::HighwayClass const cls)
|
||||
{
|
||||
switch (cls)
|
||||
{
|
||||
case ftypes::HighwayClass::Undefined: return "Undefined";
|
||||
case ftypes::HighwayClass::Error: return "Error";
|
||||
case ftypes::HighwayClass::Trunk: return "Trunk";
|
||||
case ftypes::HighwayClass::Primary: return "Primary";
|
||||
case ftypes::HighwayClass::Secondary: return "Secondary";
|
||||
case ftypes::HighwayClass::Tertiary: return "Tertiary";
|
||||
case ftypes::HighwayClass::LivingStreet: return "LivingStreet";
|
||||
case ftypes::HighwayClass::Service: return "Service";
|
||||
case ftypes::HighwayClass::Pedestrian: return "Pedestrian";
|
||||
case ftypes::HighwayClass::Count: return "Count";
|
||||
}
|
||||
ASSERT(false, ());
|
||||
return "";
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace ftypes
|
||||
{
|
||||
string DebugPrint(HighwayClass const cls)
|
||||
{
|
||||
stringstream out;
|
||||
out << "[ " << HighwayClassToString(cls) << " ]";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
HighwayClass GetHighwayClass(feature::TypesHolder const & types)
|
||||
{
|
||||
uint8_t constexpr kTruncLevel = 2;
|
||||
static HighwayClasses highwayClasses;
|
||||
|
||||
for (auto t : types)
|
||||
{
|
||||
ftype::TruncValue(t, kTruncLevel);
|
||||
HighwayClass const hc = highwayClasses.Get(t);
|
||||
if (hc != HighwayClass::Error)
|
||||
return hc;
|
||||
}
|
||||
|
||||
return HighwayClass::Error;
|
||||
}
|
||||
|
||||
uint32_t BaseChecker::PrepareToMatch(uint32_t type, uint8_t level)
|
||||
{
|
||||
ftype::TruncValue(type, level);
|
||||
|
@ -386,75 +480,4 @@ bool IsTypeConformed(uint32_t type, StringIL const & path)
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string DebugPrint(HighwayClass const cls)
|
||||
{
|
||||
stringstream out;
|
||||
out << "[ ";
|
||||
switch (cls)
|
||||
{
|
||||
case HighwayClass::Undefined:
|
||||
out << "Undefined";
|
||||
case HighwayClass::Error:
|
||||
out << "Error";
|
||||
case HighwayClass::Trunk:
|
||||
out << "Trunk";
|
||||
case HighwayClass::Primary:
|
||||
out << "Primary";
|
||||
case HighwayClass::Secondary:
|
||||
out << "Secondary";
|
||||
case HighwayClass::Tertiary:
|
||||
out << "Tertiary";
|
||||
case HighwayClass::LivingStreet:
|
||||
out << "LivingStreet";
|
||||
case HighwayClass::Service:
|
||||
out << "Service";
|
||||
case HighwayClass::Count:
|
||||
out << "Count";
|
||||
default:
|
||||
out << "Unknown value of HighwayClass: " << static_cast<int>(cls);
|
||||
}
|
||||
out << " ]";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
HighwayClass GetHighwayClass(feature::TypesHolder const & types)
|
||||
{
|
||||
Classificator const & c = classif();
|
||||
static pair<HighwayClass, uint32_t> const kHighwayClasses[] = {
|
||||
{HighwayClass::Trunk, c.GetTypeByPath({"highway", "motorway"})},
|
||||
{HighwayClass::Trunk, c.GetTypeByPath({"highway", "motorway_link"})},
|
||||
{HighwayClass::Trunk, c.GetTypeByPath({"highway", "trunk"})},
|
||||
{HighwayClass::Trunk, c.GetTypeByPath({"highway", "trunk_link"})},
|
||||
{HighwayClass::Trunk, c.GetTypeByPath({"route", "ferry"})},
|
||||
{HighwayClass::Primary, c.GetTypeByPath({"highway", "primary"})},
|
||||
{HighwayClass::Primary, c.GetTypeByPath({"highway", "primary_link"})},
|
||||
{HighwayClass::Secondary, c.GetTypeByPath({"highway", "secondary"})},
|
||||
{HighwayClass::Secondary, c.GetTypeByPath({"highway", "secondary_link"})},
|
||||
{HighwayClass::Tertiary, c.GetTypeByPath({"highway", "tertiary"})},
|
||||
{HighwayClass::Tertiary, c.GetTypeByPath({"highway", "tertiary_link"})},
|
||||
{HighwayClass::LivingStreet, c.GetTypeByPath({"highway", "unclassified"})},
|
||||
{HighwayClass::LivingStreet, c.GetTypeByPath({"highway", "residential"})},
|
||||
{HighwayClass::LivingStreet, c.GetTypeByPath({"highway", "living_street"})},
|
||||
{HighwayClass::Service, c.GetTypeByPath({"highway", "service"})},
|
||||
{HighwayClass::Service, c.GetTypeByPath({"highway", "track"})}};
|
||||
uint8_t const kTruncLevel = 2;
|
||||
|
||||
for (auto t : types)
|
||||
{
|
||||
ftype::TruncValue(t, kTruncLevel);
|
||||
for (auto const & cls : kHighwayClasses)
|
||||
{
|
||||
if (cls.second == t)
|
||||
return cls.first;
|
||||
}
|
||||
}
|
||||
|
||||
return HighwayClass::Error;
|
||||
}
|
||||
|
||||
HighwayClass GetHighwayClass(FeatureType const & ft)
|
||||
{
|
||||
return GetHighwayClass(feature::TypesHolder(ft));
|
||||
}
|
||||
}
|
||||
} // namespace ftypes
|
||||
|
|
|
@ -205,12 +205,11 @@ enum class HighwayClass
|
|||
Tertiary,
|
||||
LivingStreet,
|
||||
Service,
|
||||
Count // This value is used for internals only.
|
||||
Pedestrian,
|
||||
Count // This value is used for internals only.
|
||||
};
|
||||
|
||||
string DebugPrint(HighwayClass const cls);
|
||||
|
||||
HighwayClass GetHighwayClass(feature::TypesHolder const & types);
|
||||
HighwayClass GetHighwayClass(FeatureType const & ft);
|
||||
|
||||
} // namespace ftypes
|
||||
|
|
215
routing/bicycle_directions.cpp
Normal file
215
routing/bicycle_directions.cpp
Normal file
|
@ -0,0 +1,215 @@
|
|||
#include "routing/bicycle_directions.hpp"
|
||||
#include "routing/car_model.hpp"
|
||||
#include "routing/router_delegate.hpp"
|
||||
#include "routing/routing_result_graph.hpp"
|
||||
#include "routing/turns_generator.hpp"
|
||||
|
||||
#include "indexer/ftypes_matcher.hpp"
|
||||
#include "indexer/index.hpp"
|
||||
#include "indexer/scales.hpp"
|
||||
|
||||
#include "geometry/point2d.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace routing;
|
||||
using namespace routing::turns;
|
||||
|
||||
class RoutingResult : public IRoutingResult
|
||||
{
|
||||
public:
|
||||
RoutingResult(IRoadGraph::TEdgeVector const & routeEdges,
|
||||
BicycleDirectionsEngine::TAdjacentEdgesMap const & adjacentEdges,
|
||||
TUnpackedPathSegments const & pathSegments)
|
||||
: m_routeEdges(routeEdges)
|
||||
, m_adjacentEdges(adjacentEdges)
|
||||
, m_pathSegments(pathSegments)
|
||||
, m_routeLength(0)
|
||||
{
|
||||
for (auto const & edge : routeEdges)
|
||||
{
|
||||
m_routeLength += MercatorBounds::DistanceOnEarth(edge.GetStartJunction().GetPoint(),
|
||||
edge.GetEndJunction().GetPoint());
|
||||
}
|
||||
}
|
||||
|
||||
// turns::IRoutingResult overrides:
|
||||
TUnpackedPathSegments const & GetSegments() const override { return m_pathSegments; }
|
||||
|
||||
void GetPossibleTurns(TNodeId node, m2::PointD const & ingoingPoint,
|
||||
m2::PointD const & junctionPoint, size_t & ingoingCount,
|
||||
TurnCandidates & outgoingTurns) const override
|
||||
{
|
||||
ingoingCount = 0;
|
||||
outgoingTurns.candidates.clear();
|
||||
|
||||
auto const adjacentEdges = m_adjacentEdges.find(node);
|
||||
if (adjacentEdges == m_adjacentEdges.cend())
|
||||
{
|
||||
ASSERT(false, ());
|
||||
return;
|
||||
}
|
||||
|
||||
ingoingCount = adjacentEdges->second.m_ingoingTurnsCount;
|
||||
outgoingTurns.candidates = adjacentEdges->second.m_outgoingTurns.candidates;
|
||||
}
|
||||
|
||||
double GetPathLength() const override { return m_routeLength; }
|
||||
|
||||
m2::PointD const & GetStartPoint() const override
|
||||
{
|
||||
CHECK(!m_routeEdges.empty(), ());
|
||||
return m_routeEdges.front().GetStartJunction().GetPoint();
|
||||
}
|
||||
|
||||
m2::PointD const & GetEndPoint() const override
|
||||
{
|
||||
CHECK(!m_routeEdges.empty(), ());
|
||||
return m_routeEdges.back().GetEndJunction().GetPoint();
|
||||
}
|
||||
|
||||
private:
|
||||
IRoadGraph::TEdgeVector const & m_routeEdges;
|
||||
BicycleDirectionsEngine::TAdjacentEdgesMap const & m_adjacentEdges;
|
||||
TUnpackedPathSegments const & m_pathSegments;
|
||||
double m_routeLength;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace routing
|
||||
{
|
||||
BicycleDirectionsEngine::BicycleDirectionsEngine(Index const & index) : m_index(index) {}
|
||||
|
||||
void BicycleDirectionsEngine::Generate(IRoadGraph const & graph, vector<Junction> const & path,
|
||||
Route::TTimes & times, Route::TTurns & turns,
|
||||
vector<m2::PointD> & routeGeometry,
|
||||
my::Cancellable const & cancellable)
|
||||
{
|
||||
times.clear();
|
||||
turns.clear();
|
||||
routeGeometry.clear();
|
||||
m_adjacentEdges.clear();
|
||||
m_pathSegments.clear();
|
||||
|
||||
size_t const pathSize = path.size();
|
||||
if (pathSize == 0)
|
||||
return;
|
||||
|
||||
auto emptyPathWorkaround = [&]()
|
||||
{
|
||||
turns.emplace_back(pathSize - 1, turns::TurnDirection::ReachedYourDestination);
|
||||
this->m_adjacentEdges[0] = AdjacentEdges(1); // There's one ingoing edge to the finish.
|
||||
};
|
||||
|
||||
if (pathSize == 1)
|
||||
{
|
||||
emptyPathWorkaround();
|
||||
return;
|
||||
}
|
||||
|
||||
CalculateTimes(graph, path, times);
|
||||
|
||||
IRoadGraph::TEdgeVector routeEdges;
|
||||
if (!ReconstructPath(graph, path, routeEdges, cancellable))
|
||||
{
|
||||
LOG(LDEBUG, ("Couldn't reconstruct path."));
|
||||
emptyPathWorkaround();
|
||||
return;
|
||||
}
|
||||
if (routeEdges.empty())
|
||||
{
|
||||
emptyPathWorkaround();
|
||||
return;
|
||||
}
|
||||
|
||||
// Filling |m_adjacentEdges|.
|
||||
m_adjacentEdges.insert(make_pair(0, AdjacentEdges(0)));
|
||||
for (size_t i = 1; i < pathSize; ++i)
|
||||
{
|
||||
Junction const & prevJunction = path[i - 1];
|
||||
Junction const & currJunction = path[i];
|
||||
IRoadGraph::TEdgeVector outgoingEdges, ingoingEdges;
|
||||
graph.GetOutgoingEdges(currJunction, outgoingEdges);
|
||||
graph.GetIngoingEdges(currJunction, ingoingEdges);
|
||||
|
||||
AdjacentEdges adjacentEdges = AdjacentEdges(ingoingEdges.size());
|
||||
// Outgoing edge angle is not used for bicyle routing.
|
||||
adjacentEdges.m_outgoingTurns.isCandidatesAngleValid = false;
|
||||
adjacentEdges.m_outgoingTurns.candidates.reserve(outgoingEdges.size());
|
||||
ASSERT_EQUAL(routeEdges.size(), pathSize - 1, ());
|
||||
FeatureID const inFeatureId = routeEdges[i - 1].GetFeatureId();
|
||||
|
||||
for (auto const & edge : outgoingEdges)
|
||||
{
|
||||
auto const & outFeatureId = edge.GetFeatureId();
|
||||
// Checking for if |edge| is a fake edge.
|
||||
if (!outFeatureId.IsValid())
|
||||
continue;
|
||||
adjacentEdges.m_outgoingTurns.candidates.emplace_back(0.0 /* angle */, outFeatureId.m_index,
|
||||
GetHighwayClass(outFeatureId));
|
||||
}
|
||||
|
||||
LoadedPathSegment pathSegment;
|
||||
if (inFeatureId.IsValid())
|
||||
{
|
||||
LoadPathGeometry(inFeatureId, {prevJunction.GetPoint(), currJunction.GetPoint()},
|
||||
pathSegment);
|
||||
}
|
||||
|
||||
m_adjacentEdges.insert(make_pair(inFeatureId.m_index, move(adjacentEdges)));
|
||||
m_pathSegments.push_back(move(pathSegment));
|
||||
}
|
||||
|
||||
RoutingResult resultGraph(routeEdges, m_adjacentEdges, m_pathSegments);
|
||||
RouterDelegate delegate;
|
||||
Route::TTimes turnAnnotationTimes;
|
||||
Route::TStreets streetNames;
|
||||
MakeTurnAnnotation(resultGraph, delegate, routeGeometry, turns, turnAnnotationTimes, streetNames);
|
||||
}
|
||||
|
||||
Index::FeaturesLoaderGuard & BicycleDirectionsEngine::GetLoader(MwmSet::MwmId const & id)
|
||||
{
|
||||
if (!m_loader || id != m_loader->GetId())
|
||||
m_loader = make_unique<Index::FeaturesLoaderGuard>(m_index, id);
|
||||
return *m_loader;
|
||||
}
|
||||
|
||||
ftypes::HighwayClass BicycleDirectionsEngine::GetHighwayClass(FeatureID const & featureId)
|
||||
{
|
||||
FeatureType ft;
|
||||
GetLoader(featureId.m_mwmId).GetFeatureByIndex(featureId.m_index, ft);
|
||||
auto const highwayClass = ftypes::GetHighwayClass(ft);
|
||||
ASSERT_NOT_EQUAL(highwayClass, ftypes::HighwayClass::Error, ());
|
||||
ASSERT_NOT_EQUAL(highwayClass, ftypes::HighwayClass::Undefined, ());
|
||||
return highwayClass;
|
||||
}
|
||||
|
||||
void BicycleDirectionsEngine::LoadPathGeometry(FeatureID const & featureId,
|
||||
vector<m2::PointD> const & path,
|
||||
LoadedPathSegment & pathSegment)
|
||||
{
|
||||
pathSegment.Clear();
|
||||
|
||||
if (!featureId.IsValid())
|
||||
{
|
||||
ASSERT(false, ());
|
||||
return;
|
||||
}
|
||||
|
||||
FeatureType ft;
|
||||
GetLoader(featureId.m_mwmId).GetFeatureByIndex(featureId.m_index, ft);
|
||||
auto const highwayClass = ftypes::GetHighwayClass(ft);
|
||||
ASSERT_NOT_EQUAL(highwayClass, ftypes::HighwayClass::Error, ());
|
||||
ASSERT_NOT_EQUAL(highwayClass, ftypes::HighwayClass::Undefined, ());
|
||||
|
||||
pathSegment.m_highwayClass = highwayClass;
|
||||
pathSegment.m_isLink = ftypes::IsLinkChecker::Instance()(ft);
|
||||
|
||||
ft.GetName(FeatureType::DEFAULT_LANG, pathSegment.m_name);
|
||||
|
||||
pathSegment.m_nodeId = featureId.m_index;
|
||||
pathSegment.m_onRoundabout = ftypes::IsRoundAboutChecker::Instance()(ft);
|
||||
pathSegment.m_path = path;
|
||||
// @TODO(bykoianko) It's better to fill pathSegment.m_weight.
|
||||
}
|
||||
} // namespace routing
|
45
routing/bicycle_directions.hpp
Normal file
45
routing/bicycle_directions.hpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include "routing/directions_engine.hpp"
|
||||
#include "routing/loaded_path_segment.hpp"
|
||||
#include "routing/turn_candidate.hpp"
|
||||
|
||||
#include "std/map.hpp"
|
||||
#include "std/unique_ptr.hpp"
|
||||
|
||||
class Index;
|
||||
|
||||
namespace routing
|
||||
{
|
||||
class BicycleDirectionsEngine : public IDirectionsEngine
|
||||
{
|
||||
public:
|
||||
struct AdjacentEdges
|
||||
{
|
||||
explicit AdjacentEdges(size_t ingoingTurnsCount = 0) : m_ingoingTurnsCount(ingoingTurnsCount) {}
|
||||
|
||||
turns::TurnCandidates m_outgoingTurns;
|
||||
size_t m_ingoingTurnsCount;
|
||||
};
|
||||
|
||||
using TAdjacentEdgesMap = map<TNodeId, AdjacentEdges>;
|
||||
|
||||
BicycleDirectionsEngine(Index const & index);
|
||||
|
||||
// IDirectionsEngine override:
|
||||
void Generate(IRoadGraph const & graph, vector<Junction> const & path, Route::TTimes & times,
|
||||
Route::TTurns & turns, vector<m2::PointD> & routeGeometry,
|
||||
my::Cancellable const & cancellable) override;
|
||||
|
||||
private:
|
||||
Index::FeaturesLoaderGuard & GetLoader(MwmSet::MwmId const & id);
|
||||
ftypes::HighwayClass GetHighwayClass(FeatureID const & featureId);
|
||||
void LoadPathGeometry(FeatureID const & featureId, vector<m2::PointD> const & path,
|
||||
LoadedPathSegment & pathSegment);
|
||||
|
||||
TAdjacentEdgesMap m_adjacentEdges;
|
||||
TUnpackedPathSegments m_pathSegments;
|
||||
Index const & m_index;
|
||||
unique_ptr<Index::FeaturesLoaderGuard> m_loader;
|
||||
};
|
||||
} // namespace routing
|
90
routing/directions_engine.cpp
Normal file
90
routing/directions_engine.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
#include "routing/directions_engine.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
double constexpr KMPH2MPS = 1000.0 / (60 * 60);
|
||||
} // namespace
|
||||
|
||||
namespace routing
|
||||
{
|
||||
void IDirectionsEngine::CalculateTimes(IRoadGraph const & graph, vector<Junction> const & path,
|
||||
Route::TTimes & times) const
|
||||
{
|
||||
times.clear();
|
||||
if (path.size() <= 1)
|
||||
return;
|
||||
|
||||
// graph.GetMaxSpeedKMPH() below is used on purpose.
|
||||
// The idea is while pedestian (bicycle) routing ways for pedestrians (cyclists) are prefered.
|
||||
// At the same time routing along big roads is still possible but if there's
|
||||
// a pedestrian (bicycle) alternative it's prefered. To implement it a small speed
|
||||
// is set in pedestrian_model (bicycle_model) for big roads. On the other hand
|
||||
// the most likely a pedestrian (a cyclist) will go along big roads with average
|
||||
// speed (graph.GetMaxSpeedKMPH()).
|
||||
double const speedMPS = graph.GetMaxSpeedKMPH() * KMPH2MPS;
|
||||
|
||||
times.reserve(path.size());
|
||||
|
||||
double trackTimeSec = 0.0;
|
||||
times.emplace_back(0, trackTimeSec);
|
||||
|
||||
m2::PointD prev = path[0].GetPoint();
|
||||
for (size_t i = 1; i < path.size(); ++i)
|
||||
{
|
||||
m2::PointD const & curr = path[i].GetPoint();
|
||||
|
||||
double const lengthM = MercatorBounds::DistanceOnEarth(prev, curr);
|
||||
trackTimeSec += lengthM / speedMPS;
|
||||
|
||||
times.emplace_back(i, trackTimeSec);
|
||||
|
||||
prev = curr;
|
||||
}
|
||||
}
|
||||
|
||||
bool IDirectionsEngine::ReconstructPath(IRoadGraph const & graph, vector<Junction> const & path,
|
||||
vector<Edge> & routeEdges,
|
||||
my::Cancellable const & cancellable) const
|
||||
{
|
||||
routeEdges.clear();
|
||||
if (path.size() <= 1)
|
||||
return false;
|
||||
|
||||
routeEdges.reserve(path.size() - 1);
|
||||
|
||||
Junction curr = path[0];
|
||||
vector<Edge> currEdges;
|
||||
for (size_t i = 1; i < path.size(); ++i)
|
||||
{
|
||||
if (cancellable.IsCancelled())
|
||||
return false;
|
||||
|
||||
Junction const & next = path[i];
|
||||
|
||||
currEdges.clear();
|
||||
graph.GetOutgoingEdges(curr, currEdges);
|
||||
|
||||
bool found = false;
|
||||
for (auto const & e : currEdges)
|
||||
{
|
||||
if (e.GetEndJunction() == next)
|
||||
{
|
||||
routeEdges.emplace_back(e);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return false;
|
||||
|
||||
curr = next;
|
||||
}
|
||||
|
||||
ASSERT_EQUAL(routeEdges.size() + 1, path.size(), ());
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace routing
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "base/cancellable.hpp"
|
||||
|
||||
#include "std/vector.hpp"
|
||||
|
||||
namespace routing
|
||||
{
|
||||
|
||||
|
@ -14,9 +16,19 @@ public:
|
|||
virtual ~IDirectionsEngine() = default;
|
||||
|
||||
virtual void Generate(IRoadGraph const & graph, vector<Junction> const & path,
|
||||
Route::TTimes & times,
|
||||
Route::TTurns & turnsDir,
|
||||
Route::TTimes & times, Route::TTurns & turns,
|
||||
vector<m2::PointD> & routeGeometry,
|
||||
my::Cancellable const & cancellable) = 0;
|
||||
|
||||
protected:
|
||||
/// \brief constructs route based on |graph| and |path|. Fills |routeEdges| with the route.
|
||||
/// \returns false in case of any errors while reconstruction, if reconstruction process
|
||||
/// was cancelled and in case of extremely short paths of 0 or 1 point. Returns true otherwise.
|
||||
bool ReconstructPath(IRoadGraph const & graph, vector<Junction> const & path,
|
||||
vector<Edge> & routeEdges, my::Cancellable const & cancellable) const;
|
||||
|
||||
void CalculateTimes(IRoadGraph const & graph, vector<Junction> const & path,
|
||||
Route::TTimes & times) const;
|
||||
};
|
||||
|
||||
} // namespace routing
|
||||
|
|
|
@ -28,8 +28,8 @@ struct LoadedPathSegment
|
|||
vector<m2::PointD> m_path;
|
||||
vector<turns::SingleLaneInfo> m_lanes;
|
||||
string m_name;
|
||||
TEdgeWeight m_weight;
|
||||
TNodeId m_nodeId;
|
||||
TEdgeWeight m_weight; /*!< Time in seconds to pass the segment. */
|
||||
TNodeId m_nodeId; /*!< May be NodeId for OSRM router or FeatureId::index for graph router. */
|
||||
ftypes::HighwayClass m_highwayClass;
|
||||
bool m_onRoundabout;
|
||||
bool m_isLink;
|
||||
|
|
|
@ -52,30 +52,21 @@ double constexpr kMwmLoadedProgress = 10.0f;
|
|||
double constexpr kPointsFoundProgress = 15.0f;
|
||||
double constexpr kCrossPathFoundProgress = 50.0f;
|
||||
double constexpr kPathFoundProgress = 70.0f;
|
||||
|
||||
double PiMinusTwoVectorsAngle(m2::PointD const & p, m2::PointD const & p1, m2::PointD const & p2)
|
||||
{
|
||||
return math::pi - ang::TwoVectorsAngle(p, p1, p2);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
using RawRouteData = InternalRouteResult;
|
||||
|
||||
class OSRMRoutingResultGraph : public turns::IRoutingResultGraph
|
||||
class OSRMRoutingResult : public turns::IRoutingResult
|
||||
{
|
||||
public:
|
||||
// turns::IRoutingResultGraph overrides:
|
||||
virtual TUnpackedPathSegments const & GetSegments() const override
|
||||
{
|
||||
return m_loadedSegments;
|
||||
}
|
||||
virtual void GetPossibleTurns(TNodeId node, m2::PointD const & ingoingPoint,
|
||||
m2::PointD const & junctionPoint,
|
||||
size_t & ingoingCount,
|
||||
turns::TTurnCandidates & outgoingTurns) const override
|
||||
// turns::IRoutingResult overrides:
|
||||
TUnpackedPathSegments const & GetSegments() const override { return m_loadedSegments; }
|
||||
|
||||
void GetPossibleTurns(TNodeId node, m2::PointD const & ingoingPoint,
|
||||
m2::PointD const & junctionPoint, size_t & ingoingCount,
|
||||
turns::TurnCandidates & outgoingTurns) const override
|
||||
{
|
||||
double const kReadCrossEpsilon = 1.0E-4;
|
||||
double const kFeaturesNearTurnMeters = 3.0;
|
||||
|
||||
// Geting nodes by geometry.
|
||||
vector<NodeID> geomNodes;
|
||||
|
@ -143,31 +134,28 @@ public:
|
|||
m2::PointD const outgoingPoint = ft.GetPoint(
|
||||
seg.m_pointStart < seg.m_pointEnd ? seg.m_pointStart + 1 : seg.m_pointStart - 1);
|
||||
ASSERT_LESS(MercatorBounds::DistanceOnEarth(junctionPoint, ft.GetPoint(seg.m_pointStart)),
|
||||
kFeaturesNearTurnMeters, ());
|
||||
turns::kFeaturesNearTurnMeters, ());
|
||||
|
||||
outgoingTurns.isCandidatesAngleValid = true;
|
||||
double const a =
|
||||
my::RadToDeg(PiMinusTwoVectorsAngle(junctionPoint, ingoingPoint, outgoingPoint));
|
||||
outgoingTurns.emplace_back(a, targetNode, ftypes::GetHighwayClass(ft));
|
||||
my::RadToDeg(turns::PiMinusTwoVectorsAngle(junctionPoint, ingoingPoint, outgoingPoint));
|
||||
outgoingTurns.candidates.emplace_back(a, targetNode, ftypes::GetHighwayClass(ft));
|
||||
}
|
||||
|
||||
sort(outgoingTurns.begin(), outgoingTurns.end(),
|
||||
sort(outgoingTurns.candidates.begin(), outgoingTurns.candidates.end(),
|
||||
[](turns::TurnCandidate const & t1, turns::TurnCandidate const & t2)
|
||||
{
|
||||
return t1.angle < t2.angle;
|
||||
});
|
||||
{
|
||||
return t1.angle < t2.angle;
|
||||
});
|
||||
}
|
||||
|
||||
virtual double GetShortestPathLength() const override { return m_rawResult.shortestPathLength; }
|
||||
virtual m2::PointD const & GetStartPoint() const override
|
||||
{
|
||||
return m_rawResult.sourceEdge.segmentPoint;
|
||||
}
|
||||
virtual m2::PointD const & GetEndPoint() const override
|
||||
{
|
||||
return m_rawResult.targetEdge.segmentPoint;
|
||||
}
|
||||
double GetPathLength() const override { return m_rawResult.shortestPathLength; }
|
||||
|
||||
OSRMRoutingResultGraph(Index const & index, RoutingMapping & mapping, RawRoutingResult & result)
|
||||
m2::PointD const & GetStartPoint() const override { return m_rawResult.sourceEdge.segmentPoint; }
|
||||
|
||||
m2::PointD const & GetEndPoint() const override { return m_rawResult.targetEdge.segmentPoint; }
|
||||
|
||||
OSRMRoutingResult(Index const & index, RoutingMapping & mapping, RawRoutingResult & result)
|
||||
: m_rawResult(result), m_index(index), m_routingMapping(mapping)
|
||||
{
|
||||
for (auto const & pathSegments : m_rawResult.unpackedPathSegments)
|
||||
|
@ -193,7 +181,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
~OSRMRoutingResultGraph() {}
|
||||
private:
|
||||
TUnpackedPathSegments m_loadedSegments;
|
||||
RawRoutingResult m_rawResult;
|
||||
|
@ -336,7 +323,7 @@ OsrmRouter::ResultCode OsrmRouter::MakeRouteFromCrossesPath(TCheckedPath const &
|
|||
Route::TTimes mwmTimes;
|
||||
Route::TStreets mwmStreets;
|
||||
vector<m2::PointD> mwmPoints;
|
||||
OSRMRoutingResultGraph resultGraph(*m_pIndex, *mwmMapping, routingResult);
|
||||
OSRMRoutingResult resultGraph(*m_pIndex, *mwmMapping, routingResult);
|
||||
if (MakeTurnAnnotation(resultGraph, delegate, mwmPoints, mwmTurnsDir, mwmTimes, mwmStreets) != NoError)
|
||||
{
|
||||
LOG(LWARNING, ("Can't load road path data from disk for", mwmMapping->GetCountryName()));
|
||||
|
@ -506,7 +493,7 @@ OsrmRouter::ResultCode OsrmRouter::CalculateRoute(m2::PointD const & startPoint,
|
|||
Route::TStreets streets;
|
||||
vector<m2::PointD> points;
|
||||
|
||||
OSRMRoutingResultGraph resultGraph(*m_pIndex, *startMapping, routingResult);
|
||||
OSRMRoutingResult resultGraph(*m_pIndex, *startMapping, routingResult);
|
||||
if (MakeTurnAnnotation(resultGraph, delegate, points, turnsDir, times, streets) != NoError)
|
||||
{
|
||||
LOG(LWARNING, ("Can't load road path data from disk!"));
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
#include "routing/pedestrian_directions.hpp"
|
||||
#include "routing/turns_generator.hpp"
|
||||
#include "routing/road_graph.hpp"
|
||||
|
||||
#include "indexer/classificator.hpp"
|
||||
#include "indexer/feature.hpp"
|
||||
#include "indexer/ftypes_matcher.hpp"
|
||||
#include "indexer/index.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/logging.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
double constexpr KMPH2MPS = 1000.0 / (60 * 60);
|
||||
|
||||
bool HasType(uint32_t type, feature::TypesHolder const & types)
|
||||
{
|
||||
for (uint32_t t : types)
|
||||
|
@ -23,6 +20,14 @@ bool HasType(uint32_t type, feature::TypesHolder const & types)
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Convert(vector<routing::Junction> const & path, vector<m2::PointD> & geometry)
|
||||
{
|
||||
size_t const pathSize = path.size();
|
||||
geometry.resize(pathSize);
|
||||
for (size_t i = 0; i < pathSize; ++i)
|
||||
geometry[i] = path[i].GetPoint();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace routing
|
||||
|
@ -36,92 +41,35 @@ PedestrianDirectionsEngine::PedestrianDirectionsEngine()
|
|||
}
|
||||
|
||||
void PedestrianDirectionsEngine::Generate(IRoadGraph const & graph, vector<Junction> const & path,
|
||||
Route::TTimes & times,
|
||||
Route::TTurns & turnsDir,
|
||||
Route::TTimes & times, Route::TTurns & turns,
|
||||
vector<m2::PointD> & routeGeometry,
|
||||
my::Cancellable const & cancellable)
|
||||
{
|
||||
CHECK_GREATER(path.size(), 1, ());
|
||||
times.clear();
|
||||
turns.clear();
|
||||
routeGeometry.clear();
|
||||
|
||||
if (path.size() <= 1)
|
||||
return;
|
||||
|
||||
CalculateTimes(graph, path, times);
|
||||
|
||||
vector<Edge> routeEdges;
|
||||
if (!ReconstructPath(graph, path, routeEdges, cancellable))
|
||||
{
|
||||
LOG(LDEBUG, ("Couldn't reconstruct path"));
|
||||
LOG(LDEBUG, ("Couldn't reconstruct path."));
|
||||
// use only "arrival" direction
|
||||
turnsDir.emplace_back(path.size() - 1, turns::PedestrianDirection::ReachedYourDestination);
|
||||
turns.emplace_back(path.size() - 1, turns::PedestrianDirection::ReachedYourDestination);
|
||||
return;
|
||||
}
|
||||
|
||||
CalculateTurns(graph, routeEdges, turnsDir, cancellable);
|
||||
CalculateTurns(graph, routeEdges, turns, cancellable);
|
||||
Convert(path, routeGeometry);
|
||||
}
|
||||
|
||||
bool PedestrianDirectionsEngine::ReconstructPath(IRoadGraph const & graph, vector<Junction> const & path,
|
||||
vector<Edge> & routeEdges,
|
||||
my::Cancellable const & cancellable) const
|
||||
{
|
||||
routeEdges.reserve(path.size() - 1);
|
||||
|
||||
Junction curr = path[0];
|
||||
vector<Edge> currEdges;
|
||||
for (size_t i = 1; i < path.size(); ++i)
|
||||
{
|
||||
if (cancellable.IsCancelled())
|
||||
return false;
|
||||
|
||||
Junction const & next = path[i];
|
||||
|
||||
currEdges.clear();
|
||||
graph.GetOutgoingEdges(curr, currEdges);
|
||||
|
||||
bool found = false;
|
||||
for (Edge const & e : currEdges)
|
||||
{
|
||||
if (e.GetEndJunction() == next)
|
||||
{
|
||||
routeEdges.emplace_back(e);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return false;
|
||||
|
||||
curr = next;
|
||||
}
|
||||
|
||||
ASSERT_EQUAL(routeEdges.size()+1, path.size(), ());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PedestrianDirectionsEngine::CalculateTimes(IRoadGraph const & graph, vector<Junction> const & path,
|
||||
Route::TTimes & times) const
|
||||
{
|
||||
double const speedMPS = graph.GetMaxSpeedKMPH() * KMPH2MPS;
|
||||
|
||||
times.reserve(path.size());
|
||||
|
||||
double trackTimeSec = 0.0;
|
||||
times.emplace_back(0, trackTimeSec);
|
||||
|
||||
m2::PointD prev = path[0].GetPoint();
|
||||
for (size_t i = 1; i < path.size(); ++i)
|
||||
{
|
||||
m2::PointD const & curr = path[i].GetPoint();
|
||||
|
||||
double const lengthM = MercatorBounds::DistanceOnEarth(prev, curr);
|
||||
trackTimeSec += lengthM / speedMPS;
|
||||
|
||||
times.emplace_back(i, trackTimeSec);
|
||||
|
||||
prev = curr;
|
||||
}
|
||||
}
|
||||
|
||||
void PedestrianDirectionsEngine::CalculateTurns(IRoadGraph const & graph, vector<Edge> const & routeEdges,
|
||||
Route::TTurns & turnsDir,
|
||||
void PedestrianDirectionsEngine::CalculateTurns(IRoadGraph const & graph,
|
||||
vector<Edge> const & routeEdges,
|
||||
Route::TTurns & turns,
|
||||
my::Cancellable const & cancellable) const
|
||||
{
|
||||
for (size_t i = 0; i < routeEdges.size(); ++i)
|
||||
|
@ -137,24 +85,23 @@ void PedestrianDirectionsEngine::CalculateTurns(IRoadGraph const & graph, vector
|
|||
if (HasType(m_typeSteps, types))
|
||||
{
|
||||
if (edge.IsForward())
|
||||
turnsDir.emplace_back(i, turns::PedestrianDirection::Upstairs);
|
||||
turns.emplace_back(i, turns::PedestrianDirection::Upstairs);
|
||||
else
|
||||
turnsDir.emplace_back(i, turns::PedestrianDirection::Downstairs);
|
||||
turns.emplace_back(i, turns::PedestrianDirection::Downstairs);
|
||||
}
|
||||
else
|
||||
{
|
||||
graph.GetJunctionTypes(edge.GetStartJunction(), types);
|
||||
|
||||
if (HasType(m_typeLiftGate, types))
|
||||
turnsDir.emplace_back(i, turns::PedestrianDirection::LiftGate);
|
||||
turns.emplace_back(i, turns::PedestrianDirection::LiftGate);
|
||||
else if (HasType(m_typeGate, types))
|
||||
turnsDir.emplace_back(i, turns::PedestrianDirection::Gate);
|
||||
turns.emplace_back(i, turns::PedestrianDirection::Gate);
|
||||
}
|
||||
}
|
||||
|
||||
// direction "arrival"
|
||||
// (index of last junction is the same as number of edges)
|
||||
turnsDir.emplace_back(routeEdges.size(), turns::PedestrianDirection::ReachedYourDestination);
|
||||
turns.emplace_back(routeEdges.size(), turns::PedestrianDirection::ReachedYourDestination);
|
||||
}
|
||||
|
||||
} // namespace routing
|
||||
|
|
|
@ -11,19 +11,11 @@ public:
|
|||
PedestrianDirectionsEngine();
|
||||
|
||||
// IDirectionsEngine override:
|
||||
void Generate(IRoadGraph const & graph, vector<Junction> const & path,
|
||||
Route::TTimes & times,
|
||||
Route::TTurns & turnsDir,
|
||||
void Generate(IRoadGraph const & graph, vector<Junction> const & path, Route::TTimes & times,
|
||||
Route::TTurns & turns, vector<m2::PointD> & routeGeometry,
|
||||
my::Cancellable const & cancellable) override;
|
||||
|
||||
private:
|
||||
bool ReconstructPath(IRoadGraph const & graph, vector<Junction> const & path,
|
||||
vector<Edge> & routeEdges,
|
||||
my::Cancellable const & cancellable) const;
|
||||
|
||||
void CalculateTimes(IRoadGraph const & graph, vector<Junction> const & path,
|
||||
Route::TTimes & times) const;
|
||||
|
||||
void CalculateTurns(IRoadGraph const & graph, vector<Edge> const & routeEdges,
|
||||
Route::TTurns & turnsDir,
|
||||
my::Cancellable const & cancellable) const;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "routing/bicycle_directions.hpp"
|
||||
#include "routing/bicycle_model.hpp"
|
||||
#include "routing/features_road_graph.hpp"
|
||||
#include "routing/nearest_edge_finder.hpp"
|
||||
|
@ -49,14 +50,6 @@ IRouter::ResultCode Convert(IRoutingAlgorithm::Result value)
|
|||
return IRouter::ResultCode::RouteNotFound;
|
||||
}
|
||||
|
||||
void Convert(vector<Junction> const & path, vector<m2::PointD> & geometry)
|
||||
{
|
||||
geometry.clear();
|
||||
geometry.reserve(path.size());
|
||||
for (auto const & pos : path)
|
||||
geometry.emplace_back(pos.GetPoint());
|
||||
}
|
||||
|
||||
// Check if the found edges lays on mwm with pedestrian routing support.
|
||||
bool CheckMwmVersion(vector<pair<Edge, m2::PointD>> const & vicinities, vector<string> & mwmNames)
|
||||
{
|
||||
|
@ -172,7 +165,6 @@ IRouter::ResultCode RoadGraphRouter::CalculateRoute(m2::PointD const & startPoin
|
|||
m2::PointD const & finalPoint,
|
||||
RouterDelegate const & delegate, Route & route)
|
||||
{
|
||||
|
||||
if (!CheckMapExistence(startPoint, route) || !CheckMapExistence(finalPoint, route))
|
||||
return RouteFileNotExist;
|
||||
|
||||
|
@ -247,14 +239,13 @@ void RoadGraphRouter::ReconstructRoute(vector<Junction> && path, Route & route,
|
|||
if (path.size() == 1)
|
||||
path.emplace_back(path.back());
|
||||
|
||||
vector<m2::PointD> geometry;
|
||||
Convert(path, geometry);
|
||||
|
||||
Route::TTimes times;
|
||||
Route::TTurns turnsDir;
|
||||
vector<m2::PointD> geometry;
|
||||
// @TODO(bykoianko) streetNames is not filled in Generate(). It should be done.
|
||||
Route::TStreets streetNames;
|
||||
if (m_directionsEngine)
|
||||
m_directionsEngine->Generate(*m_roadGraph, path, times, turnsDir, cancellable);
|
||||
m_directionsEngine->Generate(*m_roadGraph, path, times, turnsDir, geometry, cancellable);
|
||||
|
||||
route.SetGeometry(geometry.begin(), geometry.end());
|
||||
route.SetSectionTimes(times);
|
||||
|
@ -267,7 +258,9 @@ unique_ptr<IRouter> CreatePedestrianAStarRouter(Index & index, TCountryFileFn co
|
|||
unique_ptr<IVehicleModelFactory> vehicleModelFactory(new PedestrianModelFactory());
|
||||
unique_ptr<IRoutingAlgorithm> algorithm(new AStarRoutingAlgorithm());
|
||||
unique_ptr<IDirectionsEngine> directionsEngine(new PedestrianDirectionsEngine());
|
||||
unique_ptr<IRouter> router(new RoadGraphRouter("astar-pedestrian", index, countryFileFn, move(vehicleModelFactory), move(algorithm), move(directionsEngine)));
|
||||
unique_ptr<IRouter> router(new RoadGraphRouter("astar-pedestrian", index, countryFileFn,
|
||||
move(vehicleModelFactory), move(algorithm),
|
||||
move(directionsEngine)));
|
||||
return router;
|
||||
}
|
||||
|
||||
|
@ -276,7 +269,9 @@ unique_ptr<IRouter> CreatePedestrianAStarBidirectionalRouter(Index & index, TCou
|
|||
unique_ptr<IVehicleModelFactory> vehicleModelFactory(new PedestrianModelFactory());
|
||||
unique_ptr<IRoutingAlgorithm> algorithm(new AStarBidirectionalRoutingAlgorithm());
|
||||
unique_ptr<IDirectionsEngine> directionsEngine(new PedestrianDirectionsEngine());
|
||||
unique_ptr<IRouter> router(new RoadGraphRouter("astar-bidirectional-pedestrian", index, countryFileFn, move(vehicleModelFactory), move(algorithm), move(directionsEngine)));
|
||||
unique_ptr<IRouter> router(new RoadGraphRouter("astar-bidirectional-pedestrian", index,
|
||||
countryFileFn, move(vehicleModelFactory),
|
||||
move(algorithm), move(directionsEngine)));
|
||||
return router;
|
||||
}
|
||||
|
||||
|
@ -284,10 +279,9 @@ unique_ptr<IRouter> CreateBicycleAStarBidirectionalRouter(Index & index, TCountr
|
|||
{
|
||||
unique_ptr<IVehicleModelFactory> vehicleModelFactory(new BicycleModelFactory());
|
||||
unique_ptr<IRoutingAlgorithm> algorithm(new AStarBidirectionalRoutingAlgorithm());
|
||||
unique_ptr<IDirectionsEngine> directionsEngine(new PedestrianDirectionsEngine());
|
||||
unique_ptr<IDirectionsEngine> directionsEngine(new BicycleDirectionsEngine(index));
|
||||
unique_ptr<IRouter> router(new RoadGraphRouter("astar-bidirectional-bicycle", index, countryFileFn, move(vehicleModelFactory),
|
||||
move(algorithm), move(directionsEngine)));
|
||||
return router;
|
||||
}
|
||||
|
||||
} // namespace routing
|
||||
|
|
|
@ -50,18 +50,25 @@ void Route::AddAbsentCountry(string const & name)
|
|||
|
||||
double Route::GetTotalDistanceMeters() const
|
||||
{
|
||||
if (!m_poly.IsValid())
|
||||
return 0.0;
|
||||
return m_poly.GetTotalDistanceM();
|
||||
}
|
||||
|
||||
double Route::GetCurrentDistanceFromBeginMeters() const
|
||||
{
|
||||
if (!m_poly.IsValid())
|
||||
return 0.0;
|
||||
return m_poly.GetDistanceFromBeginM();
|
||||
}
|
||||
|
||||
void Route::GetTurnsDistances(vector<double> & distances) const
|
||||
{
|
||||
double mercatorDistance = 0;
|
||||
distances.clear();
|
||||
if (!m_poly.IsValid())
|
||||
return;
|
||||
|
||||
double mercatorDistance = 0.0;
|
||||
auto const & polyline = m_poly.GetPolyline();
|
||||
for (auto currentTurn = m_turns.begin(); currentTurn != m_turns.end(); ++currentTurn)
|
||||
{
|
||||
|
@ -84,6 +91,8 @@ void Route::GetTurnsDistances(vector<double> & distances) const
|
|||
|
||||
double Route::GetCurrentDistanceToEndMeters() const
|
||||
{
|
||||
if (!m_poly.IsValid())
|
||||
return 0.0;
|
||||
return m_poly.GetDistanceToEndM();
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,10 @@ public:
|
|||
|
||||
template <class TIter> void SetGeometry(TIter beg, TIter end)
|
||||
{
|
||||
FollowedPolyline(beg, end).Swap(m_poly);
|
||||
if (beg == end)
|
||||
FollowedPolyline().Swap(m_poly);
|
||||
else
|
||||
FollowedPolyline(beg, end).Swap(m_poly);
|
||||
Update();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,11 +15,13 @@ INCLUDEPATH += $$ROOT_DIR/3party/jansson/src \
|
|||
SOURCES += \
|
||||
async_router.cpp \
|
||||
base/followed_polyline.cpp \
|
||||
bicycle_directions.cpp \
|
||||
bicycle_model.cpp \
|
||||
car_model.cpp \
|
||||
cross_mwm_road_graph.cpp \
|
||||
cross_mwm_router.cpp \
|
||||
cross_routing_context.cpp \
|
||||
directions_engine.cpp \
|
||||
features_road_graph.cpp \
|
||||
nearest_edge_finder.cpp \
|
||||
online_absent_fetcher.cpp \
|
||||
|
@ -51,7 +53,8 @@ HEADERS += \
|
|||
async_router.hpp \
|
||||
base/astar_algorithm.hpp \
|
||||
base/followed_polyline.hpp \
|
||||
bicycle_model.cpp \
|
||||
bicycle_directions.hpp \
|
||||
bicycle_model.hpp \
|
||||
car_model.hpp \
|
||||
cross_mwm_road_graph.hpp \
|
||||
cross_mwm_router.hpp \
|
||||
|
|
15
routing/routing_integration_tests/bicycle_route_test.cpp
Normal file
15
routing/routing_integration_tests/bicycle_route_test.cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "routing/routing_integration_tests/routing_test_tools.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
using namespace routing;
|
||||
using namespace routing::turns;
|
||||
|
||||
UNIT_TEST(RussiaMoscowSevTushinoParkPreferingBicycleWay)
|
||||
{
|
||||
integration::CalculateRouteAndTestRouteLength(
|
||||
integration::GetBicycleComponents(), MercatorBounds::FromLatLon(55.87445, 37.43711), {0., 0.},
|
||||
MercatorBounds::FromLatLon(55.87203, 37.44274), 460.);
|
||||
}
|
69
routing/routing_integration_tests/bicycle_turn_test.cpp
Normal file
69
routing/routing_integration_tests/bicycle_turn_test.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "routing/routing_integration_tests/routing_test_tools.hpp"
|
||||
|
||||
#include "routing/route.hpp"
|
||||
|
||||
using namespace routing;
|
||||
using namespace routing::turns;
|
||||
|
||||
UNIT_TEST(RussiaMoscowSevTushinoParkBicycleWayTurnTest)
|
||||
{
|
||||
TRouteResult const routeResult = integration::CalculateRoute(
|
||||
integration::GetBicycleComponents(), MercatorBounds::FromLatLon(55.87467, 37.43658),
|
||||
{0.0, 0.0}, MercatorBounds::FromLatLon(55.8719, 37.4464));
|
||||
|
||||
Route const & route = *routeResult.first;
|
||||
IRouter::ResultCode const result = routeResult.second;
|
||||
TEST_EQUAL(result, IRouter::NoError, ());
|
||||
|
||||
integration::TestTurnCount(route, 1);
|
||||
|
||||
integration::GetNthTurn(route, 0).TestValid().TestDirection(TurnDirection::TurnLeft);
|
||||
|
||||
integration::TestRouteLength(route, 752.);
|
||||
}
|
||||
|
||||
UNIT_TEST(RussiaMoscowGerPanfilovtsev22BicycleWayTurnTest)
|
||||
{
|
||||
TRouteResult const routeResult = integration::CalculateRoute(
|
||||
integration::GetBicycleComponents(), MercatorBounds::FromLatLon(55.85630, 37.41004),
|
||||
{0.0, 0.0}, MercatorBounds::FromLatLon(55.85717, 37.41052));
|
||||
|
||||
Route const & route = *routeResult.first;
|
||||
IRouter::ResultCode const result = routeResult.second;
|
||||
TEST_EQUAL(result, IRouter::NoError, ());
|
||||
|
||||
integration::TestTurnCount(route, 2);
|
||||
|
||||
integration::GetNthTurn(route, 0).TestValid().TestDirection(TurnDirection::TurnLeft);
|
||||
integration::GetNthTurn(route, 1).TestValid().TestDirection(TurnDirection::TurnLeft);
|
||||
}
|
||||
|
||||
UNIT_TEST(RussiaMoscowSalameiNerisPossibleTurnCorrectionBicycleWayTurnTest)
|
||||
{
|
||||
TRouteResult const routeResult = integration::CalculateRoute(
|
||||
integration::GetBicycleComponents(), MercatorBounds::FromLatLon(55.85159, 37.38903),
|
||||
{0.0, 0.0}, MercatorBounds::FromLatLon(55.85157, 37.38813));
|
||||
|
||||
Route const & route = *routeResult.first;
|
||||
IRouter::ResultCode const result = routeResult.second;
|
||||
TEST_EQUAL(result, IRouter::NoError, ());
|
||||
|
||||
integration::TestTurnCount(route, 1);
|
||||
|
||||
integration::GetNthTurn(route, 0).TestValid().TestDirection(TurnDirection::TurnSlightRight);
|
||||
}
|
||||
|
||||
UNIT_TEST(RussiaMoscowSevTushinoParkBicycleOnePointTurnTest)
|
||||
{
|
||||
m2::PointD const point = MercatorBounds::FromLatLon(55.8719, 37.4464);
|
||||
TRouteResult const routeResult =
|
||||
integration::CalculateRoute(integration::GetBicycleComponents(), point, {0.0, 0.0}, point);
|
||||
|
||||
Route const & route = *routeResult.first;
|
||||
IRouter::ResultCode const result = routeResult.second;
|
||||
TEST_EQUAL(result, IRouter::NoError, ());
|
||||
TEST_EQUAL(route.GetTurns().size(), 0, ());
|
||||
integration::TestRouteLength(route, 0.0);
|
||||
}
|
|
@ -515,3 +515,16 @@ UNIT_TEST(MoscowChistiePrudiSelectPointsInConnectedGraph)
|
|||
MercatorBounds::FromLatLon(55.76613, 37.63769), {0., 0.},
|
||||
MercatorBounds::FromLatLon(55.76593, 37.63893), 134.02);
|
||||
}
|
||||
|
||||
UNIT_TEST(RussiaMoscowSevTushinoParkPedestrianOnePointTurnTest)
|
||||
{
|
||||
m2::PointD const point = MercatorBounds::FromLatLon(55.8719, 37.4464);
|
||||
TRouteResult const routeResult =
|
||||
integration::CalculateRoute(integration::GetPedestrianComponents(), point, {0.0, 0.0}, point);
|
||||
|
||||
Route const & route = *routeResult.first;
|
||||
IRouter::ResultCode const result = routeResult.second;
|
||||
TEST_EQUAL(result, IRouter::NoError, ());
|
||||
integration::TestTurnCount(route, 0);
|
||||
integration::TestRouteLength(route, 0.0);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ QT *= core
|
|||
|
||||
SOURCES += \
|
||||
../../testing/testingmain.cpp \
|
||||
bicycle_route_test.cpp \
|
||||
bicycle_turn_test.cpp \
|
||||
cross_section_tests.cpp \
|
||||
online_cross_tests.cpp \
|
||||
osrm_route_test.cpp \
|
||||
|
|
|
@ -31,16 +31,21 @@
|
|||
|
||||
using namespace routing;
|
||||
|
||||
using TRouterFactory =
|
||||
function<unique_ptr<IRouter>(Index & index, TCountryFileFn const & countryFileFn)>;
|
||||
|
||||
namespace
|
||||
{
|
||||
void ChangeMaxNumberOfOpenFiles(size_t n)
|
||||
{
|
||||
struct rlimit rlp;
|
||||
getrlimit(RLIMIT_NOFILE, &rlp);
|
||||
rlp.rlim_cur = n;
|
||||
setrlimit(RLIMIT_NOFILE, &rlp);
|
||||
}
|
||||
double constexpr kErrorMeters = 1.0;
|
||||
double constexpr kErrorSeconds = 1.0;
|
||||
void ChangeMaxNumberOfOpenFiles(size_t n)
|
||||
{
|
||||
struct rlimit rlp;
|
||||
getrlimit(RLIMIT_NOFILE, &rlp);
|
||||
rlp.rlim_cur = n;
|
||||
setrlimit(RLIMIT_NOFILE, &rlp);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace integration
|
||||
{
|
||||
|
@ -69,27 +74,28 @@ namespace integration
|
|||
return storage::CountryInfoReader::CreateCountryInfoReader(platform);
|
||||
}
|
||||
|
||||
shared_ptr<OsrmRouter> CreateOsrmRouter(Index & index,
|
||||
unique_ptr<OsrmRouter> CreateOsrmRouter(Index & index,
|
||||
storage::CountryInfoGetter const & infoGetter)
|
||||
{
|
||||
shared_ptr<OsrmRouter> osrmRouter(new OsrmRouter(
|
||||
&index, [&infoGetter](m2::PointD const & pt)
|
||||
{
|
||||
return infoGetter.GetRegionCountryId(pt);
|
||||
}
|
||||
));
|
||||
unique_ptr<OsrmRouter> osrmRouter(new OsrmRouter(&index, [&infoGetter](m2::PointD const & pt)
|
||||
{
|
||||
return infoGetter.GetRegionCountryId(pt);
|
||||
}));
|
||||
return osrmRouter;
|
||||
}
|
||||
|
||||
shared_ptr<IRouter> CreatePedestrianRouter(Index & index,
|
||||
storage::CountryInfoGetter const & infoGetter)
|
||||
unique_ptr<IRouter> CreateAStarRouter(Index & index,
|
||||
storage::CountryInfoGetter const & infoGetter,
|
||||
TRouterFactory const & routerFactory)
|
||||
{
|
||||
// |infoGetter| should be a reference to an object which exists while the
|
||||
// result of the function is used.
|
||||
auto countryFileGetter = [&infoGetter](m2::PointD const & pt)
|
||||
{
|
||||
return infoGetter.GetRegionCountryId(pt);
|
||||
};
|
||||
unique_ptr<IRouter> router = CreatePedestrianAStarBidirectionalRouter(index, countryFileGetter);
|
||||
return shared_ptr<IRouter>(move(router));
|
||||
unique_ptr<IRouter> router = routerFactory(index, countryFileGetter);
|
||||
return unique_ptr<IRouter>(move(router));
|
||||
}
|
||||
|
||||
class OsrmRouterComponents : public IRouterComponents
|
||||
|
@ -104,7 +110,7 @@ namespace integration
|
|||
IRouter * GetRouter() const override { return m_osrmRouter.get(); }
|
||||
|
||||
private:
|
||||
shared_ptr<OsrmRouter> m_osrmRouter;
|
||||
unique_ptr<OsrmRouter> m_osrmRouter;
|
||||
};
|
||||
|
||||
class PedestrianRouterComponents : public IRouterComponents
|
||||
|
@ -112,14 +118,31 @@ namespace integration
|
|||
public:
|
||||
PedestrianRouterComponents(vector<LocalCountryFile> const & localFiles)
|
||||
: IRouterComponents(localFiles)
|
||||
, m_router(CreatePedestrianRouter(m_featuresFetcher->GetIndex(), *m_infoGetter))
|
||||
, m_router(CreateAStarRouter(m_featuresFetcher->GetIndex(), *m_infoGetter,
|
||||
CreatePedestrianAStarBidirectionalRouter))
|
||||
{
|
||||
}
|
||||
|
||||
IRouter * GetRouter() const override { return m_router.get(); }
|
||||
|
||||
private:
|
||||
shared_ptr<IRouter> m_router;
|
||||
unique_ptr<IRouter> m_router;
|
||||
};
|
||||
|
||||
class BicycleRouterComponents : public IRouterComponents
|
||||
{
|
||||
public:
|
||||
BicycleRouterComponents(vector<LocalCountryFile> const & localFiles)
|
||||
: IRouterComponents(localFiles)
|
||||
, m_router(CreateAStarRouter(m_featuresFetcher->GetIndex(), *m_infoGetter,
|
||||
CreateBicycleAStarBidirectionalRouter))
|
||||
{
|
||||
}
|
||||
|
||||
IRouter * GetRouter() const override { return m_router.get(); }
|
||||
|
||||
private:
|
||||
unique_ptr<IRouter> m_router;
|
||||
};
|
||||
|
||||
template <typename TRouterComponents>
|
||||
|
@ -151,21 +174,34 @@ namespace integration
|
|||
|
||||
IRouterComponents & GetOsrmComponents()
|
||||
{
|
||||
static shared_ptr<IRouterComponents> const inst = CreateAllMapsComponents<OsrmRouterComponents>();
|
||||
ASSERT(inst, ());
|
||||
return *inst;
|
||||
static auto const instance = CreateAllMapsComponents<OsrmRouterComponents>();
|
||||
ASSERT(instance, ());
|
||||
return *instance;
|
||||
}
|
||||
|
||||
shared_ptr<IRouterComponents> GetPedestrianComponents(vector<platform::LocalCountryFile> const & localFiles)
|
||||
{
|
||||
return shared_ptr<IRouterComponents>(new PedestrianRouterComponents(localFiles));
|
||||
return make_shared<PedestrianRouterComponents>(localFiles);
|
||||
}
|
||||
|
||||
IRouterComponents & GetPedestrianComponents()
|
||||
{
|
||||
static shared_ptr<IRouterComponents> const inst = CreateAllMapsComponents<PedestrianRouterComponents>();
|
||||
ASSERT(inst, ());
|
||||
return *inst;
|
||||
static auto const instance = CreateAllMapsComponents<PedestrianRouterComponents>();
|
||||
ASSERT(instance, ());
|
||||
return *instance;
|
||||
}
|
||||
|
||||
shared_ptr<IRouterComponents> GetBicycleComponents(
|
||||
vector<platform::LocalCountryFile> const & localFiles)
|
||||
{
|
||||
return make_shared<BicycleRouterComponents>(localFiles);
|
||||
}
|
||||
|
||||
IRouterComponents & GetBicycleComponents()
|
||||
{
|
||||
static auto const instance = CreateAllMapsComponents<BicycleRouterComponents>();
|
||||
ASSERT(instance, ());
|
||||
return *instance;
|
||||
}
|
||||
|
||||
TRouteResult CalculateRoute(IRouterComponents const & routerComponents,
|
||||
|
@ -208,7 +244,7 @@ namespace integration
|
|||
void TestRouteLength(Route const & route, double expectedRouteMeters,
|
||||
double relativeError)
|
||||
{
|
||||
double const delta = expectedRouteMeters * relativeError;
|
||||
double const delta = max(expectedRouteMeters * relativeError, kErrorMeters);
|
||||
double const routeMeters = route.GetTotalDistanceMeters();
|
||||
TEST(my::AlmostEqualAbs(routeMeters, expectedRouteMeters, delta),
|
||||
("Route length test failed. Expected:", expectedRouteMeters, "have:", routeMeters, "delta:", delta));
|
||||
|
@ -216,7 +252,7 @@ namespace integration
|
|||
|
||||
void TestRouteTime(Route const & route, double expectedRouteSeconds, double relativeError)
|
||||
{
|
||||
double const delta = expectedRouteSeconds * relativeError;
|
||||
double const delta = max(expectedRouteSeconds * relativeError, kErrorSeconds);
|
||||
double const routeSeconds = route.GetTotalTimeSec();
|
||||
TEST(my::AlmostEqualAbs(routeSeconds, expectedRouteSeconds, delta),
|
||||
("Route time test failed. Expected:", expectedRouteSeconds, "have:", routeSeconds, "delta:", delta));
|
||||
|
|
|
@ -78,14 +78,19 @@ unique_ptr<storage::CountryInfoGetter> CreateCountryInfoGetter();
|
|||
void TestOnlineFetcher(ms::LatLon const & startPoint, ms::LatLon const & finalPoint,
|
||||
vector<string> const & expected, IRouterComponents & routerComponents);
|
||||
|
||||
/// Get OSRM router components
|
||||
/// Gets OSRM router components
|
||||
IRouterComponents & GetOsrmComponents();
|
||||
shared_ptr<IRouterComponents> GetOsrmComponents(vector<platform::LocalCountryFile> const & localFiles);
|
||||
|
||||
/// Get pedestrian router components
|
||||
/// Gets pedestrian router components
|
||||
IRouterComponents & GetPedestrianComponents();
|
||||
shared_ptr<IRouterComponents> GetPedestrianComponents(vector<platform::LocalCountryFile> const & localFiles);
|
||||
|
||||
/// Gets bicycle router components.
|
||||
IRouterComponents & GetBicycleComponents();
|
||||
shared_ptr<IRouterComponents> GetBicycleComponents(
|
||||
vector<platform::LocalCountryFile> const & localFiles);
|
||||
|
||||
TRouteResult CalculateRoute(IRouterComponents const & routerComponents,
|
||||
m2::PointD const & startPoint, m2::PointD const & startDirection,
|
||||
m2::PointD const & finalPoint);
|
||||
|
|
|
@ -9,24 +9,25 @@ namespace routing
|
|||
{
|
||||
namespace turns
|
||||
{
|
||||
|
||||
/*!
|
||||
* \brief The IRoutingResultGraph interface for the routing result. Uncouple router from the
|
||||
* \brief The IRoutingResult interface for the routing result. Uncouple router from the
|
||||
* annotation code that describes turns. See routers for detail implementations.
|
||||
*/
|
||||
class IRoutingResultGraph
|
||||
class IRoutingResult
|
||||
{
|
||||
public:
|
||||
/// \returns information about all route segments.
|
||||
virtual TUnpackedPathSegments const & GetSegments() const = 0;
|
||||
/// \brief For a |node|, |junctionPoint| and |ingoingPoint| (point before the |node|)
|
||||
/// this method computes number of ingoing ways to |junctionPoint| and fills |outgoingTurns|.
|
||||
virtual void GetPossibleTurns(TNodeId node, m2::PointD const & ingoingPoint,
|
||||
m2::PointD const & junctionPoint,
|
||||
size_t & ingoingCount,
|
||||
TTurnCandidates & outgoingTurns) const = 0;
|
||||
virtual double GetShortestPathLength() const = 0;
|
||||
m2::PointD const & junctionPoint, size_t & ingoingCount,
|
||||
TurnCandidates & outgoingTurns) const = 0;
|
||||
virtual double GetPathLength() const = 0;
|
||||
virtual m2::PointD const & GetStartPoint() const = 0;
|
||||
virtual m2::PointD const & GetEndPoint() const = 0;
|
||||
|
||||
virtual ~IRoutingResultGraph() = default;
|
||||
virtual ~IRoutingResult() = default;
|
||||
};
|
||||
} // namespace routing
|
||||
} // namespace turns
|
||||
|
|
|
@ -41,6 +41,13 @@ struct TurnCandidate
|
|||
}
|
||||
};
|
||||
|
||||
using TTurnCandidates = vector<TurnCandidate>;
|
||||
struct TurnCandidates
|
||||
{
|
||||
vector<TurnCandidate> candidates;
|
||||
bool isCandidatesAngleValid;
|
||||
|
||||
explicit TurnCandidates(bool angleValid = true) : isCandidatesAngleValid(angleValid) {}
|
||||
};
|
||||
|
||||
} // namespace routing
|
||||
} // namespace turns
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "routing/turns.hpp"
|
||||
|
||||
#include "geometry/angles.hpp"
|
||||
|
||||
#include "base/internal/message.hpp"
|
||||
|
||||
#include "std/array.hpp"
|
||||
|
@ -277,5 +279,11 @@ string DebugPrint(SingleLaneInfo const & singleLaneInfo)
|
|||
<< ", m_lane == " << ::DebugPrint(singleLaneInfo.m_lane) << " ]" << endl;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
double PiMinusTwoVectorsAngle(m2::PointD const & junctionPoint, m2::PointD const & ingoingPoint,
|
||||
m2::PointD const & outgoingPoint)
|
||||
{
|
||||
return math::pi - ang::TwoVectorsAngle(junctionPoint, ingoingPoint, outgoingPoint);
|
||||
}
|
||||
} // namespace turns
|
||||
} // namespace routing
|
||||
|
|
|
@ -19,6 +19,8 @@ namespace turns
|
|||
/// @todo(vbykoianko) It's a good idea to gather all the turns information into one entity.
|
||||
/// For the time being several separate entities reflect the turn information. Like Route::TTurns
|
||||
|
||||
double constexpr kFeaturesNearTurnMeters = 3.0;
|
||||
|
||||
/*!
|
||||
* \warning The order of values below shall not be changed.
|
||||
* TurnRight(TurnLeft) must have a minimal value and
|
||||
|
@ -202,5 +204,13 @@ bool IsLaneWayConformedTurnDirectionApproximately(LaneWay l, TurnDirection t);
|
|||
bool ParseLanes(string lanesString, vector<SingleLaneInfo> & lanes);
|
||||
void SplitLanes(string const & lanesString, char delimiter, vector<string> & lanes);
|
||||
bool ParseSingleLane(string const & laneString, char delimiter, TSingleLane & lane);
|
||||
|
||||
/*!
|
||||
* \returns pi minus angle from vector [junctionPoint, ingoingPoint]
|
||||
* to vector [junctionPoint, outgoingPoint]. A counterclockwise rotation.
|
||||
* Angle is in range [-pi, pi].
|
||||
*/
|
||||
double PiMinusTwoVectorsAngle(m2::PointD const & junctionPoint, m2::PointD const & ingoingPoint,
|
||||
m2::PointD const & outgoingPoint);
|
||||
} // namespace turns
|
||||
} // namespace routing
|
||||
|
|
|
@ -21,37 +21,29 @@ using namespace routing::turns;
|
|||
|
||||
namespace
|
||||
{
|
||||
double const kFeaturesNearTurnMeters = 3.0;
|
||||
size_t constexpr kMaxPointsCount = 5;
|
||||
double constexpr kMinDistMeters = 200.;
|
||||
size_t constexpr kNotSoCloseMaxPointsCount = 3;
|
||||
double constexpr kNotSoCloseMinDistMeters = 30.;
|
||||
|
||||
using TGeomTurnCandidate = vector<double>;
|
||||
|
||||
double PiMinusTwoVectorsAngle(m2::PointD const & p, m2::PointD const & p1, m2::PointD const & p2)
|
||||
{
|
||||
return math::pi - ang::TwoVectorsAngle(p, p1, p2);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns false when
|
||||
* - the route leads from one big road to another one;
|
||||
* - and the other possible turns lead to small roads;
|
||||
* - and the turn is GoStraight or TurnSlight*.
|
||||
*/
|
||||
bool KeepTurnByHighwayClass(TurnDirection turn, TTurnCandidates const & possibleTurns,
|
||||
bool KeepTurnByHighwayClass(TurnDirection turn, TurnCandidates const & possibleTurns,
|
||||
TurnInfo const & turnInfo)
|
||||
{
|
||||
if (!IsGoStraightOrSlightTurn(turn))
|
||||
return true; // The road significantly changes its direction here. So this turn shall be kept.
|
||||
|
||||
// There's only one exit from this junction. NodeID of the exit is outgoingNode.
|
||||
if (possibleTurns.size() == 1)
|
||||
if (possibleTurns.candidates.size() == 1)
|
||||
return true;
|
||||
|
||||
ftypes::HighwayClass maxClassForPossibleTurns = ftypes::HighwayClass::Error;
|
||||
for (auto const & t : possibleTurns)
|
||||
for (auto const & t : possibleTurns.candidates)
|
||||
{
|
||||
if (t.node == turnInfo.m_outgoing.m_nodeId)
|
||||
continue;
|
||||
|
@ -87,10 +79,10 @@ bool KeepTurnByHighwayClass(TurnDirection turn, TTurnCandidates const & possible
|
|||
/*!
|
||||
* \brief Returns false when other possible turns leads to service roads;
|
||||
*/
|
||||
bool KeepRoundaboutTurnByHighwayClass(TurnDirection turn, TTurnCandidates const & possibleTurns,
|
||||
bool KeepRoundaboutTurnByHighwayClass(TurnDirection turn, TurnCandidates const & possibleTurns,
|
||||
TurnInfo const & turnInfo)
|
||||
{
|
||||
for (auto const & t : possibleTurns)
|
||||
for (auto const & t : possibleTurns.candidates)
|
||||
{
|
||||
if (t.node == turnInfo.m_outgoing.m_nodeId)
|
||||
continue;
|
||||
|
@ -261,14 +253,14 @@ bool TurnInfo::IsSegmentsValid() const
|
|||
return true;
|
||||
}
|
||||
|
||||
IRouter::ResultCode MakeTurnAnnotation(turns::IRoutingResultGraph const & result,
|
||||
IRouter::ResultCode MakeTurnAnnotation(turns::IRoutingResult const & result,
|
||||
RouterDelegate const & delegate, vector<m2::PointD> & points,
|
||||
Route::TTurns & turnsDir, Route::TTimes & times,
|
||||
Route::TStreets & streets)
|
||||
{
|
||||
double estimatedTime = 0;
|
||||
|
||||
LOG(LDEBUG, ("Shortest th length:", result.GetShortestPathLength()));
|
||||
LOG(LDEBUG, ("Shortest th length:", result.GetPathLength()));
|
||||
|
||||
#ifdef DEBUG
|
||||
size_t lastIdx = 0;
|
||||
|
@ -569,7 +561,7 @@ TurnDirection IntermediateDirection(const double angle)
|
|||
return FindDirectionByAngle(kLowerBounds, angle);
|
||||
}
|
||||
|
||||
void GetTurnDirection(IRoutingResultGraph const & result, TurnInfo & turnInfo, TurnItem & turn)
|
||||
void GetTurnDirection(IRoutingResult const & result, TurnInfo & turnInfo, TurnItem & turn)
|
||||
{
|
||||
if (!turnInfo.IsSegmentsValid())
|
||||
return;
|
||||
|
@ -601,26 +593,26 @@ void GetTurnDirection(IRoutingResultGraph const & result, TurnInfo & turnInfo, T
|
|||
|
||||
ASSERT_GREATER(turnInfo.m_ingoing.m_path.size(), 1, ());
|
||||
m2::PointD const ingoingPointOneSegment = turnInfo.m_ingoing.m_path[turnInfo.m_ingoing.m_path.size() - 2];
|
||||
TTurnCandidates nodes;
|
||||
TurnCandidates nodes;
|
||||
size_t ingoingCount;
|
||||
result.GetPossibleTurns(turnInfo.m_ingoing.m_nodeId, ingoingPointOneSegment, junctionPoint,
|
||||
ingoingCount, nodes);
|
||||
|
||||
size_t const numNodes = nodes.size();
|
||||
size_t const numNodes = nodes.candidates.size();
|
||||
bool const hasMultiTurns = numNodes > 1;
|
||||
|
||||
if (numNodes == 0)
|
||||
return;
|
||||
|
||||
if (!hasMultiTurns)
|
||||
if (!hasMultiTurns || !nodes.isCandidatesAngleValid)
|
||||
{
|
||||
turn.m_turn = intermediateDirection;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nodes.front().node == turnInfo.m_outgoing.m_nodeId)
|
||||
if (nodes.candidates.front().node == turnInfo.m_outgoing.m_nodeId)
|
||||
turn.m_turn = LeftmostDirection(turnAngle);
|
||||
else if (nodes.back().node == turnInfo.m_outgoing.m_nodeId)
|
||||
else if (nodes.candidates.back().node == turnInfo.m_outgoing.m_nodeId)
|
||||
turn.m_turn = RightmostDirection(turnAngle);
|
||||
else
|
||||
turn.m_turn = intermediateDirection;
|
||||
|
@ -648,7 +640,7 @@ void GetTurnDirection(IRoutingResultGraph const & result, TurnInfo & turnInfo, T
|
|||
kNotSoCloseMinDistMeters, GetIngoingPointIndex);
|
||||
|
||||
if (!KeepTurnByIngoingEdges(junctionPoint, notSoCloseToTheTurnPoint, outgoingPoint, hasMultiTurns,
|
||||
nodes.size() + ingoingCount))
|
||||
nodes.candidates.size() + ingoingCount))
|
||||
{
|
||||
turn.m_turn = TurnDirection::NoTurn;
|
||||
return;
|
||||
|
|
|
@ -42,7 +42,7 @@ using TGetIndexFunction = function<size_t(pair<size_t, size_t>)>;
|
|||
* \param streets output street names along the path.
|
||||
* \return routing operation result code.
|
||||
*/
|
||||
IRouter::ResultCode MakeTurnAnnotation(turns::IRoutingResultGraph const & result,
|
||||
IRouter::ResultCode MakeTurnAnnotation(turns::IRoutingResult const & result,
|
||||
RouterDelegate const & delegate, vector<m2::PointD> & points,
|
||||
Route::TTurns & turnsDir, Route::TTimes & times,
|
||||
Route::TStreets & streets);
|
||||
|
@ -127,8 +127,7 @@ TurnDirection GetRoundaboutDirection(bool isIngoingEdgeRoundabout, bool isOutgoi
|
|||
* \param turnInfo is used for cashing some information while turn calculation.
|
||||
* \param turn is used for keeping the result of turn calculation.
|
||||
*/
|
||||
void GetTurnDirection(IRoutingResultGraph const & result, turns::TurnInfo & turnInfo,
|
||||
TurnItem & turn);
|
||||
void GetTurnDirection(IRoutingResult const & result, turns::TurnInfo & turnInfo, TurnItem & turn);
|
||||
|
||||
/*!
|
||||
* \brief Finds an UTurn that starts from current segment and returns how many segments it lasts.
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
56099E2B1CC7C97D00A7772A /* turn_candidate.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56099E271CC7C97D00A7772A /* turn_candidate.hpp */; };
|
||||
56099E2E1CC8FBDA00A7772A /* osrm_path_segment_factory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56099E2C1CC8FBDA00A7772A /* osrm_path_segment_factory.cpp */; };
|
||||
56099E2F1CC8FBDA00A7772A /* osrm_path_segment_factory.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56099E2D1CC8FBDA00A7772A /* osrm_path_segment_factory.hpp */; };
|
||||
56099E331CC9247E00A7772A /* bicycle_directions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56099E301CC9247E00A7772A /* bicycle_directions.cpp */; };
|
||||
56099E341CC9247E00A7772A /* bicycle_directions.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56099E311CC9247E00A7772A /* bicycle_directions.hpp */; };
|
||||
56099E351CC9247E00A7772A /* directions_engine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56099E321CC9247E00A7772A /* directions_engine.cpp */; };
|
||||
563B91C51CC4F1DC00222BC1 /* bicycle_model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 563B91C31CC4F1DC00222BC1 /* bicycle_model.cpp */; };
|
||||
563B91C61CC4F1DC00222BC1 /* bicycle_model.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 563B91C41CC4F1DC00222BC1 /* bicycle_model.hpp */; };
|
||||
670B84C01A9381D900CE4492 /* cross_routing_context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 670B84BE1A9381D900CE4492 /* cross_routing_context.cpp */; };
|
||||
|
@ -188,6 +191,9 @@
|
|||
56099E271CC7C97D00A7772A /* turn_candidate.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = turn_candidate.hpp; sourceTree = "<group>"; };
|
||||
56099E2C1CC8FBDA00A7772A /* osrm_path_segment_factory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = osrm_path_segment_factory.cpp; path = ../../routing/osrm_path_segment_factory.cpp; sourceTree = "<group>"; };
|
||||
56099E2D1CC8FBDA00A7772A /* osrm_path_segment_factory.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = osrm_path_segment_factory.hpp; path = ../../routing/osrm_path_segment_factory.hpp; sourceTree = "<group>"; };
|
||||
56099E301CC9247E00A7772A /* bicycle_directions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bicycle_directions.cpp; sourceTree = "<group>"; };
|
||||
56099E311CC9247E00A7772A /* bicycle_directions.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = bicycle_directions.hpp; sourceTree = "<group>"; };
|
||||
56099E321CC9247E00A7772A /* directions_engine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = directions_engine.cpp; sourceTree = "<group>"; };
|
||||
563B91C31CC4F1DC00222BC1 /* bicycle_model.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bicycle_model.cpp; sourceTree = "<group>"; };
|
||||
563B91C41CC4F1DC00222BC1 /* bicycle_model.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = bicycle_model.hpp; sourceTree = "<group>"; };
|
||||
670B84BE1A9381D900CE4492 /* cross_routing_context.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cross_routing_context.cpp; sourceTree = "<group>"; };
|
||||
|
@ -549,6 +555,9 @@
|
|||
675343FA1A3F640D00A0A8C3 /* routing */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
56099E301CC9247E00A7772A /* bicycle_directions.cpp */,
|
||||
56099E311CC9247E00A7772A /* bicycle_directions.hpp */,
|
||||
56099E321CC9247E00A7772A /* directions_engine.cpp */,
|
||||
56099E251CC7C97D00A7772A /* loaded_path_segment.hpp */,
|
||||
56099E261CC7C97D00A7772A /* routing_result_graph.hpp */,
|
||||
56099E271CC7C97D00A7772A /* turn_candidate.hpp */,
|
||||
|
@ -665,6 +674,7 @@
|
|||
A1616E2C1B6B60AB003F078E /* router_delegate.hpp in Headers */,
|
||||
A17B42991BCFBD0E00A1EAE4 /* osrm_helpers.hpp in Headers */,
|
||||
67C7D42E1B4EB48F00FE41AA /* turns_sound_settings.hpp in Headers */,
|
||||
56099E341CC9247E00A7772A /* bicycle_directions.hpp in Headers */,
|
||||
670EE55E1B6001E7001E8064 /* routing_session.hpp in Headers */,
|
||||
56099E291CC7C97D00A7772A /* loaded_path_segment.hpp in Headers */,
|
||||
670EE55F1B6001E7001E8064 /* routing_settings.hpp in Headers */,
|
||||
|
@ -856,6 +866,7 @@
|
|||
files = (
|
||||
56099E2E1CC8FBDA00A7772A /* osrm_path_segment_factory.cpp in Sources */,
|
||||
675344201A3F644F00A0A8C3 /* vehicle_model.cpp in Sources */,
|
||||
56099E351CC9247E00A7772A /* directions_engine.cpp in Sources */,
|
||||
A1616E2B1B6B60AB003F078E /* router_delegate.cpp in Sources */,
|
||||
6741AA9C1BF35331002C974C /* turns_notification_manager.cpp in Sources */,
|
||||
67C7D42B1B4EB48F00FE41AA /* pedestrian_model.cpp in Sources */,
|
||||
|
@ -875,6 +886,7 @@
|
|||
670EE55D1B6001E7001E8064 /* routing_session.cpp in Sources */,
|
||||
A120B3451B4A7BE5002F3808 /* cross_mwm_road_graph.cpp in Sources */,
|
||||
67C7D4291B4EB48F00FE41AA /* car_model.cpp in Sources */,
|
||||
56099E331CC9247E00A7772A /* bicycle_directions.cpp in Sources */,
|
||||
674A28B11B1605D2001A525C /* osrm_engine.cpp in Sources */,
|
||||
674F9BD41B0A580E00704FFA /* road_graph.cpp in Sources */,
|
||||
67AB92E61B7B3E6E00AB5194 /* turns_tts_text.cpp in Sources */,
|
||||
|
|
Loading…
Add table
Reference in a new issue