diff options
author | Minh Nguyễn <mxn@1ec5.org> | 2015-07-30 15:34:49 -0700 |
---|---|---|
committer | Justin R. Miller <incanus@codesorcery.net> | 2015-09-07 09:22:52 -0700 |
commit | 0a172a21fdc2a87473560fd7d45f4d495d95de91 (patch) | |
tree | e4b0ccd7ee2fecdfe63ead975cbb646493ff2bb4 /include | |
parent | 584c36f348d586bd07d27e6a4c9a7f318a98044c (diff) | |
download | qtlocation-mapboxgl-0a172a21fdc2a87473560fd7d45f4d495d95de91.tar.gz |
CameraOptions
Plumbed camera options all the way through to MGLMapView. Added a method that lets you specify a direction in addition to center point and zoom level.
Added Map::jumpTo() for parity with mapbox-gl-js. Replaced usage of Map::setLatLng() and Map::setLatLngZoom() with Map::jumpTo() or Map::easeTo() within MGLMapView. Replaced MGLMapView.pitch with MGLMapCamera for setting all supported degrees of freedom simultaneously. Simultaneously move and rotate with course.
Support customizable timing functions on iOS.
iosapp now persists an archived MGLMapCamera instead of separate viewpoint properties and also synchronizes user defaults on termination. This change implements persistence entirely in Objective-C, eliminating the use of the Objective-C++ implementation.
Fixes #1643, fixes #1834. Ref #1581.
Diffstat (limited to 'include')
-rw-r--r-- | include/mbgl/ios/MGLMapCamera.h | 36 | ||||
-rw-r--r-- | include/mbgl/ios/MGLMapView.h | 26 | ||||
-rw-r--r-- | include/mbgl/ios/Mapbox.h | 1 | ||||
-rw-r--r-- | include/mbgl/map/camera.hpp | 22 | ||||
-rw-r--r-- | include/mbgl/map/map.hpp | 11 | ||||
-rw-r--r-- | include/mbgl/util/optional.hpp | 69 | ||||
-rw-r--r-- | include/mbgl/util/unitbezier.hpp | 121 |
7 files changed, 272 insertions, 14 deletions
diff --git a/include/mbgl/ios/MGLMapCamera.h b/include/mbgl/ios/MGLMapCamera.h new file mode 100644 index 0000000000..68f3923fd3 --- /dev/null +++ b/include/mbgl/ios/MGLMapCamera.h @@ -0,0 +1,36 @@ +#import "Mapbox.h" + +#pragma once + +NS_ASSUME_NONNULL_BEGIN + +/** An `MGLMapCamera` object represents a viewpoint from which the user observes some point on an `MGLMapView`. */ +@interface MGLMapCamera : NSObject <NSSecureCoding, NSCopying> + +/** Coordinate at the center of the map view. */ +@property (nonatomic) CLLocationCoordinate2D centerCoordinate; + +/** Heading measured in degrees clockwise from true north. */ +@property (nonatomic) CLLocationDirection heading; + +/** Pitch toward the horizon measured in degrees, with 0 degrees resulting in a two-dimensional map. */ +@property (nonatomic) CGFloat pitch; + +/** Meters above ground level. */ +@property (nonatomic) CLLocationDistance altitude; + +/** Returns a new camera with all properties set to 0. */ ++ (instancetype)camera; + ++ (instancetype)cameraLookingAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate + fromEyeCoordinate:(CLLocationCoordinate2D)eyeCoordinate + eyeAltitude:(CLLocationDistance)eyeAltitude; + ++ (instancetype)cameraLookingAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate + fromDistance:(CLLocationDistance)distance + pitch:(CGFloat)pitch + heading:(CLLocationDirection)heading; + +@end + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h index ba332d9845..da500f1ef6 100644 --- a/include/mbgl/ios/MGLMapView.h +++ b/include/mbgl/ios/MGLMapView.h @@ -1,4 +1,5 @@ #import "MGLGeometry.h" +#import "MGLMapCamera.h" #import <UIKit/UIKit.h> #import <CoreLocation/CoreLocation.h> @@ -6,6 +7,7 @@ NS_ASSUME_NONNULL_BEGIN @class MGLAnnotationImage; +@class MGLMapCamera; @class MGLUserLocation; @class MGLPolyline; @class MGLPolygon; @@ -136,6 +138,8 @@ IB_DESIGNABLE * @param animated Specify `YES` if you want the map view to animate scrolling and zooming to the new location or `NO` if you want the map to display the new location immediately. */ - (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel animated:(BOOL)animated; +- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction animated:(BOOL)animated; + /** The coordinate bounds visible in the receiver’s viewport. * * Changing the value of this property updates the receiver immediately. If you want to animate the change, call `setVisibleCoordinateBounds:animated:` instead. */ @@ -181,19 +185,19 @@ IB_DESIGNABLE /** Resets the map rotation to a northern heading. */ - (IBAction)resetNorth; -/** The pitch of the map (measured in degrees). - * - * The default value `0` shows a completely flat map. Maximum value is `60`. */ -@property (nonatomic) double pitch; +/** A camera representing the current viewpoint of the map. */ +@property (nonatomic, copy) MGLMapCamera *camera; -/** Changes the pitch of the map. - * @param pitch The pitch of the map (measured in degrees) relative to top-down. - * - * Changing the pitch tilts the map without changing the current center coordinate or zoom level. */ -- (void)setPitch:(double)pitch; +/** Moves the viewpoint to a different location with respect to the map with an optional transition animation. +* @param camera The new viewpoint. +* @param animated Specify `YES` if you want the map view to animate the change to the new viewpoint or `NO` if you want the map to display the new viewpoint immediately. */ +- (void)setCamera:(MGLMapCamera *)camera animated:(BOOL)animated; -/** Resets the map pitch to head-on. */ -- (IBAction)resetPitch; +/** Moves the viewpoint to a different location with respect to the map with an optional transition duration and timing function. +* @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 function A timing function used for the animation. Set this parameter to `nil` for a transition that matches most system animations. If the duration is `0`, this parameter is ignored. */ +- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function; #pragma mark - Converting Map Coordinates diff --git a/include/mbgl/ios/Mapbox.h b/include/mbgl/ios/Mapbox.h index 401a62e82e..f05f0c8429 100644 --- a/include/mbgl/ios/Mapbox.h +++ b/include/mbgl/ios/Mapbox.h @@ -1,6 +1,7 @@ #import "MGLAccountManager.h" #import "MGLAnnotation.h" #import "MGLAnnotationImage.h" +#import "MGLMapCamera.h" #import "MGLGeometry.h" #import "MGLMapView.h" #import "MGLMultiPoint.h" diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp new file mode 100644 index 0000000000..bd0b353bae --- /dev/null +++ b/include/mbgl/map/camera.hpp @@ -0,0 +1,22 @@ +#ifndef MBGL_MAP_CAMERA +#define MBGL_MAP_CAMERA + +#include <mbgl/util/geo.hpp> +#include <mbgl/util/optional.hpp> +#include <mbgl/util/chrono.hpp> +#include <mbgl/util/unitbezier.hpp> + +namespace mbgl { + +struct CameraOptions { + mapbox::util::optional<LatLng> center; + mapbox::util::optional<double> zoom; + mapbox::util::optional<double> angle; + mapbox::util::optional<double> pitch; + mapbox::util::optional<Duration> duration; + mapbox::util::optional<mbgl::util::UnitBezier> easing; +}; + +} + +#endif /* MBGL_MAP_CAMERA */ diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index ddf86045ee..4cd9293c9b 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -2,6 +2,7 @@ #define MBGL_MAP_MAP #include <mbgl/util/chrono.hpp> +#include <mbgl/map/camera.hpp> #include <mbgl/map/update.hpp> #include <mbgl/map/mode.hpp> #include <mbgl/util/geo.hpp> @@ -94,6 +95,10 @@ public: void cancelTransitions(); void setGestureInProgress(bool); + // Camera + void jumpTo(CameraOptions options); + void easeTo(CameraOptions options); + // Position void moveBy(double dx, double dy, const Duration& = Duration::zero()); void setLatLng(LatLng latLng, const Duration& = Duration::zero()); @@ -107,8 +112,8 @@ public: void setZoom(double zoom, const Duration& = Duration::zero()); double getZoom() const; void setLatLngZoom(LatLng latLng, double zoom, const Duration& = Duration::zero()); - void fitBounds(LatLngBounds bounds, EdgeInsets padding, const Duration& duration = Duration::zero()); - void fitBounds(AnnotationSegment segment, EdgeInsets padding, const Duration& duration = Duration::zero()); + CameraOptions cameraForLatLngBounds(LatLngBounds bounds, EdgeInsets padding); + CameraOptions cameraForLatLngs(std::vector<LatLng> latLngs, EdgeInsets padding); void resetZoom(); double getMinZoom() const; double getMaxZoom() const; @@ -121,7 +126,7 @@ public: void resetNorth(); // Pitch - void setPitch(double pitch); + void setPitch(double pitch, const Duration& = Duration::zero()); double getPitch() const; // Size diff --git a/include/mbgl/util/optional.hpp b/include/mbgl/util/optional.hpp new file mode 100644 index 0000000000..8d46eae857 --- /dev/null +++ b/include/mbgl/util/optional.hpp @@ -0,0 +1,69 @@ +#ifndef MAPBOX_UTIL_OPTIONAL_HPP +#define MAPBOX_UTIL_OPTIONAL_HPP + +#include <type_traits> + +#include <mbgl/util/variant.hpp> + +namespace mapbox +{ +namespace util +{ + +template <typename T> class optional +{ + static_assert(!std::is_reference<T>::value, "optional doesn't support references"); + + struct none_type + { + }; + + variant<none_type, T> variant_; + + public: + optional() = default; + + optional(optional const &rhs) + { + if (this != &rhs) + { // protect against invalid self-assignment + variant_ = rhs.variant_; + } + } + + optional(T const &v) { variant_ = v; } + + explicit operator bool() const noexcept { return variant_.template is<T>(); } + + T const &get() const { return variant_.template get<T>(); } + T &get() { return variant_.template get<T>(); } + + T const &operator*() const { return this->get(); } + T operator*() { return this->get(); } + + optional &operator=(T const &v) + { + variant_ = v; + return *this; + } + + optional &operator=(optional const &rhs) + { + if (this != &rhs) + { + variant_ = rhs.variant_; + } + return *this; + } + + template <typename... Args> void emplace(Args &&... args) + { + variant_ = T{std::forward<Args>(args)...}; + } + + void reset() { variant_ = none_type{}; } +}; +} +} + +#endif diff --git a/include/mbgl/util/unitbezier.hpp b/include/mbgl/util/unitbezier.hpp new file mode 100644 index 0000000000..095e15f809 --- /dev/null +++ b/include/mbgl/util/unitbezier.hpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MBGL_UTIL_UNITBEZIER +#define MBGL_UTIL_UNITBEZIER + +#include <cmath> + +namespace mbgl { +namespace util { + +struct UnitBezier { + UnitBezier(double p1x, double p1y, double p2x, double p2y) { + // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1). + cx = 3.0 * p1x; + bx = 3.0 * (p2x - p1x) - cx; + ax = 1.0 - cx - bx; + + cy = 3.0 * p1y; + by = 3.0 * (p2y - p1y) - cy; + ay = 1.0 - cy - by; + } + + double sampleCurveX(double t) { + // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule. + return ((ax * t + bx) * t + cx) * t; + } + + double sampleCurveY(double t) { + return ((ay * t + by) * t + cy) * t; + } + + double sampleCurveDerivativeX(double t) { + return (3.0 * ax * t + 2.0 * bx) * t + cx; + } + + // Given an x value, find a parametric value it came from. + double solveCurveX(double x, double epsilon) { + double t0; + double t1; + double t2; + double x2; + double d2; + int i; + + // First try a few iterations of Newton's method -- normally very fast. + for (t2 = x, i = 0; i < 8; ++i) { + x2 = sampleCurveX(t2) - x; + if (fabs (x2) < epsilon) + return t2; + d2 = sampleCurveDerivativeX(t2); + if (fabs(d2) < 1e-6) + break; + t2 = t2 - x2 / d2; + } + + // Fall back to the bisection method for reliability. + t0 = 0.0; + t1 = 1.0; + t2 = x; + + if (t2 < t0) + return t0; + if (t2 > t1) + return t1; + + while (t0 < t1) { + x2 = sampleCurveX(t2); + if (fabs(x2 - x) < epsilon) + return t2; + if (x > x2) + t0 = t2; + else + t1 = t2; + t2 = (t1 - t0) * .5 + t0; + } + + // Failure. + return t2; + } + + double solve(double x, double epsilon) { + return sampleCurveY(solveCurveX(x, epsilon)); + } + +private: + double ax; + double bx; + double cx; + + double ay; + double by; + double cy; +}; + +} +} + +#endif |