1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
#include "search/features_layer_matcher.hpp"
#include "search/house_to_street_table.hpp"
#include "search/reverse_geocoder.hpp"
#include "editor/osm_editor.hpp"
#include "indexer/scales.hpp"
#include "base/assert.hpp"
#include <string>
using namespace std;
namespace search
{
/// Max distance from house to street where we do search matching
/// even if there is no exact street written for this house.
int constexpr kMaxApproxStreetDistanceM = 100;
FeaturesLayerMatcher::FeaturesLayerMatcher(DataSource const & dataSource,
base::Cancellable const & cancellable)
: m_context(nullptr)
, m_postcodes(nullptr)
, m_reverseGeocoder(dataSource)
, m_nearbyStreetsCache("FeatureToNearbyStreets")
, m_matchingStreetsCache("BuildingToStreet")
, m_loader(scales::GetUpperScale(), ReverseGeocoder::kLookupRadiusM)
, m_cancellable(cancellable)
{
}
void FeaturesLayerMatcher::SetContext(MwmContext * context)
{
ASSERT(context, ());
if (m_context == context)
return;
m_context = context;
m_loader.SetContext(context);
}
void FeaturesLayerMatcher::SetPostcodes(CBV const * postcodes)
{
m_postcodes = postcodes;
}
void FeaturesLayerMatcher::OnQueryFinished()
{
m_nearbyStreetsCache.ClearIfNeeded();
m_matchingStreetsCache.ClearIfNeeded();
m_loader.OnQueryFinished();
}
uint32_t FeaturesLayerMatcher::GetMatchingStreet(uint32_t houseId)
{
auto entry = m_matchingStreetsCache.Get(houseId);
if (!entry.second)
return entry.first;
auto feature = GetByIndex(houseId);
if (!feature)
return kInvalidId;
return GetMatchingStreet(*feature);
}
FeaturesLayerMatcher::Streets const & FeaturesLayerMatcher::GetNearbyStreets(FeatureType & feature)
{
static FeaturesLayerMatcher::Streets const kEmptyStreets;
auto entry = m_nearbyStreetsCache.Get(feature.GetID().m_index);
if (!entry.second)
return entry.first;
auto & streets = entry.first;
m_reverseGeocoder.GetNearbyStreets(feature, streets);
return streets;
}
uint32_t FeaturesLayerMatcher::GetMatchingStreet(FeatureType & houseFeature)
{
// Check if this feature is modified - the logic will be different.
string streetName;
bool const edited =
osm::Editor::Instance().GetEditedFeatureStreet(houseFeature.GetID(), streetName);
// Check the cached result value.
auto entry = m_matchingStreetsCache.Get(houseFeature.GetID().m_index);
if (!edited && !entry.second)
return entry.first;
uint32_t & result = entry.first;
result = kInvalidId;
FeatureID streetId;
if (!edited && m_reverseGeocoder.GetStreetByHouse(houseFeature, streetId))
{
result = streetId.m_index;
return result;
}
// Get nearby streets and calculate the resulting index.
auto const & streets = GetNearbyStreets(houseFeature);
if (edited)
{
auto const ret = find_if(streets.begin(), streets.end(),
[&streetName](Street const & st) { return st.m_name == streetName; });
if (ret != streets.end())
{
result = ret->m_id.m_index;
return result;
}
}
// If there is no saved street for feature, assume that it's a nearest street if it's too close.
if (!streets.empty() && streets[0].m_distanceMeters < kMaxApproxStreetDistanceM)
result = streets[0].m_id.m_index;
return result;
}
} // namespace search
|