#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { using namespace style; GeometryTile::GeometryTile(const OverscaledTileID& id_, std::string sourceID_, const TileParameters& parameters, GlyphAtlas& glyphAtlas_, SpriteAtlas& spriteAtlas_) : Tile(id_), sourceID(std::move(sourceID_)), style(parameters.style), mailbox(std::make_shared(*util::RunLoop::Get())), worker(parameters.workerScheduler, ActorRef(*this, mailbox), id_, obsolete, parameters.mode), glyphAtlas(glyphAtlas_), spriteAtlas(spriteAtlas_), placementThrottler(Milliseconds(300), [this] { invokePlacement(); }) { } GeometryTile::~GeometryTile() { glyphAtlas.removeGlyphs(*this); spriteAtlas.removeRequestor(*this); cancel(); } void GeometryTile::cancel() { obsolete = true; } void GeometryTile::setError(std::exception_ptr err) { loaded = true; renderable = false; observer->onTileError(*this, err); } void GeometryTile::setData(std::unique_ptr data_) { // Mark the tile as pending again if it was complete before to prevent signaling a complete // state despite pending parse operations. pending = true; ++correlationID; worker.invoke(&GeometryTileWorker::setData, std::move(data_), correlationID); redoLayout(); } void GeometryTile::setPlacementConfig(const PlacementConfig& desiredConfig) { if (requestedConfig == desiredConfig) { return; } // Mark the tile as pending again if it was complete before to prevent signaling a complete // state despite pending parse operations. pending = true; ++correlationID; requestedConfig = desiredConfig; placementThrottler.invoke(); } void GeometryTile::invokePlacement() { if (requestedConfig) { worker.invoke(&GeometryTileWorker::setPlacementConfig, *requestedConfig, correlationID); } } void GeometryTile::redoLayout() { // Mark the tile as pending again if it was complete before to prevent signaling a complete // state despite pending parse operations. pending = true; std::vector> copy; for (const Layer* layer : style.getLayers()) { // Avoid cloning and including irrelevant layers. if (layer->is() || layer->is() || layer->baseImpl->source != sourceID || id.overscaledZ < std::floor(layer->baseImpl->minZoom) || id.overscaledZ >= std::ceil(layer->baseImpl->maxZoom) || layer->baseImpl->visibility == VisibilityType::None) { continue; } copy.push_back(layer->baseImpl->clone()); } ++correlationID; worker.invoke(&GeometryTileWorker::setLayers, std::move(copy), correlationID); } void GeometryTile::onLayout(LayoutResult result) { loaded = true; renderable = true; nonSymbolBuckets = std::move(result.nonSymbolBuckets); featureIndex = std::move(result.featureIndex); data = std::move(result.tileData); collisionTile.reset(); observer->onTileChanged(*this); } void GeometryTile::onPlacement(PlacementResult result) { loaded = true; renderable = true; if (result.correlationID == correlationID) { pending = false; } symbolBuckets = std::move(result.symbolBuckets); for (auto& entry : symbolBuckets) { dynamic_cast(entry.second.get())->spriteAtlas = &spriteAtlas; } collisionTile = std::move(result.collisionTile); observer->onTileChanged(*this); } void GeometryTile::onError(std::exception_ptr err) { loaded = true; pending = false; renderable = false; observer->onTileError(*this, err); } void GeometryTile::onGlyphsAvailable(GlyphPositionMap glyphPositions) { worker.invoke(&GeometryTileWorker::onGlyphsAvailable, std::move(glyphPositions)); } void GeometryTile::getGlyphs(GlyphDependencies glyphDependencies) { glyphAtlas.getGlyphs(*this, std::move(glyphDependencies)); } void GeometryTile::onIconsAvailable(IconMap icons) { worker.invoke(&GeometryTileWorker::onIconsAvailable, std::move(icons)); } void GeometryTile::getIcons(IconDependencies) { spriteAtlas.getIcons(*this); } Bucket* GeometryTile::getBucket(const RenderLayer& layer) const { const auto& buckets = layer.is() ? symbolBuckets : nonSymbolBuckets; const auto it = buckets.find(layer.baseImpl.id); if (it == buckets.end()) { return nullptr; } assert(it->second); return it->second.get(); } void GeometryTile::queryRenderedFeatures( std::unordered_map>& result, const GeometryCoordinates& queryGeometry, const TransformState& transformState, const RenderedQueryOptions& options) { if (!featureIndex || !data) return; featureIndex->query(result, queryGeometry, transformState.getAngle(), util::tileSize * id.overscaleFactor(), std::pow(2, transformState.getZoom() - id.overscaledZ), options, *data, id.canonical, style, collisionTile.get(), *this); } void GeometryTile::querySourceFeatures( std::vector& result, const SourceQueryOptions& options) { // Data not yet available if (!data) { return; } // No source layers, specified, nothing to do if (!options.sourceLayers) { Log::Warning(Event::General, "At least one sourceLayer required"); return; } for (auto sourceLayer : *options.sourceLayers) { // Go throught all sourceLayers, if any // to gather all the features auto layer = data->getLayer(sourceLayer); if (layer) { auto featureCount = layer->featureCount(); for (std::size_t i = 0; i < featureCount; i++) { auto feature = layer->getFeature(i); // Apply filter, if any if (options.filter && !(*options.filter)(*feature)) { continue; } result.push_back(convertFeature(*feature, id.canonical)); } } } } } // namespace mbgl