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
|
#include <mbgl/layout/merge_lines.hpp>
#include <mbgl/layout/symbol_feature.hpp>
#include <boost/functional/hash.hpp>
namespace mbgl {
namespace util {
using Index = std::unordered_map<size_t, unsigned int>;
unsigned int mergeFromRight(std::vector<SymbolFeature> &features,
Index &rightIndex,
Index::iterator left,
size_t rightKey,
GeometryCollection &geom) {
unsigned int index = left->second;
rightIndex.erase(left);
rightIndex[rightKey] = index;
features[index].geometry[0].pop_back();
features[index].geometry[0].insert(
features[index].geometry[0].end(), geom[0].begin(), geom[0].end());
geom[0].clear();
return index;
}
unsigned int mergeFromLeft(std::vector<SymbolFeature> &features,
Index &leftIndex,
size_t leftKey,
Index::iterator right,
GeometryCollection &geom) {
unsigned int index = right->second;
leftIndex.erase(right);
leftIndex[leftKey] = index;
geom[0].pop_back();
geom[0].insert(
geom[0].end(), features[index].geometry[0].begin(), features[index].geometry[0].end());
features[index].geometry[0].clear();
std::swap(features[index].geometry[0], geom[0]);
return index;
}
enum class Side {
Left = false,
Right = true,
};
size_t
getKey(const std::u16string& text, const GeometryCollection& geom, Side side) {
const GeometryCoordinate& coord = side == Side::Right ? geom[0].back() : geom[0].front();
auto hash = std::hash<std::u16string>()(text);
boost::hash_combine(hash, coord.x);
boost::hash_combine(hash, coord.y);
return hash;
}
void mergeLines(std::vector<SymbolFeature> &features) {
Index leftIndex;
Index rightIndex;
for (unsigned int k = 0; k < features.size(); k++) {
SymbolFeature &feature = features[k];
GeometryCollection &geometry = feature.geometry;
if (!feature.text) {
continue;
}
const auto leftKey = getKey(*feature.text, geometry, Side::Left);
const auto rightKey = getKey(*feature.text, geometry, Side::Right);
const auto left = rightIndex.find(leftKey);
const auto right = leftIndex.find(rightKey);
if ((left != rightIndex.end()) && (right != leftIndex.end()) &&
(left->second != right->second)) {
// found lines with the same text adjacent to both ends of the current line, merge all
// three
unsigned int j = mergeFromLeft(features, leftIndex, leftKey, right, geometry);
unsigned int i =
mergeFromRight(features, rightIndex, left, rightKey, features[j].geometry);
leftIndex.erase(leftKey);
rightIndex.erase(rightKey);
rightIndex[getKey(*feature.text, features[i].geometry, Side::Right)] = i;
} else if (left != rightIndex.end()) {
// found mergeable line adjacent to the start of the current line, merge
mergeFromRight(features, rightIndex, left, rightKey, geometry);
} else if (right != leftIndex.end()) {
// found mergeable line adjacent to the end of the current line, merge
mergeFromLeft(features, leftIndex, leftKey, right, geometry);
} else {
// no adjacent lines, add as a new item
leftIndex[leftKey] = k;
rightIndex[rightKey] = k;
}
}
}
} // end namespace util
} // end namespace mbgl
|