[core, ios, osx, android, glfw] Flipped origin of Map::latLngForPixel(), Map::pixelForLatLng()
Map and Transform methods assume an origin at the top-left corner of the view, like iOS, Android, and GLFW but unlike OS X. Transform is responsible for flipping coordinates between the top-left origin of Map and the bottom-left origin of TransformState. Fixes #3574.
This commit is contained in:
committed by
Minh Nguyễn
parent
bf87eaa7b8
commit
47b69100f9
@@ -2264,9 +2264,6 @@ public final class MapView extends FrameLayout {
|
||||
float x = point.x;
|
||||
float y = point.y;
|
||||
|
||||
// flip y direction vertically to match core GL
|
||||
y = getHeight() - y;
|
||||
|
||||
return mNativeMapView.latLngForPixel(new PointF(x / mScreenDensity, y / mScreenDensity));
|
||||
}
|
||||
|
||||
@@ -2289,9 +2286,6 @@ public final class MapView extends FrameLayout {
|
||||
float x = point.x * mScreenDensity;
|
||||
float y = point.y * mScreenDensity;
|
||||
|
||||
// flip y direction vertically to match core GL
|
||||
y = getHeight() - y;
|
||||
|
||||
return new PointF(x, y);
|
||||
}
|
||||
|
||||
|
||||
@@ -182,11 +182,11 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
|
||||
}
|
||||
|
||||
mbgl::LatLng GLFWView::makeRandomPoint() const {
|
||||
const auto sw = map->latLngForPixel({ 0, 0 });
|
||||
const auto ne = map->latLngForPixel({ double(width), double(height) });
|
||||
const auto nw = map->latLngForPixel({ 0, 0 });
|
||||
const auto se = map->latLngForPixel({ double(width), double(height) });
|
||||
|
||||
const double lon = sw.longitude + (ne.longitude - sw.longitude) * (double(std::rand()) / RAND_MAX);
|
||||
const double lat = sw.latitude + (ne.latitude - sw.latitude) * (double(std::rand()) / RAND_MAX);
|
||||
const double lon = nw.longitude + (se.longitude - nw.longitude) * (double(std::rand()) / RAND_MAX);
|
||||
const double lat = se.latitude + (nw.latitude - se.latitude) * (double(std::rand()) / RAND_MAX);
|
||||
|
||||
return { lat, lon };
|
||||
}
|
||||
@@ -368,10 +368,9 @@ void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) {
|
||||
double dx = x - view->lastX;
|
||||
double dy = y - view->lastY;
|
||||
if (dx || dy) {
|
||||
double flippedY = view->height - y;
|
||||
view->map->setLatLng(
|
||||
view->map->latLngForPixel(mbgl::PrecisionPoint(x - dx, flippedY + dy)),
|
||||
mbgl::PrecisionPoint(x, flippedY));
|
||||
view->map->latLngForPixel(mbgl::PrecisionPoint(x - dx, y + dy)),
|
||||
mbgl::PrecisionPoint(x, y));
|
||||
}
|
||||
} else if (view->rotating) {
|
||||
view->map->rotateBy({ view->lastX, view->lastY }, { x, y });
|
||||
|
||||
@@ -144,7 +144,6 @@ public:
|
||||
@property (nonatomic) UIView<MGLCalloutView> *calloutViewForSelectedAnnotation;
|
||||
@property (nonatomic) MGLUserLocationAnnotationView *userLocationAnnotationView;
|
||||
@property (nonatomic) CLLocationManager *locationManager;
|
||||
@property (nonatomic) CGPoint centerPoint;
|
||||
@property (nonatomic) CGFloat scale;
|
||||
@property (nonatomic) CGFloat angle;
|
||||
@property (nonatomic) CGFloat quickZoomStart;
|
||||
@@ -964,27 +963,15 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration)
|
||||
{
|
||||
[self trackGestureEvent:MGLEventGesturePanStart forRecognizer:pan];
|
||||
|
||||
self.centerPoint = CGPointMake(0, 0);
|
||||
|
||||
self.userTrackingMode = MGLUserTrackingModeNone;
|
||||
|
||||
[self notifyGestureDidBegin];
|
||||
}
|
||||
else if (pan.state == UIGestureRecognizerStateChanged)
|
||||
{
|
||||
CGPoint delta = CGPointMake([pan translationInView:pan.view].x - self.centerPoint.x,
|
||||
[pan translationInView:pan.view].y - self.centerPoint.y);
|
||||
|
||||
double flippedY = self.bounds.size.height - [pan locationInView:pan.view].y;
|
||||
_mbglMap->setLatLng(
|
||||
_mbglMap->latLngForPixel(mbgl::PrecisionPoint(
|
||||
[pan locationInView:pan.view].x - delta.x,
|
||||
flippedY + delta.y)),
|
||||
mbgl::PrecisionPoint(
|
||||
[pan locationInView:pan.view].x,
|
||||
flippedY));
|
||||
|
||||
self.centerPoint = CGPointMake(self.centerPoint.x + delta.x, self.centerPoint.y + delta.y);
|
||||
CGPoint delta = [pan translationInView:pan.view];
|
||||
_mbglMap->moveBy({ delta.x, delta.y });
|
||||
[pan setTranslation:CGPointZero inView:pan.view];
|
||||
|
||||
[self notifyMapChange:mbgl::MapChangeRegionIsChanging];
|
||||
}
|
||||
@@ -1946,10 +1933,6 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration)
|
||||
- (mbgl::LatLng)convertPoint:(CGPoint)point toLatLngFromView:(nullable UIView *)view
|
||||
{
|
||||
CGPoint convertedPoint = [self convertPoint:point fromView:view];
|
||||
|
||||
// Flip y coordinate for iOS view origin in the top left corner.
|
||||
convertedPoint.y = self.bounds.size.height - convertedPoint.y;
|
||||
|
||||
return _mbglMap->latLngForPixel(mbgl::PrecisionPoint(convertedPoint.x, convertedPoint.y));
|
||||
}
|
||||
|
||||
@@ -1962,10 +1945,6 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration)
|
||||
- (CGPoint)convertLatLng:(mbgl::LatLng)latLng toPointToView:(nullable UIView *)view
|
||||
{
|
||||
mbgl::vec2<double> pixel = _mbglMap->pixelForLatLng(latLng);
|
||||
|
||||
// Flip y coordinate for iOS view origin in the top left corner.
|
||||
pixel.y = self.bounds.size.height - pixel.y;
|
||||
|
||||
return [self convertPoint:CGPointMake(pixel.x, pixel.y) toView:view];
|
||||
}
|
||||
|
||||
|
||||
@@ -2133,6 +2133,8 @@ public:
|
||||
/// Converts a geographic coordinate to a point in the view’s coordinate system.
|
||||
- (NSPoint)convertLatLng:(mbgl::LatLng)latLng toPointToView:(nullable NSView *)view {
|
||||
mbgl::vec2<double> pixel = _mbglMap->pixelForLatLng(latLng);
|
||||
// Cocoa origin is at the lower-left corner.
|
||||
pixel.y = NSHeight(self.bounds) - pixel.y;
|
||||
return [self convertPoint:NSMakePoint(pixel.x, pixel.y) toView:view];
|
||||
}
|
||||
|
||||
@@ -2143,7 +2145,11 @@ public:
|
||||
/// Converts a point in the view’s coordinate system to a geographic coordinate.
|
||||
- (mbgl::LatLng)convertPoint:(NSPoint)point toLatLngFromView:(nullable NSView *)view {
|
||||
NSPoint convertedPoint = [self convertPoint:point fromView:view];
|
||||
return _mbglMap->latLngForPixel(mbgl::PrecisionPoint(convertedPoint.x, convertedPoint.y));
|
||||
return _mbglMap->latLngForPixel({
|
||||
convertedPoint.x,
|
||||
// mbgl origin is at the top-left corner.
|
||||
NSHeight(self.bounds) - convertedPoint.y,
|
||||
});
|
||||
}
|
||||
|
||||
- (NSRect)convertCoordinateBounds:(MGLCoordinateBounds)bounds toRectToView:(nullable NSView *)view {
|
||||
|
||||
@@ -259,12 +259,13 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, const Ed
|
||||
// Calculate the bounds of the possibly rotated shape with respect to the viewport.
|
||||
PrecisionPoint nePixel = {-INFINITY, -INFINITY};
|
||||
PrecisionPoint swPixel = {INFINITY, INFINITY};
|
||||
double viewportHeight = getHeight();
|
||||
for (LatLng latLng : latLngs) {
|
||||
PrecisionPoint pixel = pixelForLatLng(latLng);
|
||||
swPixel.x = std::min(swPixel.x, pixel.x);
|
||||
nePixel.x = std::max(nePixel.x, pixel.x);
|
||||
swPixel.y = std::min(swPixel.y, pixel.y);
|
||||
nePixel.y = std::max(nePixel.y, pixel.y);
|
||||
swPixel.y = std::min(swPixel.y, viewportHeight - pixel.y);
|
||||
nePixel.y = std::max(nePixel.y, viewportHeight - pixel.y);
|
||||
}
|
||||
double width = nePixel.x - swPixel.x;
|
||||
double height = nePixel.y - swPixel.y;
|
||||
@@ -289,6 +290,9 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, const Ed
|
||||
(paddedNEPixel.x + paddedSWPixel.x) / 2,
|
||||
(paddedNEPixel.y + paddedSWPixel.y) / 2,
|
||||
};
|
||||
|
||||
// CameraOptions origin is at the top-left corner.
|
||||
centerPixel.y = viewportHeight - centerPixel.y;
|
||||
|
||||
options.center = latLngForPixel(centerPixel);
|
||||
options.zoom = zoom;
|
||||
@@ -397,11 +401,11 @@ LatLng Map::latLngForProjectedMeters(const ProjectedMeters& projectedMeters) con
|
||||
}
|
||||
|
||||
PrecisionPoint Map::pixelForLatLng(const LatLng& latLng) const {
|
||||
return transform->getState().latLngToPoint(latLng);
|
||||
return transform->latLngToPoint(latLng);
|
||||
}
|
||||
|
||||
LatLng Map::latLngForPixel(const PrecisionPoint& pixel) const {
|
||||
return transform->getState().pointToLatLng(pixel);
|
||||
return transform->pointToLatLng(pixel);
|
||||
}
|
||||
|
||||
#pragma mark - Annotations
|
||||
|
||||
@@ -641,3 +641,17 @@ void Transform::cancelTransitions() {
|
||||
void Transform::setGestureInProgress(bool inProgress) {
|
||||
state.gestureInProgress = inProgress;
|
||||
}
|
||||
|
||||
#pragma mark Conversion and projection
|
||||
|
||||
PrecisionPoint Transform::latLngToPoint(const LatLng& latLng) const {
|
||||
PrecisionPoint point = state.latLngToPoint(latLng);
|
||||
point.y = state.height - point.y;
|
||||
return point;
|
||||
}
|
||||
|
||||
LatLng Transform::pointToLatLng(const PrecisionPoint& point) const {
|
||||
PrecisionPoint flippedPoint = point;
|
||||
flippedPoint.y = state.height - flippedPoint.y;
|
||||
return state.pointToLatLng(flippedPoint);
|
||||
}
|
||||
|
||||
@@ -123,6 +123,10 @@ public:
|
||||
bool isRotating() const { return state.isRotating(); }
|
||||
bool isScaling() const { return state.isScaling(); }
|
||||
bool isPanning() const { return state.isPanning(); }
|
||||
|
||||
// Conversion and projection
|
||||
PrecisionPoint latLngToPoint(const LatLng&) const;
|
||||
LatLng pointToLatLng(const PrecisionPoint&) const;
|
||||
|
||||
private:
|
||||
void unwrapLatLng(LatLng&);
|
||||
|
||||
Reference in New Issue
Block a user