#include #include #include #include #include using namespace mbgl; Annotation::Annotation(AnnotationType type_, std::vector geometry_) : type(type_), geometry(geometry_) { if (type == AnnotationType::Point) { bounds = LatLngBounds(getPoint(), getPoint()); } else { for (auto segment : geometry) { for (auto point : segment) { bounds.extend(point); } } } } LatLng Annotation::getPoint() const { return geometry[0][0]; } AnnotationManager::AnnotationManager() : nullTile(util::make_unique()) {} vec2 AnnotationManager::projectPoint(LatLng& point) { double sine = std::sin(point.latitude * M_PI / 180); double x = point.longitude / 360 + 0.5; double y = 0.5 - 0.25 * std::log((1 + sine) / (1 - sine)) / M_PI; return vec2(x, y); } std::pair, std::vector> AnnotationManager::addPointAnnotations(std::vector points, std::vector& symbols, const Map& map) { uint16_t extent = 4096; std::vector annotationIDs(points.size()); std::vector affectedTiles; for (uint32_t i = 0; i < points.size(); ++i) { uint32_t annotationID = nextID(); auto anno_it = annotations.emplace(annotationID, util::make_unique(AnnotationType::Point, std::vector({{ points[i] }}))); uint8_t maxZoom = map.getMaxZoom(); uint32_t z2 = 1 << maxZoom; vec2 p = projectPoint(points[i]); uint32_t x = p.x * z2; uint32_t y = p.y * z2; for (int8_t z = maxZoom; z >= 0; z--) { affectedTiles.emplace_back(z, x, y); Tile::ID tileID = affectedTiles.back(); Coordinate coordinate(extent * (p.x * z2 - x), extent * (p.y * z2 - y)); GeometryCollection geometries({{ {{ coordinate }} }}); std::map properties = {{ "sprite", (symbols[i].length() ? symbols[i] : defaultPointAnnotationSymbol) }}; auto feature = std::make_shared(FeatureType::Point, geometries, properties); auto tile_it = annotationTiles.find(tileID); if (tile_it != annotationTiles.end()) { // get point layer & add feature auto layer = tile_it->second.second->getMutableLayer(util::ANNOTATIONS_POINTS_LAYER_ID); layer->addFeature(feature); // record annotation association with tile tile_it->second.first.push_back(annotationID); } else { // create point layer & add feature util::ptr layer = std::make_shared(); layer->addFeature(feature); // create tile & record annotation association auto tile_pos = annotationTiles.emplace(tileID, std::make_pair(std::vector({ annotationID }), util::make_unique())); // add point layer to tile tile_pos.first->second.second->addLayer(util::ANNOTATIONS_POINTS_LAYER_ID, layer); } // record annotation association with tile feature anno_it.first->second->tileFeatures.emplace(tileID, std::vector>({ feature })); z2 /= 2; x /= 2; y /= 2; } annotationIDs.push_back(annotationID); } return std::make_pair(affectedTiles, annotationIDs); } std::vector AnnotationManager::removeAnnotations(std::vector ids) { std::vector affectedTiles; for (auto& annotationID : ids) { auto annotation_it = annotations.find(annotationID); if (annotation_it != annotations.end()) { auto& annotation = annotation_it->second; for (auto& tile_it : annotationTiles) { auto features_it = annotation->tileFeatures.find(tile_it.first); if (features_it != annotation->tileFeatures.end()) { auto layer = tile_it.second.second->getMutableLayer(util::ANNOTATIONS_POINTS_LAYER_ID); auto& features = features_it->second; layer->removeFeature(features[0]); affectedTiles.push_back(tile_it.first); } } annotations.erase(annotationID); } } return affectedTiles; } std::vector AnnotationManager::getAnnotationsInBounds(LatLngBounds queryBounds, const Map& map) const { uint8_t z = map.getMaxZoom(); uint32_t z2 = 1 << z; vec2 swPoint = projectPoint(queryBounds.sw); vec2 nePoint = projectPoint(queryBounds.ne); // tiles number y from top down Tile::ID nwTile(z, swPoint.x * z2, nePoint.y * z2); Tile::ID seTile(z, nePoint.x * z2, swPoint.y * z2); std::vector matchingAnnotations; for (auto& tile : annotationTiles) { Tile::ID id = tile.first; if (id.z == z) { if (id.x >= nwTile.x && id.x <= seTile.x && id.y >= nwTile.y && id.y <= seTile.y) { if (id.x > nwTile.x && id.x < seTile.x && id.y > nwTile.y && id.y < seTile.y) { // trivial accept; grab all of the tile's annotations std::copy(tile.second.first.begin(), tile.second.first.end(), std::back_inserter(matchingAnnotations)); } else { // check tile's annotations' bounding boxes std::copy_if(tile.second.first.begin(), tile.second.first.end(), std::back_inserter(matchingAnnotations), [&](const uint32_t annotationID) -> bool { LatLngBounds annoBounds = this->annotations.find(annotationID)->second->getBounds(); return (annoBounds.sw.latitude >= queryBounds.sw.latitude && annoBounds.ne.latitude <= queryBounds.ne.latitude && annoBounds.sw.longitude >= queryBounds.sw.longitude && annoBounds.ne.longitude <= queryBounds.ne.longitude); }); } } } } return matchingAnnotations; } LatLngBounds AnnotationManager::getBoundsForAnnotations(std::vector ids) const { LatLngBounds bounds; for (auto id : ids) { auto annotation_it = annotations.find(id); if (annotation_it != annotations.end()) { bounds.extend(annotation_it->second->getPoint()); } } return bounds; } const std::unique_ptr& AnnotationManager::getTile(Tile::ID const& id) { std::lock_guard lock(mtx); auto tile_it = annotationTiles.find(id); if (tile_it != annotationTiles.end()) { return tile_it->second.second; } return nullTile; }