523 lines
26 KiB
C++
523 lines
26 KiB
C++
#include <mbgl/layout/symbol_projection.hpp>
|
|
#include <mbgl/map/transform_state.hpp>
|
|
#include <mbgl/renderer/render_tile.hpp>
|
|
#include <mbgl/renderer/buckets/symbol_bucket.hpp>
|
|
#include <mbgl/renderer/layers/render_symbol_layer.hpp>
|
|
#include <mbgl/util/math.hpp>
|
|
|
|
namespace mbgl {
|
|
|
|
/*
|
|
* # Overview of coordinate spaces
|
|
*
|
|
* ## Tile coordinate spaces
|
|
* Each label has an anchor. Some labels have corresponding line geometries.
|
|
* The points for both anchors and lines are stored in tile units. Each tile has
|
|
* it's own coordinate space going from (0, 0) at the top left to (EXTENT,
|
|
* EXTENT) at the bottom right.
|
|
*
|
|
* ## GL coordinate space
|
|
* At the end of everything, the vertex shader needs to produce a position in GL
|
|
* coordinate space, which is (-1, 1) at the top left and (1, -1) in the bottom
|
|
* right.
|
|
*
|
|
* ## Map pixel coordinate spaces
|
|
* Each tile has a pixel coordinate space. It's just the tile units scaled so
|
|
* that one unit is whatever counts as 1 pixel at the current zoom. This space
|
|
* is used for pitch-alignment=map, rotation-alignment=map
|
|
*
|
|
* ## Rotated map pixel coordinate spaces
|
|
* Like the above, but rotated so axis of the space are aligned with the
|
|
* viewport instead of the tile. This space is used for pitch-alignment=map,
|
|
* rotation-alignment=viewport
|
|
*
|
|
* ## Viewport pixel coordinate space
|
|
* (0, 0) is at the top left of the canvas and (pixelWidth, pixelHeight) is at
|
|
* the bottom right corner of the canvas. This space is used for
|
|
* pitch-alignment=viewport
|
|
*
|
|
*
|
|
* # Vertex projection
|
|
* It goes roughly like this:
|
|
* 1. project the anchor and line from tile units into the correct label
|
|
* coordinate space
|
|
* - map pixel space pitch-alignment=map rotation-alignment=map
|
|
* - rotated map pixel space pitch-alignment=map
|
|
* rotation-alignment=viewport
|
|
* - viewport pixel space pitch-alignment=viewport
|
|
* rotation-alignment=*
|
|
* 2. if the label follows a line, find the point along the line that is the
|
|
* correct distance from the anchor.
|
|
* 3. add the glyph's corner offset to the point from step 3
|
|
* 4. convert from the label coordinate space to gl coordinates
|
|
*
|
|
* For horizontal labels we want to do step 1 in the shader for performance
|
|
* reasons (no cpu work). This is what `u_label_plane_matrix` is used for. For
|
|
* labels aligned with lines we have to steps 1 and 2 on the cpu since we need
|
|
* access to the line geometry. This is what `updateLineLabels(...)` in JS,
|
|
* `reprojectLineLabels()` in gl-native, does. Since the conversion is handled
|
|
* on the cpu we just set `u_label_plane_matrix` to an identity matrix.
|
|
*
|
|
* Steps 3 and 4 are done in the shaders for all labels.
|
|
*/
|
|
|
|
/*
|
|
* Returns a matrix for converting from tile units to the correct label coordinate space.
|
|
*/
|
|
mat4 getLabelPlaneMatrix(const mat4& posMatrix,
|
|
const bool pitchWithMap,
|
|
const bool rotateWithMap,
|
|
const TransformState& state,
|
|
const float pixelsToTileUnits) {
|
|
mat4 m;
|
|
matrix::identity(m);
|
|
if (pitchWithMap) {
|
|
matrix::scale(m, m, 1 / pixelsToTileUnits, 1 / pixelsToTileUnits, 1);
|
|
if (!rotateWithMap) {
|
|
matrix::rotate_z(m, m, state.getBearing());
|
|
}
|
|
} else {
|
|
matrix::scale(m, m, state.getSize().width / 2.0, -(state.getSize().height / 2.0), 1.0);
|
|
matrix::translate(m, m, 1, -1, 0);
|
|
matrix::multiply(m, m, posMatrix);
|
|
}
|
|
return m;
|
|
}
|
|
|
|
/*
|
|
* Returns a matrix for converting from the correct label coordinate space to gl coords.
|
|
*/
|
|
mat4 getGlCoordMatrix(const mat4& posMatrix,
|
|
const bool pitchWithMap,
|
|
const bool rotateWithMap,
|
|
const TransformState& state,
|
|
const float pixelsToTileUnits) {
|
|
mat4 m;
|
|
matrix::identity(m);
|
|
if (pitchWithMap) {
|
|
matrix::multiply(m, m, posMatrix);
|
|
matrix::scale(m, m, pixelsToTileUnits, pixelsToTileUnits, 1);
|
|
if (!rotateWithMap) {
|
|
matrix::rotate_z(m, m, -state.getBearing());
|
|
}
|
|
} else {
|
|
matrix::scale(m, m, 1, -1, 1);
|
|
matrix::translate(m, m, -1, -1, 0);
|
|
matrix::scale(m, m, 2.0 / state.getSize().width, 2.0 / state.getSize().height, 1.0);
|
|
}
|
|
return m;
|
|
}
|
|
|
|
PointAndCameraDistance project(const Point<float>& point, const mat4& matrix) {
|
|
vec4 pos = {{point.x, point.y, 0, 1}};
|
|
matrix::transformMat4(pos, pos, matrix);
|
|
return {{static_cast<float>(pos[0] / pos[3]), static_cast<float>(pos[1] / pos[3])}, static_cast<float>(pos[3])};
|
|
}
|
|
|
|
float evaluateSizeForFeature(const ZoomEvaluatedSize& zoomEvaluatedSize, const PlacedSymbol& placedSymbol) {
|
|
if (zoomEvaluatedSize.isFeatureConstant) {
|
|
return zoomEvaluatedSize.size;
|
|
} else {
|
|
if (zoomEvaluatedSize.isZoomConstant) {
|
|
return placedSymbol.lowerSize;
|
|
} else {
|
|
return placedSymbol.lowerSize + zoomEvaluatedSize.sizeT * (placedSymbol.upperSize - placedSymbol.lowerSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool isVisible(const vec4& anchorPos, const std::array<double, 2>& clippingBuffer) {
|
|
const double x = anchorPos[0] / anchorPos[3];
|
|
const double y = anchorPos[1] / anchorPos[3];
|
|
const bool inPaddedViewport = (x >= -clippingBuffer[0] && x <= clippingBuffer[0] && y >= -clippingBuffer[1] &&
|
|
y <= clippingBuffer[1]);
|
|
return inPaddedViewport;
|
|
}
|
|
|
|
void addDynamicAttributes(const Point<float>& anchorPoint,
|
|
const float angle,
|
|
gfx::VertexVector<gfx::Vertex<SymbolDynamicLayoutAttributes>>& dynamicVertexArray) {
|
|
auto dynamicVertex = SymbolSDFIconProgram::dynamicLayoutVertex(anchorPoint, angle);
|
|
dynamicVertexArray.emplace_back(dynamicVertex);
|
|
dynamicVertexArray.emplace_back(dynamicVertex);
|
|
dynamicVertexArray.emplace_back(dynamicVertex);
|
|
dynamicVertexArray.emplace_back(dynamicVertex);
|
|
}
|
|
|
|
void hideGlyphs(size_t numGlyphs, gfx::VertexVector<gfx::Vertex<SymbolDynamicLayoutAttributes>>& dynamicVertexArray) {
|
|
const Point<float> offscreenPoint = {-INFINITY, -INFINITY};
|
|
for (size_t i = 0; i < numGlyphs; i++) {
|
|
addDynamicAttributes(offscreenPoint, 0, dynamicVertexArray);
|
|
}
|
|
}
|
|
|
|
enum PlacementResult {
|
|
OK,
|
|
NotEnoughRoom,
|
|
NeedsFlipping,
|
|
UseVertical
|
|
};
|
|
|
|
Point<float> projectTruncatedLineSegment(const Point<float>& previousTilePoint,
|
|
const Point<float>& currentTilePoint,
|
|
const Point<float>& previousProjectedPoint,
|
|
const float minimumLength,
|
|
const mat4& projectionMatrix) {
|
|
// We are assuming "previousTilePoint" won't project to a point within one
|
|
// unit of the camera plane If it did, that would mean our label extended
|
|
// all the way out from within the viewport to a (very distant) point near
|
|
// the plane of the camera. We wouldn't be able to render the label anyway
|
|
// once it crossed the plane of the camera.
|
|
const Point<float> projectedUnitVertex =
|
|
project(previousTilePoint + util::unit<float>(previousTilePoint - currentTilePoint), projectionMatrix).first;
|
|
const Point<float> projectedUnitSegment = previousProjectedPoint - projectedUnitVertex;
|
|
|
|
return previousProjectedPoint + (projectedUnitSegment * (minimumLength / util::mag<float>(projectedUnitSegment)));
|
|
}
|
|
|
|
std::optional<PlacedGlyph> placeGlyphAlongLine(const float offsetX,
|
|
const float lineOffsetX,
|
|
const float lineOffsetY,
|
|
const bool flip,
|
|
const Point<float>& projectedAnchorPoint,
|
|
const Point<float>& tileAnchorPoint,
|
|
const uint16_t anchorSegment,
|
|
const GeometryCoordinates& line,
|
|
const std::vector<float>& tileDistances,
|
|
const mat4& labelPlaneMatrix,
|
|
const bool returnTileDistance) {
|
|
const float combinedOffsetX = flip ? offsetX - lineOffsetX : offsetX + lineOffsetX;
|
|
|
|
int16_t dir = combinedOffsetX > 0 ? 1 : -1;
|
|
|
|
float angle = 0.0;
|
|
if (flip) {
|
|
// The label needs to be flipped to keep text upright.
|
|
// Iterate in the reverse direction.
|
|
dir *= -1;
|
|
angle = static_cast<float>(M_PI);
|
|
}
|
|
|
|
if (dir < 0) angle += static_cast<float>(M_PI);
|
|
|
|
int32_t currentIndex = dir > 0 ? anchorSegment : anchorSegment + 1;
|
|
|
|
const int32_t initialIndex = currentIndex;
|
|
Point<float> current = projectedAnchorPoint;
|
|
Point<float> prev = projectedAnchorPoint;
|
|
float distanceToPrev = 0.0;
|
|
float currentSegmentDistance = 0.0;
|
|
const float absOffsetX = std::abs(combinedOffsetX);
|
|
|
|
while (distanceToPrev + currentSegmentDistance <= absOffsetX) {
|
|
currentIndex += dir;
|
|
|
|
// offset does not fit on the projected line
|
|
if (currentIndex < 0 || currentIndex >= static_cast<int32_t>(line.size())) {
|
|
return {};
|
|
}
|
|
|
|
prev = current;
|
|
PointAndCameraDistance projection = project(convertPoint<float>(line.at(currentIndex)), labelPlaneMatrix);
|
|
if (projection.second > 0) {
|
|
current = projection.first;
|
|
} else {
|
|
// The vertex is behind the plane of the camera, so we can't project it
|
|
// Instead, we'll create a vertex along the line that's far enough to include the glyph
|
|
const Point<float> previousTilePoint = distanceToPrev == 0
|
|
? tileAnchorPoint
|
|
: convertPoint<float>(line.at(currentIndex - dir));
|
|
const Point<float> currentTilePoint = convertPoint<float>(line.at(currentIndex));
|
|
current = projectTruncatedLineSegment(
|
|
previousTilePoint, currentTilePoint, prev, absOffsetX - distanceToPrev + 1, labelPlaneMatrix);
|
|
}
|
|
|
|
distanceToPrev += currentSegmentDistance;
|
|
currentSegmentDistance = util::dist<float>(prev, current);
|
|
}
|
|
|
|
// The point is on the current segment. Interpolate to find it.
|
|
const float segmentInterpolationT = (absOffsetX - distanceToPrev) / currentSegmentDistance;
|
|
const Point<float> prevToCurrent = current - prev;
|
|
Point<float> p = (prevToCurrent * segmentInterpolationT) + prev;
|
|
|
|
// offset the point from the line to text-offset and icon-offset
|
|
p += util::perp(prevToCurrent) * static_cast<float>(lineOffsetY * dir / util::mag(prevToCurrent));
|
|
|
|
const float segmentAngle = angle + std::atan2(current.y - prev.y, current.x - prev.x);
|
|
|
|
return {{p,
|
|
segmentAngle,
|
|
returnTileDistance
|
|
? TileDistance((currentIndex - dir) == initialIndex ? 0 : tileDistances[currentIndex - dir],
|
|
absOffsetX - distanceToPrev)
|
|
: std::optional<TileDistance>()}};
|
|
}
|
|
|
|
std::optional<std::pair<PlacedGlyph, PlacedGlyph>> placeFirstAndLastGlyph(const float fontScale,
|
|
const float lineOffsetX,
|
|
const float lineOffsetY,
|
|
const bool flip,
|
|
const Point<float>& anchorPoint,
|
|
const Point<float>& tileAnchorPoint,
|
|
const PlacedSymbol& symbol,
|
|
const mat4& labelPlaneMatrix,
|
|
const bool returnTileDistance) {
|
|
if (symbol.glyphOffsets.empty()) {
|
|
assert(false);
|
|
return {};
|
|
}
|
|
|
|
const float firstGlyphOffset = symbol.glyphOffsets.front();
|
|
const float lastGlyphOffset = symbol.glyphOffsets.back();
|
|
;
|
|
|
|
std::optional<PlacedGlyph> firstPlacedGlyph = placeGlyphAlongLine(fontScale * firstGlyphOffset,
|
|
lineOffsetX,
|
|
lineOffsetY,
|
|
flip,
|
|
anchorPoint,
|
|
tileAnchorPoint,
|
|
static_cast<uint16_t>(symbol.segment),
|
|
symbol.line,
|
|
symbol.tileDistances,
|
|
labelPlaneMatrix,
|
|
returnTileDistance);
|
|
if (!firstPlacedGlyph) return {};
|
|
|
|
std::optional<PlacedGlyph> lastPlacedGlyph = placeGlyphAlongLine(fontScale * lastGlyphOffset,
|
|
lineOffsetX,
|
|
lineOffsetY,
|
|
flip,
|
|
anchorPoint,
|
|
tileAnchorPoint,
|
|
static_cast<uint16_t>(symbol.segment),
|
|
symbol.line,
|
|
symbol.tileDistances,
|
|
labelPlaneMatrix,
|
|
returnTileDistance);
|
|
if (!lastPlacedGlyph) return {};
|
|
|
|
return std::make_pair(*firstPlacedGlyph, *lastPlacedGlyph);
|
|
}
|
|
|
|
std::optional<PlacementResult> requiresOrientationChange(const WritingModeType writingModes,
|
|
const Point<float>& firstPoint,
|
|
const Point<float>& lastPoint,
|
|
const float aspectRatio) {
|
|
if (writingModes == (WritingModeType::Horizontal | WritingModeType::Vertical)) {
|
|
// On top of choosing whether to flip, choose whether to render this
|
|
// version of the glyphs or the alternate vertical glyphs. We can't just
|
|
// filter out vertical glyphs in the horizontal range because the
|
|
// horizontal and vertical versions can have slightly different
|
|
// projections which could lead to angles where both or neither showed.
|
|
auto rise = std::abs(lastPoint.y - firstPoint.y);
|
|
auto run = std::abs(lastPoint.x - firstPoint.x) * aspectRatio;
|
|
if (rise > run) {
|
|
return PlacementResult::UseVertical;
|
|
}
|
|
}
|
|
|
|
if ((writingModes == WritingModeType::Vertical) ? (firstPoint.y < lastPoint.y) : (firstPoint.x > lastPoint.x)) {
|
|
// Includes "horizontalOnly" case for labels without vertical glyphs
|
|
return PlacementResult::NeedsFlipping;
|
|
}
|
|
return {};
|
|
}
|
|
|
|
PlacementResult placeGlyphsAlongLine(const PlacedSymbol& symbol,
|
|
const float fontSize,
|
|
const bool flip,
|
|
const bool keepUpright,
|
|
const mat4& posMatrix,
|
|
const mat4& labelPlaneMatrix,
|
|
const mat4& glCoordMatrix,
|
|
gfx::VertexVector<gfx::Vertex<SymbolDynamicLayoutAttributes>>& dynamicVertexArray,
|
|
const Point<float>& projectedAnchorPoint,
|
|
const float aspectRatio) {
|
|
const float fontScale = fontSize / util::ONE_EM;
|
|
const float lineOffsetX = symbol.lineOffset[0] * fontScale;
|
|
const float lineOffsetY = symbol.lineOffset[1] * fontScale;
|
|
|
|
std::vector<PlacedGlyph> placedGlyphs;
|
|
if (symbol.glyphOffsets.size() > 1) {
|
|
const std::optional<std::pair<PlacedGlyph, PlacedGlyph>> firstAndLastGlyph = placeFirstAndLastGlyph(
|
|
fontScale,
|
|
lineOffsetX,
|
|
lineOffsetY,
|
|
flip,
|
|
projectedAnchorPoint,
|
|
symbol.anchorPoint,
|
|
symbol,
|
|
labelPlaneMatrix,
|
|
false);
|
|
if (!firstAndLastGlyph) {
|
|
return PlacementResult::NotEnoughRoom;
|
|
}
|
|
|
|
const Point<float> firstPoint = project(firstAndLastGlyph->first.point, glCoordMatrix).first;
|
|
const Point<float> lastPoint = project(firstAndLastGlyph->second.point, glCoordMatrix).first;
|
|
|
|
if (keepUpright && !flip) {
|
|
auto orientationChange = requiresOrientationChange(symbol.writingModes, firstPoint, lastPoint, aspectRatio);
|
|
if (orientationChange) {
|
|
return *orientationChange;
|
|
}
|
|
}
|
|
|
|
placedGlyphs.push_back(firstAndLastGlyph->first);
|
|
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,
|
|
projectedAnchorPoint,
|
|
symbol.anchorPoint,
|
|
static_cast<uint16_t>(symbol.segment),
|
|
symbol.line,
|
|
symbol.tileDistances,
|
|
labelPlaneMatrix,
|
|
false);
|
|
if (placedGlyph) {
|
|
placedGlyphs.push_back(*placedGlyph);
|
|
} else {
|
|
placedGlyphs.emplace_back(Point<float>{-INFINITY, -INFINITY}, 0.0f, std::nullopt);
|
|
}
|
|
}
|
|
placedGlyphs.push_back(firstAndLastGlyph->second);
|
|
} else if (symbol.glyphOffsets.size() == 1) {
|
|
// 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(symbol.anchorPoint, posMatrix).first;
|
|
const Point<float> tileSegmentEnd = convertPoint<float>(symbol.line.at(symbol.segment + 1));
|
|
const PointAndCameraDistance projectedVertex = project(tileSegmentEnd, posMatrix);
|
|
// We know the anchor will be in the viewport, but the end of the
|
|
// line segment may be behind the plane of the camera, in which case
|
|
// we can use a point at any arbitrary (closer) point on the
|
|
// segment.
|
|
const Point<float> b = (projectedVertex.second > 0)
|
|
? projectedVertex.first
|
|
: projectTruncatedLineSegment(
|
|
symbol.anchorPoint, tileSegmentEnd, a, 1, posMatrix);
|
|
|
|
auto orientationChange = requiresOrientationChange(symbol.writingModes, a, b, aspectRatio);
|
|
if (orientationChange) {
|
|
return *orientationChange;
|
|
}
|
|
}
|
|
const float glyphOffsetX = symbol.glyphOffsets.front();
|
|
std::optional<PlacedGlyph> singleGlyph = placeGlyphAlongLine(fontScale * glyphOffsetX,
|
|
lineOffsetX,
|
|
lineOffsetY,
|
|
flip,
|
|
projectedAnchorPoint,
|
|
symbol.anchorPoint,
|
|
static_cast<uint16_t>(symbol.segment),
|
|
symbol.line,
|
|
symbol.tileDistances,
|
|
labelPlaneMatrix,
|
|
false);
|
|
if (!singleGlyph) return PlacementResult::NotEnoughRoom;
|
|
|
|
placedGlyphs.push_back(*singleGlyph);
|
|
}
|
|
|
|
// The number of placedGlyphs must equal the number of glyphOffsets, which
|
|
// must correspond to the number of glyph vertices There may be 0 glyphs
|
|
// here, if a label consists entirely of glyphs that have 0x0 dimensions
|
|
for (auto& placedGlyph : placedGlyphs) {
|
|
addDynamicAttributes(placedGlyph.point, placedGlyph.angle, dynamicVertexArray);
|
|
}
|
|
|
|
return PlacementResult::OK;
|
|
}
|
|
|
|
void reprojectLineLabels(gfx::VertexVector<gfx::Vertex<SymbolDynamicLayoutAttributes>>& dynamicVertexArray,
|
|
const std::vector<PlacedSymbol>& placedSymbols,
|
|
const mat4& posMatrix,
|
|
bool pitchWithMap,
|
|
bool rotateWithMap,
|
|
bool keepUpright,
|
|
const RenderTile& tile,
|
|
const SymbolSizeBinder& sizeBinder,
|
|
const TransformState& state) {
|
|
const ZoomEvaluatedSize partiallyEvaluatedSize = sizeBinder.evaluateForZoom(static_cast<float>(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 float pixelsToTileUnits = tile.id.pixelsToTileUnits(1.0f, static_cast<float>(state.getZoom()));
|
|
|
|
const mat4 labelPlaneMatrix = getLabelPlaneMatrix(posMatrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits);
|
|
|
|
const mat4 glCoordMatrix = getGlCoordMatrix(posMatrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits);
|
|
|
|
dynamicVertexArray.clear();
|
|
|
|
bool useVertical = false;
|
|
|
|
for (auto& placedSymbol : placedSymbols) {
|
|
// Don't do calculations for vertical glyphs unless the previous symbol
|
|
// was horizontal and we determined that vertical glyphs were necessary.
|
|
// Also don't do calculations for symbols that are collided and fully
|
|
// faded out
|
|
if (placedSymbol.hidden || (placedSymbol.writingModes == WritingModeType::Vertical && !useVertical)) {
|
|
hideGlyphs(placedSymbol.glyphOffsets.size(), dynamicVertexArray);
|
|
continue;
|
|
}
|
|
// Awkward... but we're counting on the paired "vertical" symbol coming
|
|
// immediately after its horizontal counterpart
|
|
useVertical = false;
|
|
|
|
vec4 anchorPos = {{placedSymbol.anchorPoint.x, placedSymbol.anchorPoint.y, 0, 1}};
|
|
matrix::transformMat4(anchorPos, anchorPos, posMatrix);
|
|
|
|
// Don't bother calculating the correct point for invisible labels.
|
|
if (!isVisible(anchorPos, clippingBuffer)) {
|
|
hideGlyphs(placedSymbol.glyphOffsets.size(), dynamicVertexArray);
|
|
continue;
|
|
}
|
|
|
|
const auto cameraToAnchorDistance = static_cast<float>(anchorPos[3]);
|
|
const float perspectiveRatio = 0.5f + 0.5f * (cameraToAnchorDistance / state.getCameraToCenterDistance());
|
|
|
|
const float fontSize = evaluateSizeForFeature(partiallyEvaluatedSize, placedSymbol);
|
|
const float pitchScaledFontSize = pitchWithMap ? fontSize * perspectiveRatio : fontSize / perspectiveRatio;
|
|
|
|
const Point<float> anchorPoint = project(placedSymbol.anchorPoint, labelPlaneMatrix).first;
|
|
|
|
PlacementResult placeUnflipped = placeGlyphsAlongLine(placedSymbol,
|
|
pitchScaledFontSize,
|
|
false /*unflipped*/,
|
|
keepUpright,
|
|
posMatrix,
|
|
labelPlaneMatrix,
|
|
glCoordMatrix,
|
|
dynamicVertexArray,
|
|
anchorPoint,
|
|
state.getSize().aspectRatio());
|
|
|
|
useVertical = placeUnflipped == PlacementResult::UseVertical;
|
|
|
|
if (placeUnflipped == PlacementResult::NotEnoughRoom || useVertical ||
|
|
(placeUnflipped == PlacementResult::NeedsFlipping &&
|
|
placeGlyphsAlongLine(placedSymbol,
|
|
pitchScaledFontSize,
|
|
true /*flipped*/,
|
|
keepUpright,
|
|
posMatrix,
|
|
labelPlaneMatrix,
|
|
glCoordMatrix,
|
|
dynamicVertexArray,
|
|
anchorPoint,
|
|
state.getSize().aspectRatio()) == PlacementResult::NotEnoughRoom)) {
|
|
hideGlyphs(placedSymbol.glyphOffsets.size(), dynamicVertexArray);
|
|
}
|
|
}
|
|
}
|
|
} // end namespace mbgl
|