[core] Base label "keep-upright" orientation on start and end of label

Fixes issue #9457.
This commit is contained in:
Chris Loer
2017-07-10 15:41:17 -07:00
committed by Chris Loer
parent e99e167848
commit 8ef9fcdf3e

View File

@@ -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) {
placedGlyphs.push_back(*placedGlyph);
} else {
hideGlyphs(symbol.glyphOffsets.size(), dynamicVertexArray);
return;
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);
}
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