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

Commit

Permalink
sort overlapping symbols in the y direction
Browse files Browse the repository at this point in the history
fixes #333
fixes #988

-js: 6514de77be2ff3df4267785f42f5e53c63233cac
  • Loading branch information
ansis committed May 29, 2015
1 parent 520eddb commit de3fd89
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 27 deletions.
44 changes: 26 additions & 18 deletions src/mbgl/renderer/painter_symbol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,35 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c
const auto &properties = layer_desc.getProperties<SymbolProperties>();
const auto &layout = bucket.layout;

config.stencilTest = false;
const bool drawAcrossEdges = !(layout.text.allow_overlap || layout.icon.allow_overlap ||
layout.text.ignore_placement || layout.icon.ignore_placement);

// Disable the stencil test so that labels aren't clipped to tile boundaries.
//
// Layers with features that may be drawn overlapping aren't clipped. These
// layers are sorted in the y direction, and to draw the correct ordering near
// tile edges the icons are included in both tiles and clipped when drawing.
config.stencilTest = drawAcrossEdges ? false : true;
config.depthTest = true;
config.depthMask = GL_FALSE;

if (bucket.hasCollisionBoxData() && (
(bucket.hasIconData() && properties.icon.opacity) ||
(bucket.hasTextData() && properties.text.opacity))) {
config.stencilTest = true;

useProgram(collisionBoxShader->program);
collisionBoxShader->u_matrix = matrix;
collisionBoxShader->u_scale = std::pow(2, state.getNormalizedZoom() - id.z);
collisionBoxShader->u_zoom = state.getNormalizedZoom() * 10;
collisionBoxShader->u_maxzoom = (id.z + 1) * 10;
lineWidth(3.0f);

config.depthRange = { strata, 1.0f };
bucket.drawCollisionBoxes(*collisionBoxShader);

}

if (bucket.hasIconData()) {
bool sdf = bucket.sdfIcons;

Expand Down Expand Up @@ -193,21 +218,4 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c
&SymbolBucket::drawGlyphs);
}

if (bucket.hasCollisionBoxData() && (
(bucket.hasIconData() && properties.icon.opacity) ||
(bucket.hasTextData() && properties.text.opacity))) {
config.stencilTest = true;

useProgram(collisionBoxShader->program);
collisionBoxShader->u_matrix = matrix;
collisionBoxShader->u_scale = std::pow(2, state.getNormalizedZoom() - id.z);
collisionBoxShader->u_zoom = state.getNormalizedZoom() * 10;
collisionBoxShader->u_maxzoom = (id.z + 1) * 10;
lineWidth(3.0f);

config.depthRange = { strata, 1.0f };
bucket.drawCollisionBoxes(*collisionBoxShader);

}

}
42 changes: 37 additions & 5 deletions src/mbgl/renderer/symbol_bucket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,22 @@ namespace mbgl {

SymbolInstance::SymbolInstance(Anchor &anchor, const std::vector<Coordinate> &line,
const Shaping &shapedText, const PositionedIcon &shapedIcon,
const StyleLayoutSymbol &layout, const bool inside,
const StyleLayoutSymbol &layout, const bool addToBuffers,
const float textBoxScale, const float textPadding, const float textAlongLine,
const float iconBoxScale, const float iconPadding, const float iconAlongLine,
const GlyphPositions &face) :
x(anchor.x),
y(anchor.y),
hasText(shapedText),
hasIcon(shapedIcon),

// Create the quads used for rendering the glyphs.
glyphQuads(inside && shapedText ?
glyphQuads(addToBuffers && shapedText ?
getGlyphQuads(anchor, shapedText, textBoxScale, line, layout, textAlongLine, face) :
SymbolQuads()),

// Create the quad used for rendering the icon.
iconQuads(inside && shapedIcon ?
iconQuads(addToBuffers && shapedIcon ?
getIconQuads(anchor, shapedIcon, line, layout, iconAlongLine) :
SymbolQuads()),

Expand Down Expand Up @@ -288,6 +290,8 @@ void SymbolBucket::addFeature(const std::vector<std::vector<Coordinate>> &lines,
const bool iconAlongLine =
layout.icon.rotation_alignment == RotationAlignmentType::Map &&
layout.placement == PlacementType::Line;
const bool mayOverlap = layout.text.allow_overlap || layout.icon.allow_overlap ||
layout.text.ignore_placement || layout.icon.ignore_placement;

auto& clippedLines = layout.placement == PlacementType::Line ?
util::clipLines(lines, 0, 0, 4096, 4096) :
Expand All @@ -309,7 +313,18 @@ void SymbolBucket::addFeature(const std::vector<std::vector<Coordinate>> &lines,

if (avoidEdges && !inside) continue;

symbolInstances.emplace_back(anchor, line, shapedText, shapedIcon, layout, inside,
// Normally symbol layers are drawn across tile boundaries. Only symbols
// with their anchors within the tile boundaries are added to the buffers
// to prevent symbols from being drawn twice.
//
// Symbols in layers with overlap are sorted in the y direction so that
// symbols lower on the canvas are drawn on top of symbols near the top.
// To preserve this order across tile boundaries these symbols can't
// be drawn across tile boundaries. Instead they need to be included in
// the buffers for both tiles and clipped to tile boundaries at draw time.
const bool addToBuffers = inside || mayOverlap;

symbolInstances.emplace_back(anchor, line, shapedText, shapedIcon, layout, addToBuffers,
textBoxScale, textPadding, textAlongLine,
iconBoxScale, iconPadding, iconAlongLine,
face);
Expand All @@ -335,6 +350,24 @@ void SymbolBucket::placeFeatures(bool swapImmediately) {
layout.icon.rotation_alignment == RotationAlignmentType::Map &&
layout.placement == PlacementType::Line;

const bool mayOverlap = layout.text.allow_overlap || layout.icon.allow_overlap ||
layout.text.ignore_placement || layout.icon.ignore_placement;

// Sort symbols by their y position on the canvas so that they lower symbols
// are drawn on top of higher symbols.
// Don't sort symbols that won't overlap because it isn't necessary and
// because it causes more labels to pop in and out when rotating.
if (mayOverlap) {
float sin = std::sin(collision.angle);
float cos = std::cos(collision.angle);

std::sort(symbolInstances.begin(), symbolInstances.end(), [sin, cos](SymbolInstance &a, SymbolInstance &b) {
const float aRotated = sin * a.x + cos * a.y;
const float bRotated = sin * b.x + cos * b.y;
return aRotated < bRotated;
});
}

for (SymbolInstance &symbolInstance : symbolInstances) {

const bool hasText = symbolInstance.hasText;
Expand All @@ -343,7 +376,6 @@ void SymbolBucket::placeFeatures(bool swapImmediately) {
const bool iconWithoutText = layout.text.optional || !hasText;
const bool textWithoutIcon = layout.icon.optional || !hasIcon;


// Calculate the scales at which the text and icon can be placed without collision.

float glyphScale = hasText && !layout.text.allow_overlap ?
Expand Down
10 changes: 6 additions & 4 deletions src/mbgl/renderer/symbol_bucket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@ class SymbolInstance {
const float textBoxScale, const float textPadding, const float textAlongLine,
const float iconBoxScale, const float iconPadding, const float iconAlongLine,
const GlyphPositions &face);
const bool hasText;
const bool hasIcon;
const SymbolQuads glyphQuads;
const SymbolQuads iconQuads;
float x;
float y;
bool hasText;
bool hasIcon;
SymbolQuads glyphQuads;
SymbolQuads iconQuads;
CollisionFeature textCollisionFeature;
CollisionFeature iconCollisionFeature;
};
Expand Down

0 comments on commit de3fd89

Please sign in to comment.