forked from organicmaps/organicmaps
[search] Implemented search by POI with house numbers.
This commit is contained in:
parent
f2b7db27f1
commit
58df58f385
6 changed files with 121 additions and 41 deletions
|
@ -149,7 +149,11 @@ UNIT_CLASS_TEST(SearchQueryV2Test, Smoke)
|
|||
TestPOI busStop(m2::PointD(0, 0), "Bus stop", "en");
|
||||
TestPOI tramStop(m2::PointD(0.0001, 0.0001), "Tram stop", "en");
|
||||
TestPOI quantumTeleport1(m2::PointD(0.0002, 0.0002), "Quantum teleport 1", "en");
|
||||
|
||||
TestPOI quantumTeleport2(m2::PointD(10, 10), "Quantum teleport 2", "en");
|
||||
quantumTeleport2.SetHouseNumber("3");
|
||||
quantumTeleport2.SetStreet(feynmanStreet);
|
||||
|
||||
TestPOI quantumCafe(m2::PointD(-0.0002, -0.0002), "Quantum cafe", "en");
|
||||
TestPOI lantern1(m2::PointD(10.0005, 10.0005), "lantern 1", "en");
|
||||
TestPOI lantern2(m2::PointD(10.0006, 10.0005), "lantern 2", "en");
|
||||
|
@ -214,6 +218,10 @@ UNIT_CLASS_TEST(SearchQueryV2Test, Smoke)
|
|||
TRules rules = {make_shared<ExactMatch>(wonderlandId, quantumTeleport2)};
|
||||
TEST(ResultsMatch("teleport feynman street", rules), ());
|
||||
}
|
||||
{
|
||||
TRules rules = {make_shared<ExactMatch>(wonderlandId, quantumTeleport2)};
|
||||
TEST(ResultsMatch("feynman street 3", rules), ());
|
||||
}
|
||||
{
|
||||
TRules rules = {make_shared<ExactMatch>(wonderlandId, feynmanHouse),
|
||||
make_shared<ExactMatch>(wonderlandId, lantern1)};
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "indexer/classificator.hpp"
|
||||
#include "indexer/feature.hpp"
|
||||
#include "indexer/feature_algo.hpp"
|
||||
#include "indexer/ftypes_matcher.hpp"
|
||||
|
||||
#include "coding/multilang_utf8_string.hpp"
|
||||
|
@ -16,6 +17,11 @@ namespace search
|
|||
{
|
||||
namespace tests_support
|
||||
{
|
||||
namespace
|
||||
{
|
||||
double const kTestPrecision = 1e-4;
|
||||
} // namespace
|
||||
|
||||
// TestFeature -------------------------------------------------------------------------------------
|
||||
TestFeature::TestFeature(string const & name, string const & lang)
|
||||
: m_center(0, 0), m_hasCenter(false), m_name(name), m_lang(lang)
|
||||
|
@ -38,27 +44,16 @@ bool TestFeature::Matches(FeatureType const & feature) const
|
|||
{
|
||||
uint8_t const langIndex = StringUtf8Multilang::GetLangIndex(m_lang);
|
||||
string name;
|
||||
return feature.GetName(langIndex, name) && m_name == name;
|
||||
}
|
||||
|
||||
// TestPOI -----------------------------------------------------------------------------------------
|
||||
TestPOI::TestPOI(m2::PointD const & center, string const & name, string const & lang)
|
||||
: TestFeature(center, name, lang)
|
||||
{
|
||||
}
|
||||
|
||||
void TestPOI::Serialize(FeatureBuilder1 & fb) const
|
||||
{
|
||||
TestFeature::Serialize(fb);
|
||||
auto const & classificator = classif();
|
||||
fb.SetType(classificator.GetTypeByPath({"railway", "station"}));
|
||||
}
|
||||
|
||||
string TestPOI::ToString() const
|
||||
{
|
||||
ostringstream os;
|
||||
os << "TestPOI [" << m_name << ", " << m_lang << ", " << DebugPrint(m_center) << "]";
|
||||
return os.str();
|
||||
bool const nameMatches = feature.GetName(langIndex, name) && m_name == name;
|
||||
if (!nameMatches)
|
||||
return false;
|
||||
if (m_hasCenter)
|
||||
{
|
||||
auto const center = feature::GetCenter(feature);
|
||||
if (!m_center.EqualDxDy(center, kTestPrecision))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// TestCountry -------------------------------------------------------------------------------------
|
||||
|
@ -153,6 +148,40 @@ string TestStreet::ToString() const
|
|||
return os.str();
|
||||
}
|
||||
|
||||
// TestPOI -----------------------------------------------------------------------------------------
|
||||
TestPOI::TestPOI(m2::PointD const & center, string const & name, string const & lang)
|
||||
: TestFeature(center, name, lang)
|
||||
{
|
||||
}
|
||||
|
||||
void TestPOI::Serialize(FeatureBuilder1 & fb) const
|
||||
{
|
||||
TestFeature::Serialize(fb);
|
||||
auto const & classificator = classif();
|
||||
fb.SetType(classificator.GetTypeByPath({"railway", "station"}));
|
||||
if (!m_houseNumber.empty())
|
||||
fb.AddHouseNumber(m_houseNumber);
|
||||
if (!m_streetName.empty())
|
||||
fb.AddStreet(m_streetName);
|
||||
}
|
||||
|
||||
bool TestPOI::Matches(FeatureType const & feature) const
|
||||
{
|
||||
return TestFeature::Matches(feature) && m_houseNumber == feature.GetHouseNumber();
|
||||
}
|
||||
|
||||
string TestPOI::ToString() const
|
||||
{
|
||||
ostringstream os;
|
||||
os << "TestPOI [" << m_name << ", " << m_lang << ", " << DebugPrint(m_center);
|
||||
if (!m_houseNumber.empty())
|
||||
os << ", " << m_houseNumber;
|
||||
if (!m_streetName.empty())
|
||||
os << ", " << m_streetName;
|
||||
os << "]";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
// TestBuilding ------------------------------------------------------------------------------------
|
||||
TestBuilding::TestBuilding(m2::PointD const & center, string const & name,
|
||||
string const & houseNumber, string const & lang)
|
||||
|
@ -177,6 +206,7 @@ TestBuilding::TestBuilding(vector<m2::PointD> const & boundary, string const & n
|
|||
, m_houseNumber(houseNumber)
|
||||
, m_streetName(street.GetName())
|
||||
{
|
||||
ASSERT(!m_boundary.empty(), ());
|
||||
}
|
||||
|
||||
void TestBuilding::Serialize(FeatureBuilder1 & fb) const
|
||||
|
@ -201,7 +231,22 @@ bool TestBuilding::Matches(FeatureType const & feature) const
|
|||
auto const & checker = ftypes::IsBuildingChecker::Instance();
|
||||
if (!checker(feature))
|
||||
return false;
|
||||
return TestFeature::Matches(feature) && m_houseNumber == feature.GetHouseNumber();
|
||||
if (!TestFeature::Matches(feature))
|
||||
return false;
|
||||
if (m_houseNumber != feature.GetHouseNumber())
|
||||
return false;
|
||||
|
||||
// TODO(@y): consider to check m_boundary.
|
||||
if (!m_hasCenter && !m_boundary.empty())
|
||||
{
|
||||
m2::PointD center(0, 0);
|
||||
for (auto const & p : m_boundary)
|
||||
center += p;
|
||||
center = center / m_boundary.size();
|
||||
if (!center.EqualDxDy(feature::GetCenter(feature), kTestPrecision))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string TestBuilding::ToString() const
|
||||
|
|
|
@ -33,16 +33,6 @@ protected:
|
|||
string const m_lang;
|
||||
};
|
||||
|
||||
class TestPOI : public TestFeature
|
||||
{
|
||||
public:
|
||||
TestPOI(m2::PointD const & center, string const & name, string const & lang);
|
||||
|
||||
// TestFeature overrides:
|
||||
void Serialize(FeatureBuilder1 & fb) const override;
|
||||
string ToString() const override;
|
||||
};
|
||||
|
||||
class TestCountry : public TestFeature
|
||||
{
|
||||
public:
|
||||
|
@ -92,6 +82,24 @@ private:
|
|||
vector<m2::PointD> m_points;
|
||||
};
|
||||
|
||||
class TestPOI : public TestFeature
|
||||
{
|
||||
public:
|
||||
TestPOI(m2::PointD const & center, string const & name, string const & lang);
|
||||
|
||||
// TestFeature overrides:
|
||||
void Serialize(FeatureBuilder1 & fb) const override;
|
||||
bool Matches(FeatureType const & feature) const override;
|
||||
string ToString() const override;
|
||||
|
||||
inline void SetHouseNumber(string const & houseNumber) { m_houseNumber = houseNumber; }
|
||||
inline void SetStreet(TestStreet const & street) { m_streetName = street.GetName(); }
|
||||
|
||||
private:
|
||||
string m_houseNumber;
|
||||
string m_streetName;
|
||||
};
|
||||
|
||||
class TestBuilding : public TestFeature
|
||||
{
|
||||
public:
|
||||
|
@ -107,7 +115,7 @@ public:
|
|||
bool Matches(FeatureType const & feature) const override;
|
||||
string ToString() const override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
vector<m2::PointD> const m_boundary;
|
||||
string const m_houseNumber;
|
||||
string const m_streetName;
|
||||
|
|
|
@ -239,7 +239,6 @@ private:
|
|||
vector<strings::UniString> queryTokens;
|
||||
NormalizeHouseNumber(child.m_subQuery, queryTokens);
|
||||
|
||||
auto const & checker = ftypes::IsBuildingChecker::Instance();
|
||||
uint32_t numFilterInvocations = 0;
|
||||
auto houseNumberFilter = [&](uint32_t id, FeatureType & feature, bool & loaded) -> bool
|
||||
{
|
||||
|
@ -262,9 +261,6 @@ private:
|
|||
loaded = true;
|
||||
}
|
||||
|
||||
if (!checker(feature))
|
||||
return false;
|
||||
|
||||
if (!child.m_hasDelayedFeatures)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "search/v2/search_model.hpp"
|
||||
|
||||
#include "indexer/classificator.hpp"
|
||||
#include "indexer/feature.hpp"
|
||||
#include "indexer/ftypes_matcher.hpp"
|
||||
|
||||
#include "base/macros.hpp"
|
||||
|
@ -21,7 +22,7 @@ public:
|
|||
{
|
||||
Classificator const & c = classif();
|
||||
|
||||
auto paths = { "amenity", "historic", "office", "railway", "shop", "sport", "tourism", "craft" };
|
||||
auto paths = {"amenity", "historic", "office", "railway", "shop", "sport", "tourism", "craft"};
|
||||
for (auto const & path : paths)
|
||||
m_types.push_back(c.GetTypeByPath({path}));
|
||||
}
|
||||
|
@ -54,6 +55,21 @@ private:
|
|||
OneLevelPOIChecker const m_oneLevel;
|
||||
TwoLevelPOIChecker const m_twoLevel;
|
||||
};
|
||||
|
||||
class CustomIsBuildingChecker
|
||||
{
|
||||
public:
|
||||
static CustomIsBuildingChecker const & Instance()
|
||||
{
|
||||
static const CustomIsBuildingChecker inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
bool operator()(FeatureType const & ft) const { return !ft.GetHouseNumber().empty(); }
|
||||
|
||||
private:
|
||||
CustomIsBuildingChecker() {}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
|
@ -65,7 +81,7 @@ SearchModel const & SearchModel::Instance()
|
|||
|
||||
SearchModel::SearchType SearchModel::GetSearchType(FeatureType const & feature) const
|
||||
{
|
||||
static auto const & buildingChecker = IsBuildingChecker::Instance();
|
||||
static auto const & buildingChecker = CustomIsBuildingChecker::Instance();
|
||||
static auto const & streetChecker = IsStreetChecker::Instance();
|
||||
static auto const & localityChecker = IsLocalityChecker::Instance();
|
||||
static auto const & poiChecker = IsPoiChecker::Instance();
|
||||
|
|
|
@ -24,11 +24,18 @@ class SearchModel
|
|||
public:
|
||||
enum SearchType
|
||||
{
|
||||
// Low-level features such as amenities, offices, shops, buildings
|
||||
// without house number, etc.
|
||||
SEARCH_TYPE_POI,
|
||||
|
||||
// All features with set house number.
|
||||
SEARCH_TYPE_BUILDING,
|
||||
|
||||
SEARCH_TYPE_STREET,
|
||||
SEARCH_TYPE_UNCLASSIFIED, // all low-level features except POI,
|
||||
// BUILDING and STREET
|
||||
|
||||
// All low-level features except POI, BUILDING and STREET.
|
||||
SEARCH_TYPE_UNCLASSIFIED,
|
||||
|
||||
SEARCH_TYPE_VILLAGE,
|
||||
SEARCH_TYPE_CITY,
|
||||
SEARCH_TYPE_STATE, // US or Canadian states
|
||||
|
|
Loading…
Add table
Reference in a new issue