[routing] VehicleModel refactoring.

This commit is contained in:
Viktor Govako 2022-02-20 07:57:13 +03:00
parent d02453b52f
commit ae962fa7c4
29 changed files with 760 additions and 1511 deletions

View file

@ -266,7 +266,7 @@ omim_add_test_subdirectory(generator_tests)
omim_add_test_subdirectory(generator_integration_tests)
add_subdirectory(generator_tool)
add_subdirectory(complex_generator)
add_subdirectory(feature_segments_checker)
#add_subdirectory(complex_generator)
#add_subdirectory(feature_segments_checker)
add_subdirectory(srtm_coverage_checker)
add_subdirectory(world_roads_builder)

View file

@ -563,7 +563,7 @@ UNIT_CLASS_TEST(TestWithClassificator, OsmType_Ferry)
uint32_t type = GetType({"route", "ferry"});
TEST(params.IsTypeExist(type), (params));
TEST(carModel.IsRoadType(type), ());
TEST(carModel.HasRoadType(params.m_types), ());
type = GetType({"hwtag", "nocar"});
TEST(params.IsTypeExist(type), ());
@ -582,7 +582,7 @@ UNIT_CLASS_TEST(TestWithClassificator, OsmType_Ferry)
uint32_t type = GetType({"route", "ferry"});
TEST(params.IsTypeExist(type), (params));
TEST(carModel.IsRoadType(type), ());
TEST(carModel.HasRoadType(params.m_types), ());
type = GetType({"hwtag", "yescar"});
TEST(params.IsTypeExist(type), ());
@ -594,7 +594,8 @@ UNIT_CLASS_TEST(TestWithClassificator, OsmType_Ferry)
UNIT_CLASS_TEST(TestWithClassificator, OsmType_YesCarNoCar)
{
routing::CarModel const & carModel = routing::CarModel::AllLimitsInstance();
uint32_t const yesCar = GetType({"hwtag", "yescar"});
uint32_t const noCar = GetType({"hwtag", "nocar"});
{
Tags const tags = {
@ -604,8 +605,8 @@ UNIT_CLASS_TEST(TestWithClassificator, OsmType_YesCarNoCar)
auto const params = GetFeatureBuilderParams(tags);
TEST_EQUAL(params.m_types.size(), 1, (params));
TEST(!params.IsTypeExist(carModel.GetNoCarTypeForTesting()), ());
TEST(!params.IsTypeExist(carModel.GetYesCarTypeForTesting()), ());
TEST(!params.IsTypeExist(yesCar), ());
TEST(!params.IsTypeExist(noCar), ());
}
{
@ -617,8 +618,8 @@ UNIT_CLASS_TEST(TestWithClassificator, OsmType_YesCarNoCar)
auto const params = GetFeatureBuilderParams(tags);
TEST_EQUAL(params.m_types.size(), 2, (params));
TEST(!params.IsTypeExist(carModel.GetNoCarTypeForTesting()), ());
TEST(params.IsTypeExist(carModel.GetYesCarTypeForTesting()), ());
TEST(params.IsTypeExist(yesCar), ());
TEST(!params.IsTypeExist(noCar), ());
}
{
@ -630,8 +631,20 @@ UNIT_CLASS_TEST(TestWithClassificator, OsmType_YesCarNoCar)
auto const params = GetFeatureBuilderParams(tags);
TEST_EQUAL(params.m_types.size(), 2, (params));
TEST(params.IsTypeExist(carModel.GetNoCarTypeForTesting()), ());
TEST(!params.IsTypeExist(carModel.GetYesCarTypeForTesting()), ());
TEST(!params.IsTypeExist(yesCar), ());
TEST(params.IsTypeExist(noCar), ());
}
{
Tags const tags = {
{"railway", "rail"},
{"motor_vehicle", "yes"},
};
auto const params = GetFeatureBuilderParams(tags);
TEST_EQUAL(params.m_types.size(), 1, (params));
TEST(params.IsTypeExist(GetType({"railway", "rail", "motor_vehicle"})), ());
}
}

View file

@ -61,14 +61,10 @@ namespace
class VehicleMaskBuilder final
{
public:
VehicleMaskBuilder(string const & country,
routing::CountryParentNameGetterFn const & countryParentNameGetterFn)
: m_pedestrianModel(routing::PedestrianModelFactory(countryParentNameGetterFn)
.GetVehicleModelForCountry(country))
, m_bicycleModel(routing::BicycleModelFactory(countryParentNameGetterFn)
.GetVehicleModelForCountry(country))
, m_carModel(
routing::CarModelFactory(countryParentNameGetterFn).GetVehicleModelForCountry(country))
VehicleMaskBuilder(string const & country, routing::CountryParentNameGetterFn const & parentGetter)
: m_pedestrianModel(routing::PedestrianModelFactory(parentGetter).GetVehicleModelForCountry(country))
, m_bicycleModel(routing::BicycleModelFactory(parentGetter).GetVehicleModelForCountry(country))
, m_carModel(routing::CarModelFactory(parentGetter).GetVehicleModelForCountry(country))
{
CHECK(m_pedestrianModel, ());
CHECK(m_bicycleModel, ());
@ -78,7 +74,7 @@ public:
routing::VehicleMask CalcRoadMask(FeatureType & f) const
{
return CalcMask(f, [&](routing::VehicleModelInterface const & model, FeatureType & f) {
return model.IsRoad(f);
return model.HasRoadType(f);
});
}

View file

@ -194,7 +194,7 @@ if (PLATFORM_DESKTOP)
add_subdirectory(routes_builder)
endif()
omim_add_test_subdirectory(routing_benchmarks)
omim_add_test_subdirectory(routing_consistency_tests)
#omim_add_test_subdirectory(routing_benchmarks)
#omim_add_test_subdirectory(routing_consistency_tests)
omim_add_test_subdirectory(routing_integration_tests)
omim_add_test_subdirectory(routing_tests)

View file

@ -52,35 +52,20 @@ FeaturesRoadGraph::CrossCountryVehicleModel::CrossCountryVehicleModel(
{
}
SpeedKMpH FeaturesRoadGraph::CrossCountryVehicleModel::GetSpeed(
FeatureType & f, SpeedParams const & speedParams) const
VehicleModel::Response FeaturesRoadGraph::CrossCountryVehicleModel::GetFeatureInfo(
FeatureType & ft, Request const & request) const
{
return GetVehicleModel(f.GetID())->GetSpeed(f, speedParams);
return GetVehicleModel(ft.GetID())->GetFeatureInfo(ft, request);
}
HighwayType FeaturesRoadGraph::CrossCountryVehicleModel::GetHighwayType(FeatureType & f) const
bool FeaturesRoadGraph::CrossCountryVehicleModel::HasRoadType(FeatureType & ft) const
{
return GetVehicleModel(f.GetID())->GetHighwayType(f);
return GetVehicleModel(ft.GetID())->HasRoadType(ft);
}
SpeedKMpH const & FeaturesRoadGraph::CrossCountryVehicleModel::GetOffroadSpeed() const
bool FeaturesRoadGraph::CrossCountryVehicleModel::IsOneWay(FeatureType & ft) const
{
return m_offroadSpeedKMpH;
}
bool FeaturesRoadGraph::CrossCountryVehicleModel::IsOneWay(FeatureType & f) const
{
return GetVehicleModel(f.GetID())->IsOneWay(f);
}
bool FeaturesRoadGraph::CrossCountryVehicleModel::IsRoad(FeatureType & f) const
{
return GetVehicleModel(f.GetID())->IsRoad(f);
}
bool FeaturesRoadGraph::CrossCountryVehicleModel::IsPassThroughAllowed(FeatureType & f) const
{
return GetVehicleModel(f.GetID())->IsPassThroughAllowed(f);
return GetVehicleModel(ft.GetID())->IsOneWay(ft);
}
VehicleModelInterface * FeaturesRoadGraph::CrossCountryVehicleModel::GetVehicleModel(
@ -142,9 +127,7 @@ public:
FeatureID const & featureId = ft.GetID();
IRoadGraph::RoadInfo const & roadInfo =
m_graph.GetCachedRoadInfo(featureId, ft, kInvalidSpeedKMPH);
CHECK_EQUAL(roadInfo.m_speedKMPH, kInvalidSpeedKMPH, ());
IRoadGraph::RoadInfo const & roadInfo = m_graph.GetCachedRoadInfo(featureId, ft);
m_edgesLoader(featureId, roadInfo.m_junctions, roadInfo.m_bidirectional);
}
@ -154,17 +137,16 @@ private:
IRoadGraph::ICrossEdgesLoader & m_edgesLoader;
};
IRoadGraph::RoadInfo FeaturesRoadGraph::GetRoadInfo(FeatureID const & featureId,
SpeedParams const & speedParams) const
IRoadGraph::RoadInfo FeaturesRoadGraph::GetRoadInfo(FeatureID const & featureId) const
{
RoadInfo const & ri = GetCachedRoadInfo(featureId, speedParams);
RoadInfo const & ri = GetCachedRoadInfo(featureId);
ASSERT_GREATER(ri.m_speedKMPH, 0.0, ());
return ri;
}
double FeaturesRoadGraph::GetSpeedKMpH(FeatureID const & featureId, SpeedParams const & speedParams) const
double FeaturesRoadGraph::GetSpeedKMpH(FeatureID const & featureId) const
{
double const speedKMPH = GetCachedRoadInfo(featureId, speedParams).m_speedKMPH;
double const speedKMPH = GetCachedRoadInfo(featureId).m_speedKMPH;
ASSERT_GREATER(speedKMPH, 0.0, ());
return speedKMPH;
}
@ -188,12 +170,12 @@ void FeaturesRoadGraph::FindClosestEdges(
auto const f = [&finder, this](FeatureType & ft)
{
if (!m_vehicleModel.IsRoad(ft))
if (!IsRoad(ft))
return;
FeatureID const & featureId = ft.GetID();
IRoadGraph::RoadInfo const & roadInfo = GetCachedRoadInfo(featureId, ft, kInvalidSpeedKMPH);
IRoadGraph::RoadInfo const & roadInfo = GetCachedRoadInfo(featureId, ft);
finder.AddInformationSource(IRoadGraph::FullRoadInfo(featureId, roadInfo));
};
@ -207,7 +189,7 @@ FeaturesRoadGraph::FindRoads(m2::RectD const & rect, IsGoodFeatureFn const & isG
{
vector<IRoadGraph::FullRoadInfo> roads;
auto const f = [&roads, &isGoodFeature, &rect, this](FeatureType & ft) {
if (!m_vehicleModel.IsRoad(ft))
if (!IsRoad(ft))
return;
FeatureID const & featureId = ft.GetID();
@ -216,7 +198,7 @@ FeaturesRoadGraph::FindRoads(m2::RectD const & rect, IsGoodFeatureFn const & isG
// DataSource::ForEachInRect() gives not only features inside |rect| but some other features
// which lie close to the rect. Removes all the features which don't cross |rect|.
auto const & roadInfo = GetCachedRoadInfo(featureId, ft, kInvalidSpeedKMPH);
auto const & roadInfo = GetCachedRoadInfo(featureId, ft);
if (!RectCoversPolyline(roadInfo.m_junctions, rect))
return;
@ -277,33 +259,22 @@ void FeaturesRoadGraph::ClearState()
m_mwmLocks.clear();
}
bool FeaturesRoadGraph::IsRoad(FeatureType & ft) const { return m_vehicleModel.IsRoad(ft); }
IRoadGraph::PointWithAltitudeVec FeaturesRoadGraph::GetRoadGeom(FeatureType & ft) const
bool FeaturesRoadGraph::IsRoad(FeatureType & ft) const
{
FeatureID const & featureId = ft.GetID();
IRoadGraph::RoadInfo const & roadInfo = GetCachedRoadInfo(featureId, ft, kInvalidSpeedKMPH);
CHECK_EQUAL(roadInfo.m_speedKMPH, kInvalidSpeedKMPH, ());
return roadInfo.m_junctions;
return m_vehicleModel.HasRoadType(ft);
}
bool FeaturesRoadGraph::IsOneWay(FeatureType & ft) const { return m_vehicleModel.IsOneWay(ft); }
double FeaturesRoadGraph::GetSpeedKMpHFromFt(FeatureType & ft, SpeedParams const & speedParams) const
void FeaturesRoadGraph::ExtractRoadInfo(FeatureID const & featureId, FeatureType & ft, RoadInfo & ri) const
{
return m_vehicleModel.GetSpeed(ft, speedParams).m_weight;
}
void FeaturesRoadGraph::ExtractRoadInfo(FeatureID const & featureId, FeatureType & ft,
double speedKMpH, RoadInfo & ri) const
{
ri.m_speedKMPH = speedKMpH;
Value const & value = LockMwm(featureId.m_mwmId);
if (!value.IsAlive())
return;
ri.m_bidirectional = !IsOneWay(ft);
auto const response = m_vehicleModel.GetFeatureInfo(ft, {Maxspeed(), false});
CHECK(response.m_isValid, ());
ri.m_speedKMPH = response.m_forwardSpeed.m_weight;
ri.m_bidirectional = !response.m_isOneWay;
ft.ParseGeometry(FeatureType::BEST_GEOMETRY);
size_t const pointsCount = ft.GetPointsCount();
@ -328,8 +299,7 @@ void FeaturesRoadGraph::ExtractRoadInfo(FeatureID const & featureId, FeatureType
ri.m_junctions[i] = geometry::PointWithAltitude(ft.GetPoint(i), altitudes[i]);
}
IRoadGraph::RoadInfo const & FeaturesRoadGraph::GetCachedRoadInfo(FeatureID const & featureId,
SpeedParams const & speedParams) const
IRoadGraph::RoadInfo const & FeaturesRoadGraph::GetCachedRoadInfo(FeatureID const & featureId) const
{
bool found = false;
RoadInfo & ri = m_cache.Find(featureId, found);
@ -345,13 +315,12 @@ IRoadGraph::RoadInfo const & FeaturesRoadGraph::GetCachedRoadInfo(FeatureID cons
ASSERT_EQUAL(ft->GetGeomType(), feature::GeomType::Line, ());
ExtractRoadInfo(featureId, *ft, GetSpeedKMpHFromFt(*ft, speedParams), ri);
ExtractRoadInfo(featureId, *ft, ri);
return ri;
}
IRoadGraph::RoadInfo const & FeaturesRoadGraph::GetCachedRoadInfo(FeatureID const & featureId,
FeatureType & ft,
double speedKMPH) const
IRoadGraph::RoadInfo const & FeaturesRoadGraph::GetCachedRoadInfo(
FeatureID const & featureId, FeatureType & ft) const
{
bool found = false;
RoadInfo & ri = m_cache.Find(featureId, found);
@ -361,7 +330,7 @@ IRoadGraph::RoadInfo const & FeaturesRoadGraph::GetCachedRoadInfo(FeatureID cons
// ft must be set
ASSERT_EQUAL(featureId, ft.GetID(), ());
ExtractRoadInfo(featureId, ft, speedKMPH, ri);
ExtractRoadInfo(featureId, ft, ri);
return ri;
}

View file

@ -33,14 +33,14 @@ private:
public:
CrossCountryVehicleModel(std::shared_ptr<VehicleModelFactoryInterface> vehicleModelFactory);
// VehicleModelInterface overrides:
SpeedKMpH GetSpeed(FeatureType & f, SpeedParams const & speedParams) const override;
HighwayType GetHighwayType(FeatureType & f) const override;
/// @name VehicleModelInterface overrides:
/// @{
Response GetFeatureInfo(FeatureType & ft, Request const & request) const override;
bool HasRoadType(FeatureType & ft) const override;
bool IsOneWay(FeatureType & ft) const override;
double GetMaxWeightSpeed() const override { return m_maxSpeed; }
SpeedKMpH const & GetOffroadSpeed() const override;
bool IsOneWay(FeatureType & f) const override;
bool IsRoad(FeatureType & f) const override;
bool IsPassThroughAllowed(FeatureType & f) const override;
SpeedKMpH GetOffroadSpeed() const override { return m_offroadSpeedKMpH; }
/// @}
void Clear();
@ -77,8 +77,8 @@ public:
static int GetStreetReadScale();
// IRoadGraph overrides:
RoadInfo GetRoadInfo(FeatureID const & featureId, SpeedParams const & speedParams) const override;
double GetSpeedKMpH(FeatureID const & featureId, SpeedParams const & speedParams) const override;
RoadInfo GetRoadInfo(FeatureID const & featureId) const override;
double GetSpeedKMpH(FeatureID const & featureId) const override;
double GetMaxSpeedKMpH() const override;
void ForEachFeatureClosestToCross(m2::PointD const & cross,
ICrossEdgesLoader & edgesLoader) const override;
@ -94,7 +94,6 @@ public:
void ClearState() override;
bool IsRoad(FeatureType & ft) const;
IRoadGraph::PointWithAltitudeVec GetRoadGeom(FeatureType & ft) const;
private:
friend class CrossFeaturesLoader;
@ -110,18 +109,13 @@ private:
std::unique_ptr<feature::AltitudeLoader> m_altitudeLoader;
};
bool IsOneWay(FeatureType & ft) const;
double GetSpeedKMpHFromFt(FeatureType & ft, SpeedParams const & speedParams) const;
// Searches a feature RoadInfo in the cache, and if does not find then
// loads feature from the index and takes speed for the feature from the vehicle model.
RoadInfo const & GetCachedRoadInfo(FeatureID const & featureId, SpeedParams const & speedParams) const;
RoadInfo const & GetCachedRoadInfo(FeatureID const & featureId) const;
// Searches a feature RoadInfo in the cache, and if does not find then takes passed feature and speed.
// This version is used to prevent redundant feature loading when feature speed is known.
RoadInfo const & GetCachedRoadInfo(FeatureID const & featureId, FeatureType & ft,
double speedKMPH) const;
void ExtractRoadInfo(FeatureID const & featureId, FeatureType & ft, double speedKMpH,
RoadInfo & ri) const;
RoadInfo const & GetCachedRoadInfo(FeatureID const & featureId, FeatureType & ft) const;
void ExtractRoadInfo(FeatureID const & featureId, FeatureType & ft, RoadInfo & ri) const;
Value const & LockMwm(MwmSet::MwmId const & mwmId) const;

View file

@ -185,16 +185,15 @@ void RoadGeometry::Load(VehicleModelInterface const & vehicleModel, FeatureType
{
CHECK(altitudes == nullptr || altitudes->size() == feature.GetPointsCount(), ());
m_valid = vehicleModel.IsRoad(feature);
m_isOneWay = vehicleModel.IsOneWay(feature);
m_highwayType = vehicleModel.GetHighwayType(feature);
m_isPassThroughAllowed = vehicleModel.IsPassThroughAllowed(feature);
uint32_t const fID = feature.GetID().m_index;
bool const inCity = attrs.m_cityRoads.IsCityRoad(fID);
Maxspeed const maxSpeed = attrs.m_maxSpeeds.GetMaxspeed(fID);
m_forwardSpeed = vehicleModel.GetSpeed(feature, {true /* forward */, inCity, maxSpeed});
m_backwardSpeed = vehicleModel.GetSpeed(feature, {false /* forward */, inCity, maxSpeed});
auto const response = vehicleModel.GetFeatureInfo(
feature, {attrs.m_maxSpeeds.GetMaxspeed(fID), attrs.m_cityRoads.IsCityRoad(fID)});
m_forwardSpeed = response.m_forwardSpeed;
m_backwardSpeed = response.m_backwardSpeed;
m_highwayType = response.m_highwayType;
m_valid = response.m_isValid;
m_isOneWay = response.m_isOneWay;
m_isPassThroughAllowed = response.m_isPassThroughAllowed;
feature::TypesHolder types(feature);
auto const & optionsClassfier = RoutingOptionsClassifier::Instance();

View file

@ -92,7 +92,7 @@ double CalcMaxSpeed(NumMwmIds const & numMwmIds,
return maxSpeed;
}
SpeedKMpH const & CalcOffroadSpeed(VehicleModelFactoryInterface const & vehicleModelFactory)
SpeedKMpH CalcOffroadSpeed(VehicleModelFactoryInterface const & vehicleModelFactory)
{
return vehicleModelFactory.GetVehicleModel()->GetOffroadSpeed();
}

View file

@ -292,11 +292,9 @@ void IRoadGraph::AddIngoingFakeEdge(Edge const & e)
AddEdge(e.GetEndJunction(), e, m_fakeIngoingEdges);
}
double IRoadGraph::GetSpeedKMpH(Edge const & edge, SpeedParams const & speedParams) const
double IRoadGraph::GetSpeedKMpH(Edge const & edge) const
{
double const speedKMpH =
(edge.IsFake() ? GetMaxSpeedKMpH()
: GetSpeedKMpH(edge.GetFeatureId(), speedParams));
double const speedKMpH = (edge.IsFake() ? GetMaxSpeedKMpH() : GetSpeedKMpH(edge.GetFeatureId()));
ASSERT_LESS_OR_EQUAL(speedKMpH, GetMaxSpeedKMpH(), ());
return speedKMpH;
}

View file

@ -287,13 +287,13 @@ public:
void AddIngoingFakeEdge(Edge const & e);
/// Returns RoadInfo for a road corresponding to featureId.
virtual RoadInfo GetRoadInfo(FeatureID const & featureId, SpeedParams const & speedParams) const = 0;
virtual RoadInfo GetRoadInfo(FeatureID const & featureId) const = 0;
/// Returns speed in KM/H for a road corresponding to featureId.
virtual double GetSpeedKMpH(FeatureID const & featureId, SpeedParams const & speedParams) const = 0;
virtual double GetSpeedKMpH(FeatureID const & featureId) const = 0;
/// Returns speed in KM/H for a road corresponding to edge.
double GetSpeedKMpH(Edge const & edge, SpeedParams const & speedParams) const;
double GetSpeedKMpH(Edge const & edge) const;
/// Calls edgesLoader on each feature which is close to cross.
virtual void ForEachFeatureClosestToCross(m2::PointD const & cross,

View file

@ -45,8 +45,7 @@ bool IsBicycleRoad(Types const & types)
template <typename Types>
bool IsRoad(Types const & types)
{
return IsCarRoad(types) || PedestrianModel::AllLimitsInstance().HasRoadType(types) ||
IsBicycleRoad(types);
return (IsCarRoad(types) || IsBicycleRoad(types) || PedestrianModel::AllLimitsInstance().HasRoadType(types));
}
void FillSegmentInfo(std::vector<Segment> const & segments,

View file

@ -25,8 +25,7 @@ void TestNearestOnMock1(m2::PointD const & point, size_t const candidatesCount,
for (size_t i = 0; i < graph->GetRoadCount(); ++i)
{
FeatureID const featureId = MakeTestFeatureID(base::checked_cast<uint32_t>(i));
auto const & roadInfo =
graph->GetRoadInfo(featureId, {true /* forward */, false /* in city */, Maxspeed()});
auto const & roadInfo = graph->GetRoadInfo(featureId);
finder.AddInformationSource(IRoadGraph::FullRoadInfo(featureId, roadInfo));
}

View file

@ -71,15 +71,13 @@ void RoadGraphMockSource::AddRoad(RoadInfo && ri)
m_roads.push_back(move(ri));
}
IRoadGraph::RoadInfo RoadGraphMockSource::GetRoadInfo(FeatureID const & featureId,
SpeedParams const & /* speedParams */) const
IRoadGraph::RoadInfo RoadGraphMockSource::GetRoadInfo(FeatureID const & featureId) const
{
CHECK_LESS(featureId.m_index, m_roads.size(), ("Invalid feature id."));
return m_roads[featureId.m_index];
}
double RoadGraphMockSource::GetSpeedKMpH(FeatureID const & featureId,
SpeedParams const & /* speedParams */) const
double RoadGraphMockSource::GetSpeedKMpH(FeatureID const & featureId) const
{
CHECK_LESS(featureId.m_index, m_roads.size(), ("Invalid feature id."));
return m_roads[featureId.m_index].m_speedKMPH;

View file

@ -19,9 +19,8 @@ public:
inline size_t GetRoadCount() const { return m_roads.size(); }
// routing::IRoadGraph overrides:
RoadInfo GetRoadInfo(FeatureID const & f, routing::SpeedParams const & speedParams) const override;
double GetSpeedKMpH(FeatureID const & featureId,
routing::SpeedParams const & speedParams) const override;
RoadInfo GetRoadInfo(FeatureID const & f) const override;
double GetSpeedKMpH(FeatureID const & featureId) const override;
double GetMaxSpeedKMpH() const override;
void ForEachFeatureClosestToCross(m2::PointD const & cross,
ICrossEdgesLoader & edgeLoader) const override;

View file

@ -132,8 +132,7 @@ public:
{
ASSERT_EQUAL(v, e.GetStartJunction(), ());
double const speedMPS = KMPH2MPS(
m_roadGraph.GetSpeedKMpH(e, {true /* forward */, false /* in city */, Maxspeed()}));
double const speedMPS = KMPH2MPS(m_roadGraph.GetSpeedKMpH(e));
adj.emplace_back(e.GetEndJunction(), TimeBetweenSec(e.GetStartJunction(), e.GetEndJunction(), speedMPS));
}
}
@ -152,8 +151,7 @@ public:
{
ASSERT_EQUAL(v, e.GetEndJunction(), ());
double const speedMPS = KMPH2MPS(
m_roadGraph.GetSpeedKMpH(e, {true /* forward */, false /* in city */, Maxspeed()}));
double const speedMPS = KMPH2MPS(m_roadGraph.GetSpeedKMpH(e));
adj.emplace_back(e.GetStartJunction(), TimeBetweenSec(e.GetStartJunction(), e.GetEndJunction(), speedMPS));
}
}

View file

@ -1,17 +1,11 @@
#include "routing_common/bicycle_model.hpp"
#include "indexer/classificator.hpp"
#include "indexer/feature.hpp"
#include "base/assert.hpp"
#include "base/macros.hpp"
#include "base/logging.hpp"
using namespace routing;
using namespace std;
namespace bicycle_model
{
using namespace routing;
// See model specifics in different countries here:
// https://wiki.openstreetmap.org/wiki/OSM_tags_for_routing/Access-Restrictions
// Document contains proposals for some countries, but we assume that some kinds of roads are ready for bicycle routing,
@ -28,10 +22,10 @@ namespace bicycle_model
// As result of such heuristic road is not totally the shortest, but it avoids non bicycle roads, which were
// not marked as "hwtag=nobicycle" in OSM.
HighwayBasedFactors const kDefaultFactors = GetOneFactorsForBicycleAndPedestrianModel();
HighwayFactors const kDefaultFactors = GetOneFactorsForBicycleAndPedestrianModel();
HighwayBasedSpeeds const kDefaultSpeeds = {
// {highway class : InOutCitySpeedKMpH(in city(weight, eta), out city(weight eta))}
HighwaySpeeds const kDefaultSpeeds = {
// {highway class, InOutCitySpeedKMpH(in city(weight, eta), out city(weight eta))}
{HighwayType::HighwayTrunk, InOutCitySpeedKMpH(SpeedKMpH(3.0, 18.0))},
{HighwayType::HighwayTrunkLink, InOutCitySpeedKMpH(SpeedKMpH(3.0, 18.0))},
{HighwayType::HighwayPrimary, InOutCitySpeedKMpH(SpeedKMpH(10.0, 18.0), SpeedKMpH(14.0, 18.0))},
@ -45,465 +39,219 @@ HighwayBasedSpeeds const kDefaultSpeeds = {
{HighwayType::HighwayRoad, InOutCitySpeedKMpH(SpeedKMpH(10.0, 12.0))},
{HighwayType::HighwayTrack, InOutCitySpeedKMpH(SpeedKMpH(8.0, 12.0))},
{HighwayType::HighwayPath, InOutCitySpeedKMpH(SpeedKMpH(6.0, 12.0))},
{HighwayType::HighwayBridleway, InOutCitySpeedKMpH(SpeedKMpH(4.0, 12.0))},
{HighwayType::HighwayCycleway, InOutCitySpeedKMpH(SpeedKMpH(30.0, 20.0))},
{HighwayType::HighwayResidential, InOutCitySpeedKMpH(SpeedKMpH(8.0, 10.0))},
{HighwayType::HighwayLivingStreet, InOutCitySpeedKMpH(SpeedKMpH(7.0, 8.0))},
{HighwayType::RouteFerry, InOutCitySpeedKMpH(SpeedKMpH(3.0, 20.0))},
// Steps have obvious inconvenience of a bike in hands.
{HighwayType::HighwaySteps, InOutCitySpeedKMpH(SpeedKMpH(1.0, 1.0))},
// Set minimun default bicycle speeds for the next disputable roads.
{HighwayType::HighwayPedestrian, InOutCitySpeedKMpH(SpeedKMpH(2.0))},
{HighwayType::HighwayFootway, InOutCitySpeedKMpH(SpeedKMpH(2.0))},
{HighwayType::ManMadePier, InOutCitySpeedKMpH(SpeedKMpH(2.0))},
{HighwayType::HighwayBridleway, InOutCitySpeedKMpH(SpeedKMpH(2.0))},
};
// Normal bicycle speeds for disputable roads.
HighwaySpeeds const kAdditionalSpeeds = {
{HighwayType::HighwayPedestrian, InOutCitySpeedKMpH(SpeedKMpH(5.0))},
{HighwayType::HighwayFootway, InOutCitySpeedKMpH(SpeedKMpH(7.0, 5.0))},
{HighwayType::ManMadePier, InOutCitySpeedKMpH(SpeedKMpH(7.0))},
{HighwayType::RouteFerry, InOutCitySpeedKMpH(SpeedKMpH(3.0, 20.0))},
{HighwayType::HighwayBridleway, InOutCitySpeedKMpH(SpeedKMpH(4.0, 12.0))},
};
SpeedKMpH constexpr kSpeedOffroadKMpH = {3.0 /* weight */, 3.0 /* eta */};
// Default
VehicleModel::LimitsInitList const kBicycleOptionsDefault = {
// {{roadType, roadType} passThroughAllowed}
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true}};
// All options available.
VehicleModel::LimitsInitList const kBicycleOptionsAll = {
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "bridleway"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true},
{{"highway", "pedestrian"}, true},
{{"highway", "footway"}, true}};
SpeedKMpH constexpr kOffroadSpeed = {3.0 /* weight */, 3.0 /* eta */};
// Same as defaults except trunk and trunk_link are not allowed
VehicleModel::LimitsInitList const kBicycleOptionsNoTrunk = {
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true}};
HighwaySpeeds NoTrunk()
{
HighwaySpeeds res = kDefaultSpeeds;
res.erase(HighwayType::HighwayTrunk);
res.erase(HighwayType::HighwayTrunkLink);
return res;
}
// Same as defaults except pedestrian is allowed
VehicleModel::LimitsInitList const kBicycleOptionsPedestrianAllowed = {
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true},
{{"highway", "pedestrian"}, true}};
HighwaySpeeds PedestrianAllowed()
{
HighwaySpeeds res = kDefaultSpeeds;
res[HighwayType::HighwayPedestrian] = kAdditionalSpeeds.at(HighwayType::HighwayPedestrian);
return res;
}
// Same as defaults except bridleway is allowed
VehicleModel::LimitsInitList const kBicycleOptionsBridlewayAllowed = {
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "bridleway"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true}};
HighwaySpeeds BridlewayAllowed()
{
HighwaySpeeds res = kDefaultSpeeds;
res[HighwayType::HighwayBridleway] = kAdditionalSpeeds.at(HighwayType::HighwayBridleway);
return res;
}
// Same as defaults except pedestrian and footway are allowed
VehicleModel::LimitsInitList const kBicycleOptionsPedestrianFootwayAllowed = {
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true},
{{"highway", "pedestrian"}, true},
{{"highway", "footway"}, true}};
HighwaySpeeds PedestrianFootwayAllowed()
{
HighwaySpeeds res = kDefaultSpeeds;
res[HighwayType::HighwayPedestrian] = kAdditionalSpeeds.at(HighwayType::HighwayPedestrian);
res[HighwayType::HighwayFootway] = kAdditionalSpeeds.at(HighwayType::HighwayFootway);
return res;
}
// Australia
VehicleModel::LimitsInitList const kBicycleOptionsAustralia = kBicycleOptionsAll;
HighwaySpeeds AllAllowed()
{
HighwaySpeeds res = kDefaultSpeeds;
for (auto const & e : kAdditionalSpeeds)
res[e.first] = e.second;
return res;
}
// Austria
VehicleModel::LimitsInitList const kBicycleOptionsAustria = {
// No trunk, trunk_link, path
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true}};
// Austria (No trunk, no path)
HighwaySpeeds AustriaSpeeds()
{
HighwaySpeeds res = NoTrunk();
res.erase(HighwayType::HighwayPath);
return res;
}
// Belarus
VehicleModel::LimitsInitList const kBicycleOptionsBelarus = kBicycleOptionsPedestrianFootwayAllowed;
// Belgium (No trunk, pedestrian is allowed).
HighwaySpeeds BelgiumSpeeds()
{
HighwaySpeeds res = NoTrunk();
res[HighwayType::HighwayPedestrian] = kAdditionalSpeeds.at(HighwayType::HighwayPedestrian);
return res;
}
// Belgium
VehicleModel::LimitsInitList const kBicycleOptionsBelgium = {
// No trunk, trunk_link
// Pedestrian is allowed
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true},
{{"highway", "pedestrian"}, true}};
// Brazil (Bridleway and footway are allowed)
HighwaySpeeds BrazilSpeeds()
{
HighwaySpeeds res = kDefaultSpeeds;
res[HighwayType::HighwayBridleway] = kAdditionalSpeeds.at(HighwayType::HighwayBridleway);
res[HighwayType::HighwayFootway] = kAdditionalSpeeds.at(HighwayType::HighwayFootway);
return res;
}
// Brazil
VehicleModel::LimitsInitList const kBicycleOptionsBrazil = {
// Bridleway and fotway are allowed
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "bridleway"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true},
{{"highway", "footway"}, true}};
// France, same as Belgium (No trunk, pedestrian is allowed);
HighwaySpeeds FranceSpeeds() { return BelgiumSpeeds(); }
// Denmark
VehicleModel::LimitsInitList const kBicycleOptionsDenmark = kBicycleOptionsNoTrunk;
// Ukraine (No trunk, footway and pedestrian are allowed).
HighwaySpeeds UkraineSpeeds()
{
HighwaySpeeds res = NoTrunk();
res[HighwayType::HighwayPedestrian] = kAdditionalSpeeds.at(HighwayType::HighwayPedestrian);
res[HighwayType::HighwayFootway] = kAdditionalSpeeds.at(HighwayType::HighwayFootway);
return res;
}
// France
VehicleModel::LimitsInitList const kBicycleOptionsFrance = {
// No trunk, trunk_link
// Pedestrian is allowed
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true},
{{"highway", "pedestrian"}, true}};
// United States of America (Bridleway and pedestrian are allowed)
HighwaySpeeds USASpeeds()
{
HighwaySpeeds res = kDefaultSpeeds;
res[HighwayType::HighwayBridleway] = kAdditionalSpeeds.at(HighwayType::HighwayBridleway);
res[HighwayType::HighwayPedestrian] = kAdditionalSpeeds.at(HighwayType::HighwayPedestrian);
return res;
}
// Finland
VehicleModel::LimitsInitList const kBicycleOptionsFinland = kBicycleOptionsPedestrianAllowed;
// Germany
VehicleModel::LimitsInitList const kBicycleOptionsGermany = kBicycleOptionsDefault;
// Hungary
VehicleModel::LimitsInitList const kBicycleOptionsHungary = kBicycleOptionsNoTrunk;
// Iceland
VehicleModel::LimitsInitList const kBicycleOptionsIceland = kBicycleOptionsAll;
// Netherlands
VehicleModel::LimitsInitList const kBicycleOptionsNetherlands = kBicycleOptionsNoTrunk;
// Norway
VehicleModel::LimitsInitList const kBicycleOptionsNorway = kBicycleOptionsAll;
// Oman
VehicleModel::LimitsInitList const kBicycleOptionsOman = kBicycleOptionsBridlewayAllowed;
// Poland
VehicleModel::LimitsInitList const kBicycleOptionsPoland = kBicycleOptionsNoTrunk;
// Romania
VehicleModel::LimitsInitList const kBicycleOptionsRomania = kBicycleOptionsNoTrunk;
// Russian Federation
// Footway and pedestrian are allowed
// Note. Despite the fact that according to
// https://wiki.openstreetmap.org/wiki/OSM_tags_for_routing/Access-Restrictions
// passing through service and living_street with a bicycle is prohibited
// it's allowed according to Russian traffic rules.
VehicleModel::LimitsInitList const kBicycleOptionsRussia = kBicycleOptionsPedestrianFootwayAllowed;
// Slovakia
VehicleModel::LimitsInitList const kBicycleOptionsSlovakia = kBicycleOptionsNoTrunk;
// Spain
VehicleModel::LimitsInitList const kBicycleOptionsSpain = kBicycleOptionsPedestrianAllowed;
// Switzerland
VehicleModel::LimitsInitList const kBicycleOptionsSwitzerland = kBicycleOptionsNoTrunk;
// Turkey
VehicleModel::LimitsInitList const kBicycleOptionsTurkey = kBicycleOptionsDefault;
// Ukraine
VehicleModel::LimitsInitList const kBicycleOptionsUkraine = {
// No trunk
// Footway and pedestrian are allowed
// No pass through living_street and service
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, false},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, false},
{{"highway", "steps"}, true},
{{"highway", "pedestrian"}, true},
{{"highway", "footway"}, true}};
// United Kingdom
VehicleModel::LimitsInitList const kBicycleOptionsUK = kBicycleOptionsBridlewayAllowed;
// United States of America
VehicleModel::LimitsInitList const kBicycleOptionsUS = {
// Bridleway and pedesprian are allowed
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "bridleway"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true},
{{"highway", "pedestrian"}, true}};
VehicleModel::SurfaceInitList const kBicycleSurface = {
// {{surfaceType, surfaceType}, {weightFactor, etaFactor}}
{{"psurface", "paved_good"}, {1.0, 1.0}},
{{"psurface", "paved_bad"}, {0.8, 0.8}},
{{"psurface", "unpaved_good"}, {1.0, 1.0}},
{{"psurface", "unpaved_bad"}, {0.3, 0.3}}
SurfaceFactors const kBicycleSurface = {
// {SurfaceType, {weightFactor, etaFactor}}
{SurfaceType::PavedGood, {1.0, 1.0}},
{SurfaceType::PavedBad, {0.8, 0.8}},
{SurfaceType::UnpavedGood, {1.0, 1.0}},
{SurfaceType::UnpavedBad, {0.3, 0.3}}
};
} // namespace bicycle_model
namespace routing
{
BicycleModel::BicycleModel()
: VehicleModel(classif(), bicycle_model::kBicycleOptionsDefault, bicycle_model::kBicycleSurface,
{bicycle_model::kDefaultSpeeds, bicycle_model::kDefaultFactors})
{
Init();
}
BicycleModel::BicycleModel(VehicleModel::LimitsInitList const & speedLimits)
: VehicleModel(classif(), speedLimits, bicycle_model::kBicycleSurface, {bicycle_model::kDefaultSpeeds, bicycle_model::kDefaultFactors})
BicycleModel::BicycleModel(HighwaySpeeds const & speeds)
: VehicleModel(speeds, bicycle_model::kDefaultFactors, bicycle_model::kBicycleSurface)
{
Init();
}
void BicycleModel::Init()
{
std::vector<std::string> hwtagYesBicycle = {"hwtag", "yesbicycle"};
auto const & cl = classif();
m_yesBicycleType = cl.GetTypeByPath({"hwtag", "yesbicycle"});
m_noBicycleType = cl.GetTypeByPath({"hwtag", "nobicycle"});
m_yesBicycleType = cl.GetTypeByPath(hwtagYesBicycle);
m_bidirBicycleType = cl.GetTypeByPath({"hwtag", "bidir_bicycle"});
m_onedirBicycleType = cl.GetTypeByPath({"hwtag", "onedir_bicycle"});
AddAdditionalRoadTypes(cl, {
{std::move(hwtagYesBicycle), m_maxModelSpeed},
{{"route", "ferry"}, bicycle_model::kDefaultSpeeds.Get(HighwayType::RouteFerry)},
{{"man_made", "pier"}, bicycle_model::kDefaultSpeeds.Get(HighwayType::ManMadePier)}
});
// Small dismount speed with obvious inconvenience of a bike in hands.
InOutCitySpeedKMpH const dismountSpeed(SpeedKMpH(2.0, 2.0));
/// @todo I suspect that 'highway-footway-bridge/tunnel' will not be processed properly ...
AddAdditionalRoadTypes(cl, {
{{"highway", "footway"}, dismountSpeed},
{{"highway", "pedestrian"}, dismountSpeed},
{{"highway", "steps"}, dismountSpeed}
});
}
VehicleModelInterface::RoadAvailability BicycleModel::GetRoadAvailability(feature::TypesHolder const & types) const
VehicleModel::ResultT BicycleModel::IsOneWay(uint32_t type) const
{
if (types.Has(m_yesBicycleType))
return RoadAvailability::Available;
if (types.Has(m_noBicycleType))
return RoadAvailability::NotAvailable;
return RoadAvailability::Unknown;
if (type == m_onedirBicycleType)
return ResultT::Yes;
else if (type == m_bidirBicycleType)
return ResultT::No;
return ResultT::Unknown;
}
bool BicycleModel::IsBicycleBidir(feature::TypesHolder const & types) const
VehicleModel::ResultT BicycleModel::GetRoadAvailability(uint32_t type) const
{
return types.Has(m_bidirBicycleType);
if (type == m_yesBicycleType)
return ResultT::Yes;
else if (type == m_noBicycleType)
return ResultT::No;
return ResultT::Unknown;
}
bool BicycleModel::IsBicycleOnedir(feature::TypesHolder const & types) const
SpeedKMpH BicycleModel::GetSpeedForAvailable() const
{
return types.Has(m_onedirBicycleType);
return m_maxModelSpeed.m_inCity;
}
SpeedKMpH BicycleModel::GetSpeed(FeatureType & f, SpeedParams const & speedParams) const
SpeedKMpH BicycleModel::GetOffroadSpeed() const
{
return VehicleModel::GetSpeedWihtoutMaxspeed(f, speedParams);
return bicycle_model::kOffroadSpeed;
}
bool BicycleModel::IsOneWay(FeatureType & f) const
{
feature::TypesHolder const types(f);
if (IsBicycleOnedir(types))
return true;
if (IsBicycleBidir(types))
return false;
return VehicleModel::IsOneWay(f);
}
SpeedKMpH const & BicycleModel::GetOffroadSpeed() const { return bicycle_model::kSpeedOffroadKMpH; }
// If one of feature types will be disabled for bicycles, features of this type will be simplified
// in generator. Look FeatureBuilder1::IsRoad() for more details.
// static
BicycleModel const & BicycleModel::AllLimitsInstance()
{
static BicycleModel const instance(bicycle_model::kBicycleOptionsAll);
static BicycleModel const instance(bicycle_model::AllAllowed());
return instance;
}
BicycleModelFactory::BicycleModelFactory(
CountryParentNameGetterFn const & countryParentNameGetterFn)
: VehicleModelFactory(countryParentNameGetterFn)
BicycleModelFactory::BicycleModelFactory(CountryParentNameGetterFn const & parentGetter)
: VehicleModelFactory(parentGetter)
{
using namespace bicycle_model;
// Names must be the same with country names from countries.txt
m_models[""] = make_shared<BicycleModel>(kBicycleOptionsDefault);
m_models["Australia"] = make_shared<BicycleModel>(kBicycleOptionsAustralia);
m_models["Austria"] = make_shared<BicycleModel>(kBicycleOptionsAustria);
m_models["Belarus"] = make_shared<BicycleModel>(kBicycleOptionsBelarus);
m_models["Belgium"] = make_shared<BicycleModel>(kBicycleOptionsBelgium);
m_models["Brazil"] = make_shared<BicycleModel>(kBicycleOptionsBrazil);
m_models["Denmark"] = make_shared<BicycleModel>(kBicycleOptionsDenmark);
m_models["France"] = make_shared<BicycleModel>(kBicycleOptionsFrance);
m_models["Finland"] = make_shared<BicycleModel>(kBicycleOptionsFinland);
m_models["Germany"] = make_shared<BicycleModel>(kBicycleOptionsGermany);
m_models["Hungary"] = make_shared<BicycleModel>(kBicycleOptionsHungary);
m_models["Iceland"] = make_shared<BicycleModel>(kBicycleOptionsIceland);
m_models["Netherlands"] = make_shared<BicycleModel>(kBicycleOptionsNetherlands);
m_models["Norway"] = make_shared<BicycleModel>(kBicycleOptionsNorway);
m_models["Oman"] = make_shared<BicycleModel>(kBicycleOptionsOman);
m_models["Poland"] = make_shared<BicycleModel>(kBicycleOptionsPoland);
m_models["Romania"] = make_shared<BicycleModel>(kBicycleOptionsRomania);
m_models["Russian Federation"] = make_shared<BicycleModel>(kBicycleOptionsRussia);
m_models["Slovakia"] = make_shared<BicycleModel>(kBicycleOptionsSlovakia);
m_models["Spain"] = make_shared<BicycleModel>(kBicycleOptionsSpain);
m_models["Switzerland"] = make_shared<BicycleModel>(kBicycleOptionsSwitzerland);
m_models["Turkey"] = make_shared<BicycleModel>(kBicycleOptionsTurkey);
m_models["Ukraine"] = make_shared<BicycleModel>(kBicycleOptionsUkraine);
m_models["United Kingdom"] = make_shared<BicycleModel>(kBicycleOptionsUK);
m_models["United States of America"] = make_shared<BicycleModel>(kBicycleOptionsUS);
m_models[""].reset(new BicycleModel(kDefaultSpeeds));
m_models["Australia"].reset(new BicycleModel(AllAllowed()));
m_models["Austria"].reset(new BicycleModel(AustriaSpeeds()));
m_models["Belarus"].reset(new BicycleModel(PedestrianFootwayAllowed()));
m_models["Belgium"].reset(new BicycleModel(BelgiumSpeeds()));
m_models["Brazil"].reset(new BicycleModel(BrazilSpeeds()));
m_models["Denmark"].reset(new BicycleModel(NoTrunk()));
m_models["France"].reset(new BicycleModel(FranceSpeeds()));
m_models["Finland"].reset(new BicycleModel(PedestrianAllowed()));
m_models["Germany"].reset(new BicycleModel(kDefaultSpeeds));
m_models["Hungary"].reset(new BicycleModel(NoTrunk()));
m_models["Iceland"].reset(new BicycleModel(AllAllowed()));
m_models["Netherlands"].reset(new BicycleModel(NoTrunk()));
m_models["Norway"].reset(new BicycleModel(AllAllowed()));
m_models["Oman"].reset(new BicycleModel(BridlewayAllowed()));
m_models["Poland"].reset(new BicycleModel(NoTrunk()));
m_models["Romania"].reset(new BicycleModel(NoTrunk()));
// Russian Federation
// Footway and pedestrian are allowed
// Note. Despite the fact that according to
// https://wiki.openstreetmap.org/wiki/OSM_tags_for_routing/Access-Restrictions
// passing through service and living_street with a bicycle is prohibited
// it's allowed according to Russian traffic rules.
m_models["Russian Federation"].reset(new BicycleModel(PedestrianFootwayAllowed()));
m_models["Slovakia"].reset(new BicycleModel(NoTrunk()));
m_models["Spain"].reset(new BicycleModel(PedestrianAllowed()));
m_models["Switzerland"].reset(new BicycleModel(NoTrunk()));
m_models["Turkey"].reset(new BicycleModel(kDefaultSpeeds));
m_models["Ukraine"].reset(new BicycleModel(UkraineSpeeds()));
m_models["United Kingdom"].reset(new BicycleModel(BridlewayAllowed()));
m_models["United States of America"].reset(new BicycleModel(USASpeeds()));
}
} // routing

View file

@ -1,5 +1,4 @@
#pragma once
#include "routing_common/vehicle_model.hpp"
namespace routing
@ -7,39 +6,33 @@ namespace routing
class BicycleModel : public VehicleModel
{
explicit BicycleModel(HighwaySpeeds const & speeds);
friend class BicycleModelFactory;
public:
BicycleModel();
BicycleModel(VehicleModel::LimitsInitList const & speedLimits);
/// VehicleModelInterface overrides:
SpeedKMpH GetSpeed(FeatureType & f, SpeedParams const & speedParams) const override;
bool IsOneWay(FeatureType & f) const override;
SpeedKMpH const & GetOffroadSpeed() const override;
static BicycleModel const & AllLimitsInstance();
/// @name VehicleModel overrides
/// @{
SpeedKMpH GetOffroadSpeed() const override;
protected:
RoadAvailability GetRoadAvailability(feature::TypesHolder const & types) const override;
ResultT IsOneWay(uint32_t type) const override;
ResultT GetRoadAvailability(uint32_t type) const override;
SpeedKMpH GetSpeedForAvailable() const override;
/// @}
private:
void Init();
/// @return true if it is allowed to ride a bicycle in both directions.
bool IsBicycleBidir(feature::TypesHolder const & types) const;
// Returns true if the road is explicitly set oneway for bicycles.
bool IsBicycleOnedir(feature::TypesHolder const & types) const;
uint32_t m_noBicycleType = 0;
uint32_t m_yesBicycleType = 0;
uint32_t m_bidirBicycleType = 0;
uint32_t m_onedirBicycleType = 0;
uint32_t m_noBicycleType;
uint32_t m_yesBicycleType;
uint32_t m_bidirBicycleType;
uint32_t m_onedirBicycleType;
};
class BicycleModelFactory : public VehicleModelFactory
{
public:
// TODO: remove countryParentNameGetterFn default value after removing unused bicycle routing
// from road_graph_router
BicycleModelFactory(CountryParentNameGetterFn const & countryParentNameGetterFn = {});
explicit BicycleModelFactory(CountryParentNameGetterFn const & parentGetter);
};
} // namespace routing

View file

@ -1,14 +1,6 @@
#include "routing_common/car_model.hpp"
#include "routing_common/car_model_coefs.hpp"
#include "indexer/classificator.hpp"
#include "indexer/feature.hpp"
#include "base/macros.hpp"
#include <array>
#include <unordered_map>
namespace car_model
{
using namespace std;
@ -26,204 +18,94 @@ using namespace routing;
// a start or finish. On the other hand, while route calculation the fake edges are considered
// as quite heavy. The idea behind that is to use the closest edge for the start and the finish
// of the route except for some edge cases.
SpeedKMpH constexpr kSpeedOffroadKMpH = {0.01 /* weight */, kNotUsed /* eta */};
SpeedKMpH constexpr kOffroadSpeed = {0.01 /* weight */, kNotUsed /* eta */};
VehicleModel::LimitsInitList const kCarOptionsDefault = {
// {{roadType, roadType} passThroughAllowed}
{{"highway", "motorway"}, true},
{{"highway", "motorway_link"}, true},
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "residential"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "service"}, true},
{{"highway", "living_street"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true}
/// @todo: Add to classificator
//{ {"highway", "shuttle_train"}, 10 },
//{ {"highway", "ferry"}, 5 },
//{ {"highway", "default"}, 10 },
/// @todo: Check type
//{ {"highway", "construction"}, 40 },
};
NoPassThroughHighways NoPassThroughLivingStreet()
{
return {HighwayType::HighwayLivingStreet};
}
VehicleModel::LimitsInitList const kCarOptionsNoPassThroughLivingStreet = {
{{"highway", "motorway"}, true},
{{"highway", "motorway_link"}, true},
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "residential"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "service"}, true},
{{"highway", "living_street"}, false},
{{"highway", "road"}, true},
{{"highway", "track"}, true}};
NoPassThroughHighways NoPassThroughLivingStreetAndService()
{
return {HighwayType::HighwayLivingStreet, HighwayType::HighwayService};
}
VehicleModel::LimitsInitList const kCarOptionsNoPassThroughLivingStreetAndService = {
{{"highway", "motorway"}, true},
{{"highway", "motorway_link"}, true},
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "residential"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "service"}, false},
{{"highway", "living_street"}, false},
{{"highway", "road"}, true},
{{"highway", "track"}, true}};
HighwaySpeeds NoTrack()
{
HighwaySpeeds res = kHighwayBasedSpeeds;
res.erase(HighwayType::HighwayTrack);
return res;
}
VehicleModel::LimitsInitList const kCarOptionsDenmark = {
// No track
{{"highway", "motorway"}, true},
{{"highway", "motorway_link"}, true},
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "residential"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "service"}, true},
{{"highway", "living_street"}, true},
{{"highway", "road"}, true}};
NoPassThroughHighways NoPassThroughTrack()
{
return {HighwayType::HighwayTrack};
}
VehicleModel::LimitsInitList const kCarOptionsGermany = {
// No pass through track
{{"highway", "motorway"}, true},
{{"highway", "motorway_link"}, true},
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "residential"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "service"}, true},
{{"highway", "living_street"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, false}};
VehicleModel::AdditionalRoadsList const kAdditionalRoads = {
// {{highway tags}, {weightSpeed, etaSpeed}}
{{"railway", "rail", "motor_vehicle"}, kHighwayBasedSpeeds.Get(HighwayType::RailwayRailMotorVehicle)},
{{"route", "shuttle_train"}, kHighwayBasedSpeeds.Get(HighwayType::RouteShuttleTrain)},
{{"route", "ferry"}, kHighwayBasedSpeeds.Get(HighwayType::RouteFerry)},
{{"man_made", "pier"}, kHighwayBasedSpeeds.Get(HighwayType::ManMadePier)}};
VehicleModel::SurfaceInitList const kCarSurface = {
// {{surfaceType, surfaceType}, {weightFactor, etaFactor}}
{{"psurface", "paved_good"}, {1.0, 1.0}},
{{"psurface", "paved_bad"}, {0.5, 0.5}},
{{"psurface", "unpaved_good"}, {0.4, 0.8}},
{{"psurface", "unpaved_bad"}, {0.1, 0.3}}
};
// Names must be the same with country names from countries.txt
std::unordered_map<char const *, VehicleModel::LimitsInitList> const kCarOptionsByCountries = {
{"Austria", kCarOptionsNoPassThroughLivingStreet},
{"Belarus", kCarOptionsNoPassThroughLivingStreet},
{"Denmark", kCarOptionsDenmark},
{"Germany", kCarOptionsGermany},
{"Hungary", kCarOptionsNoPassThroughLivingStreet},
{"Romania", kCarOptionsNoPassThroughLivingStreet},
{"Russian Federation", kCarOptionsNoPassThroughLivingStreetAndService},
{"Slovakia", kCarOptionsNoPassThroughLivingStreet},
{"Ukraine", kCarOptionsNoPassThroughLivingStreetAndService}
};
} // namespace car_model
namespace routing
{
CarModel::CarModel()
: VehicleModel(classif(), car_model::kCarOptionsDefault, car_model::kCarSurface,
{kHighwayBasedSpeeds, kHighwayBasedFactors})
CarModel::CarModel(HighwaySpeeds const & speeds, NoPassThroughHighways const & noPassThrough)
: VehicleModel(speeds, kHighwayBasedFactors, kHighwayBasedSurface, noPassThrough)
{
Init();
auto const & cl = classif();
m_noCarType = cl.GetTypeByPath({"hwtag", "nocar"});
m_yesCarType = cl.GetTypeByPath({"hwtag", "yescar"});
m_onewayType = cl.GetTypeByPath({"hwtag", "oneway"});
}
CarModel::CarModel(VehicleModel::LimitsInitList const & roadLimits, HighwayBasedInfo const & info)
: VehicleModel(classif(), roadLimits, car_model::kCarSurface, info)
SpeedKMpH CarModel::GetOffroadSpeed() const
{
Init();
return car_model::kOffroadSpeed;
}
SpeedKMpH const & CarModel::GetOffroadSpeed() const { return car_model::kSpeedOffroadKMpH; }
void CarModel::Init()
VehicleModel::ResultT CarModel::IsOneWay(uint32_t type) const
{
m_noCarType = classif().GetTypeByPath({"hwtag", "nocar"});
m_yesCarType = classif().GetTypeByPath({"hwtag", "yescar"});
AddAdditionalRoadTypes(classif(), car_model::kAdditionalRoads);
if (type == m_onewayType)
return ResultT::Yes;
return ResultT::Unknown;
}
VehicleModelInterface::RoadAvailability CarModel::GetRoadAvailability(feature::TypesHolder const & types) const
VehicleModel::ResultT CarModel::GetRoadAvailability(uint32_t type) const
{
if (types.Has(m_yesCarType))
return RoadAvailability::Available;
if (type == m_yesCarType)
return ResultT::Yes;
else if (type == m_noCarType)
return ResultT::No;
return ResultT::Unknown;
}
if (types.Has(m_noCarType))
return RoadAvailability::NotAvailable;
return RoadAvailability::Unknown;
SpeedKMpH CarModel::GetSpeedForAvailable() const
{
/// @todo Return 20% from maximun model speed.
return m_maxModelSpeed.m_inCity * 0.2;
}
// static
CarModel const & CarModel::AllLimitsInstance()
{
static CarModel const instance;
static CarModel const instance(kHighwayBasedSpeeds);
return instance;
}
// static
VehicleModel::LimitsInitList const & CarModel::GetOptions() { return car_model::kCarOptionsDefault; }
// static
VehicleModel::AdditionalRoadsList const & CarModel::GetAdditionalRoads()
{
return car_model::kAdditionalRoads;
}
// static
VehicleModel::SurfaceInitList const & CarModel::GetSurfaces() { return car_model::kCarSurface; }
CarModelFactory::CarModelFactory(CountryParentNameGetterFn const & countryParentNameGetterFn)
: VehicleModelFactory(countryParentNameGetterFn)
{
m_models[""] = std::make_shared<CarModel>(
car_model::kCarOptionsDefault,
HighwayBasedInfo(kHighwayBasedSpeeds, kHighwayBasedFactors));
using namespace car_model;
// Names must be the same with country names from countries.txt
for (auto const & kv : car_model::kCarOptionsByCountries)
{
auto const * country = kv.first;
auto const & limit = kv.second;
m_models[country] =
std::make_shared<CarModel>(limit, HighwayBasedInfo(kHighwayBasedSpeeds, kHighwayBasedFactors));
}
m_models[""].reset(new CarModel(kHighwayBasedSpeeds));
m_models["Austria"].reset(new CarModel(kHighwayBasedSpeeds, NoPassThroughLivingStreet()));
m_models["Belarus"].reset(new CarModel(kHighwayBasedSpeeds, NoPassThroughLivingStreet()));
m_models["Denmark"].reset(new CarModel(NoTrack()));
m_models["Germany"].reset(new CarModel(kHighwayBasedSpeeds, NoPassThroughTrack()));
m_models["Hungary"].reset(new CarModel(kHighwayBasedSpeeds, NoPassThroughLivingStreet()));
m_models["Romania"].reset(new CarModel(kHighwayBasedSpeeds, NoPassThroughLivingStreet()));
m_models["Russian Federation"].reset(new CarModel(kHighwayBasedSpeeds, NoPassThroughLivingStreetAndService()));
m_models["Slovakia"].reset(new CarModel(kHighwayBasedSpeeds, NoPassThroughLivingStreet()));
m_models["Ukraine"].reset(new CarModel(kHighwayBasedSpeeds, NoPassThroughLivingStreetAndService()));
}
} // namespace routing

View file

@ -9,34 +9,31 @@ namespace routing
class CarModel : public VehicleModel
{
explicit CarModel(HighwaySpeeds const & speeds, NoPassThroughHighways const & noPassThrough = {});
friend class CarModelFactory;
public:
CarModel();
CarModel(LimitsInitList const & roadLimits, HighwayBasedInfo const & info);
// VehicleModelInterface overrides:
SpeedKMpH const & GetOffroadSpeed() const override;
static CarModel const & AllLimitsInstance();
static LimitsInitList const & GetOptions();
static AdditionalRoadsList const & GetAdditionalRoads();
static SurfaceInitList const & GetSurfaces();
uint32_t GetNoCarTypeForTesting() const { return m_noCarType; }
uint32_t GetYesCarTypeForTesting() const { return m_yesCarType; }
/// @name VehicleModelInterface overrides
/// @{
SpeedKMpH GetOffroadSpeed() const override;
protected:
RoadAvailability GetRoadAvailability(feature::TypesHolder const & types) const override;
ResultT IsOneWay(uint32_t type) const override;
ResultT GetRoadAvailability(uint32_t type) const override;
SpeedKMpH GetSpeedForAvailable() const override;
/// @}
private:
void Init();
uint32_t m_noCarType = 0;
uint32_t m_yesCarType = 0;
uint32_t m_onewayType = 0;
};
class CarModelFactory : public VehicleModelFactory
{
public:
CarModelFactory(CountryParentNameGetterFn const & countryParentNameGetterF);
explicit CarModelFactory(CountryParentNameGetterFn const & countryParentNameGetterF);
};
} // namespace routing

View file

@ -12,7 +12,7 @@ namespace routing
* There are no (99%) traffic lights or pedestrian crossings on this kind of roads.
*/
HighwayBasedFactors const kHighwayBasedFactors = {
HighwayFactors const kHighwayBasedFactors = {
// {highway class : InOutCityFactor(in city, out city)}
{HighwayType::HighwayLivingStreet, InOutCityFactor(0.75)},
{HighwayType::HighwayMotorway, InOutCityFactor(0.90, 0.94)},
@ -36,7 +36,7 @@ HighwayBasedFactors const kHighwayBasedFactors = {
{HighwayType::RouteShuttleTrain, InOutCityFactor(0.90)},
};
HighwayBasedSpeeds const kHighwayBasedSpeeds = {
HighwaySpeeds const kHighwayBasedSpeeds = {
// {highway class : InOutCitySpeedKMpH(in city, out city)}
{HighwayType::HighwayLivingStreet, InOutCitySpeedKMpH({10.00, 10.00} /* in city */, {10.00, 10.00} /* out city */)},
{HighwayType::HighwayMotorway, InOutCitySpeedKMpH(118.0 /* in city */, 124.0 /* out city */)},
@ -59,4 +59,13 @@ HighwayBasedSpeeds const kHighwayBasedSpeeds = {
{HighwayType::RouteFerry, InOutCitySpeedKMpH({10.00, 10.00} /* in city */, {10.00, 10.00} /* out city */)},
{HighwayType::RouteShuttleTrain, InOutCitySpeedKMpH({25.00, 25.00} /* in city */, {25.00, 25.00} /* out city */)},
};
SurfaceFactors const kHighwayBasedSurface = {
// {surfaceType, {weightFactor, etaFactor}}
{SurfaceType::PavedGood, {1.0, 1.0}},
{SurfaceType::PavedBad, {0.5, 0.5}},
{SurfaceType::UnpavedGood, {0.4, 0.8}},
{SurfaceType::UnpavedBad, {0.1, 0.3}}
};
} // namespace routing

View file

@ -1,17 +1,11 @@
#include "routing_common/pedestrian_model.hpp"
#include "indexer/classificator.hpp"
#include "indexer/feature.hpp"
#include "base/assert.hpp"
#include "base/macros.hpp"
#include "base/logging.hpp"
using namespace routing;
using namespace std;
namespace pedestrian_model
{
using namespace routing;
// See model specifics in different countries here:
// https://wiki.openstreetmap.org/wiki/OSM_tags_for_routing/Access-Restrictions
// Document contains proposals for some countries, but we assume that some kinds of roads are ready for pedestrian routing,
@ -28,9 +22,9 @@ namespace pedestrian_model
// As result of such heuristic road is not totally the shortest, but it avoids non pedestrian roads, which were
// not marked as "foot=no" in OSM.
HighwayBasedFactors const kDefaultFactors = GetOneFactorsForBicycleAndPedestrianModel();
HighwayFactors const kDefaultFactors = GetOneFactorsForBicycleAndPedestrianModel();
HighwayBasedSpeeds const kDefaultSpeeds = {
HighwaySpeeds const kAllSpeeds = {
// {highway class : InOutCitySpeedKMpH(in city(weight, eta), out city(weight eta))}
{HighwayType::HighwayTrunk, InOutCitySpeedKMpH(SpeedKMpH(1.0, 5.0))},
{HighwayType::HighwayTrunkLink, InOutCitySpeedKMpH(SpeedKMpH(1.0, 5.0))},
@ -57,262 +51,93 @@ HighwayBasedSpeeds const kDefaultSpeeds = {
{HighwayType::RouteFerry, InOutCitySpeedKMpH(SpeedKMpH(3.0, 20.0))},
};
SpeedKMpH constexpr kSpeedOffroadKMpH = {3.0 /* weight */, 3.0 /* eta */};
SpeedKMpH constexpr kOffroadSpeed = {3.0 /* weight */, 3.0 /* eta */};
// Default
VehicleModel::LimitsInitList const kPedestrianOptionsDefault = {
// {{roadType, roadType} passThroughAllowed}
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true},
{{"highway", "pedestrian"}, true},
{{"highway", "footway"}, true}};
// All options available.
VehicleModel::LimitsInitList const kPedestrianOptionsAll = {
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "bridleway"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true},
{{"highway", "pedestrian"}, true},
{{"highway", "footway"}, true}};
// Default (No bridleway, no cycleway).
HighwaySpeeds DefaultSpeeds()
{
HighwaySpeeds res = kAllSpeeds;
res.erase(HighwayType::HighwayBridleway);
res.erase(HighwayType::HighwayCycleway);
return res;
}
// Same as defaults except trunk and trunk link are not allowed.
VehicleModel::LimitsInitList const kPedestrianOptionsNoTrunk = {
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true},
{{"highway", "pedestrian"}, true},
{{"highway", "footway"}, true}};
HighwaySpeeds NoTrunk()
{
HighwaySpeeds res = DefaultSpeeds();
res.erase(HighwayType::HighwayTrunk);
res.erase(HighwayType::HighwayTrunkLink);
return res;
}
// Same as defaults except cycleway is allowed.
VehicleModel::LimitsInitList const kPedestrianOptionsCyclewayAllowed = {
{{"highway", "trunk"}, true},
{{"highway", "trunk_link"}, true},
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true},
{{"highway", "pedestrian"}, true},
{{"highway", "footway"}, true}};
HighwaySpeeds AllowCycleway()
{
HighwaySpeeds res = DefaultSpeeds();
res[HighwayType::HighwayCycleway] = kAllSpeeds.at(HighwayType::HighwayCycleway);
return res;
}
// Same as defaults except cycleway is allowed and trunk and trunk_link are not allowed.
VehicleModel::LimitsInitList const kPedestrianOptionsCyclewayAllowedNoTrunk = {
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true},
{{"highway", "pedestrian"}, true},
{{"highway", "footway"}, true}};
// Australia
VehicleModel::LimitsInitList const kPedestrianOptionsAustralia = kPedestrianOptionsAll;
// Austria
VehicleModel::LimitsInitList const kPedestrianOptionsAustria = kPedestrianOptionsNoTrunk;
// Belarus
VehicleModel::LimitsInitList const kPedestrianOptionsBelarus = kPedestrianOptionsCyclewayAllowed;
HighwaySpeeds AllowCyclewayNoTrunk()
{
HighwaySpeeds res = NoTrunk();
res[HighwayType::HighwayCycleway] = kAllSpeeds.at(HighwayType::HighwayCycleway);
return res;
}
// Belgium
VehicleModel::LimitsInitList const kPedestrianOptionsBelgium = {
// Trunk and trunk_link are not allowed
// Bridleway and cycleway are allowed
{{"highway", "primary"}, true},
{{"highway", "primary_link"}, true},
{{"highway", "secondary"}, true},
{{"highway", "secondary_link"}, true},
{{"highway", "tertiary"}, true},
{{"highway", "tertiary_link"}, true},
{{"highway", "service"}, true},
{{"highway", "unclassified"}, true},
{{"highway", "road"}, true},
{{"highway", "track"}, true},
{{"highway", "path"}, true},
{{"highway", "bridleway"}, true},
{{"highway", "cycleway"}, true},
{{"highway", "residential"}, true},
{{"highway", "living_street"}, true},
{{"highway", "steps"}, true},
{{"highway", "pedestrian"}, true},
{{"highway", "footway"}, true}};
// Trunk and trunk_link are not allowed
// Bridleway and cycleway are allowed
HighwaySpeeds BelgiumSpeeds()
{
HighwaySpeeds res = AllowCyclewayNoTrunk();
res[HighwayType::HighwayBridleway] = kAllSpeeds.at(HighwayType::HighwayBridleway);
return res;
}
// Brazil
VehicleModel::LimitsInitList const kPedestrianOptionsBrazil = kPedestrianOptionsAll;
// Denmark
VehicleModel::LimitsInitList const kPedestrianOptionsDenmark = kPedestrianOptionsCyclewayAllowedNoTrunk;
// France
VehicleModel::LimitsInitList const kPedestrianOptionsFrance = kPedestrianOptionsNoTrunk;
// Finland
VehicleModel::LimitsInitList const kPedestrianOptionsFinland = kPedestrianOptionsCyclewayAllowed;
// Germany
VehicleModel::LimitsInitList const kPedestrianOptionsGermany = kPedestrianOptionsDefault;
// Hungary
VehicleModel::LimitsInitList const kPedestrianOptionsHungary = kPedestrianOptionsNoTrunk;
// Iceland
VehicleModel::LimitsInitList const kPedestrianOptionsIceland = kPedestrianOptionsAll;
// Netherlands
VehicleModel::LimitsInitList const kPedestrianOptionsNetherlands = kPedestrianOptionsCyclewayAllowedNoTrunk;
// Norway
VehicleModel::LimitsInitList const kPedestrianOptionsNorway = kPedestrianOptionsAll;
// Oman
VehicleModel::LimitsInitList const kPedestrianOptionsOman = kPedestrianOptionsAll;
// Poland
VehicleModel::LimitsInitList const kPedestrianOptionsPoland = kPedestrianOptionsNoTrunk;
// Romania
VehicleModel::LimitsInitList const kPedestrianOptionsRomania = kPedestrianOptionsNoTrunk;
// Russian Federation
VehicleModel::LimitsInitList const kPedestrianOptionsRussia = kPedestrianOptionsCyclewayAllowed;
// Slovakia
VehicleModel::LimitsInitList const kPedestrianOptionsSlovakia = kPedestrianOptionsNoTrunk;
// Spain
VehicleModel::LimitsInitList const kPedestrianOptionsSpain = kPedestrianOptionsNoTrunk;
// Switzerland
VehicleModel::LimitsInitList const kPedestrianOptionsSwitzerland = kPedestrianOptionsNoTrunk;
// Turkey
VehicleModel::LimitsInitList const kPedestrianOptionsTurkey = kPedestrianOptionsAll;
// Ukraine
VehicleModel::LimitsInitList const kPedestrianOptionsUkraine = kPedestrianOptionsNoTrunk;
// United Kingdom
VehicleModel::LimitsInitList const kPedestrianOptionsUK = kPedestrianOptionsAll;
// United States of America
VehicleModel::LimitsInitList const kPedestrianOptionsUS = kPedestrianOptionsAll;
VehicleModel::SurfaceInitList const kPedestrianSurface = {
// {{surfaceType, surfaceType}, {weightFactor, etaFactor}}
{{"psurface", "paved_good"}, {1.0, 1.0}},
{{"psurface", "paved_bad"}, {1.0, 1.0}},
{{"psurface", "unpaved_good"}, {1.0, 1.0}},
{{"psurface", "unpaved_bad"}, {0.8, 0.8}}
SurfaceFactors const kPedestrianSurface = {
// {SurfaceType, {weightFactor, etaFactor}}
{SurfaceType::PavedGood, {1.0, 1.0}},
{SurfaceType::PavedBad, {1.0, 1.0}},
{SurfaceType::UnpavedGood, {1.0, 1.0}},
{SurfaceType::UnpavedBad, {0.8, 0.8}}
};
} // namespace pedestrian_model
namespace routing
{
PedestrianModel::PedestrianModel()
: VehicleModel(classif(), pedestrian_model::kPedestrianOptionsDefault, pedestrian_model::kPedestrianSurface,
{pedestrian_model::kDefaultSpeeds, pedestrian_model::kDefaultFactors})
PedestrianModel::PedestrianModel(HighwaySpeeds const & speeds)
: VehicleModel(speeds, pedestrian_model::kDefaultFactors, pedestrian_model::kPedestrianSurface)
{
Init();
m_noFootType = classif().GetTypeByPath({"hwtag", "nofoot"});
m_yesFootType = classif().GetTypeByPath({"hwtag", "yesfoot"});
}
PedestrianModel::PedestrianModel(VehicleModel::LimitsInitList const & speedLimits)
: VehicleModel(classif(), speedLimits, pedestrian_model::kPedestrianSurface,
{pedestrian_model::kDefaultSpeeds, pedestrian_model::kDefaultFactors})
SpeedKMpH PedestrianModel::GetOffroadSpeed() const
{
Init();
return pedestrian_model::kOffroadSpeed;
}
SpeedKMpH PedestrianModel::GetSpeed(FeatureType & f, SpeedParams const & speedParams) const
VehicleModel::ResultT PedestrianModel::IsOneWay(uint32_t) const
{
return VehicleModel::GetSpeedWihtoutMaxspeed(f, speedParams);
return ResultT::Unknown;
}
SpeedKMpH const & PedestrianModel::GetOffroadSpeed() const { return pedestrian_model::kSpeedOffroadKMpH; }
void PedestrianModel::Init()
VehicleModel::ResultT PedestrianModel::GetRoadAvailability(uint32_t type) const
{
std::vector<std::string> hwtagYesFoot = {"hwtag", "yesfoot"};
m_noFootType = classif().GetTypeByPath({ "hwtag", "nofoot" });
m_yesFootType = classif().GetTypeByPath(hwtagYesFoot);
AddAdditionalRoadTypes(classif(), {
{std::move(hwtagYesFoot), m_maxModelSpeed},
{{"route", "ferry"}, pedestrian_model::kDefaultSpeeds.Get(HighwayType::RouteFerry)},
{{"man_made", "pier"}, pedestrian_model::kDefaultSpeeds.Get(HighwayType::ManMadePier)}
});
if (type == m_yesFootType)
return ResultT::Yes;
else if (type == m_noFootType)
return ResultT::No;
return ResultT::Unknown;
}
VehicleModelInterface::RoadAvailability PedestrianModel::GetRoadAvailability(feature::TypesHolder const & types) const
SpeedKMpH PedestrianModel::GetSpeedForAvailable() const
{
if (types.Has(m_yesFootType))
return RoadAvailability::Available;
if (types.Has(m_noFootType))
return RoadAvailability::NotAvailable;
return RoadAvailability::Unknown;
return m_maxModelSpeed.m_inCity;
}
// If one of feature types will be disabled for pedestrian, features of this type will be simplyfied
@ -320,40 +145,41 @@ VehicleModelInterface::RoadAvailability PedestrianModel::GetRoadAvailability(fea
// static
PedestrianModel const & PedestrianModel::AllLimitsInstance()
{
static PedestrianModel const instance(pedestrian_model::kPedestrianOptionsAll);
static PedestrianModel const instance(pedestrian_model::kAllSpeeds);
return instance;
}
PedestrianModelFactory::PedestrianModelFactory(
CountryParentNameGetterFn const & countryParentNameGetterFn)
: VehicleModelFactory(countryParentNameGetterFn)
PedestrianModelFactory::PedestrianModelFactory(CountryParentNameGetterFn const & parentGetter)
: VehicleModelFactory(parentGetter)
{
using namespace pedestrian_model;
// Names must be the same with country names from countries.txt
m_models[""] = make_shared<PedestrianModel>(kPedestrianOptionsDefault);
m_models["Australia"] = make_shared<PedestrianModel>(kPedestrianOptionsAustralia);
m_models["Austria"] = make_shared<PedestrianModel>(kPedestrianOptionsAustria);
m_models["Belarus"] = make_shared<PedestrianModel>(kPedestrianOptionsBelarus);
m_models["Belgium"] = make_shared<PedestrianModel>(kPedestrianOptionsBelgium);
m_models["Brazil"] = make_shared<PedestrianModel>(kPedestrianOptionsBrazil);
m_models["Denmark"] = make_shared<PedestrianModel>(kPedestrianOptionsDenmark);
m_models["France"] = make_shared<PedestrianModel>(kPedestrianOptionsFrance);
m_models["Finland"] = make_shared<PedestrianModel>(kPedestrianOptionsFinland);
m_models["Germany"] = make_shared<PedestrianModel>(kPedestrianOptionsGermany);
m_models["Hungary"] = make_shared<PedestrianModel>(kPedestrianOptionsHungary);
m_models["Iceland"] = make_shared<PedestrianModel>(kPedestrianOptionsIceland);
m_models["Netherlands"] = make_shared<PedestrianModel>(kPedestrianOptionsNetherlands);
m_models["Norway"] = make_shared<PedestrianModel>(kPedestrianOptionsNorway);
m_models["Oman"] = make_shared<PedestrianModel>(kPedestrianOptionsOman);
m_models["Poland"] = make_shared<PedestrianModel>(kPedestrianOptionsPoland);
m_models["Romania"] = make_shared<PedestrianModel>(kPedestrianOptionsRomania);
m_models["Russian Federation"] = make_shared<PedestrianModel>(kPedestrianOptionsRussia);
m_models["Slovakia"] = make_shared<PedestrianModel>(kPedestrianOptionsSlovakia);
m_models["Spain"] = make_shared<PedestrianModel>(kPedestrianOptionsSpain);
m_models["Switzerland"] = make_shared<PedestrianModel>(kPedestrianOptionsSwitzerland);
m_models["Turkey"] = make_shared<PedestrianModel>(kPedestrianOptionsTurkey);
m_models["Ukraine"] = make_shared<PedestrianModel>(kPedestrianOptionsUkraine);
m_models["United Kingdom"] = make_shared<PedestrianModel>(kPedestrianOptionsUK);
m_models["United States of America"] = make_shared<PedestrianModel>(kPedestrianOptionsUS);
m_models[""].reset(new PedestrianModel(DefaultSpeeds()));
m_models["Australia"].reset(new PedestrianModel(kAllSpeeds));
m_models["Austria"].reset(new PedestrianModel(NoTrunk()));
m_models["Belarus"].reset(new PedestrianModel(AllowCycleway()));
m_models["Belgium"].reset(new PedestrianModel(BelgiumSpeeds()));
m_models["Brazil"].reset(new PedestrianModel(kAllSpeeds));
m_models["Denmark"].reset(new PedestrianModel(AllowCyclewayNoTrunk()));
m_models["France"].reset(new PedestrianModel(NoTrunk()));
m_models["Finland"].reset(new PedestrianModel(AllowCycleway()));
m_models["Germany"].reset(new PedestrianModel(DefaultSpeeds()));
m_models["Hungary"].reset(new PedestrianModel(NoTrunk()));
m_models["Iceland"].reset(new PedestrianModel(kAllSpeeds));
m_models["Netherlands"].reset(new PedestrianModel(AllowCyclewayNoTrunk()));
m_models["Norway"].reset(new PedestrianModel(kAllSpeeds));
m_models["Oman"].reset(new PedestrianModel(kAllSpeeds));
m_models["Poland"].reset(new PedestrianModel(NoTrunk()));
m_models["Romania"].reset(new PedestrianModel(NoTrunk()));
m_models["Russian Federation"].reset(new PedestrianModel(AllowCycleway()));
m_models["Slovakia"].reset(new PedestrianModel(NoTrunk()));
m_models["Spain"].reset(new PedestrianModel(NoTrunk()));
m_models["Switzerland"].reset(new PedestrianModel(NoTrunk()));
m_models["Turkey"].reset(new PedestrianModel(kAllSpeeds));
m_models["Ukraine"].reset(new PedestrianModel(NoTrunk()));
m_models["United Kingdom"].reset(new PedestrianModel(kAllSpeeds));
m_models["United States of America"].reset(new PedestrianModel(kAllSpeeds));
}
} // routing

View file

@ -7,23 +7,23 @@ namespace routing
class PedestrianModel : public VehicleModel
{
explicit PedestrianModel(HighwaySpeeds const & speeds);
friend class PedestrianModelFactory;
public:
PedestrianModel();
PedestrianModel(VehicleModel::LimitsInitList const & speedLimits);
/// VehicleModelInterface overrides:
SpeedKMpH GetSpeed(FeatureType & f, SpeedParams const & speedParams) const override;
bool IsOneWay(FeatureType &) const override { return false; }
SpeedKMpH const & GetOffroadSpeed() const override;
static PedestrianModel const & AllLimitsInstance();
/// @name VehicleModelInterface overrides
/// @{
SpeedKMpH GetOffroadSpeed() const override;
protected:
RoadAvailability GetRoadAvailability(feature::TypesHolder const & types) const override;
ResultT IsOneWay(uint32_t type) const override;
ResultT GetRoadAvailability(uint32_t type) const override;
SpeedKMpH GetSpeedForAvailable() const override;
/// @}
private:
void Init();
uint32_t m_noFootType = 0;
uint32_t m_yesFootType = 0;
};
@ -31,8 +31,7 @@ private:
class PedestrianModelFactory : public VehicleModelFactory
{
public:
// TODO: remove countryParentNameGetterFn default value after removing unused pedestrian routing
// from road_graph_router
PedestrianModelFactory(CountryParentNameGetterFn const & countryParentNameGetterFn = {});
explicit PedestrianModelFactory(CountryParentNameGetterFn const & parentGetter);
};
} // namespace routing

View file

@ -39,15 +39,12 @@ string GetRegionParent(string const & id)
template <typename VehicleModelType, typename VehicleModelFactoryType>
void TestVehicleModelDefault()
{
auto defaultVehicleModel = make_shared<VehicleModelType>();
VehicleModelFactoryType vehicleModelFactory = VehicleModelFactoryType(GetRegionParent);
// Use static_pointer_cast here because VehicleModelInterface do not have EqualsForTests method
shared_ptr<VehicleModelType> defaultVehicleModelForCountry = static_pointer_cast<VehicleModelType>(
vehicleModelFactory.GetVehicleModelForCountry("Nonexistent Country Name"));
TEST(defaultVehicleModel->EqualsForTests(*defaultVehicleModelForCountry),
("Vehicle model for nonexistent counry is not equal to default."));
VehicleModelFactoryType(GetRegionParent).GetVehicleModelForCountry("Nonexistent Country Name"));
TEST(VehicleModelType::AllLimitsInstance().EqualsForTests(*defaultVehicleModelForCountry),
("Vehicle model for nonexistent country is not equal to default."));
}
// DirectParent and IndirectParent tests require tested countries to have nondefault restriction
@ -55,17 +52,14 @@ void TestVehicleModelDefault()
template <typename VehicleModelType, typename VehicleModelFactoryType>
void TestHaveNondefaultRestrictionForSelectedCountry(string country)
{
auto defaultVehicleModel = make_shared<VehicleModelType>();
auto const & defaultVehicleModel = VehicleModelType::AllLimitsInstance();
VehicleModelFactoryType vehicleModelFactory = VehicleModelFactoryType(GetRegionParent);
shared_ptr<VehicleModelType> vehicleModelCountry =
static_pointer_cast<VehicleModelType>(vehicleModelFactory.GetVehicleModelForCountry(country));
TEST(!(vehicleModelCountry->EqualsForTests(*defaultVehicleModel)),
(country,
"has default model. It may be ok if traffic restrictions was changed. "
"If so, select other country for this and next test."));
TEST(!defaultVehicleModel.EqualsForTests(*vehicleModelCountry), (country));
}
template <typename VehicleModelType, typename VehicleModelFactoryType>

View file

@ -21,7 +21,7 @@ namespace vehicle_model_test
using namespace routing;
using namespace std;
HighwayBasedSpeeds const kDefaultSpeeds = {
HighwaySpeeds const kDefaultSpeeds = {
{HighwayType::HighwayTrunk, InOutCitySpeedKMpH(100.0 /* in city */, 150.0 /* out city */)},
{HighwayType::HighwayPrimary, InOutCitySpeedKMpH(90.0 /* in city */, 120.0 /* out city */)},
{HighwayType::HighwaySecondary,
@ -31,25 +31,24 @@ HighwayBasedSpeeds const kDefaultSpeeds = {
SpeedKMpH(50.0 /* weight */, 60.0 /* eta */) /* out city */)},
{HighwayType::HighwayService,
InOutCitySpeedKMpH(SpeedKMpH(47.0 /* weight */, 36.0 /* eta */) /* in city */,
SpeedKMpH(50.0 /* weight */, 40.0 /* eta */) /* out city */)}};
SpeedKMpH(50.0 /* weight */, 40.0 /* eta */) /* out city */)}
};
HighwayBasedFactors const kDefaultFactors = {
HighwayFactors const kDefaultFactors = {
{HighwayType::HighwayTrunk, InOutCityFactor(1.0)},
{HighwayType::HighwayPrimary, InOutCityFactor(1.0)},
{HighwayType::HighwaySecondary, InOutCityFactor(1.0)},
{HighwayType::HighwayResidential, InOutCityFactor(0.5)}};
{HighwayType::HighwayResidential, InOutCityFactor(0.5)}
};
VehicleModel::LimitsInitList const kTestLimits = {{{"highway", "trunk"}, true},
{{"highway", "primary"}, true},
{{"highway", "secondary"}, true},
{{"highway", "residential"}, true},
{{"highway", "service"}, false}};
NoPassThroughHighways const kTestLimits = {HighwayType::HighwayService};
VehicleModel::SurfaceInitList const kCarSurface = {
{{"psurface", "paved_good"}, {0.8 /* weightFactor */, 0.9 /* etaFactor */}},
{{"psurface", "paved_bad"}, {0.4, 0.5}},
{{"psurface", "unpaved_good"}, {0.6, 0.8}},
{{"psurface", "unpaved_bad"}, {0.2, 0.2}}};
SurfaceFactors const kCarSurface = {
{SurfaceType::PavedGood, {0.8 /* weightFactor */, 0.9 /* etaFactor */}},
{SurfaceType::PavedBad, {0.4, 0.5}},
{SurfaceType::UnpavedGood, {0.6, 0.8}},
{SurfaceType::UnpavedBad, {0.2, 0.2}}
};
class VehicleModelTest
{
@ -62,23 +61,42 @@ class TestVehicleModel : public VehicleModel
friend void CheckOneWay(initializer_list<uint32_t> const & types, bool expectedValue);
friend void CheckPassThroughAllowed(initializer_list<uint32_t> const & types, bool expectedValue);
friend void CheckSpeedWithParams(initializer_list<uint32_t> const & types,
SpeedParams const & params, SpeedKMpH const & expectedSpeed);
Request const & request, SpeedKMpH const & expectedSpeed);
public:
TestVehicleModel()
: VehicleModel(classif(), kTestLimits, kCarSurface, {kDefaultSpeeds, kDefaultFactors})
: VehicleModel(kDefaultSpeeds, kDefaultFactors, kCarSurface, kTestLimits)
{
m_oneway = classif().GetTypeByPath({"hwtag", "oneway"});
}
// We are not going to use offroad routing in these tests.
SpeedKMpH const & GetOffroadSpeed() const override { return kDummy; }
SpeedKMpH GetOffroadSpeed() const override { return kDummy; }
protected:
ResultT IsOneWay(uint32_t type) const override
{
if (type == m_oneway)
return ResultT::Yes;
return ResultT::Unknown;
}
ResultT GetRoadAvailability(uint32_t type) const override
{
return ResultT::Unknown;
}
SpeedKMpH GetSpeedForAvailable() const override
{
TEST(false, ());
return kDummy;
}
private:
static SpeedKMpH const kDummy;
uint32_t m_oneway;
SpeedKMpH const kDummy = {0.0 /* weight */, 0.0 /* eta */};
};
SpeedKMpH const TestVehicleModel::kDummy = {0.0 /* weight */, 0.0 /* eta */};
uint32_t GetType(char const * s0, char const * s1 = 0, char const * s2 = 0)
{
char const * const t[] = {s0, s1, s2};
@ -91,23 +109,24 @@ uint32_t GetOnewayType()
return GetType("hwtag", "oneway");
}
void CheckSpeedWithParams(initializer_list<uint32_t> const & types, SpeedParams const & params,
SpeedKMpH const & expectedSpeed)
void CheckSpeedWithParams(initializer_list<uint32_t> const & types, VehicleModel::Request const & request,
SpeedKMpH const & expectedForward, SpeedKMpH const & expectedBackward = {})
{
TestVehicleModel vehicleModel;
feature::TypesHolder h;
for (uint32_t t : types)
h.Add(t);
TEST_EQUAL(vehicleModel.GetTypeSpeed(h, params), expectedSpeed, ());
auto const response = vehicleModel.GetFeatureInfo(h, request);
TEST_EQUAL(response.m_forwardSpeed, expectedForward, ());
if (expectedBackward.IsValid())
TEST_EQUAL(response.m_backwardSpeed, expectedBackward, ());
}
void CheckSpeed(initializer_list<uint32_t> const & types, InOutCitySpeedKMpH const & expectedSpeed)
{
SpeedParams const inCity(true /* forward */, true /* in city */, Maxspeed());
CheckSpeedWithParams(types, inCity, expectedSpeed.m_inCity);
SpeedParams const outCity(true /* forward */, false /* in city */, Maxspeed());
CheckSpeedWithParams(types, outCity, expectedSpeed.m_outCity);
CheckSpeedWithParams(types, {Maxspeed(), true /* in city */}, expectedSpeed.m_inCity);
CheckSpeedWithParams(types, {Maxspeed(), false /* in city */}, expectedSpeed.m_outCity);
}
void CheckOneWay(initializer_list<uint32_t> const & types, bool expectedValue)
@ -117,7 +136,8 @@ void CheckOneWay(initializer_list<uint32_t> const & types, bool expectedValue)
for (uint32_t t : types)
h.Add(t);
TEST_EQUAL(vehicleModel.HasOneWayType(h), expectedValue, ());
auto const response = vehicleModel.GetFeatureInfo(h, {});
TEST_EQUAL(response.m_isOneWay, expectedValue, ());
}
void CheckPassThroughAllowed(initializer_list<uint32_t> const & types, bool expectedValue)
@ -127,7 +147,8 @@ void CheckPassThroughAllowed(initializer_list<uint32_t> const & types, bool expe
for (uint32_t t : types)
h.Add(t);
TEST_EQUAL(vehicleModel.HasPassThroughType(h), expectedValue, ());
auto const response = vehicleModel.GetFeatureInfo(h, {});
TEST_EQUAL(response.m_isPassThroughAllowed, expectedValue, ());
}
@ -140,9 +161,9 @@ UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_MaxSpeed)
UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_Speed)
{
{
CheckSpeed({GetType("highway", "secondary", "bridge")}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
CheckSpeed({GetType("highway", "secondary", "tunnel")}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
CheckSpeed({GetType("highway", "secondary")}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
CheckSpeed({GetType("highway", "secondary", "bridge")}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
CheckSpeed({GetType("highway", "secondary", "tunnel")}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
CheckSpeed({GetType("highway", "secondary")}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
}
CheckSpeed({GetType("highway", "trunk")},
@ -158,9 +179,9 @@ UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_Speed_MultiTypes)
uint32_t const typeSecondary = GetType("highway", "secondary");
uint32_t const typeHighway = GetType("highway");
CheckSpeed({typeTunnel, typeSecondary}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
CheckSpeed({typeTunnel, typeHighway}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
CheckSpeed({typeHighway, typeTunnel}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
CheckSpeed({typeTunnel, typeSecondary}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
CheckSpeed({typeTunnel, typeHighway}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
CheckSpeed({typeHighway, typeTunnel}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
}
UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_OneWay)
@ -168,9 +189,9 @@ UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_OneWay)
uint32_t const typeBridge = GetType("highway", "secondary", "bridge");
uint32_t const typeOneway = GetOnewayType();
CheckSpeed({typeBridge, typeOneway}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
CheckSpeed({typeBridge, typeOneway}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
CheckOneWay({typeBridge, typeOneway}, true);
CheckSpeed({typeOneway, typeBridge}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
CheckSpeed({typeOneway, typeBridge}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
CheckOneWay({typeOneway, typeBridge}, true);
CheckOneWay({typeOneway}, true);
@ -182,9 +203,9 @@ UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_DifferentSpeeds)
uint32_t const typePrimary = GetType("highway", "primary");
uint32_t const typeOneway = GetOnewayType();
CheckSpeed({typeSecondary, typePrimary}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
CheckSpeed({typeSecondary, typePrimary}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
CheckSpeed({typeSecondary, typePrimary, typeOneway}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
CheckSpeed({typeSecondary, typePrimary, typeOneway}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
CheckOneWay({typePrimary, typeOneway, typeSecondary}, true);
}
@ -228,26 +249,23 @@ UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_MaxspeedFactor)
Maxspeed const maxspeed90 =
Maxspeed(measurement_utils::Units::Metric, 90 /* forward speed */, kInvalidSpeed);
CheckSpeedWithParams({secondary, unpavedBad},
SpeedParams(true /* forward */, false /* in city */, maxspeed90),
{maxspeed90, false /* in city */},
SpeedKMpH(18.0));
CheckSpeedWithParams({primary, pavedGood},
SpeedParams(true /* forward */, false /* in city */, maxspeed90),
{maxspeed90, false /* in city */},
SpeedKMpH(72.0, 81.0));
Maxspeed const maxspeed9070 =
Maxspeed(measurement_utils::Units::Metric, 90 /* forward speed */, 70);
Maxspeed(measurement_utils::Units::Metric, 90 /* forward speed */, 70 /* backward speed */);
CheckSpeedWithParams({primary, pavedGood},
SpeedParams(true /* forward */, false /* in city */, maxspeed9070),
SpeedKMpH(72.0, 81.0));
CheckSpeedWithParams({primary, pavedGood},
SpeedParams(false /* forward */, false /* in city */, maxspeed9070),
SpeedKMpH(56.0, 63.0));
{maxspeed9070, false},
SpeedKMpH(72.0, 81.0), SpeedKMpH(56.0, 63.0));
Maxspeed const maxspeed60 =
Maxspeed(measurement_utils::Units::Metric, 60 /* forward speed */, kInvalidSpeed);
Maxspeed(measurement_utils::Units::Metric, 60 /* forward speed */, kInvalidSpeed /* backward speed */);
CheckSpeedWithParams({residential, pavedGood},
SpeedParams(true /* forward */, false /* in city */, maxspeed60),
{maxspeed60, false /* in city */},
SpeedKMpH(24.0, 27.0));
}
@ -279,13 +297,11 @@ UNIT_TEST(VehicleModel_CarModelValidation)
for (auto const hwType : carRoadTypes)
{
auto const * factor = kHighwayBasedFactors.Find(hwType);
TEST(factor, (hwType));
TEST(factor->IsValid(), (hwType, *factor));
auto const factor = kHighwayBasedFactors.at(hwType);
TEST(factor.IsValid(), ());
auto const * speed = kHighwayBasedSpeeds.Find(hwType);
TEST(speed, (hwType));
TEST(speed->IsValid(), (hwType, *speed));
auto const speed = kHighwayBasedSpeeds.at(hwType);
TEST(speed.IsValid(), ());
}
}
} // namespace vehicle_model_test

View file

@ -12,115 +12,140 @@
#include <algorithm>
#include <sstream>
using namespace routing;
namespace routing
{
using namespace std;
namespace
{
template <double const & (*F)(double const &, double const &), typename WeightAndETA>
WeightAndETA Pick(WeightAndETA const & lhs, WeightAndETA const & rhs)
{
return {F(lhs.m_weight, rhs.m_weight), F(lhs.m_eta, rhs.m_eta)};
};
}
InOutCitySpeedKMpH Max(InOutCitySpeedKMpH const & lhs, InOutCitySpeedKMpH const & rhs)
{
return {Pick<max>(lhs.m_inCity, rhs.m_inCity), Pick<max>(lhs.m_outCity, rhs.m_outCity)};
}
/// @todo This function is used to to get key to fetch speed factor from model,
/// but we assign factors for links too. @see kHighwayBasedFactors.
HighwayType GetHighwayTypeKey(HighwayType type)
VehicleModel::VehicleModel(HighwaySpeeds const & speeds, HighwayFactors const & factors,
SurfaceFactors const & surfaces, NoPassThroughHighways const & noPassThrough)
{
switch (type)
m_surfaceFactors.Reserve(surfaces.size());
for (auto const & e : surfaces)
{
case HighwayType::HighwayMotorwayLink: return HighwayType::HighwayMotorway;
case HighwayType::HighwayTrunkLink: return HighwayType::HighwayTrunk;
case HighwayType::HighwayPrimaryLink: return HighwayType::HighwayPrimary;
case HighwayType::HighwaySecondaryLink: return HighwayType::HighwaySecondary;
case HighwayType::HighwayTertiaryLink: return HighwayType::HighwayTertiary;
default: return type;
ASSERT(e.second.IsValid(), ());
m_surfaceFactors.Insert(static_cast<uint32_t>(e.first), e.second);
}
}
} // namespace
namespace routing
{
VehicleModel::VehicleModel(Classificator const & classif, LimitsInitList const & featureTypeLimits,
SurfaceInitList const & featureTypeSurface, HighwayBasedInfo const & info)
: m_highwayBasedInfo(info), m_onewayType(classif.GetTypeByPath({"hwtag", "oneway"}))
{
m_roadTypes.Reserve(featureTypeLimits.size());
for (auto const & v : featureTypeLimits)
m_highwayInfo.Reserve(speeds.size());
for (auto const & e : speeds)
{
auto const clType = classif.GetTypeByPath(v.m_type);
auto const hwType = static_cast<HighwayType>(classif.GetIndexForType(clType));
auto const * speed = info.m_speeds.Find(hwType);
ASSERT(speed, ("Can't found speed for", hwType));
ASSERT(e.second.IsValid(), ());
/// @todo Consider using not only highway class speed but max_speed * max_speed_factor.
m_maxModelSpeed = Max(m_maxModelSpeed, *speed);
m_roadTypes.Insert(clType, v.m_isPassThroughAllowed);
}
m_roadTypes.FinishBuilding();
Info info;
info.m_speed = e.second;
m_surfaceFactors.Reserve(featureTypeSurface.size());
for (auto const & v : featureTypeSurface)
{
auto const & speedFactor = v.m_factor;
ASSERT_LESS_OR_EQUAL(speedFactor.m_weight, 1.0, ());
ASSERT_LESS_OR_EQUAL(speedFactor.m_eta, 1.0, ());
ASSERT_GREATER(speedFactor.m_weight, 0.0, ());
ASSERT_GREATER(speedFactor.m_eta, 0.0, ());
m_surfaceFactors.Insert(classif.GetTypeByPath(v.m_type), v.m_factor);
auto const itFactor = factors.find(e.first);
if (itFactor != factors.end())
info.m_factor = itFactor->second;
if (noPassThrough.count(e.first) > 0)
info.m_isPassThroughAllowed = false;
m_highwayInfo.Insert(static_cast<uint32_t>(e.first), info);
m_maxModelSpeed = Max(m_maxModelSpeed, info.m_speed);
}
m_highwayInfo.FinishBuilding();
}
void VehicleModel::AddAdditionalRoadTypes(Classificator const & classif, AdditionalRoadsList const & roads)
VehicleModel::Response VehicleModel::GetFeatureInfo(FeatureType & ft, Request const & request) const
{
for (auto const & r : roads)
return GetFeatureInfo(feature::TypesHolder(ft), request);
}
bool VehicleModel::HasRoadType(FeatureType & ft) const
{
return HasRoadType(feature::TypesHolder(ft));
}
bool VehicleModel::IsOneWay(FeatureType & ft) const
{
for (uint32_t type : feature::TypesHolder(ft))
{
uint32_t const type = classif.GetTypeByPath(r.m_type);
if (m_roadTypes.Find(type) == nullptr)
NormalizeType(type);
if (IsOneWay(type) == ResultT::Yes)
return true;
}
return false;
}
VehicleModel::Response VehicleModel::GetFeatureInfo(feature::TypesHolder const & types,
Request const & request) const
{
Response response;
SpeedFactor surface;
Info const * info = nullptr;
for (uint32_t type : types)
{
switch (GetRoadAvailability(type))
{
m_addRoadTypes.Insert(type, r.m_speed);
m_maxModelSpeed = Max(m_maxModelSpeed, r.m_speed);
case ResultT::Yes:
response.m_isValid = true;
continue;
case ResultT::No:
response.m_isValid = false;
return response;
}
switch (IsOneWay(type))
{
case ResultT::Yes:
response.m_isOneWay = true;
continue;
case ResultT::No:
response.m_isOneWay = false;
continue;
}
auto const * sf = m_surfaceFactors.Find(type);
if (sf)
{
surface = Pick<min>(*sf, surface);
continue;
}
NormalizeType(type);
if (info == nullptr)
{
info = m_highwayInfo.Find(type);
if (info)
{
response.m_highwayType = static_cast<HighwayType>(type);
response.m_isValid = true;
response.m_isPassThroughAllowed = info->m_isPassThroughAllowed;
}
}
}
}
uint32_t VehicleModel::PrepareToMatchType(uint32_t type)
{
return ftypes::BaseChecker::PrepareToMatch(type, 2);
}
if (!response.m_isValid)
return response;
SpeedKMpH VehicleModel::GetSpeed(FeatureType & f, SpeedParams const & speedParams) const
{
feature::TypesHolder const types(f);
RoadAvailability const restriction = GetRoadAvailability(types);
if (restriction == RoadAvailability::NotAvailable || !HasRoadType(types))
return {};
return GetTypeSpeed(types, speedParams);
}
HighwayType VehicleModel::GetHighwayType(FeatureType & f) const
{
feature::TypesHolder const types(f);
for (auto const t : types)
if (info == nullptr)
{
auto const ret = GetHighwayType(t);
if (ret)
return *ret;
// LOG(LWARNING, ("Model doesn't have HighwayType entry, but hwtag=yes.",
// ft.DebugString(FeatureType::BEST_GEOMETRY)));
if (m_addRoadTypes.Find(t))
return static_cast<HighwayType>(classif().GetIndexForType(t));
response.m_isPassThroughAllowed = true;
}
UNREACHABLE();
return HighwayType::HighwayResidential;
response.m_forwardSpeed = GetSpeed(info, request.m_speed.GetSpeedKmPH(true), request.m_inCity) * surface;
response.m_backwardSpeed = GetSpeed(info, request.m_speed.GetSpeedKmPH(false), request.m_inCity) * surface;
return response;
}
double VehicleModel::GetMaxWeightSpeed() const
@ -128,186 +153,53 @@ double VehicleModel::GetMaxWeightSpeed() const
return max(m_maxModelSpeed.m_inCity.m_weight, m_maxModelSpeed.m_outCity.m_weight);
}
optional<HighwayType> VehicleModel::GetHighwayType(uint32_t type) const
void VehicleModel::NormalizeType(uint32_t type) const
{
type = PrepareToMatchType(type);
auto const * value = m_roadTypes.Find(type);
if (value)
return static_cast<HighwayType>(classif().GetIndexForType(type));
return {};
// The only exception that has 3-arity type.
if (type != static_cast<uint32_t>(HighwayType::RailwayRailMotorVehicle))
ftype::TruncValue(type, 2);
}
void VehicleModel::GetSurfaceFactor(uint32_t type, SpeedFactor & factor) const
SpeedKMpH VehicleModel::GetSpeed(Info const * info, MaxspeedType ftMaxSpeed, bool inCity) const
{
auto const * surface = m_surfaceFactors.Find(type);
if (surface)
factor = Pick<min>(factor, *surface);
auto const maxModelSpeed = m_maxModelSpeed.GetSpeed(inCity);
auto const factor = info ? info->m_factor.GetFactor(inCity) : 1.0;
ASSERT_LESS_OR_EQUAL(factor.m_weight, 1.0, ());
ASSERT_LESS_OR_EQUAL(factor.m_eta, 1.0, ());
ASSERT_GREATER(factor.m_weight, 0.0, ());
ASSERT_GREATER(factor.m_eta, 0.0, ());
}
void VehicleModel::GetAdditionalRoadSpeed(uint32_t type, bool isCityRoad,
optional<SpeedKMpH> & speed) const
{
auto const * s = m_addRoadTypes.Find(type);
if (s)
if (ftMaxSpeed != kInvalidSpeed)
{
auto const & res = isCityRoad ? s->m_inCity : s->m_outCity;
speed = speed ? Pick<min>(*speed, res) : res;
return Pick<min>(SpeedKMpH(static_cast<double>(ftMaxSpeed)) * factor, maxModelSpeed);
}
else if (info)
{
SpeedKMpH const speed = info->m_speed.GetSpeed(inCity);
/// @todo Hm, well this is not obvious for me and should be revised.
// Predefined model speeds are taken from the former code and should not be multiplied with the factor.
// On the contrary, ETA speed should be multiplied.
return SpeedKMpH(min(speed.m_weight, maxModelSpeed.m_weight),
min(factor.m_eta * speed.m_eta, maxModelSpeed.m_eta));
}
else
{
return GetSpeedForAvailable();
}
}
SpeedKMpH VehicleModel::GetSpeedOnFeatureWithMaxspeed(HighwayType const & type,
SpeedParams const & speedParams) const
{
ASSERT(speedParams.m_maxspeed.IsValid(), ());
auto const featureMaxSpeedKmPH = speedParams.m_maxspeed.GetSpeedKmPH(speedParams.m_forward);
ASSERT(featureMaxSpeedKmPH != kInvalidSpeed, (type, speedParams.m_forward, speedParams.m_maxspeed));
auto const typeKey = GetHighwayTypeKey(type);
auto const * factor = m_highwayBasedInfo.m_factors.Find(typeKey);
ASSERT(factor, ("Key:", typeKey, "is not found."));
bool const isCityRoad = speedParams.m_inCity;
return Pick<min>(SpeedKMpH(static_cast<double>(featureMaxSpeedKmPH)) * factor->GetFactor(isCityRoad),
m_maxModelSpeed.GetSpeed(isCityRoad));
}
SpeedKMpH VehicleModel::GetSpeedOnFeatureWithoutMaxspeed(HighwayType const & type,
SpeedParams const & speedParams) const
{
ASSERT(!speedParams.m_maxspeed.IsValid(), ());
auto const * s = m_highwayBasedInfo.m_speeds.Find(type);
ASSERT(s, ("Key:", type, "is not found."));
auto const typeKey = GetHighwayTypeKey(type);
auto const * factor = m_highwayBasedInfo.m_factors.Find(typeKey);
ASSERT(factor, ("Key:", typeKey, "is not found."));
auto const isCityRoad = speedParams.m_inCity;
SpeedKMpH const speed = s->GetSpeed(isCityRoad);
ASSERT(speed.IsValid(), (speed));
SpeedKMpH const & maxModelSpeed = m_maxModelSpeed.GetSpeed(isCityRoad);
/// @todo Hm, well this is not obvious for me and should be revised.
// Speeds from the m_highwayBasedInfo are taken from the former code and should not
// be multiplied to the factor. On the contrary, ETA speed should be multiplied.
return SpeedKMpH(
min(speed.m_weight, maxModelSpeed.m_weight),
min(factor->GetFactor(isCityRoad).m_eta * speed.m_eta, maxModelSpeed.m_eta));
}
SpeedKMpH VehicleModel::GetTypeSpeed(feature::TypesHolder const & types,
SpeedParams const & speedParams) const
{
bool const isCityRoad = speedParams.m_inCity;
optional<HighwayType> hwType;
SpeedFactor surfaceFactor;
optional<SpeedKMpH> additionalRoadSpeed;
for (uint32_t t : types)
{
if (!hwType)
hwType = GetHighwayType(t);
GetSurfaceFactor(t, surfaceFactor);
GetAdditionalRoadSpeed(t, isCityRoad, additionalRoadSpeed);
}
if (additionalRoadSpeed)
return *additionalRoadSpeed * surfaceFactor;
ASSERT(hwType, ());
auto const resultHwType = *hwType;
if (speedParams.m_maxspeed.IsValid())
return GetSpeedOnFeatureWithMaxspeed(resultHwType, speedParams) * surfaceFactor;
return GetSpeedOnFeatureWithoutMaxspeed(resultHwType, speedParams) * surfaceFactor;
}
SpeedKMpH VehicleModel::GetSpeedWihtoutMaxspeed(FeatureType & f,
SpeedParams const & speedParams) const
{
return VehicleModel::GetSpeed(f, {speedParams.m_forward, speedParams.m_inCity, Maxspeed()});
}
bool VehicleModel::IsOneWay(FeatureType & f) const
{
return HasOneWayType(feature::TypesHolder(f));
}
bool VehicleModel::HasOneWayType(feature::TypesHolder const & types) const
{
return types.Has(m_onewayType);
}
bool VehicleModel::IsRoad(FeatureType & f) const
{
if (f.GetGeomType() != feature::GeomType::Line)
return false;
feature::TypesHolder const types(f);
if (GetRoadAvailability(types) == RoadAvailability::NotAvailable)
return false;
return HasRoadType(types);
}
bool VehicleModel::IsPassThroughAllowed(FeatureType & f) const
{
feature::TypesHolder const types(f);
// Allow pass through additional road types e.g. peer, ferry.
for (uint32_t t : types)
{
if (m_addRoadTypes.Find(t))
return true;
}
return HasPassThroughType(types);
}
bool VehicleModel::HasPassThroughType(feature::TypesHolder const & types) const
{
for (uint32_t const t : types)
{
bool const * allow = m_roadTypes.Find(PrepareToMatchType(t));
if (allow && *allow)
return true;
}
return false;
}
bool VehicleModel::IsRoadType(uint32_t type) const
{
return m_addRoadTypes.Find(type) || m_roadTypes.Find(PrepareToMatchType(type));
}
VehicleModelInterface::RoadAvailability VehicleModel::GetRoadAvailability(feature::TypesHolder const &) const
{
return RoadAvailability::Unknown;
}
VehicleModelFactory::VehicleModelFactory(
CountryParentNameGetterFn const & countryParentNameGetterFn)
VehicleModelFactory::VehicleModelFactory(CountryParentNameGetterFn const & countryParentNameGetterFn)
: m_countryParentNameGetterFn(countryParentNameGetterFn)
{
}
shared_ptr<VehicleModelInterface> VehicleModelFactory::GetVehicleModel() const
{
auto const itr = m_models.find("");
ASSERT(itr != m_models.end(), ("No default vehicle model. VehicleModelFactory was not "
"properly constructed"));
return itr->second;
auto const it = m_models.find("");
CHECK(it != m_models.end(), ());
return it->second;
}
shared_ptr<VehicleModelInterface> VehicleModelFactory::GetVehicleModelForCountry(
string const & country) const
shared_ptr<VehicleModelInterface>
VehicleModelFactory::GetVehicleModelForCountry(string const & country) const
{
string parent = country;
while (!parent.empty())
@ -329,9 +221,9 @@ string VehicleModelFactory::GetParent(string const & country) const
return m_countryParentNameGetterFn(country);
}
HighwayBasedFactors GetOneFactorsForBicycleAndPedestrianModel()
HighwayFactors GetOneFactorsForBicycleAndPedestrianModel()
{
return HighwayBasedFactors{
return {
{HighwayType::HighwayTrunk, InOutCityFactor(1.0)},
{HighwayType::HighwayTrunkLink, InOutCityFactor(1.0)},
{HighwayType::HighwayPrimary, InOutCityFactor(1.0)},
@ -357,18 +249,6 @@ HighwayBasedFactors GetOneFactorsForBicycleAndPedestrianModel()
};
}
string DebugPrint(VehicleModelInterface::RoadAvailability const l)
{
switch (l)
{
case VehicleModelInterface::RoadAvailability::Available: return "Available";
case VehicleModelInterface::RoadAvailability::NotAvailable: return "NotAvailable";
case VehicleModelInterface::RoadAvailability::Unknown: return "Unknown";
}
UNREACHABLE();
}
string DebugPrint(SpeedKMpH const & speed)
{
ostringstream oss;

View file

@ -5,34 +5,26 @@
#include "base/small_map.hpp"
#include "base/stl_helpers.hpp"
#include <array>
#include <cstdint>
#include <functional>
#include <initializer_list>
#include <limits>
#include <memory>
#include <optional>
#include <sstream>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
class Classificator;
class FeatureType;
namespace feature { class TypesHolder; }
class FeatureType;
namespace routing
{
double constexpr kNotUsed = std::numeric_limits<double>::max();
struct InOutCityFactor;
struct InOutCitySpeedKMpH;
// Each value is equal to the corresponding type index from types.txt.
// The ascending order is strict. Check for static_cast<HighwayType> in vehicle_model.cpp
enum class HighwayType : uint32_t
// Check for static_cast<HighwayType> in vehicle_model.cpp
enum class HighwayType : uint16_t
{
HighwayResidential = 1,
HighwayService = 2,
@ -62,22 +54,14 @@ enum class HighwayType : uint32_t
RouteShuttleTrain = 1054,
};
using HighwayBasedFactors = base::SmallMap<HighwayType, InOutCityFactor>;
using HighwayBasedSpeeds = base::SmallMap<HighwayType, InOutCitySpeedKMpH>;
/// \brief Params for calculation of an approximate speed on a feature.
struct SpeedParams
// Each value is equal to the corresponding type index from types.txt.
// Check for static_cast<SurfaceType> in vehicle_model.cpp
enum class SurfaceType : uint16_t
{
SpeedParams(bool forward, bool inCity, Maxspeed const & maxspeed)
: m_maxspeed(maxspeed), m_forward(forward), m_inCity(inCity)
{
}
Maxspeed m_maxspeed;
// Retrieve forward (true) or backward (false) speed.
bool m_forward;
// If a corresponding feature lies inside a city of a town.
bool m_inCity;
PavedGood = 1116,
PavedBad = 1117,
UnpavedGood = 1118,
UnpavedBad = 1119,
};
/// \brief Speeds which are used for edge weight and ETA estimations.
@ -99,8 +83,8 @@ struct SpeedKMpH
double m_eta = 0.0; // KMpH
};
/// \brief Factors which modify weight and ETA speed on feature in case of bad pavement (reduce)
/// or good highway class (increase).
/// \brief Factors which modify weight and ETA speed on feature in case of
/// bad pavement (reduce) or good highway class (increase).
/// Both should be greater then 0.
struct SpeedFactor
{
@ -156,6 +140,7 @@ struct InOutCitySpeedKMpH
struct InOutCityFactor
{
constexpr InOutCityFactor() = default;
constexpr explicit InOutCityFactor(SpeedFactor const & factor) noexcept
: m_inCity(factor), m_outCity(factor)
{
@ -177,37 +162,39 @@ struct InOutCityFactor
SpeedFactor m_outCity;
};
struct HighwayBasedInfo
{
HighwayBasedInfo(HighwayBasedSpeeds const & speeds, HighwayBasedFactors const & factors)
: m_speeds(speeds)
, m_factors(factors)
{
}
using HighwaySpeeds = std::unordered_map<HighwayType, InOutCitySpeedKMpH>;
using HighwayFactors = std::unordered_map<HighwayType, InOutCityFactor>;
using SurfaceFactors = std::unordered_map<SurfaceType, SpeedFactor>;
using NoPassThroughHighways = std::unordered_set<HighwayType>;
HighwayBasedSpeeds const & m_speeds;
HighwayBasedFactors const & m_factors;
};
class VehicleModelInterface
{
public:
enum class RoadAvailability
{
NotAvailable,
Available,
Unknown,
};
virtual ~VehicleModelInterface() = default;
/// @return Allowed weight and ETA speed in KMpH.
/// 0 means that it's forbidden to move on this feature or it's not a road at all.
/// Weight and ETA should be less than max model speed's values respectively.
/// @param inCity is true if |f| lies in a city of town.
virtual SpeedKMpH GetSpeed(FeatureType & f, SpeedParams const & speedParams) const = 0;
struct Request
{
Maxspeed m_speed;
bool m_inCity;
};
struct Response
{
SpeedKMpH m_forwardSpeed, m_backwardSpeed;
virtual HighwayType GetHighwayType(FeatureType & f) const = 0;
// Highway type can be null, but m_isValid == true if Feature has hwtype=yes*
// without any recognizable highway classifier type in it.
std::optional<HighwayType> m_highwayType;
bool m_isValid = false;
bool m_isOneWay;
bool m_isPassThroughAllowed;
};
virtual Response GetFeatureInfo(FeatureType & ft, Request const & request) const = 0;
/// @todo Remove after proper FeaturesRoadGraph refactoring.
virtual bool HasRoadType(FeatureType & ft) const = 0;
virtual bool IsOneWay(FeatureType & ft) const = 0;
/// @return Maximum model weight speed.
/// All speeds which the model returns must be less than or equal to this speed.
@ -215,20 +202,7 @@ public:
/// @return Offroad speed in KMpH for vehicle. This speed should be used for non-feature routing
/// e.g. to connect start point to nearest feature.
virtual SpeedKMpH const & GetOffroadSpeed() const = 0;
virtual bool IsOneWay(FeatureType & f) const = 0;
/// @returns true iff feature |f| can be used for routing with corresponding vehicle model.
virtual bool IsRoad(FeatureType & f) const = 0;
/// @returns true iff feature |f| can be used for through passage with corresponding vehicle model.
/// e.g. in Russia roads tagged "highway = service" are not allowed for through passage;
/// however, road with this tag can be be used if it is close enough to the start or destination
/// point of the route.
/// Roads with additional types e.g. "path = ferry", "vehicle_type = yes" considered as allowed
/// to pass through.
virtual bool IsPassThroughAllowed(FeatureType & f) const = 0;
virtual SpeedKMpH GetOffroadSpeed() const = 0;
};
class VehicleModelFactoryInterface
@ -239,7 +213,7 @@ public:
/// but it may be non optimal for some countries
virtual std::shared_ptr<VehicleModelInterface> GetVehicleModel() const = 0;
/// @return The most optimal vehicle model for specified country
/// @return The most optimal vehicle model for specified \a country
virtual std::shared_ptr<VehicleModelInterface> GetVehicleModelForCountry(
std::string const & country) const = 0;
};
@ -247,51 +221,27 @@ public:
class VehicleModel : public VehicleModelInterface
{
public:
struct FeatureTypeLimits
{
std::vector<std::string> m_type;
bool m_isPassThroughAllowed; // pass through this road type is allowed
};
struct FeatureTypeSurface
{
std::vector<std::string> m_type; // road surface type 'psurface=*'
SpeedFactor m_factor;
};
struct AdditionalRoad
{
std::vector<std::string> m_type;
InOutCitySpeedKMpH m_speed;
};
using AdditionalRoadsList = std::initializer_list<AdditionalRoad>;
using LimitsInitList = std::initializer_list<FeatureTypeLimits>;
using SurfaceInitList = std::initializer_list<FeatureTypeSurface>;
VehicleModel(Classificator const & classif, LimitsInitList const & featureTypeLimits,
SurfaceInitList const & featureTypeSurface, HighwayBasedInfo const & info);
VehicleModel(HighwaySpeeds const & speeds, HighwayFactors const & factors,
SurfaceFactors const & surfaces, NoPassThroughHighways const & noPassThrough = {});
/// @name VehicleModelInterface overrides.
/// @{
SpeedKMpH GetSpeed(FeatureType & f, SpeedParams const & speedParams) const override;
HighwayType GetHighwayType(FeatureType & f) const override;
Response GetFeatureInfo(FeatureType & ft, Request const & request) const override;
bool HasRoadType(FeatureType & ft) const override;
bool IsOneWay(FeatureType & ft) const override;
double GetMaxWeightSpeed() const override;
bool IsOneWay(FeatureType & f) const override;
bool IsRoad(FeatureType & f) const override;
bool IsPassThroughAllowed(FeatureType & f) const override;
/// @}
public:
/// @returns true if |m_highwayTypes| or |m_addRoadTypes| contains |type| and false otherwise.
bool IsRoadType(uint32_t type) const;
Response GetFeatureInfo(feature::TypesHolder const & types, Request const & request) const;
template <class TList>
bool HasRoadType(TList const & types) const
template <class ContT> bool HasRoadType(ContT const & types) const
{
for (uint32_t t : types)
for (uint32_t type : types)
{
if (IsRoadType(t))
NormalizeType(type);
if (m_highwayInfo.Find(type))
return true;
}
return false;
@ -299,57 +249,50 @@ public:
bool EqualsForTests(VehicleModel const & rhs) const
{
return (m_roadTypes == rhs.m_roadTypes) && (m_addRoadTypes == rhs.m_addRoadTypes) &&
(m_onewayType == rhs.m_onewayType);
return (m_highwayInfo == rhs.m_highwayInfo && m_highwayInfo == rhs.m_highwayInfo &&
m_maxModelSpeed == rhs.m_maxModelSpeed);
}
protected:
/// @returns a special restriction which is set to the feature.
virtual RoadAvailability GetRoadAvailability(feature::TypesHolder const & types) const;
enum class ResultT
{
Yes, No, Unknown
};
void AddAdditionalRoadTypes(Classificator const & classif, AdditionalRoadsList const & roads);
/// @returns If oneway road.
virtual ResultT IsOneWay(uint32_t type) const = 0;
static uint32_t PrepareToMatchType(uint32_t type);
/// @returns Availability according to a special restriction: hwtag={yes,no}{car,bicycle,foot}.
virtual ResultT GetRoadAvailability(uint32_t type) const = 0;
/// \returns true if |types| is a oneway feature.
/// \note According to OSM, tag "oneway" could have value "-1". That means it's a oneway feature
/// with reversed geometry. In that case at map generation the geometry of such features
/// is reversed (the order of points is changed) so in vehicle model all oneway feature
/// may be considered as features with forward geometry.
bool HasOneWayType(feature::TypesHolder const & types) const;
bool HasPassThroughType(feature::TypesHolder const & types) const;
SpeedKMpH GetTypeSpeed(feature::TypesHolder const & types, SpeedParams const & speedParams) const;
SpeedKMpH GetSpeedWihtoutMaxspeed(FeatureType & f, SpeedParams const & speedParams) const;
/// @returns Default speed for available road, but not in the current HighwayType model.
virtual SpeedKMpH GetSpeedForAvailable() const = 0;
/// \brief Maximum within all the speed limits set in a model (car model, bicycle model and so on).
/// Do not mix with maxspeed value tag, which defines maximum legal speed on a feature.
InOutCitySpeedKMpH m_maxModelSpeed;
private:
std::optional<HighwayType> GetHighwayType(uint32_t type) const;
void GetSurfaceFactor(uint32_t type, SpeedFactor & factor) const;
void GetAdditionalRoadSpeed(uint32_t type, bool isCityRoad,
std::optional<SpeedKMpH> & speed) const;
void NormalizeType(uint32_t type) const;
SpeedKMpH GetSpeedOnFeatureWithoutMaxspeed(HighwayType const & type,
SpeedParams const & speedParams) const;
SpeedKMpH GetSpeedOnFeatureWithMaxspeed(HighwayType const & type,
SpeedParams const & speedParams) const;
struct Info
{
InOutCitySpeedKMpH m_speed;
InOutCityFactor m_factor;
bool m_isPassThroughAllowed = true;
// HW type -> speed and factor.
HighwayBasedInfo m_highwayBasedInfo;
uint32_t m_onewayType;
bool operator==(Info const & rhs) const
{
return (m_speed == rhs.m_speed && m_factor == rhs.m_factor &&
m_isPassThroughAllowed == rhs.m_isPassThroughAllowed);
}
};
SpeedKMpH GetSpeed(Info const * info, MaxspeedType ftMaxSpeed, bool inCity) const;
base::SmallMap<uint32_t, Info> m_highwayInfo;
// HW type -> allow pass through.
base::SmallMap<uint32_t, bool> m_roadTypes;
// Mapping surface types psurface={paved_good/paved_bad/unpaved_good/unpaved_bad} to surface speed factors.
base::SmallMapBase<uint32_t, SpeedFactor> m_surfaceFactors;
/// @todo Do we really need a separate map here or can merge with the m_roadTypes map?
base::SmallMapBase<uint32_t, InOutCitySpeedKMpH> m_addRoadTypes;
};
class VehicleModelFactory : public VehicleModelFactoryInterface
@ -375,12 +318,12 @@ protected:
CountryParentNameGetterFn m_countryParentNameGetterFn;
};
HighwayBasedFactors GetOneFactorsForBicycleAndPedestrianModel();
HighwayFactors GetOneFactorsForBicycleAndPedestrianModel();
std::string DebugPrint(VehicleModelInterface::RoadAvailability const l);
std::string DebugPrint(SpeedKMpH const & speed);
std::string DebugPrint(SpeedFactor const & speedFactor);
std::string DebugPrint(InOutCitySpeedKMpH const & speed);
std::string DebugPrint(InOutCityFactor const & speedFactor);
std::string DebugPrint(HighwayType type);
} // namespace routing

View file

@ -11,6 +11,7 @@
#include "routing/index_graph_loader.hpp"
#include "routing/maxspeeds.hpp"
#include "routing_common/car_model_coefs.hpp"
#include "routing_common/car_model.hpp"
#include "routing_common/maxspeed_conversion.hpp"
#include "routing_common/vehicle_model.hpp"
@ -90,16 +91,11 @@ class CarModelTypes final
public:
CarModelTypes()
{
auto const & cl = classif();
for (auto const & e : routing::kHighwayBasedSpeeds)
m_hwtags.push_back(static_cast<uint32_t>(e.first));
for (auto const & road : CarModel::GetAdditionalRoads())
m_hwtags.push_back(cl.GetTypeByPath(road.m_type));
for (auto const & speed : CarModel::GetOptions())
m_hwtags.push_back(cl.GetTypeByPath(speed.m_type));
for (auto const & surface : CarModel::GetSurfaces())
m_surfaceTags.push_back(cl.GetTypeByPath(surface.m_type));
for (auto const & e : routing::kHighwayBasedSurface)
m_surfaceTags.push_back(static_cast<uint32_t>(e.first));
}
struct Type
@ -402,8 +398,8 @@ void CmdTagsTable(string const & filepath, string const & trackExtension, String
auto const countryName = storage.GetTopmostParentFor(mwmName);
auto const carModelFactory = make_shared<CarModelFactory>(VehicleModelFactory::CountryParentNameGetterFn{});
shared_ptr<VehicleModelInterface> vehicleModel =
carModelFactory->GetVehicleModelForCountry(mwmName);
shared_ptr<VehicleModelInterface> vehicleModel = carModelFactory->GetVehicleModelForCountry(mwmName);
string const mwmFile = GetCurrentVersionMwmFile(storage, mwmName);
MatchedTrackPointToMoveType pointToMoveType(FilesContainerR(make_unique<FileReader>(mwmFile)), *vehicleModel);
Geometry geometry(GeometryLoader::CreateFromFile(mwmFile, vehicleModel));

View file

@ -147,7 +147,7 @@ void TrackMatcher::Step::FillCandidatesWithNearbySegments(
if (ft.GetID().m_mwmId.GetInfo()->GetType() != MwmInfo::COUNTRY)
return;
if (!vehicleModel.IsRoad(ft))
if (!vehicleModel.HasRoadType(ft))
return;
ft.ParseGeometry(FeatureType::BEST_GEOMETRY);

View file

@ -177,13 +177,17 @@ SpeedGroup TrafficInfo::GetSpeedGroup(RoadSegmentId const & id) const
void TrafficInfo::ExtractTrafficKeys(string const & mwmPath, vector<RoadSegmentId> & result)
{
result.clear();
feature::ForEachFeature(mwmPath, [&](FeatureType & ft, uint32_t const fid) {
if (!routing::CarModel::AllLimitsInstance().IsRoad(ft))
auto const & carModel = routing::CarModel::AllLimitsInstance();
feature::ForEachFeature(mwmPath, [&](FeatureType & ft, uint32_t const fid)
{
auto const response = carModel.GetFeatureInfo(ft, {});
if (!response.m_isValid)
return;
ft.ParseGeometry(FeatureType::BEST_GEOMETRY);
auto const numPoints = static_cast<uint16_t>(ft.GetPointsCount());
uint8_t const numDirs = routing::CarModel::AllLimitsInstance().IsOneWay(ft) ? 1 : 2;
uint8_t const numDirs = response.m_isOneWay ? 1 : 2;
for (uint16_t i = 0; i + 1 < numPoints; ++i)
{
for (uint8_t dir = 0; dir < numDirs; ++dir)