diff options
Diffstat (limited to 'src/mbgl/layout/symbol_layout.cpp')
-rw-r--r-- | src/mbgl/layout/symbol_layout.cpp | 445 |
1 files changed, 282 insertions, 163 deletions
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index d8d143632c..59c2999163 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -1,19 +1,20 @@ -#include <mbgl/layout/symbol_layout.hpp> -#include <mbgl/layout/merge_lines.hpp> #include <mbgl/layout/clip_lines.hpp> +#include <mbgl/layout/merge_lines.hpp> +#include <mbgl/layout/symbol_layout.hpp> #include <mbgl/renderer/bucket_parameters.hpp> -#include <mbgl/renderer/layers/render_symbol_layer.hpp> #include <mbgl/renderer/image_atlas.hpp> +#include <mbgl/renderer/layers/render_symbol_layer.hpp> #include <mbgl/text/get_anchors.hpp> #include <mbgl/text/shaping.hpp> -#include <mbgl/util/utf.hpp> +#include <mbgl/tile/geometry_tile_data.hpp> +#include <mbgl/tile/tile.hpp> #include <mbgl/util/constants.hpp> -#include <mbgl/util/string.hpp> #include <mbgl/util/i18n.hpp> #include <mbgl/util/platform.hpp> -#include <mbgl/tile/geometry_tile_data.hpp> -#include <mbgl/tile/tile.hpp> +#include <mbgl/util/string.hpp> +#include <mbgl/util/utf.hpp> +#include <iostream> #include <mapbox/polylabel.hpp> namespace mbgl { @@ -22,10 +23,8 @@ using namespace style; template <class Property> static bool has(const style::SymbolLayoutProperties::PossiblyEvaluated& layout) { - return layout.get<Property>().match( - [] (const typename Property::Type& t) { return !t.empty(); }, - [] (const auto&) { return true; } - ); + return layout.get<Property>().match([](const typename Property::Type& t) { return !t.empty(); }, + [](const auto&) { return true; }); } namespace { @@ -42,7 +41,8 @@ expression::Value sectionOptionsToValue(const SectionOptions& options) { return result; } -inline const SymbolLayerProperties& toSymbolLayerProperties(const Immutable<LayerProperties>& layer) { +inline const SymbolLayerProperties& +toSymbolLayerProperties(const Immutable<LayerProperties>& layer) { return static_cast<const SymbolLayerProperties&>(*layer); } @@ -61,8 +61,7 @@ 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>()) { const SymbolLayer::Impl& leader = toSymbolLayerProperties(layers.at(0)).layerImpl(); @@ -102,9 +101,11 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, const bool hasSymbolSortKey = !leader.layout.get<SymbolSortKey>().isUndefined(); 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>()); + const bool zOrderByViewportY = symbolZOrder == SymbolZOrderType::ViewportY || + (symbolZOrder == SymbolZOrderType::Auto && !sortFeaturesByKey); + 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); @@ -114,7 +115,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, const size_t featureCount = sourceLayer->featureCount(); for (size_t i = 0; i < featureCount; ++i) { auto feature = sourceLayer->getFeature(i); - if (!leader.filter(expression::EvaluationContext { this->zoom, feature.get() })) + if (!leader.filter(expression::EvaluationContext{ this->zoom, feature.get() })) continue; SymbolFeature ft(std::move(feature)); @@ -127,7 +128,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, FontStack baseFontStack = layout.evaluate<TextFont>(zoom, ft); ft.formattedText = TaggedString(); - for (const auto & section : formatted.sections) { + for (const auto& section : formatted.sections) { std::string u8string = section.text; if (textTransform == TextTransformType::Uppercase) { u8string = platform::uppercase(u8string); @@ -141,15 +142,17 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, section.textColor); } - - const bool canVerticalizeText = layout.get<TextRotationAlignment>() == AlignmentType::Map - && layout.get<SymbolPlacement>() != SymbolPlacementType::Point - && util::i18n::allowsVerticalWritingMode(ft.formattedText->rawText()); + 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. for (std::size_t j = 0; j < ft.formattedText->length(); j++) { - const auto& sectionFontStack = formatted.sections[ft.formattedText->getSectionIndex(j)].fontStack; - GlyphIDs& dependencies = glyphDependencies[sectionFontStack ? *sectionFontStack : baseFontStack]; + const auto& sectionFontStack = + formatted.sections[ft.formattedText->getSectionIndex(j)].fontStack; + GlyphIDs& dependencies = + glyphDependencies[sectionFontStack ? *sectionFontStack : baseFontStack]; char16_t codePoint = ft.formattedText->getCharCodeAt(j); dependencies.insert(codePoint); if (canVerticalizeText) { @@ -201,24 +204,31 @@ const float baselineOffset = 7.0f; // We don't care which shaping we get because this is used for collision purposes // and all the justifications have the same collision box. const Shaping& getDefaultHorizontalShaping(const ShapedTextOrientations& shapedTextOrientations) { - if (shapedTextOrientations.right) return shapedTextOrientations.right; - if (shapedTextOrientations.center) return shapedTextOrientations.center; - if (shapedTextOrientations.left) return shapedTextOrientations.left; + if (shapedTextOrientations.right) + return shapedTextOrientations.right; + if (shapedTextOrientations.center) + return shapedTextOrientations.center; + if (shapedTextOrientations.left) + return shapedTextOrientations.left; return shapedTextOrientations.horizontal; } -Shaping& shapingForTextJustifyType(ShapedTextOrientations& shapedTextOrientations, style::TextJustifyType type) { - switch(type) { - case style::TextJustifyType::Right: return shapedTextOrientations.right; - case style::TextJustifyType::Left: return shapedTextOrientations.left; - case style::TextJustifyType::Center: return shapedTextOrientations.center; +Shaping& shapingForTextJustifyType(ShapedTextOrientations& shapedTextOrientations, + style::TextJustifyType type) { + switch (type) { + case style::TextJustifyType::Right: + return shapedTextOrientations.right; + case style::TextJustifyType::Left: + return shapedTextOrientations.left; + case style::TextJustifyType::Center: + return shapedTextOrientations.center; default: assert(false); return shapedTextOrientations.horizontal; } } -} // namespace +} // namespace // static Point<float> SymbolLayout::evaluateRadialOffset(SymbolAnchorType anchor, float radialOffset) { @@ -268,14 +278,18 @@ Point<float> SymbolLayout::evaluateRadialOffset(SymbolAnchorType anchor, float r return result; } -void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions, - const ImageMap& imageMap, const ImagePositions& imagePositions) { +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 textAlongLine = + layout.get<TextRotationAlignment>() == AlignmentType::Map && !isPointPlacement; for (auto it = features.begin(); it != features.end(); ++it) { auto& feature = *it; - if (feature.geometry.empty()) continue; + if (feature.geometry.empty()) + continue; ShapedTextOrientations shapedTextOrientations; optional<PositionedIcon> shapedIcon; @@ -284,15 +298,19 @@ 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 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) { + 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, - /* ems */ lineHeight, - textAnchor, - textJustify, + /* maxWidth: ems */ + isPointPlacement ? layout.evaluate<TextMaxWidth>(zoom, feature) * util::ONE_EM + : 0.0f, + /* ems */ lineHeight, textAnchor, textJustify, /* ems */ spacing, /* translate */ textOffset, /* writingMode */ writingMode, @@ -301,23 +319,28 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions return result; }; - const std::vector<style::TextVariableAnchorType> variableTextAnchor = layout.evaluate<TextVariableAnchor>(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); + 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 + // 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 if (radialOffset > 0.0f) { // The style spec says don't use `text-offset` and `text-radial-offset` together - // but doesn't actually specify what happens if you use both. We go with the radial offset. + // 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}; + layout.evaluate<TextOffset>(zoom, feature)[1] * util::ONE_EM }; } } - TextJustifyType textJustify = textAlongLine ? TextJustifyType::Center : layout.evaluate<TextJustify>(zoom, feature); - // If this layer uses text-variable-anchor, generate shapings for all justification possibilities. + 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; if (textJustify != TextJustifyType::Auto) { @@ -327,14 +350,17 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions justifications.push_back(getAnchorJustification(anchor)); } } - for (TextJustifyType justification: justifications) { - Shaping& shapingForJustification = shapingForTextJustifyType(shapedTextOrientations, justification); + for (TextJustifyType justification : justifications) { + Shaping& shapingForJustification = + shapingForTextJustifyType(shapedTextOrientations, justification); if (shapingForJustification) { continue; } - // If using text-variable-anchor for the layer, we use a center anchor for all shapings and apply - // the offsets for the anchor in the placement step. - Shaping shaping = applyShaping(*feature.formattedText, WritingModeType::Horizontal, SymbolAnchorType::Center, justification); + // If using text-variable-anchor for the layer, we use a center anchor for all + // shapings and apply the offsets for the anchor in the placement step. + Shaping shaping = + applyShaping(*feature.formattedText, WritingModeType::Horizontal, + SymbolAnchorType::Center, justification); if (shaping) { shapingForJustification = std::move(shaping); if (shaping.lineCount == 1u) { @@ -347,14 +373,17 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions if (textJustify == TextJustifyType::Auto) { textJustify = getAnchorJustification(textAnchor); } - Shaping shaping = applyShaping(*feature.formattedText, WritingModeType::Horizontal, textAnchor, textJustify); + Shaping shaping = applyShaping(*feature.formattedText, WritingModeType::Horizontal, + textAnchor, textJustify); if (shaping) { shapedTextOrientations.horizontal = std::move(shaping); } - if (util::i18n::allowsVerticalWritingMode(feature.formattedText->rawText()) && textAlongLine) { + if (util::i18n::allowsVerticalWritingMode(feature.formattedText->rawText()) && + textAlongLine) { feature.formattedText->verticalizePunctuation(); - shapedTextOrientations.vertical = applyShaping(*feature.formattedText, WritingModeType::Vertical, textAnchor, textJustify); + shapedTextOrientations.vertical = applyShaping( + *feature.formattedText, WritingModeType::Vertical, textAnchor, textJustify); } } } @@ -364,8 +393,7 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions auto image = imageMap.find(*feature.icon); if (image != imageMap.end()) { shapedIcon = PositionedIcon::shapeIcon( - imagePositions.at(*feature.icon), - layout.evaluate<IconOffset>(zoom, feature), + imagePositions.at(*feature.icon), layout.evaluate<IconOffset>(zoom, feature), layout.evaluate<IconAnchor>(zoom, feature), layout.evaluate<IconRotate>(zoom, feature) * util::DEG2RAD); if (image->second->sdf) { @@ -381,7 +409,8 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions // if either shapedText or icon position is present, add the feature if (getDefaultHorizontalShaping(shapedTextOrientations) || shapedIcon) { - addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, glyphPositions, textOffset); + addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, + shapedIcon, glyphPositions, textOffset); } feature.geometry.clear(); @@ -401,7 +430,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, 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> textOffset = { { offset.x, offset.y } }; const std::array<float, 2> iconOffset = layout.evaluate<IconOffset>(zoom, feature); @@ -409,7 +438,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, // 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>(24, feature); const float fontScale = layoutTextSize / glyphSize; const float textBoxScale = tilePixelRatio * fontScale; @@ -421,16 +450,19 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, 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>(); + const SymbolPlacementType textPlacement = + layout.get<TextRotationAlignment>() != AlignmentType::Map ? SymbolPlacementType::Point + : layout.get<SymbolPlacement>(); const float textRepeatDistance = symbolSpacing / 2; const auto evaluatedLayoutProperties = layout.evaluate(zoom, feature); - IndexedSubfeature indexedFeature(feature.index, sourceLayer->getName(), bucketLeaderID, symbolInstances.size()); + IndexedSubfeature indexedFeature(feature.index, sourceLayer->getName(), bucketLeaderID, + symbolInstances.size()); - auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) { - const bool anchorInsideTile = anchor.point.x >= 0 && anchor.point.x < util::EXTENT && anchor.point.y >= 0 && anchor.point.y < util::EXTENT; + auto addSymbolInstance = [&](std::shared_ptr<SymbolInstanceCommonData> sharedData, + Anchor& anchor) { + const bool anchorInsideTile = anchor.point.x >= 0 && anchor.point.x < util::EXTENT && + anchor.point.y >= 0 && anchor.point.y < util::EXTENT; if (mode == MapMode::Tile || anchorInsideTile) { // For static/continuous rendering, only add symbols anchored within this tile: @@ -438,55 +470,76 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, // In tiled rendering mode, add all symbols in the buffers so that we can: // (1) render symbols that overlap into this tile // (2) approximate collision detection effects from neighboring symbols - symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, - evaluatedLayoutProperties, layoutTextSize, - textBoxScale, textPadding, textPlacement, textOffset, - iconBoxScale, iconPadding, iconOffset, - glyphPositions, indexedFeature, layoutFeatureIndex, feature.index, - feature.formattedText ? feature.formattedText->rawText() : std::u16string(), overscaling, rotation, radialTextOffset); + symbolInstances.emplace_back(anchor, sharedData, shapedTextOrientations, shapedIcon, + textPadding, textPlacement, iconBoxScale, iconPadding, + indexedFeature, overscaling, rotation); } }; const auto& type = feature.getType(); - + uint32_t count{ 0U }; if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) { auto clippedLines = util::clipLines(feature.geometry, 0, 0, util::EXTENT, util::EXTENT); + std::cout << "-----Zoom level " << zoom << "------" << std::endl; + // std::cout<< "---------Number of cliped lines: "<< clippedLines.size() << + // "--------------"<<std::endl; for (const auto& line : clippedLines) { - Anchors anchors = getAnchors(line, - symbolSpacing, - textMaxAngle, - (shapedTextOrientations.vertical ?: getDefaultHorizontalShaping(shapedTextOrientations)).left, - (shapedTextOrientations.vertical ?: getDefaultHorizontalShaping(shapedTextOrientations)).right, - (shapedIcon ? shapedIcon->left() : 0), - (shapedIcon ? shapedIcon->right() : 0), - glyphSize, - textMaxBoxScale, - overscaling); - + // std::cout << "Number of geometries: "<< line.size()<< std::endl; + auto sharedData = std::make_shared<SymbolInstanceCommonData>( + line, shapedTextOrientations, shapedIcon, evaluatedLayoutProperties, layoutTextSize, textBoxScale, + textPlacement, textOffset, iconOffset, glyphPositions, layoutFeatureIndex, + feature.index, + (feature.formattedText ? feature.formattedText->rawText() : std::u16string()), + radialTextOffset); + + Anchors anchors = getAnchors( + line, symbolSpacing, textMaxAngle, + (shapedTextOrientations.vertical + ?: getDefaultHorizontalShaping(shapedTextOrientations)) + .left, + (shapedTextOrientations.vertical + ?: getDefaultHorizontalShaping(shapedTextOrientations)) + .right, + (shapedIcon ? shapedIcon->left() : 0), (shapedIcon ? shapedIcon->right() : 0), + glyphSize, textMaxBoxScale, overscaling); + // std::cout<< "Number of anchors : "<< anchors.size() << std::endl; for (auto& anchor : anchors) { - if (!feature.formattedText || !anchorIsTooClose(feature.formattedText->rawText(), textRepeatDistance, anchor)) { - addSymbolInstance(line, anchor); + if (!feature.formattedText || !anchorIsTooClose(feature.formattedText->rawText(), + textRepeatDistance, anchor)) { + addSymbolInstance(sharedData, anchor); + ++count; } } } +// std::cout << "---------Create new Symbol instances for Line, number: " << count +// << "--------------" << std::endl; } 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) { + auto sharedData = std::make_shared<SymbolInstanceCommonData>( + line, shapedTextOrientations, shapedIcon, evaluatedLayoutProperties, layoutTextSize, textBoxScale, + textPlacement, textOffset, iconOffset, glyphPositions, layoutFeatureIndex, + feature.index, + (feature.formattedText ? feature.formattedText->rawText() : std::u16string()), + radialTextOffset); if (line.size() > 1) { - optional<Anchor> anchor = getCenterAnchor(line, - textMaxAngle, - (shapedTextOrientations.vertical ?: getDefaultHorizontalShaping(shapedTextOrientations)).left, - (shapedTextOrientations.vertical ?: getDefaultHorizontalShaping(shapedTextOrientations)).right, - (shapedIcon ? shapedIcon->left() : 0), - (shapedIcon ? shapedIcon->right() : 0), - glyphSize, - textMaxBoxScale); + optional<Anchor> anchor = getCenterAnchor( + line, textMaxAngle, + (shapedTextOrientations.vertical + ?: getDefaultHorizontalShaping(shapedTextOrientations)) + .left, + (shapedTextOrientations.vertical + ?: getDefaultHorizontalShaping(shapedTextOrientations)) + .right, + (shapedIcon ? shapedIcon->left() : 0), (shapedIcon ? shapedIcon->right() : 0), + glyphSize, textMaxBoxScale); if (anchor) { - addSymbolInstance(line, *anchor); + addSymbolInstance(sharedData, *anchor); } } } + } else if (type == FeatureType::Polygon) { for (const auto& polygon : classifyRings(feature.geometry)) { Polygon<double> poly; @@ -501,24 +554,46 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, // 1 pixel worth of precision, in tile coordinates auto poi = mapbox::polylabel(poly, double(util::EXTENT / util::tileSize)); Anchor anchor(poi.x, poi.y, 0, minScale); - addSymbolInstance(polygon[0], anchor); + auto sharedData = std::make_shared<SymbolInstanceCommonData>( + polygon[0], shapedTextOrientations, shapedIcon, evaluatedLayoutProperties, layoutTextSize, + textBoxScale, textPlacement, textOffset, iconOffset, glyphPositions, + layoutFeatureIndex, feature.index, + (feature.formattedText ? feature.formattedText->rawText() : std::u16string()), + radialTextOffset); + addSymbolInstance(sharedData, anchor); } } else if (type == FeatureType::LineString) { for (const auto& line : feature.geometry) { + auto sharedData = std::make_shared<SymbolInstanceCommonData>( + line, shapedTextOrientations, shapedIcon, evaluatedLayoutProperties, layoutTextSize, textBoxScale, + textPlacement, textOffset, iconOffset, glyphPositions, layoutFeatureIndex, + feature.index, + (feature.formattedText ? feature.formattedText->rawText() : std::u16string()), + radialTextOffset); Anchor anchor(line[0].x, line[0].y, 0, minScale); - addSymbolInstance(line, anchor); + addSymbolInstance(sharedData, anchor); } } else if (type == FeatureType::Point) { for (const auto& points : feature.geometry) { for (const auto& point : points) { + auto sharedData = std::make_shared<SymbolInstanceCommonData>( + GeometryCoordinates{ point }, shapedTextOrientations, shapedIcon, evaluatedLayoutProperties, layoutTextSize, textBoxScale, + textPlacement, textOffset, iconOffset, glyphPositions, layoutFeatureIndex, + feature.index, + (feature.formattedText ? feature.formattedText->rawText() : std::u16string()), + radialTextOffset); Anchor anchor(point.x, point.y, 0, minScale); - addSymbolInstance({point}, anchor); + addSymbolInstance(sharedData, anchor); } } + // std::cout << "---------Create new Symbol instances for Point, number: "<< count + // << "--------------"<<std::endl; } } -bool SymbolLayout::anchorIsTooClose(const std::u16string& text, const float repeatDistance, const Anchor& anchor) { +bool SymbolLayout::anchorIsTooClose(const std::u16string& text, + const float repeatDistance, + const Anchor& anchor) { if (compareText.find(text) == compareText.end()) { compareText.emplace(text, Anchors()); } else { @@ -533,8 +608,8 @@ bool SymbolLayout::anchorIsTooClose(const std::u16string& text, const float repe return false; } -// Analog of `addToLineVertexArray` in JS. This version doesn't need to build up a line array like the -// JS version does, but it uses the same logic to calculate tile distances. +// Analog of `addToLineVertexArray` in JS. This version doesn't need to build up a line array like +// the JS version does, but it uses the same logic to calculate tile distances. std::vector<float> CalculateTileDistances(const GeometryCoordinates& line, const Anchor& anchor) { std::vector<float> tileDistances(line.size()); if (anchor.segment != -1) { @@ -556,15 +631,21 @@ std::vector<float> CalculateTileDistances(const GeometryCoordinates& line, const return tileDistances; } -void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIndex>&, std::unordered_map<std::string, LayerRenderData>& renderData, const bool firstLoad, const bool showCollisionBoxes) { - auto bucket = std::make_shared<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(symbolInstances), tilePixelRatio); +void SymbolLayout::createBucket(const ImagePositions&, + std::unique_ptr<FeatureIndex>&, + std::unordered_map<std::string, LayerRenderData>& renderData, + const bool firstLoad, + const bool showCollisionBoxes) { + auto bucket = std::make_shared<SymbolBucket>( + layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear, + sortFeaturesByY, bucketLeaderID, std::move(symbolInstances), tilePixelRatio); - for (SymbolInstance &symbolInstance : bucket->symbolInstances) { - const bool hasText = symbolInstance.hasText; - const bool hasIcon = symbolInstance.hasIcon; - const bool singleLine = symbolInstance.singleLine; + for (SymbolInstance& symbolInstance : bucket->symbolInstances) { + const bool hasText = symbolInstance.commonData->hasText; + const bool hasIcon = symbolInstance.commonData->hasIcon; + const bool singleLine = symbolInstance.commonData->singleLine; - const auto& feature = features.at(symbolInstance.layoutFeatureIndex); + const auto& feature = features.at(symbolInstance.commonData->layoutFeatureIndex); // Insert final placement into collision tree and add glyphs/icons to buffers @@ -572,40 +653,59 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn optional<std::size_t> lastAddedSection; if (singleLine) { optional<std::size_t> placedTextIndex; - lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, placedTextIndex, symbolInstance.rightJustifiedGlyphQuads, lastAddedSection); + lastAddedSection = addSymbolGlyphQuads( + *bucket, symbolInstance, feature, symbolInstance.commonData->writingModes, + placedTextIndex, symbolInstance.commonData->rightJustifiedGlyphQuads, + lastAddedSection); symbolInstance.placedRightTextIndex = placedTextIndex; symbolInstance.placedCenterTextIndex = placedTextIndex; symbolInstance.placedLeftTextIndex = placedTextIndex; } else { - if (!symbolInstance.rightJustifiedGlyphQuads.empty()) { - lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, symbolInstance.placedRightTextIndex, symbolInstance.rightJustifiedGlyphQuads, lastAddedSection); + if (!symbolInstance.commonData->rightJustifiedGlyphQuads.empty()) { + lastAddedSection = addSymbolGlyphQuads( + *bucket, symbolInstance, feature, symbolInstance.commonData->writingModes, + symbolInstance.placedRightTextIndex, + symbolInstance.commonData->rightJustifiedGlyphQuads, lastAddedSection); } - if (!symbolInstance.centerJustifiedGlyphQuads.empty()) { - lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, symbolInstance.placedCenterTextIndex, symbolInstance.centerJustifiedGlyphQuads, lastAddedSection); + if (!symbolInstance.commonData->centerJustifiedGlyphQuads.empty()) { + lastAddedSection = addSymbolGlyphQuads( + *bucket, symbolInstance, feature, symbolInstance.commonData->writingModes, + symbolInstance.placedCenterTextIndex, + symbolInstance.commonData->centerJustifiedGlyphQuads, lastAddedSection); } - if (!symbolInstance.leftJustifiedGlyphQuads.empty()) { - lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, symbolInstance.placedLeftTextIndex, symbolInstance.leftJustifiedGlyphQuads, lastAddedSection); + if (!symbolInstance.commonData->leftJustifiedGlyphQuads.empty()) { + lastAddedSection = addSymbolGlyphQuads( + *bucket, symbolInstance, feature, symbolInstance.commonData->writingModes, + symbolInstance.placedLeftTextIndex, + symbolInstance.commonData->leftJustifiedGlyphQuads, lastAddedSection); } } - if (symbolInstance.writingModes & WritingModeType::Vertical) { - lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, WritingModeType::Vertical, symbolInstance.placedVerticalTextIndex, symbolInstance.verticalGlyphQuads, lastAddedSection); + if (symbolInstance.commonData->writingModes & WritingModeType::Vertical) { + lastAddedSection = addSymbolGlyphQuads( + *bucket, symbolInstance, feature, WritingModeType::Vertical, + symbolInstance.placedVerticalTextIndex, + symbolInstance.commonData->verticalGlyphQuads, lastAddedSection); } assert(lastAddedSection); // True, as hasText == true; updatePaintPropertiesForSection(*bucket, feature, *lastAddedSection); } if (hasIcon) { - if (symbolInstance.iconQuad) { + if (symbolInstance.commonData->iconQuad) { const Range<float> sizeData = bucket->iconSizeBinder->getVertexSizeData(feature); - bucket->icon.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max, - symbolInstance.iconOffset, WritingModeType::None, symbolInstance.line, std::vector<float>()); + bucket->icon.placedSymbols.emplace_back( + symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, + sizeData.max, symbolInstance.commonData->iconOffset, WritingModeType::None, + symbolInstance.commonData->line, std::vector<float>()); symbolInstance.placedIconIndex = bucket->icon.placedSymbols.size() - 1; PlacedSymbol& iconSymbol = bucket->icon.placedSymbols.back(); - iconSymbol.vertexStartIndex = addSymbol(bucket->icon, sizeData, *symbolInstance.iconQuad, - symbolInstance.anchor, iconSymbol, feature.sortKey); + iconSymbol.vertexStartIndex = + addSymbol(bucket->icon, sizeData, *symbolInstance.commonData->iconQuad, + symbolInstance.anchor, iconSymbol, feature.sortKey); for (auto& pair : bucket->paintProperties) { - pair.second.iconBinders.populateVertexVectors(feature, bucket->icon.vertices.elements(), {}, {}); + pair.second.iconBinders.populateVertexVectors( + feature, bucket->icon.vertices.elements(), {}, {}); } } } @@ -614,23 +714,24 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn if (showCollisionBoxes) { addToDebugBuffers(*bucket); } - if (bucket->hasData()){ + if (bucket->hasData()) { for (const auto& pair : layerPaintProperties) { if (!firstLoad) { bucket->justReloaded = true; } - renderData.emplace(pair.first, LayerRenderData{bucket, pair.second}); + renderData.emplace(pair.first, LayerRenderData{ bucket, pair.second }); } } - } void SymbolLayout::updatePaintPropertiesForSection(SymbolBucket& bucket, const SymbolFeature& feature, std::size_t sectionIndex) { - const auto& formattedSection = sectionOptionsToValue((*feature.formattedText).sectionAt(sectionIndex)); + const auto& formattedSection = + sectionOptionsToValue((*feature.formattedText).sectionAt(sectionIndex)); for (auto& pair : bucket.paintProperties) { - pair.second.textBinders.populateVertexVectors(feature, bucket.text.vertices.elements(), {}, {}, formattedSection); + pair.second.textBinders.populateVertexVectors(feature, bucket.text.vertices.elements(), {}, + {}, formattedSection); } } @@ -644,8 +745,10 @@ std::size_t SymbolLayout::addSymbolGlyphQuads(SymbolBucket& bucket, const Range<float> sizeData = bucket.textSizeBinder->getVertexSizeData(feature); const bool hasFormatSectionOverrides = bucket.hasFormatSectionOverrides(); - bucket.text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max, - symbolInstance.textOffset, writingMode, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor)); + bucket.text.placedSymbols.emplace_back( + symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max, + symbolInstance.commonData->textOffset, writingMode, symbolInstance.commonData->line, + CalculateTileDistances(symbolInstance.commonData->line, symbolInstance.anchor)); placedIndex = bucket.text.placedSymbols.size() - 1; PlacedSymbol& placedSymbol = bucket.text.placedSymbols.back(); @@ -657,7 +760,8 @@ std::size_t SymbolLayout::addSymbolGlyphQuads(SymbolBucket& bucket, } lastAddedSection = symbolQuad.sectionIndex; } - size_t index = addSymbol(bucket.text, sizeData, symbolQuad, symbolInstance.anchor, placedSymbol, feature.sortKey); + size_t index = addSymbol(bucket.text, sizeData, symbolQuad, symbolInstance.anchor, + placedSymbol, feature.sortKey); if (firstSymbol) { placedSymbol.vertexStartIndex = index; firstSymbol = false; @@ -675,16 +779,17 @@ size_t SymbolLayout::addSymbol(SymbolBucket::Buffer& buffer, float sortKey) { constexpr const uint16_t vertexLength = 4; - const auto &tl = symbol.tl; - const auto &tr = symbol.tr; - const auto &bl = symbol.bl; - const auto &br = symbol.br; - const auto &tex = symbol.tex; + const auto& tl = symbol.tl; + const auto& tr = symbol.tr; + const auto& bl = symbol.bl; + const auto& br = symbol.br; + const auto& tex = symbol.tex; if (buffer.segments.empty() || buffer.segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max() || fabs(buffer.segments.back().sortKey - sortKey) > std::numeric_limits<float>::epsilon()) { - buffer.segments.emplace_back(buffer.vertices.elements(), buffer.triangles.elements(), 0ul, 0ul, sortKey); + buffer.segments.emplace_back(buffer.vertices.elements(), buffer.triangles.elements(), 0ul, + 0ul, sortKey); } // We're generating triangle fans, so we always start with the first @@ -694,10 +799,14 @@ size_t SymbolLayout::addSymbol(SymbolBucket::Buffer& buffer, uint16_t index = segment.vertexLength; // coordinates (2 triangles) - buffer.vertices.emplace_back(SymbolSDFIconProgram::layoutVertex(labelAnchor.point, tl, symbol.glyphOffset.y, tex.x, tex.y, sizeData)); - buffer.vertices.emplace_back(SymbolSDFIconProgram::layoutVertex(labelAnchor.point, tr, symbol.glyphOffset.y, tex.x + tex.w, tex.y, sizeData)); - buffer.vertices.emplace_back(SymbolSDFIconProgram::layoutVertex(labelAnchor.point, bl, symbol.glyphOffset.y, tex.x, tex.y + tex.h, sizeData)); - buffer.vertices.emplace_back(SymbolSDFIconProgram::layoutVertex(labelAnchor.point, br, symbol.glyphOffset.y, tex.x + tex.w, tex.y + tex.h, sizeData)); + buffer.vertices.emplace_back(SymbolSDFIconProgram::layoutVertex( + labelAnchor.point, tl, symbol.glyphOffset.y, tex.x, tex.y, sizeData)); + buffer.vertices.emplace_back(SymbolSDFIconProgram::layoutVertex( + labelAnchor.point, tr, symbol.glyphOffset.y, tex.x + tex.w, tex.y, sizeData)); + buffer.vertices.emplace_back(SymbolSDFIconProgram::layoutVertex( + labelAnchor.point, bl, symbol.glyphOffset.y, tex.x, tex.y + tex.h, sizeData)); + buffer.vertices.emplace_back(SymbolSDFIconProgram::layoutVertex( + labelAnchor.point, br, symbol.glyphOffset.y, tex.x + tex.w, tex.y + tex.h, sizeData)); // Dynamic/Opacity vertices are initialized so that the vertex count always agrees with // the layout vertex buffer, but they will always be updated before rendering happens @@ -731,37 +840,47 @@ void SymbolLayout::addToDebugBuffers(SymbolBucket& bucket) { return; } - for (const SymbolInstance &symbolInstance : symbolInstances) { + for (const SymbolInstance& symbolInstance : symbolInstances) { auto populateCollisionBox = [&](const auto& feature) { - SymbolBucket::CollisionBuffer& collisionBuffer = feature.alongLine ? - static_cast<SymbolBucket::CollisionBuffer&>(bucket.collisionCircle) : - static_cast<SymbolBucket::CollisionBuffer&>(bucket.collisionBox); - for (const CollisionBox &box : feature.boxes) { + SymbolBucket::CollisionBuffer& collisionBuffer = + feature.alongLine + ? static_cast<SymbolBucket::CollisionBuffer&>(bucket.collisionCircle) + : static_cast<SymbolBucket::CollisionBuffer&>(bucket.collisionBox); + for (const CollisionBox& box : feature.boxes) { auto& anchor = box.anchor; - Point<float> tl{box.x1, box.y1}; - Point<float> tr{box.x2, box.y1}; - Point<float> bl{box.x1, box.y2}; - Point<float> br{box.x2, box.y2}; + Point<float> tl{ box.x1, box.y1 }; + Point<float> tr{ box.x2, box.y1 }; + Point<float> bl{ box.x1, box.y2 }; + Point<float> br{ box.x2, box.y2 }; static constexpr std::size_t vertexLength = 4; const std::size_t indexLength = feature.alongLine ? 6 : 8; - if (collisionBuffer.segments.empty() || collisionBuffer.segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) { - collisionBuffer.segments.emplace_back(collisionBuffer.vertices.elements(), - feature.alongLine? bucket.collisionCircle.triangles.elements() : bucket.collisionBox.lines.elements()); + if (collisionBuffer.segments.empty() || + collisionBuffer.segments.back().vertexLength + vertexLength > + std::numeric_limits<uint16_t>::max()) { + collisionBuffer.segments.emplace_back( + collisionBuffer.vertices.elements(), + feature.alongLine ? bucket.collisionCircle.triangles.elements() + : bucket.collisionBox.lines.elements()); } auto& segment = collisionBuffer.segments.back(); uint16_t index = segment.vertexLength; - collisionBuffer.vertices.emplace_back(CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, tl)); - collisionBuffer.vertices.emplace_back(CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, tr)); - collisionBuffer.vertices.emplace_back(CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, br)); - collisionBuffer.vertices.emplace_back(CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, bl)); + collisionBuffer.vertices.emplace_back( + CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, tl)); + collisionBuffer.vertices.emplace_back( + CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, tr)); + collisionBuffer.vertices.emplace_back( + CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, br)); + collisionBuffer.vertices.emplace_back( + CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, bl)); // Dynamic vertices are initialized so that the vertex count always agrees with - // the layout vertex buffer, but they will always be updated before rendering happens + // the layout vertex buffer, but they will always be updated before rendering + // happens auto dynamicVertex = CollisionBoxProgram::dynamicVertex(false, false, {}); collisionBuffer.dynamicVertices.emplace_back(dynamicVertex); collisionBuffer.dynamicVertices.emplace_back(dynamicVertex); |