Merge branch 'master' of github.com:mapbox/llmr-native
This commit is contained in:
@@ -26,3 +26,6 @@ script:
|
||||
- make llmr
|
||||
- make linux
|
||||
- make run-tests
|
||||
|
||||
notifications:
|
||||
- hipchat: WB52YkcbCGMbNcStsGeaoRO7cyBSK4wX2ZHo2Y4b@GL
|
||||
|
||||
19
bin/style.js
19
bin/style.js
@@ -77,11 +77,11 @@ module.exports = {
|
||||
"value": "park",
|
||||
"type": "fill"
|
||||
},
|
||||
"landuse_cemetary": {
|
||||
"landuse_cemetery": {
|
||||
"source": "mapbox streets",
|
||||
"layer": "landuse",
|
||||
"field": "class",
|
||||
"value": "cemetary",
|
||||
"value": "cemetery",
|
||||
"type": "fill"
|
||||
},
|
||||
"landuse_hospital": {
|
||||
@@ -567,7 +567,7 @@ module.exports = {
|
||||
"land": "#f8f4f0",
|
||||
"water": "#a0c8f0",
|
||||
"park": "#d8e8c8",
|
||||
"cemetary": "#e0e4dd",
|
||||
"cemetery": "#e0e4dd",
|
||||
"hospital": "#fde",
|
||||
"school": "#f0e8f8",
|
||||
"wood": "#6a4",
|
||||
@@ -610,8 +610,8 @@ module.exports = {
|
||||
"name": "landuse_park",
|
||||
"bucket": "landuse_park"
|
||||
}, {
|
||||
"name": "landuse_cemetary",
|
||||
"bucket": "landuse_cemetary"
|
||||
"name": "landuse_cemetery",
|
||||
"bucket": "landuse_cemetery"
|
||||
}, {
|
||||
"name": "landuse_hospital",
|
||||
"bucket": "landuse_hospital"
|
||||
@@ -943,8 +943,8 @@ module.exports = {
|
||||
"landuse_park": {
|
||||
"color": "park",
|
||||
},
|
||||
"landuse_cemetary": {
|
||||
"color": "cemetary",
|
||||
"landuse_cemetery": {
|
||||
"color": "cemetery",
|
||||
},
|
||||
"landuse_hospital": {
|
||||
"color": "hospital",
|
||||
@@ -1005,9 +1005,10 @@ module.exports = {
|
||||
"building_shadow": {
|
||||
"color": "building_shadow",
|
||||
"translate": [
|
||||
2,
|
||||
2
|
||||
1,
|
||||
1
|
||||
],
|
||||
"translate-anchor": "viewport",
|
||||
"opacity": [
|
||||
"stops", {
|
||||
"z": 0,
|
||||
|
||||
@@ -88,10 +88,10 @@ void GLFWView::scroll(GLFWwindow *window, double /*xoffset*/, double yoffset) {
|
||||
GLFWView *view = (GLFWView *)glfwGetWindowUserPointer(window);
|
||||
double delta = yoffset * 40;
|
||||
|
||||
bool is_wheel = delta != 0 && fmod(delta, 4.000244140625) == 0;
|
||||
bool is_wheel = delta != 0 && std::fmod(delta, 4.000244140625) == 0;
|
||||
|
||||
double absdelta = delta < 0 ? -delta : delta;
|
||||
double scale = 2.0 / (1.0 + exp(-absdelta / 100.0));
|
||||
double scale = 2.0 / (1.0 + std::exp(-absdelta / 100.0));
|
||||
|
||||
// Make the scroll wheel a bit slower.
|
||||
if (!is_wheel) {
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
: w((x < 0 ? x - (1 << z) + 1 : x) / (1 << z)), z(z), x(x), y(y) {}
|
||||
|
||||
inline uint64_t to_uint64() const {
|
||||
return ((pow(2, z) * y + x) * 32) + z;
|
||||
return ((std::pow(2, z) * y + x) * 32) + z;
|
||||
}
|
||||
|
||||
inline operator std::string() const {
|
||||
|
||||
@@ -81,8 +81,8 @@ private:
|
||||
|
||||
// Limit the amount of zooming possible on the map.
|
||||
// TODO: make these modifiable from outside.
|
||||
const double min_scale = pow(2, 0);
|
||||
const double max_scale = pow(2, 20);
|
||||
const double min_scale = std::pow(2, 0);
|
||||
const double max_scale = std::pow(2, 20);
|
||||
|
||||
// cache values for spherical mercator math
|
||||
double zc, Bc, Cc;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <llmr/util/mat4.hpp>
|
||||
#include <llmr/util/noncopyable.hpp>
|
||||
#include <llmr/renderer/frame_history.hpp>
|
||||
#include <llmr/style/properties.hpp>
|
||||
|
||||
#include <llmr/shader/plain_shader.hpp>
|
||||
#include <llmr/shader/outline_shader.hpp>
|
||||
@@ -88,7 +89,7 @@ public:
|
||||
bool needsAnimation() const;
|
||||
private:
|
||||
void setupShaders();
|
||||
void translateLayer(std::array<float, 2> translation, bool reverse = false);
|
||||
const mat4 &translatedMatrix(const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchor anchor = TranslateAnchor::Map);
|
||||
|
||||
void prepareTile(const Tile& tile);
|
||||
void useProgram(uint32_t program);
|
||||
@@ -97,6 +98,7 @@ private:
|
||||
|
||||
public:
|
||||
mat4 matrix;
|
||||
mat4 vtxMatrix;
|
||||
mat4 projMatrix;
|
||||
mat4 nativeMatrix;
|
||||
mat4 extrudeMatrix;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
namespace llmr {
|
||||
|
||||
// Stores a premultiplied color, with all four channels ranging from 0..1
|
||||
typedef std::array<float, 4> Color;
|
||||
|
||||
enum class Winding {
|
||||
@@ -31,6 +32,11 @@ enum class Property {
|
||||
Linear = 4
|
||||
};
|
||||
|
||||
enum class TranslateAnchor : uint8_t {
|
||||
Map = 1,
|
||||
Viewport = 2
|
||||
};
|
||||
|
||||
namespace functions {
|
||||
|
||||
float null(float z, const std::vector<float>&);
|
||||
@@ -57,6 +63,7 @@ struct FunctionProperty {
|
||||
struct PointClass {
|
||||
FunctionProperty enabled = true;
|
||||
std::array<FunctionProperty, 2> translate = {{ 0, 0 }};
|
||||
TranslateAnchor translateAnchor = TranslateAnchor::Map;
|
||||
FunctionProperty size;
|
||||
Color color = {{ 0, 0, 0, 1 }};
|
||||
FunctionProperty opacity = 1;
|
||||
@@ -68,6 +75,7 @@ struct PointClass {
|
||||
struct PointProperties {
|
||||
bool enabled = true;
|
||||
std::array<float, 2> translate = {{ 0, 0 }};
|
||||
TranslateAnchor translateAnchor = TranslateAnchor::Map;
|
||||
float size = 0;
|
||||
Color color = {{ 0, 0, 0, 1 }};
|
||||
float opacity = 1.0;
|
||||
@@ -79,6 +87,7 @@ struct PointProperties {
|
||||
struct LineClass {
|
||||
FunctionProperty enabled = true;
|
||||
std::array<FunctionProperty, 2> translate = {{ 0, 0 }};
|
||||
TranslateAnchor translateAnchor = TranslateAnchor::Map;
|
||||
FunctionProperty width;
|
||||
FunctionProperty offset;
|
||||
Color color = {{ 0, 0, 0, 1 }};
|
||||
@@ -89,6 +98,7 @@ struct LineClass {
|
||||
struct LineProperties {
|
||||
bool enabled = true;
|
||||
std::array<float, 2> translate = {{ 0, 0 }};
|
||||
TranslateAnchor translateAnchor = TranslateAnchor::Map;
|
||||
float width = 0;
|
||||
float offset = 0;
|
||||
Color color = {{ 0, 0, 0, 1 }};
|
||||
@@ -99,6 +109,7 @@ struct LineProperties {
|
||||
struct FillClass {
|
||||
FunctionProperty enabled = true;
|
||||
std::array<FunctionProperty, 2> translate = {{ 0, 0 }};
|
||||
TranslateAnchor translateAnchor = TranslateAnchor::Map;
|
||||
Winding winding = Winding::NonZero;
|
||||
FunctionProperty antialias = true;
|
||||
Color fill_color = {{ 0, 0, 0, 1 }};
|
||||
@@ -110,6 +121,7 @@ struct FillClass {
|
||||
struct FillProperties {
|
||||
bool enabled = true;
|
||||
std::array<float, 2> translate = {{ 0, 0 }};
|
||||
TranslateAnchor translateAnchor = TranslateAnchor::Map;
|
||||
Winding winding = Winding::NonZero;
|
||||
bool antialias = true;
|
||||
Color fill_color = {{ 0, 0, 0, 1 }};
|
||||
@@ -121,6 +133,7 @@ struct FillProperties {
|
||||
struct TextClass {
|
||||
FunctionProperty enabled = true;
|
||||
std::array<FunctionProperty, 2> translate = {{ 0, 0 }};
|
||||
TranslateAnchor translateAnchor = TranslateAnchor::Map;
|
||||
Color color = {{ 0, 0, 0, 1 }};
|
||||
Color halo = {{ 1, 1, 1, 0.75 }};
|
||||
FunctionProperty haloRadius = 0.25f;
|
||||
@@ -133,6 +146,7 @@ struct TextClass {
|
||||
struct TextProperties {
|
||||
bool enabled = true;
|
||||
std::array<float, 2> translate = {{ 0, 0 }};
|
||||
TranslateAnchor translateAnchor = TranslateAnchor::Map;
|
||||
Color color = {{ 0, 0, 0, 1 }};
|
||||
Color halo = {{ 1, 1, 1, 0.75 }};
|
||||
float haloRadius = 0.25f;
|
||||
|
||||
@@ -44,7 +44,7 @@ inline T min(T a, T b, T c, T d) {
|
||||
// a x b = |a||b|sin(θ) for θ.
|
||||
template <typename T = double, typename S>
|
||||
inline T angle_between(S ax, S ay, S bx, S by) {
|
||||
return atan2((ax * by - ay * bx), ax * bx + ay * by);
|
||||
return std::atan2((ax * by - ay * bx), ax * bx + ay * by);
|
||||
}
|
||||
|
||||
template <typename T = double, typename S>
|
||||
@@ -54,7 +54,7 @@ inline T angle_between(const vec2<S>& a, const vec2<S>& b) {
|
||||
|
||||
template <typename T = double, typename S>
|
||||
inline T angle_to(const vec2<S>& a, const vec2<S>& b) {
|
||||
return atan2(a.y - b.y, a.x - b.x);
|
||||
return std::atan2(a.y - b.y, a.x - b.x);
|
||||
}
|
||||
|
||||
template <typename T, typename S1, typename S2>
|
||||
@@ -75,7 +75,7 @@ template <typename T, typename S1, typename S2>
|
||||
inline vec2<T> normal(const S1& a, const S2& b) {
|
||||
T dx = b.x - a.x;
|
||||
T dy = b.y - a.y;
|
||||
T c = sqrt(dx * dx + dy * dy);
|
||||
T c = std::sqrt(dx * dx + dy * dy);
|
||||
return { dx / c, dy / c };
|
||||
}
|
||||
|
||||
@@ -83,14 +83,14 @@ template <typename T, typename S1, typename S2>
|
||||
inline T dist(const S1& a, const S2& b) {
|
||||
T dx = b.x - a.x;
|
||||
T dy = b.y - a.y;
|
||||
T c = sqrt(dx * dx + dy * dy);
|
||||
T c = std::sqrt(dx * dx + dy * dy);
|
||||
return c;
|
||||
}
|
||||
|
||||
// Take the magnitude of vector a.
|
||||
template <typename T = double, typename S>
|
||||
inline T mag(const S& a) {
|
||||
return sqrt(a.x * a.x + a.y * a.y);
|
||||
return std::sqrt(a.x * a.x + a.y * a.y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,7 +15,11 @@ namespace uv {
|
||||
|
||||
class mutex {
|
||||
public:
|
||||
inline mutex() { assert(uv_mutex_init(&mtx) == 0); }
|
||||
inline mutex() {
|
||||
if (uv_mutex_init(&mtx) != 0) {
|
||||
throw std::runtime_error("failed to initialize mutex");
|
||||
}
|
||||
}
|
||||
inline ~mutex() { uv_mutex_destroy(&mtx); }
|
||||
inline void lock() { uv_mutex_lock(&mtx); }
|
||||
inline void unlock() { uv_mutex_unlock(&mtx); }
|
||||
@@ -35,7 +39,11 @@ private:
|
||||
|
||||
class rwlock {
|
||||
public:
|
||||
inline rwlock() { assert(uv_rwlock_init(&mtx) == 0); }
|
||||
inline rwlock() {
|
||||
if (uv_rwlock_init(&mtx) != 0) {
|
||||
throw std::runtime_error("failed to initialize read-write lock");
|
||||
}
|
||||
}
|
||||
inline ~rwlock() { uv_rwlock_destroy(&mtx); }
|
||||
inline void rdlock() { uv_rwlock_rdlock(&mtx); }
|
||||
inline void wrlock() { uv_rwlock_wrlock(&mtx); }
|
||||
|
||||
@@ -114,7 +114,7 @@ const std::map<std::string, Color> kCSSColorTable = {
|
||||
|
||||
template <typename T>
|
||||
uint8_t clamp_css_byte(T i) { // Clamp to integer 0 .. 255.
|
||||
i = round(i); // Seems to be what Chrome does (vs truncation).
|
||||
i = std::round(i); // Seems to be what Chrome does (vs truncation).
|
||||
return i < 0 ? 0 : i > 255 ? 255 : i;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ void DebugFontBuffer::addText(const char *text, double left, double baseline, do
|
||||
if (glyph.data[j] == -1 && glyph.data[j + 1] == -1) {
|
||||
prev = false;
|
||||
} else {
|
||||
int16_t x = round(left + glyph.data[j] * scale);
|
||||
int16_t y = round(baseline - glyph.data[j + 1] * scale);
|
||||
int16_t x = std::round(left + glyph.data[j] * scale);
|
||||
int16_t y = std::round(baseline - glyph.data[j + 1] * scale);
|
||||
if (prev) {
|
||||
coords = static_cast<uint16_t *>(addElement());
|
||||
coords[0] = prev_x;
|
||||
|
||||
@@ -14,8 +14,8 @@ size_t LineVertexBuffer::add(vertex_type x, vertex_type y, float ex, float ey, i
|
||||
coords[1] = (y * 2) | ty;
|
||||
|
||||
int8_t *extrude = static_cast<int8_t *>(data);
|
||||
extrude[4] = round(extrudeScale * ex);
|
||||
extrude[5] = round(extrudeScale * ey);
|
||||
extrude[4] = std::round(extrudeScale * ex);
|
||||
extrude[5] = std::round(extrudeScale * ey);
|
||||
|
||||
coords[3] = linesofar;
|
||||
|
||||
|
||||
@@ -15,21 +15,21 @@ size_t TextVertexBuffer::add(int16_t x, int16_t y, float ox, float oy, uint16_t
|
||||
int16_t *shorts = static_cast<int16_t *>(data);
|
||||
shorts[0] = x;
|
||||
shorts[1] = y;
|
||||
shorts[2] = round(ox * 64); // use 1/64 pixels for placement
|
||||
shorts[3] = round(oy * 64);
|
||||
shorts[2] = std::round(ox * 64); // use 1/64 pixels for placement
|
||||
shorts[3] = std::round(oy * 64);
|
||||
|
||||
uint8_t *ubytes = static_cast<uint8_t *>(data);
|
||||
// a_data1
|
||||
ubytes[8] = tx / 4;
|
||||
ubytes[9] = ty / 4;
|
||||
ubytes[10] = labelminzoom * 10;
|
||||
ubytes[11] = (int16_t)round(angle * angleFactor) % 256;
|
||||
ubytes[11] = (int16_t)std::round(angle * angleFactor) % 256;
|
||||
|
||||
// a_data2
|
||||
ubytes[12] = minzoom * 10; // 1/10 zoom levels: z16 == 160.
|
||||
ubytes[13] = fmin(maxzoom, 25) * 10; // 1/10 zoom levels: z16 == 160.
|
||||
ubytes[14] = util::max((int16_t)round(range[0] * angleFactor), (int16_t)0) % 256;
|
||||
ubytes[15] = util::min((int16_t)round(range[1] * angleFactor), (int16_t)255) % 256;
|
||||
ubytes[13] = std::fmin(maxzoom, 25) * 10; // 1/10 zoom levels: z16 == 160.
|
||||
ubytes[14] = util::max((int16_t)std::round(range[0] * angleFactor), (int16_t)0) % 256;
|
||||
ubytes[15] = util::min((int16_t)std::round(range[1] * angleFactor), (int16_t)255) % 256;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
@@ -312,8 +312,8 @@ edge _edge(const llmr::vec2<double> a, const llmr::vec2<double> b) {
|
||||
|
||||
// scan-line conversion
|
||||
void _scanSpans(edge e0, edge e1, int32_t ymin, int32_t ymax, ScanLine scanLine) {
|
||||
double y0 = fmax(ymin, floor(e1.y0)),
|
||||
y1 = fmin(ymax, ceil(e1.y1));
|
||||
double y0 = std::fmax(ymin, std::floor(e1.y0)),
|
||||
y1 = std::fmin(ymax, std::ceil(e1.y1));
|
||||
|
||||
// sort edges by x-coordinate
|
||||
if ((e0.x0 == e1.x0 && e0.y0 == e1.y0) ?
|
||||
@@ -328,9 +328,9 @@ void _scanSpans(edge e0, edge e1, int32_t ymin, int32_t ymax, ScanLine scanLine)
|
||||
d0 = e0.dx > 0, // use y + 1 to compute x0
|
||||
d1 = e1.dx < 0; // use y + 1 to compute x1
|
||||
for (int32_t y = y0; y < y1; y++) {
|
||||
double x0 = m0 * fmax(0, fmin(e0.dy, y + d0 - e0.y0)) + e0.x0,
|
||||
x1 = m1 * fmax(0, fmin(e1.dy, y + d1 - e1.y0)) + e1.x0;
|
||||
scanLine(floor(x1), ceil(x0), y, ymax);
|
||||
double x0 = m0 * std::fmax(0, std::fmin(e0.dy, y + d0 - e0.y0)) + e0.x0,
|
||||
x1 = m1 * std::fmax(0, std::fmin(e1.dy, y + d1 - e1.y0)) + e1.x0;
|
||||
scanLine(std::floor(x1), std::ceil(x0), y, ymax);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,7 +357,7 @@ double Source::getZoom() const {
|
||||
}
|
||||
|
||||
std::forward_list<llmr::Tile::ID> Source::covering_tiles(int32_t zoom, const box& points) {
|
||||
int32_t dim = pow(2, zoom);
|
||||
int32_t dim = std::pow(2, zoom);
|
||||
std::forward_list<llmr::Tile::ID> tiles;
|
||||
bool is_raster = (type == Type::raster);
|
||||
double search_zoom = getZoom();
|
||||
@@ -389,8 +389,8 @@ std::forward_list<llmr::Tile::ID> Source::covering_tiles(int32_t zoom, const box
|
||||
const vec2<double>& center = points.center;
|
||||
tiles.sort([¢er](const Tile::ID& a, const Tile::ID& b) {
|
||||
// Sorts by distance from the box center
|
||||
return fabs(a.x - center.x) + fabs(a.y - center.y) <
|
||||
fabs(b.x - center.x) + fabs(b.y - center.y);
|
||||
return std::fabs(a.x - center.x) + std::fabs(a.y - center.y) <
|
||||
std::fabs(b.x - center.x) + std::fabs(b.y - center.y);
|
||||
});
|
||||
|
||||
tiles.unique();
|
||||
|
||||
@@ -12,7 +12,7 @@ Tile::Tile(const ID& id)
|
||||
|
||||
Tile::ID Tile::ID::parent(int8_t parent_z) const {
|
||||
assert(parent_z < z);
|
||||
int32_t dim = pow(2, z - parent_z);
|
||||
int32_t dim = std::pow(2, z - parent_z);
|
||||
return Tile::ID{
|
||||
parent_z,
|
||||
(x >= 0 ? x : x - dim + 1) / dim,
|
||||
@@ -22,7 +22,7 @@ Tile::ID Tile::ID::parent(int8_t parent_z) const {
|
||||
|
||||
std::forward_list<Tile::ID> Tile::ID::children(int32_t child_z) const {
|
||||
assert(child_z > z);
|
||||
int32_t factor = pow(2, child_z - z);
|
||||
int32_t factor = std::pow(2, child_z - z);
|
||||
|
||||
std::forward_list<ID> children;
|
||||
for (int32_t ty = y * factor, y_max = (y + 1) * factor; ty < y_max; ++ty) {
|
||||
@@ -34,7 +34,7 @@ std::forward_list<Tile::ID> Tile::ID::children(int32_t child_z) const {
|
||||
}
|
||||
|
||||
Tile::ID Tile::ID::normalized() const {
|
||||
int32_t dim = pow(2, z);
|
||||
int32_t dim = std::pow(2, z);
|
||||
int32_t nx = x, ny = y;
|
||||
while (nx < 0) nx += dim;
|
||||
while (nx >= dim) nx -= dim;
|
||||
@@ -45,7 +45,7 @@ bool Tile::ID::isChildOf(const Tile::ID &parent) const {
|
||||
if (parent.z >= z || parent.w != w) {
|
||||
return false;
|
||||
}
|
||||
int32_t scale = pow(2, z - parent.z);
|
||||
int32_t scale = std::pow(2, z - parent.z);
|
||||
return parent.x == ((x < 0 ? x - scale + 1 : x) / scale) &&
|
||||
parent.y == y / scale;
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ void Transform::moveBy(const double dx, const double dy, const time duration) {
|
||||
void Transform::_moveBy(const double dx, const double dy, const time duration) {
|
||||
// This is only called internally, so we don't need a lock here.
|
||||
|
||||
final.x = current.x + cos(current.angle) * dx + sin(current.angle) * dy;
|
||||
final.y = current.y + cos(current.angle) * dy + sin(-current.angle) * dx;
|
||||
final.x = current.x + std::cos(current.angle) * dx + std::sin(current.angle) * dy;
|
||||
final.y = current.y + std::cos(current.angle) * dy + std::sin(-current.angle) * dx;
|
||||
|
||||
if (duration == 0) {
|
||||
current.x = final.x;
|
||||
@@ -68,9 +68,9 @@ void Transform::_moveBy(const double dx, const double dy, const time duration) {
|
||||
void Transform::setLonLat(const double lon, const double lat, const time duration) {
|
||||
uv::writelock lock(mtx);
|
||||
|
||||
const double f = fmin(fmax(sin(D2R * lat), -0.9999), 0.9999);
|
||||
double xn = -round(lon * Bc);
|
||||
double yn = round(0.5 * Cc * log((1 + f) / (1 - f)));
|
||||
const double f = std::fmin(std::fmax(std::sin(D2R * lat), -0.9999), 0.9999);
|
||||
double xn = -std::round(lon * Bc);
|
||||
double yn = std::round(0.5 * Cc * std::log((1 + f) / (1 - f)));
|
||||
|
||||
_setScaleXY(current.scale, xn, yn, duration);
|
||||
}
|
||||
@@ -79,16 +79,16 @@ void Transform::setLonLatZoom(const double lon, const double lat, const double z
|
||||
const time duration) {
|
||||
uv::writelock lock(mtx);
|
||||
|
||||
double new_scale = pow(2.0, zoom);
|
||||
double new_scale = std::pow(2.0, zoom);
|
||||
|
||||
const double s = new_scale * util::tileSize;
|
||||
zc = s / 2;
|
||||
Bc = s / 360;
|
||||
Cc = s / (2 * M_PI);
|
||||
|
||||
const double f = fmin(fmax(sin(D2R * lat), -0.9999), 0.9999);
|
||||
double xn = -round(lon * Bc);
|
||||
double yn = round(0.5 * Cc * log((1 + f) / (1 - f)));
|
||||
const double f = std::fmin(std::fmax(std::sin(D2R * lat), -0.9999), 0.9999);
|
||||
double xn = -std::round(lon * Bc);
|
||||
double yn = std::round(0.5 * Cc * log((1 + f) / (1 - f)));
|
||||
|
||||
_setScaleXY(new_scale, xn, yn, duration);
|
||||
}
|
||||
@@ -97,7 +97,7 @@ void Transform::getLonLat(double &lon, double &lat) const {
|
||||
uv::readlock lock(mtx);
|
||||
|
||||
lon = -final.x / Bc;
|
||||
lat = R2D * (2 * atan(exp(final.y / Cc)) - 0.5 * M_PI);
|
||||
lat = R2D * (2 * std::atan(std::exp(final.y / Cc)) - 0.5 * M_PI);
|
||||
}
|
||||
|
||||
void Transform::getLonLatZoom(double &lon, double &lat, double &zoom) const {
|
||||
@@ -159,7 +159,7 @@ void Transform::setScale(const double scale, const double cx, const double cy,
|
||||
void Transform::setZoom(const double zoom, const time duration) {
|
||||
uv::writelock lock(mtx);
|
||||
|
||||
_setScale(pow(2.0, zoom), -1, -1, duration);
|
||||
_setScale(std::pow(2.0, zoom), -1, -1, duration);
|
||||
}
|
||||
|
||||
double Transform::getZoom() const {
|
||||
@@ -224,8 +224,8 @@ void Transform::_setScale(double new_scale, double cx, double cy, const time dur
|
||||
const double dy = (cy - current.height / 2) * (1.0 - factor);
|
||||
|
||||
// Account for angle
|
||||
const double angle_sin = sin(-current.angle);
|
||||
const double angle_cos = cos(-current.angle);
|
||||
const double angle_sin = std::sin(-current.angle);
|
||||
const double angle_cos = std::cos(-current.angle);
|
||||
const double ax = angle_cos * dx - angle_sin * dy;
|
||||
const double ay = angle_sin * dx + angle_cos * dy;
|
||||
|
||||
@@ -276,15 +276,15 @@ void Transform::rotateBy(const double start_x, const double start_y, const doubl
|
||||
const double begin_center_y = start_y - center_y;
|
||||
|
||||
const double beginning_center_dist =
|
||||
sqrt(begin_center_x * begin_center_x + begin_center_y * begin_center_y);
|
||||
std::sqrt(begin_center_x * begin_center_x + begin_center_y * begin_center_y);
|
||||
|
||||
// If the first click was too close to the center, move the center of rotation by 200 pixels
|
||||
// in the direction of the click.
|
||||
if (beginning_center_dist < 200) {
|
||||
const double offset_x = -200, offset_y = 0;
|
||||
const double rotate_angle = atan2(begin_center_y, begin_center_x);
|
||||
const double rotate_angle_sin = sin(rotate_angle);
|
||||
const double rotate_angle_cos = cos(rotate_angle);
|
||||
const double rotate_angle = std::atan2(begin_center_y, begin_center_x);
|
||||
const double rotate_angle_sin = std::sin(rotate_angle);
|
||||
const double rotate_angle_cos = std::cos(rotate_angle);
|
||||
center_x = start_x + rotate_angle_cos * offset_x - rotate_angle_sin * offset_y;
|
||||
center_y = start_y + rotate_angle_sin * offset_x + rotate_angle_cos * offset_y;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using namespace llmr;
|
||||
#pragma mark - Matrix
|
||||
|
||||
void TransformState::matrixFor(mat4& matrix, const Tile::ID& id) const {
|
||||
const double tile_scale = pow(2, id.z);
|
||||
const double tile_scale = std::pow(2, id.z);
|
||||
const double tile_size = scale * util::tileSize / tile_scale;
|
||||
|
||||
matrix::identity(matrix);
|
||||
@@ -23,10 +23,10 @@ void TransformState::matrixFor(mat4& matrix, const Tile::ID& id) const {
|
||||
}
|
||||
|
||||
box TransformState::cornersToBox(uint32_t z) const {
|
||||
const double ref_scale = pow(2, z);
|
||||
const double ref_scale = std::pow(2, z);
|
||||
|
||||
const double angle_sin = sin(-angle);
|
||||
const double angle_cos = cos(-angle);
|
||||
const double angle_sin = std::sin(-angle);
|
||||
const double angle_cos = std::cos(-angle);
|
||||
|
||||
const double w_2 = width / 2;
|
||||
const double h_2 = height / 2;
|
||||
@@ -88,15 +88,15 @@ float TransformState::getPixelRatio() const {
|
||||
#pragma mark - Zoom
|
||||
|
||||
float TransformState::getNormalizedZoom() const {
|
||||
return log(scale * util::tileSize / 256.0f) / M_LN2;
|
||||
return std::log(scale * util::tileSize / 256.0f) / M_LN2;
|
||||
}
|
||||
|
||||
int32_t TransformState::getIntegerZoom() const {
|
||||
return floor(getZoom());
|
||||
return std::floor(getZoom());
|
||||
}
|
||||
|
||||
double TransformState::getZoom() const {
|
||||
return log(scale) / M_LN2;
|
||||
return std::log(scale) / M_LN2;
|
||||
}
|
||||
|
||||
double TransformState::getScale() const {
|
||||
|
||||
@@ -155,7 +155,7 @@ void FillBucket::tessellate() {
|
||||
|
||||
for (size_t i = 0; i < vertex_count; ++i) {
|
||||
if (vertex_indices[i] == TESS_UNDEF) {
|
||||
vertexBuffer.add(round(vertices[i * 2]), round(vertices[i * 2 + 1]));
|
||||
vertexBuffer.add(std::round(vertices[i * 2]), std::round(vertices[i * 2 + 1]));
|
||||
vertex_indices[i] = (TESSindex)total_vertex_count;
|
||||
total_vertex_count++;
|
||||
}
|
||||
|
||||
@@ -159,12 +159,12 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
|
||||
double joinAngularity = nextNormal.x * joinNormal.y - nextNormal.y * joinNormal.x;
|
||||
joinNormal.x /= joinAngularity;
|
||||
joinNormal.y /= joinAngularity;
|
||||
double roundness = fmax(abs(joinNormal.x), abs(joinNormal.y));
|
||||
double roundness = std::fmax(std::abs(joinNormal.x), std::abs(joinNormal.y));
|
||||
|
||||
|
||||
// Switch to miter joins if the angle is very low.
|
||||
if (currentJoin != JoinType::Miter) {
|
||||
if (fabs(joinAngularity) < 0.5 && roundness < miterLimit) {
|
||||
if (std::fabs(joinAngularity) < 0.5 && roundness < miterLimit) {
|
||||
currentJoin = JoinType::Miter;
|
||||
}
|
||||
}
|
||||
@@ -209,7 +209,7 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
|
||||
|
||||
else if (currentJoin == JoinType::Miter) {
|
||||
// MITER JOIN
|
||||
if (fabs(joinAngularity) < 0.01) {
|
||||
if (std::fabs(joinAngularity) < 0.01) {
|
||||
// The two normals are almost parallel.
|
||||
joinNormal.x = -nextNormal.y;
|
||||
joinNormal.y = nextNormal.x;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <llmr/util/timer.hpp>
|
||||
#include <llmr/util/time.hpp>
|
||||
#include <llmr/util/clip_ids.hpp>
|
||||
#include <llmr/util/constants.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
@@ -170,17 +171,28 @@ void Painter::renderTileLayer(const Tile& tile, const LayerDescription &layer_de
|
||||
}
|
||||
}
|
||||
|
||||
void Painter::translateLayer(std::array<float, 2> translation, bool reverse) {
|
||||
if (translation[0] || translation[1]) {
|
||||
if (reverse) {
|
||||
translation[0] *= -1;
|
||||
translation[1] *= -1;
|
||||
const mat4 &Painter::translatedMatrix(const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchor anchor) {
|
||||
if (translation[0] == 0 && translation[1] == 0) {
|
||||
return matrix;
|
||||
} else {
|
||||
// TODO: Get rid of the 8 (scaling from 4096 to tile size)
|
||||
const double factor = ((double)(1 << id.z)) / map.getState().getScale() * (4096.0 / util::tileSize);
|
||||
|
||||
if (anchor == TranslateAnchor::Viewport) {
|
||||
const double sin_a = std::sin(-map.getState().getAngle());
|
||||
const double cos_a = std::cos(-map.getState().getAngle());
|
||||
matrix::translate(vtxMatrix, matrix,
|
||||
factor * (translation[0] * cos_a - translation[1] * sin_a),
|
||||
factor * (translation[0] * sin_a + translation[1] * cos_a),
|
||||
0);
|
||||
} else {
|
||||
matrix::translate(vtxMatrix, matrix,
|
||||
factor * translation[0],
|
||||
factor * translation[1],
|
||||
0);
|
||||
}
|
||||
matrix::translate(matrix,
|
||||
matrix,
|
||||
translation[0] / map.getState().getPixelRatio(),
|
||||
translation[1] / map.getState().getPixelRatio(),
|
||||
0);
|
||||
|
||||
return vtxMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,13 +35,13 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
|
||||
stroke_color = fill_color;
|
||||
}
|
||||
|
||||
translateLayer(properties.translate);
|
||||
const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
|
||||
|
||||
// Because we're drawing top-to-bottom, and we update the stencil mask
|
||||
// below, we have to draw the outline first (!)
|
||||
if (outline && pass == Translucent) {
|
||||
useProgram(outlineShader->program);
|
||||
outlineShader->setMatrix(matrix);
|
||||
outlineShader->setMatrix(vtxMatrix);
|
||||
lineWidth(2.0f); // This is always fixed and does not depend on the pixelRatio!
|
||||
|
||||
outlineShader->setColor(stroke_color);
|
||||
@@ -77,8 +77,8 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
|
||||
// Draw texture fill
|
||||
ImagePosition imagePos = sprite->getPosition(properties.image, true);
|
||||
|
||||
float factor = 8.0 / pow(2, map.getState().getIntegerZoom() - id.z);
|
||||
float mix = fmod(map.getState().getZoom(), 1.0);
|
||||
float factor = 8.0 / std::pow(2, map.getState().getIntegerZoom() - id.z);
|
||||
float mix = std::fmod(map.getState().getZoom(), 1.0);
|
||||
|
||||
std::array<float, 2> imageSize = {{
|
||||
imagePos.size.x * factor,
|
||||
@@ -87,13 +87,13 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
|
||||
};
|
||||
|
||||
std::array<float, 2> offset = {{
|
||||
(float)fmod(id.x * 4096, imageSize[0]),
|
||||
(float)fmod(id.y * 4096, imageSize[1])
|
||||
(float)std::fmod(id.x * 4096, imageSize[0]),
|
||||
(float)std::fmod(id.y * 4096, imageSize[1])
|
||||
}
|
||||
};
|
||||
|
||||
useProgram(patternShader->program);
|
||||
patternShader->setMatrix(matrix);
|
||||
patternShader->setMatrix(vtxMatrix);
|
||||
patternShader->setOffset(offset);
|
||||
patternShader->setPatternSize(imageSize);
|
||||
patternShader->setPatternTopLeft({{ imagePos.tl.x, imagePos.tl.y }});
|
||||
@@ -111,7 +111,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
|
||||
// fragments
|
||||
// Draw filling rectangle.
|
||||
useProgram(plainShader->program);
|
||||
plainShader->setMatrix(matrix);
|
||||
plainShader->setMatrix(vtxMatrix);
|
||||
plainShader->setColor(fill_color);
|
||||
|
||||
// Draw the actual triangles into the color & stencil buffer.
|
||||
@@ -124,7 +124,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
|
||||
// below, we have to draw the outline first (!)
|
||||
if (fringeline && pass == Translucent) {
|
||||
useProgram(outlineShader->program);
|
||||
outlineShader->setMatrix(matrix);
|
||||
outlineShader->setMatrix(vtxMatrix);
|
||||
lineWidth(2.0f); // This is always fixed and does not depend on the pixelRatio!
|
||||
|
||||
outlineShader->setColor(fill_color);
|
||||
@@ -138,6 +138,4 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
|
||||
glDepthRange(strata + strata_epsilon, 1.0f);
|
||||
bucket.drawVertices(*outlineShader);
|
||||
}
|
||||
|
||||
translateLayer(properties.translate, true);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
using namespace llmr;
|
||||
|
||||
void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, const Tile::ID& /*id*/) {
|
||||
void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, const Tile::ID& id) {
|
||||
// Abort early.
|
||||
if (pass == Opaque) return;
|
||||
if (!bucket.hasData()) return;
|
||||
@@ -21,8 +21,8 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons
|
||||
|
||||
// These are the radii of the line. We are limiting it to 16, which will result
|
||||
// in a point size of 64 on retina.
|
||||
float inset = fmin((fmax(-1, offset - width / 2 - 0.5) + 1), 16.0f);
|
||||
float outset = fmin(offset + width / 2 + 0.5, 16.0f);
|
||||
float inset = std::fmin((std::fmax(-1, offset - width / 2 - 0.5) + 1), 16.0f);
|
||||
float outset = std::fmin(offset + width / 2 + 0.5, 16.0f);
|
||||
|
||||
Color color = properties.color;
|
||||
color[0] *= properties.opacity;
|
||||
@@ -33,14 +33,14 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons
|
||||
float dash_length = properties.dash_array[0];
|
||||
float dash_gap = properties.dash_array[1];
|
||||
|
||||
translateLayer(properties.translate);
|
||||
const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
|
||||
|
||||
glDepthRange(strata, 1.0f);
|
||||
|
||||
// We're only drawing end caps + round line joins if the line is > 2px. Otherwise, they aren't visible anyway.
|
||||
if (bucket.hasPoints() && outset > 1.0f) {
|
||||
useProgram(linejoinShader->program);
|
||||
linejoinShader->setMatrix(matrix);
|
||||
linejoinShader->setMatrix(vtxMatrix);
|
||||
linejoinShader->setColor(color);
|
||||
linejoinShader->setWorld({{
|
||||
map.getState().getFramebufferWidth() * 0.5f,
|
||||
@@ -53,7 +53,7 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons
|
||||
}
|
||||
});
|
||||
|
||||
float pointSize = ceil(map.getState().getPixelRatio() * outset * 2.0);
|
||||
float pointSize = std::ceil(map.getState().getPixelRatio() * outset * 2.0);
|
||||
#if defined(GL_ES_VERSION_2_0)
|
||||
linejoinShader->setSize(pointSize);
|
||||
#else
|
||||
@@ -79,7 +79,7 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons
|
||||
|
||||
} else {
|
||||
useProgram(lineShader->program);
|
||||
lineShader->setMatrix(matrix);
|
||||
lineShader->setMatrix(vtxMatrix);
|
||||
lineShader->setExtrudeMatrix(extrudeMatrix);
|
||||
lineShader->setDashArray({{ dash_length, dash_gap }});
|
||||
lineShader->setLineWidth({{ outset, inset }});
|
||||
@@ -87,6 +87,4 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons
|
||||
lineShader->setColor(color);
|
||||
bucket.drawLines(*lineShader);
|
||||
}
|
||||
|
||||
translateLayer(properties.translate, true);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
using namespace llmr;
|
||||
|
||||
void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, const Tile::ID& /*id&*/) {
|
||||
void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, const Tile::ID& id) {
|
||||
// Abort early.
|
||||
if (!bucket.hasData()) return;
|
||||
if (pass == Opaque) return;
|
||||
@@ -17,8 +17,6 @@ void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, co
|
||||
const PointProperties& properties = point_properties_it->second;
|
||||
if (!properties.enabled) return;
|
||||
|
||||
translateLayer(properties.translate);
|
||||
|
||||
Color color = properties.color;
|
||||
color[0] *= properties.opacity;
|
||||
color[1] *= properties.opacity;
|
||||
@@ -37,9 +35,11 @@ void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, co
|
||||
imagePos = sprite->getPosition(sized_image, false);
|
||||
}
|
||||
|
||||
const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
|
||||
|
||||
if (!imagePos.size) {
|
||||
useProgram(dotShader->program);
|
||||
dotShader->setMatrix(matrix);
|
||||
dotShader->setMatrix(vtxMatrix);
|
||||
dotShader->setColor(color);
|
||||
|
||||
const float pointSize = (properties.radius ? properties.radius * 2 : 8) * map.getState().getPixelRatio();
|
||||
@@ -55,7 +55,7 @@ void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, co
|
||||
bucket.drawPoints(*dotShader);
|
||||
} else {
|
||||
useProgram(pointShader->program);
|
||||
pointShader->setMatrix(matrix);
|
||||
pointShader->setMatrix(vtxMatrix);
|
||||
pointShader->setColor(color);
|
||||
|
||||
pointShader->setImage(0);
|
||||
@@ -75,6 +75,4 @@ void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, co
|
||||
glDepthRange(strata, 1.0f);
|
||||
bucket.drawPoints(*pointShader);
|
||||
}
|
||||
|
||||
translateLayer(properties.translate, true);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
using namespace llmr;
|
||||
|
||||
void Painter::renderText(TextBucket& bucket, const std::string& layer_name, const Tile::ID& /*id*/) {
|
||||
void Painter::renderText(TextBucket& bucket, const std::string& layer_name, const Tile::ID& id) {
|
||||
// Abort early.
|
||||
if (pass == Opaque) return;
|
||||
if (!bucket.hasData()) return;
|
||||
@@ -16,8 +16,6 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons
|
||||
const TextProperties& properties = text_properties_it->second;
|
||||
if (!properties.enabled) return;
|
||||
|
||||
translateLayer(properties.translate);
|
||||
|
||||
mat4 exMatrix;
|
||||
matrix::copy(exMatrix, projMatrix);
|
||||
if (bucket.geom_desc.path == TextPathType::Curve) {
|
||||
@@ -30,11 +28,13 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons
|
||||
}
|
||||
|
||||
// If layerStyle.size > bucket.info.fontSize then labels may collide
|
||||
float fontSize = fmin(properties.size, bucket.geom_desc.font_size);
|
||||
float fontSize = std::fmin(properties.size, bucket.geom_desc.font_size);
|
||||
matrix::scale(exMatrix, exMatrix, fontSize / 24.0f, fontSize / 24.0f, 1.0f);
|
||||
|
||||
const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
|
||||
|
||||
useProgram(textShader->program);
|
||||
textShader->setMatrix(matrix);
|
||||
textShader->setMatrix(vtxMatrix);
|
||||
textShader->setExtrudeMatrix(exMatrix);
|
||||
|
||||
map.getGlyphAtlas().bind();
|
||||
@@ -44,7 +44,7 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons
|
||||
textShader->setGamma(2.5f / fontSize / map.getState().getPixelRatio());
|
||||
|
||||
// Convert the -pi..pi to an int8 range.
|
||||
float angle = round((map.getState().getAngle() + rotate) / M_PI * 128);
|
||||
float angle = std::round((map.getState().getAngle() + rotate) / M_PI * 128);
|
||||
|
||||
// adjust min/max zooms for variable font sies
|
||||
float zoomAdjust = log(fontSize / bucket.geom_desc.font_size) / log(2);
|
||||
@@ -75,8 +75,8 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons
|
||||
float startingZ = history.front().z;
|
||||
const FrameSnapshot lastFrame = history.back();
|
||||
float endingZ = lastFrame.z;
|
||||
float lowZ = fmin(startingZ, endingZ);
|
||||
float highZ = fmax(startingZ, endingZ);
|
||||
float lowZ = std::fmin(startingZ, endingZ);
|
||||
float highZ = std::fmax(startingZ, endingZ);
|
||||
|
||||
// Calculate the speed of zooming, and how far it would zoom in terms of zoom levels in one duration
|
||||
float zoomDiff = endingZ - history[1].z,
|
||||
@@ -91,8 +91,8 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons
|
||||
float bump = (currentTime - lastFrame.timestamp) / duration * fadedist;
|
||||
|
||||
textShader->setFadeDist(fadedist * 10);
|
||||
textShader->setMinFadeZoom(floor(lowZ * 10));
|
||||
textShader->setMaxFadeZoom(floor(highZ * 10));
|
||||
textShader->setMinFadeZoom(std::floor(lowZ * 10));
|
||||
textShader->setMaxFadeZoom(std::floor(highZ * 10));
|
||||
textShader->setFadeZoom((map.getState().getZoom() + bump) * 10);
|
||||
|
||||
// We're drawing in the translucent pass which is bottom-to-top, so we need
|
||||
@@ -109,6 +109,4 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons
|
||||
textShader->setBuffer((256.0f - 64.0f) / 256.0f);
|
||||
glDepthRange(strata + strata_epsilon, 1.0f);
|
||||
bucket.drawGlyphs(*textShader);
|
||||
|
||||
translateLayer(properties.translate, true);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ float functions::stops(float z, const std::vector<float>& stops) {
|
||||
// Linear interpolation if base is 0
|
||||
if (smaller_val == 0) return factor * larger_val;
|
||||
// Exponential interpolation between the values
|
||||
return smaller_val * pow(larger_val / smaller_val, factor);
|
||||
return smaller_val * std::pow(larger_val / smaller_val, factor);
|
||||
} else if (larger || smaller) {
|
||||
// Do not draw a line.
|
||||
return -std::numeric_limits<float>::infinity();
|
||||
@@ -77,7 +77,7 @@ float functions::linear(float z, const std::vector<float>& values) {
|
||||
const float min = values[3];
|
||||
const float max = values[4];
|
||||
|
||||
return fmin(fmax(min, val + (z - z_base) * slope), max);
|
||||
return std::fmin(std::fmax(min, val + (z - z_base) * slope), max);
|
||||
}
|
||||
|
||||
float functions::exponential(float z, const std::vector<float>& values) {
|
||||
@@ -91,5 +91,5 @@ float functions::exponential(float z, const std::vector<float>& values) {
|
||||
const float min = values[3];
|
||||
const float max = values[4];
|
||||
|
||||
return fmin(fmax(min, val + pow(1.75, (z - z_base)) * slope), max);
|
||||
return std::fmin(std::fmax(min, val + std::pow(1.75, (z - z_base)) * slope), max);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ void Style::cascade(float z) {
|
||||
fill.enabled = layer.enabled.evaluate<bool>(z);
|
||||
fill.translate = {{ layer.translate[0].evaluate<float>(z),
|
||||
layer.translate[1].evaluate<float>(z) }};
|
||||
fill.translateAnchor = layer.translateAnchor;
|
||||
fill.winding = layer.winding;
|
||||
fill.antialias = layer.antialias.evaluate<bool>(z);
|
||||
fill.fill_color = layer.fill_color;
|
||||
@@ -59,6 +60,7 @@ void Style::cascade(float z) {
|
||||
stroke.enabled = layer.enabled.evaluate<bool>(z);
|
||||
stroke.translate = {{ layer.translate[0].evaluate<float>(z),
|
||||
layer.translate[1].evaluate<float>(z) }};
|
||||
stroke.translateAnchor = layer.translateAnchor;
|
||||
stroke.width = layer.width.evaluate<float>(z);
|
||||
stroke.offset = layer.offset.evaluate<float>(z);
|
||||
stroke.color = layer.color;
|
||||
@@ -78,6 +80,7 @@ void Style::cascade(float z) {
|
||||
point.enabled = layer.enabled.evaluate<bool>(z);
|
||||
point.translate = {{ layer.translate[0].evaluate<float>(z),
|
||||
layer.translate[1].evaluate<float>(z) }};
|
||||
point.translateAnchor = layer.translateAnchor;
|
||||
point.color = layer.color;
|
||||
point.size = layer.size.evaluate<float>(z);
|
||||
point.opacity = layer.opacity.evaluate<float>(z);
|
||||
@@ -97,6 +100,7 @@ void Style::cascade(float z) {
|
||||
text.enabled = layer.enabled.evaluate<bool>(z);
|
||||
text.translate = {{ layer.translate[0].evaluate<float>(z),
|
||||
layer.translate[1].evaluate<float>(z) }};
|
||||
text.translateAnchor = layer.translateAnchor;
|
||||
text.color = layer.color;
|
||||
text.size = layer.size.evaluate<float>(z);
|
||||
text.halo = layer.halo;
|
||||
|
||||
@@ -194,6 +194,19 @@ void StyleParser::parseConstants(JSVal value) {
|
||||
}
|
||||
}
|
||||
|
||||
TranslateAnchor parseTranslateAnchor(JSVal anchor) {
|
||||
if (anchor.IsString()) {
|
||||
std::string a { anchor.GetString(), anchor.GetStringLength() };
|
||||
if (a == "viewport") {
|
||||
return TranslateAnchor::Viewport;
|
||||
} else {
|
||||
return TranslateAnchor::Map;
|
||||
}
|
||||
} else {
|
||||
throw Style::exception("translate anchor must be a string");
|
||||
}
|
||||
}
|
||||
|
||||
void StyleParser::parseClasses(JSVal value, std::map<std::string, ClassDescription>& classes, std::map<std::string, BucketDescription>& buckets, std::vector<LayerDescription>& layers) {
|
||||
if (value.IsArray()) {
|
||||
for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
|
||||
@@ -333,18 +346,25 @@ Color StyleParser::parseColor(JSVal value) {
|
||||
throw Style::exception("color values must be numbers");
|
||||
}
|
||||
|
||||
return {{static_cast<float>(r.GetDouble()),
|
||||
static_cast<float>(g.GetDouble()),
|
||||
static_cast<float>(b.GetDouble()),
|
||||
static_cast<float>(a.GetDouble())}};
|
||||
// Premultiply the color.
|
||||
const double alpha = a.GetDouble();
|
||||
return {{static_cast<float>(alpha * r.GetDouble()),
|
||||
static_cast<float>(alpha * g.GetDouble()),
|
||||
static_cast<float>(alpha * b.GetDouble()),
|
||||
static_cast<float>(alpha)}};
|
||||
|
||||
} else if (!rvalue.IsString()) {
|
||||
throw Style::exception("color value must be a string");
|
||||
}
|
||||
|
||||
CSSColorParser::Color css_color = CSSColorParser::parse({ rvalue.GetString(), rvalue.GetStringLength() });
|
||||
return {{(float)css_color.r / 255, (float)css_color.g / 255,
|
||||
(float)css_color.b / 255, css_color.a}};
|
||||
|
||||
// Premultiply the color.
|
||||
const float factor = css_color.a / 255;
|
||||
return {{(float)css_color.r * factor,
|
||||
(float)css_color.g * factor,
|
||||
(float)css_color.b * factor,
|
||||
css_color.a}};
|
||||
}
|
||||
|
||||
FunctionProperty::fn StyleParser::parseFunctionType(JSVal type) {
|
||||
@@ -427,6 +447,10 @@ FillClass StyleParser::parseFillClass(JSVal value) {
|
||||
klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }};
|
||||
}
|
||||
|
||||
if (value.HasMember("translate-anchor")) {
|
||||
klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.fill_color = parseColor(value["color"]);
|
||||
}
|
||||
@@ -464,6 +488,10 @@ LineClass StyleParser::parseLineClass(JSVal value) {
|
||||
klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }};
|
||||
}
|
||||
|
||||
if (value.HasMember("translate-anchor")) {
|
||||
klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.color = parseColor(value["color"]);
|
||||
}
|
||||
@@ -496,6 +524,10 @@ PointClass StyleParser::parsePointClass(JSVal value) {
|
||||
klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }};
|
||||
}
|
||||
|
||||
if (value.HasMember("translate-anchor")) {
|
||||
klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.color = parseColor(value["color"]);
|
||||
}
|
||||
@@ -523,7 +555,6 @@ PointClass StyleParser::parsePointClass(JSVal value) {
|
||||
return klass;
|
||||
}
|
||||
|
||||
|
||||
TextClass StyleParser::parseTextClass(JSVal value) {
|
||||
TextClass klass;
|
||||
|
||||
@@ -536,6 +567,10 @@ TextClass StyleParser::parseTextClass(JSVal value) {
|
||||
klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }};
|
||||
}
|
||||
|
||||
if (value.HasMember("translate-anchor")) {
|
||||
klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]);
|
||||
}
|
||||
|
||||
if (value.HasMember("color")) {
|
||||
klass.color = parseColor(value["color"]);
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ PlacementProperty Collision::place(const PlacedGlyphs &placed_glyphs,
|
||||
const CollisionRect &box = glyph.box;
|
||||
float x12 = box.tl.x * box.tl.x, y12 = box.tl.y * box.tl.y,
|
||||
x22 = box.br.x * box.br.x, y22 = box.br.y * box.br.y,
|
||||
diag = sqrt(
|
||||
diag = std::sqrt(
|
||||
util::max(x12 + y12, x12 + y22, x22 + y12, x22 + y22));
|
||||
|
||||
glyph.bbox = CollisionRect{{-diag, -diag}, {diag, diag}};
|
||||
@@ -147,7 +147,7 @@ float Collision::getPlacementScale(const GlyphBoxes &glyphs,
|
||||
return -1;
|
||||
}
|
||||
|
||||
float minScale = fmax(minPlacementScale, glyph.minScale);
|
||||
float minScale = std::fmax(minPlacementScale, glyph.minScale);
|
||||
float maxScale = glyph.maxScale;
|
||||
|
||||
if (minScale >= maxScale) {
|
||||
@@ -184,7 +184,7 @@ float Collision::getPlacementScale(const GlyphBoxes &glyphs,
|
||||
}
|
||||
|
||||
// todo: unhardcode the 8 = tileExtent/tileSize
|
||||
float padding = fmax(pad, placement.padding) * 8.0f;
|
||||
float padding = std::fmax(pad, placement.padding) * 8.0f;
|
||||
|
||||
// Original algorithm:
|
||||
float s1 = (ob.tl.x - nb.br.x - padding) /
|
||||
@@ -207,7 +207,7 @@ float Collision::getPlacementScale(const GlyphBoxes &glyphs,
|
||||
s3 = s4 = 1;
|
||||
}
|
||||
|
||||
float collisionFreeScale = fmin(fmax(s1, s2), fmax(s3, s4));
|
||||
float collisionFreeScale = std::fmin(std::fmax(s1, s2), std::fmax(s3, s4));
|
||||
|
||||
// Only update label's min scale if the glyph was
|
||||
// restricted by a collision
|
||||
@@ -278,12 +278,12 @@ PlacementRange Collision::getPlacementRange(const GlyphBoxes &glyphs,
|
||||
if (!(intersectX && intersectY))
|
||||
continue;
|
||||
|
||||
float scale = fmax(placementScale, b.placementScale);
|
||||
float scale = std::fmax(placementScale, b.placementScale);
|
||||
// TODO? glyph.box or glyph.bbox?
|
||||
CollisionRange range = rotationRange(glyph, b, scale);
|
||||
|
||||
placementRange[0] = fmin(placementRange[0], range[0]);
|
||||
placementRange[1] = fmax(placementRange[1], range[1]);
|
||||
placementRange[0] = std::fmin(placementRange[0], range[0]);
|
||||
placementRange[1] = std::fmax(placementRange[1], range[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +300,7 @@ void Collision::insert(const GlyphBoxes &glyphs, const CollisionAnchor &anchor,
|
||||
const CollisionRect &bbox = glyph.bbox;
|
||||
const CollisionRect &box = glyph.box;
|
||||
|
||||
float minScale = fmax(placementScale, glyph.minScale);
|
||||
float minScale = std::fmax(placementScale, glyph.minScale);
|
||||
|
||||
Box bounds{Point{anchor.x + bbox.tl.x / minScale,
|
||||
anchor.y + bbox.tl.y / minScale},
|
||||
|
||||
@@ -28,7 +28,7 @@ Placement::Placement(int8_t zoom)
|
||||
// glyphs be placed, slowing down collision checking. Only place labels if
|
||||
// they will show up within the intended zoom range of the tile.
|
||||
// TODO make this not hardcoded to 3
|
||||
maxPlacementScale(exp(log(2) * util::min((25.5 - zoom), 3.0))) {}
|
||||
maxPlacementScale(std::exp(log(2) * util::min((25.5 - zoom), 3.0))) {}
|
||||
|
||||
bool byScale(const Anchor &a, const Anchor &b) { return a.scale < b.scale; }
|
||||
|
||||
@@ -95,20 +95,20 @@ void getSegmentGlyphs(std::back_insert_iterator<GlyphInstances> glyphs,
|
||||
float prevscale = std::numeric_limits<float>::infinity();
|
||||
float prevAngle = 0.0f;
|
||||
|
||||
offset = fabs(offset);
|
||||
offset = std::fabs(offset);
|
||||
|
||||
const float placementScale = anchor.scale;
|
||||
|
||||
while (true) {
|
||||
const float dist = util::dist<float>(newAnchor, end);
|
||||
const float scale = offset / dist;
|
||||
float angle = -atan2(end.x - newAnchor.x, end.y - newAnchor.y) +
|
||||
float angle = -std::atan2(end.x - newAnchor.x, end.y - newAnchor.y) +
|
||||
direction * M_PI / 2.0f;
|
||||
if (upsideDown)
|
||||
angle += M_PI;
|
||||
|
||||
// Don't place around sharp corners
|
||||
float angleDiff = fmod((angle - prevAngle), (2.0f * M_PI));
|
||||
float angleDiff = std::fmod((angle - prevAngle), (2.0f * M_PI));
|
||||
if (prevAngle && angleDiff > maxAngleDelta) {
|
||||
anchor.scale = prevscale;
|
||||
break;
|
||||
@@ -120,7 +120,7 @@ void getSegmentGlyphs(std::back_insert_iterator<GlyphInstances> glyphs,
|
||||
/* minScale */ scale,
|
||||
/* maxScale */ prevscale,
|
||||
/* angle */ static_cast<float>(
|
||||
fmod((angle + 2.0 * M_PI), (2.0 * M_PI)))};
|
||||
std::fmod((angle + 2.0 * M_PI), (2.0 * M_PI)))};
|
||||
|
||||
if (scale <= placementScale)
|
||||
break;
|
||||
@@ -228,8 +228,8 @@ PlacedGlyphs getGlyphs(Anchor &anchor, float advance, const Shaping &shaping,
|
||||
|
||||
if (angle) {
|
||||
// Compute the transformation matrix.
|
||||
float angle_sin = sin(angle);
|
||||
float angle_cos = cos(angle);
|
||||
float angle_sin = std::sin(angle);
|
||||
float angle_cos = std::cos(angle);
|
||||
std::array<float, 4> matrix = {
|
||||
{angle_cos, -angle_sin, angle_sin, angle_cos}};
|
||||
|
||||
@@ -251,7 +251,7 @@ PlacedGlyphs getGlyphs(Anchor &anchor, float advance, const Shaping &shaping,
|
||||
glyphs.emplace_back(PlacedGlyph{
|
||||
tl, tr, bl, br, glyph.rect, width, height,
|
||||
static_cast<float>(
|
||||
fmod((anchor.angle + rotate + instance.offset + 2 * M_PI),
|
||||
std::fmod((anchor.angle + rotate + instance.offset + 2 * M_PI),
|
||||
(2 * M_PI))),
|
||||
GlyphBox{box, instance.minScale, instance.maxScale,
|
||||
instance.anchor, horizontal}});
|
||||
|
||||
@@ -54,19 +54,19 @@ rotatingRotatingCollisions(const CollisionRect &a, const CollisionRect &b,
|
||||
// Calculate angles at which collisions may occur
|
||||
const std::array<float, 8> c = {{
|
||||
// top/bottom
|
||||
/*[0]*/ static_cast<float>(asin((float)(a.br.y - b.tl.y) / d)),
|
||||
/*[1]*/ static_cast<float>(asin((float)(a.br.y - b.tl.y) / d) + M_PI),
|
||||
/*[0]*/ static_cast<float>(std::asin((float)(a.br.y - b.tl.y) / d)),
|
||||
/*[1]*/ static_cast<float>(std::asin((float)(a.br.y - b.tl.y) / d) + M_PI),
|
||||
/*[2]*/ static_cast<float>(2 * M_PI -
|
||||
asin((float)(-a.tl.y + b.br.y) / d)),
|
||||
/*[3]*/ static_cast<float>(M_PI - asin((float)(-a.tl.y + b.br.y) / d)),
|
||||
std::asin((float)(-a.tl.y + b.br.y) / d)),
|
||||
/*[3]*/ static_cast<float>(M_PI - std::asin((float)(-a.tl.y + b.br.y) / d)),
|
||||
|
||||
// left/right
|
||||
/*[4]*/ static_cast<float>(2 * M_PI -
|
||||
acos((float)(a.br.x - b.tl.x) / d)),
|
||||
/*[5]*/ static_cast<float>(acos((float)(a.br.x - b.tl.x) / d)),
|
||||
/*[6]*/ static_cast<float>(M_PI - acos((float)(-a.tl.x + b.br.x) / d)),
|
||||
std::acos((float)(a.br.x - b.tl.x) / d)),
|
||||
/*[5]*/ static_cast<float>(std::acos((float)(a.br.x - b.tl.x) / d)),
|
||||
/*[6]*/ static_cast<float>(M_PI - std::acos((float)(-a.tl.x + b.br.x) / d)),
|
||||
/*[7]*/ static_cast<float>(M_PI +
|
||||
acos((float)(-a.tl.x + b.br.x) / d))}};
|
||||
std::acos((float)(-a.tl.x + b.br.x) / d))}};
|
||||
|
||||
const float rl = a.br.x - b.tl.x;
|
||||
const float lr = -a.tl.x + b.br.x;
|
||||
@@ -98,7 +98,7 @@ rotatingRotatingCollisions(const CollisionRect &a, const CollisionRect &b,
|
||||
// between anchors.
|
||||
// Convert the angles to angles from north.
|
||||
f.push_back(
|
||||
fmod((c[i] + angleBetweenAnchors + 2 * M_PI), (2 * M_PI)));
|
||||
std::fmod((c[i] + angleBetweenAnchors + 2 * M_PI), (2 * M_PI)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ rotatingRotatingCollisions(const CollisionRect &a, const CollisionRect &b,
|
||||
|
||||
double getAngle(const CollisionPoint &p1, const CollisionPoint &p2,
|
||||
CollisionAngle d, const CollisionPoint &corner) {
|
||||
return fmod(util::angle_between(util::interp(p1.x, p2.x, d),
|
||||
return std::fmod(util::angle_between(util::interp(p1.x, p2.x, d),
|
||||
util::interp(p1.y, p2.y, d), corner.x,
|
||||
corner.y) +
|
||||
2 * M_PI,
|
||||
@@ -141,8 +141,8 @@ void circleEdgeCollisions(std::back_insert_iterator<CollisionAngles> angles,
|
||||
|
||||
// a collision exists only if line intersects circle at two points
|
||||
if (discriminant > 0) {
|
||||
CollisionAngle x1 = (-b - sqrt(discriminant)) / (2 * a);
|
||||
CollisionAngle x2 = (-b + sqrt(discriminant)) / (2 * a);
|
||||
CollisionAngle x1 = (-b - std::sqrt(discriminant)) / (2 * a);
|
||||
CollisionAngle x2 = (-b + std::sqrt(discriminant)) / (2 * a);
|
||||
|
||||
// only add points if within line segment
|
||||
// hack to handle floating point representations of 0 and 1
|
||||
|
||||
@@ -87,16 +87,16 @@ void matrix::copy(mat4& out, const mat4& a) {
|
||||
}
|
||||
|
||||
void matrix::translate(mat4& out, const mat4& a, float x, float y, float z) {
|
||||
float a00, a01, a02, a03,
|
||||
a10, a11, a12, a13,
|
||||
a20, a21, a22, a23;
|
||||
|
||||
if (a == out) {
|
||||
out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
|
||||
out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
|
||||
out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
|
||||
out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
|
||||
} else {
|
||||
float a00, a01, a02, a03,
|
||||
a10, a11, a12, a13,
|
||||
a20, a21, a22, a23;
|
||||
|
||||
a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
|
||||
a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
|
||||
a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
|
||||
@@ -113,8 +113,8 @@ void matrix::translate(mat4& out, const mat4& a, float x, float y, float z) {
|
||||
}
|
||||
|
||||
void matrix::rotate_z(mat4& out, const mat4& a, float rad) {
|
||||
float s = sin(rad),
|
||||
c = cos(rad),
|
||||
float s = std::sin(rad),
|
||||
c = std::cos(rad),
|
||||
a00 = a[0],
|
||||
a01 = a[1],
|
||||
a02 = a[2],
|
||||
|
||||
@@ -49,8 +49,8 @@ TEST(RotationRange, rotatingFixedCollisions) {
|
||||
CollisionRect{CollisionPoint{1.4142, -10}, CollisionPoint{10, 10}});
|
||||
|
||||
EXPECT_EQ(1, collisions.size());
|
||||
EXPECT_EQ(135, round(deg(collisions.front()[0])));
|
||||
EXPECT_EQ(135, round(deg(collisions.front()[1])));
|
||||
EXPECT_EQ(135, std::round(deg(collisions.front()[0])));
|
||||
EXPECT_EQ(135, std::round(deg(collisions.front()[1])));
|
||||
}
|
||||
|
||||
TEST(RotationRange, cornerBoxCollisions) {
|
||||
@@ -122,10 +122,10 @@ TEST(RotationRange, rotatingRotatingCollisions) {
|
||||
CollisionAnchor{1, 1});
|
||||
|
||||
EXPECT_EQ(2, c.size());
|
||||
EXPECT_EQ(135, round(deg(c[0][0])));
|
||||
EXPECT_EQ(135, round(deg(c[0][1])));
|
||||
EXPECT_EQ(315, round(deg(c[1][0])));
|
||||
EXPECT_EQ(315, round(deg(c[1][1])));
|
||||
EXPECT_EQ(135, std::round(deg(c[0][0])));
|
||||
EXPECT_EQ(135, std::round(deg(c[0][1])));
|
||||
EXPECT_EQ(315, std::round(deg(c[1][0])));
|
||||
EXPECT_EQ(315, std::round(deg(c[1][1])));
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user