diff --git a/search/latlon_match.cpp b/search/latlon_match.cpp index 8708a54f26..3fa2a5176b 100644 --- a/search/latlon_match.cpp +++ b/search/latlon_match.cpp @@ -1,13 +1,14 @@ #include "latlon_match.hpp" -#include "../indexer/mercator.hpp" - #include "../base/macros.hpp" #include "../std/array.hpp" #include "../std/cmath.hpp" #include "../std/cstdlib.hpp" #include "../std/cstring.hpp" +#include "../std/algorithm.hpp" +#include "../std/utility.hpp" + namespace search { @@ -161,10 +162,10 @@ bool MatchLatLonDegree(string const & query, double & lat, double & lon) double const x = strtod(s, &s2); if (s == s2) { - // Invalid token + // invalid token if (s == s1) { - // Return error if there are no any delimiters + // Return error if there are no any delimiters. return false; } else @@ -177,26 +178,36 @@ bool MatchLatLonDegree(string const & query, double & lat, double & lon) s = s2; SkipSpaces(s); - int const i = GetDMSIndex(s); - switch (i) + int i = GetDMSIndex(s); + if (i == -1) { - case -1: // expect valid control symbol - return false; + if (v[base].second && v[base + 1].second && !v[base + 2].second) + { + // assume seconds if degrees and minutes are present + i = 2; + } + else + { + // assume degrees by default + i = 0; + } + } - case 0: // degree + if (i == 0) // degrees + { if (v[base].second) { if (base == 0) base += 3; else { - // repeated value + // too many degree values return false; } } - break; - - default: // minutes or seconds + } + else // minutes or seconds + { if (x < 0.0 || v[base + i].second || !v[base].second) return false; } @@ -230,10 +241,18 @@ bool MatchLatLonDegree(string const & query, double & lat, double & lon) if (arrPos[1]) lat = -lat; if (arrPos[3]) lon = -lon; - if (lon > 180.0) lon -= 360.0; - if (lon < -180.0) lon += 360.0; + // Valid input ranges for longitude are: [0, 360] or [-180, 180]. + // We do normilize it to [-180, 180]. + if (lon > 180.0) + { + if (lon > 360.0) + return false; + lon -= 360.0; + } + else if (lon < -180.0) + return false; - return MercatorBounds::ValidLat(lat) && MercatorBounds::ValidLon(lon); + return (fabs(lat) <= 90.0); } } // search diff --git a/search/latlon_match.hpp b/search/latlon_match.hpp index c62bc424b4..122b8b9fb5 100644 --- a/search/latlon_match.hpp +++ b/search/latlon_match.hpp @@ -1,14 +1,16 @@ #pragma once -#include "../base/base.hpp" #include "../std/string.hpp" + namespace search { -// Check if query can be represented as '(lat, lon)'. +/// Check if query can be represented as '(lat, lon)'. +/// @deprecated Use MatchLatLonDegree instead. bool MatchLatLon(string const & query, double & lat, double & lon, double & precisionLat, double & precisionLon); +/// Parse input query for most input coordinates cases. bool MatchLatLonDegree(string const & query, double & lat, double & lon); } // namespace search diff --git a/search/search_query.cpp b/search/search_query.cpp index 2d8a7f44a1..3b41022450 100644 --- a/search/search_query.cpp +++ b/search/search_query.cpp @@ -321,9 +321,8 @@ void Query::SetQuery(string const & query) void Query::SearchCoordinates(string const & query, Results & res) const { - double lat, lon, latPrec, lonPrec; - if (MatchLatLon(query, lat, lon, latPrec, lonPrec) || - MatchLatLonDegree(query, lat, lon)) + double lat, lon; + if (MatchLatLonDegree(query, lat, lon)) { //double const precision = 5.0 * max(0.0001, min(latPrec, lonPrec)); // Min 55 meters res.AddResult(MakeResult(impl::PreResult2(GetViewport(), m_position, lat, lon))); diff --git a/search/search_tests/latlon_match_test.cpp b/search/search_tests/latlon_match_test.cpp index 848eef6491..dbd4467ded 100644 --- a/search/search_tests/latlon_match_test.cpp +++ b/search/search_tests/latlon_match_test.cpp @@ -18,6 +18,12 @@ pair, pair > TestLatLonMatchSuccessful(stri double precLat = -3503; double precLon = -3504; TEST(search::MatchLatLon(s, lat, lon, precLat, precLon), (s, lat, lon, precLat, precLon)); + + double lat1, lon1; + TEST(search::MatchLatLonDegree(s, lat1, lon1), (s)); + TEST_ALMOST_EQUAL(lat, lat1, ()); + TEST_ALMOST_EQUAL(lon, lon1, ()); + return make_pair(make_pair(lat, lon), make_pair(precLat, precLon)); } @@ -27,11 +33,14 @@ void TestLatLonFailed(string const & s) double lon = -3502; double latPrec = -3503; double lonPrec = -3504; + TEST(!search::MatchLatLon(s, lat, lon, latPrec, lonPrec), (s, lat, lon, latPrec, lonPrec)); TEST_EQUAL(lat, -3501, ()); TEST_EQUAL(lon, -3502, ()); TEST_EQUAL(latPrec, -3503, ()); TEST_EQUAL(lonPrec, -3504, ()); + + TEST(!search::MatchLatLonDegree(s, lat, lon), (s)); } } // unnamed namespace @@ -124,4 +133,12 @@ UNIT_TEST(LatLon_Degree_Match) TEST(!MatchLatLonDegree("55°45′20.9916″W 37°37′3.6228″E", lat, lon), ()); TEST(!MatchLatLonDegree("N55°45′20.9916″ S37°37′3.6228″", lat, lon), ()); + + TEST(MatchLatLonDegree("54° 25' 0N 1° 53' 46W", lat, lon), ()); + TEST_ALMOST_EQUAL(lat, 54.41666666666667, ()); + TEST_ALMOST_EQUAL(lon, -1.89611111111111, ()); + + TEST(MatchLatLonDegree("47.33471°N 8.53112°E", lat, lon), ()); + TEST_ALMOST_EQUAL(lat, 47.33471, ()); + TEST_ALMOST_EQUAL(lon, 8.53112, ()); }