[routing] Gather all maxspeed parsing functionality to a special unit and tests on it.

This commit is contained in:
Vladimir Byko-Ianko 2018-10-24 16:20:41 +03:00 committed by mpimenov
parent 298706f18e
commit a807b47d59
4 changed files with 175 additions and 61 deletions

View file

@ -7,6 +7,7 @@
#include "base/assert.hpp"
#include "base/control_flow.hpp"
#include "base/logging.hpp"
#include "base/string_utils.hpp"
#include <array>
@ -17,7 +18,6 @@ size_t const CameraNodeIntermediateDataProcessor::kMaxSpeedSpeedStringLength = 3
namespace routing
{
void CameraNodeProcessor::Open(std::string const & writerFile, std::string const & readerFile,
std::string const & speedFile)
{
@ -114,44 +114,18 @@ void CameraNodeIntermediateDataProcessor::ProcessWay(uint64_t id, WayElement con
std::string CameraNodeIntermediateDataProcessor::ValidateMaxSpeedString(std::string const & maxSpeedString)
{
uint16_t speed = 0;
measurement_utils::Units units = measurement_utils::Units::Metric;
if (RoadCategoryToSpeed(maxSpeedString, speed, units))
SpeedInUnits speed;
if (!MaxspeedValueToSpeed(maxSpeedString, speed) || !speed.IsNumeric())
return std::string();
switch (speed.m_units)
{
if (speed == kNoneMaxSpeed)
return string(); // Speed cam with no restriction on speed.
else
return strings::to_string(static_cast<int32_t>(measurement_utils::ToSpeedKmPH(speed, units)));
case measurement_utils::Units::Metric: return strings::to_string(speed.m_speed);
case measurement_utils::Units::Imperial:
return strings::to_string(measurement_utils::MphToKmph(speed.m_speed));
}
// strings::to_int doesn't work here because of bad errno.
std::string result;
size_t i;
for (i = 0; i < maxSpeedString.size(); ++i)
{
if (!isdigit(maxSpeedString[i]))
break;
result += maxSpeedString[i];
}
while (i < maxSpeedString.size() && isspace(maxSpeedString[i]))
++i;
if (strings::StartsWith(string(maxSpeedString.begin() + i, maxSpeedString.end()), "kmh"))
return result;
if (strings::StartsWith(string(maxSpeedString.begin() + i, maxSpeedString.end()), "mph"))
{
int32_t mph = 0;
if (!strings::to_int(result.c_str(), mph))
return string();
auto const kmh = static_cast<int32_t>(measurement_utils::MphToKmph(mph));
return strings::to_string(kmh);
}
return result;
CHECK_SWITCH();
return std::string();
}
void CameraNodeIntermediateDataProcessor::ProcessNode(OsmElement & em)

View file

@ -1,21 +1,18 @@
#include "generator/category_to_speed.hpp"
#include "base/string_utils.hpp"
#include <cctype>
#include <sstream>
#include <unordered_map>
namespace
{
using namespace generator;
using namespace measurement_utils;
using namespace std;
struct Speed
{
Speed() = delete;
uint16_t m_speed = 0;
Units m_units = Units::Metric;
};
std::unordered_map<std::string, Speed> const kRoadCategoryToSpeed = {
unordered_map<string, SpeedInUnits> const kRoadCategoryToSpeed = {
{"AR:urban", {40, Units::Metric}},
{"AR:urban:primary", {60, Units::Metric}},
{"AR:urban:secondary", {60, Units::Metric}},
@ -140,15 +137,80 @@ std::unordered_map<std::string, Speed> const kRoadCategoryToSpeed = {
namespace generator
{
bool RoadCategoryToSpeed(std::string const & category, uint16_t & speed,
measurement_utils::Units & units)
bool RoadCategoryToSpeed(string const & category, SpeedInUnits & speed)
{
auto const it = kRoadCategoryToSpeed.find(category);
if (it == kRoadCategoryToSpeed.cend())
return false;
speed = it->second.m_speed;
units = it->second.m_units;
speed = it->second;
return true;
}
bool MaxspeedValueToSpeed(string const & maxspeedValue, SpeedInUnits & speed)
{
if (RoadCategoryToSpeed(maxspeedValue, speed))
return true;
if (maxspeedValue == "none")
{
speed.m_speed = kNoneMaxSpeed;
speed.m_units = Units::Metric; // It's dummy value in case of kNoneMaxSpeed
return true;
}
if (maxspeedValue == "walk")
{
speed.m_speed = kWalkMaxSpeed;
speed.m_units = Units::Metric; // It's dummy value in case of kWalkMaxSpeed
return true;
}
// strings::to_int doesn't work here because of bad errno.
string speedStr;
size_t i;
for (i = 0; i < maxspeedValue.size(); ++i)
{
if (!isdigit(maxspeedValue[i]))
break;
speedStr += maxspeedValue[i];
}
while (i < maxspeedValue.size() && isspace(maxspeedValue[i]))
++i;
if (maxspeedValue.size() == i ||
strings::StartsWith(string(maxspeedValue.begin() + i, maxspeedValue.end()), "kmh"))
{
int32_t kmph = 0;
if (!strings::to_int(speedStr.c_str(), kmph) || kmph == 0)
return false;
speed.m_speed = static_cast<uint16_t>(kmph);
speed.m_units = Units::Metric;
return true;
}
if (strings::StartsWith(string(maxspeedValue.begin() + i, maxspeedValue.end()), "mph"))
{
int32_t mph = 0;
if (!strings::to_int(speedStr.c_str(), mph) || mph == 0)
return false;
speed.m_speed = static_cast<uint16_t>(mph);
speed.m_units = Units::Imperial;
return true;
}
return false;
}
string DebugPrint(SpeedInUnits const & speed)
{
ostringstream oss;
oss << "SpeedInUnits [ m_speed == " << speed.m_speed
<< ", m_units == " << DebugPrint(speed.m_units) << " ]";
return oss.str();
}
} // generator

View file

@ -9,6 +9,20 @@
namespace generator
{
uint16_t constexpr kNoneMaxSpeed = std::numeric_limits<uint16_t>::max();
uint16_t constexpr kWalkMaxSpeed = std::numeric_limits<uint16_t>::max() - 1;
struct SpeedInUnits
{
SpeedInUnits() = default;
SpeedInUnits(uint16_t speed, measurement_utils::Units units) noexcept : m_speed(speed), m_units(units) {}
bool operator==(SpeedInUnits const & s) const { return m_speed == s.m_speed && m_units == s.m_units; }
bool IsNumeric() const { return m_speed != kNoneMaxSpeed && m_speed != kWalkMaxSpeed; }
uint16_t m_speed = 0; // Speed in km per hour or mile per hour depends on m_units value.
measurement_utils::Units m_units = measurement_utils::Units::Metric;
};
/// \brief Obtains |speed| and |units| by road category based on
/// the table in https://wiki.openstreetmap.org/wiki/Speed_limits
@ -19,6 +33,14 @@ uint16_t constexpr kNoneMaxSpeed = std::numeric_limits<uint16_t>::max();
/// speed = 60 and units = Units::Metric.
/// \note If the method returns true the field |speed| may be filled with |kNoneMaxSpeed| value.
/// It means no speed limits for the |category|. It's currently actual for Germany.
bool RoadCategoryToSpeed(std::string const & category, uint16_t & speed,
measurement_utils::Units & units);
bool RoadCategoryToSpeed(std::string const & category, SpeedInUnits & speed);
/// \brief Tries to convert the value of tag maxspeed to speed in appropriate units.
/// \returns false in case of error and true if the conversion is successful.
/// \note speed.m_speed will be filled with kNoneMaxSpeed or kWalkMaxSpeed if
/// maxspeedValue is equal to "none" or "walk". The value of speed.m_units does not
/// matter in this case.
bool MaxspeedValueToSpeed(std::string const & maxspeedValue, SpeedInUnits & speed);
std::string DebugPrint(SpeedInUnits const & speed);
} // generator

View file

@ -458,17 +458,73 @@ UNIT_TEST(SpeedCameraGenerationTest_CameraIsNearFeature_2)
UNIT_TEST(RoadCategoryToSpeedTest)
{
uint16_t speed = 0;
Units units = Units::Metric;
SpeedInUnits speed;
TEST(RoadCategoryToSpeed("RU:rural", speed, units), ());
TEST_EQUAL(speed, 90, ());
TEST_EQUAL(units, Units::Metric, ());
TEST(RoadCategoryToSpeed("RU:rural", speed), ());
TEST_EQUAL(speed, SpeedInUnits(90, Units::Metric), ());
TEST(speed.IsNumeric(), ());
TEST(RoadCategoryToSpeed("UK:motorway", speed, units), ());
TEST_EQUAL(speed, 70, ());
TEST_EQUAL(units, Units::Imperial, ());
TEST(RoadCategoryToSpeed("DE:motorway", speed), ());
TEST_EQUAL(speed, SpeedInUnits(kNoneMaxSpeed, Units::Metric), ());
TEST(!speed.IsNumeric(), ());
TEST(!RoadCategoryToSpeed("UNKNOWN:unknown", speed, units), ());
TEST(RoadCategoryToSpeed("UK:motorway", speed), ());
TEST_EQUAL(speed, SpeedInUnits(70, Units::Imperial), ());
TEST(speed.IsNumeric(), ());
TEST(!RoadCategoryToSpeed("UNKNOWN:unknown", speed), ());
}
UNIT_TEST(MaxspeedValueToSpeedTest)
{
SpeedInUnits speed;
TEST(MaxspeedValueToSpeed("RU:rural", speed), ());
TEST_EQUAL(speed, SpeedInUnits(90, Units::Metric), ());
TEST(MaxspeedValueToSpeed("90", speed), ());
TEST_EQUAL(speed, SpeedInUnits(90, Units::Metric), ());
TEST(MaxspeedValueToSpeed("90 ", speed), ());
TEST_EQUAL(speed, SpeedInUnits(90, Units::Metric), ());
TEST(MaxspeedValueToSpeed("60kmh", speed), ());
TEST_EQUAL(speed, SpeedInUnits(60, Units::Metric), ());
TEST(MaxspeedValueToSpeed("60 kmh", speed), ());
TEST_EQUAL(speed, SpeedInUnits(60, Units::Metric), ());
TEST(MaxspeedValueToSpeed("60 kmh", speed), ());
TEST_EQUAL(speed, SpeedInUnits(60, Units::Metric), ());
TEST(MaxspeedValueToSpeed("60 kmh and some other string", speed), ());
TEST_EQUAL(speed, SpeedInUnits(60, Units::Metric), ());
TEST(MaxspeedValueToSpeed("75mph", speed), ());
TEST_EQUAL(speed, SpeedInUnits(75, Units::Imperial), ());
TEST(MaxspeedValueToSpeed("75 mph", speed), ());
TEST_EQUAL(speed, SpeedInUnits(75, Units::Imperial), ());
TEST(MaxspeedValueToSpeed("75 mph", speed), ());
TEST_EQUAL(speed, SpeedInUnits(75, Units::Imperial), ());
TEST(MaxspeedValueToSpeed("75 mph and some other string", speed), ());
TEST_EQUAL(speed, SpeedInUnits(75, Units::Imperial), ());
TEST(MaxspeedValueToSpeed("75mph", speed), ());
TEST_EQUAL(speed, SpeedInUnits(75, Units::Imperial), ());
TEST(MaxspeedValueToSpeed("75 mph", speed), ());
TEST_EQUAL(speed, SpeedInUnits(75, Units::Imperial), ());
TEST(MaxspeedValueToSpeed("75 mph", speed), ());
TEST_EQUAL(speed, SpeedInUnits(75, Units::Imperial), ());
TEST(MaxspeedValueToSpeed("75 mph and some other string", speed), ());
TEST_EQUAL(speed, SpeedInUnits(75, Units::Imperial), ());
TEST(!MaxspeedValueToSpeed("some other string", speed), ());
TEST(!MaxspeedValueToSpeed("60 kmph", speed), ());
}
} // namespace