#include #include #include #include #include #include #include #include #include #include #include namespace mbgl { FeatureIndex::FeatureIndex() : grid(util::EXTENT, 16, 0) { } void FeatureIndex::insert(const GeometryCollection& geometries, std::size_t index, const std::string& sourceLayerName, const std::string& bucketName) { for (const auto& ring : geometries) { grid.insert(IndexedSubfeature { index, sourceLayerName, bucketName, sortIndex++ }, mapbox::geometry::envelope(ring)); } } static bool vectorContains(const std::vector& vector, const std::string& s) { return std::find(vector.begin(), vector.end(), s) != vector.end(); } static bool vectorsIntersect(const std::vector& vectorA, const std::vector& vectorB) { for (const auto& a : vectorA) { if (vectorContains(vectorB, a)) { return true; } } return false; } static bool topDown(const IndexedSubfeature& a, const IndexedSubfeature& b) { return a.sortIndex > b.sortIndex; } static bool topDownSymbols(const IndexedSubfeature& a, const IndexedSubfeature& b) { return a.sortIndex < b.sortIndex; } void FeatureIndex::query( std::unordered_map>& result, const GeometryCollection& queryGeometry, const float bearing, const double tileSize, const double scale, const optional>& filterLayerIDs, const GeometryTile& geometryTile, const Style& style) const { mapbox::geometry::box box = mapbox::geometry::envelope(queryGeometry); const float pixelsToTileUnits = util::EXTENT / tileSize / scale; const int16_t additionalRadius = std::min(util::EXTENT, std::ceil(style.getQueryRadius() * pixelsToTileUnits)); std::vector features = grid.query({ box.min - additionalRadius, box.max + additionalRadius }); std::sort(features.begin(), features.end(), topDown); size_t previousSortIndex = std::numeric_limits::max(); for (const auto& indexedFeature : features) { // If this feature is the same as the previous feature, skip it. if (indexedFeature.sortIndex == previousSortIndex) continue; previousSortIndex = indexedFeature.sortIndex; addFeature(result, indexedFeature, queryGeometry, filterLayerIDs, geometryTile, style, bearing, pixelsToTileUnits); } // query symbol features assert(collisionTile); std::vector symbolFeatures = collisionTile->queryRenderedSymbols(box, scale); std::sort(symbolFeatures.begin(), symbolFeatures.end(), topDownSymbols); for (const auto& symbolFeature : symbolFeatures) { addFeature(result, symbolFeature, queryGeometry, filterLayerIDs, geometryTile, style, bearing, pixelsToTileUnits); } } void FeatureIndex::addFeature( std::unordered_map>& result, const IndexedSubfeature& indexedFeature, const GeometryCollection& queryGeometry, const optional>& filterLayerIDs, const GeometryTile& geometryTile, const Style& style, const float bearing, const float pixelsToTileUnits) const { auto& layerIDs = bucketLayerIDs.at(indexedFeature.bucketName); if (filterLayerIDs && !vectorsIntersect(layerIDs, *filterLayerIDs)) { return; } auto sourceLayer = geometryTile.getLayer(indexedFeature.sourceLayerName); assert(sourceLayer); auto geometryTileFeature = sourceLayer->getFeature(indexedFeature.index); assert(geometryTileFeature); for (const auto& layerID : layerIDs) { if (filterLayerIDs && !vectorContains(*filterLayerIDs, layerID)) { continue; } auto styleLayer = style.getLayer(layerID); if (!styleLayer) { continue; } if (!styleLayer->is()) { auto geometries = geometryTileFeature->getGeometries(); if (!styleLayer->queryIntersectsGeometry(queryGeometry, geometries, bearing, pixelsToTileUnits)) continue; } Feature feature { mapbox::geometry::point() }; feature.properties = geometryTileFeature->getProperties(); optional id = geometryTileFeature->getID(); if (id) { feature.id = Value(*id); } result[layerID].push_back(std::move(feature)); } } optional FeatureIndex::translateQueryGeometry( const GeometryCollection& queryGeometry, const std::array& translate, const TranslateAnchorType anchorType, const float bearing, const float pixelsToTileUnits) { if (translate[0] == 0 && translate[1] == 0) { return {}; } GeometryCoordinate translateVec(translate[0] * pixelsToTileUnits, translate[1] * pixelsToTileUnits); if (anchorType == TranslateAnchorType::Viewport) { translateVec = util::rotate(translateVec, -bearing); } GeometryCollection translated; for (const auto& ring : queryGeometry) { translated.emplace_back(); auto& translatedRing = translated.back(); for (const auto& p : ring) { translatedRing.push_back(p - translateVec); } } return translated; } void FeatureIndex::addBucketLayerName(const std::string& bucketName, const std::string& layerID) { bucketLayerIDs[bucketName].push_back(layerID); } void FeatureIndex::setCollisionTile(std::unique_ptr collisionTile_) { collisionTile = std::move(collisionTile_); } } // namespace mbgl