From 71bfaec131d05ef360279cee83f5014febcd3d52 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 7 Sep 2015 14:43:26 -0700 Subject: [PATCH 01/18] bump podspec for ios-v2.1.0-pre.3 --- ios/Mapbox-iOS-SDK.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Mapbox-iOS-SDK.podspec b/ios/Mapbox-iOS-SDK.podspec index 099a84c8a..449d4ce1d 100644 --- a/ios/Mapbox-iOS-SDK.podspec +++ b/ios/Mapbox-iOS-SDK.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |m| m.name = 'Mapbox-iOS-SDK' - m.version = '2.0.0-symbols' + m.version = '2.1.0-pre.3-symbols' m.summary = 'Open source vector map solution for iOS with full styling capabilities.' m.description = 'Open source OpenGL-based vector map solution for iOS with full styling capabilities and Cocoa bindings.' From 72b75fab983f8b4064ffc22951dac0fbc8bbd87a Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 7 Sep 2015 14:44:02 -0700 Subject: [PATCH 02/18] [publish ios-v2.1.0-pre.3] From b29ef4011ef7f92af84d207aa5b005b8bb5c12e2 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 7 Sep 2015 14:45:11 -0700 Subject: [PATCH 03/18] fix typo in iOS script --- scripts/ios/publish.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ios/publish.sh b/scripts/ios/publish.sh index 61270fb45..c914fcacc 100755 --- a/scripts/ios/publish.sh +++ b/scripts/ios/publish.sh @@ -6,7 +6,7 @@ set -u # # iOS release tag format is `vX.Y.Z`; `X.Y.Z` gets passed in -# In the case of symbolicated builds, we also append the `style`. +# In the case of symbolicated builds, we also append the `-symbols`. # PUBLISH_VERSION="$1" From a9ef04e2189f2fc9947cb54c71732760e5c8e0db Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 7 Sep 2015 14:44:02 -0700 Subject: [PATCH 04/18] [publish ios-v2.1.0-pre.3] From 7127cfebb5949e2bdb4ef86f8c192c7bdc04caed Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Tue, 8 Sep 2015 11:43:55 -0400 Subject: [PATCH 05/18] Fix build, only ask for location permission on user's instigation Previously in #2265 we would ask for location permission at app startup if `!settings->showsUserLocation`. #2193 0a172a21fdc2a87473560fd7d45f4d495d95de91 changed the way we used `NSUserDefaults` and mostly removed the `settings` object, which broke #2265. Rather than fix our pestering location permissions ask at startup, this commit now only asks for location permissions when the user hits the locate-me button. Once a user grants permission, the user dot appears because a `userTrackingMode` is set, `showsUserLocation` is permanently set to `YES` in `NSUserDefaults` and is restored at launch. --- ios/app/MBXViewController.mm | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ios/app/MBXViewController.mm b/ios/app/MBXViewController.mm index b32371770..d94e41b5f 100644 --- a/ios/app/MBXViewController.mm +++ b/ios/app/MBXViewController.mm @@ -83,13 +83,6 @@ static NSUInteger const kStyleVersion = 8; action:@selector(locateUser)]; [self restoreState:nil]; - - if ( ! settings->showsUserLocation) - { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - self.mapView.showsUserLocation = YES; - }); - } } - (void)saveState:(__unused NSNotification *)notification From db28ef37dbabd3e8f53289e843def4a3a68cdf06 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 8 Sep 2015 18:03:10 -0700 Subject: [PATCH 06/18] fixes #1675: abstract annotation tile refresh check/render; trigger post-sprite/sprite store load --- src/mbgl/map/annotation.hpp | 1 + src/mbgl/map/map_context.cpp | 10 ++++++++-- src/mbgl/map/map_context.hpp | 2 ++ src/mbgl/style/style.cpp | 4 ++++ src/mbgl/style/style.hpp | 1 + test/style/resource_loading.cpp | 4 ++++ 6 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/mbgl/map/annotation.hpp b/src/mbgl/map/annotation.hpp index 745fc779c..5adec162f 100644 --- a/src/mbgl/map/annotation.hpp +++ b/src/mbgl/map/annotation.hpp @@ -52,6 +52,7 @@ public: ~AnnotationManager(); void markStaleTiles(std::unordered_set); + size_t getStaleTileCount() const { return staleTiles.size(); } std::unordered_set resetStaleTiles(); void setDefaultPointAnnotationSymbol(const std::string& symbol); diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 94aedb46d..0ebcd73f8 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -142,9 +142,11 @@ void MapContext::loadStyleJSON(const std::string& json, const std::string& base) updateFlags |= Update::DefaultTransition | Update::Classes | Update::Zoom; asyncUpdate->send(); +} - auto staleTiles = data.getAnnotationManager()->resetStaleTiles(); - if (!staleTiles.empty()) { +void MapContext::updateAnnotationTilesIfNeeded() { + if (data.getAnnotationManager()->getStaleTileCount()) { + auto staleTiles = data.getAnnotationManager()->resetStaleTiles(); updateAnnotationTiles(staleTiles); } } @@ -417,4 +419,8 @@ void MapContext::onResourceLoadingFailed(std::exception_ptr error) { } } +void MapContext::onSpriteStoreLoaded() { + updateAnnotationTilesIfNeeded(); +} + } diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp index f1bfb01e4..449a0f1d1 100644 --- a/src/mbgl/map/map_context.hpp +++ b/src/mbgl/map/map_context.hpp @@ -54,6 +54,7 @@ public: bool isLoaded() const; double getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol); + void updateAnnotationTilesIfNeeded(); void updateAnnotationTiles(const std::unordered_set&); void setSourceTileCacheSize(size_t size); @@ -66,6 +67,7 @@ public: // Style::Observer implementation. void onTileDataChanged() override; void onResourceLoadingFailed(std::exception_ptr error) override; + void onSpriteStoreLoaded() override; private: // Update the state indicated by the accumulated Update flags, then render. diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index 768621530..d4c9bd4e5 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -190,6 +190,10 @@ void Style::onSpriteLoaded(const Sprites& sprites) { // Add all sprite images to the SpriteStore object spriteStore->setSprites(sprites); + if (observer) { + observer->onSpriteStoreLoaded(); + } + shouldReparsePartialTiles = true; emitTileDataChanged(); } diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index cbc0ee2db..3f9696ffb 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -39,6 +39,7 @@ public: virtual ~Observer() = default; virtual void onTileDataChanged() = 0; + virtual void onSpriteStoreLoaded() = 0; virtual void onResourceLoadingFailed(std::exception_ptr error) = 0; }; diff --git a/test/style/resource_loading.cpp b/test/style/resource_loading.cpp index 056243458..5ed09065a 100644 --- a/test/style/resource_loading.cpp +++ b/test/style/resource_loading.cpp @@ -63,6 +63,10 @@ public: callback_(error); } + void onSpriteStoreLoaded() override { + // no-op + } + private: MapData data_; Transform transform_; From 182bd9723e4b13161a2139db4c33f124a95d9c4b Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Tue, 1 Sep 2015 23:30:54 -0400 Subject: [PATCH 07/18] [iOS] Initial user location puck --- platform/ios/MGLUserLocationAnnotationView.m | 480 ++++++++++++------- 1 file changed, 296 insertions(+), 184 deletions(-) diff --git a/platform/ios/MGLUserLocationAnnotationView.m b/platform/ios/MGLUserLocationAnnotationView.m index 7733674e6..301e3c4b2 100644 --- a/platform/ios/MGLUserLocationAnnotationView.m +++ b/platform/ios/MGLUserLocationAnnotationView.m @@ -8,6 +8,9 @@ const CGFloat MGLUserLocationAnnotationDotSize = 22.0; const CGFloat MGLUserLocationAnnotationHaloSize = 115.0; +const CGFloat MGLUserLocationAnnotationPuckSize = 35.0; +const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuckSize * 0.6; + @interface MGLUserLocationAnnotationView () @property (nonatomic, readwrite) CALayer *haloLayer; @@ -18,12 +21,17 @@ const CGFloat MGLUserLocationAnnotationHaloSize = 115.0; @implementation MGLUserLocationAnnotationView { + BOOL _puckModeActivated; + + CALayer *_puckDot; + CAShapeLayer *_puckArrow; + CALayer *_headingIndicatorLayer; CAShapeLayer *_headingIndicatorMaskLayer; CALayer *_accuracyRingLayer; CALayer *_dotBorderLayer; CALayer *_dotLayer; - + double _oldHeadingAccuracy; CLLocationAccuracy _oldHorizontalAccuracy; double _oldZoom; @@ -37,7 +45,9 @@ const CGFloat MGLUserLocationAnnotationHaloSize = 115.0; - (instancetype)initInMapView:(MGLMapView *)mapView { - if (self = [super initWithFrame:CGRectMake(0, 0, MGLUserLocationAnnotationDotSize, MGLUserLocationAnnotationDotSize)]) + CGFloat frameSize = (mapView.userTrackingMode == MGLUserTrackingModeFollowWithCourse) ? MGLUserLocationAnnotationPuckSize : MGLUserLocationAnnotationDotSize; + + if (self = [super initWithFrame:CGRectMake(0, 0, frameSize, frameSize)]) { self.annotation = [[MGLUserLocation alloc] initWithMapView:mapView]; _mapView = mapView; @@ -55,189 +65,291 @@ const CGFloat MGLUserLocationAnnotationHaloSize = 115.0; - (void)setTintColor:(UIColor *)tintColor { - if (_accuracyRingLayer) + if (_puckModeActivated) { - _accuracyRingLayer.backgroundColor = [tintColor CGColor]; + _puckArrow.fillColor = [tintColor CGColor]; + } + else + { + if (_accuracyRingLayer) + { + _accuracyRingLayer.backgroundColor = [tintColor CGColor]; + } + + _haloLayer.backgroundColor = [tintColor CGColor]; + _dotLayer.backgroundColor = [tintColor CGColor]; + + _headingIndicatorLayer.contents = (__bridge id)[[self headingIndicatorTintedGradientImage] CGImage]; } - - _haloLayer.backgroundColor = [tintColor CGColor]; - _dotLayer.backgroundColor = [tintColor CGColor]; - - _headingIndicatorLayer.contents = (__bridge id)[[self headingIndicatorTintedGradientImage] CGImage]; } - (void)setupLayers { if (CLLocationCoordinate2DIsValid(self.annotation.coordinate)) { - // update heading indicator - // - if (_headingIndicatorLayer) - { - _headingIndicatorLayer.hidden = !(_mapView.userTrackingMode == MGLUserTrackingModeFollowWithHeading || - _mapView.userTrackingMode == MGLUserTrackingModeFollowWithCourse); - - if (_oldHeadingAccuracy != self.annotation.heading.headingAccuracy) - { - // recalculate the clipping mask based on updated accuracy - _headingIndicatorMaskLayer.path = [[self headingIndicatorClippingMask] CGPath]; + (_mapView.userTrackingMode == MGLUserTrackingModeFollowWithCourse) ? [self drawPuck] : [self drawDot]; + } +} - _oldHeadingAccuracy = self.annotation.heading.headingAccuracy; - } - } - - // heading indicator (tinted, semi-circle) - // - if ( ! _headingIndicatorLayer && self.annotation.heading.headingAccuracy) +- (void)drawPuck +{ + if ( ! _puckModeActivated) + { + self.layer.sublayers = nil; + + _headingIndicatorLayer = nil; + _headingIndicatorMaskLayer = nil; + _accuracyRingLayer = nil; + _haloLayer = nil; + _dotBorderLayer = nil; + _dotLayer = nil; + + _puckModeActivated = YES; + } + + // background dot (white with black shadow) + // + if ( ! _puckDot) + { + _puckDot = [self circleLayerWithSize:MGLUserLocationAnnotationPuckSize]; + _puckDot.backgroundColor = [[UIColor whiteColor] CGColor]; + _puckDot.shadowColor = [[UIColor blackColor] CGColor]; + _puckDot.shadowOffset = CGSizeMake(0, 1); + _puckDot.shadowRadius = 1; + _puckDot.shadowOpacity = 0.1; + + [self.layer addSublayer:_puckDot]; + } + + // arrow + // + if ( ! _puckArrow) + { + _puckArrow = [CAShapeLayer layer]; + _puckArrow.path = [[self puckArrow] CGPath]; + _puckArrow.fillColor = [_mapView.tintColor CGColor]; + _puckArrow.bounds = CGRectMake(0, 0, MGLUserLocationAnnotationArrowSize, MGLUserLocationAnnotationArrowSize); + _puckArrow.position = CGPointMake(super.bounds.size.width / 2.0, super.bounds.size.height / 2.0); + _puckArrow.shouldRasterize = YES; + _puckArrow.rasterizationScale = [UIScreen mainScreen].scale; + _puckArrow.drawsAsynchronously = YES; + + [self.layer addSublayer:_puckArrow]; + } + + if (self.mapView.pitch) + { + CATransform3D t = CATransform3DRotate(CATransform3DIdentity, MGLRadiansFromDegrees(self.mapView.pitch), 1.0, 0, 0); + self.layer.sublayerTransform = t; + } +} + +CGFloat MGLRadiansFromDegrees(CLLocationDegrees degrees) +{ + return degrees * M_PI / 180; +} + +CLLocationDegrees MGLDegreesFromRadians(CGFloat radians) +{ + return radians * 180 / M_PI; +} + +- (UIBezierPath *)puckArrow +{ + CGFloat max = MGLUserLocationAnnotationArrowSize; + + UIBezierPath *bezierPath = UIBezierPath.bezierPath; + [bezierPath moveToPoint: CGPointMake(max * 0.5, 0)]; + [bezierPath addLineToPoint: CGPointMake(max * 0.1, max)]; + [bezierPath addLineToPoint: CGPointMake(max * 0.5, max * 0.65)]; + [bezierPath addLineToPoint: CGPointMake(max * 0.9, max)]; + [bezierPath addLineToPoint: CGPointMake(max * 0.5, 0)]; + [bezierPath closePath]; + + return bezierPath; +} + +- (void)drawDot +{ + if (_puckModeActivated) + { + self.layer.sublayers = nil; + + _puckDot = nil; + _puckArrow = nil; + + _puckModeActivated = NO; + + self.layer.sublayerTransform = CATransform3DIdentity; + } + + // update heading indicator + // + if (_headingIndicatorLayer) + { + _headingIndicatorLayer.hidden = !(_mapView.userTrackingMode == MGLUserTrackingModeFollowWithHeading || + _mapView.userTrackingMode == MGLUserTrackingModeFollowWithCourse); + + if (_oldHeadingAccuracy != self.annotation.heading.headingAccuracy) { - CGFloat headingIndicatorSize = MGLUserLocationAnnotationHaloSize; - - _headingIndicatorLayer = [CALayer layer]; - _headingIndicatorLayer.bounds = CGRectMake(0, 0, headingIndicatorSize, headingIndicatorSize); - _headingIndicatorLayer.position = CGPointMake(super.bounds.size.width / 2.0, super.bounds.size.height / 2.0); - _headingIndicatorLayer.contents = (__bridge id)[[self headingIndicatorTintedGradientImage] CGImage]; - _headingIndicatorLayer.contentsGravity = kCAGravityBottom; - _headingIndicatorLayer.contentsScale = [UIScreen mainScreen].scale; - _headingIndicatorLayer.opacity = 0.4; - _headingIndicatorLayer.shouldRasterize = YES; - _headingIndicatorLayer.rasterizationScale = [UIScreen mainScreen].scale; - _headingIndicatorLayer.drawsAsynchronously = YES; - - [self.layer insertSublayer:_headingIndicatorLayer below:_dotBorderLayer]; - } - - // heading indicator accuracy mask (fan-shaped) - // - if ( ! _headingIndicatorMaskLayer && self.annotation.heading.headingAccuracy) - { - _headingIndicatorMaskLayer = [CAShapeLayer layer]; - _headingIndicatorMaskLayer.frame = _headingIndicatorLayer.bounds; + // recalculate the clipping mask based on updated accuracy _headingIndicatorMaskLayer.path = [[self headingIndicatorClippingMask] CGPath]; - // apply the mask to the halo-radius-sized gradient layer - _headingIndicatorLayer.mask = _headingIndicatorMaskLayer; - _oldHeadingAccuracy = self.annotation.heading.headingAccuracy; } + } + + // heading indicator (tinted, semi-circle) + // + if ( ! _headingIndicatorLayer && self.annotation.heading.headingAccuracy) + { + CGFloat headingIndicatorSize = MGLUserLocationAnnotationHaloSize; + + _headingIndicatorLayer = [CALayer layer]; + _headingIndicatorLayer.bounds = CGRectMake(0, 0, headingIndicatorSize, headingIndicatorSize); + _headingIndicatorLayer.position = CGPointMake(super.bounds.size.width / 2.0, super.bounds.size.height / 2.0); + _headingIndicatorLayer.contents = (__bridge id)[[self headingIndicatorTintedGradientImage] CGImage]; + _headingIndicatorLayer.contentsGravity = kCAGravityBottom; + _headingIndicatorLayer.contentsScale = [UIScreen mainScreen].scale; + _headingIndicatorLayer.opacity = 0.4; + _headingIndicatorLayer.shouldRasterize = YES; + _headingIndicatorLayer.rasterizationScale = [UIScreen mainScreen].scale; + _headingIndicatorLayer.drawsAsynchronously = YES; + + [self.layer insertSublayer:_headingIndicatorLayer below:_dotBorderLayer]; + } + + // heading indicator accuracy mask (fan-shaped) + // + if ( ! _headingIndicatorMaskLayer && self.annotation.heading.headingAccuracy) + { + _headingIndicatorMaskLayer = [CAShapeLayer layer]; + _headingIndicatorMaskLayer.frame = _headingIndicatorLayer.bounds; + _headingIndicatorMaskLayer.path = [[self headingIndicatorClippingMask] CGPath]; + + // apply the mask to the halo-radius-sized gradient layer + _headingIndicatorLayer.mask = _headingIndicatorMaskLayer; + + _oldHeadingAccuracy = self.annotation.heading.headingAccuracy; + } + + // update accuracy ring (if zoom or horizontal accuracy have changed) + // + if (_accuracyRingLayer && (_oldZoom != self.mapView.zoomLevel || _oldHorizontalAccuracy != self.annotation.location.horizontalAccuracy)) + { + CGFloat accuracyRingSize = [self calculateAccuracyRingSize]; - // update accuracy ring (if zoom or horizontal accuracy have changed) - // - if (_accuracyRingLayer && (_oldZoom != self.mapView.zoomLevel || _oldHorizontalAccuracy != self.annotation.location.horizontalAccuracy)) + // only show the accuracy ring if it won't be obscured by the location dot + if (accuracyRingSize > MGLUserLocationAnnotationDotSize + 15) { - CGFloat accuracyRingSize = [self calculateAccuracyRingSize]; - - // only show the accuracy ring if it won't be obscured by the location dot - if (accuracyRingSize > MGLUserLocationAnnotationDotSize + 15) - { - _accuracyRingLayer.hidden = NO; - _accuracyRingLayer.bounds = CGRectMake(0, 0, accuracyRingSize, accuracyRingSize); - _accuracyRingLayer.cornerRadius = accuracyRingSize / 2; - - // match the halo to the accuracy ring - _haloLayer.bounds = _accuracyRingLayer.bounds; - _haloLayer.cornerRadius = _accuracyRingLayer.cornerRadius; - _haloLayer.shouldRasterize = NO; - } - else - { - _accuracyRingLayer.hidden = YES; - - _haloLayer.bounds = CGRectMake(0, 0, MGLUserLocationAnnotationHaloSize, MGLUserLocationAnnotationHaloSize); - _haloLayer.cornerRadius = MGLUserLocationAnnotationHaloSize / 2.0; - _haloLayer.shouldRasterize = YES; - _haloLayer.rasterizationScale = [UIScreen mainScreen].scale; - } - - // store accuracy and zoom so we're not redrawing unchanged location updates - _oldHorizontalAccuracy = self.annotation.location.horizontalAccuracy; - _oldZoom = self.mapView.zoomLevel; + _accuracyRingLayer.hidden = NO; + _accuracyRingLayer.bounds = CGRectMake(0, 0, accuracyRingSize, accuracyRingSize); + _accuracyRingLayer.cornerRadius = accuracyRingSize / 2; + + // match the halo to the accuracy ring + _haloLayer.bounds = _accuracyRingLayer.bounds; + _haloLayer.cornerRadius = _accuracyRingLayer.cornerRadius; + _haloLayer.shouldRasterize = NO; } + else + { + _accuracyRingLayer.hidden = YES; + + _haloLayer.bounds = CGRectMake(0, 0, MGLUserLocationAnnotationHaloSize, MGLUserLocationAnnotationHaloSize); + _haloLayer.cornerRadius = MGLUserLocationAnnotationHaloSize / 2.0; + _haloLayer.shouldRasterize = YES; + _haloLayer.rasterizationScale = [UIScreen mainScreen].scale; + } + + // store accuracy and zoom so we're not redrawing unchanged location updates + _oldHorizontalAccuracy = self.annotation.location.horizontalAccuracy; + _oldZoom = self.mapView.zoomLevel; + } + + // accuracy ring (circular, tinted, mostly-transparent) + // + if ( ! _accuracyRingLayer && self.annotation.location.horizontalAccuracy) + { + CGFloat accuracyRingSize = [self calculateAccuracyRingSize]; + _accuracyRingLayer = [self circleLayerWithSize:accuracyRingSize]; + _accuracyRingLayer.backgroundColor = [_mapView.tintColor CGColor]; + _accuracyRingLayer.opacity = 0.1; + _accuracyRingLayer.shouldRasterize = NO; + _accuracyRingLayer.allowsGroupOpacity = NO; - // accuracy ring (circular, tinted, mostly-transparent) - // - if ( ! _accuracyRingLayer && self.annotation.location.horizontalAccuracy) - { - CGFloat accuracyRingSize = [self calculateAccuracyRingSize]; - _accuracyRingLayer = [self circleLayerWithSize:accuracyRingSize]; - _accuracyRingLayer.backgroundColor = [_mapView.tintColor CGColor]; - _accuracyRingLayer.opacity = 0.1; - _accuracyRingLayer.shouldRasterize = NO; - _accuracyRingLayer.allowsGroupOpacity = NO; - - [self.layer addSublayer:_accuracyRingLayer]; - } + [self.layer addSublayer:_accuracyRingLayer]; + } + + // expanding sonar-like pulse (circular, tinted, fades out) + // + if ( ! _haloLayer) + { + _haloLayer = [self circleLayerWithSize:MGLUserLocationAnnotationHaloSize]; + _haloLayer.backgroundColor = [_mapView.tintColor CGColor]; + _haloLayer.allowsGroupOpacity = NO; + + // set defaults for the animations + CAAnimationGroup *animationGroup = [self loopingAnimationGroupWithDuration:3.0]; + + // scale out radially with initial acceleration + CAKeyframeAnimation *boundsAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale.xy"]; + boundsAnimation.values = @[@0, @0.35, @1]; + boundsAnimation.keyTimes = @[@0, @0.2, @1]; + + // go transparent as scaled out, start semi-opaque + CAKeyframeAnimation *opacityAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; + opacityAnimation.values = @[@0.4, @0.4, @0]; + opacityAnimation.keyTimes = @[@0, @0.2, @1]; + + animationGroup.animations = @[boundsAnimation, opacityAnimation]; + + [_haloLayer addAnimation:animationGroup forKey:@"animateTransformAndOpacity"]; + + [self.layer addSublayer:_haloLayer]; + } + + // background dot (white with black shadow) + // + if ( ! _dotBorderLayer) + { + _dotBorderLayer = [self circleLayerWithSize:MGLUserLocationAnnotationDotSize]; + _dotBorderLayer.backgroundColor = [[UIColor whiteColor] CGColor]; + _dotBorderLayer.shadowColor = [[UIColor blackColor] CGColor]; + _dotBorderLayer.shadowOffset = CGSizeMake(0, 0); + _dotBorderLayer.shadowRadius = 3; + _dotBorderLayer.shadowOpacity = 0.25; - // expanding sonar-like pulse (circular, tinted, fades out) - // - if ( ! _haloLayer) - { - _haloLayer = [self circleLayerWithSize:MGLUserLocationAnnotationHaloSize]; - _haloLayer.backgroundColor = [_mapView.tintColor CGColor]; - _haloLayer.allowsGroupOpacity = NO; - - // set defaults for the animations - CAAnimationGroup *animationGroup = [self loopingAnimationGroupWithDuration:3.0]; - - // scale out radially with initial acceleration - CAKeyframeAnimation *boundsAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale.xy"]; - boundsAnimation.values = @[@0, @0.35, @1]; - boundsAnimation.keyTimes = @[@0, @0.2, @1]; - - // go transparent as scaled out, start semi-opaque - CAKeyframeAnimation *opacityAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; - opacityAnimation.values = @[@0.4, @0.4, @0]; - opacityAnimation.keyTimes = @[@0, @0.2, @1]; - - animationGroup.animations = @[boundsAnimation, opacityAnimation]; - - [_haloLayer addAnimation:animationGroup forKey:@"animateTransformAndOpacity"]; - - [self.layer addSublayer:_haloLayer]; - } - - // background dot (white with black shadow) - // - if ( ! _dotBorderLayer) - { - _dotBorderLayer = [self circleLayerWithSize:MGLUserLocationAnnotationDotSize]; - _dotBorderLayer.backgroundColor = [[UIColor whiteColor] CGColor]; - _dotBorderLayer.shadowColor = [[UIColor blackColor] CGColor]; - _dotBorderLayer.shadowOffset = CGSizeMake(0, 0); - _dotBorderLayer.shadowRadius = 3; - _dotBorderLayer.shadowOpacity = 0.25; - - [self.layer addSublayer:_dotBorderLayer]; - } - - // inner dot (pulsing, tinted) - // - if ( ! _dotLayer) - { - _dotLayer = [self circleLayerWithSize:MGLUserLocationAnnotationDotSize * 0.75]; - _dotLayer.backgroundColor = [_mapView.tintColor CGColor]; - _dotLayer.shouldRasterize = NO; - - // set defaults for the animations - CAAnimationGroup *animationGroup = [self loopingAnimationGroupWithDuration:1.5]; - animationGroup.autoreverses = YES; - animationGroup.fillMode = kCAFillModeBoth; - - // scale the dot up and down - CABasicAnimation *pulseAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale.xy"]; - pulseAnimation.fromValue = @0.8; - pulseAnimation.toValue = @1; - - // fade opacity in and out, subtly - CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; - opacityAnimation.fromValue = @0.8; - opacityAnimation.toValue = @1; - - animationGroup.animations = @[pulseAnimation, opacityAnimation]; - - [_dotLayer addAnimation:animationGroup forKey:@"animateTransformAndOpacity"]; - - [self.layer addSublayer:_dotLayer]; - } + [self.layer addSublayer:_dotBorderLayer]; + } + + // inner dot (pulsing, tinted) + // + if ( ! _dotLayer) + { + _dotLayer = [self circleLayerWithSize:MGLUserLocationAnnotationDotSize * 0.75]; + _dotLayer.backgroundColor = [_mapView.tintColor CGColor]; + _dotLayer.shouldRasterize = NO; + + // set defaults for the animations + CAAnimationGroup *animationGroup = [self loopingAnimationGroupWithDuration:1.5]; + animationGroup.autoreverses = YES; + animationGroup.fillMode = kCAFillModeBoth; + + // scale the dot up and down + CABasicAnimation *pulseAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale.xy"]; + pulseAnimation.fromValue = @0.8; + pulseAnimation.toValue = @1; + + // fade opacity in and out, subtly + CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; + opacityAnimation.fromValue = @0.8; + opacityAnimation.toValue = @1; + + animationGroup.animations = @[pulseAnimation, opacityAnimation]; + + [_dotLayer addAnimation:animationGroup forKey:@"animateTransformAndOpacity"]; + + [self.layer addSublayer:_dotLayer]; } } @@ -250,7 +362,7 @@ const CGFloat MGLUserLocationAnnotationHaloSize = 115.0; circleLayer.shouldRasterize = YES; circleLayer.rasterizationScale = [UIScreen mainScreen].scale; circleLayer.drawsAsynchronously = YES; - + return circleLayer; } @@ -261,7 +373,7 @@ const CGFloat MGLUserLocationAnnotationHaloSize = 115.0; animationGroup.repeatCount = INFINITY; animationGroup.removedOnCompletion = NO; animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]; - + return animationGroup; } @@ -269,65 +381,65 @@ const CGFloat MGLUserLocationAnnotationHaloSize = 115.0; { CGFloat latRadians = self.annotation.coordinate.latitude * M_PI / 180.0f; CGFloat pixelRadius = self.annotation.location.horizontalAccuracy / cos(latRadians) / [self.mapView metersPerPixelAtLatitude:self.annotation.coordinate.latitude]; - + return pixelRadius * 2; } - (UIImage *)headingIndicatorTintedGradientImage { UIImage *image; - + CGFloat haloRadius = MGLUserLocationAnnotationHaloSize / 2.0; - + UIGraphicsBeginImageContextWithOptions(CGSizeMake(MGLUserLocationAnnotationHaloSize, haloRadius), NO, 0); - + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef context = UIGraphicsGetCurrentContext(); - + // gradient from the tint color to no-alpha tint color CGFloat gradientLocations[] = {0.0, 1.0}; CGGradientRef gradient = CGGradientCreateWithColors( - colorSpace, (__bridge CFArrayRef)@[(id)[_mapView.tintColor CGColor], - (id)[[_mapView.tintColor colorWithAlphaComponent:0] CGColor]], gradientLocations); - + colorSpace, (__bridge CFArrayRef)@[(id)[_mapView.tintColor CGColor], + (id)[[_mapView.tintColor colorWithAlphaComponent:0] CGColor]], gradientLocations); + // draw the gradient from the center point to the edge (full halo radius) CGPoint centerPoint = CGPointMake(haloRadius, haloRadius); CGContextDrawRadialGradient(context, gradient, centerPoint, 0.0, centerPoint, haloRadius, nil); - + image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); - + CGGradientRelease(gradient); CGColorSpaceRelease(colorSpace); - + return image; } - (UIBezierPath *)headingIndicatorClippingMask { CGFloat accuracy = self.annotation.heading.headingAccuracy; - + // size the mask using exagerated accuracy, but keep within a good display range CGFloat clippingDegrees = 90 - (accuracy * 1.5); clippingDegrees = fmin(clippingDegrees, 55); clippingDegrees = fmax(clippingDegrees, 10); - + CGRect ovalRect = CGRectMake(0, 0, MGLUserLocationAnnotationHaloSize, MGLUserLocationAnnotationHaloSize); UIBezierPath *ovalPath = UIBezierPath.bezierPath; - + // clip the oval to ± incoming accuracy degrees (converted to radians), from the top [ovalPath addArcWithCenter:CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect)) radius:CGRectGetWidth(ovalRect) / 2.0 startAngle:(-180 + clippingDegrees) * M_PI / 180 endAngle:-clippingDegrees * M_PI / 180 clockwise:YES]; - + [ovalPath addLineToPoint:CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect))]; [ovalPath closePath]; - + return ovalPath; } From b611c9bb7bc6fa807ddb03922f1ffa26df9765e6 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Fri, 4 Sep 2015 00:00:28 -0400 Subject: [PATCH 08/18] [iOS] Move radians/degrees conversion functions to MGLGeometry.h --- include/mbgl/ios/MGLGeometry.h | 11 +++++++++++ platform/ios/MGLMapView.mm | 10 ---------- platform/ios/MGLUserLocationAnnotationView.m | 10 ---------- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/include/mbgl/ios/MGLGeometry.h b/include/mbgl/ios/MGLGeometry.h index 6226af1d0..2dee7c76c 100644 --- a/include/mbgl/ios/MGLGeometry.h +++ b/include/mbgl/ios/MGLGeometry.h @@ -3,6 +3,7 @@ #import "MGLTypes.h" #import +#import NS_ASSUME_NONNULL_BEGIN @@ -82,4 +83,14 @@ NS_INLINE NSString *MGLStringFromCoordinateBounds(MGLCoordinateBounds bounds) { bounds.ne.latitude, bounds.ne.longitude]; } +NS_INLINE CGFloat MGLRadiansFromDegrees(CLLocationDegrees degrees) +{ + return degrees * M_PI / 180; +} + +NS_INLINE CLLocationDegrees MGLDegreesFromRadians(CGFloat radians) +{ + return radians * 180 / M_PI; +} + NS_ASSUME_NONNULL_END diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index e509b5c8d..705627663 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -60,16 +60,6 @@ static NSURL *MGLURLForBundledStyleNamed(NSString *styleName) return [NSURL URLWithString:[NSString stringWithFormat:@"asset://styles/%@.json", styleName]]; } -CGFloat MGLRadiansFromDegrees(CLLocationDegrees degrees) -{ - return degrees * M_PI / 180; -} - -CLLocationDegrees MGLDegreesFromRadians(CGFloat radians) -{ - return radians * 180 / M_PI; -} - mbgl::util::UnitBezier MGLUnitBezierForMediaTimingFunction(CAMediaTimingFunction *function) { if ( ! function) diff --git a/platform/ios/MGLUserLocationAnnotationView.m b/platform/ios/MGLUserLocationAnnotationView.m index 301e3c4b2..06da8a998 100644 --- a/platform/ios/MGLUserLocationAnnotationView.m +++ b/platform/ios/MGLUserLocationAnnotationView.m @@ -144,16 +144,6 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck } } -CGFloat MGLRadiansFromDegrees(CLLocationDegrees degrees) -{ - return degrees * M_PI / 180; -} - -CLLocationDegrees MGLDegreesFromRadians(CGFloat radians) -{ - return radians * 180 / M_PI; -} - - (UIBezierPath *)puckArrow { CGFloat max = MGLUserLocationAnnotationArrowSize; From 60d68158a3be7830f52e90e149999631883e8461 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Fri, 4 Sep 2015 00:41:43 -0400 Subject: [PATCH 09/18] =?UTF-8?q?[iOS]=20Pitch=20the=20dot,=20add=20faux?= =?UTF-8?q?=203D=20effect=20to=20tilted=20dot=20and=20puck=20This=20expose?= =?UTF-8?q?s=20the=20na=C3=AFvet=C3=A9=20of=20the=20current=20pitch=20tran?= =?UTF-8?q?sform:=20accuracy=20ring=20sizing=20stays=20constant,=20despite?= =?UTF-8?q?=20vertical=20screen=20movement.=20Still,=20it=20looks=20better?= =?UTF-8?q?=20pitched=20than=20not.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- platform/ios/MGLUserLocationAnnotationView.m | 88 ++++++++++++++++---- 1 file changed, 72 insertions(+), 16 deletions(-) diff --git a/platform/ios/MGLUserLocationAnnotationView.m b/platform/ios/MGLUserLocationAnnotationView.m index 06da8a998..22c1d00f1 100644 --- a/platform/ios/MGLUserLocationAnnotationView.m +++ b/platform/ios/MGLUserLocationAnnotationView.m @@ -8,7 +8,7 @@ const CGFloat MGLUserLocationAnnotationDotSize = 22.0; const CGFloat MGLUserLocationAnnotationHaloSize = 115.0; -const CGFloat MGLUserLocationAnnotationPuckSize = 35.0; +const CGFloat MGLUserLocationAnnotationPuckSize = 45.0; const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuckSize * 0.6; @interface MGLUserLocationAnnotationView () @@ -35,6 +35,7 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck double _oldHeadingAccuracy; CLLocationAccuracy _oldHorizontalAccuracy; double _oldZoom; + double _oldPitch; } - (instancetype)initWithFrame:(CGRect)frame @@ -88,6 +89,42 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck if (CLLocationCoordinate2DIsValid(self.annotation.coordinate)) { (_mapView.userTrackingMode == MGLUserTrackingModeFollowWithCourse) ? [self drawPuck] : [self drawDot]; + [self updatePitch]; + } +} + +- (void)updatePitch +{ + if (self.mapView.camera.pitch && (self.mapView.camera.pitch != _oldPitch)) + { + CATransform3D t = CATransform3DRotate(CATransform3DIdentity, MGLRadiansFromDegrees(self.mapView.camera.pitch), 1.0, 0, 0); + self.layer.sublayerTransform = t; + + [self updateFaux3DEffect]; + + _oldPitch = self.mapView.camera.pitch; + } +} + +- (void)updateFaux3DEffect +{ + CGFloat pitch = MGLRadiansFromDegrees(self.mapView.camera.pitch); + + if (_puckDot) + { + _puckDot.shadowOffset = CGSizeMake(0, fmaxf(pitch * 10.f, 1.f)); + _puckDot.shadowRadius = fmaxf(pitch * 5.f, 0.75f); + } + + if (_dotBorderLayer) + { + _dotBorderLayer.shadowOffset = CGSizeMake(0.f, pitch * 10.f); + _dotBorderLayer.shadowRadius = fmaxf(pitch * 5.f, 3.f); + } + + if (_dotLayer) + { + _dotLayer.zPosition = pitch * 2.f; } } @@ -103,8 +140,6 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck _haloLayer = nil; _dotBorderLayer = nil; _dotLayer = nil; - - _puckModeActivated = YES; } // background dot (white with black shadow) @@ -114,9 +149,17 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck _puckDot = [self circleLayerWithSize:MGLUserLocationAnnotationPuckSize]; _puckDot.backgroundColor = [[UIColor whiteColor] CGColor]; _puckDot.shadowColor = [[UIColor blackColor] CGColor]; - _puckDot.shadowOffset = CGSizeMake(0, 1); - _puckDot.shadowRadius = 1; - _puckDot.shadowOpacity = 0.1; + _puckDot.shadowOpacity = 0.25; + + if (self.mapView.camera.pitch) + { + [self updateFaux3DEffect]; + } + else + { + _puckDot.shadowOffset = CGSizeMake(0, 1); + _puckDot.shadowRadius = 0.75; + } [self.layer addSublayer:_puckDot]; } @@ -137,10 +180,11 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck [self.layer addSublayer:_puckArrow]; } - if (self.mapView.pitch) + if ( ! _puckModeActivated) { - CATransform3D t = CATransform3DRotate(CATransform3DIdentity, MGLRadiansFromDegrees(self.mapView.pitch), 1.0, 0, 0); - self.layer.sublayerTransform = t; + _puckModeActivated = YES; + + [self updateFaux3DEffect]; } } @@ -167,10 +211,6 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck _puckDot = nil; _puckArrow = nil; - - _puckModeActivated = NO; - - self.layer.sublayerTransform = CATransform3DIdentity; } // update heading indicator @@ -277,6 +317,7 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck _haloLayer = [self circleLayerWithSize:MGLUserLocationAnnotationHaloSize]; _haloLayer.backgroundColor = [_mapView.tintColor CGColor]; _haloLayer.allowsGroupOpacity = NO; + _haloLayer.zPosition = -0.1f; // set defaults for the animations CAAnimationGroup *animationGroup = [self loopingAnimationGroupWithDuration:3.0]; @@ -305,10 +346,18 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck _dotBorderLayer = [self circleLayerWithSize:MGLUserLocationAnnotationDotSize]; _dotBorderLayer.backgroundColor = [[UIColor whiteColor] CGColor]; _dotBorderLayer.shadowColor = [[UIColor blackColor] CGColor]; - _dotBorderLayer.shadowOffset = CGSizeMake(0, 0); - _dotBorderLayer.shadowRadius = 3; _dotBorderLayer.shadowOpacity = 0.25; - + + if (self.mapView.camera.pitch) + { + [self updateFaux3DEffect]; + } + else + { + _dotBorderLayer.shadowOffset = CGSizeMake(0, 0); + _dotBorderLayer.shadowRadius = 3; + } + [self.layer addSublayer:_dotBorderLayer]; } @@ -341,6 +390,13 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck [self.layer addSublayer:_dotLayer]; } + + if (_puckModeActivated) + { + _puckModeActivated = NO; + + [self updateFaux3DEffect]; + } } - (CALayer *)circleLayerWithSize:(CGFloat)layerSize From b162d2cafab89f43bddd5289c5be3815b3abb0f0 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Thu, 10 Sep 2015 19:29:13 -0400 Subject: [PATCH 10/18] [iOS] Remove unneccessary pitch check Fix case where moving the tilted dot off-screen, changing the pitch to 0, and then moving the dot back on screen would not reset the pitch of the dot. --- platform/ios/MGLUserLocationAnnotationView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/ios/MGLUserLocationAnnotationView.m b/platform/ios/MGLUserLocationAnnotationView.m index 22c1d00f1..b477b1088 100644 --- a/platform/ios/MGLUserLocationAnnotationView.m +++ b/platform/ios/MGLUserLocationAnnotationView.m @@ -95,7 +95,7 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck - (void)updatePitch { - if (self.mapView.camera.pitch && (self.mapView.camera.pitch != _oldPitch)) + if (self.mapView.camera.pitch != _oldPitch) { CATransform3D t = CATransform3DRotate(CATransform3DIdentity, MGLRadiansFromDegrees(self.mapView.camera.pitch), 1.0, 0, 0); self.layer.sublayerTransform = t; From 26a5d128b46febc1ca2ed41e468c59c66d90af1d Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Wed, 26 Aug 2015 11:14:08 -0400 Subject: [PATCH 11/18] increase precision for coordinate conversions This fixes the earthquakes while panning at high zoom levels. Cherry-picked from 9607171612c4a40e41eddaff5230ad571571a5b9 on the perspective-improved-gestures branch. --- src/mbgl/map/transform_state.cpp | 31 +++++++++++++++---------------- src/mbgl/map/transform_state.hpp | 8 ++++---- src/mbgl/util/mat4.cpp | 2 +- src/mbgl/util/tile_coordinate.hpp | 12 ++++++------ src/mbgl/util/vec4.cpp | 2 +- 5 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index c672ca5de..e37f10dc6 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -157,21 +157,21 @@ float TransformState::getPitch() const { #pragma mark - Projection -float TransformState::lngX(float lng) const { +double TransformState::lngX(double lng) const { return (180.0f + lng) * worldSize() / 360.0f; } -float TransformState::latY(float lat) const { - float y_ = 180.0f / M_PI * std::log(std::tan(M_PI / 4 + lat * M_PI / 360.0f)); +double TransformState::latY(double lat) const { + double y_ = 180.0f / M_PI * std::log(std::tan(M_PI / 4 + lat * M_PI / 360.0f)); return (180.0f - y_) * worldSize() / 360.0f; } -float TransformState::xLng(float x_, float worldSize_) const { +double TransformState::xLng(double x_, double worldSize_) const { return x_ * 360.0f / worldSize_ - 180.0f; } -float TransformState::yLat(float y_, float worldSize_) const { - float y2 = 180.0f - y_ * 360.0f / worldSize_; +double TransformState::yLat(double y_, double worldSize_) const { + double y2 = 180.0f - y_ * 360.0f / worldSize_; return 360.0f / M_PI * std::atan(std::exp(y2 * M_PI / 180.0f)) - 90.0f; } @@ -245,17 +245,16 @@ TileCoordinate TransformState::pointToCoordinate(const vec2 point) const matrix::transformMat4(coord0, point0, inverted); matrix::transformMat4(coord1, point1, inverted); - float w0 = coord0[3]; - float w1 = coord1[3]; - float x0 = coord0[0] / w0; - float x1 = coord1[0] / w1; - float y0 = coord0[1] / w0; - float y1 = coord1[1] / w1; - float z0 = coord0[2] / w0; - float z1 = coord1[2] / w1; + double w0 = coord0[3]; + double w1 = coord1[3]; + double x0 = coord0[0] / w0; + double x1 = coord1[0] / w1; + double y0 = coord0[1] / w0; + double y1 = coord1[1] / w1; + double z0 = coord0[2] / w0; + double z1 = coord1[2] / w1; - - float t = z0 == z1 ? 0 : (targetZ - z0) / (z1 - z0); + double t = z0 == z1 ? 0 : (targetZ - z0) / (z1 - z0); return { util::interpolate(x0, x1, t), util::interpolate(y0, y1, t), tileZoom }; } diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index d4b46f04b..c3e1072c9 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -79,10 +79,10 @@ private: // logical dimensions uint16_t width = 0, height = 0; - float xLng(float x, float worldSize) const; - float yLat(float y, float worldSize) const; - float lngX(float lon) const; - float latY(float lat) const; + double xLng(double x, double worldSize) const; + double yLat(double y, double worldSize) const; + double lngX(double lon) const; + double latY(double lat) const; float zoomScale(float zoom) const; float worldSize() const; diff --git a/src/mbgl/util/mat4.cpp b/src/mbgl/util/mat4.cpp index 123c8464f..0934cd081 100644 --- a/src/mbgl/util/mat4.cpp +++ b/src/mbgl/util/mat4.cpp @@ -46,7 +46,7 @@ void matrix::identity(mat4& out) { } bool matrix::invert(mat4& out, mat4& a) { - float a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + double a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], diff --git a/src/mbgl/util/tile_coordinate.hpp b/src/mbgl/util/tile_coordinate.hpp index 0f5f0dcb8..836539b5b 100644 --- a/src/mbgl/util/tile_coordinate.hpp +++ b/src/mbgl/util/tile_coordinate.hpp @@ -6,15 +6,15 @@ namespace mbgl { struct TileCoordinate { - float column; - float row; - float zoom; + double column; + double row; + double zoom; - TileCoordinate(float column_, float row_, float zoom_) : + TileCoordinate(double column_, double row_, double zoom_) : column(column_), row(row_), zoom(zoom_) {} - TileCoordinate zoomTo(float targetZoom) { - float scale = std::pow(2, targetZoom - zoom); + TileCoordinate zoomTo(double targetZoom) { + double scale = std::pow(2, targetZoom - zoom); return { column * scale, row * scale, targetZoom }; } diff --git a/src/mbgl/util/vec4.cpp b/src/mbgl/util/vec4.cpp index 415b15d80..bee4eaf97 100644 --- a/src/mbgl/util/vec4.cpp +++ b/src/mbgl/util/vec4.cpp @@ -25,7 +25,7 @@ using namespace mbgl; void matrix::transformMat4(vec4& out, vec4& a, mat4& m) { - float x = a[0], y = a[1], z = a[2], w = a[3]; + double x = a[0], y = a[1], z = a[2], w = a[3]; out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w; out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w; out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w; From f8ed28cca0ba160d658958f7b0f8a3312fa62d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Thu, 10 Sep 2015 13:39:47 -0700 Subject: [PATCH 12/18] Increased precision of coordinate conversion methods Fixes #2230. --- src/mbgl/map/transform_state.cpp | 16 ++++++++-------- src/mbgl/map/transform_state.hpp | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index e37f10dc6..ac3988dc5 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -175,7 +175,7 @@ double TransformState::yLat(double y_, double worldSize_) const { return 360.0f / M_PI * std::atan(std::exp(y2 * M_PI / 180.0f)) - 90.0f; } -float TransformState::zoomScale(float zoom) const { +double TransformState::zoomScale(double zoom) const { return std::pow(2.0f, zoom); } @@ -192,8 +192,8 @@ LatLng TransformState::pointToLatLng(const vec2 point) const { } TileCoordinate TransformState::latLngToCoordinate(const LatLng& latLng) const { - const float tileZoom = getIntegerZoom(); - const float k = zoomScale(tileZoom) / worldSize(); + const double tileZoom = getZoom(); + const double k = zoomScale(tileZoom) / worldSize(); return { lngX(latLng.longitude) * k, latY(latLng.latitude) * k, @@ -202,12 +202,12 @@ TileCoordinate TransformState::latLngToCoordinate(const LatLng& latLng) const { } LatLng TransformState::coordinateToLatLng(const TileCoordinate& coord) const { - const float worldSize_ = zoomScale(coord.zoom); + const double worldSize_ = zoomScale(coord.zoom); LatLng latLng = { yLat(coord.row, worldSize_), xLng(coord.column, worldSize_) }; - while (latLng.longitude < 180.0f) latLng.longitude += 360.0f; + while (latLng.longitude < -180.0f) latLng.longitude += 360.0f; while (latLng.longitude > 180.0f) latLng.longitude -= 360.0f; return latLng; } @@ -223,7 +223,7 @@ vec2 TransformState::coordinateToPoint(const TileCoordinate& coord) cons TileCoordinate TransformState::pointToCoordinate(const vec2 point) const { float targetZ = 0; - const float tileZoom = getIntegerZoom(); + const double tileZoom = getZoom(); mat4 mat = coordinatePointMatrix(tileZoom); @@ -259,11 +259,11 @@ TileCoordinate TransformState::pointToCoordinate(const vec2 point) const return { util::interpolate(x0, x1, t), util::interpolate(y0, y1, t), tileZoom }; } -mat4 TransformState::coordinatePointMatrix(float z) const { +mat4 TransformState::coordinatePointMatrix(double z) const { mat4 proj; getProjMatrix(proj); float s = util::tileSize * scale / std::pow(2, z); - matrix::scale(proj, proj, s , s, 1); + matrix::scale(proj, proj, s, s, 1); matrix::multiply(proj, getPixelMatrix(), proj); return proj; } diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index c3e1072c9..6fcd35ffa 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -83,10 +83,10 @@ private: double yLat(double y, double worldSize) const; double lngX(double lon) const; double latY(double lat) const; - float zoomScale(float zoom) const; + double zoomScale(double zoom) const; float worldSize() const; - mat4 coordinatePointMatrix(float z) const; + mat4 coordinatePointMatrix(double z) const; mat4 getPixelMatrix() const; private: From b10ae77765795a216ff6633d19cb8a184a9f1301 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Fri, 11 Sep 2015 16:34:10 -0400 Subject: [PATCH 13/18] [iOS] Fix MGLPolyline documentation typo --- include/mbgl/ios/MGLPolyline.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mbgl/ios/MGLPolyline.h b/include/mbgl/ios/MGLPolyline.h index 7cbbadeca..07c5286c8 100644 --- a/include/mbgl/ios/MGLPolyline.h +++ b/include/mbgl/ios/MGLPolyline.h @@ -9,7 +9,7 @@ NS_ASSUME_NONNULL_BEGIN /** The `MGLPolyline` class represents a shape consisting of one or more points that define connecting line segments. The points are connected end-to-end in the order they are provided. The first and last points are not connected to each other. */ @interface MGLPolyline : MGLMultiPoint -/** Creates and returns an `MGLPolygon` object from the specified set of coordinates. +/** Creates and returns an `MGLPolyline` object from the specified set of coordinates. * @param coords The array of coordinates defining the shape. The data in this array is copied to the new object. * @param count The number of items in the _`coords`_ array. * @return A new polyline object. */ From b72acf5dc5e92369e7b33b12c7e41c2515c3ff94 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Fri, 11 Sep 2015 15:33:17 -0700 Subject: [PATCH 14/18] bump podspec to 2.1.0-pre.4 --- ios/Mapbox-iOS-SDK.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Mapbox-iOS-SDK.podspec b/ios/Mapbox-iOS-SDK.podspec index 449d4ce1d..fce1a602d 100644 --- a/ios/Mapbox-iOS-SDK.podspec +++ b/ios/Mapbox-iOS-SDK.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |m| m.name = 'Mapbox-iOS-SDK' - m.version = '2.1.0-pre.3-symbols' + m.version = '2.1.0-pre.4-symbols' m.summary = 'Open source vector map solution for iOS with full styling capabilities.' m.description = 'Open source OpenGL-based vector map solution for iOS with full styling capabilities and Cocoa bindings.' From be29ad1c101b848054167ad60901694abd68bdcb Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Fri, 11 Sep 2015 15:34:43 -0700 Subject: [PATCH 15/18] [publish ios-v2.1.0-pre.4] From 0fa2461371741a1c35ec7c85b30cfbd94ed8556b Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Sep 2015 18:20:47 -0700 Subject: [PATCH 16/18] update podspec for 2.1.0 final and no symbols --- ios/Mapbox-iOS-SDK.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Mapbox-iOS-SDK.podspec b/ios/Mapbox-iOS-SDK.podspec index fce1a602d..3fad85cf1 100644 --- a/ios/Mapbox-iOS-SDK.podspec +++ b/ios/Mapbox-iOS-SDK.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |m| m.name = 'Mapbox-iOS-SDK' - m.version = '2.1.0-pre.4-symbols' + m.version = '2.1.0' m.summary = 'Open source vector map solution for iOS with full styling capabilities.' m.description = 'Open source OpenGL-based vector map solution for iOS with full styling capabilities and Cocoa bindings.' From ab1daf85ba3184c0c9308f21b3d8e496894b0373 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Sep 2015 18:21:29 -0700 Subject: [PATCH 17/18] [publish ios-v2.1.0] From 6bfb18f075f5d7bbb05a01aa9519c0c553e2c5f2 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Sep 2015 18:40:42 -0700 Subject: [PATCH 18/18] update changelog for ios-v2.1.0 --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1b3e3003..f7ecd8cd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## iOS 2.1.0 + +- A two-finger vertical swipe now tilts the map into perspective mode. ([#2116](https://github.com/mapbox/mapbox-gl-native/pull/2116)) +- A new `MGLMapCamera` API allows you to transition multiple viewpoint properties, including rotation and pitch, simultaneously with an optional custom duration and timing function. ([#2193](https://github.com/mapbox/mapbox-gl-native/pull/2193)) +- A new user tracking mode, `MGLUserTrackingModeFollowWithCourse`, has been added for indicating the current direction of travel. ([#2068](https://github.com/mapbox/mapbox-gl-native/pull/2068)) +- Version 8 (`v8`) of the [Mapbox GL style spec](https://www.mapbox.com/mapbox-gl-style-spec/) is now required. If you are using a custom `v7` style, it needs to be upgraded using [this migrator script](https://github.com/mapbox/mapbox-gl-style-spec/blob/mb-pages/migrations/v7.js). ([#2052](https://github.com/mapbox/mapbox-gl-native/pull/2052)) +- Applications built with Mapbox GL no longer crash when Location Services launches them in background mode. ([#1821](https://github.com/mapbox/mapbox-gl-native/pull/1821), [#1869](https://github.com/mapbox/mapbox-gl-native/pull/1869)) +- Fixed a crash when adding annotations to an `MGLMapView` inside `-viewDidLoad`. ([#1874](https://github.com/mapbox/mapbox-gl-native/pull/1874)) +- The user location annotation view now indicates the location reading’s accuracy and the device’s heading. ([#2010](https://github.com/mapbox/mapbox-gl-native/pull/2010)) +- Eliminated linker warnings and errors when building against the iOS 9.0 SDK in Xcode 7. ([#1962](https://github.com/mapbox/mapbox-gl-native/pull/1962)) +- Worked around a bug in the iOS 9.0 SDK that caused a crash on launch. ([#1958](https://github.com/mapbox/mapbox-gl-native/pull/1958)) +- User location tracking no longer sends `MGLMapView` into an invalid region on iOS 9. ([#1925](https://github.com/mapbox/mapbox-gl-native/pull/1925)) +- Eliminated console spew in the iOS demo application that was related to Mapbox Metrics HTTP requests. ([#1937](https://github.com/mapbox/mapbox-gl-native/issues/1937)) +- Implemented `-[MGLMapView showAnnotations:animated:]`. ([#2050](https://github.com/mapbox/mapbox-gl-native/pull/2050)) +- Fixed a crash adding a shape annotation with zero points. ([#2098](https://github.com/mapbox/mapbox-gl-native/pull/2098)) +- Debug mode now displays information useful for debugging the label collision algorithm. ([#1808](https://github.com/mapbox/mapbox-gl-native/pull/1808)) +- Minor style updates. ([#1910](https://github.com/mapbox/mapbox-gl-native/pull/1910)) +- The CocoaPods pod now contains a `README.md` file. ([#1886](https://github.com/mapbox/mapbox-gl-native/pull/1886)) + ## iOS 2.0.0 Repackaging 2.0.0-pre.1 as it contained no issues.