forked from organicmaps/organicmaps
[platform] Simplify Distance::GetFormattedDistance().
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
This commit is contained in:
parent
847bf0240b
commit
1ead1f5931
2 changed files with 87 additions and 66 deletions
|
@ -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
|
||||
|
|
|
@ -108,8 +108,9 @@ UNIT_TEST(Distance_To)
|
|||
double newDistance;
|
||||
Distance::Units newUnits;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
std::vector<TestData> 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 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
|
||||
|
|
Loading…
Add table
Reference in a new issue