summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Guerra Soto <fabian.guerra@mapbox.com>2017-10-18 15:18:54 -0400
committerGitHub <noreply@github.com>2017-10-18 15:18:54 -0400
commitb7b8baef9d30d31a757dbbc0fbb8cb2c5cf3585e (patch)
treebd25ec804666cb22a7583a27e63e95c5bd65eef3
parent24fc48982a635578db3f2262b9f56a27c53688cb (diff)
downloadqtlocation-mapboxgl-b7b8baef9d30d31a757dbbc0fbb8cb2c5cf3585e.tar.gz
[ios, macos] Add selection support to MGLMultiPoint annotations. (#9984)
* [ios, macos] Add selection support to MGLMultiPoint annotations. * [ios, macos] Update changelogs.
-rw-r--r--include/mbgl/renderer/renderer.hpp2
-rw-r--r--platform/ios/CHANGELOG.md1
-rw-r--r--platform/ios/app/MBXViewController.m1
-rw-r--r--platform/ios/src/MGLMapView.mm107
-rw-r--r--platform/macos/CHANGELOG.md1
-rw-r--r--platform/macos/src/MGLMapView.mm75
-rw-r--r--src/mbgl/annotation/annotation_manager.cpp1
-rw-r--r--src/mbgl/annotation/annotation_manager.hpp1
-rw-r--r--src/mbgl/annotation/shape_annotation_impl.cpp3
-rw-r--r--src/mbgl/renderer/renderer.cpp15
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp19
-rw-r--r--src/mbgl/renderer/renderer_impl.hpp3
12 files changed, 165 insertions, 64 deletions
diff --git a/include/mbgl/renderer/renderer.hpp b/include/mbgl/renderer/renderer.hpp
index be8abb2c29..23d2451a2e 100644
--- a/include/mbgl/renderer/renderer.hpp
+++ b/include/mbgl/renderer/renderer.hpp
@@ -40,6 +40,8 @@ public:
std::vector<Feature> queryRenderedFeatures(const ScreenBox& box, const RenderedQueryOptions& options = {}) const;
std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options = {}) const;
AnnotationIDs queryPointAnnotations(const ScreenBox& box) const;
+ AnnotationIDs queryShapeAnnotations(const ScreenBox& box) const;
+ AnnotationIDs getAnnotationIDs(const std::vector<Feature>&) const;
// Debug
void dumpDebugLogs();
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 82de619d7b..3dd46f3e93 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -30,6 +30,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Added an `overlays` property to `MGLMapView`. ([#8617](https://github.com/mapbox/mapbox-gl-native/pull/8617))
* Selecting an annotation no longer sets the user tracking mode to `MGLUserTrackingModeNone`. ([#10094](https://github.com/mapbox/mapbox-gl-native/pull/10094))
* Added `-[MGLMapView cameraThatFitsShape:direction:edgePadding:]` to get a camera with zoom level and center coordinate computed to fit a shape. ([#10107](https://github.com/mapbox/mapbox-gl-native/pull/10107))
+* Added support selection of shape and polyline annotations.([#9984](https://github.com/mapbox/mapbox-gl-native/pull/9984))
### Other changes
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index 07838bc6bd..5bccb64608 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -827,6 +827,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
}
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:polygonCoordinates count:[stateCoordinatePairs count]];
+ polygon.title = feature[@"properties"][@"NAME"];
[self.mapView addAnnotation:polygon];
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index ac608dd074..4112df6e76 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -3257,6 +3257,12 @@ public:
}
std::vector<MGLAnnotationTag> annotationTags = [self annotationTagsInRect:rect];
+ std::vector<MGLAnnotationTag> shapeAnnotationTags = [self shapeAnnotationTagsInRect:rect];
+
+ if (shapeAnnotationTags.size()) {
+ annotationTags.insert(annotationTags.end(), shapeAnnotationTags.begin(), shapeAnnotationTags.end());
+ }
+
if (annotationTags.size())
{
NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:annotationTags.size()];
@@ -3762,6 +3768,12 @@ public:
queryRect = CGRectInset(queryRect, -MGLAnnotationImagePaddingForHitTest,
-MGLAnnotationImagePaddingForHitTest);
std::vector<MGLAnnotationTag> nearbyAnnotations = [self annotationTagsInRect:queryRect];
+ BOOL queryingShapeAnnotations = NO;
+
+ if (!nearbyAnnotations.size()) {
+ nearbyAnnotations = [self shapeAnnotationTagsInRect:queryRect];
+ queryingShapeAnnotations = YES;
+ }
if (nearbyAnnotations.size())
{
@@ -3769,54 +3781,56 @@ public:
CGRect hitRect = CGRectInset({ point, CGSizeZero },
-MGLAnnotationImagePaddingForHitTest,
-MGLAnnotationImagePaddingForHitTest);
-
- // Filter out any annotation whose image or view is unselectable or for which
- // hit testing fails.
- auto end = std::remove_if(nearbyAnnotations.begin(), nearbyAnnotations.end(),
- [&](const MGLAnnotationTag annotationTag)
- {
- id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag];
- NSAssert(annotation, @"Unknown annotation found nearby tap");
- if ( ! annotation)
- {
- return true;
- }
-
- MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
- CGRect annotationRect;
-
- MGLAnnotationView *annotationView = annotationContext.annotationView;
- if (annotationView)
- {
- if ( ! annotationView.enabled)
+
+ if (!queryingShapeAnnotations) {
+ // Filter out any annotation whose image or view is unselectable or for which
+ // hit testing fails.
+ auto end = std::remove_if(nearbyAnnotations.begin(), nearbyAnnotations.end(), [&](const MGLAnnotationTag annotationTag) {
+ id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag];
+ NSAssert(annotation, @"Unknown annotation found nearby tap");
+ if ( ! annotation)
{
return true;
}
- CGPoint calloutAnchorPoint = [self convertCoordinate:annotation.coordinate toPointToView:self];
- CGRect frame = CGRectInset({ calloutAnchorPoint, CGSizeZero }, -CGRectGetWidth(annotationView.frame) / 2, -CGRectGetHeight(annotationView.frame) / 2);
- annotationRect = UIEdgeInsetsInsetRect(frame, annotationView.alignmentRectInsets);
- }
- else
- {
- MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
- if ( ! annotationImage.enabled)
+ MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
+ CGRect annotationRect;
+
+ MGLAnnotationView *annotationView = annotationContext.annotationView;
+
+ if (annotationView)
{
- return true;
+ if ( ! annotationView.enabled)
+ {
+ return true;
+ }
+
+ CGPoint calloutAnchorPoint = [self convertCoordinate:annotation.coordinate toPointToView:self];
+ CGRect frame = CGRectInset({ calloutAnchorPoint, CGSizeZero }, -CGRectGetWidth(annotationView.frame) / 2, -CGRectGetHeight(annotationView.frame) / 2);
+ annotationRect = UIEdgeInsetsInsetRect(frame, annotationView.alignmentRectInsets);
}
+ else
+ {
+ MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
+ if ( ! annotationImage.enabled)
+ {
+ return true;
+ }
- MGLAnnotationImage *fallbackAnnotationImage = [self dequeueReusableAnnotationImageWithIdentifier:MGLDefaultStyleMarkerSymbolName];
- UIImage *fallbackImage = fallbackAnnotationImage.image;
+ MGLAnnotationImage *fallbackAnnotationImage = [self dequeueReusableAnnotationImageWithIdentifier:MGLDefaultStyleMarkerSymbolName];
+ UIImage *fallbackImage = fallbackAnnotationImage.image;
- annotationRect = [self frameOfImage:annotationImage.image ?: fallbackImage centeredAtCoordinate:annotation.coordinate];
- }
+ annotationRect = [self frameOfImage:annotationImage.image ?: fallbackImage centeredAtCoordinate:annotation.coordinate];
+ }
- // Filter out the annotation if the fattened finger didn’t land
- // within the image’s alignment rect.
- return !!!CGRectIntersectsRect(annotationRect, hitRect);
- });
+ // Filter out the annotation if the fattened finger didn’t land
+ // within the image’s alignment rect.
+ return !!!CGRectIntersectsRect(annotationRect, hitRect);
+ });
+
+ nearbyAnnotations.resize(std::distance(nearbyAnnotations.begin(), end));
+ }
- nearbyAnnotations.resize(std::distance(nearbyAnnotations.begin(), end));
}
MGLAnnotationTag hitAnnotationTag = MGLAnnotationTagNotFound;
@@ -3899,6 +3913,14 @@ public:
});
}
+- (std::vector<MGLAnnotationTag>)shapeAnnotationTagsInRect:(CGRect)rect
+{
+ return _rendererFrontend->getRenderer()->queryShapeAnnotations({
+ { CGRectGetMinX(rect), CGRectGetMinY(rect) },
+ { CGRectGetMaxX(rect), CGRectGetMaxY(rect) },
+ });
+}
+
- (id <MGLAnnotation>)selectedAnnotation
{
if (_userLocationAnnotationIsSelected)
@@ -3950,8 +3972,6 @@ public:
{
if ( ! annotation) return;
- if ([annotation isKindOfClass:[MGLMultiPoint class]]) return;
-
if (annotation == self.selectedAnnotation) return;
[self deselectAnnotation:self.selectedAnnotation animated:NO];
@@ -4095,6 +4115,13 @@ public:
{
return CGRectZero;
}
+
+ if ([annotation isKindOfClass:[MGLMultiPoint class]]) {
+ CLLocationCoordinate2D origin = annotation.coordinate;
+ CGPoint originPoint = [self convertCoordinate:origin toPointToView:self];
+ return CGRectMake(originPoint.x, originPoint.y, MGLAnnotationImagePaddingForHitTest, MGLAnnotationImagePaddingForHitTest);
+
+ }
UIImage *image = [self imageOfAnnotationWithTag:annotationTag].image;
if ( ! image)
{
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index 31b3540a7c..4b3292c600 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -27,6 +27,7 @@
* Increased the default maximum zoom level from 20 to 22. ([#9835](https://github.com/mapbox/mapbox-gl-native/pull/9835))
* Added an `overlays` property to `MGLMapView`. ([#8617](https://github.com/mapbox/mapbox-gl-native/pull/8617))
* Added `-[MGLMapView cameraThatFitsShape:direction:edgePadding:]` to get a camera with zoom level and center coordinate computed to fit a shape. ([#10107](https://github.com/mapbox/mapbox-gl-native/pull/10107))
+* Added support selection of shape and polyline annotations.([#9984](https://github.com/mapbox/mapbox-gl-native/pull/9984))
### Other changes
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index 0aa5bdc9db..af8ddbbe11 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -1791,6 +1791,12 @@ public:
}
std::vector<MGLAnnotationTag> annotationTags = [self annotationTagsInRect:rect];
+ std::vector<MGLAnnotationTag> shapeAnnotationTags = [self shapeAnnotationTagsInRect:rect];
+
+ if (shapeAnnotationTags.size()) {
+ annotationTags.insert(annotationTags.end(), shapeAnnotationTags.begin(), shapeAnnotationTags.end());
+ }
+
if (annotationTags.size())
{
NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:annotationTags.size()];
@@ -2050,35 +2056,43 @@ public:
queryRect = NSInsetRect(queryRect, -MGLAnnotationImagePaddingForHitTest,
-MGLAnnotationImagePaddingForHitTest);
std::vector<MGLAnnotationTag> nearbyAnnotations = [self annotationTagsInRect:queryRect];
+ BOOL queryingShapeAnnotations = NO;
+
+ if (!nearbyAnnotations.size()) {
+ nearbyAnnotations = [self shapeAnnotationTagsInRect:queryRect];
+ queryingShapeAnnotations = YES;
+ }
if (nearbyAnnotations.size()) {
// Assume that the user is fat-fingering an annotation.
NSRect hitRect = NSInsetRect({ point, NSZeroSize },
-MGLAnnotationImagePaddingForHitTest,
-MGLAnnotationImagePaddingForHitTest);
-
- // Filter out any annotation whose image is unselectable or for which
- // hit testing fails.
- auto end = std::remove_if(nearbyAnnotations.begin(), nearbyAnnotations.end(), [&](const MGLAnnotationTag annotationTag) {
- id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag];
- NSAssert(annotation, @"Unknown annotation found nearby click");
- if (!annotation) {
- return true;
- }
-
- MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
- if (!annotationImage.selectable) {
- return true;
- }
-
- // Filter out the annotation if the fattened finger didn’t land on a
- // translucent or opaque pixel in the image.
- NSRect annotationRect = [self frameOfImage:annotationImage.image
- centeredAtCoordinate:annotation.coordinate];
- return !!![annotationImage.image hitTestRect:hitRect withImageDestinationRect:annotationRect
- context:nil hints:nil flipped:NO];
- });
- nearbyAnnotations.resize(std::distance(nearbyAnnotations.begin(), end));
+
+ if (!queryingShapeAnnotations) {
+ // Filter out any annotation whose image is unselectable or for which
+ // hit testing fails.
+ auto end = std::remove_if(nearbyAnnotations.begin(), nearbyAnnotations.end(), [&](const MGLAnnotationTag annotationTag) {
+ id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag];
+ NSAssert(annotation, @"Unknown annotation found nearby click");
+ if (!annotation) {
+ return true;
+ }
+
+ MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
+ if (!annotationImage.selectable) {
+ return true;
+ }
+
+ // Filter out the annotation if the fattened finger didn’t land on a
+ // translucent or opaque pixel in the image.
+ NSRect annotationRect = [self frameOfImage:annotationImage.image
+ centeredAtCoordinate:annotation.coordinate];
+ return !!![annotationImage.image hitTestRect:hitRect withImageDestinationRect:annotationRect
+ context:nil hints:nil flipped:NO];
+ });
+ nearbyAnnotations.resize(std::distance(nearbyAnnotations.begin(), end));
+ }
}
MGLAnnotationTag hitAnnotationTag = MGLAnnotationTagNotFound;
@@ -2149,6 +2163,14 @@ public:
});
}
+- (std::vector<MGLAnnotationTag>)shapeAnnotationTagsInRect:(NSRect)rect {
+ // Cocoa origin is at the lower-left corner.
+ return _rendererFrontend->getRenderer()->queryShapeAnnotations({
+ { NSMinX(rect), NSHeight(self.bounds) - NSMaxY(rect) },
+ { NSMaxX(rect), NSHeight(self.bounds) - NSMinY(rect) },
+ });
+}
+
- (id <MGLAnnotation>)selectedAnnotation {
if ( ! _annotationContextsByAnnotationTag.count(_selectedAnnotationTag) ||
_selectedAnnotationTag == MGLAnnotationTagNotFound) {
@@ -2314,6 +2336,13 @@ public:
if (!annotation) {
return NSZeroRect;
}
+ if ([annotation isKindOfClass:[MGLMultiPoint class]]) {
+ CLLocationCoordinate2D origin = annotation.coordinate;
+ CGPoint originPoint = [self convertCoordinate:origin toPointToView:self];
+ return CGRectMake(originPoint.x, originPoint.y, MGLAnnotationImagePaddingForHitTest, MGLAnnotationImagePaddingForHitTest);
+
+ }
+
NSImage *image = [self imageOfAnnotationWithTag:annotationTag].image;
if (!image) {
image = [self dequeueReusableAnnotationImageWithIdentifier:MGLDefaultStyleMarkerSymbolName].image;
diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp
index 1f2d01e9eb..a4d53bbd3f 100644
--- a/src/mbgl/annotation/annotation_manager.cpp
+++ b/src/mbgl/annotation/annotation_manager.cpp
@@ -18,6 +18,7 @@ using namespace style;
const std::string AnnotationManager::SourceID = "com.mapbox.annotations";
const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points";
+const std::string AnnotationManager::ShapeLayerID = "com.mapbox.annotations.shape.";
AnnotationManager::AnnotationManager(Style& style_)
: style(style_) {
diff --git a/src/mbgl/annotation/annotation_manager.hpp b/src/mbgl/annotation/annotation_manager.hpp
index a028a8f1ba..22b25cd2ac 100644
--- a/src/mbgl/annotation/annotation_manager.hpp
+++ b/src/mbgl/annotation/annotation_manager.hpp
@@ -46,6 +46,7 @@ public:
static const std::string SourceID;
static const std::string PointLayerID;
+ static const std::string ShapeLayerID;
private:
void add(const AnnotationID&, const SymbolAnnotation&, const uint8_t);
diff --git a/src/mbgl/annotation/shape_annotation_impl.cpp b/src/mbgl/annotation/shape_annotation_impl.cpp
index 0c1a631ad8..9288159b6a 100644
--- a/src/mbgl/annotation/shape_annotation_impl.cpp
+++ b/src/mbgl/annotation/shape_annotation_impl.cpp
@@ -1,5 +1,6 @@
#include <mbgl/annotation/shape_annotation_impl.hpp>
#include <mbgl/annotation/annotation_tile.hpp>
+#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/math/wrap.hpp>
#include <mbgl/math/clamp.hpp>
@@ -15,7 +16,7 @@ namespace geojsonvt = mapbox::geojsonvt;
ShapeAnnotationImpl::ShapeAnnotationImpl(const AnnotationID id_, const uint8_t maxZoom_)
: id(id_),
maxZoom(maxZoom_),
- layerID("com.mapbox.annotations.shape." + util::toString(id)) {
+ layerID(AnnotationManager::ShapeLayerID + util::toString(id)) {
}
void ShapeAnnotationImpl::updateTileData(const CanonicalTileID& tileID, AnnotationTileData& data) {
diff --git a/src/mbgl/renderer/renderer.cpp b/src/mbgl/renderer/renderer.cpp
index e915f5e146..8953b419f7 100644
--- a/src/mbgl/renderer/renderer.cpp
+++ b/src/mbgl/renderer/renderer.cpp
@@ -57,6 +57,21 @@ AnnotationIDs Renderer::queryPointAnnotations(const ScreenBox& box) const {
RenderedQueryOptions options;
options.layerIDs = {{ AnnotationManager::PointLayerID }};
auto features = queryRenderedFeatures(box, options);
+ return getAnnotationIDs(features);
+}
+
+AnnotationIDs Renderer::queryShapeAnnotations(const ScreenBox& box) const {
+ auto features = impl->queryShapeAnnotations({
+ box.min,
+ {box.max.x, box.min.y},
+ box.max,
+ {box.min.x, box.max.y},
+ box.min
+ });
+ return getAnnotationIDs(features);
+}
+
+AnnotationIDs Renderer::getAnnotationIDs(const std::vector<Feature>& features) const {
std::set<AnnotationID> set;
for (auto &feature : features) {
assert(feature.id);
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index 6a8c18792e..7339756e52 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -629,6 +629,10 @@ std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineStrin
}
}
+ return queryRenderedFeatures(geometry, options, layers);
+}
+
+std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options, const std::vector<const RenderLayer*>& layers) const {
std::unordered_set<std::string> sourceIDs;
for (const RenderLayer* layer : layers) {
sourceIDs.emplace(layer->baseImpl->source);
@@ -663,6 +667,21 @@ std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineStrin
return result;
}
+std::vector<Feature> Renderer::Impl::queryShapeAnnotations(const ScreenLineString& geometry) const {
+ std::vector<const RenderLayer*> shapeAnnotationLayers;
+ RenderedQueryOptions options;
+ for (const auto& layerImpl : *layerImpls) {
+ if (std::mismatch(layerImpl->id.begin(), layerImpl->id.end(),
+ AnnotationManager::ShapeLayerID.begin(), AnnotationManager::ShapeLayerID.end()).second == AnnotationManager::ShapeLayerID.end()) {
+ if (const RenderLayer* layer = getRenderLayer(layerImpl->id)) {
+ shapeAnnotationLayers.emplace_back(layer);
+ }
+ }
+ }
+
+ return queryRenderedFeatures(geometry, options, shapeAnnotationLayers);
+}
+
std::vector<Feature> Renderer::Impl::querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options) const {
const RenderSource* source = getRenderSource(sourceID);
if (!source) return {};
diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp
index 30e7f70722..db2a6e7a74 100644
--- a/src/mbgl/renderer/renderer_impl.hpp
+++ b/src/mbgl/renderer/renderer_impl.hpp
@@ -49,6 +49,7 @@ public:
std::vector<Feature> queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&) const;
std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const;
+ std::vector<Feature> queryShapeAnnotations(const ScreenLineString&) const;
void onLowMemory();
void dumDebugLogs();
@@ -61,6 +62,8 @@ private:
RenderLayer* getRenderLayer(const std::string& id);
const RenderLayer* getRenderLayer(const std::string& id) const;
+
+ std::vector<Feature> queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&, const std::vector<const RenderLayer*>&) const;
// GlyphManagerObserver implementation.
void onGlyphsError(const FontStack&, const GlyphRange&, std::exception_ptr) override;