summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mbgl/map/map.hpp3
-rw-r--r--platform/ios/app/MBXAnnotationView.m4
-rw-r--r--platform/ios/app/MBXViewController.m5
-rw-r--r--platform/ios/src/MGLAnnotationView.mm114
-rw-r--r--platform/ios/src/MGLAnnotationView_Private.h4
-rw-r--r--platform/ios/src/MGLMapView.mm62
-rw-r--r--platform/ios/src/MGLMapView_Private.h2
-rw-r--r--src/mbgl/map/map.cpp4
8 files changed, 182 insertions, 16 deletions
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp
index 1b45c87c28..b9811733bc 100644
--- a/include/mbgl/map/map.hpp
+++ b/include/mbgl/map/map.hpp
@@ -30,6 +30,8 @@ class Image;
class Style;
} // namespace style
+using mat4 = std::array<double, 16>;
+
class Map : private util::noncopyable {
public:
explicit Map(Backend&,
@@ -139,6 +141,7 @@ public:
// Projection
ScreenCoordinate pixelForLatLng(const LatLng&) const;
LatLng latLngForPixel(const ScreenCoordinate&) const;
+ void getProjMatrix(mat4& matrix, uint16_t nearZ = 1) const;
// Annotations
void addAnnotationImage(std::unique_ptr<style::Image>);
diff --git a/platform/ios/app/MBXAnnotationView.m b/platform/ios/app/MBXAnnotationView.m
index 6877c5cd3d..a90a6cac7e 100644
--- a/platform/ios/app/MBXAnnotationView.m
+++ b/platform/ios/app/MBXAnnotationView.m
@@ -17,8 +17,8 @@
{
[super setSelected:selected animated:animated];
- self.layer.borderColor = selected ? [UIColor blackColor].CGColor : [UIColor whiteColor].CGColor;
- self.layer.borderWidth = selected ? 2.0 : 0;
+ self.layer.borderColor = selected ? [UIColor blackColor].CGColor : [UIColor blueColor].CGColor;
+ self.layer.borderWidth = selected ? 2.0 : 1.0;
}
- (void)setDragState:(MGLAnnotationViewDragState)dragState animated:(BOOL)animated
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index f7c20430d9..c62ef23230 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -1713,6 +1713,9 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
annotationView = [[MBXAnnotationView alloc] initWithReuseIdentifier:MBXViewControllerAnnotationViewReuseIdentifer];
annotationView.frame = CGRectMake(0, 0, 30, 30);
annotationView.backgroundColor = [UIColor whiteColor];
+ annotationView.layer.borderColor = [UIColor blueColor].CGColor;
+ annotationView.layer.borderWidth = 2;
+ annotationView.layer.cornerRadius = 4;
// Note that having two long press gesture recognizers on overlapping
// views (`self.view` & `annotationView`) will cause weird behaviour.
@@ -1731,7 +1734,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
// annotationView.scalesWithViewingDistance = NO;
} else {
// orange indicates that the annotation view was reused
- annotationView.backgroundColor = [UIColor orangeColor];
+ annotationView.layer.borderColor = [UIColor orangeColor].CGColor;
}
return annotationView;
}
diff --git a/platform/ios/src/MGLAnnotationView.mm b/platform/ios/src/MGLAnnotationView.mm
index 13edc444c6..7eed337702 100644
--- a/platform/ios/src/MGLAnnotationView.mm
+++ b/platform/ios/src/MGLAnnotationView.mm
@@ -5,8 +5,36 @@
#import "NSBundle+MGLAdditions.h"
+#import <GLKit/GLKit.h>
+
#include <mbgl/util/constants.hpp>
+CATransform3D MGLTransform3DFromMatrix4(GLKMatrix4 matrix) {
+ CATransform3D transform;
+
+ transform.m11 = matrix.m[0];
+ transform.m12 = matrix.m[1];
+ transform.m13 = matrix.m[2];
+ transform.m14 = matrix.m[3];
+
+ transform.m21 = matrix.m[4];
+ transform.m22 = matrix.m[5];
+ transform.m23 = matrix.m[6];
+ transform.m24 = matrix.m[7];
+
+ transform.m31 = matrix.m[8];
+ transform.m32 = matrix.m[9];
+ transform.m33 = matrix.m[10];
+ transform.m34 = matrix.m[11];
+
+ transform.m41 = matrix.m[12];
+ transform.m42 = matrix.m[13];
+ transform.m43 = matrix.m[14];
+ transform.m44 = matrix.m[15];
+
+ return transform;
+}
+
@interface MGLAnnotationView () <UIGestureRecognizerDelegate>
@property (nonatomic, readwrite, nullable) NSString *reuseIdentifier;
@@ -142,23 +170,85 @@
// We keep track of each viewing distance scale transform that we apply. Each iteration,
// we can account for it so that we don't get cumulative scaling every time we move.
// We also avoid clobbering any existing transform passed in by the client, too.
- CATransform3D undoOfLastScaleTransform = CATransform3DInvert(_lastAppliedTransform);
+ CATransform3D undoOfLastAppliedTransform = CATransform3DInvert(_lastAppliedTransform);
CATransform3D freeTransform = CATransform3DIdentity;
MGLMapCamera *camera = self.mapView.camera;
- if (camera.pitch >= 0 && (self.freeAxes & MGLAnnotationViewBillboardAxisX))
+// if (camera.pitch >= 0 && (self.freeAxes & MGLAnnotationViewBillboardAxisX))
{
+// freeTransform = self.mapView.projectionTransform;
+
+ CGRect superBounds = self.superview.bounds;
+
+ // Build a projection matrix, paralleling the code found in mbgl.
+ // mbgl::TransformState::fov
+ double fov = 0.6435011087932844;
+ double halfFov = fov / 2.0;
+ double cameraToCenterDistance = 0.5 * CGRectGetHeight(superBounds) / tanf(halfFov);
+
+ double groundAngle = M_PI_2 + MGLRadiansFromDegrees(camera.pitch);
+ double topHalfSurfaceDistance = sinf(halfFov) * cameraToCenterDistance / sinf(M_PI - groundAngle - halfFov);
+
+ // Calculate z distance of the farthest fragment that should be rendered.
+ double furthestDistance = cosf(M_PI_2 - MGLRadiansFromDegrees(camera.pitch)) * topHalfSurfaceDistance + cameraToCenterDistance;
+
+ // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance`.
+ double farZ = furthestDistance * 1.01;
+
+ GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(fov, CGRectGetWidth(superBounds) / CGRectGetHeight(superBounds), 1, farZ);
+ CATransform3D projectionTransform = MGLTransform3DFromMatrix4(projectionMatrix);
+// freeTransform = projectionTransform;
+// self.layer.sublayerTransform = projectionTransform;
+
+ // Unlike the Mapbox GL JS camera, separate camera translation and rotation out into its world matrix.
+ // If this is applied directly to the projection matrix, it will work OK but break raycasting.
+ GLKMatrix4 cameraTranslateZ = GLKMatrix4MakeTranslation(0, 0, -cameraToCenterDistance);
+ GLKMatrix4 cameraRotateX = GLKMatrix4MakeXRotation(MGLRadiansFromDegrees(camera.pitch));
+ GLKMatrix4 cameraWorldMatrix = GLKMatrix4Multiply(cameraRotateX, cameraTranslateZ);
+ GLKMatrix4 cameraRotateZ = GLKMatrix4MakeZRotation(-MGLRadiansFromDegrees(camera.heading));
+ cameraWorldMatrix = GLKMatrix4Multiply(cameraRotateZ, cameraWorldMatrix);
+
+// self.layer.sublayerTransform = MGLTransform3DFromMatrix4(cameraWorldMatrix);
+
+ double zoomPow = powf(2.0, self.mapView.zoomLevel);
+ double worldSize = mbgl::util::tileSize * zoomPow;
+ double x = (180 + camera.centerCoordinate.longitude) * worldSize / 360.0;
+ double y = MGLDegreesFromRadians(logf(tanf(M_PI_4 + camera.centerCoordinate.latitude * M_PI / 360.0)));
+ y = (180 - y) * worldSize / 360.0;
+
+ // Handle scaling and translation of objects in the map in the world's matrix transform, not the camera.
+ GLKMatrix4 rotateMap = GLKMatrix4MakeZRotation(M_PI);
+ GLKMatrix4 translateCenter = GLKMatrix4MakeTranslation(mbgl::util::tileSize / 2.0, -mbgl::util::tileSize / 2.0, 0);
+ GLKMatrix4 worldMatrix = GLKMatrix4Multiply(translateCenter, rotateMap);
+ GLKMatrix4 scale = GLKMatrix4MakeScale(zoomPow, zoomPow, zoomPow);
+ worldMatrix = GLKMatrix4Multiply(scale, worldMatrix);
+ GLKMatrix4 translateMap = GLKMatrix4MakeTranslation(-x, y, 0);
+ worldMatrix = GLKMatrix4Multiply(translateMap, worldMatrix);
+// freeTransform = MGLTransform3DFromMatrix4(worldMatrix);
+
+// bool isInvertible;
+// GLKMatrix4 inverseCameraWorldMatrix = GLKMatrix4Invert(cameraWorldMatrix, &isInvertible);
+// NSAssert(isInvertible, @"Camera world matrix should be invertible.");
+// GLKMatrix4 modelViewMatrix = GLKMatrix4Multiply(inverseCameraWorldMatrix, worldMatrix);
+// freeTransform = MGLTransform3DFromMatrix4(modelViewMatrix);
+
+
+
// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreAnimation_guide/AdvancedAnimationTricks/AdvancedAnimationTricks.html#//apple_ref/doc/uid/TP40004514-CH8-SW13
// FIXME: This is a rough, eyeballed value. Replace this transform with one derived from mbgl::TransformState::coordinatePointMatrix().
- CGRect superBounds = self.superview.bounds;
- freeTransform.m34 = -1.0 / (1000 - CGRectGetWidth(superBounds));
+ double xPoint = (180 + self.annotation.coordinate.longitude) * worldSize / 360.0;
+ double yPoint = MGLDegreesFromRadians(logf(tanf(M_PI_4 + self.annotation.coordinate.latitude * M_PI / 360.0)));
+ y = (180 - y) * worldSize / 360.0;
+ double xDelta = x - xPoint;
+ freeTransform.m34 = -1.0 / (1.0 - furthestDistance * 0.5);
- freeTransform = CATransform3DRotate(freeTransform, MGLRadiansFromDegrees(camera.pitch), 1.0, 0, 0);
- }
- if (camera.heading >= 0 && (self.freeAxes & MGLAnnotationViewBillboardAxisY))
- {
- freeTransform = CATransform3DRotate(freeTransform, MGLRadiansFromDegrees(-camera.heading), 0.0, 0.0, 1.0);
+ freeTransform = CATransform3DRotate(freeTransform, MGLRadiansFromDegrees(camera.pitch), -1.0, 0, 0);
+// self.layer.anchorPoint = [self convertPoint:self.superview.center toView:self];
}
+// if (camera.heading >= 0 && (self.freeAxes & MGLAnnotationViewBillboardAxisY))
+// {
+// freeTransform = CATransform3DRotate(freeTransform, MGLRadiansFromDegrees(-camera.heading), 0.0, 0.0, 1.0);
+// }
CATransform3D scaleTransform = CATransform3DIdentity;
CGFloat superviewHeight = CGRectGetHeight(self.superview.frame);
@@ -182,11 +272,11 @@
// map view is 50% pitched then the annotation view should be reduced by 37.5% (.75 * .5). The
// reduction is then normalized for a scale of 1.0.
CGFloat pitchAdjustedScale = 1.0 - maxScaleReduction * pitchIntensity;
- scaleTransform = CATransform3DMakeScale(pitchAdjustedScale, pitchAdjustedScale, 1);
+// scaleTransform = CATransform3DMakeScale(pitchAdjustedScale, pitchAdjustedScale, 1);
}
- CATransform3D effectiveTransform = CATransform3DConcat(freeTransform, scaleTransform);
- self.layer.transform = CATransform3DConcat(self.layer.transform, CATransform3DConcat(undoOfLastScaleTransform, effectiveTransform));
+ CATransform3D effectiveTransform = freeTransform;//CATransform3DConcat(freeTransform, scaleTransform);
+ self.layer.transform = CATransform3DConcat(self.layer.transform, CATransform3DConcat(undoOfLastAppliedTransform, effectiveTransform));
_lastAppliedTransform = effectiveTransform;
}
diff --git a/platform/ios/src/MGLAnnotationView_Private.h b/platform/ios/src/MGLAnnotationView_Private.h
index c4695051c5..40d7bc3bb9 100644
--- a/platform/ios/src/MGLAnnotationView_Private.h
+++ b/platform/ios/src/MGLAnnotationView_Private.h
@@ -1,10 +1,14 @@
#import "MGLAnnotationView.h"
#import "MGLAnnotation.h"
+#import <GLKit/GLKit.h>
+
NS_ASSUME_NONNULL_BEGIN
@class MGLMapView;
+CATransform3D MGLTransform3DFromMatrix4(GLKMatrix4 matrix);
+
@interface MGLAnnotationView (Private)
@property (nonatomic, readwrite, nullable) NSString *reuseIdentifier;
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 1444fc3cb0..72e471ac80 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -165,6 +165,32 @@ mbgl::util::UnitBezier MGLUnitBezierForMediaTimingFunction(CAMediaTimingFunction
return { p1[0], p1[1], p2[0], p2[1] };
}
+static CATransform3D MGLTransform3DFromMat4(mbgl::mat4 &matrix) {
+ CATransform3D transform;
+
+ transform.m11 = matrix[0];
+ transform.m12 = matrix[1];
+ transform.m13 = matrix[2];
+ transform.m14 = matrix[3];
+
+ transform.m21 = matrix[4];
+ transform.m22 = matrix[5];
+ transform.m23 = matrix[6];
+ transform.m24 = matrix[7];
+
+ transform.m31 = matrix[8];
+ transform.m32 = matrix[9];
+ transform.m33 = matrix[10];
+ transform.m34 = matrix[11];
+
+ transform.m41 = matrix[12];
+ transform.m42 = matrix[13];
+ transform.m43 = matrix[14];
+ transform.m44 = matrix[15];
+
+ return transform;
+}
+
@interface MGLAnnotationAccessibilityElement : UIAccessibilityElement
@property (nonatomic) MGLAnnotationTag tag;
@@ -3285,9 +3311,12 @@ public:
}
else
{
+// CGFloat side = mbgl::util::tileSize * powf(2.0, self.zoomLevel);
+// CGRect frame = CGRectMake(0, 0, side, side);
+// newAnnotationContainerView = [[MGLAnnotationContainerView alloc] initWithFrame:frame];
newAnnotationContainerView = [[MGLAnnotationContainerView alloc] initWithFrame:self.bounds];
}
- newAnnotationContainerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+// newAnnotationContainerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
newAnnotationContainerView.contentMode = UIViewContentModeCenter;
[newAnnotationContainerView addSubviews:annotationViews];
[_glView insertSubview:newAnnotationContainerView atIndex:0];
@@ -5001,6 +5030,31 @@ public:
NSArray *visibleAnnotations = [self visibleAnnotationsInRect:viewPort];
NSMutableArray *offscreenAnnotations = [self.annotations mutableCopy];
[offscreenAnnotations removeObjectsInArray:visibleAnnotations];
+
+ MGLMapCamera *camera = self.camera;
+
+ // Build a projection matrix, paralleling the code found in mbgl.
+ // mbgl::TransformState::fov
+ double fov = 0.6435011087932844;
+ double halfFov = fov / 2.0;
+ double cameraToCenterDistance = 0.5 * CGRectGetHeight(self.bounds) / tanf(halfFov);
+
+ double groundAngle = M_PI_2 + MGLRadiansFromDegrees(camera.pitch);
+ double topHalfSurfaceDistance = sinf(halfFov) * cameraToCenterDistance / sinf(M_PI - groundAngle - halfFov);
+
+ // Calculate z distance of the farthest fragment that should be rendered.
+ double furthestDistance = cosf(M_PI_2 - MGLRadiansFromDegrees(camera.pitch)) * topHalfSurfaceDistance + cameraToCenterDistance;
+
+ // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance`.
+ double farZ = furthestDistance * 1.01;
+
+ GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(fov, CGRectGetWidth(self.bounds) / CGRectGetHeight(self.bounds), 1, farZ);
+// CATransform3D projectionTransform = MGLTransform3DFromMatrix4(projectionMatrix);
+
+ CATransform3D projectionTransform = CATransform3DIdentity;
+ projectionTransform.m34 = -1.0 / (1.0 - furthestDistance * 0.5);
+ projectionTransform = CATransform3DRotate(projectionTransform, MGLRadiansFromDegrees(camera.pitch), -1, 0, 0);
+// self.annotationContainerView.layer.sublayerTransform = projectionTransform;
// Update the center of visible annotation views
for (id<MGLAnnotation> annotation in visibleAnnotations)
@@ -5086,6 +5140,12 @@ public:
[CATransaction commit];
}
+- (CATransform3D)projectionTransform {
+ mbgl::mat4 matrix;
+ _mbglMap->getProjMatrix(matrix);
+ return MGLTransform3DFromMat4(matrix);
+}
+
- (void)updateCalloutView
{
UIView <MGLCalloutView> *calloutView = self.calloutViewForSelectedAnnotation;
diff --git a/platform/ios/src/MGLMapView_Private.h b/platform/ios/src/MGLMapView_Private.h
index 4e2765377c..a273b8b3a3 100644
--- a/platform/ios/src/MGLMapView_Private.h
+++ b/platform/ios/src/MGLMapView_Private.h
@@ -17,6 +17,8 @@ extern const CGSize MGLAnnotationAccessibilityElementMinimumSize;
- (mbgl::Map *)mbglMap;
+- (CATransform3D)projectionTransform;
+
/** Returns whether the map view is currently loading or processing any assets required to render the map */
- (BOOL)isFullyLoaded;
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 034e43f260..8d4b40530c 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -699,6 +699,10 @@ LatLng Map::latLngForPixel(const ScreenCoordinate& pixel) const {
return impl->transform.screenCoordinateToLatLng(pixel);
}
+void Map::getProjMatrix(mat4& matrix, uint16_t nearZ) const {
+ impl->transform.getState().getProjMatrix(matrix, nearZ);
+}
+
#pragma mark - Annotations
void Map::addAnnotationImage(std::unique_ptr<style::Image> image) {