summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChris Loer <chris.loer@gmail.com>2017-07-10 15:41:17 -0700
committerChris Loer <chris.loer@mapbox.com>2017-07-12 13:32:44 -0700
commit8ef9fcdf3ee9d1266771878205568944aedc7aa6 (patch)
treec1e9400ce895fcc9b967d324973d713d034c36ab /src
parente99e1678488246bf850864fdaba1fc1de2fe4480 (diff)
downloadqtlocation-mapboxgl-8ef9fcdf3ee9d1266771878205568944aedc7aa6.tar.gz
[core] Base label "keep-upright" orientation on start and end of label
Fixes issue #9457.
Diffstat (limited to 'src')
-rw-r--r--src/mbgl/layout/symbol_projection.cpp94
1 files changed, 76 insertions, 18 deletions
diff --git a/src/mbgl/layout/symbol_projection.cpp b/src/mbgl/layout/symbol_projection.cpp
index 99555f7997..8ccd6a0410 100644
--- a/src/mbgl/layout/symbol_projection.cpp
+++ b/src/mbgl/layout/symbol_projection.cpp
@@ -144,6 +144,12 @@ namespace mbgl {
Point<float> point;
float angle;
};
+
+ enum PlacementResult {
+ OK,
+ NotEnoughRoom,
+ NeedsFlipping
+ };
optional<PlacedGlyph> placeGlyphAlongLine(const float offsetX, const float lineOffsetX, const float lineOffsetY, const bool flip,
Point<float> anchorPoint, const uint16_t anchorSegment, const GeometryCoordinates& line, const mat4& labelPlaneMatrix) {
@@ -198,8 +204,14 @@ namespace mbgl {
return {{ p, segmentAngle }};
}
- void placeGlyphsAlongLine(const PlacedSymbol& symbol, const float fontSize, const bool flip, const mat4& labelPlaneMatrix,
- gl::VertexVector<SymbolDynamicLayoutAttributes::Vertex>& dynamicVertexArray) {
+ PlacementResult placeGlyphsAlongLine(const PlacedSymbol& symbol,
+ const float fontSize,
+ const bool flip,
+ const bool keepUpright,
+ const mat4& posMatrix,
+ const mat4& labelPlaneMatrix,
+ const mat4& glCoordMatrix,
+ gl::VertexVector<SymbolDynamicLayoutAttributes::Vertex>& dynamicVertexArray) {
const float fontScale = fontSize / 24.0;
const float lineOffsetX = symbol.lineOffset[0] * fontSize;
const float lineOffsetY = symbol.lineOffset[1] * fontSize;
@@ -207,19 +219,60 @@ namespace mbgl {
const Point<float> anchorPoint = project(symbol.anchorPoint, labelPlaneMatrix);
std::vector<PlacedGlyph> placedGlyphs;
- for (auto glyphOffsetX : symbol.glyphOffsets) {
- auto placedGlyph = placeGlyphAlongLine(glyphOffsetX * fontScale, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix);
- if (placedGlyph) {
+ if (symbol.glyphOffsets.size() > 1) {
+
+ const float firstGlyphOffset = symbol.glyphOffsets.front();
+ const float lastGlyphOffset = symbol.glyphOffsets.back();
+
+ optional<PlacedGlyph> firstPlacedGlyph = placeGlyphAlongLine(fontScale * firstGlyphOffset, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix);
+ if (!firstPlacedGlyph)
+ return PlacementResult::NotEnoughRoom;
+
+ optional<PlacedGlyph> lastPlacedGlyph = placeGlyphAlongLine(fontScale * lastGlyphOffset, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix);
+ if (!lastPlacedGlyph)
+ return PlacementResult::NotEnoughRoom;
+
+ const Point<float> firstPoint = project(firstPlacedGlyph->point, glCoordMatrix);
+ const Point<float> lastPoint = project(lastPlacedGlyph->point, glCoordMatrix);
+
+ if (keepUpright && !flip &&
+ (symbol.useVerticalMode ? firstPoint.y < lastPoint.y : firstPoint.x > lastPoint.x)) {
+ return PlacementResult::NeedsFlipping;
+ }
+
+ placedGlyphs.push_back(*firstPlacedGlyph);
+ for (size_t glyphIndex = 1; glyphIndex < symbol.glyphOffsets.size() - 1; glyphIndex++) {
+ const float glyphOffsetX = symbol.glyphOffsets[glyphIndex];
+ // Since first and last glyph fit on the line, we're sure that the rest of the glyphs can be placed
+ auto placedGlyph = placeGlyphAlongLine(glyphOffsetX * fontScale, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix);
placedGlyphs.push_back(*placedGlyph);
- } else {
- hideGlyphs(symbol.glyphOffsets.size(), dynamicVertexArray);
- return;
}
+ placedGlyphs.push_back(*lastPlacedGlyph);
+ } else {
+ // Only a single glyph to place
+ // So, determine whether to flip based on projected angle of the line segment it's on
+ if (keepUpright && !flip) {
+ const Point<float> a = project(convertPoint<float>(symbol.line.at(symbol.segment)), posMatrix);
+ const Point<float> b = project(convertPoint<float>(symbol.line.at(symbol.segment + 1)), posMatrix);
+ if (symbol.useVerticalMode ? b.y > a.y : b.x < a.x) {
+ return PlacementResult::NeedsFlipping;
+ }
+ }
+ assert(symbol.glyphOffsets.size() == 1); // We are relying on SymbolInstance.hasText filtering out symbols without any glyphs at all
+ const float glyphOffsetX = symbol.glyphOffsets.front();
+ optional<PlacedGlyph> singleGlyph = placeGlyphAlongLine(fontScale * glyphOffsetX, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment,
+ symbol.line, labelPlaneMatrix);
+ if (!singleGlyph)
+ return PlacementResult::NotEnoughRoom;
+
+ placedGlyphs.push_back(*singleGlyph);
}
for (auto& placedGlyph : placedGlyphs) {
addDynamicAttributes(placedGlyph.point, placedGlyph.angle, symbol.placementZoom, dynamicVertexArray);
}
+
+ return PlacementResult::OK;
}
void reprojectLineLabels(gl::VertexVector<SymbolDynamicLayoutAttributes::Vertex>& dynamicVertexArray, const std::vector<PlacedSymbol>& placedSymbols,
@@ -229,9 +282,15 @@ namespace mbgl {
const ZoomEvaluatedSize partiallyEvaluatedSize = sizeBinder.evaluateForZoom(state.getZoom());
const std::array<double, 2> clippingBuffer = {{ 256.0 / state.getSize().width * 2.0 + 1.0, 256.0 / state.getSize().height * 2.0 + 1.0 }};
+
+ const bool pitchWithMap = values.pitchAlignment == style::AlignmentType::Map;
+ const bool rotateWithMap = values.rotationAlignment == style::AlignmentType::Map;
+ const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1, state.getZoom());
- const mat4 labelPlaneMatrix = getLabelPlaneMatrix(posMatrix, values.pitchAlignment == style::AlignmentType::Map,
- values.rotationAlignment == style::AlignmentType::Map, state, tile.id.pixelsToTileUnits(1, state.getZoom()));
+ const mat4 labelPlaneMatrix = getLabelPlaneMatrix(posMatrix, pitchWithMap,
+ rotateWithMap, state, pixelsToTileUnits);
+
+ const mat4 glCoordMatrix = getGlCoordMatrix(posMatrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits);
dynamicVertexArray.clear();
@@ -245,13 +304,6 @@ namespace mbgl {
continue;
}
- bool flip = false;
- if (values.keepUpright) {
- const Point<float> a = project(convertPoint<float>(placedSymbol.line.at(placedSymbol.segment)), posMatrix);
- const Point<float> b = project(convertPoint<float>(placedSymbol.line.at(placedSymbol.segment + 1)), posMatrix);
- flip = placedSymbol.useVerticalMode ? b.y > a.y : b.x < a.x;
- }
-
const float cameraToAnchorDistance = anchorPos[3];
const float perspectiveRatio = 1 + 0.5 * ((cameraToAnchorDistance / state.getCameraToCenterDistance()) - 1.0);
@@ -260,7 +312,13 @@ namespace mbgl {
fontSize * perspectiveRatio :
fontSize / perspectiveRatio;
- placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, flip, labelPlaneMatrix, dynamicVertexArray);
+ PlacementResult placeUnflipped = placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, false /*unflipped*/, values.keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray);
+
+ if (placeUnflipped == PlacementResult::NotEnoughRoom ||
+ (placeUnflipped == PlacementResult::NeedsFlipping &&
+ placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, true /*flipped*/, values.keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray) == PlacementResult::NotEnoughRoom)) {
+ hideGlyphs(placedSymbol.glyphOffsets.size(), dynamicVertexArray);
+ }
}
}
} // end namespace mbgl