summaryrefslogtreecommitdiff
path: root/src/mbgl/util/merge_lines.cpp
blob: 7eb8306707c4009d802836e089e9d1e621ce8415 (plain)
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
#include "merge_lines.hpp"
#include <sstream>

namespace mbgl {
namespace util {

unsigned int mergeFromRight(std::vector<SymbolFeature> &features,
                            std::map<std::string, unsigned int> &rightIndex,
                            std::map<std::string, unsigned int>::iterator left,
                            std::string &rightKey,
                            std::vector<std::vector<Coordinate>> &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,
                           std::map<std::string, unsigned int> &leftIndex,
                           std::string &leftKey,
                           std::map<std::string, unsigned int>::iterator right,
                           std::vector<std::vector<Coordinate>> &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;
}

std::string
getKey(const std::u32string &text, const std::vector<std::vector<Coordinate>> &geom, bool onRight) {
    const Coordinate &coord = onRight ? geom[0].back() : geom[0].front();
    std::ostringstream key;
    for (const char32_t &c : text) {
        key << (char)c;
    }
    key << ":" << coord.x << ":" << coord.y;
    return key.str();
}

void mergeLines(std::vector<SymbolFeature> &features) {

    std::map<std::string, unsigned int> leftIndex;
    std::map<std::string, unsigned int> rightIndex;

    for (unsigned int k = 0; k < features.size(); k++) {
        SymbolFeature &feature = features[k];
        std::vector<std::vector<Coordinate>> &geometry = feature.geometry;

        if (!feature.label.length()) {
            continue;
        }

        std::string leftKey = getKey(feature.label, geometry, false);
        std::string rightKey = getKey(feature.label, geometry, true);

        auto left = rightIndex.find(leftKey);
        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.label, features[i].geometry, true)] = 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