diff --git a/generator/camera_node_processor.cpp b/generator/camera_node_processor.cpp index 21d132dfcc..252feaa17c 100644 --- a/generator/camera_node_processor.cpp +++ b/generator/camera_node_processor.cpp @@ -7,6 +7,7 @@ #include "base/assert.hpp" #include "base/control_flow.hpp" #include "base/logging.hpp" +#include "base/string_utils.hpp" #include @@ -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(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(measurement_utils::MphToKmph(mph)); - return strings::to_string(kmh); - } - - return result; + CHECK_SWITCH(); + return std::string(); } void CameraNodeIntermediateDataProcessor::ProcessNode(OsmElement & em) diff --git a/generator/category_to_speed.cpp b/generator/category_to_speed.cpp index 529178f489..65b3b2556f 100644 --- a/generator/category_to_speed.cpp +++ b/generator/category_to_speed.cpp @@ -1,21 +1,18 @@ #include "generator/category_to_speed.hpp" +#include "base/string_utils.hpp" + +#include +#include #include 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 const kRoadCategoryToSpeed = { +unordered_map 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 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(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(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 diff --git a/generator/category_to_speed.hpp b/generator/category_to_speed.hpp index b227a26afe..ff6442692a 100644 --- a/generator/category_to_speed.hpp +++ b/generator/category_to_speed.hpp @@ -9,6 +9,20 @@ namespace generator { uint16_t constexpr kNoneMaxSpeed = std::numeric_limits::max(); +uint16_t constexpr kWalkMaxSpeed = std::numeric_limits::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::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 diff --git a/generator/generator_tests/speed_cameras_test.cpp b/generator/generator_tests/speed_cameras_test.cpp index d163e15982..28d2b585d7 100644 --- a/generator/generator_tests/speed_cameras_test.cpp +++ b/generator/generator_tests/speed_cameras_test.cpp @@ -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