Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
26
libs/routing_common/CMakeLists.txt
Normal file
26
libs/routing_common/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
project(routing_common)
|
||||
|
||||
set(SRC
|
||||
bicycle_model.cpp
|
||||
bicycle_model.hpp
|
||||
car_model.cpp
|
||||
car_model.hpp
|
||||
car_model_coefs.hpp # This file is generated by running ../configure.sh script.
|
||||
maxspeed_conversion.cpp
|
||||
maxspeed_conversion.hpp
|
||||
num_mwm_id.hpp
|
||||
pedestrian_model.cpp
|
||||
pedestrian_model.hpp
|
||||
vehicle_model.cpp
|
||||
vehicle_model.hpp
|
||||
)
|
||||
|
||||
omim_add_library(${PROJECT_NAME} ${SRC})
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
base
|
||||
indexer
|
||||
platform
|
||||
)
|
||||
|
||||
omim_add_test_subdirectory(routing_common_tests)
|
||||
304
libs/routing_common/bicycle_model.cpp
Normal file
304
libs/routing_common/bicycle_model.cpp
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
#include "routing_common/bicycle_model.hpp"
|
||||
|
||||
#include "indexer/classificator.hpp"
|
||||
#include "indexer/feature.hpp"
|
||||
|
||||
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,
|
||||
// but not listed in tables in the document. For example, steps are not listed, paths, roads and services features also
|
||||
// can be treated as ready for bicycle routing. These road types were added to lists below.
|
||||
|
||||
// See road types here:
|
||||
// https://wiki.openstreetmap.org/wiki/Key:highway
|
||||
|
||||
// Heuristics:
|
||||
// For less bicycle roads we add fine by setting smaller value of weight speed, and for more bicycle roads we
|
||||
// set greater values of weight speed. Algorithm picks roads with greater weight speed first,
|
||||
// preferencing a more bicycle roads over less bicycle.
|
||||
// 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();
|
||||
|
||||
SpeedKMpH constexpr kSpeedOffroadKMpH = {1.5 /* weight */, 3.0 /* eta */};
|
||||
SpeedKMpH constexpr kSpeedDismountKMpH = {2.0 /* weight */, 4.0 /* eta */};
|
||||
// Applies only to countries where cycling is allowed on footways (by default the above dismount speed is used).
|
||||
SpeedKMpH constexpr kSpeedOnFootwayKMpH = {8.0 /* weight */, 10.0 /* eta */};
|
||||
|
||||
HighwayBasedSpeeds const kDefaultSpeeds = {
|
||||
// {highway class : InOutCitySpeedKMpH(in city(weight, eta), out city(weight eta))}
|
||||
// Note that roads with hwtag=yesbicycle get high speed of 0.9 * Cycleway.
|
||||
/// @see Russia_UseTrunk test for Trunk weights.
|
||||
{HighwayType::HighwayTrunk, InOutCitySpeedKMpH(SpeedKMpH(7.0, 17.0), SpeedKMpH(9.0, 19.0))},
|
||||
// Presence of link roads usually means that connected roads are high traffic.
|
||||
// And complex intersections themselves are not nice for cyclists. We can't
|
||||
// easily extrapolate this to the main roads, but at least penalize the link roads a bit.
|
||||
// https://github.com/organicmaps/organicmaps/pull/9692#discussion_r1851442568
|
||||
{HighwayType::HighwayTrunkLink, InOutCitySpeedKMpH(SpeedKMpH(6.0, 17.0), SpeedKMpH(8.0, 19.0))},
|
||||
{HighwayType::HighwayPrimary, InOutCitySpeedKMpH(SpeedKMpH(10.0, 17.0), SpeedKMpH(12.0, 19.0))},
|
||||
{HighwayType::HighwayPrimaryLink, InOutCitySpeedKMpH(SpeedKMpH(8.0, 17.0), SpeedKMpH(11.0, 19.0))},
|
||||
{HighwayType::HighwaySecondary, InOutCitySpeedKMpH(SpeedKMpH(13.0, 17.0), SpeedKMpH(15.0, 19.0))},
|
||||
{HighwayType::HighwaySecondaryLink, InOutCitySpeedKMpH(SpeedKMpH(11.0, 17.0), SpeedKMpH(13.0, 19.0))},
|
||||
{HighwayType::HighwayTertiary, InOutCitySpeedKMpH(SpeedKMpH(14.0, 17.0), SpeedKMpH(17.0, 19.0))},
|
||||
{HighwayType::HighwayTertiaryLink, InOutCitySpeedKMpH(SpeedKMpH(13.0, 17.0), SpeedKMpH(16.0, 19.0))},
|
||||
{HighwayType::HighwayUnclassified, InOutCitySpeedKMpH(SpeedKMpH(13.0, 17.0), SpeedKMpH(15.0, 19.0))},
|
||||
{HighwayType::HighwayResidential, InOutCitySpeedKMpH(SpeedKMpH(12.0, 14.0), SpeedKMpH(14.0, 17.0))},
|
||||
{HighwayType::HighwayService, InOutCitySpeedKMpH(SpeedKMpH(13.0, 15.0), SpeedKMpH(15.0, 17.0))},
|
||||
{HighwayType::HighwayRoad, InOutCitySpeedKMpH(SpeedKMpH(11.0, 15.0), SpeedKMpH(14.0, 17.0))},
|
||||
|
||||
{HighwayType::HighwayTrack, InOutCitySpeedKMpH(SpeedKMpH(8.0, 12.0), SpeedKMpH(10.0, 14.0))},
|
||||
{HighwayType::HighwayPath, InOutCitySpeedKMpH(SpeedKMpH(6.0, 10.0), SpeedKMpH(7.0, 12.0))},
|
||||
{HighwayType::HighwayBridleway, InOutCitySpeedKMpH(SpeedKMpH(4.0, 10.0), SpeedKMpH(5.0, 12.0))},
|
||||
|
||||
{HighwayType::HighwayCycleway, InOutCitySpeedKMpH(SpeedKMpH(21.0, 18.0), SpeedKMpH(23.0, 20.0))},
|
||||
{HighwayType::HighwayLivingStreet, InOutCitySpeedKMpH(SpeedKMpH(12.0, 10.0), SpeedKMpH(14.0, 12.0))},
|
||||
// Steps have obvious inconvenience of a bike in hands.
|
||||
{HighwayType::HighwaySteps, InOutCitySpeedKMpH(SpeedKMpH(1.0, 1.0))},
|
||||
{HighwayType::HighwayPedestrian, InOutCitySpeedKMpH(kSpeedDismountKMpH)},
|
||||
{HighwayType::HighwayFootway, InOutCitySpeedKMpH(kSpeedDismountKMpH)},
|
||||
{HighwayType::ManMadePier, InOutCitySpeedKMpH(kSpeedOnFootwayKMpH)},
|
||||
/// @todo A car ferry has {10, 10}. Weight = 9 is 60% from reasonable 15 average speed.
|
||||
{HighwayType::RouteFerry, InOutCitySpeedKMpH(SpeedKMpH(9.0, 20.0))},
|
||||
};
|
||||
|
||||
// Default, no bridleway.
|
||||
VehicleModel::LimitsInitList const kDefaultOptions = {
|
||||
// {HighwayType, passThroughAllowed}
|
||||
{HighwayType::HighwayTrunk, true},
|
||||
{HighwayType::HighwayTrunkLink, true},
|
||||
{HighwayType::HighwayPrimary, true},
|
||||
{HighwayType::HighwayPrimaryLink, true},
|
||||
{HighwayType::HighwaySecondary, true},
|
||||
{HighwayType::HighwaySecondaryLink, true},
|
||||
{HighwayType::HighwayTertiary, true},
|
||||
{HighwayType::HighwayTertiaryLink, true},
|
||||
{HighwayType::HighwayService, true},
|
||||
{HighwayType::HighwayUnclassified, true},
|
||||
{HighwayType::HighwayRoad, true},
|
||||
{HighwayType::HighwayTrack, true},
|
||||
{HighwayType::HighwayPath, true},
|
||||
// HighwayBridleway is missing
|
||||
{HighwayType::HighwayCycleway, true},
|
||||
{HighwayType::HighwayResidential, true},
|
||||
{HighwayType::HighwayLivingStreet, true},
|
||||
// HighwayLadder is missing
|
||||
{HighwayType::HighwaySteps, true},
|
||||
{HighwayType::HighwayPedestrian, true},
|
||||
{HighwayType::HighwayFootway, true},
|
||||
{HighwayType::ManMadePier, true},
|
||||
{HighwayType::RouteFerry, true}};
|
||||
|
||||
// Same as defaults except trunk and trunk_link are not allowed
|
||||
VehicleModel::LimitsInitList NoTrunk()
|
||||
{
|
||||
VehicleModel::LimitsInitList res;
|
||||
res.reserve(kDefaultOptions.size() - 2);
|
||||
for (auto const & e : kDefaultOptions)
|
||||
if (e.m_type != HighwayType::HighwayTrunk && e.m_type != HighwayType::HighwayTrunkLink)
|
||||
res.push_back(e);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Same as defaults except pedestrian is allowed
|
||||
HighwayBasedSpeeds NormalPedestrianSpeed()
|
||||
{
|
||||
HighwayBasedSpeeds res = kDefaultSpeeds;
|
||||
res.Replace(HighwayType::HighwayPedestrian, InOutCitySpeedKMpH(kSpeedOnFootwayKMpH));
|
||||
return res;
|
||||
}
|
||||
|
||||
// Same as defaults except bridleway is allowed
|
||||
VehicleModel::LimitsInitList AllAllowed()
|
||||
{
|
||||
auto res = kDefaultOptions;
|
||||
res.push_back({HighwayType::HighwayBridleway, true});
|
||||
return res;
|
||||
}
|
||||
|
||||
// Same as defaults except pedestrian and footway are allowed
|
||||
HighwayBasedSpeeds NormalPedestrianAndFootwaySpeed()
|
||||
{
|
||||
HighwayBasedSpeeds res = kDefaultSpeeds;
|
||||
InOutCitySpeedKMpH const footSpeed(kSpeedOnFootwayKMpH);
|
||||
res.Replace(HighwayType::HighwayPedestrian, footSpeed);
|
||||
res.Replace(HighwayType::HighwayFootway, footSpeed);
|
||||
return res;
|
||||
}
|
||||
|
||||
HighwayBasedSpeeds DismountPathSpeed()
|
||||
{
|
||||
HighwayBasedSpeeds res = kDefaultSpeeds;
|
||||
res.Replace(HighwayType::HighwayPath, InOutCitySpeedKMpH(kSpeedDismountKMpH));
|
||||
return res;
|
||||
}
|
||||
|
||||
HighwayBasedSpeeds PreferFootwaysToRoads()
|
||||
{
|
||||
HighwayBasedSpeeds res = kDefaultSpeeds;
|
||||
|
||||
// Decrease secondary/tertiary weight speed (-20% from default).
|
||||
InOutCitySpeedKMpH roadSpeed = InOutCitySpeedKMpH(SpeedKMpH(11.0, 17.0), SpeedKMpH(16.0, 19.0));
|
||||
res.Replace(HighwayType::HighwaySecondary, roadSpeed);
|
||||
res.Replace(HighwayType::HighwaySecondaryLink, roadSpeed);
|
||||
res.Replace(HighwayType::HighwayTertiary, roadSpeed);
|
||||
res.Replace(HighwayType::HighwayTertiaryLink, roadSpeed);
|
||||
|
||||
// Increase footway speed to make bigger than other roads (+20% from default roads).
|
||||
InOutCitySpeedKMpH footSpeed = InOutCitySpeedKMpH(SpeedKMpH(17.0, 12.0), SpeedKMpH(20.0, 15.0));
|
||||
res.Replace(HighwayType::HighwayPedestrian, footSpeed);
|
||||
res.Replace(HighwayType::HighwayFootway, footSpeed);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// No trunk, No pass through living_street and service
|
||||
VehicleModel::LimitsInitList UkraineOptions()
|
||||
{
|
||||
auto res = NoTrunk();
|
||||
for (auto & e : res)
|
||||
if (e.m_type == HighwayType::HighwayLivingStreet || e.m_type == HighwayType::HighwayService)
|
||||
e.m_isPassThroughAllowed = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
VehicleModel::SurfaceInitList const kBicycleSurface = {
|
||||
// {{surfaceType}, {weightFactor, etaFactor}}
|
||||
{{"psurface", "paved_good"}, {1.0, 1.0}},
|
||||
{{"psurface", "paved_bad"}, {0.8, 0.8}},
|
||||
{{"psurface", "unpaved_good"}, {0.9, 0.9}},
|
||||
{{"psurface", "unpaved_bad"}, {0.3, 0.3}},
|
||||
// No dedicated cycleway doesn't mean that bicycle is not allowed, just lower weight.
|
||||
// If nocycleway is tagged explicitly then there is no cycling infra for sure.
|
||||
// Otherwise there is a small chance cycling infra is present though not mapped?
|
||||
/// @todo(pastk): this heuristic is controversial, maybe remove completely?
|
||||
{{"hwtag", "nocycleway"}, {0.95, 0.95}},
|
||||
};
|
||||
} // namespace bicycle_model
|
||||
|
||||
namespace routing
|
||||
{
|
||||
BicycleModel::BicycleModel() : BicycleModel(bicycle_model::kDefaultOptions) {}
|
||||
|
||||
BicycleModel::BicycleModel(VehicleModel::LimitsInitList const & limits)
|
||||
: BicycleModel(limits, bicycle_model::kDefaultSpeeds)
|
||||
{}
|
||||
|
||||
BicycleModel::BicycleModel(VehicleModel::LimitsInitList const & limits, HighwayBasedSpeeds const & speeds)
|
||||
: VehicleModel(classif(), limits, bicycle_model::kBicycleSurface, {speeds, bicycle_model::kDefaultFactors})
|
||||
{
|
||||
using namespace bicycle_model;
|
||||
|
||||
// No bridleway in default.
|
||||
ASSERT_EQUAL(kDefaultOptions.size(), kDefaultSpeeds.size() - 1, ());
|
||||
|
||||
std::vector<std::string> hwtagYesBicycle = {"hwtag", "yesbicycle"};
|
||||
|
||||
auto const & cl = classif();
|
||||
m_noType = cl.GetTypeByPath({"hwtag", "nobicycle"});
|
||||
m_yesType = cl.GetTypeByPath(hwtagYesBicycle);
|
||||
m_bidirBicycleType = cl.GetTypeByPath({"hwtag", "bidir_bicycle"});
|
||||
m_onedirBicycleType = cl.GetTypeByPath({"hwtag", "onedir_bicycle"});
|
||||
|
||||
// Assign 90% of max cycleway speed for bicycle=yes to keep choosing most preferred cycleway.
|
||||
auto const yesSpeed = kDefaultSpeeds.Get(HighwayType::HighwayCycleway).m_inCity * 0.9;
|
||||
AddAdditionalRoadTypes(cl, {{std::move(hwtagYesBicycle), InOutCitySpeedKMpH(yesSpeed)}});
|
||||
|
||||
// Update max speed with possible ferry transfer and bicycle speed downhill.
|
||||
// See EdgeEstimator::CalcHeuristic, GetBicycleClimbPenalty.
|
||||
SpeedKMpH constexpr kMaxBicycleSpeedKMpH(100.0);
|
||||
CHECK_LESS(m_maxModelSpeed, kMaxBicycleSpeedKMpH, ());
|
||||
m_maxModelSpeed = kMaxBicycleSpeedKMpH;
|
||||
}
|
||||
|
||||
bool BicycleModel::IsBicycleBidir(feature::TypesHolder const & types) const
|
||||
{
|
||||
return types.Has(m_bidirBicycleType);
|
||||
}
|
||||
|
||||
bool BicycleModel::IsBicycleOnedir(feature::TypesHolder const & types) const
|
||||
{
|
||||
return types.Has(m_onedirBicycleType);
|
||||
}
|
||||
|
||||
SpeedKMpH BicycleModel::GetSpeed(FeatureTypes const & types, SpeedParams const & speedParams) const
|
||||
{
|
||||
return GetTypeSpeedImpl(types, speedParams, false /* isCar */);
|
||||
}
|
||||
|
||||
bool BicycleModel::IsOneWay(FeatureTypes const & types) const
|
||||
{
|
||||
if (IsBicycleOnedir(types))
|
||||
return true;
|
||||
|
||||
if (IsBicycleBidir(types))
|
||||
return false;
|
||||
|
||||
return VehicleModel::IsOneWay(types);
|
||||
}
|
||||
|
||||
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::AllAllowed(), bicycle_model::NormalPedestrianAndFootwaySpeed());
|
||||
return instance;
|
||||
}
|
||||
|
||||
// static
|
||||
SpeedKMpH BicycleModel::DismountSpeed()
|
||||
{
|
||||
return bicycle_model::kSpeedDismountKMpH;
|
||||
}
|
||||
|
||||
BicycleModelFactory::BicycleModelFactory(CountryParentNameGetterFn const & countryParentNameGetterFn)
|
||||
: VehicleModelFactory(countryParentNameGetterFn)
|
||||
{
|
||||
using namespace bicycle_model;
|
||||
using std::make_shared;
|
||||
|
||||
// Names must be the same with country names from countries.txt
|
||||
m_models[""] = make_shared<BicycleModel>(kDefaultOptions);
|
||||
|
||||
m_models["Australia"] = make_shared<BicycleModel>(AllAllowed(), NormalPedestrianAndFootwaySpeed());
|
||||
m_models["Austria"] = make_shared<BicycleModel>(NoTrunk(), DismountPathSpeed());
|
||||
// Belarus law demands to use footways for bicycles where possible.
|
||||
m_models["Belarus"] = make_shared<BicycleModel>(kDefaultOptions, PreferFootwaysToRoads());
|
||||
m_models["Belgium"] = make_shared<BicycleModel>(NoTrunk(), NormalPedestrianSpeed());
|
||||
m_models["Brazil"] = make_shared<BicycleModel>(AllAllowed());
|
||||
m_models["Denmark"] = make_shared<BicycleModel>(NoTrunk());
|
||||
m_models["France"] = make_shared<BicycleModel>(NoTrunk(), NormalPedestrianSpeed());
|
||||
m_models["Finland"] = make_shared<BicycleModel>(kDefaultOptions, NormalPedestrianSpeed());
|
||||
m_models["Hungary"] = make_shared<BicycleModel>(NoTrunk());
|
||||
m_models["Iceland"] = make_shared<BicycleModel>(AllAllowed(), NormalPedestrianAndFootwaySpeed());
|
||||
m_models["Ireland"] = make_shared<BicycleModel>(AllAllowed());
|
||||
m_models["Italy"] = make_shared<BicycleModel>(kDefaultOptions, NormalPedestrianSpeed());
|
||||
m_models["Netherlands"] = make_shared<BicycleModel>(NoTrunk());
|
||||
m_models["Norway"] = make_shared<BicycleModel>(AllAllowed(), NormalPedestrianAndFootwaySpeed());
|
||||
m_models["Oman"] = make_shared<BicycleModel>(AllAllowed());
|
||||
m_models["Philippines"] = make_shared<BicycleModel>(AllAllowed(), NormalPedestrianSpeed());
|
||||
m_models["Poland"] = make_shared<BicycleModel>(NoTrunk());
|
||||
m_models["Romania"] = make_shared<BicycleModel>(AllAllowed());
|
||||
// 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"] = make_shared<BicycleModel>(kDefaultOptions, NormalPedestrianAndFootwaySpeed());
|
||||
m_models["Slovakia"] = make_shared<BicycleModel>(NoTrunk());
|
||||
m_models["Spain"] = make_shared<BicycleModel>(NoTrunk(), NormalPedestrianSpeed());
|
||||
m_models["Sweden"] = make_shared<BicycleModel>(kDefaultOptions, NormalPedestrianSpeed());
|
||||
m_models["Switzerland"] = make_shared<BicycleModel>(NoTrunk(), NormalPedestrianAndFootwaySpeed());
|
||||
m_models["Ukraine"] = make_shared<BicycleModel>(UkraineOptions());
|
||||
m_models["United Kingdom"] = make_shared<BicycleModel>(AllAllowed());
|
||||
m_models["United States of America"] = make_shared<BicycleModel>(AllAllowed(), NormalPedestrianSpeed());
|
||||
}
|
||||
} // namespace routing
|
||||
40
libs/routing_common/bicycle_model.hpp
Normal file
40
libs/routing_common/bicycle_model.hpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include "routing_common/vehicle_model.hpp"
|
||||
|
||||
namespace routing
|
||||
{
|
||||
|
||||
class BicycleModel : public VehicleModel
|
||||
{
|
||||
public:
|
||||
BicycleModel();
|
||||
explicit BicycleModel(VehicleModel::LimitsInitList const & limits);
|
||||
BicycleModel(VehicleModel::LimitsInitList const & limits, HighwayBasedSpeeds const & speeds);
|
||||
|
||||
/// VehicleModelInterface overrides:
|
||||
SpeedKMpH GetSpeed(FeatureTypes const & types, SpeedParams const & speedParams) const override;
|
||||
bool IsOneWay(FeatureTypes const & types) const override;
|
||||
SpeedKMpH const & GetOffroadSpeed() const override;
|
||||
|
||||
static BicycleModel const & AllLimitsInstance();
|
||||
static SpeedKMpH DismountSpeed();
|
||||
|
||||
private:
|
||||
/// @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_bidirBicycleType = 0;
|
||||
uint32_t m_onedirBicycleType = 0;
|
||||
};
|
||||
|
||||
class BicycleModelFactory : public VehicleModelFactory
|
||||
{
|
||||
public:
|
||||
// TODO: remove countryParentNameGetterFn default value after removing unused bicycle routing
|
||||
// from road_graph_router
|
||||
BicycleModelFactory(CountryParentNameGetterFn const & countryParentNameGetterFn = {});
|
||||
};
|
||||
} // namespace routing
|
||||
158
libs/routing_common/car_model.cpp
Normal file
158
libs/routing_common/car_model.cpp
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
#include "routing_common/car_model.hpp"
|
||||
#include "routing_common/car_model_coefs.hpp"
|
||||
|
||||
#include "indexer/classificator.hpp"
|
||||
|
||||
namespace car_model
|
||||
{
|
||||
using namespace routing;
|
||||
|
||||
// See model specifics in different countries here:
|
||||
// https://wiki.openstreetmap.org/wiki/OSM_tags_for_routing/Access-Restrictions
|
||||
|
||||
// See road types here:
|
||||
// https://wiki.openstreetmap.org/wiki/Key:highway
|
||||
|
||||
// |kSpeedOffroadKMpH| is a speed which is used for edges that don't lie on road features.
|
||||
// For example for pure fake edges. In car routing, off road speed for calculation ETA is not used.
|
||||
// The weight of such edges is considered as 0 seconds. It's especially actual when an airport is
|
||||
// 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 */};
|
||||
|
||||
VehicleModel::LimitsInitList const kDefaultOptions = {
|
||||
// {HighwayType, passThroughAllowed}
|
||||
{HighwayType::HighwayMotorway, true}, {HighwayType::HighwayMotorwayLink, true},
|
||||
{HighwayType::HighwayTrunk, true}, {HighwayType::HighwayTrunkLink, true},
|
||||
{HighwayType::HighwayPrimary, true}, {HighwayType::HighwayPrimaryLink, true},
|
||||
{HighwayType::HighwaySecondary, true}, {HighwayType::HighwaySecondaryLink, true},
|
||||
{HighwayType::HighwayTertiary, true}, {HighwayType::HighwayTertiaryLink, true},
|
||||
{HighwayType::HighwayResidential, true}, {HighwayType::HighwayUnclassified, true},
|
||||
{HighwayType::HighwayService, true}, {HighwayType::HighwayLivingStreet, true},
|
||||
{HighwayType::HighwayRoad, true}, {HighwayType::HighwayTrack, true},
|
||||
{HighwayType::RouteShuttleTrain, true}, {HighwayType::RouteFerry, true},
|
||||
{HighwayType::ManMadePier, true}};
|
||||
|
||||
VehicleModel::LimitsInitList NoPassThroughLivingStreet()
|
||||
{
|
||||
auto res = kDefaultOptions;
|
||||
for (auto & e : res)
|
||||
if (e.m_type == HighwayType::HighwayLivingStreet)
|
||||
e.m_isPassThroughAllowed = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
VehicleModel::LimitsInitList NoPassThroughService(VehicleModel::LimitsInitList res = kDefaultOptions)
|
||||
{
|
||||
for (auto & e : res)
|
||||
if (e.m_type == HighwayType::HighwayService)
|
||||
e.m_isPassThroughAllowed = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
VehicleModel::LimitsInitList NoTrack()
|
||||
{
|
||||
VehicleModel::LimitsInitList res;
|
||||
res.reserve(kDefaultOptions.size() - 1);
|
||||
for (auto const & e : kDefaultOptions)
|
||||
if (e.m_type != HighwayType::HighwayTrack)
|
||||
res.push_back(e);
|
||||
return res;
|
||||
}
|
||||
|
||||
VehicleModel::LimitsInitList NoPassThroughTrack()
|
||||
{
|
||||
auto res = kDefaultOptions;
|
||||
for (auto & e : res)
|
||||
if (e.m_type == HighwayType::HighwayTrack)
|
||||
e.m_isPassThroughAllowed = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
/// @todo Should make some compare constrains (like in CarModel_TrackVsGravelTertiary test)
|
||||
/// to better fit these factors with reality. I have no idea, how they were set.
|
||||
VehicleModel::SurfaceInitList const kCarSurface = {
|
||||
// {{surfaceType, surfaceType}, {weightFactor, etaFactor}}
|
||||
{{"psurface", "paved_good"}, {1.0, 1.0}},
|
||||
{{"psurface", "paved_bad"}, {0.6, 0.7}},
|
||||
{{"psurface", "unpaved_good"}, {0.4, 0.7}},
|
||||
{{"psurface", "unpaved_bad"}, {0.2, 0.3}}};
|
||||
} // namespace car_model
|
||||
|
||||
namespace routing
|
||||
{
|
||||
CarModel::CarModel() : CarModel(car_model::kDefaultOptions) {}
|
||||
|
||||
CarModel::CarModel(VehicleModel::LimitsInitList const & roadLimits)
|
||||
: VehicleModel(classif(), roadLimits, car_model::kCarSurface, {kHighwayBasedSpeeds, kHighwayBasedFactors})
|
||||
{
|
||||
ASSERT_EQUAL(kHighwayBasedSpeeds.size(), kHighwayBasedFactors.size(), ());
|
||||
ASSERT_EQUAL(kHighwayBasedSpeeds.size(), car_model::kDefaultOptions.size(), ());
|
||||
|
||||
std::vector<std::string> hwtagYesCar = {"hwtag", "yescar"};
|
||||
auto const & cl = classif();
|
||||
|
||||
m_noType = cl.GetTypeByPath({"hwtag", "nocar"});
|
||||
m_yesType = cl.GetTypeByPath(hwtagYesCar);
|
||||
|
||||
// Set small track speed if highway is not in kHighwayBasedSpeeds (path, pedestrian), but marked as yescar.
|
||||
AddAdditionalRoadTypes(cl, {{std::move(hwtagYesCar), kHighwayBasedSpeeds.Get(HighwayType::HighwayTrack)}});
|
||||
|
||||
// Set max possible (reasonable) car speed. See EdgeEstimator::CalcHeuristic.
|
||||
SpeedKMpH constexpr kMaxCarSpeedKMpH(200.0);
|
||||
CHECK_LESS(m_maxModelSpeed, kMaxCarSpeedKMpH, ());
|
||||
m_maxModelSpeed = kMaxCarSpeedKMpH;
|
||||
}
|
||||
|
||||
SpeedKMpH CarModel::GetSpeed(FeatureTypes const & types, SpeedParams const & speedParams) const
|
||||
{
|
||||
return GetTypeSpeedImpl(types, speedParams, true /* isCar */);
|
||||
}
|
||||
|
||||
SpeedKMpH const & CarModel::GetOffroadSpeed() const
|
||||
{
|
||||
return car_model::kSpeedOffroadKMpH;
|
||||
}
|
||||
|
||||
// static
|
||||
CarModel const & CarModel::AllLimitsInstance()
|
||||
{
|
||||
static CarModel const instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
// static
|
||||
VehicleModel::LimitsInitList const & CarModel::GetOptions()
|
||||
{
|
||||
return car_model::kDefaultOptions;
|
||||
}
|
||||
|
||||
// static
|
||||
VehicleModel::SurfaceInitList const & CarModel::GetSurfaces()
|
||||
{
|
||||
return car_model::kCarSurface;
|
||||
}
|
||||
|
||||
CarModelFactory::CarModelFactory(CountryParentNameGetterFn const & countryParentNameGetterFn)
|
||||
: VehicleModelFactory(countryParentNameGetterFn)
|
||||
{
|
||||
using namespace car_model;
|
||||
using std::make_shared;
|
||||
|
||||
// Names must be the same with country names from countries.txt
|
||||
m_models[""] = make_shared<CarModel>();
|
||||
|
||||
m_models["Austria"] = make_shared<CarModel>(NoPassThroughLivingStreet());
|
||||
m_models["Belarus"] = make_shared<CarModel>(NoPassThroughLivingStreet());
|
||||
m_models["Brazil"] = make_shared<CarModel>(NoPassThroughService(NoPassThroughTrack()));
|
||||
m_models["Denmark"] = make_shared<CarModel>(NoTrack());
|
||||
m_models["Germany"] = make_shared<CarModel>(NoPassThroughTrack());
|
||||
m_models["Hungary"] = make_shared<CarModel>(NoPassThroughLivingStreet());
|
||||
m_models["Poland"] = make_shared<CarModel>(NoPassThroughService());
|
||||
m_models["Romania"] = make_shared<CarModel>(NoPassThroughLivingStreet());
|
||||
m_models["Russian Federation"] = make_shared<CarModel>(NoPassThroughService(NoPassThroughLivingStreet()));
|
||||
m_models["Slovakia"] = make_shared<CarModel>(NoPassThroughLivingStreet());
|
||||
m_models["Ukraine"] = make_shared<CarModel>(NoPassThroughService(NoPassThroughLivingStreet()));
|
||||
}
|
||||
} // namespace routing
|
||||
28
libs/routing_common/car_model.hpp
Normal file
28
libs/routing_common/car_model.hpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "routing_common/vehicle_model.hpp"
|
||||
|
||||
namespace routing
|
||||
{
|
||||
|
||||
class CarModel : public VehicleModel
|
||||
{
|
||||
public:
|
||||
CarModel();
|
||||
explicit CarModel(LimitsInitList const & roadLimits);
|
||||
|
||||
/// VehicleModelInterface overrides:
|
||||
SpeedKMpH GetSpeed(FeatureTypes const & types, SpeedParams const & speedParams) const override;
|
||||
SpeedKMpH const & GetOffroadSpeed() const override;
|
||||
|
||||
static CarModel const & AllLimitsInstance();
|
||||
static LimitsInitList const & GetOptions();
|
||||
static SurfaceInitList const & GetSurfaces();
|
||||
};
|
||||
|
||||
class CarModelFactory : public VehicleModelFactory
|
||||
{
|
||||
public:
|
||||
CarModelFactory(CountryParentNameGetterFn const & countryParentNameGetterF);
|
||||
};
|
||||
} // namespace routing
|
||||
82
libs/routing_common/car_model_coefs.hpp
Normal file
82
libs/routing_common/car_model_coefs.hpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#pragma once
|
||||
|
||||
#include "routing_common/vehicle_model.hpp"
|
||||
|
||||
// These are default car model coefficients for open source developers.
|
||||
|
||||
namespace routing
|
||||
{
|
||||
HighwayBasedFactors const kHighwayBasedFactors = {
|
||||
// {highway class : InOutCityFactor(in city, out city)}
|
||||
|
||||
// Tier 1 (decrease ETA a bit according to the tests):
|
||||
{HighwayType::HighwayMotorway, InOutCityFactor(SpeedFactor{0.95 /* weight */, 0.93 /* eta */})},
|
||||
// See XXX_KeepMotorway integration tests.
|
||||
{HighwayType::HighwayMotorwayLink, InOutCityFactor(0.75)}, // 0.20 less
|
||||
{HighwayType::HighwayTrunk, InOutCityFactor(0.90)},
|
||||
{HighwayType::HighwayTrunkLink, InOutCityFactor(0.80)}, // 0.15 less
|
||||
|
||||
// Tier 2:
|
||||
{HighwayType::HighwayPrimary,
|
||||
InOutCityFactor(SpeedFactor{0.95 /* weight */, 0.90 /* eta */} /* in city */, 0.85 /* out city */)},
|
||||
{HighwayType::HighwayPrimaryLink, InOutCityFactor(0.70 /* in city */, 0.75 /* out city */)}, // 0.10 less
|
||||
{HighwayType::HighwaySecondary, InOutCityFactor(0.80 /* in city */, 0.85 /* out city */)},
|
||||
{HighwayType::HighwaySecondaryLink, InOutCityFactor(0.70 /* in city */, 0.75 /* out city */)}, // 0.10 less
|
||||
|
||||
// Tier 3:
|
||||
{HighwayType::HighwayTertiary,
|
||||
InOutCityFactor(0.70 /* in city */, 0.75 /* out city */)}, // 0.10 less than Secondary
|
||||
{HighwayType::HighwayTertiaryLink, InOutCityFactor(0.60 /* in city */, 0.65 /* out city */)}, // 0.10 less
|
||||
{HighwayType::HighwayUnclassified, InOutCityFactor(0.70 /* in city */, 0.75 /* out city */)},
|
||||
|
||||
// Tier 4:
|
||||
{HighwayType::HighwayResidential, InOutCityFactor(0.70)},
|
||||
{HighwayType::HighwayLivingStreet, InOutCityFactor(0.70)},
|
||||
|
||||
// The rest:
|
||||
// By VNG: Changed 0.3 -> 0.95 for Road and 0.3 -> 1.0 for Track.
|
||||
// They are already have very small speeds (10, 5 respectively).
|
||||
// There are no (99%) traffic lights or pedestrian crossings on this kind of roads.
|
||||
{HighwayType::HighwayService, InOutCityFactor(0.70)},
|
||||
{HighwayType::HighwayRoad, InOutCityFactor(0.90)},
|
||||
{HighwayType::HighwayTrack, InOutCityFactor(1.0)},
|
||||
{HighwayType::ManMadePier, InOutCityFactor(0.90)},
|
||||
|
||||
{HighwayType::RouteFerry, InOutCityFactor(0.90)},
|
||||
{HighwayType::RouteShuttleTrain, InOutCityFactor(0.90)},
|
||||
};
|
||||
|
||||
HighwayBasedSpeeds const kHighwayBasedSpeeds = {
|
||||
// {highway class : InOutCitySpeedKMpH(in city, out city)}
|
||||
|
||||
// Tier 1:
|
||||
{HighwayType::HighwayMotorway, InOutCitySpeedKMpH(118.0 /* in city */, 124.0 /* out city */)},
|
||||
{HighwayType::HighwayMotorwayLink, InOutCitySpeedKMpH(109.00 /* in city */, 115.00 /* out city */)},
|
||||
{HighwayType::HighwayTrunk, InOutCitySpeedKMpH(90.00 /* in city */, 103.00 /* out city */)},
|
||||
{HighwayType::HighwayTrunkLink, InOutCitySpeedKMpH(77.00 /* in city */, 91.00 /* out city */)},
|
||||
|
||||
// Tier 2:
|
||||
{HighwayType::HighwayPrimary, InOutCitySpeedKMpH(65.00 /* in city */, 82.00 /* out city */)},
|
||||
{HighwayType::HighwayPrimaryLink, InOutCitySpeedKMpH(58.00 /* in city */, 72.00 /* out city */)},
|
||||
{HighwayType::HighwaySecondary, InOutCitySpeedKMpH(60.00 /* in city */, 70.00 /* out city */)},
|
||||
{HighwayType::HighwaySecondaryLink, InOutCitySpeedKMpH(48.00 /* in city */, 56.00 /* out city */)},
|
||||
|
||||
// Tier 3:
|
||||
{HighwayType::HighwayTertiary, InOutCitySpeedKMpH(50.00 /* in city */, 50.00 /* out city */)},
|
||||
{HighwayType::HighwayTertiaryLink, InOutCitySpeedKMpH({40.95, 34.97} /* in city */, {45.45, 39.73} /* out city */)},
|
||||
{HighwayType::HighwayUnclassified, InOutCitySpeedKMpH(30.00 /* in city */, 40.00 /* out city */)},
|
||||
|
||||
// Tier 4:
|
||||
{HighwayType::HighwayResidential, InOutCitySpeedKMpH({20.00, 26.00} /* in city */, {26.00, 26.00} /* out city */)},
|
||||
{HighwayType::HighwayLivingStreet, InOutCitySpeedKMpH(10.00 /* in city */, 10.00 /* out city */)},
|
||||
|
||||
// The rest:
|
||||
{HighwayType::HighwayService, InOutCitySpeedKMpH(15.00 /* in city */, 15.00 /* out city */)},
|
||||
{HighwayType::HighwayRoad, InOutCitySpeedKMpH(10.00 /* in city */, 10.00 /* out city */)},
|
||||
{HighwayType::HighwayTrack, InOutCitySpeedKMpH(5.00 /* in city */, 5.00 /* out city */)},
|
||||
{HighwayType::ManMadePier, InOutCitySpeedKMpH({17.00, 10.00} /* in city */, {17.00, 10.00} /* out city */)},
|
||||
|
||||
{HighwayType::RouteFerry, InOutCitySpeedKMpH(10.00 /* in city */, 10.00 /* out city */)},
|
||||
{HighwayType::RouteShuttleTrain, InOutCitySpeedKMpH(25.00 /* in city */, 25.00 /* out city */)},
|
||||
};
|
||||
} // namespace routing
|
||||
373
libs/routing_common/maxspeed_conversion.cpp
Normal file
373
libs/routing_common/maxspeed_conversion.cpp
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
#include "routing_common/maxspeed_conversion.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace routing
|
||||
{
|
||||
using namespace std;
|
||||
using namespace measurement_utils;
|
||||
|
||||
// SpeedInUnits ------------------------------------------------------------------------------------
|
||||
bool SpeedInUnits::operator==(SpeedInUnits const & rhs) const
|
||||
{
|
||||
return m_speed == rhs.m_speed && m_units == rhs.m_units;
|
||||
}
|
||||
|
||||
bool SpeedInUnits::IsNumeric() const
|
||||
{
|
||||
return routing::IsNumeric(m_speed);
|
||||
}
|
||||
|
||||
MaxspeedType SpeedInUnits::GetSpeedKmPH() const
|
||||
{
|
||||
return static_cast<MaxspeedType>(ToSpeedKmPH(m_speed, m_units));
|
||||
}
|
||||
|
||||
// Maxspeed ----------------------------------------------------------------------------------------
|
||||
Maxspeed::Maxspeed(Units units, MaxspeedType forward, MaxspeedType backward)
|
||||
: m_units(units)
|
||||
, m_forward(forward)
|
||||
, m_backward(backward)
|
||||
{}
|
||||
|
||||
bool Maxspeed::operator==(Maxspeed const & rhs) const
|
||||
{
|
||||
return m_units == rhs.m_units && m_forward == rhs.m_forward && m_backward == rhs.m_backward;
|
||||
}
|
||||
|
||||
MaxspeedType Maxspeed::GetSpeedInUnits(bool forward) const
|
||||
{
|
||||
return (forward || !IsBidirectional()) ? m_forward : m_backward;
|
||||
}
|
||||
|
||||
MaxspeedType Maxspeed::GetSpeedKmPH(bool forward) const
|
||||
{
|
||||
auto const speedInUnits = GetSpeedInUnits(forward);
|
||||
switch (speedInUnits)
|
||||
{
|
||||
case kInvalidSpeed:
|
||||
return kInvalidSpeed; // That means IsValid() returns false.
|
||||
|
||||
// A feature is marked as a feature without any speed limits (maxspeed=="none").
|
||||
// Should be less than CarModel::kMaxCarSpeedKMpH.
|
||||
case kNoneMaxSpeed: return MaxspeedType{130};
|
||||
|
||||
// A feature is marked with the maxspeed=="walk" tag, a speed of a walking person.
|
||||
case kWalkMaxSpeed: return MaxspeedType{6};
|
||||
|
||||
case kCommonMaxSpeedValue: return MaxspeedType{60};
|
||||
}
|
||||
return static_cast<MaxspeedType>(ToSpeedKmPH(speedInUnits, m_units));
|
||||
}
|
||||
|
||||
// FeatureMaxspeed ---------------------------------------------------------------------------------
|
||||
FeatureMaxspeed::FeatureMaxspeed(uint32_t fid, measurement_utils::Units units, MaxspeedType forward,
|
||||
MaxspeedType backward /* = kInvalidSpeed */) noexcept
|
||||
: m_featureId(fid)
|
||||
, m_maxspeed(units, forward, backward)
|
||||
{}
|
||||
|
||||
bool FeatureMaxspeed::operator==(FeatureMaxspeed const & rhs) const
|
||||
{
|
||||
return m_featureId == rhs.m_featureId && m_maxspeed == rhs.m_maxspeed;
|
||||
}
|
||||
|
||||
SpeedInUnits FeatureMaxspeed::GetForwardSpeedInUnits() const
|
||||
{
|
||||
return SpeedInUnits(m_maxspeed.GetForward(), m_maxspeed.GetUnits());
|
||||
}
|
||||
|
||||
SpeedInUnits FeatureMaxspeed::GetBackwardSpeedInUnits() const
|
||||
{
|
||||
return SpeedInUnits(m_maxspeed.GetBackward(), m_maxspeed.GetUnits());
|
||||
}
|
||||
|
||||
// MaxspeedConverter -------------------------------------------------------------------------------
|
||||
MaxspeedConverter::MaxspeedConverter()
|
||||
{
|
||||
vector<tuple<SpeedMacro, MaxspeedType, Units>> const table = {
|
||||
// Special values.
|
||||
{SpeedMacro::Undefined, kInvalidSpeed /* speed */, Units::Metric},
|
||||
{SpeedMacro::None, kNoneMaxSpeed /* speed */, Units::Metric},
|
||||
{SpeedMacro::Walk, kWalkMaxSpeed /* speed */, Units::Metric},
|
||||
|
||||
// Km per hour.
|
||||
{SpeedMacro::Speed1KmPH, 1 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed2KmPH, 2 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed3KmPH, 3 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed4KmPH, 4 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed5KmPH, 5 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed6KmPH, 6 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed7KmPH, 7 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed8KmPH, 8 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed9KmPH, 9 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed10KmPH, 10 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed11KmPH, 11 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed12KmPH, 12 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed13KmPH, 13 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed14KmPH, 14 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed15KmPH, 15 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed16KmPH, 16 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed18KmPH, 18 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed20KmPH, 20 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed22KmPH, 22 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed25KmPH, 25 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed24KmPH, 24 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed28KmPH, 28 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed30KmPH, 30 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed32KmPH, 32 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed35KmPH, 35 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed36KmPH, 36 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed39KmPH, 39 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed40KmPH, 40 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed45KmPH, 45 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed50KmPH, 50 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed55KmPH, 55 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed56KmPH, 56 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed60KmPH, 60 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed64KmPH, 64 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed65KmPH, 65 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed70KmPH, 70 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed72KmPH, 72 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed75KmPH, 75 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed80KmPH, 80 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed82KmPH, 82 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed85KmPH, 85 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed89KmPH, 89 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed90KmPH, 90 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed93KmPH, 93 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed95KmPH, 95 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed96KmPH, 96 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed100KmPH, 100 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed104KmPH, 104 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed105KmPH, 105 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed106KmPH, 106 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed110KmPH, 110 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed112KmPH, 112 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed115KmPH, 115 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed120KmPH, 120 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed125KmPH, 125 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed127KmPH, 127 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed130KmPH, 130 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed135KmPH, 135 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed140KmPH, 140 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed141KmPH, 141 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed145KmPH, 145 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed150KmPH, 150 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed155KmPH, 155 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed160KmPH, 160 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed165KmPH, 165 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed170KmPH, 170 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed177KmPH, 177 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed180KmPH, 180 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed185KmPH, 185 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed190KmPH, 190 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed193KmPH, 193 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed195KmPH, 195 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed200KmPH, 200 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed201KmPH, 201 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed210KmPH, 210 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed217KmPH, 217 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed220KmPH, 220 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed230KmPH, 230 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed240KmPH, 240 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed250KmPH, 250 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed260KmPH, 260 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed270KmPH, 270 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed275KmPH, 275 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed280KmPH, 280 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed285KmPH, 285 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed300KmPH, 300 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed305KmPH, 305 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed310KmPH, 310 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed320KmPH, 320 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed350KmPH, 350 /* speed */, Units::Metric},
|
||||
{SpeedMacro::Speed380KmPH, 380 /* speed */, Units::Metric},
|
||||
|
||||
// Miles per hour.
|
||||
{SpeedMacro::Speed3MPH, 3 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed4MPH, 4 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed5MPH, 5 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed6MPH, 6 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed7MPH, 7 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed8MPH, 8 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed9MPH, 9 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed10MPH, 10 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed12MPH, 12 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed13MPH, 13 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed14MPH, 14 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed15MPH, 15 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed17MPH, 17 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed18MPH, 18 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed19MPH, 19 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed20MPH, 20 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed24MPH, 24 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed25MPH, 25 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed30MPH, 30 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed35MPH, 35 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed40MPH, 40 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed45MPH, 45 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed50MPH, 50 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed55MPH, 55 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed59MPH, 59 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed60MPH, 60 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed65MPH, 65 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed70MPH, 70 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed75MPH, 75 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed79MPH, 79 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed80MPH, 80 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed85MPH, 85 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed90MPH, 90 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed95MPH, 95 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed100MPH, 100 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed105MPH, 105 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed110MPH, 110 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed115MPH, 115 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed120MPH, 120 /* speed */, Units::Imperial},
|
||||
{SpeedMacro::Speed125MPH, 125 /* speed */, Units::Imperial},
|
||||
};
|
||||
|
||||
for (auto const & e : table)
|
||||
m_macroToSpeed[static_cast<uint8_t>(get<0>(e))] = SpeedInUnits(get<1>(e), get<2>(e));
|
||||
|
||||
ASSERT_EQUAL(static_cast<uint8_t>(SpeedMacro::Undefined), 0, ());
|
||||
m_speedToMacro.insert(make_pair(SpeedInUnits(kInvalidSpeed, Units::Metric), SpeedMacro::Undefined));
|
||||
for (size_t i = 1; i < numeric_limits<uint8_t>::max(); ++i)
|
||||
{
|
||||
auto const & speed = m_macroToSpeed[i];
|
||||
if (speed.IsValid())
|
||||
m_speedToMacro.insert(make_pair(speed, static_cast<SpeedMacro>(i)));
|
||||
}
|
||||
}
|
||||
|
||||
SpeedInUnits MaxspeedConverter::MacroToSpeed(SpeedMacro macro) const
|
||||
{
|
||||
uint8_t const m = static_cast<uint8_t>(macro);
|
||||
ASSERT_LESS(m, m_macroToSpeed.size(), ());
|
||||
return m_macroToSpeed[m];
|
||||
}
|
||||
|
||||
SpeedMacro MaxspeedConverter::SpeedToMacro(SpeedInUnits const & speed) const
|
||||
{
|
||||
auto const it = m_speedToMacro.find(speed);
|
||||
if (it == m_speedToMacro.cend())
|
||||
{
|
||||
switch (speed.GetSpeed())
|
||||
{
|
||||
case kNoneMaxSpeed: return SpeedMacro::None;
|
||||
case kWalkMaxSpeed: return SpeedMacro::Walk;
|
||||
case kCommonMaxSpeedValue: return SpeedMacro::Speed60KmPH;
|
||||
}
|
||||
|
||||
return SpeedMacro::Undefined;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
SpeedInUnits MaxspeedConverter::ClosestValidMacro(SpeedInUnits const & speed) const
|
||||
{
|
||||
auto it = m_speedToMacro.lower_bound(speed);
|
||||
if (it == m_speedToMacro.end())
|
||||
{
|
||||
--it;
|
||||
}
|
||||
else if (speed == it->first)
|
||||
{
|
||||
return speed;
|
||||
}
|
||||
else if (it != m_speedToMacro.begin())
|
||||
{
|
||||
auto it2 = it;
|
||||
--it2;
|
||||
|
||||
ASSERT(speed.GetUnits() == it->first.GetUnits() || speed.GetUnits() == it2->first.GetUnits(), ());
|
||||
auto const Diff = [&speed](SpeedInUnits const & rhs)
|
||||
{
|
||||
if (speed.GetUnits() != rhs.GetUnits())
|
||||
return std::numeric_limits<int>::max();
|
||||
return abs(int(rhs.GetSpeed()) - int(speed.GetSpeed()));
|
||||
};
|
||||
|
||||
if (Diff(it2->first) < Diff(it->first))
|
||||
it = it2;
|
||||
}
|
||||
|
||||
return it->first;
|
||||
}
|
||||
|
||||
// static
|
||||
MaxspeedConverter const & MaxspeedConverter::Instance()
|
||||
{
|
||||
static MaxspeedConverter const inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
MaxspeedConverter const & GetMaxspeedConverter()
|
||||
{
|
||||
return MaxspeedConverter::Instance();
|
||||
}
|
||||
|
||||
bool HaveSameUnits(SpeedInUnits const & lhs, SpeedInUnits const & rhs)
|
||||
{
|
||||
return lhs.GetUnits() == rhs.GetUnits() || !lhs.IsNumeric() || !rhs.IsNumeric();
|
||||
}
|
||||
|
||||
bool IsNumeric(MaxspeedType speed)
|
||||
{
|
||||
return (speed != kInvalidSpeed && speed != kNoneMaxSpeed && speed != kWalkMaxSpeed && speed != kCommonMaxSpeedValue);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string PrintMaxspeedType(MaxspeedType s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case kInvalidSpeed: return "Invalid";
|
||||
case kNoneMaxSpeed: return "None";
|
||||
case kWalkMaxSpeed: return "Walk";
|
||||
case kCommonMaxSpeedValue: return "Common";
|
||||
}
|
||||
return std::to_string(int(s));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
string DebugPrint(Maxspeed maxspeed)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "Maxspeed { m_units: " << DebugPrint(maxspeed.GetUnits())
|
||||
<< ", m_forward: " << PrintMaxspeedType(maxspeed.GetForward())
|
||||
<< ", m_backward: " << PrintMaxspeedType(maxspeed.GetBackward()) << " }";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
string DebugPrint(SpeedMacro maxspeed)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "SpeedMacro { " << static_cast<int>(maxspeed)
|
||||
<< ", decoded: " << DebugPrint(GetMaxspeedConverter().MacroToSpeed(maxspeed)) << " }";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
string DebugPrint(SpeedInUnits const & speed)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "SpeedInUnits { m_speed: " << PrintMaxspeedType(speed.GetSpeed())
|
||||
<< ", m_units: " << DebugPrint(speed.GetUnits()) << " }";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
string DebugPrint(FeatureMaxspeed const & featureMaxspeed)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "FeatureMaxspeed { m_featureId: " << featureMaxspeed.GetFeatureId()
|
||||
<< ", m_maxspeed: " << DebugPrint(featureMaxspeed.GetMaxspeed()) << " }";
|
||||
return oss.str();
|
||||
}
|
||||
} // namespace routing
|
||||
315
libs/routing_common/maxspeed_conversion.hpp
Normal file
315
libs/routing_common/maxspeed_conversion.hpp
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
#pragma once
|
||||
|
||||
#include "platform/measurement_utils.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace routing
|
||||
{
|
||||
/// \brief This enum class contains the most popular maxspeed values according to
|
||||
/// https://taginfo.openstreetmap.org/keys/maxspeed#values.
|
||||
/// \note Value of this enum is saved to mwm. So they should not be changed because of backward
|
||||
/// compatibility. But it's possible to add some new values to this enum.
|
||||
enum class SpeedMacro : uint8_t
|
||||
{
|
||||
// Special values.
|
||||
Undefined,
|
||||
None, // No maxspeed restriction (E.g. a motorway in Germany).
|
||||
Walk, // Driver should move as a walking person.
|
||||
|
||||
// Km per hour.
|
||||
Speed1KmPH = 10,
|
||||
Speed2KmPH,
|
||||
Speed3KmPH,
|
||||
Speed4KmPH,
|
||||
Speed5KmPH,
|
||||
Speed6KmPH,
|
||||
Speed7KmPH,
|
||||
Speed8KmPH,
|
||||
Speed9KmPH,
|
||||
Speed10KmPH,
|
||||
Speed11KmPH,
|
||||
Speed12KmPH,
|
||||
Speed13KmPH,
|
||||
Speed14KmPH,
|
||||
Speed15KmPH,
|
||||
Speed16KmPH,
|
||||
Speed18KmPH,
|
||||
Speed20KmPH,
|
||||
Speed22KmPH,
|
||||
Speed25KmPH,
|
||||
Speed24KmPH,
|
||||
Speed28KmPH,
|
||||
Speed30KmPH,
|
||||
Speed32KmPH,
|
||||
Speed35KmPH,
|
||||
Speed36KmPH,
|
||||
Speed39KmPH,
|
||||
Speed40KmPH,
|
||||
Speed45KmPH,
|
||||
Speed50KmPH,
|
||||
Speed55KmPH,
|
||||
Speed56KmPH,
|
||||
Speed60KmPH,
|
||||
Speed64KmPH,
|
||||
Speed65KmPH,
|
||||
Speed70KmPH,
|
||||
Speed72KmPH,
|
||||
Speed75KmPH,
|
||||
Speed80KmPH,
|
||||
Speed82KmPH,
|
||||
Speed85KmPH,
|
||||
Speed89KmPH,
|
||||
Speed90KmPH,
|
||||
Speed93KmPH,
|
||||
Speed95KmPH,
|
||||
Speed96KmPH,
|
||||
Speed100KmPH,
|
||||
Speed104KmPH,
|
||||
Speed105KmPH,
|
||||
Speed106KmPH,
|
||||
Speed110KmPH,
|
||||
Speed112KmPH,
|
||||
Speed115KmPH,
|
||||
Speed120KmPH,
|
||||
Speed125KmPH,
|
||||
Speed127KmPH,
|
||||
Speed130KmPH,
|
||||
Speed135KmPH,
|
||||
Speed140KmPH,
|
||||
Speed141KmPH,
|
||||
Speed145KmPH,
|
||||
Speed150KmPH,
|
||||
Speed155KmPH,
|
||||
Speed160KmPH,
|
||||
Speed165KmPH,
|
||||
Speed170KmPH,
|
||||
Speed177KmPH,
|
||||
Speed180KmPH,
|
||||
Speed185KmPH,
|
||||
Speed190KmPH,
|
||||
Speed193KmPH,
|
||||
Speed195KmPH,
|
||||
Speed200KmPH,
|
||||
Speed201KmPH,
|
||||
Speed210KmPH,
|
||||
Speed217KmPH,
|
||||
Speed220KmPH,
|
||||
Speed230KmPH,
|
||||
Speed240KmPH,
|
||||
Speed250KmPH,
|
||||
Speed260KmPH,
|
||||
Speed270KmPH,
|
||||
Speed275KmPH,
|
||||
Speed280KmPH,
|
||||
Speed285KmPH,
|
||||
Speed300KmPH,
|
||||
Speed305KmPH,
|
||||
Speed310KmPH,
|
||||
Speed320KmPH,
|
||||
Speed350KmPH,
|
||||
Speed380KmPH,
|
||||
|
||||
// Miles per hour.
|
||||
Speed3MPH = 110,
|
||||
Speed4MPH,
|
||||
Speed5MPH,
|
||||
Speed6MPH,
|
||||
Speed7MPH,
|
||||
Speed8MPH,
|
||||
Speed9MPH,
|
||||
Speed10MPH,
|
||||
Speed12MPH,
|
||||
Speed13MPH,
|
||||
Speed14MPH,
|
||||
Speed15MPH,
|
||||
Speed17MPH,
|
||||
Speed18MPH,
|
||||
Speed19MPH,
|
||||
Speed20MPH,
|
||||
Speed24MPH,
|
||||
Speed25MPH,
|
||||
Speed30MPH,
|
||||
Speed35MPH,
|
||||
Speed40MPH,
|
||||
Speed45MPH,
|
||||
Speed50MPH,
|
||||
Speed55MPH,
|
||||
Speed59MPH,
|
||||
Speed60MPH,
|
||||
Speed65MPH,
|
||||
Speed70MPH,
|
||||
Speed75MPH,
|
||||
Speed79MPH,
|
||||
Speed80MPH,
|
||||
Speed85MPH,
|
||||
Speed90MPH,
|
||||
Speed95MPH,
|
||||
Speed100MPH,
|
||||
Speed105MPH,
|
||||
Speed110MPH,
|
||||
Speed115MPH,
|
||||
Speed120MPH,
|
||||
Speed125MPH,
|
||||
};
|
||||
|
||||
using MaxspeedType = uint16_t;
|
||||
|
||||
MaxspeedType constexpr kInvalidSpeed = std::numeric_limits<MaxspeedType>::max();
|
||||
MaxspeedType constexpr kNoneMaxSpeed = std::numeric_limits<MaxspeedType>::max() - 1;
|
||||
MaxspeedType constexpr kWalkMaxSpeed = std::numeric_limits<MaxspeedType>::max() - 2;
|
||||
MaxspeedType constexpr kCommonMaxSpeedValue = std::numeric_limits<MaxspeedType>::max() - 3;
|
||||
|
||||
class SpeedInUnits
|
||||
{
|
||||
public:
|
||||
SpeedInUnits() = default;
|
||||
SpeedInUnits(MaxspeedType speed, measurement_utils::Units units) noexcept : m_speed(speed), m_units(units) {}
|
||||
|
||||
void SetSpeed(MaxspeedType speed) { m_speed = speed; }
|
||||
void SetUnits(measurement_utils::Units units) { m_units = units; }
|
||||
|
||||
MaxspeedType GetSpeed() const { return m_speed; }
|
||||
measurement_utils::Units GetUnits() const { return m_units; }
|
||||
|
||||
bool operator==(SpeedInUnits const & rhs) const;
|
||||
|
||||
/// @note Used as map keys compare. Doesn't make real speed comparison.
|
||||
struct Less
|
||||
{
|
||||
bool operator()(SpeedInUnits const & l, SpeedInUnits const & r) const
|
||||
{
|
||||
if (l.m_units == r.m_units)
|
||||
return l.m_speed < r.m_speed;
|
||||
return l.m_units < r.m_units;
|
||||
}
|
||||
};
|
||||
|
||||
bool IsNumeric() const;
|
||||
bool IsValid() const { return m_speed != kInvalidSpeed; }
|
||||
|
||||
/// @pre IsNumeric() == true.
|
||||
MaxspeedType GetSpeedKmPH() const;
|
||||
|
||||
private:
|
||||
// Speed in km per hour or mile per hour depends on m_units value.
|
||||
MaxspeedType m_speed = kInvalidSpeed;
|
||||
// |m_units| is undefined in case of SpeedMacro::None and SpeedMacro::Walk.
|
||||
measurement_utils::Units m_units = measurement_utils::Units::Metric;
|
||||
};
|
||||
|
||||
class Maxspeed
|
||||
{
|
||||
public:
|
||||
Maxspeed() = default;
|
||||
Maxspeed(measurement_utils::Units units, MaxspeedType forward, MaxspeedType backward);
|
||||
|
||||
bool operator==(Maxspeed const & rhs) const;
|
||||
|
||||
void SetUnits(measurement_utils::Units units) { m_units = units; }
|
||||
void SetForward(MaxspeedType forward) { m_forward = forward; }
|
||||
void SetBackward(MaxspeedType backward) { m_backward = backward; }
|
||||
|
||||
measurement_utils::Units GetUnits() const { return m_units; }
|
||||
MaxspeedType GetForward() const { return m_forward; }
|
||||
MaxspeedType GetBackward() const { return m_backward; }
|
||||
|
||||
bool IsValid() const { return m_forward != kInvalidSpeed; }
|
||||
/// \returns true if Maxspeed is considered as Bidirectional(). It means different
|
||||
/// speed is set for forward and backward direction. Otherwise returns false. It means
|
||||
/// |m_forward| speed should be used for the both directions.
|
||||
bool IsBidirectional() const { return IsValid() && m_backward != kInvalidSpeed; }
|
||||
|
||||
/// \brief returns speed according to |m_units|. |kInvalidSpeed|, |kNoneMaxSpeed| or
|
||||
/// |kWalkMaxSpeed| may be returned.
|
||||
MaxspeedType GetSpeedInUnits(bool forward) const;
|
||||
|
||||
/// \brief returns speed in km per hour. If it's not valid |kInvalidSpeed| is
|
||||
/// returned. Otherwise forward or backward speed in km per hour is returned. |kNoneMaxSpeed| and
|
||||
/// |kWalkMaxSpeed| are converted to some numbers.
|
||||
MaxspeedType GetSpeedKmPH(bool forward) const;
|
||||
|
||||
private:
|
||||
measurement_utils::Units m_units = measurement_utils::Units::Metric;
|
||||
// Speed in km per hour or mile per hour depends on |m_units|.
|
||||
MaxspeedType m_forward = kInvalidSpeed;
|
||||
// Speed in km per hour or mile per hour depends on |m_units|. If |m_backward| == kInvalidSpeed
|
||||
// |m_forward| speed should be used for the both directions.
|
||||
MaxspeedType m_backward = kInvalidSpeed;
|
||||
};
|
||||
|
||||
/// \brief Feature id and corresponding maxspeed tag value. |m_forward| and |m_backward| fields
|
||||
/// reflect the fact that a feature may have different maxspeed tag value for different directions.
|
||||
/// If |m_backward| is invalid it means that |m_forward| tag contains maxspeed for
|
||||
/// the both directions. If a feature has maxspeed forward and maxspeed backward in different units
|
||||
/// it's considered as an invalid one and it's not saved into mwm.
|
||||
class FeatureMaxspeed
|
||||
{
|
||||
public:
|
||||
FeatureMaxspeed(uint32_t fid, measurement_utils::Units units, MaxspeedType forward,
|
||||
MaxspeedType backward = kInvalidSpeed) noexcept;
|
||||
|
||||
bool operator==(FeatureMaxspeed const & rhs) const;
|
||||
|
||||
struct Less
|
||||
{
|
||||
bool operator()(FeatureMaxspeed const & l, FeatureMaxspeed const & r) const
|
||||
{
|
||||
return l.m_featureId < r.m_featureId;
|
||||
}
|
||||
bool operator()(uint32_t l, FeatureMaxspeed const & r) const { return l < r.m_featureId; }
|
||||
bool operator()(FeatureMaxspeed const & l, uint32_t r) const { return l.m_featureId < r; }
|
||||
};
|
||||
|
||||
bool IsValid() const { return m_maxspeed.IsValid(); }
|
||||
bool IsBidirectional() const { return m_maxspeed.IsBidirectional(); }
|
||||
|
||||
uint32_t GetFeatureId() const { return m_featureId; }
|
||||
Maxspeed const & GetMaxspeed() const { return m_maxspeed; }
|
||||
|
||||
SpeedInUnits GetForwardSpeedInUnits() const;
|
||||
SpeedInUnits GetBackwardSpeedInUnits() const;
|
||||
|
||||
private:
|
||||
uint32_t m_featureId = 0;
|
||||
Maxspeed m_maxspeed;
|
||||
};
|
||||
|
||||
/// \brief Generator converts real speed (SpeedInUnits) into 1-byte values for serialization (SpeedMacro),
|
||||
/// based on most used speeds (see MaxspeedConverter ctor).
|
||||
/// If you make any manipulation with speeds and want to save it, consider using ClosestValidMacro.
|
||||
class MaxspeedConverter
|
||||
{
|
||||
public:
|
||||
SpeedInUnits MacroToSpeed(SpeedMacro macro) const;
|
||||
SpeedMacro SpeedToMacro(SpeedInUnits const & speed) const;
|
||||
|
||||
SpeedInUnits ClosestValidMacro(SpeedInUnits const & speed) const;
|
||||
|
||||
static MaxspeedConverter const & Instance();
|
||||
|
||||
private:
|
||||
MaxspeedConverter();
|
||||
|
||||
std::array<SpeedInUnits, std::numeric_limits<uint8_t>::max()> m_macroToSpeed;
|
||||
std::map<SpeedInUnits, SpeedMacro, SpeedInUnits::Less> m_speedToMacro;
|
||||
};
|
||||
|
||||
MaxspeedConverter const & GetMaxspeedConverter();
|
||||
bool HaveSameUnits(SpeedInUnits const & lhs, SpeedInUnits const & rhs);
|
||||
bool IsFeatureIdLess(FeatureMaxspeed const & lhs, FeatureMaxspeed const & rhs);
|
||||
|
||||
/// \returns false if \a speed is equal to predefined values
|
||||
/// {kInvalidSpeed, kNoneMaxSpeed, kWalkMaxSpeed, kCommonMaxSpeedValue}
|
||||
/// \param speed in km per hour or mile per hour.
|
||||
bool IsNumeric(MaxspeedType speed);
|
||||
|
||||
std::string DebugPrint(Maxspeed maxspeed);
|
||||
std::string DebugPrint(SpeedMacro maxspeed);
|
||||
std::string DebugPrint(SpeedInUnits const & speed);
|
||||
std::string DebugPrint(FeatureMaxspeed const & featureMaxspeed);
|
||||
} // namespace routing
|
||||
65
libs/routing_common/num_mwm_id.hpp
Normal file
65
libs/routing_common/num_mwm_id.hpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
#include "platform/country_file.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/checked_cast.hpp"
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace routing
|
||||
{
|
||||
using NumMwmId = std::uint16_t;
|
||||
NumMwmId constexpr kFakeNumMwmId = std::numeric_limits<NumMwmId>::max();
|
||||
NumMwmId constexpr kGeneratorMwmId = 0;
|
||||
|
||||
class NumMwmIds final
|
||||
{
|
||||
public:
|
||||
bool IsEmpty() const { return m_idToFile.empty(); }
|
||||
|
||||
void RegisterFile(platform::CountryFile const & file)
|
||||
{
|
||||
if (ContainsFile(file))
|
||||
return;
|
||||
|
||||
NumMwmId const id = base::asserted_cast<NumMwmId>(m_idToFile.size());
|
||||
m_idToFile.push_back(file);
|
||||
m_fileToId[file] = id;
|
||||
|
||||
// LOG(LDEBUG, ("MWM:", file.GetName(), "=", id));
|
||||
}
|
||||
|
||||
bool ContainsFile(platform::CountryFile const & file) const { return m_fileToId.find(file) != m_fileToId.cend(); }
|
||||
|
||||
bool ContainsFileForMwm(NumMwmId mwmId) const { return mwmId < m_idToFile.size(); }
|
||||
|
||||
platform::CountryFile const & GetFile(NumMwmId mwmId) const
|
||||
{
|
||||
ASSERT_LESS(mwmId, m_idToFile.size(), ());
|
||||
return m_idToFile[mwmId];
|
||||
}
|
||||
|
||||
NumMwmId GetId(platform::CountryFile const & file) const
|
||||
{
|
||||
auto const it = m_fileToId.find(file);
|
||||
ASSERT(it != m_fileToId.cend(), ("Can't find mwm id for", file));
|
||||
return it->second;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void ForEachId(F && f) const
|
||||
{
|
||||
for (NumMwmId id = 0; id < base::asserted_cast<NumMwmId>(m_idToFile.size()); ++id)
|
||||
f(id);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<platform::CountryFile> m_idToFile;
|
||||
std::map<platform::CountryFile, NumMwmId> m_fileToId;
|
||||
};
|
||||
} // namespace routing
|
||||
231
libs/routing_common/pedestrian_model.cpp
Normal file
231
libs/routing_common/pedestrian_model.cpp
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
#include "routing_common/pedestrian_model.hpp"
|
||||
|
||||
#include "indexer/classificator.hpp"
|
||||
|
||||
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, but not listed in tables in the document. For example, steps are not listed, paths, roads and services
|
||||
// features also can be treated as ready for pedestrian routing. These road types were added to lists below.
|
||||
|
||||
// See road types here:
|
||||
// https://wiki.openstreetmap.org/wiki/Key:highway
|
||||
|
||||
// Heuristics:
|
||||
// For less pedestrian roads we add fine by setting smaller value of weight speed, and for more pedestrian roads we
|
||||
// set greater values of weight speed. Algorithm picks roads with greater speed first,
|
||||
// preferencing a more pedestrian roads over less pedestrian.
|
||||
// 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();
|
||||
|
||||
HighwayBasedSpeeds const kDefaultSpeeds = {
|
||||
// {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))},
|
||||
{HighwayType::HighwayPrimary, InOutCitySpeedKMpH(SpeedKMpH(2.0, 5.0))},
|
||||
{HighwayType::HighwayPrimaryLink, InOutCitySpeedKMpH(SpeedKMpH(2.0, 5.0))},
|
||||
{HighwayType::HighwaySecondary, InOutCitySpeedKMpH(SpeedKMpH(3.0, 5.0))},
|
||||
{HighwayType::HighwaySecondaryLink, InOutCitySpeedKMpH(SpeedKMpH(3.0, 5.0))},
|
||||
{HighwayType::HighwayTertiary, InOutCitySpeedKMpH(SpeedKMpH(4.0, 5.0))},
|
||||
{HighwayType::HighwayTertiaryLink, InOutCitySpeedKMpH(SpeedKMpH(4.0, 5.0))},
|
||||
{HighwayType::HighwayRoad, InOutCitySpeedKMpH(SpeedKMpH(4.0, 5.0))},
|
||||
|
||||
{HighwayType::HighwayService, InOutCitySpeedKMpH(SpeedKMpH(4.5, 5.0))},
|
||||
{HighwayType::HighwayUnclassified, InOutCitySpeedKMpH(SpeedKMpH(4.5, 5.0))},
|
||||
{HighwayType::HighwayResidential, InOutCitySpeedKMpH(SpeedKMpH(4.5, 5.0))},
|
||||
|
||||
{HighwayType::HighwayBridleway, InOutCitySpeedKMpH(SpeedKMpH(1.0, 5.0))},
|
||||
{HighwayType::HighwayLadder, InOutCitySpeedKMpH(SpeedKMpH(0.5))},
|
||||
{HighwayType::HighwaySteps, InOutCitySpeedKMpH(SpeedKMpH(2.5))},
|
||||
{HighwayType::HighwayCycleway, InOutCitySpeedKMpH(SpeedKMpH(4.0, 5.0))},
|
||||
|
||||
{HighwayType::HighwayTrack, InOutCitySpeedKMpH(SpeedKMpH(5.0))},
|
||||
{HighwayType::HighwayPath, InOutCitySpeedKMpH(SpeedKMpH(5.0))},
|
||||
{HighwayType::HighwayLivingStreet, InOutCitySpeedKMpH(SpeedKMpH(5.0))},
|
||||
{HighwayType::ManMadePier, InOutCitySpeedKMpH(SpeedKMpH(5.0))},
|
||||
|
||||
// Set 10% higher weight (than default 5) for foot designated ways.
|
||||
{HighwayType::HighwayPedestrian, InOutCitySpeedKMpH(SpeedKMpH(5.5, 5.0))},
|
||||
{HighwayType::HighwayFootway, InOutCitySpeedKMpH(SpeedKMpH(5.5, 5.0))},
|
||||
|
||||
/// @todo A car ferry has {10, 10}. Weight = 3 is 60% from reasonable 5 max speed.
|
||||
{HighwayType::RouteFerry, InOutCitySpeedKMpH(SpeedKMpH(3.0, 20.0))},
|
||||
};
|
||||
|
||||
// https://github.com/organicmaps/organicmaps/issues/2492
|
||||
// 3 kmph (was before) is a big default offroad speed, almost as normal walking speed.
|
||||
SpeedKMpH constexpr kSpeedOffroadKMpH = {0.5 /* weight */, 3.0 /* eta */};
|
||||
|
||||
// Default, no bridleway and cycleway
|
||||
VehicleModel::LimitsInitList const kDefaultOptions = {
|
||||
// {HighwayType, passThroughAllowed}
|
||||
{HighwayType::HighwayTrunk, true},
|
||||
{HighwayType::HighwayTrunkLink, true},
|
||||
{HighwayType::HighwayPrimary, true},
|
||||
{HighwayType::HighwayPrimaryLink, true},
|
||||
{HighwayType::HighwaySecondary, true},
|
||||
{HighwayType::HighwaySecondaryLink, true},
|
||||
{HighwayType::HighwayTertiary, true},
|
||||
{HighwayType::HighwayTertiaryLink, true},
|
||||
{HighwayType::HighwayService, true},
|
||||
{HighwayType::HighwayUnclassified, true},
|
||||
{HighwayType::HighwayRoad, true},
|
||||
{HighwayType::HighwayTrack, true},
|
||||
{HighwayType::HighwayPath, true},
|
||||
// HighwayBridleway, HighwayCycleway are missing
|
||||
{HighwayType::HighwayResidential, true},
|
||||
{HighwayType::HighwayLivingStreet, true},
|
||||
{HighwayType::HighwayLadder, true},
|
||||
{HighwayType::HighwaySteps, true},
|
||||
{HighwayType::HighwayPedestrian, true},
|
||||
{HighwayType::HighwayFootway, true},
|
||||
{HighwayType::ManMadePier, true},
|
||||
{HighwayType::RouteFerry, true}};
|
||||
|
||||
// Same as defaults except bridleway and cycleway are allowed.
|
||||
VehicleModel::LimitsInitList AllAllowed()
|
||||
{
|
||||
auto res = kDefaultOptions;
|
||||
res.push_back({HighwayType::HighwayBridleway, true});
|
||||
res.push_back({HighwayType::HighwayCycleway, true});
|
||||
return res;
|
||||
}
|
||||
|
||||
// Same as defaults except trunk and trunk link are not allowed.
|
||||
VehicleModel::LimitsInitList NoTrunk()
|
||||
{
|
||||
VehicleModel::LimitsInitList res;
|
||||
res.reserve(kDefaultOptions.size() - 2);
|
||||
for (auto const & e : kDefaultOptions)
|
||||
if (e.m_type != HighwayType::HighwayTrunk && e.m_type != HighwayType::HighwayTrunkLink)
|
||||
res.push_back(e);
|
||||
return res;
|
||||
}
|
||||
|
||||
VehicleModel::LimitsInitList YesCycleway(VehicleModel::LimitsInitList res = kDefaultOptions)
|
||||
{
|
||||
res.push_back({HighwayType::HighwayCycleway, true});
|
||||
return res;
|
||||
}
|
||||
|
||||
VehicleModel::LimitsInitList YesBridleway(VehicleModel::LimitsInitList res = kDefaultOptions)
|
||||
{
|
||||
res.push_back({HighwayType::HighwayBridleway, true});
|
||||
return res;
|
||||
}
|
||||
|
||||
/// @see Turkey_UsePrimary, Georgia_UsePrimary test.
|
||||
HighwayBasedSpeeds IncreasePrimary()
|
||||
{
|
||||
/// @todo Probably, should make Primary = Secondary = 4.
|
||||
HighwayBasedSpeeds res = pedestrian_model::kDefaultSpeeds;
|
||||
res.Replace(HighwayType::HighwayPrimary, InOutCitySpeedKMpH(SpeedKMpH(3.0, 5.0)));
|
||||
res.Replace(HighwayType::HighwayPrimaryLink, InOutCitySpeedKMpH(SpeedKMpH(3.0, 5.0)));
|
||||
return res;
|
||||
}
|
||||
|
||||
VehicleModel::SurfaceInitList const kPedestrianSurface = {
|
||||
// {{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}},
|
||||
// no dedicated sidewalk, doesn't mean that foot is not allowed, just lower weight
|
||||
{{"hwtag", "nosidewalk"}, {0.8, 0.8}},
|
||||
};
|
||||
} // namespace pedestrian_model
|
||||
|
||||
namespace routing
|
||||
{
|
||||
PedestrianModel::PedestrianModel() : PedestrianModel(pedestrian_model::kDefaultOptions) {}
|
||||
|
||||
PedestrianModel::PedestrianModel(VehicleModel::LimitsInitList const & limits)
|
||||
: PedestrianModel(limits, pedestrian_model::kDefaultSpeeds)
|
||||
{}
|
||||
|
||||
PedestrianModel::PedestrianModel(VehicleModel::LimitsInitList const & limits, HighwayBasedSpeeds const & speeds)
|
||||
: VehicleModel(classif(), limits, pedestrian_model::kPedestrianSurface, {speeds, pedestrian_model::kDefaultFactors})
|
||||
{
|
||||
using namespace pedestrian_model;
|
||||
|
||||
// No bridleway and cycleway in default.
|
||||
ASSERT_EQUAL(kDefaultOptions.size(), kDefaultSpeeds.size() - 2, ());
|
||||
|
||||
std::vector<std::string> hwtagYesFoot = {"hwtag", "yesfoot"};
|
||||
auto const & cl = classif();
|
||||
|
||||
m_noType = cl.GetTypeByPath({"hwtag", "nofoot"});
|
||||
m_yesType = cl.GetTypeByPath(hwtagYesFoot);
|
||||
|
||||
AddAdditionalRoadTypes(cl, {{std::move(hwtagYesFoot), kDefaultSpeeds.Get(HighwayType::HighwayLivingStreet)}});
|
||||
|
||||
// Update max pedestrian speed with possible ferry transfer. See EdgeEstimator::CalcHeuristic.
|
||||
SpeedKMpH constexpr kMaxPedestrianSpeedKMpH(60.0);
|
||||
CHECK_LESS(m_maxModelSpeed, kMaxPedestrianSpeedKMpH, ());
|
||||
m_maxModelSpeed = kMaxPedestrianSpeedKMpH;
|
||||
}
|
||||
|
||||
SpeedKMpH PedestrianModel::GetSpeed(FeatureTypes const & types, SpeedParams const & speedParams) const
|
||||
{
|
||||
return GetTypeSpeedImpl(types, speedParams, false /* isCar */);
|
||||
}
|
||||
|
||||
SpeedKMpH const & PedestrianModel::GetOffroadSpeed() const
|
||||
{
|
||||
return pedestrian_model::kSpeedOffroadKMpH;
|
||||
}
|
||||
|
||||
// If one of feature types will be disabled for pedestrian, features of this type will be simplyfied
|
||||
// in generator. Look FeatureBuilder1::IsRoad() for more details.
|
||||
// static
|
||||
PedestrianModel const & PedestrianModel::AllLimitsInstance()
|
||||
{
|
||||
static PedestrianModel const instance(pedestrian_model::AllAllowed());
|
||||
return instance;
|
||||
}
|
||||
|
||||
PedestrianModelFactory::PedestrianModelFactory(CountryParentNameGetterFn const & countryParentNameGetterFn)
|
||||
: VehicleModelFactory(countryParentNameGetterFn)
|
||||
{
|
||||
using namespace pedestrian_model;
|
||||
using std::make_shared;
|
||||
|
||||
// Names must be the same with country names from countries.txt
|
||||
m_models[""] = make_shared<PedestrianModel>(kDefaultOptions);
|
||||
|
||||
m_models["Australia"] = make_shared<PedestrianModel>(AllAllowed());
|
||||
m_models["Austria"] = make_shared<PedestrianModel>(NoTrunk());
|
||||
m_models["Belarus"] = make_shared<PedestrianModel>(YesCycleway());
|
||||
m_models["Belgium"] = make_shared<PedestrianModel>(YesCycleway(YesBridleway(NoTrunk())));
|
||||
m_models["Brazil"] = make_shared<PedestrianModel>(YesBridleway());
|
||||
m_models["Denmark"] = make_shared<PedestrianModel>(YesCycleway(NoTrunk()));
|
||||
m_models["France"] = make_shared<PedestrianModel>(NoTrunk());
|
||||
m_models["Finland"] = make_shared<PedestrianModel>(YesCycleway());
|
||||
m_models["Georgia"] = make_shared<PedestrianModel>(AllAllowed(), IncreasePrimary());
|
||||
m_models["Greece"] = make_shared<PedestrianModel>(YesCycleway(YesBridleway(NoTrunk())));
|
||||
m_models["Hungary"] = make_shared<PedestrianModel>(NoTrunk());
|
||||
m_models["Iceland"] = make_shared<PedestrianModel>(AllAllowed());
|
||||
m_models["Ireland"] = make_shared<PedestrianModel>(AllAllowed());
|
||||
m_models["Netherlands"] = make_shared<PedestrianModel>(YesCycleway(NoTrunk()));
|
||||
m_models["Norway"] = make_shared<PedestrianModel>(AllAllowed());
|
||||
m_models["Oman"] = make_shared<PedestrianModel>(AllAllowed());
|
||||
m_models["Philippines"] = make_shared<PedestrianModel>(AllAllowed());
|
||||
m_models["Poland"] = make_shared<PedestrianModel>(YesBridleway(NoTrunk()));
|
||||
m_models["Romania"] = make_shared<PedestrianModel>(YesBridleway());
|
||||
m_models["Russian Federation"] = make_shared<PedestrianModel>(YesCycleway());
|
||||
m_models["Slovakia"] = make_shared<PedestrianModel>(NoTrunk());
|
||||
m_models["Spain"] = make_shared<PedestrianModel>(NoTrunk());
|
||||
m_models["Sweden"] = make_shared<PedestrianModel>(AllAllowed());
|
||||
m_models["Switzerland"] = make_shared<PedestrianModel>(NoTrunk());
|
||||
m_models["Turkey"] = make_shared<PedestrianModel>(AllAllowed(), IncreasePrimary());
|
||||
m_models["Ukraine"] = make_shared<PedestrianModel>(NoTrunk());
|
||||
m_models["United Kingdom"] = make_shared<PedestrianModel>(AllAllowed());
|
||||
m_models["United States of America"] = make_shared<PedestrianModel>(AllAllowed());
|
||||
}
|
||||
} // namespace routing
|
||||
30
libs/routing_common/pedestrian_model.hpp
Normal file
30
libs/routing_common/pedestrian_model.hpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "routing_common/vehicle_model.hpp"
|
||||
|
||||
namespace routing
|
||||
{
|
||||
|
||||
class PedestrianModel : public VehicleModel
|
||||
{
|
||||
public:
|
||||
PedestrianModel();
|
||||
explicit PedestrianModel(VehicleModel::LimitsInitList const & speedLimits);
|
||||
PedestrianModel(VehicleModel::LimitsInitList const & limits, HighwayBasedSpeeds const & speeds);
|
||||
|
||||
/// VehicleModelInterface overrides:
|
||||
SpeedKMpH GetSpeed(FeatureTypes const & types, SpeedParams const & speedParams) const override;
|
||||
bool IsOneWay(FeatureTypes const &) const override { return false; }
|
||||
SpeedKMpH const & GetOffroadSpeed() const override;
|
||||
|
||||
static PedestrianModel const & AllLimitsInstance();
|
||||
};
|
||||
|
||||
class PedestrianModelFactory : public VehicleModelFactory
|
||||
{
|
||||
public:
|
||||
// TODO: remove countryParentNameGetterFn default value after removing unused pedestrian routing
|
||||
// from road_graph_router
|
||||
PedestrianModelFactory(CountryParentNameGetterFn const & countryParentNameGetterFn = {});
|
||||
};
|
||||
} // namespace routing
|
||||
14
libs/routing_common/routing_common_tests/CMakeLists.txt
Normal file
14
libs/routing_common/routing_common_tests/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
project(routing_common_tests)
|
||||
|
||||
set(SRC
|
||||
bicycle_model_test.cpp
|
||||
vehicle_model_for_country_test.cpp
|
||||
vehicle_model_test.cpp
|
||||
)
|
||||
|
||||
omim_add_test(${PROJECT_NAME} ${SRC})
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
indexer
|
||||
routing_common
|
||||
)
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "routing_common/bicycle_model.hpp"
|
||||
|
||||
#include "indexer/classificator.hpp"
|
||||
#include "indexer/classificator_loader.hpp"
|
||||
#include "indexer/feature_data.hpp"
|
||||
|
||||
namespace bicycle_model_test
|
||||
{
|
||||
using namespace routing;
|
||||
|
||||
class BicycleModelTest
|
||||
{
|
||||
public:
|
||||
BicycleModelTest() { classificator::Load(); }
|
||||
|
||||
std::shared_ptr<VehicleModel> GetModel(std::string const & country)
|
||||
{
|
||||
return std::dynamic_pointer_cast<VehicleModel>(BicycleModelFactory().GetVehicleModelForCountry(country));
|
||||
}
|
||||
|
||||
SpeedParams DefaultSpeedParams() { return {true /* forward */, true /* isCity */, Maxspeed()}; }
|
||||
};
|
||||
|
||||
UNIT_CLASS_TEST(BicycleModelTest, Turkey)
|
||||
{
|
||||
auto const model = GetModel("Turkey");
|
||||
TEST(model, ());
|
||||
auto const & cl = classif();
|
||||
|
||||
feature::TypesHolder holder;
|
||||
holder.Add(cl.GetTypeByPath({"highway", "footway", "tunnel"}));
|
||||
|
||||
TEST(model->HasRoadType(holder), ());
|
||||
TEST_EQUAL(model->GetSpeed(holder, DefaultSpeedParams()), BicycleModel::DismountSpeed(), ());
|
||||
}
|
||||
|
||||
} // namespace bicycle_model_test
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "routing_common/bicycle_model.hpp"
|
||||
#include "routing_common/car_model.hpp"
|
||||
#include "routing_common/pedestrian_model.hpp"
|
||||
|
||||
#include "indexer/classificator_loader.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace vehicle_model_for_country_test
|
||||
{
|
||||
using namespace routing;
|
||||
using namespace std;
|
||||
|
||||
class VehicleModelForCountryTest
|
||||
{
|
||||
public:
|
||||
VehicleModelForCountryTest() { classificator::Load(); }
|
||||
};
|
||||
|
||||
string GetRegionParent(string const & id)
|
||||
{
|
||||
if (id == "Moscow")
|
||||
return "Russian Federation";
|
||||
if (id == "Munich")
|
||||
return "Bavaria";
|
||||
if (id == "Bavaria")
|
||||
return "Germany";
|
||||
if (id == "San Francisco")
|
||||
return "California";
|
||||
if (id == "California")
|
||||
return "United States of America";
|
||||
return "";
|
||||
}
|
||||
|
||||
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."));
|
||||
}
|
||||
|
||||
// DirectParent and IndirectParent tests require tested countries to have nondefault restriction
|
||||
// If selected countries will change their restrictions to default, select other countries for tests
|
||||
template <typename VehicleModelType, typename VehicleModelFactoryType>
|
||||
void TestHaveNondefaultRestrictionForSelectedCountry(string country)
|
||||
{
|
||||
auto defaultVehicleModel = make_shared<VehicleModelType>();
|
||||
|
||||
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."));
|
||||
}
|
||||
|
||||
template <typename VehicleModelType, typename VehicleModelFactoryType>
|
||||
void ParentTest(string child, string parent)
|
||||
{
|
||||
VehicleModelFactoryType vehicleModelFactory = VehicleModelFactoryType(GetRegionParent);
|
||||
|
||||
shared_ptr<VehicleModelType> vehicleModelChild =
|
||||
static_pointer_cast<VehicleModelType>(vehicleModelFactory.GetVehicleModelForCountry(child));
|
||||
shared_ptr<VehicleModelType> vehicleModelParent =
|
||||
static_pointer_cast<VehicleModelType>(vehicleModelFactory.GetVehicleModelForCountry(parent));
|
||||
|
||||
TEST(vehicleModelChild->EqualsForTests(*vehicleModelParent), ("Can not expand car model for", child, "to", parent));
|
||||
}
|
||||
|
||||
// Test we have default vehicle models for nonexistent(unknown) country
|
||||
UNIT_CLASS_TEST(VehicleModelForCountryTest, CarModel_Default)
|
||||
{
|
||||
TestVehicleModelDefault<CarModel, CarModelFactory>();
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelForCountryTest, BicycleModel_Default)
|
||||
{
|
||||
TestVehicleModelDefault<BicycleModel, BicycleModelFactory>();
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelForCountryTest, PedestrianModel_Default)
|
||||
{
|
||||
TestVehicleModelDefault<PedestrianModel, PedestrianModelFactory>();
|
||||
}
|
||||
|
||||
// 1. Test we have nondefault car model for Russia
|
||||
// 2. Test we can get car model for Moscow using GetRegionParent callback: car model for Moscow equals
|
||||
// car model for Russia and it's not default model.
|
||||
UNIT_CLASS_TEST(VehicleModelForCountryTest, CarModel_DirectParent)
|
||||
{
|
||||
TestHaveNondefaultRestrictionForSelectedCountry<CarModel, CarModelFactory>("Russian Federation");
|
||||
ParentTest<CarModel, CarModelFactory>("Moscow", "Russian Federation");
|
||||
}
|
||||
|
||||
// 1. Test we have nondefault bicycle model for Russia
|
||||
// 2. Test we can get bicycle model for Moscow using GetRegionParent callback: bicycle model for Moscow
|
||||
// equals bicycle model for Russia and it's not default model.
|
||||
UNIT_CLASS_TEST(VehicleModelForCountryTest, BicycleModel_DirectParent)
|
||||
{
|
||||
// Road types for RF are equal with defaults (speeds are not compared).
|
||||
// TestHaveNondefaultRestrictionForSelectedCountry<BicycleModel, BicycleModelFactory>("Russian Federation");
|
||||
ParentTest<BicycleModel, BicycleModelFactory>("Moscow", "Russian Federation");
|
||||
}
|
||||
|
||||
// 1. Test we have nondefault pedestrian model for Russia
|
||||
// 2. Test we can get pedestrian model for Moscow using GetRegionParent callback: pedestrian model for
|
||||
// Moscow equals pedestrian model for Russia and it's not default model.
|
||||
UNIT_CLASS_TEST(VehicleModelForCountryTest, PedestrianModel_DirectParent)
|
||||
{
|
||||
TestHaveNondefaultRestrictionForSelectedCountry<PedestrianModel, PedestrianModelFactory>("Russian Federation");
|
||||
ParentTest<PedestrianModel, PedestrianModelFactory>("Moscow", "Russian Federation");
|
||||
}
|
||||
|
||||
// Test has the same idea as previous one except Germany is not direct parent of Munich
|
||||
// in GetRegionParent function: Munich -> Bavaria -> Germany
|
||||
UNIT_CLASS_TEST(VehicleModelForCountryTest, CarModel_InirectParent)
|
||||
{
|
||||
TestHaveNondefaultRestrictionForSelectedCountry<CarModel, CarModelFactory>("Germany");
|
||||
ParentTest<CarModel, CarModelFactory>("Munich", "Germany");
|
||||
}
|
||||
|
||||
// Test has the same idea as previous one except United States of America are not direct parent of
|
||||
// San Francisco in GetRegionParent function: San Francisco -> California -> United States of America
|
||||
UNIT_CLASS_TEST(VehicleModelForCountryTest, BicycleModel_IndirectParent)
|
||||
{
|
||||
TestHaveNondefaultRestrictionForSelectedCountry<BicycleModel, BicycleModelFactory>("United States of America");
|
||||
ParentTest<BicycleModel, BicycleModelFactory>("San Francisco", "United States of America");
|
||||
}
|
||||
|
||||
// Test has the same idea as previous one except United States of America are not direct parent of
|
||||
// San Francisco in GetRegionParent function: San Francisco -> California -> United States of America
|
||||
UNIT_CLASS_TEST(VehicleModelForCountryTest, PedestrianModel_IndirectParent)
|
||||
{
|
||||
TestHaveNondefaultRestrictionForSelectedCountry<PedestrianModel, PedestrianModelFactory>("United States of America");
|
||||
ParentTest<PedestrianModel, PedestrianModelFactory>("San Francisco", "United States of America");
|
||||
}
|
||||
} // namespace vehicle_model_for_country_test
|
||||
504
libs/routing_common/routing_common_tests/vehicle_model_test.cpp
Normal file
504
libs/routing_common/routing_common_tests/vehicle_model_test.cpp
Normal file
|
|
@ -0,0 +1,504 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "routing_common/bicycle_model.hpp"
|
||||
#include "routing_common/car_model.hpp"
|
||||
#include "routing_common/car_model_coefs.hpp"
|
||||
#include "routing_common/maxspeed_conversion.hpp"
|
||||
#include "routing_common/pedestrian_model.hpp"
|
||||
#include "routing_common/vehicle_model.hpp"
|
||||
|
||||
#include "indexer/classificator.hpp"
|
||||
#include "indexer/classificator_loader.hpp"
|
||||
#include "indexer/feature_data.hpp"
|
||||
|
||||
#include "platform/measurement_utils.hpp"
|
||||
|
||||
#include "base/math.hpp"
|
||||
|
||||
namespace vehicle_model_test
|
||||
{
|
||||
using namespace routing;
|
||||
using namespace std;
|
||||
|
||||
HighwayBasedSpeeds 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,
|
||||
InOutCitySpeedKMpH(SpeedKMpH(80.0 /* weight */, 70.0 /* eta */) /* in and out city*/)},
|
||||
{HighwayType::HighwayResidential, InOutCitySpeedKMpH(SpeedKMpH(45.0 /* weight */, 55.0 /* eta */) /* in city */,
|
||||
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 */)}};
|
||||
|
||||
HighwayBasedFactors const kDefaultFactors = {{HighwayType::HighwayTrunk, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayPrimary, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwaySecondary, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayResidential, InOutCityFactor(0.5)}};
|
||||
|
||||
VehicleModel::LimitsInitList const kTestLimits = {{HighwayType::HighwayTrunk, true},
|
||||
{HighwayType::HighwayPrimary, true},
|
||||
{HighwayType::HighwaySecondary, true},
|
||||
{HighwayType::HighwayResidential, true},
|
||||
{HighwayType::HighwayService, false}};
|
||||
|
||||
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}}};
|
||||
|
||||
class VehicleModelTest
|
||||
{
|
||||
public:
|
||||
VehicleModelTest()
|
||||
{
|
||||
classificator::Load();
|
||||
auto const & c = classif();
|
||||
|
||||
primary = c.GetTypeByPath({"highway", "primary"});
|
||||
secondary = c.GetTypeByPath({"highway", "secondary"});
|
||||
secondaryBridge = c.GetTypeByPath({"highway", "secondary", "bridge"});
|
||||
secondaryTunnel = c.GetTypeByPath({"highway", "secondary", "tunnel"});
|
||||
residential = c.GetTypeByPath({"highway", "residential"});
|
||||
|
||||
path = c.GetTypeByPath({"highway", "path"});
|
||||
footway = c.GetTypeByPath({"highway", "footway"});
|
||||
cycleway = c.GetTypeByPath({"highway", "cycleway"});
|
||||
yesBicycle = c.GetTypeByPath({"hwtag", "yesbicycle"});
|
||||
yesFoot = c.GetTypeByPath({"hwtag", "yesfoot"});
|
||||
|
||||
oneway = c.GetTypeByPath({"hwtag", "oneway"});
|
||||
pavedGood = c.GetTypeByPath({"psurface", "paved_good"});
|
||||
pavedBad = c.GetTypeByPath({"psurface", "paved_bad"});
|
||||
unpavedGood = c.GetTypeByPath({"psurface", "unpaved_good"});
|
||||
unpavedBad = c.GetTypeByPath({"psurface", "unpaved_bad"});
|
||||
}
|
||||
|
||||
uint32_t primary, secondary, secondaryTunnel, secondaryBridge, residential;
|
||||
uint32_t path, footway, cycleway, yesBicycle, yesFoot;
|
||||
uint32_t oneway, pavedGood, pavedBad, unpavedGood, unpavedBad;
|
||||
|
||||
static SpeedParams DefaultParams() { return {{}, kInvalidSpeed, false /* inCity */}; }
|
||||
};
|
||||
|
||||
class VehicleModelStub : public VehicleModel
|
||||
{
|
||||
public:
|
||||
VehicleModelStub() : VehicleModel(classif(), kTestLimits, kCarSurface, {kDefaultSpeeds, kDefaultFactors}) {}
|
||||
|
||||
SpeedKMpH GetSpeed(feature::TypesHolder const & types, SpeedParams const & params) const override
|
||||
{
|
||||
return GetTypeSpeedImpl(types, params, true /* isCar */);
|
||||
}
|
||||
|
||||
// We are not going to use offroad routing in these tests.
|
||||
SpeedKMpH const & GetOffroadSpeed() const override
|
||||
{
|
||||
static SpeedKMpH offroad{0.0 /* weight */, 0.0 /* eta */};
|
||||
return offroad;
|
||||
}
|
||||
};
|
||||
|
||||
void CheckSpeedWithParams(initializer_list<uint32_t> const & types, SpeedParams const & params,
|
||||
SpeedKMpH const & expectedSpeed)
|
||||
{
|
||||
VehicleModelStub model;
|
||||
feature::TypesHolder h;
|
||||
for (uint32_t t : types)
|
||||
h.Add(t);
|
||||
|
||||
TEST_EQUAL(model.GetSpeed(h, params), expectedSpeed, ());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void CheckOneWay(initializer_list<uint32_t> const & types, bool expectedValue)
|
||||
{
|
||||
VehicleModelStub model;
|
||||
feature::TypesHolder h;
|
||||
for (uint32_t t : types)
|
||||
h.Add(t);
|
||||
|
||||
TEST_EQUAL(model.IsOneWay(h), expectedValue, ());
|
||||
}
|
||||
|
||||
void CheckPassThroughAllowed(initializer_list<uint32_t> const & types, bool expectedValue)
|
||||
{
|
||||
VehicleModelStub model;
|
||||
feature::TypesHolder h;
|
||||
for (uint32_t t : types)
|
||||
h.Add(t);
|
||||
|
||||
TEST_EQUAL(model.IsPassThroughAllowed(h), expectedValue, ());
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelStub, MaxSpeed)
|
||||
{
|
||||
TEST_EQUAL(GetMaxWeightSpeed(), 150.0, ());
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelTest, Speed)
|
||||
{
|
||||
{
|
||||
CheckSpeed({secondaryBridge}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
|
||||
CheckSpeed({secondaryTunnel}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
|
||||
CheckSpeed({secondary}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
|
||||
}
|
||||
|
||||
CheckSpeed({classif().GetTypeByPath({"highway", "trunk"})},
|
||||
{SpeedKMpH(100.0 /* weight */, 100.0 /* eta */) /* in city */,
|
||||
SpeedKMpH(150.0 /* weight */, 150.0 /* eta */) /* out of city */});
|
||||
CheckSpeed({primary}, {SpeedKMpH(90.0, 90.0), SpeedKMpH(120.0, 120.0)});
|
||||
CheckSpeed({residential}, {SpeedKMpH(22.5, 27.5), SpeedKMpH(25.0, 30.0)});
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelTest, Speed_MultiTypes)
|
||||
{
|
||||
uint32_t const typeHighway = classif().GetTypeByPath({"highway"});
|
||||
|
||||
CheckSpeed({secondaryTunnel, secondary}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
|
||||
CheckSpeed({secondaryTunnel, typeHighway}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
|
||||
CheckSpeed({typeHighway, secondaryTunnel}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelTest, OneWay)
|
||||
{
|
||||
CheckSpeed({secondaryBridge, oneway}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
|
||||
CheckOneWay({secondaryBridge, oneway}, true);
|
||||
CheckSpeed({oneway, secondaryBridge}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
|
||||
CheckOneWay({oneway, secondaryBridge}, true);
|
||||
|
||||
CheckOneWay({oneway}, true);
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelTest, DifferentSpeeds)
|
||||
{
|
||||
// What is the purpose of this artificial test with several highway types? To show that order is important?
|
||||
CheckSpeed({secondary, primary}, kDefaultSpeeds.Get(HighwayType::HighwaySecondary));
|
||||
CheckSpeed({oneway, primary, secondary}, kDefaultSpeeds.Get(HighwayType::HighwayPrimary));
|
||||
CheckOneWay({primary, oneway, secondary}, true);
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelTest, PassThroughAllowed)
|
||||
{
|
||||
CheckPassThroughAllowed({secondary}, true);
|
||||
CheckPassThroughAllowed({primary}, true);
|
||||
CheckPassThroughAllowed({classif().GetTypeByPath({"highway", "service"})}, false);
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelTest, SpeedFactor)
|
||||
{
|
||||
CheckSpeed({secondary, pavedGood}, {SpeedKMpH(64.0 /* weight */, 63.0 /* eta */) /* in city */,
|
||||
SpeedKMpH(64.0 /* weight */, 63.0 /* eta */) /* out of city */});
|
||||
CheckSpeed({secondary, pavedBad}, {SpeedKMpH(32.0, 35.0), SpeedKMpH(32.0, 35.0)});
|
||||
CheckSpeed({secondary, unpavedGood}, {SpeedKMpH(48.0, 56.0), SpeedKMpH(48.0, 56.0)});
|
||||
CheckSpeed({secondary, unpavedBad}, {SpeedKMpH(16.0, 14.0), SpeedKMpH(16.0, 14.0)});
|
||||
|
||||
CheckSpeed({residential, pavedGood}, {SpeedKMpH(18.0, 24.75), SpeedKMpH(20.0, 27.0)});
|
||||
CheckSpeed({residential, pavedBad}, {SpeedKMpH(9.0, 13.75), SpeedKMpH(10.0, 15.0)});
|
||||
CheckSpeed({residential, unpavedGood}, {SpeedKMpH(13.5, 22.0), SpeedKMpH(15.0, 24.0)});
|
||||
CheckSpeed({residential, unpavedBad}, {SpeedKMpH(4.5, 5.5), SpeedKMpH(5.0, 6.0)});
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelTest, MaxspeedFactor)
|
||||
{
|
||||
auto constexpr units = measurement_utils::Units::Metric;
|
||||
|
||||
Maxspeed const maxspeed90 = Maxspeed(units, 90, kInvalidSpeed);
|
||||
|
||||
// pavedBad == unpavedBad for the roads with explicitly defined speeds.
|
||||
CheckSpeedWithParams({secondary, unpavedBad}, SpeedParams(true /* forward */, false /* in city */, maxspeed90),
|
||||
SpeedKMpH(36.0, 45.0));
|
||||
CheckSpeedWithParams({secondary, pavedBad}, SpeedParams(true /* forward */, false /* in city */, maxspeed90),
|
||||
SpeedKMpH(36.0, 45.0));
|
||||
|
||||
CheckSpeedWithParams({primary, pavedGood}, SpeedParams(true /* forward */, false /* in city */, maxspeed90),
|
||||
SpeedKMpH(72.0, 81.0));
|
||||
|
||||
Maxspeed const maxspeed9070 = Maxspeed(units, 90, 70);
|
||||
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));
|
||||
|
||||
Maxspeed const maxspeed60 = Maxspeed(units, 60, kInvalidSpeed);
|
||||
CheckSpeedWithParams({residential, pavedGood}, SpeedParams(true /* forward */, false /* in city */, maxspeed60),
|
||||
SpeedKMpH(24.0, 27.0));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool LessSpeed(SpeedKMpH const & l, SpeedKMpH const & r)
|
||||
{
|
||||
TEST(l.IsValid() && r.IsValid(), (l, r));
|
||||
// Weight should be strict less, ETA may be equal.
|
||||
return l.m_weight < r.m_weight && l.m_eta <= r.m_eta;
|
||||
}
|
||||
|
||||
#define TEST_LESS_SPEED(l, r) TEST(LessSpeed(l, r), (l, r))
|
||||
|
||||
bool LessOrEqualSpeed(SpeedKMpH const & l, SpeedKMpH const & r)
|
||||
{
|
||||
TEST(l.IsValid() && r.IsValid(), (l, r));
|
||||
return l.m_weight <= r.m_weight;
|
||||
}
|
||||
|
||||
#define TEST_LESS_OR_EQUAL_SPEED(l, r) TEST(LessOrEqualSpeed(l, r), (l, r))
|
||||
} // namespace
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelTest, CarModel_TrackVsGravelTertiary)
|
||||
{
|
||||
auto const & model = CarModel::AllLimitsInstance();
|
||||
auto const & c = classif();
|
||||
auto const p = DefaultParams();
|
||||
|
||||
feature::TypesHolder h1;
|
||||
h1.Add(c.GetTypeByPath({"highway", "track"}));
|
||||
|
||||
feature::TypesHolder h2;
|
||||
h2.Add(c.GetTypeByPath({"highway", "tertiary"}));
|
||||
h2.Add(unpavedBad); // from OSM surface=gravel
|
||||
|
||||
// https://www.openstreetmap.org/#map=19/45.43640/36.39689
|
||||
// Obvious that gravel tertiary (moreover with maxspeed=60kmh) should be better than track.
|
||||
|
||||
{
|
||||
SpeedParams p2({measurement_utils::Units::Metric, 60, 60}, kInvalidSpeed, false /* inCity */);
|
||||
TEST_LESS_SPEED(model.GetSpeed(h1, p), model.GetSpeed(h2, p2));
|
||||
}
|
||||
|
||||
{
|
||||
TEST_LESS_SPEED(model.GetSpeed(h1, p), model.GetSpeed(h2, p));
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelTest, CarModel_Smoke)
|
||||
{
|
||||
auto const & model = CarModel::AllLimitsInstance();
|
||||
auto const & c = classif();
|
||||
auto const p = DefaultParams();
|
||||
|
||||
feature::TypesHolder h1;
|
||||
h1.Add(secondary);
|
||||
|
||||
feature::TypesHolder h2;
|
||||
h2.Add(secondary);
|
||||
h2.Add(c.GetTypeByPath({"hwtag", "yescar"}));
|
||||
|
||||
feature::TypesHolder h3;
|
||||
h3.Add(c.GetTypeByPath({"highway", "tertiary"}));
|
||||
|
||||
TEST_EQUAL(model.GetSpeed(h1, p), model.GetSpeed(h2, p), ());
|
||||
TEST_LESS_SPEED(model.GetSpeed(h3, p), model.GetSpeed(h2, p));
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelTest, BicycleModel_Smoke)
|
||||
{
|
||||
auto const & model = BicycleModel::AllLimitsInstance();
|
||||
auto const & c = classif();
|
||||
auto const p = DefaultParams();
|
||||
|
||||
feature::TypesHolder h1;
|
||||
h1.Add(cycleway);
|
||||
h1.Add(yesBicycle);
|
||||
|
||||
feature::TypesHolder h2;
|
||||
h2.Add(cycleway);
|
||||
|
||||
feature::TypesHolder h3;
|
||||
h3.Add(secondary);
|
||||
h3.Add(yesBicycle);
|
||||
|
||||
feature::TypesHolder h4;
|
||||
h4.Add(secondary);
|
||||
|
||||
feature::TypesHolder h5;
|
||||
h5.Add(secondary);
|
||||
h5.Add(c.GetTypeByPath({"hwtag", "nocycleway"}));
|
||||
|
||||
TEST_EQUAL(model.GetSpeed(h1, p), model.GetSpeed(h2, p), ());
|
||||
TEST_LESS_SPEED(model.GetSpeed(h3, p), model.GetSpeed(h2, p));
|
||||
TEST_LESS_SPEED(model.GetSpeed(h4, p), model.GetSpeed(h3, p));
|
||||
TEST_LESS_SPEED(model.GetSpeed(h5, p), model.GetSpeed(h4, p));
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelTest, BicycleModel_Speeds)
|
||||
{
|
||||
auto const & model = BicycleModel::AllLimitsInstance();
|
||||
auto const p = DefaultParams();
|
||||
|
||||
std::vector<std::vector<uint32_t>> const highways = {
|
||||
{cycleway, pavedGood}, // TODO: should be higher than next, but is equal
|
||||
{cycleway},
|
||||
{cycleway, unpavedGood}, // TODO: should be lower than previous, but is equal
|
||||
{footway, yesBicycle, pavedGood}, // TODO: should be higher than next, but is equal
|
||||
{footway, yesBicycle},
|
||||
{path,
|
||||
yesBicycle}, // TODO: unpaved by default, so should be lower than shared footways or cycleways, but is equal
|
||||
{cycleway, pavedBad},
|
||||
{footway, yesBicycle, pavedBad},
|
||||
{footway}, // If allowed in the region.
|
||||
{cycleway, unpavedBad},
|
||||
{path, unpavedGood}, // Its controversial what is preferrable: a good path or a bad cycleway
|
||||
{path, yesBicycle, unpavedBad},
|
||||
/// @todo(pastk): "nobicycle" is ignored in speed calculation atm, the routing is just forbidden there.
|
||||
/// But "nobicycle" should result in a dismount speed instead, see
|
||||
/// https://github.com/organicmaps/organicmaps/issues/9784
|
||||
// {footway, c.GetTypeByPath({"hwtag", "nobicycle"})},
|
||||
// {path, c.GetTypeByPath({"hwtag", "nobicycle"})},
|
||||
{path, unpavedBad},
|
||||
};
|
||||
|
||||
feature::TypesHolder hprev;
|
||||
for (size_t i = 0; i < highways.size(); ++i)
|
||||
{
|
||||
feature::TypesHolder h;
|
||||
for (uint32_t t : highways[i])
|
||||
h.Add(t);
|
||||
LOG(LINFO, (h, model.GetSpeed(h, p)));
|
||||
|
||||
if (i > 0)
|
||||
TEST_LESS_OR_EQUAL_SPEED(model.GetSpeed(h, p), model.GetSpeed(hprev, p));
|
||||
hprev = h;
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelTest, PedestrianModel_Smoke)
|
||||
{
|
||||
auto const & model = PedestrianModel::AllLimitsInstance();
|
||||
auto const & c = classif();
|
||||
auto const p = DefaultParams();
|
||||
|
||||
feature::TypesHolder h1;
|
||||
h1.Add(residential);
|
||||
h1.Add(c.GetTypeByPath({"hwtag", "yesfoot"}));
|
||||
|
||||
feature::TypesHolder h2;
|
||||
h2.Add(residential);
|
||||
|
||||
feature::TypesHolder h3;
|
||||
h3.Add(residential);
|
||||
h3.Add(c.GetTypeByPath({"hwtag", "nosidewalk"}));
|
||||
|
||||
TEST_LESS_SPEED(model.GetSpeed(h2, p), model.GetSpeed(h1, p));
|
||||
TEST_LESS_SPEED(model.GetSpeed(h3, p), model.GetSpeed(h2, p));
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(VehicleModelTest, PedestrianModel_Speeds)
|
||||
{
|
||||
auto const & model = PedestrianModel::AllLimitsInstance();
|
||||
// auto const & c = classif();
|
||||
auto const p = DefaultParams();
|
||||
|
||||
std::vector<std::vector<uint32_t>> const highways = {
|
||||
{footway, pavedGood}, // TODO: should be higher than next, but is equal
|
||||
{footway},
|
||||
{footway, pavedBad}, // TODO: should be lower than previous, but is equal
|
||||
{footway, yesBicycle}, // TODO: should be lower than previous, but is equal
|
||||
{path, yesFoot}, // TODO: should be higher than previous, but is equal
|
||||
{path, unpavedGood}, // TODO: should be lower than previous, but is equal
|
||||
{path, yesBicycle}, // TODO: should be lower than previous, but is equal
|
||||
{cycleway},
|
||||
{path, unpavedBad},
|
||||
{cycleway, unpavedBad},
|
||||
// {path, c.GetTypeByPath({"hwtag", "nofoot"})}, // TODO: should be forbidden, but has no effect ATM
|
||||
// {cycleway, c.GetTypeByPath({"hwtag", "nofoot"})}, // TODO: should be forbidden, but has no effect ATM
|
||||
};
|
||||
|
||||
feature::TypesHolder hprev;
|
||||
for (size_t i = 0; i < highways.size(); ++i)
|
||||
{
|
||||
feature::TypesHolder h;
|
||||
for (uint32_t t : highways[i])
|
||||
h.Add(t);
|
||||
LOG(LINFO, (h, model.GetSpeed(h, p)));
|
||||
|
||||
if (i > 0)
|
||||
TEST_LESS_OR_EQUAL_SPEED(model.GetSpeed(h, p), model.GetSpeed(hprev, p));
|
||||
hprev = h;
|
||||
}
|
||||
}
|
||||
|
||||
#undef TEST_LESS_SPEED
|
||||
#undef TEST_LESS_OR_EQUAL_SPEED
|
||||
|
||||
UNIT_TEST(VehicleModel_MultiplicationOperatorTest)
|
||||
{
|
||||
SpeedKMpH const speed(90 /* weight */, 100 /* eta */);
|
||||
SpeedFactor const factor(1.0, 1.1);
|
||||
SpeedKMpH const lResult = speed * factor;
|
||||
SpeedKMpH const rResult = factor * speed;
|
||||
TEST_EQUAL(lResult, rResult, ());
|
||||
TEST(AlmostEqualULPs(lResult.m_weight, 90.0), ());
|
||||
TEST(AlmostEqualULPs(lResult.m_eta, 110.0), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(VehicleModel_CarModelValidation)
|
||||
{
|
||||
HighwayType const carRoadTypes[] = {
|
||||
HighwayType::HighwayLivingStreet, HighwayType::HighwayMotorway, HighwayType::HighwayMotorwayLink,
|
||||
HighwayType::HighwayPrimary, HighwayType::HighwayPrimaryLink, HighwayType::HighwayResidential,
|
||||
HighwayType::HighwayRoad, HighwayType::HighwaySecondary, HighwayType::HighwaySecondaryLink,
|
||||
HighwayType::HighwayService, HighwayType::HighwayTertiary, HighwayType::HighwayTertiaryLink,
|
||||
HighwayType::HighwayTrack, HighwayType::HighwayTrunk, HighwayType::HighwayTrunkLink,
|
||||
HighwayType::HighwayUnclassified, HighwayType::ManMadePier, HighwayType::RouteShuttleTrain,
|
||||
HighwayType::RouteFerry,
|
||||
};
|
||||
|
||||
for (auto const hwType : carRoadTypes)
|
||||
{
|
||||
auto const * factor = kHighwayBasedFactors.Find(hwType);
|
||||
TEST(factor, (hwType));
|
||||
TEST(factor->IsValid(), (hwType, *factor));
|
||||
|
||||
auto const * speed = kHighwayBasedSpeeds.Find(hwType);
|
||||
TEST(speed, (hwType));
|
||||
TEST(speed->IsValid(), (hwType, *speed));
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(VehicleModel_HighwayType_Values)
|
||||
{
|
||||
classificator::Load();
|
||||
auto const & cl = classif();
|
||||
|
||||
auto const check = [&cl](HighwayType hwType, base::StringIL clType)
|
||||
{ return static_cast<uint16_t>(hwType) == cl.GetIndexForType(cl.GetTypeByPath(clType)); };
|
||||
|
||||
TEST(check(HighwayType::HighwayResidential, {"highway", "residential"}), ());
|
||||
TEST(check(HighwayType::HighwayService, {"highway", "service"}), ());
|
||||
TEST(check(HighwayType::HighwayUnclassified, {"highway", "unclassified"}), ());
|
||||
TEST(check(HighwayType::HighwayFootway, {"highway", "footway"}), ());
|
||||
TEST(check(HighwayType::HighwayTrack, {"highway", "track"}), ());
|
||||
TEST(check(HighwayType::HighwayTertiary, {"highway", "tertiary"}), ());
|
||||
TEST(check(HighwayType::HighwaySecondary, {"highway", "secondary"}), ());
|
||||
TEST(check(HighwayType::HighwayPath, {"highway", "path"}), ());
|
||||
TEST(check(HighwayType::HighwayPrimary, {"highway", "primary"}), ());
|
||||
TEST(check(HighwayType::HighwayRoad, {"highway", "road"}), ());
|
||||
TEST(check(HighwayType::HighwayCycleway, {"highway", "cycleway"}), ());
|
||||
TEST(check(HighwayType::HighwayMotorwayLink, {"highway", "motorway_link"}), ());
|
||||
TEST(check(HighwayType::HighwayLivingStreet, {"highway", "living_street"}), ());
|
||||
TEST(check(HighwayType::HighwayMotorway, {"highway", "motorway"}), ());
|
||||
TEST(check(HighwayType::HighwayLadder, {"highway", "ladder"}), ());
|
||||
TEST(check(HighwayType::HighwaySteps, {"highway", "steps"}), ());
|
||||
TEST(check(HighwayType::HighwayTrunk, {"highway", "trunk"}), ());
|
||||
TEST(check(HighwayType::HighwayPedestrian, {"highway", "pedestrian"}), ());
|
||||
TEST(check(HighwayType::HighwayTrunkLink, {"highway", "trunk_link"}), ());
|
||||
TEST(check(HighwayType::HighwayPrimaryLink, {"highway", "primary_link"}), ());
|
||||
TEST(check(HighwayType::ManMadePier, {"man_made", "pier"}), ());
|
||||
TEST(check(HighwayType::HighwayBridleway, {"highway", "bridleway"}), ());
|
||||
TEST(check(HighwayType::HighwaySecondaryLink, {"highway", "secondary_link"}), ());
|
||||
TEST(check(HighwayType::RouteFerry, {"route", "ferry"}), ());
|
||||
TEST(check(HighwayType::HighwayTertiaryLink, {"highway", "tertiary_link"}), ());
|
||||
TEST(check(HighwayType::HighwayLadder, {"highway", "ladder"}), ());
|
||||
TEST(check(HighwayType::HighwayBusway, {"highway", "busway"}), ());
|
||||
TEST(check(HighwayType::RouteShuttleTrain, {"route", "shuttle_train"}), ());
|
||||
}
|
||||
|
||||
} // namespace vehicle_model_test
|
||||
421
libs/routing_common/vehicle_model.cpp
Normal file
421
libs/routing_common/vehicle_model.cpp
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
#include "routing_common/vehicle_model.hpp"
|
||||
|
||||
#include "indexer/classificator.hpp"
|
||||
#include "indexer/ftypes_matcher.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
|
||||
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)};
|
||||
}
|
||||
|
||||
SpeedKMpH Max(SpeedKMpH const & lhs, InOutCitySpeedKMpH const & rhs)
|
||||
{
|
||||
return Pick<max>(lhs, Pick<max>(rhs.m_inCity, rhs.m_outCity));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
VehicleModel::VehicleModel(Classificator const & classif, LimitsInitList const & featureTypeLimits,
|
||||
SurfaceInitList const & featureTypeSurface, HighwayBasedInfo const & info)
|
||||
: m_highwayBasedInfo(info)
|
||||
, m_onewayType(ftypes::IsOneWayChecker::Instance().GetType())
|
||||
{
|
||||
m_roadTypes.Reserve(featureTypeLimits.size());
|
||||
for (auto const & v : featureTypeLimits)
|
||||
{
|
||||
auto const * speed = info.m_speeds.Find(v.m_type);
|
||||
ASSERT(speed, ("Can't found speed for", v.m_type));
|
||||
|
||||
m_maxModelSpeed = Max(m_maxModelSpeed, *speed);
|
||||
|
||||
m_roadTypes.Insert(classif.GetTypeForIndex(static_cast<uint32_t>(v.m_type)), v.m_isPassThroughAllowed);
|
||||
}
|
||||
m_roadTypes.FinishBuilding();
|
||||
|
||||
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), speedFactor);
|
||||
|
||||
if (v.m_type[1] == "paved_bad")
|
||||
m_minSurfaceFactorForMaxspeed = speedFactor;
|
||||
}
|
||||
}
|
||||
|
||||
void VehicleModel::AddAdditionalRoadTypes(Classificator const & classif, AdditionalRoadsList const & roads)
|
||||
{
|
||||
for (auto const & r : roads)
|
||||
{
|
||||
uint32_t const type = classif.GetTypeByPath(r.m_type);
|
||||
if (m_roadTypes.Find(type) == nullptr)
|
||||
{
|
||||
m_addRoadTypes.Insert(type, r.m_speed);
|
||||
m_maxModelSpeed = Max(m_maxModelSpeed, r.m_speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<HighwayType> VehicleModel::GetHighwayType(FeatureTypes const & types) const
|
||||
{
|
||||
for (uint32_t t : types)
|
||||
{
|
||||
ftype::TruncValue(t, 2);
|
||||
|
||||
auto const ret = GetHighwayType(t);
|
||||
if (ret)
|
||||
return *ret;
|
||||
}
|
||||
|
||||
// For example Denmark has "No track" profile (see kCarOptionsDenmark), but tracks exist in MWM.
|
||||
return {};
|
||||
}
|
||||
|
||||
double VehicleModel::GetMaxWeightSpeed() const
|
||||
{
|
||||
return m_maxModelSpeed.m_weight;
|
||||
}
|
||||
|
||||
optional<HighwayType> VehicleModel::GetHighwayType(uint32_t type) const
|
||||
{
|
||||
auto const * value = m_roadTypes.Find(type);
|
||||
if (value)
|
||||
return static_cast<HighwayType>(classif().GetIndexForType(type));
|
||||
return {};
|
||||
}
|
||||
|
||||
void VehicleModel::GetSurfaceFactor(uint32_t type, SpeedFactor & factor) const
|
||||
{
|
||||
auto const * surface = m_surfaceFactors.Find(type);
|
||||
if (surface)
|
||||
factor = Pick<min>(factor, *surface);
|
||||
|
||||
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)
|
||||
{
|
||||
// Now we have only 1 additional type "yes" for all models.
|
||||
ASSERT(!speed, ());
|
||||
speed = isCityRoad ? s->m_inCity : s->m_outCity;
|
||||
}
|
||||
}
|
||||
|
||||
/// @note Saved speed |params| is taken into account only if isCar == true.
|
||||
SpeedKMpH VehicleModel::GetTypeSpeedImpl(FeatureTypes const & types, SpeedParams const & params, bool isCar) const
|
||||
{
|
||||
bool const isCityRoad = params.m_inCity;
|
||||
optional<HighwayType> hwType;
|
||||
SpeedFactor surfaceFactor;
|
||||
optional<SpeedKMpH> additionalRoadSpeed;
|
||||
for (uint32_t t : types)
|
||||
{
|
||||
ftype::TruncValue(t, 2);
|
||||
|
||||
if (!hwType)
|
||||
hwType = GetHighwayType(t);
|
||||
|
||||
GetSurfaceFactor(t, surfaceFactor);
|
||||
GetAdditionalRoadSpeed(t, isCityRoad, additionalRoadSpeed);
|
||||
}
|
||||
|
||||
SpeedKMpH speed;
|
||||
if (hwType)
|
||||
{
|
||||
if (isCar && params.m_maxspeed.IsValid())
|
||||
{
|
||||
MaxspeedType const s = params.m_maxspeed.GetSpeedKmPH(params.m_forward);
|
||||
ASSERT(s != kInvalidSpeed, (*hwType, params.m_forward, params.m_maxspeed));
|
||||
speed = {static_cast<double>(s)};
|
||||
|
||||
// Looks like a crutch, limit surface factor if maxspeed is set.
|
||||
/// @see USA_UseDirt_WithMaxspeed test.
|
||||
surfaceFactor.SetMin(m_minSurfaceFactorForMaxspeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const * s = m_highwayBasedInfo.m_speeds.Find(*hwType);
|
||||
ASSERT(s, ("Key:", *hwType, "is not found."));
|
||||
speed = s->GetSpeed(isCityRoad);
|
||||
|
||||
if (isCar)
|
||||
{
|
||||
// Override the global default speed with the MWM's saved default speed if they are not significantly differ
|
||||
// (2x), to avoid anomaly peaks (especially for tracks).
|
||||
/// @todo MWM saved speeds should be validated in generator.
|
||||
if (params.m_defSpeedKmPH != kInvalidSpeed &&
|
||||
fabs(speed.m_weight - params.m_defSpeedKmPH) / speed.m_weight < 1.0)
|
||||
{
|
||||
double const factor = speed.m_eta / speed.m_weight;
|
||||
speed.m_weight = params.m_defSpeedKmPH;
|
||||
speed.m_eta = speed.m_weight * factor;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take additional speed for bicycle and pedestrian only.
|
||||
if (additionalRoadSpeed)
|
||||
speed = Pick<max>(speed, *additionalRoadSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
auto const typeKey = *hwType;
|
||||
auto const * factor = m_highwayBasedInfo.m_factors.Find(typeKey);
|
||||
ASSERT(factor, ("Key:", typeKey, "is not found."));
|
||||
auto const & f = factor->GetFactor(isCityRoad);
|
||||
speed.m_weight *= f.m_weight;
|
||||
speed.m_eta *= f.m_eta;
|
||||
}
|
||||
else
|
||||
{
|
||||
// In case if we have highway=footway + motorcar=yes :)
|
||||
ASSERT(additionalRoadSpeed, ());
|
||||
if (additionalRoadSpeed)
|
||||
speed = *additionalRoadSpeed;
|
||||
}
|
||||
|
||||
ASSERT(!(m_maxModelSpeed < speed), (speed, m_maxModelSpeed, types));
|
||||
return speed * surfaceFactor;
|
||||
}
|
||||
|
||||
bool VehicleModel::IsOneWay(FeatureTypes const & types) const
|
||||
{
|
||||
return types.Has(m_onewayType);
|
||||
}
|
||||
|
||||
bool VehicleModel::IsRoad(FeatureTypes const & types) const
|
||||
{
|
||||
return types.GetGeomType() == feature::GeomType::Line && IsRoadImpl(types);
|
||||
}
|
||||
|
||||
bool VehicleModel::IsPassThroughAllowed(FeatureTypes const & types) const
|
||||
{
|
||||
for (uint32_t t : types)
|
||||
{
|
||||
ftype::TruncValue(t, 2);
|
||||
|
||||
// Additional types (like ferry) are always pass-through now.
|
||||
if (m_addRoadTypes.Find(t))
|
||||
return true;
|
||||
|
||||
bool const * allow = m_roadTypes.Find(t);
|
||||
if (allow && *allow)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VehicleModel::IsRoadType(uint32_t type) const
|
||||
{
|
||||
ftype::TruncValue(type, 2);
|
||||
return m_addRoadTypes.Find(type) || m_roadTypes.Find(type);
|
||||
}
|
||||
|
||||
bool VehicleModel::IsRoadImpl(FeatureTypes const & types) const
|
||||
{
|
||||
for (uint32_t const t : types)
|
||||
{
|
||||
// Assume that Yes and No are not possible at the same time. Return first flag, otherwise.
|
||||
if (t == m_yesType)
|
||||
return true;
|
||||
if (t == m_noType)
|
||||
return false;
|
||||
}
|
||||
|
||||
return HasRoadType(types);
|
||||
}
|
||||
|
||||
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(), ());
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
shared_ptr<VehicleModelInterface> VehicleModelFactory::GetVehicleModelForCountry(string const & country) const
|
||||
{
|
||||
string parent = country;
|
||||
while (!parent.empty())
|
||||
{
|
||||
auto it = m_models.find(parent);
|
||||
if (it != m_models.end())
|
||||
return it->second;
|
||||
|
||||
parent = GetParent(parent);
|
||||
}
|
||||
|
||||
return GetVehicleModel();
|
||||
}
|
||||
|
||||
string VehicleModelFactory::GetParent(string const & country) const
|
||||
{
|
||||
if (!m_countryParentNameGetterFn)
|
||||
return string();
|
||||
return m_countryParentNameGetterFn(country);
|
||||
}
|
||||
|
||||
HighwayBasedFactors GetOneFactorsForBicycleAndPedestrianModel()
|
||||
{
|
||||
return HighwayBasedFactors{
|
||||
{HighwayType::HighwayTrunk, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayTrunkLink, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayPrimary, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayPrimaryLink, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwaySecondary, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwaySecondaryLink, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayTertiary, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayTertiaryLink, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayService, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayUnclassified, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayRoad, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayTrack, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayPath, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayBridleway, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayCycleway, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayResidential, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayLivingStreet, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayLadder, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwaySteps, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayPedestrian, InOutCityFactor(1.0)},
|
||||
{HighwayType::HighwayFootway, InOutCityFactor(1.0)},
|
||||
{HighwayType::ManMadePier, InOutCityFactor(1.0)},
|
||||
{HighwayType::RouteFerry, InOutCityFactor(1.0)},
|
||||
};
|
||||
}
|
||||
|
||||
string DebugPrint(SpeedKMpH const & speed)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "SpeedKMpH [ ";
|
||||
oss << "weight:" << speed.m_weight << ", ";
|
||||
oss << "eta:" << speed.m_eta << " ]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string DebugPrint(SpeedFactor const & speedFactor)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "SpeedFactor [ ";
|
||||
oss << "weight:" << speedFactor.m_weight << ", ";
|
||||
oss << "eta:" << speedFactor.m_eta << " ]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
string DebugPrint(InOutCitySpeedKMpH const & speed)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "InOutCitySpeedKMpH [ ";
|
||||
oss << "inCity:" << DebugPrint(speed.m_inCity) << ", ";
|
||||
oss << "outCity:" << DebugPrint(speed.m_outCity) << " ]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
string DebugPrint(InOutCityFactor const & speedFactor)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "InOutCityFactor [ ";
|
||||
oss << "inCity:" << DebugPrint(speedFactor.m_inCity) << ", ";
|
||||
oss << "outCity:" << DebugPrint(speedFactor.m_outCity) << " ]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
string DebugPrint(HighwayType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case HighwayType::HighwayResidential: return "highway-residential";
|
||||
case HighwayType::HighwayService: return "highway-service";
|
||||
case HighwayType::HighwayUnclassified: return "highway-unclassified";
|
||||
case HighwayType::HighwayFootway: return "highway-footway";
|
||||
case HighwayType::HighwayTrack: return "highway-track";
|
||||
case HighwayType::HighwayTertiary: return "highway-tertiary";
|
||||
case HighwayType::HighwaySecondary: return "highway-secondary";
|
||||
case HighwayType::HighwayPath: return "highway-path";
|
||||
case HighwayType::HighwayPrimary: return "highway-primary";
|
||||
case HighwayType::HighwayRoad: return "highway-road";
|
||||
case HighwayType::HighwayCycleway: return "highway-cycleway";
|
||||
case HighwayType::HighwayMotorwayLink: return "highway-motorway_link";
|
||||
case HighwayType::HighwayLivingStreet: return "highway-living_street";
|
||||
case HighwayType::HighwayMotorway: return "highway-motorway";
|
||||
case HighwayType::HighwayLadder: return "highway-ladder";
|
||||
case HighwayType::HighwaySteps: return "highway-steps";
|
||||
case HighwayType::HighwayTrunk: return "highway-trunk";
|
||||
case HighwayType::HighwayPedestrian: return "highway-pedestrian";
|
||||
case HighwayType::HighwayTrunkLink: return "highway-trunk_link";
|
||||
case HighwayType::HighwayPrimaryLink: return "highway-primary_link";
|
||||
case HighwayType::ManMadePier: return "man_made-pier";
|
||||
case HighwayType::HighwayBridleway: return "highway-bridleway";
|
||||
case HighwayType::HighwaySecondaryLink: return "highway-secondary_link";
|
||||
case HighwayType::RouteFerry: return "route-ferry";
|
||||
case HighwayType::HighwayTertiaryLink: return "highway-tertiary_link";
|
||||
case HighwayType::HighwayBusway: return "highway-busway";
|
||||
case HighwayType::RouteShuttleTrain: return "route-shuttle_train";
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void FromString(std::string_view s, HighwayType & highwayType)
|
||||
{
|
||||
// Build reverse lookup from DebugPrint function
|
||||
static std::unordered_map<std::string, HighwayType> const stringToEnum = []()
|
||||
{
|
||||
std::unordered_map<std::string, HighwayType> map;
|
||||
|
||||
// All possible HighwayType values
|
||||
constexpr HighwayType allTypes[] = {
|
||||
HighwayType::HighwayResidential, HighwayType::HighwayService, HighwayType::HighwayUnclassified,
|
||||
HighwayType::HighwayFootway, HighwayType::HighwayTrack, HighwayType::HighwayTertiary,
|
||||
HighwayType::HighwaySecondary, HighwayType::HighwayPath, HighwayType::HighwayPrimary,
|
||||
HighwayType::HighwayRoad, HighwayType::HighwayCycleway, HighwayType::HighwayMotorwayLink,
|
||||
HighwayType::HighwayLivingStreet, HighwayType::HighwayMotorway, HighwayType::HighwaySteps,
|
||||
HighwayType::HighwayTrunk, HighwayType::HighwayPedestrian, HighwayType::HighwayTrunkLink,
|
||||
HighwayType::HighwayPrimaryLink, HighwayType::ManMadePier, HighwayType::HighwayBridleway,
|
||||
HighwayType::HighwaySecondaryLink, HighwayType::RouteFerry, HighwayType::HighwayTertiaryLink,
|
||||
HighwayType::HighwayBusway, HighwayType::RouteShuttleTrain};
|
||||
|
||||
for (auto type : allTypes)
|
||||
map[DebugPrint(type)] = type;
|
||||
|
||||
return map;
|
||||
}();
|
||||
|
||||
auto it = stringToEnum.find(std::string(s));
|
||||
if (it != stringToEnum.end())
|
||||
{
|
||||
highwayType = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(false, ("Could not read HighwayType from string", s));
|
||||
highwayType = HighwayType::HighwayResidential; // default fallback
|
||||
}
|
||||
}
|
||||
} // namespace routing
|
||||
371
libs/routing_common/vehicle_model.hpp
Normal file
371
libs/routing_common/vehicle_model.hpp
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
#pragma once
|
||||
|
||||
#include "routing_common/maxspeed_conversion.hpp"
|
||||
|
||||
#include "indexer/feature_data.hpp"
|
||||
|
||||
#include "base/small_map.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class Classificator;
|
||||
class FeatureType;
|
||||
|
||||
namespace routing
|
||||
{
|
||||
double constexpr kNotUsed = std::numeric_limits<double>::max();
|
||||
|
||||
struct InOutCityFactor;
|
||||
struct InOutCitySpeedKMpH;
|
||||
|
||||
// Each value is equal to the corresponding 0-based type index from types.txt
|
||||
// (an ID from mapcss-mapping.csv minus 1).
|
||||
// The ascending order is strict. Check for static_cast<HighwayType> in vehicle_model.cpp
|
||||
enum class HighwayType : uint16_t
|
||||
{
|
||||
HighwayResidential = 1,
|
||||
HighwayService = 2,
|
||||
HighwayUnclassified = 4,
|
||||
HighwayFootway = 6,
|
||||
HighwayTrack = 7,
|
||||
HighwayTertiary = 8,
|
||||
HighwaySecondary = 12,
|
||||
HighwayPath = 15,
|
||||
HighwayPrimary = 26,
|
||||
HighwayRoad = 410,
|
||||
HighwayCycleway = 36,
|
||||
HighwayMotorwayLink = 43,
|
||||
HighwayLivingStreet = 54,
|
||||
HighwayMotorway = 57,
|
||||
HighwaySteps = 58,
|
||||
HighwayTrunk = 65,
|
||||
HighwayPedestrian = 69,
|
||||
HighwayTrunkLink = 90,
|
||||
HighwayPrimaryLink = 95,
|
||||
ManMadePier = 119,
|
||||
HighwayBridleway = 167,
|
||||
HighwaySecondaryLink = 176,
|
||||
RouteFerry = 259,
|
||||
HighwayTertiaryLink = 272,
|
||||
HighwayLadder = 478,
|
||||
HighwayBusway = 857, // reserve type here, but this type is not used for any routing by default
|
||||
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
|
||||
{
|
||||
/// @deprecated For unit tests compatibility.
|
||||
SpeedParams(bool forward, bool inCity, Maxspeed const & maxspeed)
|
||||
: m_maxspeed(maxspeed)
|
||||
, m_defSpeedKmPH(kInvalidSpeed)
|
||||
, m_inCity(inCity)
|
||||
, m_forward(forward)
|
||||
{}
|
||||
|
||||
SpeedParams(Maxspeed const & maxspeed, MaxspeedType defSpeedKmPH, bool inCity)
|
||||
: m_maxspeed(maxspeed)
|
||||
, m_defSpeedKmPH(defSpeedKmPH)
|
||||
, m_inCity(inCity)
|
||||
{}
|
||||
|
||||
// Maxspeed stored for feature, if any.
|
||||
Maxspeed m_maxspeed;
|
||||
// Default speed for this feature type in MWM, if any (kInvalidSpeed otherwise).
|
||||
MaxspeedType m_defSpeedKmPH;
|
||||
// If a corresponding feature lies inside a city of a town.
|
||||
bool m_inCity;
|
||||
// Retrieve forward (true) or backward (false) speed.
|
||||
bool m_forward;
|
||||
};
|
||||
|
||||
/// \brief Speeds which are used for edge weight and ETA estimations.
|
||||
struct SpeedKMpH
|
||||
{
|
||||
constexpr SpeedKMpH() = default;
|
||||
constexpr SpeedKMpH(double weight) noexcept : m_weight(weight), m_eta(weight) {}
|
||||
constexpr SpeedKMpH(double weight, double eta) noexcept : m_weight(weight), m_eta(eta) {}
|
||||
|
||||
bool operator==(SpeedKMpH const & rhs) const { return m_weight == rhs.m_weight && m_eta == rhs.m_eta; }
|
||||
bool operator!=(SpeedKMpH const & rhs) const { return !(*this == rhs); }
|
||||
|
||||
bool operator<(SpeedKMpH const & rhs) const { return m_weight < rhs.m_weight && m_eta < rhs.m_eta; }
|
||||
|
||||
bool IsValid() const { return m_weight > 0 && m_eta > 0; }
|
||||
|
||||
double m_weight =
|
||||
0.0; // KMpH - speed in km/h adjusted for desirability
|
||||
// cycling on very large road may be fast but speed used for route finding will be treated as much lower
|
||||
double m_eta = 0.0; // KMpH - actual expected speed in km/h, used to display expected arrival time
|
||||
};
|
||||
|
||||
/// \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
|
||||
{
|
||||
constexpr SpeedFactor() = default;
|
||||
constexpr SpeedFactor(double factor) noexcept : m_weight(factor), m_eta(factor) {}
|
||||
constexpr SpeedFactor(double weight, double eta) noexcept : m_weight(weight), m_eta(eta) {}
|
||||
|
||||
bool IsValid() const { return m_weight > 0.0 && m_weight <= 1.0 && m_eta > 0.0 && m_eta <= 1.0; }
|
||||
void SetMin(SpeedFactor const & f)
|
||||
{
|
||||
ASSERT(f.IsValid(), ());
|
||||
m_weight = std::max(f.m_weight, m_weight);
|
||||
m_eta = std::max(f.m_eta, m_eta);
|
||||
}
|
||||
|
||||
bool operator==(SpeedFactor const & rhs) const { return m_weight == rhs.m_weight && m_eta == rhs.m_eta; }
|
||||
bool operator!=(SpeedFactor const & rhs) const { return !(*this == rhs); }
|
||||
|
||||
double m_weight = 1.0;
|
||||
double m_eta = 1.0;
|
||||
};
|
||||
|
||||
inline SpeedKMpH operator*(SpeedFactor const & factor, SpeedKMpH const & speed)
|
||||
{
|
||||
return {speed.m_weight * factor.m_weight, speed.m_eta * factor.m_eta};
|
||||
}
|
||||
|
||||
inline SpeedKMpH operator*(SpeedKMpH const & speed, SpeedFactor const & factor)
|
||||
{
|
||||
return {speed.m_weight * factor.m_weight, speed.m_eta * factor.m_eta};
|
||||
}
|
||||
|
||||
struct InOutCitySpeedKMpH
|
||||
{
|
||||
constexpr InOutCitySpeedKMpH() = default;
|
||||
constexpr explicit InOutCitySpeedKMpH(SpeedKMpH const & speed) noexcept : m_inCity(speed), m_outCity(speed) {}
|
||||
constexpr InOutCitySpeedKMpH(SpeedKMpH const & inCity, SpeedKMpH const & outCity) noexcept
|
||||
: m_inCity(inCity)
|
||||
, m_outCity(outCity)
|
||||
{}
|
||||
|
||||
bool operator==(InOutCitySpeedKMpH const & rhs) const
|
||||
{
|
||||
return m_inCity == rhs.m_inCity && m_outCity == rhs.m_outCity;
|
||||
}
|
||||
|
||||
SpeedKMpH const & GetSpeed(bool isCity) const { return isCity ? m_inCity : m_outCity; }
|
||||
bool IsValid() const { return m_inCity.IsValid() && m_outCity.IsValid(); }
|
||||
|
||||
SpeedKMpH m_inCity;
|
||||
SpeedKMpH m_outCity;
|
||||
};
|
||||
|
||||
struct InOutCityFactor
|
||||
{
|
||||
constexpr explicit InOutCityFactor(SpeedFactor const & factor) noexcept : m_inCity(factor), m_outCity(factor) {}
|
||||
constexpr InOutCityFactor(SpeedFactor const & inCity, SpeedFactor const & outCity) noexcept
|
||||
: m_inCity(inCity)
|
||||
, m_outCity(outCity)
|
||||
{}
|
||||
|
||||
bool operator==(InOutCityFactor const & rhs) const { return m_inCity == rhs.m_inCity && m_outCity == rhs.m_outCity; }
|
||||
|
||||
SpeedFactor const & GetFactor(bool isCity) const { return isCity ? m_inCity : m_outCity; }
|
||||
bool IsValid() const { return m_inCity.IsValid() && m_outCity.IsValid(); }
|
||||
|
||||
SpeedFactor m_inCity;
|
||||
SpeedFactor m_outCity;
|
||||
};
|
||||
|
||||
struct HighwayBasedInfo
|
||||
{
|
||||
HighwayBasedInfo(HighwayBasedSpeeds const & speeds, HighwayBasedFactors const & factors)
|
||||
: m_speeds(speeds)
|
||||
, m_factors(factors)
|
||||
{}
|
||||
|
||||
HighwayBasedSpeeds m_speeds;
|
||||
HighwayBasedFactors const & m_factors;
|
||||
};
|
||||
|
||||
class VehicleModelInterface
|
||||
{
|
||||
public:
|
||||
virtual ~VehicleModelInterface() = default;
|
||||
|
||||
using FeatureTypes = feature::TypesHolder;
|
||||
|
||||
/// @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(FeatureTypes const & types, SpeedParams const & speedParams) const = 0;
|
||||
|
||||
virtual std::optional<HighwayType> GetHighwayType(FeatureTypes const & types) const = 0;
|
||||
|
||||
/// @return Maximum model weight speed (km/h).
|
||||
/// All speeds which the model returns must be less or equal to this speed.
|
||||
/// @see EdgeEstimator::CalcHeuristic.
|
||||
virtual double GetMaxWeightSpeed() const = 0;
|
||||
|
||||
/// @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(FeatureTypes const & types) const = 0;
|
||||
|
||||
/// @returns true iff feature |f| can be used for routing with corresponding vehicle model.
|
||||
virtual bool IsRoad(FeatureTypes const & types) 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(FeatureTypes const & types) const = 0;
|
||||
};
|
||||
|
||||
class VehicleModelFactoryInterface
|
||||
{
|
||||
public:
|
||||
virtual ~VehicleModelFactoryInterface() = default;
|
||||
/// @return Default vehicle model which corresponds for all countrines,
|
||||
/// 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
|
||||
virtual std::shared_ptr<VehicleModelInterface> GetVehicleModelForCountry(std::string const & country) const = 0;
|
||||
};
|
||||
|
||||
class VehicleModel : public VehicleModelInterface
|
||||
{
|
||||
public:
|
||||
struct FeatureTypeLimits
|
||||
{
|
||||
HighwayType 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::vector<FeatureTypeLimits>;
|
||||
using SurfaceInitList = std::initializer_list<FeatureTypeSurface>;
|
||||
|
||||
VehicleModel(Classificator const & classif, LimitsInitList const & featureTypeLimits,
|
||||
SurfaceInitList const & featureTypeSurface, HighwayBasedInfo const & info);
|
||||
|
||||
/// @name VehicleModelInterface overrides.
|
||||
/// @{
|
||||
std::optional<HighwayType> GetHighwayType(FeatureTypes const & types) const override;
|
||||
double GetMaxWeightSpeed() const override;
|
||||
|
||||
/// \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 IsOneWay(FeatureTypes const & types) const override;
|
||||
bool IsRoad(FeatureTypes const & types) const override;
|
||||
bool IsPassThroughAllowed(FeatureTypes const & types) const override;
|
||||
/// @}
|
||||
|
||||
// Made public to have simple access from unit tests.
|
||||
|
||||
public:
|
||||
/// @returns true if |m_highwayTypes| or |m_addRoadTypes| contains |type| and false otherwise.
|
||||
bool IsRoadType(uint32_t type) const;
|
||||
template <class TList>
|
||||
bool HasRoadType(TList const & types) const
|
||||
{
|
||||
for (uint32_t t : types)
|
||||
if (IsRoadType(t))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EqualsForTests(VehicleModel const & rhs) const
|
||||
{
|
||||
return (m_roadTypes == rhs.m_roadTypes) && (m_addRoadTypes == rhs.m_addRoadTypes) &&
|
||||
(m_onewayType == rhs.m_onewayType);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32_t m_yesType, m_noType;
|
||||
bool IsRoadImpl(FeatureTypes const & types) const;
|
||||
|
||||
SpeedKMpH GetTypeSpeedImpl(FeatureTypes const & types, SpeedParams const & params, bool isCar) const;
|
||||
|
||||
void AddAdditionalRoadTypes(Classificator const & classif, AdditionalRoadsList const & roads);
|
||||
|
||||
uint32_t PrepareToMatchType(uint32_t type) const;
|
||||
|
||||
/// \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.
|
||||
SpeedKMpH 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;
|
||||
|
||||
// HW type -> speed and factor.
|
||||
HighwayBasedInfo m_highwayBasedInfo;
|
||||
uint32_t m_onewayType;
|
||||
|
||||
// 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;
|
||||
SpeedFactor m_minSurfaceFactorForMaxspeed;
|
||||
|
||||
/// @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
|
||||
{
|
||||
public:
|
||||
// Callback which takes territory name (mwm graph node name) and returns its parent
|
||||
// territory name. Used to properly find local restrictions in GetVehicleModelForCountry.
|
||||
// For territories which do not have parent (countries) or have multiple parents
|
||||
// (disputed territories) it should return empty name.
|
||||
// For example "Munich" -> "Bavaria"; "Bavaria" -> "Germany"; "Germany" -> ""
|
||||
using CountryParentNameGetterFn = std::function<std::string(std::string const &)>;
|
||||
|
||||
std::shared_ptr<VehicleModelInterface> GetVehicleModel() const override;
|
||||
|
||||
std::shared_ptr<VehicleModelInterface> GetVehicleModelForCountry(std::string const & country) const override;
|
||||
|
||||
protected:
|
||||
explicit VehicleModelFactory(CountryParentNameGetterFn const & countryParentNameGetterFn);
|
||||
std::string GetParent(std::string const & country) const;
|
||||
|
||||
std::unordered_map<std::string, std::shared_ptr<VehicleModelInterface>> m_models;
|
||||
CountryParentNameGetterFn m_countryParentNameGetterFn;
|
||||
};
|
||||
|
||||
HighwayBasedFactors GetOneFactorsForBicycleAndPedestrianModel();
|
||||
|
||||
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);
|
||||
void FromString(std::string_view s, HighwayType & highwayType);
|
||||
} // namespace routing
|
||||
Loading…
Add table
Add a link
Reference in a new issue