summaryrefslogtreecommitdiff
path: root/src/mbgl/layout/symbol_layout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/layout/symbol_layout.cpp')
-rw-r--r--src/mbgl/layout/symbol_layout.cpp148
1 files changed, 76 insertions, 72 deletions
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index d8d143632c..098a872c06 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -46,7 +46,38 @@ inline const SymbolLayerProperties& toSymbolLayerProperties(const Immutable<Laye
return static_cast<const SymbolLayerProperties&>(*layer);
}
+inline Immutable<style::SymbolLayoutProperties::PossiblyEvaluated> createLayout(const SymbolLayoutProperties::Unevaluated& unevaluated, float zoom) {
+ auto layout = makeMutable<style::SymbolLayoutProperties::PossiblyEvaluated>(unevaluated.evaluate(PropertyEvaluationParameters(zoom)));
+
+ if (layout->get<IconRotationAlignment>() == AlignmentType::Auto) {
+ if (layout->get<SymbolPlacement>() != SymbolPlacementType::Point) {
+ layout->get<IconRotationAlignment>() = AlignmentType::Map;
+ } else {
+ layout->get<IconRotationAlignment>() = AlignmentType::Viewport;
+ }
+ }
+
+ if (layout->get<TextRotationAlignment>() == AlignmentType::Auto) {
+ if (layout->get<SymbolPlacement>() != SymbolPlacementType::Point) {
+ layout->get<TextRotationAlignment>() = AlignmentType::Map;
+ } else {
+ layout->get<TextRotationAlignment>() = AlignmentType::Viewport;
+ }
+ }
+
+ // If unspecified `*-pitch-alignment` inherits `*-rotation-alignment`
+ if (layout->get<TextPitchAlignment>() == AlignmentType::Auto) {
+ layout->get<TextPitchAlignment>() = layout->get<TextRotationAlignment>();
+ }
+ if (layout->get<IconPitchAlignment>() == AlignmentType::Auto) {
+ layout->get<IconPitchAlignment>() = layout->get<IconRotationAlignment>();
+ }
+
+ return layout;
+}
+
} // namespace
+
SymbolLayout::SymbolLayout(const BucketParameters& parameters,
const std::vector<Immutable<style::LayerProperties>>& layers,
std::unique_ptr<GeometryTileLayer> sourceLayer_,
@@ -61,50 +92,23 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
tileSize(util::tileSize * overscaling),
tilePixelRatio(float(util::EXTENT) / tileSize),
textSize(toSymbolLayerProperties(layers.at(0)).layerImpl().layout.get<TextSize>()),
- iconSize(toSymbolLayerProperties(layers.at(0)).layerImpl().layout.get<IconSize>())
- {
-
+ iconSize(toSymbolLayerProperties(layers.at(0)).layerImpl().layout.get<IconSize>()),
+ layout(createLayout(toSymbolLayerProperties(layers.at(0)).layerImpl().layout, zoom)) {
const SymbolLayer::Impl& leader = toSymbolLayerProperties(layers.at(0)).layerImpl();
- layout = leader.layout.evaluate(PropertyEvaluationParameters(zoom));
-
- if (layout.get<IconRotationAlignment>() == AlignmentType::Auto) {
- if (layout.get<SymbolPlacement>() != SymbolPlacementType::Point) {
- layout.get<IconRotationAlignment>() = AlignmentType::Map;
- } else {
- layout.get<IconRotationAlignment>() = AlignmentType::Viewport;
- }
- }
-
- if (layout.get<TextRotationAlignment>() == AlignmentType::Auto) {
- if (layout.get<SymbolPlacement>() != SymbolPlacementType::Point) {
- layout.get<TextRotationAlignment>() = AlignmentType::Map;
- } else {
- layout.get<TextRotationAlignment>() = AlignmentType::Viewport;
- }
- }
-
- // If unspecified `*-pitch-alignment` inherits `*-rotation-alignment`
- if (layout.get<TextPitchAlignment>() == AlignmentType::Auto) {
- layout.get<TextPitchAlignment>() = layout.get<TextRotationAlignment>();
- }
- if (layout.get<IconPitchAlignment>() == AlignmentType::Auto) {
- layout.get<IconPitchAlignment>() = layout.get<IconRotationAlignment>();
- }
-
- const bool hasText = has<TextField>(layout) && has<TextFont>(layout);
- const bool hasIcon = has<IconImage>(layout);
+ const bool hasText = has<TextField>(*layout) && has<TextFont>(*layout);
+ const bool hasIcon = has<IconImage>(*layout);
if (!hasText && !hasIcon) {
return;
}
const bool hasSymbolSortKey = !leader.layout.get<SymbolSortKey>().isUndefined();
- const auto symbolZOrder = layout.get<SymbolZOrder>();
+ const auto symbolZOrder = layout->get<SymbolZOrder>();
const bool sortFeaturesByKey = symbolZOrder != SymbolZOrderType::ViewportY && hasSymbolSortKey;
const bool zOrderByViewportY = symbolZOrder == SymbolZOrderType::ViewportY || (symbolZOrder == SymbolZOrderType::Auto && !sortFeaturesByKey);
- sortFeaturesByY = zOrderByViewportY && (layout.get<TextAllowOverlap>() || layout.get<IconAllowOverlap>() ||
- layout.get<TextIgnorePlacement>() || layout.get<IconIgnorePlacement>());
+ sortFeaturesByY = zOrderByViewportY && (layout->get<TextAllowOverlap>() || layout->get<IconAllowOverlap>() ||
+ layout->get<TextIgnorePlacement>() || layout->get<IconIgnorePlacement>());
for (const auto& layer : layers) {
layerPaintProperties.emplace(layer->baseImpl->id, layer);
@@ -122,9 +126,9 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
ft.index = i;
if (hasText) {
- auto formatted = layout.evaluate<TextField>(zoom, ft);
- auto textTransform = layout.evaluate<TextTransform>(zoom, ft);
- FontStack baseFontStack = layout.evaluate<TextFont>(zoom, ft);
+ auto formatted = layout->evaluate<TextField>(zoom, ft);
+ auto textTransform = layout->evaluate<TextTransform>(zoom, ft);
+ FontStack baseFontStack = layout->evaluate<TextFont>(zoom, ft);
ft.formattedText = TaggedString();
for (const auto & section : formatted.sections) {
@@ -142,8 +146,8 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
}
- const bool canVerticalizeText = layout.get<TextRotationAlignment>() == AlignmentType::Map
- && layout.get<SymbolPlacement>() != SymbolPlacementType::Point
+ const bool canVerticalizeText = layout->get<TextRotationAlignment>() == AlignmentType::Map
+ && layout->get<SymbolPlacement>() != SymbolPlacementType::Point
&& util::i18n::allowsVerticalWritingMode(ft.formattedText->rawText());
// Loop through all characters of this text and collect unique codepoints.
@@ -161,13 +165,13 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
}
if (hasIcon) {
- ft.icon = layout.evaluate<IconImage>(zoom, ft);
+ ft.icon = layout->evaluate<IconImage>(zoom, ft);
imageDependencies.emplace(*ft.icon, ImageType::Icon);
}
if (ft.formattedText || ft.icon) {
if (sortFeaturesByKey) {
- ft.sortKey = layout.evaluate<SymbolSortKey>(zoom, ft);
+ ft.sortKey = layout->evaluate<SymbolSortKey>(zoom, ft);
const auto lowerBound = std::lower_bound(features.begin(), features.end(), ft);
features.insert(lowerBound, std::move(ft));
} else {
@@ -176,7 +180,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
}
}
- if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
+ if (layout->get<SymbolPlacement>() == SymbolPlacementType::Line) {
util::mergeLines(features);
}
}
@@ -270,8 +274,8 @@ Point<float> SymbolLayout::evaluateRadialOffset(SymbolAnchorType anchor, float r
void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions,
const ImageMap& imageMap, const ImagePositions& imagePositions) {
- const bool isPointPlacement = layout.get<SymbolPlacement>() == SymbolPlacementType::Point;
- const bool textAlongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map && !isPointPlacement;
+ const bool isPointPlacement = layout->get<SymbolPlacement>() == SymbolPlacementType::Point;
+ const bool textAlongLine = layout->get<TextRotationAlignment>() == AlignmentType::Map && !isPointPlacement;
for (auto it = features.begin(); it != features.end(); ++it) {
auto& feature = *it;
@@ -283,13 +287,13 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions
// if feature has text, shape the text
if (feature.formattedText) {
- const float lineHeight = layout.get<TextLineHeight>() * util::ONE_EM;
- const float spacing = util::i18n::allowsLetterSpacing(feature.formattedText->rawText()) ? layout.evaluate<TextLetterSpacing>(zoom, feature) * util::ONE_EM : 0.0f;
+ const float lineHeight = layout->get<TextLineHeight>() * util::ONE_EM;
+ const float spacing = util::i18n::allowsLetterSpacing(feature.formattedText->rawText()) ? layout->evaluate<TextLetterSpacing>(zoom, feature) * util::ONE_EM : 0.0f;
auto applyShaping = [&] (const TaggedString& formattedText, WritingModeType writingMode, SymbolAnchorType textAnchor, TextJustifyType textJustify) {
const Shaping result = getShaping(
/* string */ formattedText,
- /* maxWidth: ems */ isPointPlacement ? layout.evaluate<TextMaxWidth>(zoom, feature) * util::ONE_EM : 0.0f,
+ /* maxWidth: ems */ isPointPlacement ? layout->evaluate<TextMaxWidth>(zoom, feature) * util::ONE_EM : 0.0f,
/* ems */ lineHeight,
textAnchor,
textJustify,
@@ -301,9 +305,9 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions
return result;
};
- const std::vector<style::TextVariableAnchorType> variableTextAnchor = layout.evaluate<TextVariableAnchor>(zoom, feature);
- const float radialOffset = layout.evaluate<TextRadialOffset>(zoom, feature);
- const SymbolAnchorType textAnchor = layout.evaluate<TextAnchor>(zoom, feature);
+ const std::vector<style::TextVariableAnchorType> variableTextAnchor = layout->evaluate<TextVariableAnchor>(zoom, feature);
+ const float radialOffset = layout->evaluate<TextRadialOffset>(zoom, feature);
+ const SymbolAnchorType textAnchor = layout->evaluate<TextAnchor>(zoom, feature);
if (variableTextAnchor.empty()) {
// Layers with variable anchors use the `text-radial-offset` property and the [x, y] offset vector
// is calculated at placement time instead of layout time
@@ -312,11 +316,11 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions
// but doesn't actually specify what happens if you use both. We go with the radial offset.
textOffset = evaluateRadialOffset(textAnchor, radialOffset * util::ONE_EM);
} else {
- textOffset = { layout.evaluate<TextOffset>(zoom, feature)[0] * util::ONE_EM,
- layout.evaluate<TextOffset>(zoom, feature)[1] * util::ONE_EM};
+ textOffset = { layout->evaluate<TextOffset>(zoom, feature)[0] * util::ONE_EM,
+ layout->evaluate<TextOffset>(zoom, feature)[1] * util::ONE_EM};
}
}
- TextJustifyType textJustify = textAlongLine ? TextJustifyType::Center : layout.evaluate<TextJustify>(zoom, feature);
+ TextJustifyType textJustify = textAlongLine ? TextJustifyType::Center : layout->evaluate<TextJustify>(zoom, feature);
// If this layer uses text-variable-anchor, generate shapings for all justification possibilities.
if (!textAlongLine && !variableTextAnchor.empty()) {
std::vector<TextJustifyType> justifications;
@@ -365,15 +369,15 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions
if (image != imageMap.end()) {
shapedIcon = PositionedIcon::shapeIcon(
imagePositions.at(*feature.icon),
- layout.evaluate<IconOffset>(zoom, feature),
- layout.evaluate<IconAnchor>(zoom, feature),
- layout.evaluate<IconRotate>(zoom, feature) * util::DEG2RAD);
+ layout->evaluate<IconOffset>(zoom, feature),
+ layout->evaluate<IconAnchor>(zoom, feature),
+ layout->evaluate<IconRotate>(zoom, feature) * util::DEG2RAD);
if (image->second->sdf) {
sdfIcons = true;
}
if (image->second->pixelRatio != pixelRatio) {
iconsNeedLinear = true;
- } else if (layout.get<IconRotate>().constantOr(1) != 0) {
+ } else if (layout->get<IconRotate>().constantOr(1) != 0) {
iconsNeedLinear = true;
}
}
@@ -399,34 +403,34 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
const float minScale = 0.5f;
const float glyphSize = 24.0f;
- const float layoutTextSize = layout.evaluate<TextSize>(zoom + 1, feature);
- const float layoutIconSize = layout.evaluate<IconSize>(zoom + 1, feature);
+ const float layoutTextSize = layout->evaluate<TextSize>(zoom + 1, feature);
+ const float layoutIconSize = layout->evaluate<IconSize>(zoom + 1, feature);
const std::array<float, 2> textOffset = {{ offset.x, offset.y }};
- const std::array<float, 2> iconOffset = layout.evaluate<IconOffset>(zoom, feature);
+ const std::array<float, 2> iconOffset = layout->evaluate<IconOffset>(zoom, feature);
// To reduce the number of labels that jump around when zooming we need
// to use a text-size value that is the same for all zoom levels.
// This calculates text-size at a high zoom level so that all tiles can
// use the same value when calculating anchor positions.
- const float textMaxSize = layout.evaluate<TextSize>(18, feature);
+ const float textMaxSize = layout->evaluate<TextSize>(18, feature);
const float fontScale = layoutTextSize / glyphSize;
const float textBoxScale = tilePixelRatio * fontScale;
const float textMaxBoxScale = tilePixelRatio * textMaxSize / glyphSize;
const float iconBoxScale = tilePixelRatio * layoutIconSize;
- const float symbolSpacing = tilePixelRatio * layout.get<SymbolSpacing>();
- const float textPadding = layout.get<TextPadding>() * tilePixelRatio;
- const float iconPadding = layout.get<IconPadding>() * tilePixelRatio;
- const float textMaxAngle = layout.get<TextMaxAngle>() * util::DEG2RAD;
- const float rotation = layout.evaluate<IconRotate>(zoom, feature);
- const float radialTextOffset = layout.evaluate<TextRadialOffset>(zoom, feature) * util::ONE_EM;
- const SymbolPlacementType textPlacement = layout.get<TextRotationAlignment>() != AlignmentType::Map
+ const float symbolSpacing = tilePixelRatio * layout->get<SymbolSpacing>();
+ const float textPadding = layout->get<TextPadding>() * tilePixelRatio;
+ const float iconPadding = layout->get<IconPadding>() * tilePixelRatio;
+ const float textMaxAngle = layout->get<TextMaxAngle>() * util::DEG2RAD;
+ const float rotation = layout->evaluate<IconRotate>(zoom, feature);
+ const float radialTextOffset = layout->evaluate<TextRadialOffset>(zoom, feature) * util::ONE_EM;
+ const SymbolPlacementType textPlacement = layout->get<TextRotationAlignment>() != AlignmentType::Map
? SymbolPlacementType::Point
- : layout.get<SymbolPlacement>();
+ : layout->get<SymbolPlacement>();
const float textRepeatDistance = symbolSpacing / 2;
- const auto evaluatedLayoutProperties = layout.evaluate(zoom, feature);
+ const auto evaluatedLayoutProperties = layout->evaluate(zoom, feature);
IndexedSubfeature indexedFeature(feature.index, sourceLayer->getName(), bucketLeaderID, symbolInstances.size());
auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) {
@@ -449,7 +453,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
const auto& type = feature.getType();
- if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
+ 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,
@@ -469,7 +473,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
}
}
}
- } else if (layout.get<SymbolPlacement>() == SymbolPlacementType::LineCenter) {
+ } else if (layout->get<SymbolPlacement>() == SymbolPlacementType::LineCenter) {
// No clipping, multiple lines per feature are allowed
// "lines" with only one point are ignored as in clipLines
for (const auto& line : feature.geometry) {