[core] Check for NaNs in mbgl::util::{min,max,clamp}
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
#include <limits>
|
||||
|
||||
#include <mbgl/util/vec.hpp>
|
||||
|
||||
@@ -11,33 +12,33 @@ namespace util {
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline T max(T a, T b) {
|
||||
return b > a ? b : a;
|
||||
typename std::enable_if_t<std::is_integral<T>::value, T> max(T a, T b) {
|
||||
return std::max(a, b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T max(T a, T b, T c) {
|
||||
return max(max(a, b), c);
|
||||
typename std::enable_if_t<std::is_floating_point<T>::value, T> max(T a, T b) {
|
||||
return std::fmax(a, b);
|
||||
}
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
typename std::enable_if_t<std::is_arithmetic<T>::value, T> max(T a, T b, Ts... args) {
|
||||
return max(a, max(b, args...));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T max(T a, T b, T c, T d) {
|
||||
return max(max(a, b), max(c, d));
|
||||
typename std::enable_if_t<std::is_integral<T>::value, T> min(T a, T b) {
|
||||
return std::min(a, b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T min(T a, T b) {
|
||||
return b < a ? b : a;
|
||||
typename std::enable_if_t<std::is_floating_point<T>::value, T> min(T a, T b) {
|
||||
return std::fmin(a, b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T min(T a, T b, T c) {
|
||||
return min(min(a, b), c);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T min(T a, T b, T c, T d) {
|
||||
return min(min(a, b), min(c, d));
|
||||
template <typename T, typename... Ts>
|
||||
typename std::enable_if_t<std::is_arithmetic<T>::value, T> min(T a, T b, Ts... args) {
|
||||
return min(a, min(b, args...));
|
||||
}
|
||||
|
||||
// Find the angle of the two vectors, solving the formula for the cross product
|
||||
@@ -113,8 +114,8 @@ inline S unit(const S& a) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T clamp(T value, T min, T max) {
|
||||
return value < min ? min : (value > max ? max : value);
|
||||
T clamp(T value, T min_, T max_) {
|
||||
return max(min_, min(max_, value));
|
||||
}
|
||||
|
||||
// Constrains n to the given range (including min, excluding max) via modular
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/geo.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
@@ -13,16 +14,16 @@ class Projection {
|
||||
public:
|
||||
static inline double getMetersPerPixelAtLatitude(double lat, double zoom) {
|
||||
const double mapPixelWidthAtZoom = std::pow(2.0, zoom) * util::tileSize;
|
||||
const double constrainedLatitude = ::fmin(::fmax(lat, -util::LATITUDE_MAX), util::LATITUDE_MAX);
|
||||
const double constrainedLatitude = util::clamp(lat, -util::LATITUDE_MAX, util::LATITUDE_MAX);
|
||||
|
||||
return std::cos(constrainedLatitude * util::DEG2RAD) * util::M2PI * util::EARTH_RADIUS_M / mapPixelWidthAtZoom;
|
||||
}
|
||||
|
||||
static inline ProjectedMeters projectedMetersForLatLng(const LatLng& latLng) {
|
||||
const double constrainedLatitude = ::fmin(::fmax(latLng.latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX);
|
||||
const double constrainedLatitude = util::clamp(latLng.latitude, -util::LATITUDE_MAX, util::LATITUDE_MAX);
|
||||
|
||||
const double m = 1 - 1e-15;
|
||||
const double f = ::fmin(::fmax(std::sin(util::DEG2RAD * constrainedLatitude), -m), m);
|
||||
const double f = util::clamp(std::sin(util::DEG2RAD * constrainedLatitude), -m, m);
|
||||
|
||||
const double easting = util::EARTH_RADIUS_M * latLng.longitude * util::DEG2RAD;
|
||||
const double northing = 0.5 * util::EARTH_RADIUS_M * std::log((1 + f) / (1 - f));
|
||||
@@ -34,7 +35,7 @@ public:
|
||||
double latitude = (2 * std::atan(std::exp(projectedMeters.northing / util::EARTH_RADIUS_M)) - (M_PI / 2)) * util::RAD2DEG;
|
||||
double longitude = projectedMeters.easting * util::RAD2DEG / util::EARTH_RADIUS_M;
|
||||
|
||||
latitude = ::fmin(::fmax(latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX);
|
||||
latitude = util::clamp(latitude, -util::LATITUDE_MAX, util::LATITUDE_MAX);
|
||||
|
||||
return LatLng(latitude, longitude);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <mbgl/annotation/annotation_manager.hpp>
|
||||
#include <mbgl/annotation/annotation_tile.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/layer/line_layer.hpp>
|
||||
@@ -90,8 +91,8 @@ void ShapeAnnotationImpl::updateTile(const TileID& tileID, AnnotationTile& tile)
|
||||
std::vector<geojsonvt::LonLat> points;
|
||||
|
||||
for (size_t i = 0; i < shape.segments[0].size(); ++i) { // first segment for now (no holes)
|
||||
const double constraintedLatitude = ::fmin(::fmax(shape.segments[0][i].latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX);
|
||||
points.push_back(geojsonvt::LonLat(shape.segments[0][i].longitude, constraintedLatitude));
|
||||
const double constrainedLatitude = util::clamp(shape.segments[0][i].latitude, -util::LATITUDE_MAX, util::LATITUDE_MAX);
|
||||
points.push_back(geojsonvt::LonLat(shape.segments[0][i].longitude, constrainedLatitude));
|
||||
}
|
||||
|
||||
if (type == geojsonvt::ProjectedFeatureType::Polygon &&
|
||||
|
||||
@@ -410,6 +410,7 @@ void Transform::scaleBy(double ds, const Duration& duration) {
|
||||
}
|
||||
|
||||
void Transform::scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& duration) {
|
||||
if (std::isnan(ds)) return;
|
||||
double scale = util::clamp(state.scale * ds, state.min_scale, state.max_scale);
|
||||
setScale(scale, anchor, duration);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <mbgl/util/math.hpp>
|
||||
#include <mbgl/util/geo.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/map/tile_id.hpp>
|
||||
@@ -13,8 +14,8 @@ LatLng::LatLng(const TileID& id) {
|
||||
}
|
||||
|
||||
ScreenCoordinate LatLng::project() const {
|
||||
// Clamp to the latitude limits of Mercator.
|
||||
const double constrainedLatitude = ::fmin(::fmax(latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX);
|
||||
// Clamp to the latitude limits of Web Mercator.
|
||||
const double constrainedLatitude = util::clamp(latitude, -util::LATITUDE_MAX, util::LATITUDE_MAX);
|
||||
|
||||
// Project a coordinate into unit space in a square map.
|
||||
const double sine = std::sin(constrainedLatitude * util::DEG2RAD);
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
'util/geo.cpp',
|
||||
'util/image.cpp',
|
||||
'util/mapbox.cpp',
|
||||
'util/math.cpp',
|
||||
'util/merge_lines.cpp',
|
||||
'util/run_loop.cpp',
|
||||
'util/text_conversions.cpp',
|
||||
|
||||
42
test/util/math.cpp
Normal file
42
test/util/math.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "../fixtures/util.hpp"
|
||||
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
TEST(Math, MinMaxFloatingPoint) {
|
||||
double minimumValue = std::numeric_limits<double>::min();
|
||||
double lowestValue = std::numeric_limits<double>::lowest();
|
||||
double maximumValue = std::numeric_limits<double>::max();
|
||||
double quietNAN = std::numeric_limits<double>::quiet_NaN();
|
||||
|
||||
ASSERT_DOUBLE_EQ(lowestValue, util::min(minimumValue, lowestValue));
|
||||
ASSERT_DOUBLE_EQ(lowestValue, util::min(double(NAN), lowestValue));
|
||||
ASSERT_DOUBLE_EQ(lowestValue, util::min(quietNAN, lowestValue));
|
||||
ASSERT_DOUBLE_EQ(0., util::min(2., 1., 0.));
|
||||
|
||||
ASSERT_DOUBLE_EQ(maximumValue, util::max(double(NAN), maximumValue));
|
||||
ASSERT_DOUBLE_EQ(maximumValue, util::max(quietNAN, maximumValue));
|
||||
ASSERT_DOUBLE_EQ(10., util::max(8., 9., 10.));
|
||||
|
||||
ASSERT_DOUBLE_EQ(0., util::clamp(0., quietNAN, quietNAN));
|
||||
ASSERT_DOUBLE_EQ(0., util::clamp(0., lowestValue, maximumValue));
|
||||
}
|
||||
|
||||
TEST(Math, MinMaxIntegral) {
|
||||
int32_t minimumValue = std::numeric_limits<int32_t>::min();
|
||||
int32_t lowestValue = std::numeric_limits<int32_t>::lowest();
|
||||
int32_t maximumValue = std::numeric_limits<int32_t>::max();
|
||||
int32_t quietNAN = std::numeric_limits<int32_t>::quiet_NaN();
|
||||
|
||||
ASSERT_EQ(lowestValue, util::min(minimumValue, lowestValue));
|
||||
ASSERT_EQ(lowestValue, util::min(quietNAN, lowestValue));
|
||||
ASSERT_EQ(0, util::min(2, 1, 0));
|
||||
|
||||
ASSERT_EQ(maximumValue, util::max(quietNAN, maximumValue));
|
||||
ASSERT_EQ(10, util::max(8, 9, 10));
|
||||
|
||||
ASSERT_EQ(0, util::clamp(0, quietNAN, quietNAN));
|
||||
ASSERT_EQ(0, util::clamp(0, lowestValue, maximumValue));
|
||||
}
|
||||
Reference in New Issue
Block a user