MeasurementUtils::OSMDistanceToMeters validation.

This commit is contained in:
Alex Zolotarev 2016-03-15 20:39:41 +03:00 committed by Sergey Yershov
parent 226b50494a
commit ba208ffb6c
3 changed files with 163 additions and 1 deletions

View file

@ -3,9 +3,12 @@
#include "geometry/mercator.hpp"
#include "base/string_utils.hpp"
#include "base/macros.hpp"
#include "base/math.hpp"
#include "base/stl_add.hpp"
#include "base/string_utils.hpp"
#include "std/cstring.hpp"
#include "std/iomanip.hpp"
#include "std/sstream.hpp"
@ -189,4 +192,97 @@ string FormatSpeed(double metersPerSecond)
return res;
}
bool OSMDistanceToMeters(string const & osmRawValue, double & outMeters)
{
char * stop;
char const * s = osmRawValue.c_str();
outMeters = strtod(s, &stop);
// Not a number, was not parsed at all.
if (s == stop)
return false;
if (!isfinite(outMeters))
return false;
switch (*stop)
{
// Default units - meters.
case 0: return true;
// Feet and probably inches.
case '\'':
{
outMeters = FeetToMeters(outMeters);
s = stop + 1;
double const inches = strtod(s, &stop);
if (s != stop && *stop == '"' && isfinite(inches))
outMeters += InchesToMeters(inches);
return true;
}
break;
// Inches.
case '\"': outMeters = InchesToMeters(outMeters); return true;
// It's probably a range. Use maximum value (if possible) for a range.
case '-':
{
s = stop + 1;
double const newValue = strtod(s, &stop);
if (s != stop && isfinite(newValue))
outMeters = newValue;
}
break;
// It's probably a list. Use maximum value (if possible) for a list.
case ';':
do
{
s = stop + 1;
double const newValue = strtod(s, &stop);
if (s == stop)
break;
if (isfinite(newValue))
outMeters = newValue;
} while (*stop && *stop == ';');
break;
}
while (*stop && isspace(*stop))
++stop;
// Default units - meters.
if (*stop == 0)
return true;
if (strstr(stop, "nmi") == stop)
outMeters = NauticalMilesToMeters(outMeters);
else if (strstr(stop, "mi") == stop)
outMeters = MilesToMeters(outMeters);
else if (strstr(stop, "ft") == stop)
outMeters = FeetToMeters(outMeters);
else if (strstr(stop, "feet") == stop)
outMeters = FeetToMeters(outMeters);
else if (strstr(stop, "km") == stop)
outMeters = outMeters * 1000;
// Count all other cases as meters.
return true;
}
string OSMDistanceToMetersString(string const & osmRawValue,
bool supportZeroAndNegativeValues,
int digitsAfterComma)
{
double meters;
if (OSMDistanceToMeters(osmRawValue, meters))
{
if (!supportZeroAndNegativeValues && meters <= 0)
return {};
return strings::to_string_dac(meters, digitsAfterComma);
}
return {};
}
} // namespace MeasurementUtils

View file

@ -12,6 +12,8 @@ inline double MilesToMeters(double mi) { return mi * 1609.344; }
inline double MetersToFeet(double m) { return m * 3.2808399; }
inline double FeetToMeters(double ft) { return ft * 0.3048; }
inline double FeetToMiles(double ft) { return ft * 5280; }
inline double InchesToMeters(double in) { return in / 39.370; }
inline double NauticalMilesToMeters(double nmi) { return nmi * 1852; }
/// Takes into an account user settings [metric, imperial]
/// @param[in] m meters
@ -37,4 +39,13 @@ void FormatLatLon(double lat, double lon, string & latText, string & lonText, in
string FormatMercator(m2::PointD const & mercator, int dac = 6);
void FormatMercator(m2::PointD const & mercator, string & lat, string & lon, int dac = 6);
/// Converts OSM distance (height, ele etc.) to meters.
/// @returns false if fails.
bool OSMDistanceToMeters(string const & osmRawValue, double & outMeters);
/// Converts OSM distance (height, ele etc.) to meters string.
/// @returns empty string on failure.
string OSMDistanceToMetersString(string const & osmRawValue,
bool supportZeroAndNegativeValues = true,
int digitsAfterComma = 2);
}

View file

@ -101,3 +101,58 @@ UNIT_TEST(FormatSpeed)
TEST_EQUAL(FormatSpeed(10), "36km/h", ());
TEST_EQUAL(FormatSpeed(1), "3.6km/h", ());
}
UNIT_TEST(OSMDistanceToMetersString)
{
TEST_EQUAL(OSMDistanceToMetersString(""), "", ());
TEST_EQUAL(OSMDistanceToMetersString("INF"), "", ());
TEST_EQUAL(OSMDistanceToMetersString("NAN"), "", ());
TEST_EQUAL(OSMDistanceToMetersString("not a number"), "", ());
TEST_EQUAL(OSMDistanceToMetersString("10й"), "10", ());
TEST_EQUAL(OSMDistanceToMetersString("0"), "0", ());
TEST_EQUAL(OSMDistanceToMetersString("0.0"), "0", ());
TEST_EQUAL(OSMDistanceToMetersString("0.0000000"), "0", ());
TEST_EQUAL(OSMDistanceToMetersString("22.5"), "22.5", ());
TEST_EQUAL(OSMDistanceToMetersString("+21.5"), "21.5", ());
TEST_EQUAL(OSMDistanceToMetersString("1e+2"), "100", ());
TEST_EQUAL(OSMDistanceToMetersString("5 метров"), "5", ());
TEST_EQUAL(OSMDistanceToMetersString(" 4.4 "), "4.4", ());
TEST_EQUAL(OSMDistanceToMetersString("8-15"), "15", ());
TEST_EQUAL(OSMDistanceToMetersString("8-15 ft"), "4.57", ());
TEST_EQUAL(OSMDistanceToMetersString("8-й километр"), "8", ());
TEST_EQUAL(OSMDistanceToMetersString("8;9;10"), "10", ());
TEST_EQUAL(OSMDistanceToMetersString("8;9;10 meters"), "10", ());
TEST_EQUAL(OSMDistanceToMetersString("8;9;10 km"), "10000", ());
TEST_EQUAL(OSMDistanceToMetersString("10;20!111"), "20", ());
TEST_EQUAL(OSMDistanceToMetersString("10;20\""), "20", ());
TEST_EQUAL(OSMDistanceToMetersString("-100.3"), "-100.3", ());
TEST_EQUAL(OSMDistanceToMetersString("99.0000000"), "99", ());
TEST_EQUAL(OSMDistanceToMetersString("8900.000023"), "8900", ());
TEST_EQUAL(OSMDistanceToMetersString("-300.9999"), "-301", ());
TEST_EQUAL(OSMDistanceToMetersString("-300.9"), "-300.9", ());
TEST_EQUAL(OSMDistanceToMetersString("15 m"), "15", ());
TEST_EQUAL(OSMDistanceToMetersString("15.9 m"), "15.9", ());
TEST_EQUAL(OSMDistanceToMetersString("15.9m"), "15.9", ());
TEST_EQUAL(OSMDistanceToMetersString("3000 ft"), "914.4", ());
TEST_EQUAL(OSMDistanceToMetersString("3000ft"), "914.4", ());
TEST_EQUAL(OSMDistanceToMetersString("100 feet"), "30.48", ());
TEST_EQUAL(OSMDistanceToMetersString("100feet"), "30.48", ());
TEST_EQUAL(OSMDistanceToMetersString("3 nmi"), "5556", ());
TEST_EQUAL(OSMDistanceToMetersString("3 mi"), "4828.03", ());
TEST_EQUAL(OSMDistanceToMetersString("3.3 km"), "3300", ());
TEST_EQUAL(OSMDistanceToMetersString("105'"), "32", ());
TEST_EQUAL(OSMDistanceToMetersString("11'"), "3.35", ());
TEST_EQUAL(OSMDistanceToMetersString("11 3\""), "11", ());
TEST_EQUAL(OSMDistanceToMetersString("11 3'"), "11", ());
TEST_EQUAL(OSMDistanceToMetersString("11\"'"), "0.28", ());
TEST_EQUAL(OSMDistanceToMetersString("11'\""), "3.35", ());
TEST_EQUAL(OSMDistanceToMetersString("11'4\""), "3.45", ());
TEST_EQUAL(OSMDistanceToMetersString("11\""), "0.28", ());
TEST_EQUAL(OSMDistanceToMetersString("100 \""), "100", ());
TEST_EQUAL(OSMDistanceToMetersString("0", false), "", ());
TEST_EQUAL(OSMDistanceToMetersString("-15", false), "", ());
TEST_EQUAL(OSMDistanceToMetersString("15.12345", false, 1), "15.1", ());
TEST_EQUAL(OSMDistanceToMetersString("15.123", false, 4), "15.123", ());
TEST_EQUAL(OSMDistanceToMetersString("15.654321", true, 1), "15.7", ());
}