diff --git a/platform/distance.cpp b/platform/distance.cpp index 83ede6de4d..1290dbde29 100644 --- a/platform/distance.cpp +++ b/platform/distance.cpp @@ -7,6 +7,8 @@ namespace platform { +using namespace measurement_utils; + namespace { Distance MetersTo(double distance, Distance::Units units) @@ -18,9 +20,9 @@ Distance MetersTo(double distance, Distance::Units units) case Distance::Units::Kilometers: return {distance / 1000, Distance::Units::Kilometers}; case Distance::Units::Feet: - return {measurement_utils::MetersToFeet(distance), Distance::Units::Feet}; + return {MetersToFeet(distance), Distance::Units::Feet}; case Distance::Units::Miles: - return {measurement_utils::MetersToMiles(distance), Distance::Units::Miles}; + return {MetersToMiles(distance), Distance::Units::Miles}; default: UNREACHABLE(); } } @@ -35,11 +37,11 @@ Distance FeetTo(double distance, Distance::Units units) switch (units) { case Distance::Units::Meters: - return {measurement_utils::FeetToMeters(distance), Distance::Units::Meters}; + return {FeetToMeters(distance), Distance::Units::Meters}; case Distance::Units::Kilometers: - return {measurement_utils::FeetToMeters(distance) / 1000, Distance::Units::Kilometers}; + return {FeetToMeters(distance) / 1000, Distance::Units::Kilometers}; case Distance::Units::Miles: - return {measurement_utils::FeetToMiles(distance), Distance::Units::Miles}; + return {FeetToMiles(distance), Distance::Units::Miles}; default: UNREACHABLE(); } } @@ -49,17 +51,20 @@ Distance MilesTo(double distance, Distance::Units units) switch (units) { case Distance::Units::Meters: - return {measurement_utils::MilesToMeters(distance), Distance::Units::Meters}; + return {MilesToMeters(distance), Distance::Units::Meters}; case Distance::Units::Kilometers: - return {measurement_utils::MilesToMeters(distance) / 1000, Distance::Units::Kilometers}; + return {MilesToMeters(distance) / 1000, Distance::Units::Kilometers}; case Distance::Units::Feet: - return {measurement_utils::MilesToFeet(distance), Distance::Units::Feet}; + return {MilesToFeet(distance), Distance::Units::Feet}; default: UNREACHABLE(); } } double WithPrecision(double value, uint8_t precision) { + if (precision == 0) + return std::round(value); + double const factor = std::pow(10, precision); return std::round(value * factor) / factor; } @@ -79,9 +84,10 @@ Distance Distance::CreateFormatted(double distanceInMeters) Distance Distance::CreateAltitudeFormatted(double meters) { Distance elevation = Distance(meters).To( - measurement_utils::GetMeasurementUnits() == measurement_utils::Units::Metric ? Units::Meters : Units::Feet); - if (elevation.IsLowUnits()) - elevation.m_distance = WithPrecision(elevation.m_distance, 0); + GetMeasurementUnits() == measurement_utils::Units::Metric ? Units::Meters : Units::Feet); + + ASSERT(elevation.IsLowUnits(), ()); + elevation.m_distance = WithPrecision(elevation.m_distance, 0); return elevation; } @@ -91,11 +97,12 @@ bool Distance::IsLowUnits() const { return m_units == Units::Meters || m_units = bool Distance::IsHighUnits() const { return !IsLowUnits(); } -Distance Distance::To(Distance::Units units) const +Distance Distance::To(Units units) const { if (m_units == units) return *this; + /// @todo These double switches can be replaced with 4x4 factors matrix. switch (m_units) { case Units::Meters: return MetersTo(m_distance, units); @@ -108,7 +115,7 @@ Distance Distance::To(Distance::Units units) const Distance Distance::ToPlatformUnitsFormatted() const { - return To(measurement_utils::GetMeasurementUnits() == measurement_utils::Units::Metric ? Units::Meters : Units::Feet) + return To(GetMeasurementUnits() == measurement_utils::Units::Metric ? Units::Meters : Units::Feet) .GetFormattedDistance(); } @@ -145,42 +152,34 @@ Distance Distance::GetFormattedDistance() const { ASSERT(IsValid(), ()); - Distance newDistance = *this; - int precision = 0; + // To low units. + Distance res; + if (m_units == Units::Kilometers) + res = To(Units::Meters); + else if (m_units == Units::Miles) + res = To(Units::Feet); + else + res = *this; - if (newDistance.m_units == Units::Kilometers) - newDistance = newDistance.To(Units::Meters); - else if (newDistance.m_units == Units::Miles) - newDistance = newDistance.To(Units::Feet); - - double lowValue = round(newDistance.m_distance); + double lowRound = std::round(res.m_distance); // Round distances over 100 units to 10 units, e.g. 112 -> 110, 998 -> 1000 - if (lowValue > 100) - lowValue = round(lowValue / 10) * 10; + if (lowRound > 100) + lowRound = std::round(lowRound / 10) * 10; // Use high units for distances of 1000 units and over, // e.g. 1000m -> 1.0km, 1290m -> 1.3km, 1000ft -> 0.2mi - if (lowValue >= 1000.0) + if (lowRound >= 1000.0) { - double highFactor = newDistance.m_units == Units::Meters ? 1000 : 5280; - double highValue = newDistance.m_distance / highFactor; - newDistance.m_distance = highValue; - newDistance.m_units = newDistance.m_units == Units::Meters ? Units::Kilometers : Units::Miles; - precision = round(highValue * 10) / 10 >= 10.0 ? 0 : 1; + // To high units. + res = res.To(res.m_units == Units::Meters ? Units::Kilometers : Units::Miles); + + // For distances of 10.0 high units and over round to a whole number, e.g. 9.98 -> 10, 10.9 -> 11 + uint8_t const precision = (std::round(res.m_distance * 10) / 10 >= 10.0) ? 0 : 1; + return { WithPrecision(res.m_distance, precision), res.m_units }; } - else - newDistance.m_distance = lowValue; - if (IsHighUnits() && newDistance.GetUnits() != m_units) - newDistance = *this; - - if (newDistance.m_distance > 100) - newDistance.m_distance = round(newDistance.m_distance / 10) * 10; - - if (IsHighUnits() && newDistance.m_distance < 10) - precision = 1; - - return {WithPrecision(newDistance.m_distance, precision), newDistance.m_units}; + res.m_distance = lowRound; + return res; } std::string Distance::ToString() const diff --git a/platform/platform_tests/distance_tests.cpp b/platform/platform_tests/distance_tests.cpp index 32ecc67959..36dce75d04 100644 --- a/platform/platform_tests/distance_tests.cpp +++ b/platform/platform_tests/distance_tests.cpp @@ -108,8 +108,9 @@ UNIT_TEST(Distance_To) double newDistance; Distance::Units newUnits; }; + // clang-format off - std::vector testData{ + TestData testData[] = { {0.1, Units::Meters, Units::Feet, 0, Units::Feet}, {0.3, Units::Meters, Units::Feet, 1, Units::Feet}, {0.3048, Units::Meters, Units::Feet, 1, Units::Feet}, @@ -132,14 +133,17 @@ UNIT_TEST(Distance_To) {15933, Units::Meters, Units::Feet, 9.9, Units::Miles}, {16093, Units::Meters, Units::Feet, 10, Units::Miles}, {16093.5, Units::Meters, Units::Feet, 10, Units::Miles}, - {16898.113, Units::Meters, Units::Feet, 11, Units::Miles}, + {16898.464, Units::Meters, Units::Feet, 11, Units::Miles}, {16898.113, Units::Meters, Units::Kilometers, 17, Units::Kilometers}, - {302, Units::Meters, Units::Miles, 0.2, Units::Miles}, + {302, Units::Meters, Units::Miles, 990, Units::Feet}, + {994, Units::Meters, Units::Kilometers, 990, Units::Meters}, + {995, Units::Meters, Units::Kilometers, 1, Units::Kilometers}, {0.1, Units::Kilometers, Units::Meters, 100, Units::Meters}, + {0.3, Units::Kilometers, Units::Kilometers, 300, Units::Meters}, {12, Units::Kilometers, Units::Feet, 7.5, Units::Miles}, {0.1, Units::Kilometers, Units::Feet, 330, Units::Feet}, {110, Units::Feet, Units::Meters, 34, Units::Meters}, - {1100, Units::Feet, Units::Kilometers, 0.3, Units::Kilometers}, + {1100, Units::Feet, Units::Kilometers, 340, Units::Meters}, {1100, Units::Feet, Units::Meters, 340, Units::Meters}, {1100, Units::Feet, Units::Miles, 0.2, Units::Miles}, {0.2, Units::Miles, Units::Meters, 320, Units::Meters}, @@ -147,13 +151,14 @@ UNIT_TEST(Distance_To) {11, Units::Miles, Units::Kilometers, 18, Units::Kilometers}, {0.1, Units::Miles, Units::Feet, 530, Units::Feet}, }; + // clang-format on for (TestData const & data : testData) { - Distance const formattedDistance = + Distance const formatted = Distance(data.initialDistance, data.initialUnits).To(data.to).GetFormattedDistance(); - TEST_ALMOST_EQUAL_ULPS(formattedDistance.GetDistance(), data.newDistance, (formattedDistance.ToString())); - TEST_EQUAL(formattedDistance.GetUnits(), data.newUnits, (formattedDistance.ToString())); + TEST_ALMOST_EQUAL_ULPS(formatted.GetDistance(), data.newDistance, (data.initialDistance)); + TEST_EQUAL(formatted.GetUnits(), data.newUnits, ()); } } @@ -229,8 +234,9 @@ UNIT_TEST(Distance_FormattedDistance) std::string formattedDistanceString; std::string formattedString; }; + // clang-format off - std::vector testData{ + TestData testData[] = { // From Meters to Meters {Distance(0, Units::Meters), 0, Units::Meters, "0", "0 m"}, {Distance(0.3, Units::Meters), 0, Units::Meters, "0", "0 m"}, @@ -250,17 +256,21 @@ UNIT_TEST(Distance_FormattedDistance) {Distance(991, Units::Meters), 990, Units::Meters, "990", "990 m"}, // From Kilometers to Kilometers - {Distance(0, Units::Kilometers), 0, Units::Kilometers, "0", "0 km"}, + {Distance(0, Units::Kilometers), 0, Units::Meters, "0", "0 m"}, + {Distance(0.3, Units::Kilometers), 300, Units::Meters, "300", "300 m"}, {Distance(1.234, Units::Kilometers), 1.2, Units::Kilometers, "1.2", "1.2 km"}, {Distance(10, Units::Kilometers), 10, Units::Kilometers, "10", "10 km"}, + {Distance(11, Units::Kilometers), 11, Units::Kilometers, "11", "11 km"}, + {Distance(54, Units::Kilometers), 54, Units::Kilometers, "54", "54 km"}, {Distance(99.99, Units::Kilometers), 100, Units::Kilometers, "100", "100 km"}, {Distance(100.01, Units::Kilometers), 100, Units::Kilometers, "100", "100 km"}, - {Distance(115, Units::Kilometers), 120, Units::Kilometers, "120", "120 km"}, - {Distance(130, Units::Kilometers), 130, Units::Kilometers, "130", "130 km"}, - {Distance(980, Units::Kilometers), 980, Units::Kilometers, "980", "980 km"}, + {Distance(115, Units::Kilometers), 115, Units::Kilometers, "115", "115 km"}, + {Distance(999, Units::Kilometers), 999, Units::Kilometers, "999", "999 km"}, {Distance(1000, Units::Kilometers), 1000, Units::Kilometers, "1000", "1000 km"}, + {Distance(1049.99, Units::Kilometers), 1050, Units::Kilometers, "1050", "1050 km"}, {Distance(1050, Units::Kilometers), 1050, Units::Kilometers, "1050", "1050 km"}, - {Distance(1234, Units::Kilometers), 1230, Units::Kilometers, "1230", "1230 km"}, + {Distance(1050.01, Units::Kilometers), 1050, Units::Kilometers, "1050", "1050 km"}, + {Distance(1234, Units::Kilometers), 1234, Units::Kilometers, "1234", "1234 km"}, // From Feet to Feet {Distance(0, Units::Feet), 0, Units::Feet, "0", "0 ft"}, @@ -272,16 +282,19 @@ UNIT_TEST(Distance_FormattedDistance) {Distance(991, Units::Feet), 990, Units::Feet, "990", "990 ft"}, // From Miles to Miles - {Distance(0, Units::Miles), 0, Units::Miles, "0", "0 mi"}, + {Distance(0, Units::Miles), 0, Units::Feet, "0", "0 ft"}, + {Distance(0.1, Units::Miles), 530, Units::Feet, "530", "530 ft"}, {Distance(1, Units::Miles), 1, Units::Miles, "1", "1 mi"}, {Distance(1.234, Units::Miles), 1.2, Units::Miles, "1.2", "1.2 mi"}, {Distance(9.99, Units::Miles), 10, Units::Miles, "10", "10 mi"}, {Distance(10.01, Units::Miles), 10, Units::Miles, "10", "10 mi"}, - {Distance(105, Units::Miles), 110, Units::Miles, "110", "110 mi"}, - {Distance(145, Units::Miles), 150, Units::Miles, "150", "150 mi"}, - {Distance(998, Units::Miles), 1000, Units::Miles, "1000", "1000 mi"}, - {Distance(999, Units::Miles), 1000, Units::Miles, "1000", "1000 mi"}, + {Distance(11, Units::Miles), 11, Units::Miles, "11", "11 mi"}, + {Distance(54, Units::Miles), 54, Units::Miles, "54", "54 mi"}, + {Distance(145, Units::Miles), 145, Units::Miles, "145", "145 mi"}, + {Distance(999, Units::Miles), 999, Units::Miles, "999", "999 mi"}, + {Distance(1149.99, Units::Miles), 1150, Units::Miles, "1150", "1150 mi"}, {Distance(1150, Units::Miles), 1150, Units::Miles, "1150", "1150 mi"}, + {Distance(1150.01, Units::Miles), 1150, Units::Miles, "1150", "1150 mi"}, // From Meters to Kilometers {Distance(999, Units::Meters), 1, Units::Kilometers, "1", "1 km"}, @@ -299,7 +312,9 @@ UNIT_TEST(Distance_FormattedDistance) {Distance(10000, Units::Meters), 10, Units::Kilometers, "10", "10 km"}, {Distance(10499.9, Units::Meters), 10, Units::Kilometers, "10", "10 km"}, {Distance(10501, Units::Meters), 11, Units::Kilometers, "11", "11 km"}, - {Distance(287'386, Units::Meters), 290, Units::Kilometers, "290", "290 km"}, + {Distance(101'001, Units::Meters), 101, Units::Kilometers, "101", "101 km"}, + {Distance(101'999, Units::Meters), 102, Units::Kilometers, "102", "102 km"}, + {Distance(287'386, Units::Meters), 287, Units::Kilometers, "287", "287 km"}, // From Feet to Miles {Distance(999, Units::Feet), 0.2, Units::Miles, "0.2", "0.2 mi"}, @@ -309,19 +324,26 @@ UNIT_TEST(Distance_FormattedDistance) {Distance(7920, Units::Feet), 1.5, Units::Miles, "1.5", "1.5 mi"}, {Distance(10560, Units::Feet), 2, Units::Miles, "2", "2 mi"}, {Distance(100'000, Units::Feet), 19, Units::Miles, "19", "19 mi"}, + {Distance(285'120, Units::Feet), 54, Units::Miles, "54", "54 mi"}, + {Distance(633'547, Units::Feet), 120, Units::Miles, "120", "120 mi"}, + {Distance(633'600, Units::Feet), 120, Units::Miles, "120", "120 mi"}, + {Distance(633'653, Units::Feet), 120, Units::Miles, "120", "120 mi"}, + {Distance(999'999, Units::Feet), 189, Units::Miles, "189", "189 mi"}, }; + // clang-format on for (TestData const & data : testData) { - Distance const formattedDistance = data.distance.GetFormattedDistance(); + Distance const formatted = data.distance.GetFormattedDistance(); // Run two times to verify that nothing breaks after second format - for (auto const & d : {formattedDistance, formattedDistance.GetFormattedDistance()}) + for (auto const & d : {formatted, formatted.GetFormattedDistance()}) { - TEST_ALMOST_EQUAL_ULPS(d.GetDistance(), data.formattedDistance, (data.distance.ToString())); - TEST_EQUAL(d.GetUnits(), data.formattedUnits, (data.distance.ToString())); - TEST_EQUAL(d.GetDistanceString(), data.formattedDistanceString, (data.distance.ToString())); - TEST_EQUAL(d.ToString(), data.formattedString, (data.distance.ToString())); + TEST_ALMOST_EQUAL_ULPS(d.GetDistance(), data.formattedDistance, (data.distance)); + TEST_EQUAL(d.GetUnits(), data.formattedUnits, (data.distance)); + TEST_EQUAL(d.GetDistanceString(), data.formattedDistanceString, (data.distance)); + TEST_EQUAL(d.ToString(), data.formattedString, (data.distance)); } } } + } // namespace platform