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

Fix flyTo trajectory; port to OS X #3301

Merged
merged 5 commits into from
Dec 15, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Known issues:

- `MGLMapView` methods that alter the viewport now accept optional completion handlers. ([#3090](https://github.com/mapbox/mapbox-gl-native/pull/3090))
- Tapping now selects annotations more reliably. Tapping near the top of a large annotation image now selects that annotation. An annotation image’s alignment insets influence how far away the user can tap and still select the annotation. For example, if your annotation image has a large shadow, you can keep that shadow from being tappable by excluding it from the image’s alignment rect. ([#3261](https://github.com/mapbox/mapbox-gl-native/pull/3261))
- A new method on MGLMapView, `-flyToCamera:withDuration:completionHandler:`, lets you transition between viewpoints along an arc as if by aircraft. ([#3171](https://github.com/mapbox/mapbox-gl-native/pull/3171), [#3301](https://github.com/mapbox/mapbox-gl-native/pull/3301))
- The user dot’s callout view is now centered above the user dot. It was previously offset slightly to the left. ([#3261](https://github.com/mapbox/mapbox-gl-native/pull/3261))

## iOS 3.0.1
Expand Down
11 changes: 7 additions & 4 deletions include/mbgl/ios/MGLMapView.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,15 @@ IB_DESIGNABLE
* @param completion The block to execute after the animation finishes. */
- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion;

#pragma mark - flyTo
/** Uses a ballistic parabolic motion to "fly" the viewpoint to a different location with respect to the map with a default duration based on the length of the flight path.
* @param camera The new viewpoint.
* @param completion The block to execute after the animation finishes. */
- (void)flyToCamera:(MGLMapCamera *)camera completionHandler:(nullable void (^)(void))completion;

/** Uses a ballistic parabolic motion to "fly" the viewpoint to a different location with respect to the map with an optional transition duration.
* @param camera The new viewpoint.
* @param duration The amount of time, measured in seconds, that the transition animation should take. Specify `0` to jump to the new viewpoint instantaneously.
* @param completion The block to execute after the animation finishes. */
* @param camera The new viewpoint.
* @param duration The amount of time, measured in seconds, that the transition animation should take. Specify `0` to use the default duration, which is based on the length of the flight path.
* @param completion The block to execute after the animation finishes. */
- (void)flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration completionHandler:(nullable void (^)(void))completion;

#pragma mark - Converting Map Coordinates
Expand Down
2 changes: 2 additions & 0 deletions include/mbgl/map/camera.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ struct CameraOptions {
mapbox::util::optional<double> angle;
mapbox::util::optional<double> pitch;
mapbox::util::optional<Duration> duration;
mapbox::util::optional<double> speed;
mapbox::util::optional<double> curve;
mapbox::util::optional<mbgl::util::UnitBezier> easing;
std::function<void(double)> transitionFrameFn;
std::function<void()> transitionFinishFn;
Expand Down
18 changes: 18 additions & 0 deletions include/mbgl/osx/MGLMapView.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,24 @@ IB_DESIGNABLE
@param completion The block to execute after the animation finishes. */
- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion;

/** Uses a ballistic parabolic motion to “fly” the viewpoint to a different
location with respect to the map with a default duration based on the length
of the flight path.

@param camera The new viewpoint.
@param completion The block to execute after the animation finishes. */
- (void)flyToCamera:(MGLMapCamera *)camera completionHandler:(nullable void (^)(void))completion;

/** Uses a ballistic parabolic motion to “fly” the viewpoint to a different
location with respect to the map with an optional transition duration.

@param camera The new viewpoint.
@param duration The amount of time, measured in seconds, that the transition
animation should take. Specify `0` to use the default duration, which is
based on the length of the flight path.
@param completion The block to execute after the animation finishes. */
- (void)flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration completionHandler:(nullable void (^)(void))completion;

/** The geographic coordinate bounds visible in the receiver’s viewport.

Changing the value of this property updates the receiver immediately. If you
Expand Down
56 changes: 56 additions & 0 deletions ios/app/MBXViewController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@

static UIColor *const kTintColor = [UIColor colorWithRed:0.120 green:0.550 blue:0.670 alpha:1.000];

static const CLLocationCoordinate2D WorldTourDestinations[] = {
{ 38.9131982, -77.0325453144239 },
{ 37.7757368, -122.4135302 },
{ 12.9810816, 77.6368034 },
{ -13.15589555, -74.2178961777998 },
};

@interface MBXViewController () <UIActionSheetDelegate, MGLMapViewDelegate>

@property (nonatomic) MGLMapView *mapView;
Expand All @@ -15,6 +22,9 @@ @interface MBXViewController () <UIActionSheetDelegate, MGLMapViewDelegate>
@end

@implementation MBXViewController
{
BOOL _isTouringWorld;
}

#pragma mark - Setup

Expand Down Expand Up @@ -138,6 +148,7 @@ - (void)showSettings
@"Add 1,000 Points",
@"Add 10,000 Points",
@"Add Test Shapes",
@"Start World Tour",
@"Remove Annotations",
nil];

Expand Down Expand Up @@ -242,6 +253,10 @@ - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSIn
}
}
else if (buttonIndex == actionSheet.firstOtherButtonIndex + 8)
{
[self startWorldTour:actionSheet];
}
else if (buttonIndex == actionSheet.firstOtherButtonIndex + 9)
{
[self.mapView removeAnnotations:self.mapView.annotations];
}
Expand Down Expand Up @@ -332,6 +347,46 @@ - (void)locateUser
self.mapView.userTrackingMode = nextMode;
}

- (IBAction)startWorldTour:(__unused id)sender
{
_isTouringWorld = YES;

[self.mapView removeAnnotations:self.mapView.annotations];
NSUInteger numberOfAnnotations = sizeof(WorldTourDestinations) / sizeof(WorldTourDestinations[0]);
NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:numberOfAnnotations];
for (NSUInteger i = 0; i < numberOfAnnotations; i++)
{
MGLPointAnnotation *annotation = [[MGLPointAnnotation alloc] init];
annotation.coordinate = WorldTourDestinations[i];
[annotations addObject:annotation];
}
[self.mapView addAnnotations:annotations];
[self continueWorldTourWithRemainingAnnotations:annotations];
}

- (void)continueWorldTourWithRemainingAnnotations:(NS_MUTABLE_ARRAY_OF(MGLPointAnnotation *) *)annotations
{
MGLPointAnnotation *nextAnnotation = annotations.firstObject;
if (!nextAnnotation || !_isTouringWorld)
{
_isTouringWorld = NO;
return;
}

[annotations removeObjectAtIndex:0];
MGLMapCamera *camera = [MGLMapCamera cameraLookingAtCenterCoordinate:nextAnnotation.coordinate
fromDistance:10
pitch:arc4random_uniform(60)
heading:arc4random_uniform(360)];
__weak MBXViewController *weakSelf = self;
[self.mapView flyToCamera:camera completionHandler:^{
MBXViewController *strongSelf = weakSelf;
[strongSelf performSelector:@selector(continueWorldTourWithRemainingAnnotations:)
withObject:annotations
afterDelay:2];
}];
}

#pragma mark - Destruction

- (void)dealloc
Expand All @@ -348,6 +403,7 @@ - (MGLAnnotationImage *)mapView:(MGLMapView * __nonnull)mapView imageForAnnotati
if ([annotation.title isEqualToString:@"Dropped Marker"]) return nil; // use default marker

NSString *title = [(MGLPointAnnotation *)annotation title];
if (!title.length) return nil;
NSString *lastTwoCharacters = [title substringFromIndex:title.length - 2];

UIColor *color;
Expand Down
66 changes: 44 additions & 22 deletions platform/ios/MGLMapView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1787,18 +1787,57 @@ - (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration a

- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion
{
[self _setCamera:camera withDuration:duration animationTimingFunction:function completionHandler:completion useFly:NO];
_mbglMap->cancelTransitions();
mbgl::CameraOptions options = [self cameraOptionsObjectForAnimatingToCamera:camera];
if (duration > 0)
{
options.duration = MGLDurationInSeconds(duration);
options.easing = MGLUnitBezierForMediaTimingFunction(function);
}
if (completion)
{
options.transitionFinishFn = [completion]() {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
completion();
});
};
}

[self willChangeValueForKey:@"camera"];
_mbglMap->easeTo(options);
[self didChangeValueForKey:@"camera"];
}

- (void)flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration completionHandler:(nullable void (^)(void))completion
- (void)flyToCamera:(MGLMapCamera *)camera completionHandler:(nullable void (^)(void))completion
{
[self _setCamera:camera withDuration:duration animationTimingFunction:nil completionHandler:completion useFly:YES];
[self flyToCamera:camera withDuration:0 completionHandler:completion];
}

- (void)_setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion useFly:(BOOL)fly
- (void)flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration completionHandler:(nullable void (^)(void))completion
{
_mbglMap->cancelTransitions();
mbgl::CameraOptions options = [self cameraOptionsObjectForAnimatingToCamera:camera];
if (duration > 0)
{
options.duration = MGLDurationInSeconds(duration);
}
if (completion)
{
options.transitionFinishFn = [completion]() {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
completion();
});
};
}

[self willChangeValueForKey:@"camera"];
_mbglMap->flyTo(options);
[self didChangeValueForKey:@"camera"];
}

/// Returns a CameraOptions object that specifies parameters for animating to
/// the given camera.
- (mbgl::CameraOptions)cameraOptionsObjectForAnimatingToCamera:(MGLMapCamera *)camera {
// The opposite side is the distance between the center and one edge.
mbgl::LatLng centerLatLng = MGLLatLngFromLocationCoordinate2D(camera.centerCoordinate);
mbgl::ProjectedMeters centerMeters = _mbglMap->projectedMetersForLatLng(centerLatLng);
Expand Down Expand Up @@ -1855,24 +1894,7 @@ - (void)_setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration
{
options.pitch = pitch;
}
if (duration > 0)
{
options.duration = MGLDurationInSeconds(duration);
options.easing = MGLUnitBezierForMediaTimingFunction(function);
}
if (completion)
{
options.transitionFinishFn = [completion]() {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
completion();
});
};
}
if (fly) {
_mbglMap->flyTo(options);
} else {
_mbglMap->easeTo(options);
}
return options;
}

- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(nullable UIView *)view
Expand Down
65 changes: 62 additions & 3 deletions platform/osx/app/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken";
static NSString * const MGLDroppedPinAnnotationImageIdentifier = @"dropped";

static const CLLocationCoordinate2D WorldTourDestinations[] = {
{ .latitude = 38.9131982, .longitude = -77.0325453144239 },
{ .latitude = 37.7757368, .longitude = -122.4135302 },
{ .latitude = 12.9810816, .longitude = 77.6368034 },
{ .latitude = -13.15589555, .longitude = -74.2178961777998 },
};

@interface AppDelegate () <NSApplicationDelegate, NSSharingServicePickerDelegate, NSMenuDelegate, MGLMapViewDelegate>

@property (weak) IBOutlet NSWindow *window;
Expand All @@ -26,6 +33,7 @@ @implementation AppDelegate {

BOOL _showsToolTipsOnDroppedPins;
BOOL _randomizesCursorsOnDroppedPins;
BOOL _isTouringWorld;
}

#pragma mark Lifecycle
Expand Down Expand Up @@ -283,6 +291,48 @@ - (IBAction)removeAllPins:(id)sender {
[self.mapView removeAnnotations:self.mapView.annotations];
}

- (IBAction)startWorldTour:(id)sender {
_isTouringWorld = YES;

[self removeAllPins:sender];
NSUInteger numberOfAnnotations = sizeof(WorldTourDestinations) / sizeof(WorldTourDestinations[0]);
NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:numberOfAnnotations];
for (NSUInteger i = 0; i < numberOfAnnotations; i++) {
MGLPointAnnotation *annotation = [[MGLPointAnnotation alloc] init];
annotation.coordinate = WorldTourDestinations[i];
[annotations addObject:annotation];
}
[self.mapView addAnnotations:annotations];
[self continueWorldTourWithRemainingAnnotations:annotations];
}

- (void)continueWorldTourWithRemainingAnnotations:(NS_MUTABLE_ARRAY_OF(MGLPointAnnotation *) *)annotations {
MGLPointAnnotation *nextAnnotation = annotations.firstObject;
if (!nextAnnotation || !_isTouringWorld) {
_isTouringWorld = NO;
return;
}

[annotations removeObjectAtIndex:0];
MGLMapCamera *camera = [MGLMapCamera cameraLookingAtCenterCoordinate:nextAnnotation.coordinate
fromDistance:0
pitch:arc4random_uniform(60)
heading:arc4random_uniform(360)];
__weak AppDelegate *weakSelf = self;
[self.mapView flyToCamera:camera completionHandler:^{
AppDelegate *strongSelf = weakSelf;
[strongSelf performSelector:@selector(continueWorldTourWithRemainingAnnotations:)
withObject:annotations
afterDelay:2];
}];
}

- (IBAction)stopWorldTour:(id)sender {
_isTouringWorld = NO;
// Any programmatic viewpoint change cancels outstanding animations.
self.mapView.camera = self.mapView.camera;
}

#pragma mark Help methods

- (IBAction)showShortcuts:(id)sender {
Expand Down Expand Up @@ -445,6 +495,12 @@ - (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
if (menuItem.action == @selector(removeAllPins:)) {
return self.mapView.annotations.count;
}
if (menuItem.action == @selector(startWorldTour:)) {
return !_isTouringWorld;
}
if (menuItem.action == @selector(stopWorldTour:)) {
return _isTouringWorld;
}
if (menuItem.action == @selector(showShortcuts:)) {
return YES;
}
Expand Down Expand Up @@ -480,9 +536,12 @@ - (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem {

if (toolbarItem.action == @selector(showShareMenu:)) {
[(NSButton *)toolbarItem.view sendActionOn:NSLeftMouseDownMask];
return ([MGLAccountManager accessToken]
&& [self.mapView.styleURL.scheme isEqualToString:@"mapbox"]
&& [self.mapView.styleURL.pathComponents.firstObject isEqualToString:@"styles"]);
if (![MGLAccountManager accessToken]) {
return NO;
}
NSURL *styleURL = self.mapView.styleURL;
return ([styleURL.scheme isEqualToString:@"mapbox"]
&& [styleURL.pathComponents.firstObject isEqualToString:@"styles"]);
}
if (toolbarItem.action == @selector(setStyle:)) {
NSPopUpButton *popUpButton = (NSPopUpButton *)toolbarItem.view;
Expand Down
15 changes: 14 additions & 1 deletion platform/osx/app/MainMenu.xib
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@
<action selector="toggleRandomizesCursorsOnDroppedPins:" target="-1" id="Mpw-b8-oub"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="wQq-Mx-QY0"/>
<menuItem isSeparatorItem="YES" id="Sl5-nE-kHd"/>
<menuItem title="Blanket Map With Pins" id="LMZ-oe-Ngh">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
Expand All @@ -482,6 +482,19 @@
<action selector="removeAllPins:" target="-1" id="NRM-y5-Wul"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="wQq-Mx-QY0"/>
<menuItem title="Start World Tour" id="VFo-Jh-2sw">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startWorldTour:" target="-1" id="66Y-Gm-Yn1"/>
</connections>
</menuItem>
<menuItem title="Stop World Tour" id="Pa8-qU-xfr">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopWorldTour:" target="-1" id="aq0-7t-AGi"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
Expand Down
Loading