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

Commit

Permalink
[ios, macos] Fixed camera initialization with eye coordinate
Browse files Browse the repository at this point in the history
Rewrote the code that calculates the heading and pitch of the camera when given an eye coordinate.
  • Loading branch information
1ec5 committed Oct 2, 2018
1 parent 85a474e commit a9dc1b5
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 11 deletions.
22 changes: 11 additions & 11 deletions platform/darwin/src/MGLMapCamera.mm
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#import "MGLMapCamera.h"
#import "MGLGeometry_Private.h"

#include <mbgl/util/projection.hpp>
#import <CoreLocation/CoreLocation.h>

#include <mbgl/math/wrap.hpp>

BOOL MGLEqualFloatWithAccuracy(CGFloat left, CGFloat right, CGFloat accuracy)
{
Expand All @@ -27,17 +29,15 @@ + (instancetype)cameraLookingAtCenterCoordinate:(CLLocationCoordinate2D)centerCo
CLLocationDirection heading = -1;
CGFloat pitch = -1;
if (CLLocationCoordinate2DIsValid(centerCoordinate) && CLLocationCoordinate2DIsValid(eyeCoordinate)) {
mbgl::LatLng centerLatLng = MGLLatLngFromLocationCoordinate2D(centerCoordinate);
mbgl::LatLng eyeLatLng = MGLLatLngFromLocationCoordinate2D(eyeCoordinate);

mbgl::ProjectedMeters centerMeters = mbgl::Projection::projectedMetersForLatLng(centerLatLng);
mbgl::ProjectedMeters eyeMeters = mbgl::Projection::projectedMetersForLatLng(eyeLatLng);
heading = std::atan((centerMeters.northing() - eyeMeters.northing()) /
(centerMeters.easting() - eyeMeters.easting()));
heading = MGLDirectionBetweenCoordinates(eyeCoordinate, centerCoordinate);

double groundDistance = std::hypot(centerMeters.northing() - eyeMeters.northing(),
centerMeters.easting() - eyeMeters.easting());
pitch = std::atan(eyeAltitude / groundDistance);
CLLocation *centerLocation = [[CLLocation alloc] initWithLatitude:centerCoordinate.latitude
longitude:centerCoordinate.longitude];
CLLocation *eyeLocation = [[CLLocation alloc] initWithLatitude:eyeCoordinate.latitude
longitude:eyeCoordinate.longitude];
CLLocationDistance groundDistance = [eyeLocation distanceFromLocation:centerLocation];
CGFloat radianPitch = atan2(eyeAltitude, groundDistance);
pitch = mbgl::util::wrap(90 - MGLDegreesFromRadians(radianPitch), 0.0, 360.0);
}

return [[self alloc] initWithCenterCoordinate:centerCoordinate
Expand Down
39 changes: 39 additions & 0 deletions platform/darwin/test/MGLMapCameraTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,45 @@ @interface MGLMapCameraTests : XCTestCase

@implementation MGLMapCameraTests

- (void)testEyeCoordinateInitialization {
CLLocationCoordinate2D fountainSquare = CLLocationCoordinate2DMake(39.10152215, -84.5124439696089);
CLLocationCoordinate2D unionTerminal = CLLocationCoordinate2DMake(39.10980955, -84.5352778794236);

MGLMapCamera *camera = [MGLMapCamera cameraLookingAtCenterCoordinate:fountainSquare
fromEyeCoordinate:fountainSquare
eyeAltitude:1000];
MKMapCamera *mkCamera = [MKMapCamera cameraLookingAtCenterCoordinate:fountainSquare
fromEyeCoordinate:fountainSquare
eyeAltitude:1000];
XCTAssertEqual(camera.centerCoordinate.latitude, fountainSquare.latitude);
XCTAssertEqual(camera.centerCoordinate.longitude, fountainSquare.longitude);
XCTAssertEqual(camera.centerCoordinate.latitude, mkCamera.centerCoordinate.latitude);
XCTAssertEqual(camera.centerCoordinate.longitude, mkCamera.centerCoordinate.longitude);
XCTAssertEqual(camera.altitude, 1000, @"Eye altitude should be equivalent to altitude in untilted camera.");
XCTAssertEqual(camera.altitude, mkCamera.altitude, @"Eye altitude in untilted camera should match MapKit.");
XCTAssertEqual(camera.pitch, 0, @"Camera directly over center coordinate should be untilted.");
XCTAssertEqual(camera.pitch, mkCamera.pitch, @"Camera directly over center coordinate should have same pitch as MapKit.");
XCTAssertEqual(camera.heading, 0, @"Camera directly over center coordinate should be unrotated.");
XCTAssertEqual(camera.heading, mkCamera.heading, @"Camera directly over center coordinate should have same heading as MapKit.");

camera = [MGLMapCamera cameraLookingAtCenterCoordinate:fountainSquare
fromEyeCoordinate:unionTerminal
eyeAltitude:1000];
mkCamera = [MKMapCamera cameraLookingAtCenterCoordinate:fountainSquare
fromEyeCoordinate:unionTerminal
eyeAltitude:1000];
XCTAssertEqual(camera.centerCoordinate.latitude, fountainSquare.latitude);
XCTAssertEqual(camera.centerCoordinate.longitude, fountainSquare.longitude);
XCTAssertEqual(camera.centerCoordinate.latitude, mkCamera.centerCoordinate.latitude);
XCTAssertEqual(camera.centerCoordinate.longitude, mkCamera.centerCoordinate.longitude);
XCTAssertEqual(camera.altitude, 1000);
XCTAssertEqual(camera.altitude, mkCamera.altitude, @"Eye altitude in tilted camera should match MapKit.");
XCTAssertEqualWithAccuracy(camera.pitch, 65.3469146074, 0.01);
XCTAssertEqual(camera.pitch, mkCamera.pitch);
XCTAssertEqualWithAccuracy(camera.heading, 115.066396383, 0.01);
XCTAssertEqualWithAccuracy(camera.heading, mkCamera.heading, 0.01);
}

- (void)testViewingDistanceInitialization {
CLLocationCoordinate2D fountainSquare = CLLocationCoordinate2DMake(39.10152215, -84.5124439696089);
MGLMapCamera *camera = [MGLMapCamera cameraLookingAtCenterCoordinate:fountainSquare
Expand Down

0 comments on commit a9dc1b5

Please sign in to comment.