-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Fix MGLMapCamera initialization and viewing distance calculations #12966
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't wait to see if this works with my animations. A few fixes to make. Let me know when you're ready
platform/darwin/src/MGLMapCamera.mm
Outdated
CLLocationDirection eyeAngle = 360 - groundAngle - pitch; | ||
CLLocationDistance altitude = self.altitude; | ||
// Solution of triangles given angle-side-angle. | ||
return altitude * sin(groundAngle) / (sin(groundAngle) * cos(eyeAngle) + sin(eyeAngle) * cos(groundAngle)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These angles need to be converted to radians
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch – more reason for me to unit test this thing. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spotted #12967 along the way.
platform/darwin/src/MGLMapCamera.mm
Outdated
CLLocationDirection eyeAngle = 360 - groundAngle - pitch; | ||
CLLocationDistance altitude = self.altitude; | ||
// Solution of triangles given angle-side-angle. | ||
return altitude * sin(groundAngle) / (sin(groundAngle) * cos(eyeAngle) + sin(eyeAngle) * cos(groundAngle)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
groundAngle = PI/2, sin(PI/2) = 1 and cos(PI/2) = 0.
This equation is effectively altitude / cos(eyeAngle) which produces a negative number.
I think eyeAngle is meant to be the difference between the pitch value and 90.
Try this:
- (CLLocationDistance)viewingDistance {
CLLocationDirection eyeAngleFromGround = 90 - self.pitch;
CGFloat eyeAngleFromGroundRadians = eyeAngleFromGround * M_PI_2 / 180;
CLLocationDistance altitude = self.altitude;
return altitude / sin(eyeAngleFromGroundRadians)
}
34c2425
to
4413e82
Compare
Thanks for your feedback, @d-prukop. I’ve fixed the issues you pointed out and added tests. |
4413e82
to
8577a32
Compare
correctlyFromDistance:10000 | ||
pitch:0 | ||
heading:0]; | ||
MKMapCamera *mkCamera = [MKMapCamera cameraLookingAtCenterCoordinate:fountainSquare |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I can tell, this is the first time we’re explicitly testing the iOS/macOS SDK against MapKit. I think we should try to test against MapKit like this whenever an API is intended to match a MapKit API one-for-one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
I went ahead and fixed #12967 too. |
This doesn't quite address my problems with MGLCamera. There is still wierd behavior when animating viewingDistance and pitch at the same time. I'm going to ask that we still merge in #12938 until we can come up with a more comprehensive solution. |
platform/darwin/src/MGLMapCamera.h
Outdated
@@ -63,10 +78,47 @@ MGL_EXPORT | |||
The value `180` means the top of the map points due south, and so on. | |||
*/ | |||
+ (instancetype)cameraLookingAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate | |||
fromDistance:(CLLocationDistance)distance | |||
correctlyFromDistance:(CLLocationDistance)distance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible avoid the correctly
word? what are your thoughts on fromLineOfSightDistance
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered fromLineOfSightDistance
, but it bridges to Swift as fromLineOfSight
, which is unfortunate. “Correctly” is also unfortunate, but I’m hopeful that it would be temporary and that we’d swap it in for fromDistance
at the next available opportunity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another possibility would be acrossDistance
, which bridges to Swift elegantly as across
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm inclined for acrossDistance
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like having the word distance in there - can we use NS_SWIFT_NAME in this case? To throw some more out there, perhaps withSubjectDistance
, fromViewDistance
, withCameraAtDistance
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like having the word distance in there
Forcing the word “distance” would violate Swift API naming guidelines. The Swift compiler is doing the right thing here, since the type is CLLocationDistance
. I’ll go with acrossDistance
in Objective-C, which bridges to Swift as across
; none of the other suggestions to a better job of distinguishing between viewing distance and viewing altitude anyways.
Is this the same behavior seen in the “before” screen recording in #12938 (comment)? If so, can you ensure that |
f42bbd4
to
4a13bd7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be great if we could find an alternative to across
(which isn't particularly clear to me - it feels more like the "adjacent" rather than the hypotenuse).
@@ -63,10 +85,46 @@ MGL_EXPORT | |||
The value `180` means the top of the map points due south, and so on. | |||
*/ | |||
+ (instancetype)cameraLookingAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate | |||
fromDistance:(CLLocationDistance)distance | |||
acrossDistance:(CLLocationDistance)distance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make it clear that the across
distance here is the same as the viewingDistance
above? Either by documentation, by an alternative parameter name?
If we don't want to explicitly use viewingDistance
due to Swift bridging, are there any alternatives that would be clearer? radius
, orbit
, span
? Actually I quite like radius
in this context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m not sure any of those alternatives distinguishes between the hypotenuse and adjacent any more than acrossDistance
would, but I just don’t think that distinction is very important. Consider that the original method – which I want to return to eventually, once we remove the incorrect implementation – calls it fromDistance
, for simplicity and consistency with MapKit. The point is to distinguish from the opposite (altitude), which all these options accomplish to varying degrees. (The property, meanwhile, is still called viewingDistance
– do you think it needs to be revisited?)
If acrossDistance
doesn’t work, then my next suggestion would be -cameraLookingAtDistance:toCoordinate:pitch:heading:
(camera(lookingAt:to:pitch:heading:)
) or something like that. But honestly, I keep getting frustrated because all the good ways to express this concept in English require putting a word after the quantity (e.g., “from … away”), which doesn’t work here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep - I totally hear you about language frustrations. I think the truth is that we have the best one, it's just that we need to deprecate it first before re-using it! 🔀
Let's get this one in 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, for what it’s worth, there is a more detailed explanation of this parameter a few lines further up:
mapbox-gl-native/platform/darwin/src/MGLMapCamera.h
Lines 71 to 73 in 44aa4f4
This method interprets the distance as a straight-line distance from the | |
viewpoint to the center coordinate. To specify the altitude of the viewpoint, | |
use the `-cameraLookingAtCenterCoordinate:altitude:pitch:heading:` method. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🏼
+[MGLMapCamera cameraLookingAtCenterCoordinate:fromDistance:pitch:heading:] incorrectly treated the distance as an altitude. Due to backwards compatibility concerns, this method can’t be fixed in place. Instead, separate +[MGLMapCamera cameraLookingAtCenterCoordinate:correctlyFromDistance:pitch:heading:] and +[MGLMapCamera cameraLookingAtCenterCoordinate:altitude:pitch:heading:] methods have been added.
Co-authored-by: Dave Prukop <dave.prukop@mapbox.com>
Rewrote the code that calculates the heading and pitch of the camera when given an eye coordinate.
4a13bd7
to
44aa4f4
Compare
MGLMapCamera can now be expressed in terms of viewing distance.
+[MGLMapCamera cameraLookingAtCenterCoordinate:fromDistance:pitch:heading:]
incorrectly treated the distance as an altitude. Due to backwards compatibility concerns, this method can’t be fixed in place until the next semver-major release. Instead, separate+cameraLookingAtCenterCoordinate:correctlyFromDistance:pitch:heading:
and+cameraLookingAtCenterCoordinate:altitude:pitch:heading:
methods have been added, and the original method has been deprecated to head-off continuing confusion.A
viewingDistance
property has been added to MGLMapCamera. This property is computed from thealtitude
andpitch
properties, so there isn’t any parallel state to keep track of. The benefit of this approach over #12938 is that there are fewer, more testable code paths, and developers using this SDK can officially take advantage of theviewingDistance
property without having to forward-declare anything. One can imagine aneyeCoordinate
property being added along the same lines in the future.Rewrote
+[MGLMapCamera cameraLookingAtCenterCoordinate:fromEyeCoordinate:eyeAltitude:]
to produce the right heading and pitch (and thus respect the specified eye coordinate).Please double-check my trigonometry.
I still need to add unit tests before this PR can land.Fixes #12943 and fixes #12967. Supersedes #12938 and part of #12518.
/cc @d-prukop @fabian-guerra @julianrex