summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2017-06-23 12:17:31 -0700
committerMinh Nguyễn <mxn@1ec5.org>2017-07-05 18:32:59 -0700
commit3d255176c549f96a17d05c8e5240067f7c2ad0f4 (patch)
tree1bc2f94c195749fddd0497a82614c5ed7727f8d5
parentf35b8703268cb09d5a48fa56a94b87564e8064db (diff)
downloadqtlocation-mapboxgl-3d255176c549f96a17d05c8e5240067f7c2ad0f4.tar.gz
[ios] Lots of experiments
The transform matrix is correct, but applying it to the annotation container view incorrectly translates each annotation view, and applying it to each annotation view individually causes an incorrect anchor point to be used.
-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) {