Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1021 from mapbox/point-annotations-api
Browse files Browse the repository at this point in the history
refs #893 #992: point annotations API
  • Loading branch information
incanus committed Mar 18, 2015
2 parents 1ce51a1 + 93abf88 commit d47b298
Show file tree
Hide file tree
Showing 24 changed files with 656 additions and 39 deletions.
72 changes: 72 additions & 0 deletions include/mbgl/map/annotation.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#ifndef MBGL_MAP_ANNOTATIONS
#define MBGL_MAP_ANNOTATIONS

#include <mbgl/map/tile.hpp>
#include <mbgl/map/live_tile.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/vec.hpp>

#include <string>
#include <vector>
#include <map>
#include <mutex>
#include <memory>

namespace mbgl {

class Annotation;
class Map;

typedef std::vector<LatLng> AnnotationSegment;

enum class AnnotationType : uint8_t {
Point,
Shape
};

class AnnotationManager : private util::noncopyable {
public:
AnnotationManager();

void setDefaultPointAnnotationSymbol(std::string& symbol) { defaultPointAnnotationSymbol = symbol; }
std::pair<std::vector<Tile::ID>, std::vector<uint32_t>> addPointAnnotations(std::vector<LatLng>, std::vector<std::string>& symbols, const Map&);
std::vector<Tile::ID> removeAnnotations(std::vector<uint32_t>);
std::vector<uint32_t> getAnnotationsInBounds(LatLngBounds, const Map&) const;
LatLngBounds getBoundsForAnnotations(std::vector<uint32_t>) const;

const std::unique_ptr<LiveTile>& getTile(Tile::ID const& id);

private:
uint32_t nextID() { return nextID_++; }
static vec2<double> projectPoint(LatLng& point);

private:
std::mutex mtx;
std::string defaultPointAnnotationSymbol;
std::map<uint32_t, std::unique_ptr<Annotation>> annotations;
std::map<Tile::ID, std::pair<std::vector<uint32_t>, std::unique_ptr<LiveTile>>> annotationTiles;
std::unique_ptr<LiveTile> nullTile;
uint32_t nextID_ = 0;
};

class Annotation : private util::noncopyable {
friend class AnnotationManager;
public:
Annotation(AnnotationType, std::vector<AnnotationSegment>);

private:
LatLng getPoint() const;
LatLngBounds getBounds() const { return bounds; }

private:
const AnnotationType type = AnnotationType::Point;
const std::vector<AnnotationSegment> geometry;
std::map<Tile::ID, std::vector<std::weak_ptr<const LiveTileFeature>>> tileFeatures;
LatLngBounds bounds;
};

}

#endif
15 changes: 14 additions & 1 deletion include/mbgl/map/map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class GlyphAtlas;
class SpriteAtlas;
class LineAtlas;
class Environment;
class AnnotationManager;

class Map : private util::noncopyable {
friend class View;
Expand Down Expand Up @@ -140,13 +141,23 @@ class Map : private util::noncopyable {
inline const vec2<double> pixelForLatLng(const LatLng latLng) const { return state.pixelForLatLng(latLng); }
inline const LatLng latLngForPixel(const vec2<double> pixel) const { return state.latLngForPixel(pixel); }

// Annotations
void setDefaultPointAnnotationSymbol(std::string&);
uint32_t addPointAnnotation(LatLng, std::string& symbol);
std::vector<uint32_t> addPointAnnotations(std::vector<LatLng>, std::vector<std::string>& symbols);
void removeAnnotation(uint32_t);
void removeAnnotations(std::vector<uint32_t>);
std::vector<uint32_t> getAnnotationsInBounds(LatLngBounds) const;
LatLngBounds getBoundsForAnnotations(std::vector<uint32_t>) const;

// Debug
void setDebug(bool value);
void toggleDebug();
bool getDebug() const;

inline const TransformState &getState() const { return state; }
inline std::chrono::steady_clock::time_point getTime() const { return animationTime; }
inline AnnotationManager& getAnnotationManager() const { return *annotationManager; }

private:
// This may only be called by the View object.
Expand All @@ -170,6 +181,8 @@ class Map : private util::noncopyable {
// the stylesheet.
void prepare();

void updateAnnotationTiles(std::vector<Tile::ID>&);

enum class Mode : uint8_t {
None, // we're not doing any processing
Continuous, // continually updating map
Expand Down Expand Up @@ -219,8 +232,8 @@ class Map : private util::noncopyable {
util::ptr<Sprite> sprite;
const std::unique_ptr<LineAtlas> lineAtlas;
util::ptr<TexturePool> texturePool;

const std::unique_ptr<Painter> painter;
util::ptr<AnnotationManager> annotationManager;

std::string styleURL;
std::string styleJSON = "";
Expand Down
3 changes: 3 additions & 0 deletions include/mbgl/util/constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define MBGL_UTIL_CONSTANTS

#include <cmath>
#include <string>

namespace mbgl {

Expand All @@ -15,6 +16,8 @@ extern const double M2PI;
extern const double EARTH_RADIUS_M;
extern const double LATITUDE_MAX;

extern const std::string ANNOTATIONS_POINTS_LAYER_ID;

}

namespace debug {
Expand Down
15 changes: 15 additions & 0 deletions include/mbgl/util/geo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ struct ProjectedMeters {
: northing(n), easting(e) {}
};

struct LatLngBounds {
LatLng sw = {90, 180};
LatLng ne = {-90, -180};

inline LatLngBounds(LatLng sw_ = {90, 180}, LatLng ne_ = {-90, -180})
: sw(sw_), ne(ne_) {}

inline void extend(const LatLng& point) {
if (point.latitude < sw.latitude) sw.latitude = point.latitude;
if (point.latitude > ne.latitude) ne.latitude = point.latitude;
if (point.longitude < sw.longitude) sw.longitude = point.longitude;
if (point.longitude > ne.longitude) ne.longitude = point.longitude;
}
};

}

#endif
2 changes: 1 addition & 1 deletion macosx/mapboxgl-app.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
'product_extension': 'app',
'mac_bundle': 1,
'mac_bundle_resources': [
'Icon.icns',
'Icon.icns'
],

'dependencies': [
Expand Down
190 changes: 190 additions & 0 deletions src/mbgl/map/annotation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
#include <mbgl/map/annotation.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/util/std.hpp>

#include <algorithm>
#include <memory>

using namespace mbgl;

Annotation::Annotation(AnnotationType type_, std::vector<AnnotationSegment> 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<LiveTile>()) {}

vec2<double> 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<double>(x, y);
}

std::pair<std::vector<Tile::ID>, std::vector<uint32_t>> AnnotationManager::addPointAnnotations(std::vector<LatLng> points, std::vector<std::string>& symbols, const Map& map) {

uint16_t extent = 4096;

std::vector<uint32_t> annotationIDs(points.size());
std::vector<Tile::ID> affectedTiles;

for (uint32_t i = 0; i < points.size(); ++i) {
uint32_t annotationID = nextID();

auto anno_it = annotations.emplace(annotationID, util::make_unique<Annotation>(AnnotationType::Point, std::vector<AnnotationSegment>({{ points[i] }})));

uint8_t maxZoom = map.getMaxZoom();

uint32_t z2 = 1 << maxZoom;

vec2<double> 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<std::string, std::string> properties = {{ "sprite", (symbols[i].length() ? symbols[i] : defaultPointAnnotationSymbol) }};

auto feature = std::make_shared<const LiveTileFeature>(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<LiveTileLayer> layer = std::make_shared<LiveTileLayer>();
layer->addFeature(feature);
// create tile & record annotation association
auto tile_pos = annotationTiles.emplace(tileID, std::make_pair(std::vector<uint32_t>({ annotationID }), util::make_unique<LiveTile>()));
// 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<std::weak_ptr<const LiveTileFeature>>({ feature }));

z2 /= 2;
x /= 2;
y /= 2;
}

annotationIDs.push_back(annotationID);
}

return std::make_pair(affectedTiles, annotationIDs);
}

std::vector<Tile::ID> AnnotationManager::removeAnnotations(std::vector<uint32_t> ids) {
std::vector<Tile::ID> 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& tileAnnotations = tile_it.second.first;
util::erase_if(tileAnnotations, tileAnnotations.begin(),
tileAnnotations.end(), [&](const uint32_t annotationID_) -> bool {
return (annotationID_ == annotationID);
});
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<uint32_t> AnnotationManager::getAnnotationsInBounds(LatLngBounds queryBounds, const Map& map) const {
uint8_t z = map.getMaxZoom();
uint32_t z2 = 1 << z;
vec2<double> swPoint = projectPoint(queryBounds.sw);
vec2<double> 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<uint32_t> 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<uint32_t> 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<LiveTile>& AnnotationManager::getTile(Tile::ID const& id) {
std::lock_guard<std::mutex> lock(mtx);

auto tile_it = annotationTiles.find(id);
if (tile_it != annotationTiles.end()) {
return tile_it->second.second;
}
return nullTile;
}
10 changes: 5 additions & 5 deletions src/mbgl/map/geometry_tile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,22 @@ enum class FeatureType : uint8_t {

typedef std::vector<std::vector<Coordinate>> GeometryCollection;

class GeometryTileFeature : public mbgl::util::noncopyable {
class GeometryTileFeature : private util::noncopyable {
public:
virtual FeatureType getType() const = 0;
virtual mapbox::util::optional<Value> getValue(const std::string& key) const = 0;
virtual GeometryCollection getGeometries() const = 0;
};

class GeometryTileLayer : public mbgl::util::noncopyable {
class GeometryTileLayer : private util::noncopyable {
public:
virtual std::size_t featureCount() const = 0;
virtual util::ptr<const GeometryTileFeature> feature(std::size_t i) const = 0;
virtual util::ptr<const GeometryTileFeature> getFeature(std::size_t) const = 0;
};

class GeometryTile : public mbgl::util::noncopyable {
class GeometryTile : private util::noncopyable {
public:
virtual util::ptr<const GeometryTileLayer> getLayer(const std::string&) const = 0;
virtual util::ptr<GeometryTileLayer> getLayer(const std::string&) const = 0;
};

class GeometryTileFeatureExtractor {
Expand Down
Loading

0 comments on commit d47b298

Please sign in to comment.