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

Commit

Permalink
[core] Corrected flying trajectory; pitched flight
Browse files Browse the repository at this point in the history
Corrected some fairly opaque code that was incorrectly ported from GL JS the first time around in #3171, causing the trajectory to extend far into the Earth’s orbit. Also transition pitch while flying, call transition frame/finish callback functions, and recognize the same “speed” and “curve” parameters that GL JS does.

Fixes #3296, fixes #3297.
  • Loading branch information
1ec5 committed Dec 15, 2015
1 parent b75c6ed commit e1854f0
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 41 deletions.
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
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
102 changes: 61 additions & 41 deletions src/mbgl/map/transform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ void Transform::flyTo(const CameraOptions &options) {
LatLng startLatLng = getLatLng();
double zoom = flyOptions.zoom ? *flyOptions.zoom : getZoom();
double angle = flyOptions.angle ? *flyOptions.angle : getAngle();
double pitch = flyOptions.pitch ? *flyOptions.pitch : getPitch();
if (std::isnan(latLng.latitude) || std::isnan(latLng.longitude) || std::isnan(zoom)) {
return;
}
Expand All @@ -337,13 +338,14 @@ void Transform::flyTo(const CameraOptions &options) {

view.notifyMapChange(MapChangeRegionWillChangeAnimated);

const double startS = state.scale;
const double startZ = state.scaleZoom(state.scale);
const double startA = state.angle;
const double startP = state.pitch;
state.panning = true;
state.scaling = true;
state.rotating = true;

const double rho = 1.42;
double rho = flyOptions.curve ? *flyOptions.curve : 1.42;
double w0 = std::max(state.width, state.height);
double w1 = w0 / new_scale;
double u1 = ::hypot(xn, yn);
Expand Down Expand Up @@ -371,47 +373,65 @@ void Transform::flyTo(const CameraOptions &options) {
double S = (is_close ? (std::abs(std::log(w1 / w0)) / rho)
: ((r(1) - r0) / rho));

if (!flyOptions.duration) {
flyOptions.duration = Duration::zero();
Duration duration = flyOptions.duration ? *flyOptions.duration : Duration::zero();
if (flyOptions.duration) {
duration = *flyOptions.duration;
} else {
double speed = flyOptions.speed ? *flyOptions.speed : 1.2;
duration = std::chrono::duration_cast<std::chrono::steady_clock::duration>(
std::chrono::duration<double, std::chrono::seconds::period>(S / speed));
}
startTransition(
[=](double t) {
util::UnitBezier ease = flyOptions.easing ? *flyOptions.easing : util::UnitBezier(0, 0, 0.25, 1);
return ease.solve(t, 0.001);
},
[=](double k) {
double s = k * S;
double us = u(s);

//First calculate the desired latlng
double desiredLat = startLatLng.latitude + (latLng.latitude - startLatLng.latitude) * us;
double desiredLng = startLatLng.longitude + (latLng.longitude - startLatLng.longitude) * us;

//Now calculate desired zoom
state.scale = startS - w(s);

//Now set values
const double new_scaled_tile_size = state.scale * util::tileSize;
state.Bc = new_scaled_tile_size / 360;
state.Cc = new_scaled_tile_size / util::M2PI;

const double f2 = ::fmin(::fmax(std::sin(util::DEG2RAD * desiredLat), -m), m);
state.x = -desiredLng * state.Bc;
state.y = 0.5 * state.Cc * std::log((1 + f2) / (1 - f2));

if (angle != startA) {
state.angle = util::wrap(util::interpolate(startA, angle, k), -M_PI, M_PI);
}

view.notifyMapChange(MapChangeRegionIsChanging);
return Update::Zoom;
},
[=] {
state.panning = false;
state.scaling = false;
state.rotating = false;
view.notifyMapChange(MapChangeRegionDidChangeAnimated);
}, *flyOptions.duration);
[=](double t) {
util::UnitBezier ease = flyOptions.easing ? *flyOptions.easing : util::UnitBezier(0, 0, 0.25, 1);
return ease.solve(t, 0.001);
},
[=](double k) {
double s = k * S;
double us = u(s);

//First calculate the desired latlng
double desiredLat = startLatLng.latitude + (latLng.latitude - startLatLng.latitude) * us;
double desiredLng = startLatLng.longitude + (latLng.longitude - startLatLng.longitude) * us;

//Now calculate desired zoom
double desiredZoom = startZ + state.scaleZoom(1 / w(s));
double desiredScale = state.zoomScale(desiredZoom);
state.scale = ::fmax(::fmin(desiredScale, state.max_scale), state.min_scale);

//Now set values
const double new_scaled_tile_size = state.scale * util::tileSize;
state.Bc = new_scaled_tile_size / 360;
state.Cc = new_scaled_tile_size / util::M2PI;

const double f2 = ::fmin(::fmax(std::sin(util::DEG2RAD * desiredLat), -m), m);
state.x = -desiredLng * state.Bc;
state.y = 0.5 * state.Cc * std::log((1 + f2) / (1 - f2));

if (angle != startA) {
state.angle = util::wrap(util::interpolate(startA, angle, k), -M_PI, M_PI);
}
if (pitch != startP) {
state.pitch = util::clamp(util::interpolate(startP, pitch, k), 0., 60.);
}
// At k = 1.0, a DidChangeAnimated notification should be sent from finish().
if (k < 1.0) {
if (options.transitionFrameFn) {
options.transitionFrameFn(k);
}
view.notifyMapChange(MapChangeRegionIsChanging);
}
return Update::Zoom;
},
[=] {
state.panning = false;
state.scaling = false;
state.rotating = false;
if (options.transitionFinishFn) {
options.transitionFinishFn();
}
view.notifyMapChange(MapChangeRegionDidChangeAnimated);
}, duration);
};

#pragma mark - Angle
Expand Down
4 changes: 4 additions & 0 deletions src/mbgl/map/transform_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ double TransformState::zoomScale(double zoom) const {
return std::pow(2.0f, zoom);
}

double TransformState::scaleZoom(double s) const {
return std::log2(s);
}

float TransformState::worldSize() const {
return util::tileSize * scale;
}
Expand Down
1 change: 1 addition & 0 deletions src/mbgl/map/transform_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class TransformState {
double lngX(double lon) const;
double latY(double lat) const;
double zoomScale(double zoom) const;
double scaleZoom(double scale) const;
float worldSize() const;

mat4 coordinatePointMatrix(double z) const;
Expand Down

0 comments on commit e1854f0

Please sign in to comment.