Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[core] Fix symbol rendering for multipoints
Browse files Browse the repository at this point in the history
  • Loading branch information
jfirebaugh committed Dec 20, 2016
1 parent 3dcff6c commit dad57df
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 88 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"lodash": "^4.16.4",
"mapbox-gl": "mapbox/mapbox-gl-js#ab836206d415ca3a74257a3066d11a54ab2838cb",
"mapbox-gl-style-spec": "mapbox/mapbox-gl-style-spec#49e8b407bdbbe6f7c92dbcb56d3d51f425fc2653",
"mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#bbe948a30c3879b77a220eaa1336f61d46db5953",
"mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#e1ada02a706fd124fc3441fd3a2b3cda67960ff5",
"mkdirp": "^0.5.1",
"node-cmake": "^1.2.1",
"pixelmatch": "^4.0.2",
Expand Down
1 change: 1 addition & 0 deletions src/mbgl/layout/symbol_feature.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace mbgl {

class SymbolFeature {
public:
FeatureType type;
GeometryCollection geometry;
optional<std::u16string> text;
optional<std::string> icon;
Expand Down
132 changes: 72 additions & 60 deletions src/mbgl/layout/symbol_layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,8 @@ SymbolLayout::SymbolLayout(std::string bucketName_,
}

if (ft.text || ft.icon) {
auto &multiline = ft.geometry;

GeometryCollection geometryCollection = feature->getGeometries();
for (auto& line : geometryCollection) {
multiline.emplace_back();
for (auto& point : line) {
multiline.back().emplace_back(point.x, point.y);
}
}

ft.type = feature->getType();
ft.geometry = feature->getGeometries();
features.push_back(std::move(ft));
}
}
Expand Down Expand Up @@ -229,17 +221,17 @@ void SymbolLayout::prepare(uintptr_t tileUID,

// if either shapedText or icon position is present, add the feature
if (shapedText || shapedIcon) {
addFeature(feature.geometry, shapedText, shapedIcon, face, feature.index);
addFeature(feature, shapedText, shapedIcon, face);
}
}

features.clear();
}


void SymbolLayout::addFeature(const GeometryCollection &lines,
const Shaping &shapedText, const PositionedIcon &shapedIcon, const GlyphPositions &face, const size_t index) {

void SymbolLayout::addFeature(const SymbolFeature& feature,
const Shaping& shapedText,
const PositionedIcon& shapedIcon,
const GlyphPositions& face) {
const float minScale = 0.5f;
const float glyphSize = 24.0f;

Expand All @@ -258,55 +250,75 @@ void SymbolLayout::addFeature(const GeometryCollection &lines,
const SymbolPlacementType iconPlacement = layout.get<IconRotationAlignment>() != AlignmentType::Map
? SymbolPlacementType::Point
: layout.get<SymbolPlacement>();
const bool isLine = layout.get<SymbolPlacement>() == SymbolPlacementType::Line;
const float textRepeatDistance = symbolSpacing / 2;
IndexedSubfeature indexedFeature = {feature.index, sourceLayerName, bucketName, symbolInstances.size()};

auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) {
// https://github.com/mapbox/vector-tile-spec/tree/master/2.1#41-layers
// +-------------------+ Symbols with anchors located on tile edges
// |(0,0) || are duplicated on neighbor tiles.
// | ||
// | || In continuous mode, to avoid overdraw we
// | || skip symbols located on the extent edges.
// | Tile || In still mode, we include the features in
// | || the buffers for both tiles and clip them
// | || at draw time.
// | ||
// +-------------------| In this scenario, the inner bounding box
// +-------------------+ is called 'withinPlus0', and the outer
// (extent,extent) is called 'inside'.
const bool withinPlus0 = anchor.point.x >= 0 && anchor.point.x < util::EXTENT && anchor.point.y >= 0 && anchor.point.y < util::EXTENT;
const bool inside = withinPlus0 || anchor.point.x == util::EXTENT || anchor.point.y == util::EXTENT;

if (avoidEdges && !inside) return;

const bool addToBuffers = mode == MapMode::Still || withinPlus0;

symbolInstances.emplace_back(anchor, line, shapedText, shapedIcon, layout, addToBuffers, symbolInstances.size(),
textBoxScale, textPadding, textPlacement,
iconBoxScale, iconPadding, iconPlacement,
face, indexedFeature);
};

auto& clippedLines = isLine ?
util::clipLines(lines, 0, 0, util::EXTENT, util::EXTENT) :
lines;

IndexedSubfeature indexedFeature = {index, sourceLayerName, bucketName, symbolInstances.size()};

for (const auto& line : clippedLines) {
if (line.empty()) continue;

// Calculate the anchor points around which you want to place labels
Anchors anchors = isLine ?
getAnchors(line, symbolSpacing, textMaxAngle, shapedText.left, shapedText.right, shapedIcon.left, shapedIcon.right, glyphSize, textMaxBoxScale, overscaling) :
Anchors({ Anchor(float(line[0].x), float(line[0].y), 0, minScale) });

// For each potential label, create the placement features used to check for collisions, and the quads use for rendering.
for (Anchor &anchor : anchors) {
if (shapedText && isLine) {
if (anchorIsTooClose(shapedText.text, textRepeatDistance, anchor)) {
continue;
if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
auto clippedLines = util::clipLines(feature.geometry, 0, 0, util::EXTENT, util::EXTENT);
for (const auto& line : clippedLines) {
Anchors anchors = getAnchors(line,
symbolSpacing,
textMaxAngle,
shapedText.left,
shapedText.right,
shapedIcon.left,
shapedIcon.right,
glyphSize,
textMaxBoxScale,
overscaling);

for (auto& anchor : anchors) {
if (!shapedText || !anchorIsTooClose(shapedText.text, textRepeatDistance, anchor)) {
addSymbolInstance(line, anchor);
}
}

// https://github.com/mapbox/vector-tile-spec/tree/master/2.1#41-layers
// +-------------------+ Symbols with anchors located on tile edges
// |(0,0) || are duplicated on neighbor tiles.
// | ||
// | || In continuous mode, to avoid overdraw we
// | || skip symbols located on the extent edges.
// | Tile || In still mode, we include the features in
// | || the buffers for both tiles and clip them
// | || at draw time.
// | ||
// +-------------------| In this scenario, the inner bounding box
// +-------------------+ is called 'withinPlus0', and the outer
// (extent,extent) is called 'inside'.
const bool withinPlus0 = anchor.point.x >= 0 && anchor.point.x < util::EXTENT && anchor.point.y >= 0 && anchor.point.y < util::EXTENT;
const bool inside = withinPlus0 || anchor.point.x == util::EXTENT || anchor.point.y == util::EXTENT;

if (avoidEdges && !inside) continue;

const bool addToBuffers = mode == MapMode::Still || withinPlus0;

symbolInstances.emplace_back(anchor, line, shapedText, shapedIcon, layout, addToBuffers, symbolInstances.size(),
textBoxScale, textPadding, textPlacement,
iconBoxScale, iconPadding, iconPlacement,
face, indexedFeature);
}
} else if (feature.type == FeatureType::Polygon) {
// TODO: pole of inaccessibility
for (const auto& ring : feature.geometry) {
for (const auto& point : ring) {
Anchor anchor(point.x, point.y, 0, minScale);
addSymbolInstance(ring, anchor);
}
}
} else if (feature.type == FeatureType::LineString) {
for (const auto& line : feature.geometry) {
Anchor anchor(line[0].x, line[0].y, 0, minScale);
addSymbolInstance(line, anchor);
}
} else if (feature.type == FeatureType::Point) {
for (const auto& points : feature.geometry) {
for (const auto& point : points) {
Anchor anchor(point.x, point.y, 0, minScale);
addSymbolInstance({point}, anchor);
}
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions src/mbgl/layout/symbol_layout.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,10 @@ class SymbolLayout {
const std::string sourceLayerName;

private:
void addFeature(const GeometryCollection&,
void addFeature(const SymbolFeature&,
const Shaping& shapedText,
const PositionedIcon& shapedIcon,
const GlyphPositions& face,
const size_t index);
const GlyphPositions& face);

bool anchorIsTooClose(const std::u16string& text, const float repeatDistance, const Anchor&);
std::map<std::u16string, std::vector<Anchor>> compareText;
Expand Down
1 change: 1 addition & 0 deletions src/mbgl/text/get_anchors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Anchors getAnchors(const GeometryCoordinates &line, float spacing,
const float maxAngle, const float textLeft, const float textRight,
const float iconLeft, const float iconRight,
const float glyphSize, const float boxScale, const float overscaling) {
if (line.empty()) return {};

// Resample a line to get anchor points for labels and check that each
// potential label passes text-max-angle check and has enough froom to fit
Expand Down
50 changes: 26 additions & 24 deletions test/util/merge_lines.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,26 @@
const std::u16string aaa = u"a";
const std::u16string bbb = u"b";

using namespace mbgl;

TEST(MergeLines, SameText) {
// merges lines with the same text
std::vector<mbgl::SymbolFeature> input1 = {
{ {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 },
{ {{{4, 0}, {5, 0}, {6, 0}}}, bbb, {}, 0 },
{ {{{8, 0}, {9, 0}}}, aaa, {}, 0 },
{ {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 },
{ {{{6, 0}, {7, 0}, {8, 0}}}, aaa, {}, 0 },
{ {{{5, 0}, {6, 0}}}, aaa, {}, 0 }
{ FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 },
{ FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, bbb, {}, 0 },
{ FeatureType::LineString, {{{8, 0}, {9, 0}}}, aaa, {}, 0 },
{ FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 },
{ FeatureType::LineString, {{{6, 0}, {7, 0}, {8, 0}}}, aaa, {}, 0 },
{ FeatureType::LineString, {{{5, 0}, {6, 0}}}, aaa, {}, 0 }
};

const std::vector<mbgl::SymbolFeature> expected1 = {
{ {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 },
{ {{{4, 0}, {5, 0}, {6, 0}}}, bbb, {}, 0 },
{ {{{5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}}}, aaa, {}, 0 },
{ {{}}, aaa, {}, 0 },
{ {{}}, aaa, {}, 0 },
{ {{}}, aaa, {}, 0 }
{ FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 },
{ FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, bbb, {}, 0 },
{ FeatureType::LineString, {{{5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}}}, aaa, {}, 0 },
{ FeatureType::LineString, {{}}, aaa, {}, 0 },
{ FeatureType::LineString, {{}}, aaa, {}, 0 },
{ FeatureType::LineString, {{}}, aaa, {}, 0 }
};

mbgl::util::mergeLines(input1);
Expand All @@ -36,15 +38,15 @@ TEST(MergeLines, SameText) {
TEST(MergeLines, BothEnds) {
// mergeLines handles merge from both ends
std::vector<mbgl::SymbolFeature> input2 = {
{ {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 },
{ {{{4, 0}, {5, 0}, {6, 0}}}, aaa, {}, 0 },
{ {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 }
{ FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 },
{ FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, aaa, {}, 0 },
{ FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 }
};

const std::vector<mbgl::SymbolFeature> expected2 = {
{ {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}}}, aaa, {}, 0 },
{ {{}}, aaa, {}, 0 },
{ {{}}, aaa, {}, 0 }
{ FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}}}, aaa, {}, 0 },
{ FeatureType::LineString, {{}}, aaa, {}, 0 },
{ FeatureType::LineString, {{}}, aaa, {}, 0 }
};

mbgl::util::mergeLines(input2);
Expand All @@ -57,15 +59,15 @@ TEST(MergeLines, BothEnds) {
TEST(MergeLines, CircularLines) {
// mergeLines handles circular lines
std::vector<mbgl::SymbolFeature> input3 = {
{ {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 },
{ {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 },
{ {{{4, 0}, {0, 0}}}, aaa, {}, 0 }
{ FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 },
{ FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 },
{ FeatureType::LineString, {{{4, 0}, {0, 0}}}, aaa, {}, 0 }
};

const std::vector<mbgl::SymbolFeature> expected3 = {
{ {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 0}}}, aaa, {}, 0 },
{ {{}}, aaa, {}, 0 },
{ {{}}, aaa, {}, 0 }
{ FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 0}}}, aaa, {}, 0 },
{ FeatureType::LineString, {{}}, aaa, {}, 0 },
{ FeatureType::LineString, {{}}, aaa, {}, 0 }
};

mbgl::util::mergeLines(input3);
Expand Down

0 comments on commit dad57df

Please sign in to comment.