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

Commit

Permalink
[core] Tighten LatLng and other geo.hpp classes
Browse files Browse the repository at this point in the history
* Remove LatLng::null and enforce invariants
* Remove unnecessary operator bool()
  • Loading branch information
jfirebaugh committed Jun 15, 2016
1 parent a0b2982 commit 043bf80
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 90 deletions.
30 changes: 10 additions & 20 deletions include/mbgl/util/geo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <mapbox/geometry/box.hpp>

#include <cmath>
#include <stdexcept>

namespace mbgl {

Expand All @@ -21,17 +22,19 @@ using ScreenBox = mapbox::geometry::box<double>;

class LatLng {
public:
struct null {};

double latitude;
double longitude;

enum WrapMode : bool { Unwrapped, Wrapped };

LatLng(null) : latitude(std::numeric_limits<double>::quiet_NaN()), longitude(latitude) {}

LatLng(double lat = 0, double lon = 0, WrapMode mode = Unwrapped)
: latitude(lat), longitude(lon) { if (mode == Wrapped) wrap(); }
: latitude(lat), longitude(lon) {
if (std::isnan(lat)) throw std::domain_error("latitude must not be NaN");
if (std::isnan(lon)) throw std::domain_error("longitude must not be NaN");
if (std::abs(lat) > 90.0) throw std::domain_error("latitude must be between -90 and 90");
if (!std::isfinite(lon)) throw std::domain_error("longitude must not be infinite");
if (mode == Wrapped) wrap();
}

LatLng wrapped() const { return { latitude, longitude, Wrapped }; }

Expand All @@ -48,10 +51,6 @@ class LatLng {
else if (longitude < 0 && end.longitude > 0) longitude += util::DEGREES_MAX;
}

explicit operator bool() const {
return !(std::isnan(latitude) || std::isnan(longitude));
}

// Constructs a LatLng object with the top left position of the specified tile.
LatLng(const CanonicalTileID& id);
LatLng(const UnwrappedTileID& id);
Expand All @@ -72,10 +71,6 @@ class ProjectedMeters {

ProjectedMeters(double n = 0, double e = 0)
: northing(n), easting(e) {}

explicit operator bool() const {
return !(std::isnan(northing) || std::isnan(easting));
}
};

inline bool operator==(const ProjectedMeters& a, const ProjectedMeters& b) {
Expand Down Expand Up @@ -193,14 +188,9 @@ class EdgeInsets {
double right = 0; ///< Number of pixels inset from the right edge.

EdgeInsets() {}

EdgeInsets(const double t, const double l, const double b, const double r)
: top(t), left(l), bottom(b), right(r) {}

explicit operator bool() const {
return !(std::isnan(top) || std::isnan(left) || std::isnan(bottom) || std::isnan(right))
&& (top || left || bottom || right);
}

void operator+=(const EdgeInsets& o) {
top += o.top;
Expand All @@ -214,7 +204,7 @@ class EdgeInsets {
top + o.top, left + o.left, bottom + o.bottom, right + o.right,
};
}

ScreenCoordinate getCenter(uint16_t width, uint16_t height) const;
};

Expand Down
6 changes: 3 additions & 3 deletions src/mbgl/map/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, optional
// Calculate the zoom level.
double scaleX = getWidth() / width;
double scaleY = getHeight() / height;
if (padding && *padding) {
if (padding) {
scaleX -= (padding->left + padding->right) / width;
scaleY -= (padding->top + padding->bottom) / height;
}
Expand All @@ -515,7 +515,7 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, optional

// Calculate the center point of a virtual bounds that is extended in all directions by padding.
ScreenCoordinate centerPixel = nePixel + swPixel;
if (padding && *padding) {
if (padding) {
ScreenCoordinate paddedNEPixel = {
padding->right / minScale,
padding->top / minScale,
Expand Down Expand Up @@ -580,7 +580,7 @@ void Map::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second
}

void Map::setBearing(double degrees, const Duration& duration) {
setBearing(degrees, EdgeInsets(), duration);
setBearing(degrees, optional<EdgeInsets>(), duration);
}

void Map::setBearing(double degrees, optional<ScreenCoordinate> anchor, const Duration& duration) {
Expand Down
35 changes: 13 additions & 22 deletions src/mbgl/map/transform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,12 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
double angle = camera.angle.value_or(getAngle());
double pitch = camera.pitch.value_or(getPitch());

if (!latLng || std::isnan(zoom)) {
if (std::isnan(zoom)) {
return;
}

// Determine endpoints.
EdgeInsets padding;
if (camera.padding) padding = *camera.padding;
optional<EdgeInsets> padding = camera.padding;
LatLng startLatLng = getLatLng(padding);
// If gesture in progress, we transfer the world rounds from the end
// longitude into start, so we can guarantee the "scroll effect" of rounding
Expand Down Expand Up @@ -176,13 +175,12 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
double angle = camera.angle.value_or(getAngle());
double pitch = camera.pitch.value_or(getPitch());

if (!latLng || std::isnan(zoom)) {
if (std::isnan(zoom)) {
return;
}

// Determine endpoints.
EdgeInsets padding;
if (camera.padding) padding = *camera.padding;
optional<EdgeInsets> padding = camera.padding;
LatLng startLatLng = getLatLng(padding).wrapped();
startLatLng.unwrapForShortestPath(latLng);

Expand All @@ -206,9 +204,9 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima

/// w₀: Initial visible span, measured in pixels at the initial scale.
/// Known henceforth as a <i>screenful</i>.
double w0 = padding ? std::max(state.width, state.height)
: std::max(state.width - padding.left - padding.right,
state.height - padding.top - padding.bottom);
double w0 = padding ? std::max(state.width - padding->left - padding->right,
state.height - padding->top - padding->bottom)
: std::max(state.width, state.height);
/// w₁: Final visible span, measured in pixels with respect to the initial
/// scale.
double w1 = w0 / state.zoomScale(zoom - startZoom);
Expand Down Expand Up @@ -346,34 +344,27 @@ void Transform::setLatLng(const LatLng& latLng, const Duration& duration) {
}

void Transform::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const Duration& duration) {
if (!latLng) return;
CameraOptions camera;
camera.center = latLng;
camera.padding = padding;
easeTo(camera, duration);
}

void Transform::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const Duration& duration) {
if (!latLng) return;
CameraOptions camera;
camera.center = latLng;
if (anchor) {
EdgeInsets padding;
padding.top = anchor->y;
padding.left = anchor->x;
padding.bottom = state.height - anchor->y;
padding.right = state.width - anchor->x;
if (padding) camera.padding = padding;
camera.padding = EdgeInsets(anchor->y, anchor->x, state.height - anchor->y, state.width - anchor->x);
}
easeTo(camera, duration);
}

void Transform::setLatLngZoom(const LatLng& latLng, double zoom, const Duration& duration) {
setLatLngZoom(latLng, zoom, EdgeInsets {}, duration);
setLatLngZoom(latLng, zoom, optional<EdgeInsets>(), duration);
}

void Transform::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const Duration& duration) {
if (!latLng || std::isnan(zoom)) return;
if (std::isnan(zoom)) return;

CameraOptions camera;
camera.center = latLng;
Expand All @@ -383,15 +374,15 @@ void Transform::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeIn
}

LatLng Transform::getLatLng(optional<EdgeInsets> padding) const {
if (padding && *padding) {
if (padding) {
return screenCoordinateToLatLng(padding->getCenter(state.width, state.height));
} else {
return state.getLatLng();
}
}

ScreenCoordinate Transform::getScreenCoordinate(optional<EdgeInsets> padding) const {
if (padding && *padding) {
if (padding) {
return padding->getCenter(state.width, state.height);
} else {
return { state.width / 2., state.height / 2. };
Expand Down Expand Up @@ -494,7 +485,7 @@ void Transform::setAngle(double angle, optional<ScreenCoordinate> anchor, const

void Transform::setAngle(double angle, optional<EdgeInsets> padding, const Duration& duration) {
optional<ScreenCoordinate> anchor;
if (padding && *padding) anchor = getScreenCoordinate(padding);
if (padding) anchor = getScreenCoordinate(padding);
setAngle(angle, anchor, duration);
}

Expand Down
46 changes: 1 addition & 45 deletions test/map/transform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,40 +44,6 @@ TEST(Transform, InvalidScale) {
ASSERT_DOUBLE_EQ(2, transform.getScale());
}

TEST(Transform, InvalidLatLng) {
Transform transform;

ASSERT_DOUBLE_EQ(0, transform.getLatLng().latitude);
ASSERT_DOUBLE_EQ(0, transform.getLatLng().longitude);
ASSERT_DOUBLE_EQ(1, transform.getScale());

transform.setScale(2 << 0);
transform.setLatLng({ 8, 10 });

ASSERT_DOUBLE_EQ(8, transform.getLatLng().latitude);
ASSERT_DOUBLE_EQ(10, transform.getLatLng().longitude);
ASSERT_DOUBLE_EQ(2, transform.getScale());

transform.setLatLngZoom({ 10, 8 }, 2);

ASSERT_DOUBLE_EQ(10, transform.getLatLng().latitude);
ASSERT_DOUBLE_EQ(8, transform.getLatLng().longitude);
ASSERT_DOUBLE_EQ(4, transform.getScale());

const double invalid = std::nan("");
transform.setLatLngZoom({ invalid, 8 }, 2);

ASSERT_DOUBLE_EQ(10, transform.getLatLng().latitude);
ASSERT_DOUBLE_EQ(8, transform.getLatLng().longitude);
ASSERT_DOUBLE_EQ(4, transform.getScale());

transform.setLatLngZoom({ 10, invalid }, 2);

ASSERT_DOUBLE_EQ(10, transform.getLatLng().latitude);
ASSERT_DOUBLE_EQ(8, transform.getLatLng().longitude);
ASSERT_DOUBLE_EQ(4, transform.getScale());
}


TEST(Transform, InvalidBearing) {
Transform transform;
Expand Down Expand Up @@ -320,17 +286,7 @@ TEST(Transform, Padding) {
1000.0 / 4.0,
});

EdgeInsets padding;

padding.top = 0;
ASSERT_FALSE(bool(padding));

padding.top = NAN;
ASSERT_FALSE(bool(padding));

padding.top = 1000.0 / 2.0;
ASSERT_TRUE(bool(padding));

EdgeInsets padding(1000.0 / 2.0, 0, 0, 0);
const LatLng shiftedCenter = transform.getLatLng(padding);
ASSERT_NE(trueCenter.latitude, shiftedCenter.latitude);
ASSERT_DOUBLE_EQ(trueCenter.longitude, shiftedCenter.longitude);
Expand Down

0 comments on commit 043bf80

Please sign in to comment.