void Placement::placeLayer(const RenderLayerSymbolInterface& symbolInterface, const mat4& projMatrix, bool showCollisionBoxes) { std::unordered_set<uint32_t> seenCrossTileIDs; for (const RenderTile& renderTile : symbolInterface.getRenderTiles()) { if (!renderTile.tile.isRenderable()) { continue; } assert(renderTile.tile.kind == Tile::Kind::Geometry); GeometryTile& geometryTile = static_cast<GeometryTile&>(renderTile.tile); auto bucket = symbolInterface.getSymbolBucket(renderTile); if (!bucket) { continue; } SymbolBucket& symbolBucket = *bucket; if (symbolBucket.bucketLeaderID != symbolInterface.layerID()) { // Only place this layer if it's the "group leader" for the bucket continue; } auto& layout = symbolBucket.layout; const float pixelsToTileUnits = renderTile.id.pixelsToTileUnits(1, state.getZoom()); const float scale = std::pow(2, state.getZoom() - geometryTile.id.overscaledZ); const float textPixelRatio = (util::tileSize * geometryTile.id.overscaleFactor()) / util::EXTENT; mat4 posMatrix; state.matrixFor(posMatrix, renderTile.id); matrix::multiply(posMatrix, projMatrix, posMatrix); mat4 textLabelPlaneMatrix = getLabelPlaneMatrix(posMatrix, layout.get<style::TextPitchAlignment>() == style::AlignmentType::Map, layout.get<style::TextRotationAlignment>() == style::AlignmentType::Map, state, pixelsToTileUnits); mat4 iconLabelPlaneMatrix = getLabelPlaneMatrix(posMatrix, layout.get<style::IconPitchAlignment>() == style::AlignmentType::Map, layout.get<style::IconRotationAlignment>() == style::AlignmentType::Map, state, pixelsToTileUnits); // As long as this placement lives, we have to hold onto this bucket's // matching FeatureIndex/data for querying purposes retainedQueryData.emplace(std::piecewise_construct, std::forward_as_tuple(symbolBucket.bucketInstanceId), std::forward_as_tuple(symbolBucket.bucketInstanceId, geometryTile.getFeatureIndex(), geometryTile.id)); const auto collisionGroup = collisionGroups.get(geometryTile.sourceID); placeLayerBucket(symbolBucket, posMatrix, textLabelPlaneMatrix, iconLabelPlaneMatrix, scale, textPixelRatio, showCollisionBoxes, seenCrossTileIDs, renderTile.tile.holdForFade(), collisionGroup); } }
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(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, 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 float cameraToAnchorDistance = anchorPos[3]; const float perspectiveRatio = 0.5 + 0.5 * (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); } } }