merge adjacent roads with same text for labelling

js: https://github.com/mapbox/mapbox-gl-js/pull/683
This commit is contained in:
Ansis Brammanis
2015-01-08 23:23:35 -05:00
parent 166a3e21fa
commit e4858b6a02
3 changed files with 147 additions and 26 deletions

View File

@@ -16,6 +16,7 @@
#include <mbgl/util/utf.hpp>
#include <mbgl/util/token.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/merge_lines.hpp>
namespace mbgl {
@@ -145,7 +146,37 @@ void SymbolBucket::addFeatures(const VectorTileLayer &layer, const FilterExpress
const FontStack &fontStack = glyphStore.getFontStack(properties.text.font);
for (const SymbolFeature &feature : features) {
std::vector<std::vector<std::vector<Coordinate>>> geometries;
for (unsigned int k = 0; k < features.size(); k++) {
const SymbolFeature &feature = features[k];
geometries.emplace_back();
std::vector<std::vector<Coordinate>> &multiline = geometries.back();
// Decode all lines.
Geometry::command cmd;
bool first = true;
pbf geom(feature.geometry);
Geometry geometry(geom);
int32_t x, y;
while ((cmd = geometry.next(x, y)) != Geometry::end) {
if (first || cmd == Geometry::move_to) {
multiline.emplace_back();
first = false;
}
multiline.back().emplace_back(x, y);
}
}
if (properties.placement == PlacementType::Line) {
util::mergeLines(features, geometries);
}
for (unsigned int k = 0; k < geometries.size(); k++) {
if (!geometries[k].size()) continue;
const SymbolFeature &feature = features[k];
Shaping shaping;
Rect<uint16_t> image;
GlyphPositions face;
@@ -181,32 +212,13 @@ void SymbolBucket::addFeatures(const VectorTileLayer &layer, const FilterExpress
// if either shaping or icon position is present, add the feature
if (shaping.size() || image) {
addFeature(feature.geometry, shaping, face, image);
}
}
}
void SymbolBucket::addFeature(const pbf &geom_pbf, const Shaping &shaping,
const GlyphPositions &face, const Rect<uint16_t> &image) {
// Decode all lines.
std::vector<Coordinate> line;
Geometry::command cmd;
Coordinate coord;
pbf geom(geom_pbf);
Geometry geometry(geom);
int32_t x, y;
while ((cmd = geometry.next(x, y)) != Geometry::end) {
if (cmd == Geometry::move_to) {
if (!line.empty()) {
addFeature(line, shaping, face, image);
line.clear();
std::vector<std::vector<Coordinate>> &multiline = geometries[k];
for (const std::vector<Coordinate> &line : multiline) {
if (line.size()) {
addFeature(line, shaping, face, image);
}
}
}
line.emplace_back(x, y);
}
if (line.size()) {
addFeature(line, shaping, face, image);
}
}

View File

@@ -77,7 +77,6 @@ private:
std::vector<SymbolFeature> processFeatures(const VectorTileLayer &layer, const FilterExpression &filter, GlyphStore &glyphStore, const Sprite &sprite);
void addFeature(const pbf &geom_pbf, const Shaping &shaping, const GlyphPositions &face, const Rect<uint16_t> &image);
void addFeature(const std::vector<Coordinate> &line, const Shaping &shaping, const GlyphPositions &face, const Rect<uint16_t> &image);

View File

@@ -0,0 +1,110 @@
#ifndef MBGL_UTIL_MERGELINES
#define MBGL_UTIL_MERGELINES
#include <map>
#include <string>
#include <vector>
#include <sstream>
#include <mbgl/renderer/symbol_bucket.hpp>
#include <iostream>
namespace mbgl {
namespace util {
unsigned int mergeFromRight(
std::vector<std::vector<std::vector<Coordinate>>> &geometries,
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;
geometries[index][0].pop_back();
geometries[index][0].insert(geometries[index][0].end(), geom[0].begin(), geom[0].end());
geom[0].clear();
return index;
}
unsigned int mergeFromLeft(
std::vector<std::vector<std::vector<Coordinate>>> &geometries,
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(), geometries[index][0].begin(), geometries[index][0].end());
geometries[index][0].clear();
std::swap(geometries[index][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(const std::vector<SymbolFeature> &features, std::vector<std::vector<std::vector<Coordinate>>> &geometries) {
std::map<std::string,unsigned int> leftIndex;
std::map<std::string,unsigned int> rightIndex;
if (features.size()) getKey(features[0].label, geometries[0], false);
for (unsigned int k = 0; k < features.size(); k++) {
const SymbolFeature &feature = features[k];
std::vector<std::vector<Coordinate>> &geometry = geometries[k];
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(geometries, leftIndex, leftKey, right, geometry);
unsigned int i = mergeFromRight(geometries, rightIndex, left, rightKey, geometries[j]);
leftIndex.erase(leftIndex.find(leftKey));
rightIndex.erase(rightIndex.find(rightKey));
rightIndex[getKey(feature.label, geometries[i], true)] = i;
} else if (left != rightIndex.end()) {
// found mergeable line adjacent to the start of the current line, merge
mergeFromRight(geometries, rightIndex, left, rightKey, geometry);
} else if (right != leftIndex.end()) {
// found mergeable line adjacent to the end of the current line, merge
mergeFromLeft(geometries, 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
#endif