[core] Limit pitch based on edge insets. Fix max Z calculation in getProjMatrix.
Patch partly fixes #15163 in a way that it doesn't allow loading tens of thousands of tiles and attempt to show area above horizon: Limit pitch based on edge insets. It is not too bad - current limit of 60 degrees stays active until center of perspective is moved towards the bottom, to 84% of screen height. The plan is to split removal of 60 degrees limit to follow up patch. Fix max Z calculation in getProjMatrix. TransformState::getProjMatrix calculation of farZ was complex with possibility to lead to negative z values. Replacing it with simpler, precise calculation: furthestDistance = cameraToCenterDistance / (1 - tanFovAboveCenter * std::tan(getPitch())); TransformState::getProjMatrix calculation of farZ was an aproximation. Replacing it with simpler, but precise calculation. Related to: #15163
This commit is contained in:
@@ -138,9 +138,6 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
|
||||
if (bearing != startBearing) {
|
||||
state.bearing = util::wrap(util::interpolate(startBearing, bearing, t), -M_PI, M_PI);
|
||||
}
|
||||
if (pitch != startPitch) {
|
||||
state.pitch = util::interpolate(startPitch, pitch, t);
|
||||
}
|
||||
if (padding != startEdgeInsets) {
|
||||
// Interpolate edge insets
|
||||
state.edgeInsets = {
|
||||
@@ -150,6 +147,10 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
|
||||
util::interpolate(startEdgeInsets.right(), padding.right(), t)
|
||||
};
|
||||
}
|
||||
auto maxPitch = getMaxPitchForEdgeInsets(state.edgeInsets);
|
||||
if (pitch != startPitch || maxPitch < startPitch) {
|
||||
state.pitch = std::min(maxPitch, util::interpolate(startPitch, pitch, t));
|
||||
}
|
||||
}, duration);
|
||||
}
|
||||
|
||||
@@ -302,9 +303,6 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
|
||||
if (bearing != startBearing) {
|
||||
state.bearing = util::wrap(util::interpolate(startBearing, bearing, k), -M_PI, M_PI);
|
||||
}
|
||||
if (pitch != startPitch) {
|
||||
state.pitch = util::interpolate(startPitch, pitch, k);
|
||||
}
|
||||
if (padding != startEdgeInsets) {
|
||||
// Interpolate edge insets
|
||||
state.edgeInsets = {
|
||||
@@ -314,6 +312,10 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
|
||||
util::interpolate(startEdgeInsets.right(), padding.right(), us)
|
||||
};
|
||||
}
|
||||
auto maxPitch = getMaxPitchForEdgeInsets(state.edgeInsets);
|
||||
if (pitch != startPitch || maxPitch < startPitch) {
|
||||
state.pitch = std::min(maxPitch, util::interpolate(startPitch, pitch, k));
|
||||
}
|
||||
}, duration);
|
||||
}
|
||||
|
||||
@@ -576,4 +578,21 @@ LatLng Transform::screenCoordinateToLatLng(const ScreenCoordinate& point, LatLng
|
||||
return state.screenCoordinateToLatLng(flippedPoint, wrapMode);
|
||||
}
|
||||
|
||||
double Transform::getMaxPitchForEdgeInsets(const EdgeInsets &insets) const
|
||||
{
|
||||
double centerOffsetY = 0.5 * (insets.top() - insets.bottom()); // See TransformState::getCenterOffset.
|
||||
|
||||
const auto height = state.size.height;
|
||||
assert(height);
|
||||
// For details, see description at https://github.com/mapbox/mapbox-gl-native/pull/15195
|
||||
// The definition of half of TransformState::fov with no inset, is: fov = arctan((height / 2) / (height * 1.5)).
|
||||
// We use half of fov, as it is field of view above perspective center.
|
||||
// With inset, this angle changes and tangentOfFovAboveCenterAngle = (h/2 + centerOffsetY) / (height * 1.5).
|
||||
// 1.03 is a bit extra added to prevent parallel ground to viewport clipping plane.
|
||||
const double tangentOfFovAboveCenterAngle = 1.03 * (height / 2.0 + centerOffsetY) / (1.5 * height);
|
||||
const double fovAboveCenter = std::atan(tangentOfFovAboveCenterAngle);
|
||||
return M_PI * 0.5 - fovAboveCenter;
|
||||
// e.g. Maximum pitch of 60 degrees is when perspective center's offset from the top is 84% of screen height.
|
||||
}
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
Reference in New Issue
Block a user