summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnsis Brammanis <brammanis@gmail.com>2016-01-28 21:41:20 -0800
committerAnsis Brammanis <brammanis@gmail.com>2016-02-02 14:49:03 -0800
commit4e0d1070f623811513e6800e4ac906d69958d66a (patch)
treefa10d0d169a26f680cd6dd2ead69e42bd541ce85
parentf1f53c36d0d392f83cf99859d993d70676048bdf (diff)
downloadqtlocation-mapboxgl-4e0d1070f623811513e6800e4ac906d69958d66a.tar.gz
[core] support tiles with non-4096 extents
Convert all geometries to the maximum extent supported by our buffers and then use that constant extent everywhere else.
-rw-r--r--include/mbgl/util/constants.hpp1
-rw-r--r--package.json2
-rw-r--r--src/mbgl/annotation/annotation_tile.hpp1
-rw-r--r--src/mbgl/layer/circle_layer.cpp3
-rw-r--r--src/mbgl/layer/fill_layer.cpp3
-rw-r--r--src/mbgl/layer/line_layer.cpp3
-rw-r--r--src/mbgl/map/geometry_tile.hpp1
-rw-r--r--src/mbgl/map/transform_state.cpp2
-rw-r--r--src/mbgl/map/vector_tile.cpp4
-rw-r--r--src/mbgl/map/vector_tile.hpp1
-rw-r--r--src/mbgl/renderer/circle_bucket.cpp4
-rw-r--r--src/mbgl/renderer/painter.cpp3
-rw-r--r--src/mbgl/renderer/painter.hpp21
-rw-r--r--src/mbgl/renderer/painter_fill.cpp2
-rw-r--r--src/mbgl/renderer/painter_line.cpp6
-rw-r--r--src/mbgl/renderer/painter_symbol.cpp4
-rw-r--r--src/mbgl/renderer/symbol_bucket.cpp10
-rw-r--r--src/mbgl/renderer/symbol_bucket.hpp1
-rw-r--r--src/mbgl/shader/raster.vertex.glsl2
-rw-r--r--src/mbgl/text/collision_tile.cpp5
-rw-r--r--src/mbgl/text/collision_tile.hpp1
-rw-r--r--src/mbgl/text/get_anchors.cpp6
-rw-r--r--src/mbgl/tile/geojson_tile.hpp1
-rw-r--r--src/mbgl/util/constants.cpp12
-rw-r--r--src/mbgl/util/get_geometries.cpp19
-rw-r--r--src/mbgl/util/get_geometries.hpp12
26 files changed, 93 insertions, 37 deletions
diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp
index 22a460c9b0..94b21ccb36 100644
--- a/include/mbgl/util/constants.hpp
+++ b/include/mbgl/util/constants.hpp
@@ -10,6 +10,7 @@ namespace mbgl {
namespace util {
extern const float tileSize;
+extern const int32_t EXTENT;
extern const double DEG2RAD;
extern const double RAD2DEG;
diff --git a/package.json b/package.json
index c31fd2b7c5..50d5a393d1 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,7 @@
],
"devDependencies": {
"aws-sdk": "^2.2.21",
- "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#7a17d43bd8482a01dc165de6fff6ae4c33c4fc5d",
+ "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#67fe48d058c23dbb4a8ac36ce0270185da3045a8",
"node-gyp": "^3.2.1",
"request": "^2.67.0",
"tape": "^4.2.2"
diff --git a/src/mbgl/annotation/annotation_tile.hpp b/src/mbgl/annotation/annotation_tile.hpp
index 1735b3eb81..742a4114a8 100644
--- a/src/mbgl/annotation/annotation_tile.hpp
+++ b/src/mbgl/annotation/annotation_tile.hpp
@@ -17,6 +17,7 @@ public:
FeatureType getType() const override { return type; }
optional<Value> getValue(const std::string&) const override;
GeometryCollection getGeometries() const override { return geometries; }
+ uint32_t getExtent() const override { return 4096; }
const FeatureType type;
const std::unordered_map<std::string, std::string> properties;
diff --git a/src/mbgl/layer/circle_layer.cpp b/src/mbgl/layer/circle_layer.cpp
index 23fbc06d86..0a28b2f2c1 100644
--- a/src/mbgl/layer/circle_layer.cpp
+++ b/src/mbgl/layer/circle_layer.cpp
@@ -1,6 +1,7 @@
#include <mbgl/layer/circle_layer.hpp>
#include <mbgl/style/style_bucket_parameters.hpp>
#include <mbgl/renderer/circle_bucket.hpp>
+#include <mbgl/util/get_geometries.hpp>
namespace mbgl {
@@ -45,7 +46,7 @@ std::unique_ptr<Bucket> CircleLayer::createBucket(StyleBucketParameters& paramet
auto bucket = std::make_unique<CircleBucket>();
parameters.eachFilteredFeature(filter, [&] (const auto& feature) {
- bucket->addGeometry(feature.getGeometries());
+ bucket->addGeometry(getGeometries(feature));
});
return std::move(bucket);
diff --git a/src/mbgl/layer/fill_layer.cpp b/src/mbgl/layer/fill_layer.cpp
index 6a5a9de4f3..739a6fd20c 100644
--- a/src/mbgl/layer/fill_layer.cpp
+++ b/src/mbgl/layer/fill_layer.cpp
@@ -1,6 +1,7 @@
#include <mbgl/layer/fill_layer.hpp>
#include <mbgl/style/style_bucket_parameters.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
+#include <mbgl/util/get_geometries.hpp>
namespace mbgl {
@@ -58,7 +59,7 @@ std::unique_ptr<Bucket> FillLayer::createBucket(StyleBucketParameters& parameter
auto bucket = std::make_unique<FillBucket>();
parameters.eachFilteredFeature(filter, [&] (const auto& feature) {
- bucket->addGeometry(feature.getGeometries());
+ bucket->addGeometry(getGeometries(feature));
});
return std::move(bucket);
diff --git a/src/mbgl/layer/line_layer.cpp b/src/mbgl/layer/line_layer.cpp
index 1c6c1dc8d6..8454eb2664 100644
--- a/src/mbgl/layer/line_layer.cpp
+++ b/src/mbgl/layer/line_layer.cpp
@@ -2,6 +2,7 @@
#include <mbgl/style/style_bucket_parameters.hpp>
#include <mbgl/renderer/line_bucket.hpp>
#include <mbgl/map/tile_id.hpp>
+#include <mbgl/util/get_geometries.hpp>
namespace mbgl {
@@ -79,7 +80,7 @@ std::unique_ptr<Bucket> LineLayer::createBucket(StyleBucketParameters& parameter
bucket->layout.roundLimit.calculate(p);
parameters.eachFilteredFeature(filter, [&] (const auto& feature) {
- bucket->addGeometry(feature.getGeometries());
+ bucket->addGeometry(getGeometries(feature));
});
return std::move(bucket);
diff --git a/src/mbgl/map/geometry_tile.hpp b/src/mbgl/map/geometry_tile.hpp
index e906fed8f3..5cb2f96fdc 100644
--- a/src/mbgl/map/geometry_tile.hpp
+++ b/src/mbgl/map/geometry_tile.hpp
@@ -32,6 +32,7 @@ public:
virtual FeatureType getType() const = 0;
virtual optional<Value> getValue(const std::string& key) const = 0;
virtual GeometryCollection getGeometries() const = 0;
+ virtual uint32_t getExtent() const = 0;
};
class GeometryTileLayer : private util::noncopyable {
diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp
index c0c1845a54..92a35f7faa 100644
--- a/src/mbgl/map/transform_state.cpp
+++ b/src/mbgl/map/transform_state.cpp
@@ -21,7 +21,7 @@ void TransformState::matrixFor(mat4& matrix, const TileID& id, const int8_t z) c
matrix::identity(matrix);
matrix::translate(matrix, matrix, id.x * s, id.y * s, 0);
- matrix::scale(matrix, matrix, s / 4096.0f, s / 4096.0f, 1);
+ matrix::scale(matrix, matrix, s / util::EXTENT, s / util::EXTENT, 1);
}
void TransformState::getProjMatrix(mat4& projMatrix) const {
diff --git a/src/mbgl/map/vector_tile.cpp b/src/mbgl/map/vector_tile.cpp
index f837714b8d..17746a26a1 100644
--- a/src/mbgl/map/vector_tile.cpp
+++ b/src/mbgl/map/vector_tile.cpp
@@ -130,6 +130,10 @@ GeometryCollection VectorTileFeature::getGeometries() const {
return lines;
}
+uint32_t VectorTileFeature::getExtent() const {
+ return layer.extent;
+}
+
VectorTile::VectorTile(std::shared_ptr<const std::string> data_)
: data(std::move(data_)) {
}
diff --git a/src/mbgl/map/vector_tile.hpp b/src/mbgl/map/vector_tile.hpp
index a53c0bc44f..8550b1c55a 100644
--- a/src/mbgl/map/vector_tile.hpp
+++ b/src/mbgl/map/vector_tile.hpp
@@ -18,6 +18,7 @@ public:
FeatureType getType() const override { return type; }
optional<Value> getValue(const std::string&) const override;
GeometryCollection getGeometries() const override;
+ uint32_t getExtent() const override;
private:
const VectorTileLayer& layer;
diff --git a/src/mbgl/renderer/circle_bucket.cpp b/src/mbgl/renderer/circle_bucket.cpp
index 13a3cebafe..1ebe8ffaf3 100644
--- a/src/mbgl/renderer/circle_bucket.cpp
+++ b/src/mbgl/renderer/circle_bucket.cpp
@@ -3,6 +3,7 @@
#include <mbgl/shader/circle_shader.hpp>
#include <mbgl/layer/circle_layer.hpp>
+#include <mbgl/util/constants.hpp>
using namespace mbgl;
@@ -31,14 +32,13 @@ bool CircleBucket::hasData() const {
}
void CircleBucket::addGeometry(const GeometryCollection& geometryCollection) {
- const int extent = 4096;
for (auto& circle : geometryCollection) {
for(auto & geometry : circle) {
auto x = geometry.x;
auto y = geometry.y;
// Do not include points that are outside the tile boundaries.
- if (x < 0 || x >= extent || y < 0 || y >= extent) continue;
+ if (x < 0 || x >= util::EXTENT || y < 0 || y >= util::EXTENT) continue;
// this geometry will be of the Point type, and we'll derive
// two triangles from it.
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp
index 19b597a77b..0fd76314dc 100644
--- a/src/mbgl/renderer/painter.cpp
+++ b/src/mbgl/renderer/painter.cpp
@@ -344,8 +344,7 @@ mat4 Painter::translatedMatrix(const mat4& matrix, const std::array<float, 2> &t
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)) / state.getScale() * (4096.0 / util::tileSize / id.overscaling);
+ const double factor = ((double)(1 << id.z)) / state.getScale() * (util::EXTENT / util::tileSize / id.overscaling);
mat4 vtxMatrix;
if (anchor == TranslateAnchorType::Viewport) {
diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp
index 7189bcc19b..092c164033 100644
--- a/src/mbgl/renderer/painter.hpp
+++ b/src/mbgl/renderer/painter.hpp
@@ -18,6 +18,7 @@
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/chrono.hpp>
+#include <mbgl/util/constants.hpp>
#include <array>
#include <vector>
@@ -129,8 +130,8 @@ private:
// used to composite images and flips the geometry upside down
const mat4 flipMatrix = []{
mat4 flip;
- matrix::ortho(flip, 0, 4096, -4096, 0, 0, 1);
- matrix::translate(flip, flip, 0, -4096, 0);
+ matrix::ortho(flip, 0, util::EXTENT, -util::EXTENT, 0, 0, 1);
+ matrix::translate(flip, flip, 0, -util::EXTENT, 0);
return flip;
}();
@@ -186,13 +187,13 @@ private:
StaticVertexBuffer tileStencilBuffer = {
// top left triangle
{ 0, 0 },
- { 4096, 0 },
- { 0, 4096 },
+ { util::EXTENT, 0 },
+ { 0, util::EXTENT },
// bottom right triangle
- { 4096, 0 },
- { 0, 4096 },
- { 4096, 4096 },
+ { util::EXTENT, 0 },
+ { 0, util::EXTENT },
+ { util::EXTENT, util::EXTENT },
};
VertexArrayObject coveringPlainArray;
@@ -201,9 +202,9 @@ private:
// Set up the tile boundary lines we're using to draw the tile outlines.
StaticVertexBuffer tileBorderBuffer = {
{ 0, 0 },
- { 4096, 0 },
- { 4096, 4096 },
- { 0, 4096 },
+ { util::EXTENT, 0 },
+ { util::EXTENT, util::EXTENT },
+ { 0, util::EXTENT },
{ 0, 0 },
};
diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp
index 0217cb1a5d..44ae1919a0 100644
--- a/src/mbgl/renderer/painter_fill.cpp
+++ b/src/mbgl/renderer/painter_fill.cpp
@@ -65,7 +65,7 @@ void Painter::renderFill(FillBucket& bucket, const FillLayer& layer, const TileI
// Image fill.
if (pass == RenderPass::Translucent && posA && posB) {
- float factor = (8.0 / std::pow(2, state.getIntegerZoom() - id.z)) / id.overscaling;
+ float factor = (util::EXTENT / util::tileSize / std::pow(2, state.getIntegerZoom() - id.z)) / id.overscaling;
mat3 patternMatrixA;
matrix::identity(patternMatrixA);
diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp
index b849073cc1..b507c8c865 100644
--- a/src/mbgl/renderer/painter_line.cpp
+++ b/src/mbgl/renderer/painter_line.cpp
@@ -51,7 +51,7 @@ void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileI
color[2] *= properties.opacity;
color[3] *= properties.opacity;
- float ratio = state.getScale() / std::pow(2, id.z) / (4096.0 / (512.0 * id.overscaling));
+ float ratio = state.getScale() / std::pow(2, id.z) / (util::EXTENT / (512.0 * id.overscaling));
mat2 antialiasingMatrix;
matrix::identity(antialiasingMatrix);
@@ -83,7 +83,7 @@ void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileI
LinePatternPos posB = lineAtlas->getDashPosition(properties.dasharray.value.to, layout.cap == CapType::Round);
lineAtlas->bind();
- float patternratio = std::pow(2.0, std::floor(::log2(state.getScale())) - id.z) / 8.0 * id.overscaling;
+ float patternratio = std::pow(2.0, std::floor(::log2(state.getScale())) - id.z) / (util::EXTENT / util::tileSize) * id.overscaling;
float scaleXA = patternratio / posA.width / properties.dashLineWidth / properties.dasharray.value.fromScale;
float scaleYA = -posA.height / 2.0;
float scaleXB = patternratio / posB.width / properties.dashLineWidth / properties.dasharray.value.toScale;
@@ -109,7 +109,7 @@ void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileI
if (!imagePosA || !imagePosB)
return;
- float factor = 4096.0 / (512 * id.overscaling) / std::pow(2, state.getIntegerZoom() - id.z);
+ float factor = util::EXTENT / (512 * id.overscaling) / std::pow(2, state.getIntegerZoom() - id.z);
config.program = linepatternShader->program;
diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp
index e45cc822dc..0538485824 100644
--- a/src/mbgl/renderer/painter_symbol.cpp
+++ b/src/mbgl/renderer/painter_symbol.cpp
@@ -34,7 +34,7 @@ void Painter::renderSDF(SymbolBucket &bucket,
if (skewed) {
matrix::identity(exMatrix);
- s = 4096.0f / util::tileSize / id.overscaling / std::pow(2, state.getZoom() - id.z);
+ s = util::EXTENT / util::tileSize / id.overscaling / std::pow(2, state.getZoom() - id.z);
gammaScale = 1.0f / std::cos(state.getPitch());
} else {
exMatrix = extrudeMatrix;
@@ -211,7 +211,7 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const
if (skewed) {
matrix::identity(exMatrix);
- s = 4096.0f / util::tileSize / id.overscaling / std::pow(2, state.getZoom() - id.z);
+ s = util::EXTENT / util::tileSize / id.overscaling / std::pow(2, state.getZoom() - id.z);
} else {
exMatrix = extrudeMatrix;
matrix::rotate_z(exMatrix, exMatrix, state.getNorthOrientationAngle());
diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp
index 75cf496d15..36d285909b 100644
--- a/src/mbgl/renderer/symbol_bucket.cpp
+++ b/src/mbgl/renderer/symbol_bucket.cpp
@@ -24,6 +24,8 @@
#include <mbgl/util/merge_lines.hpp>
#include <mbgl/util/clip_lines.hpp>
#include <mbgl/util/std.hpp>
+#include <mbgl/util/get_geometries.hpp>
+#include <mbgl/util/constants.hpp>
namespace mbgl {
@@ -54,7 +56,7 @@ SymbolInstance::SymbolInstance(Anchor& anchor, const std::vector<Coordinate>& li
SymbolBucket::SymbolBucket(float overscaling_, float zoom_, const MapMode mode_)
- : overscaling(overscaling_), zoom(zoom_), tileSize(512 * overscaling_), tilePixelRatio(tileExtent / tileSize), mode(mode_) {
+ : overscaling(overscaling_), zoom(zoom_), tileSize(512 * overscaling_), tilePixelRatio(util::EXTENT / tileSize), mode(mode_) {
}
SymbolBucket::~SymbolBucket() {
@@ -141,7 +143,7 @@ void SymbolBucket::parseFeatures(const GeometryTileLayer& layer,
auto &multiline = ft.geometry;
- GeometryCollection geometryCollection = feature->getGeometries();
+ GeometryCollection geometryCollection = getGeometries(*feature);
for (auto& line : geometryCollection) {
multiline.emplace_back();
for (auto& point : line) {
@@ -295,7 +297,7 @@ void SymbolBucket::addFeature(const std::vector<std::vector<Coordinate>> &lines,
const float textRepeatDistance = symbolSpacing / 2;
auto& clippedLines = isLine ?
- util::clipLines(lines, 0, 0, 4096, 4096) :
+ util::clipLines(lines, 0, 0, util::EXTENT, util::EXTENT) :
lines;
for (const auto& line : clippedLines) {
@@ -314,7 +316,7 @@ void SymbolBucket::addFeature(const std::vector<std::vector<Coordinate>> &lines,
}
}
- const bool inside = !(anchor.x < 0 || anchor.x > 4096 || anchor.y < 0 || anchor.y > 4096);
+ const bool inside = !(anchor.x < 0 || anchor.x > util::EXTENT || anchor.y < 0 || anchor.y > util::EXTENT);
if (avoidEdges && !inside) continue;
diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp
index 68a622bb8a..7ea5fa05d7 100644
--- a/src/mbgl/renderer/symbol_bucket.hpp
+++ b/src/mbgl/renderer/symbol_bucket.hpp
@@ -117,7 +117,6 @@ private:
const float overscaling;
const float zoom;
const float tileSize;
- const float tileExtent = 4096.0f;
const float tilePixelRatio;
const MapMode mode;
diff --git a/src/mbgl/shader/raster.vertex.glsl b/src/mbgl/shader/raster.vertex.glsl
index 97e563f585..107b82a0ef 100644
--- a/src/mbgl/shader/raster.vertex.glsl
+++ b/src/mbgl/shader/raster.vertex.glsl
@@ -8,6 +8,6 @@ varying vec2 v_pos;
void main() {
gl_Position = u_matrix * vec4(a_pos, 0, 1);
- float dimension = (4096.0 + 2.0 * u_buffer);
+ float dimension = (8192.0 + 2.0 * u_buffer);
v_pos = (a_pos / dimension) + (u_buffer / dimension);
}
diff --git a/src/mbgl/text/collision_tile.cpp b/src/mbgl/text/collision_tile.cpp
index b24e2cfcdb..d02307d2ed 100644
--- a/src/mbgl/text/collision_tile.cpp
+++ b/src/mbgl/text/collision_tile.cpp
@@ -1,4 +1,5 @@
#include <mbgl/text/collision_tile.hpp>
+#include <mbgl/util/constants.hpp>
#include <cmath>
namespace mbgl {
@@ -10,11 +11,11 @@ CollisionTile::CollisionTile(PlacementConfig config_) : config(config_),
// left
CollisionBox(vec2<float>(0, 0), 0, -infinity, 0, infinity, infinity),
// right
- CollisionBox(vec2<float>(extent, 0), 0, -infinity, 0, infinity, infinity),
+ CollisionBox(vec2<float>(util::EXTENT, 0), 0, -infinity, 0, infinity, infinity),
// top
CollisionBox(vec2<float>(0, 0), -infinity, 0, infinity, 0, infinity),
// bottom
- CollisionBox(vec2<float>(0, extent), -infinity, 0, infinity, 0, infinity),
+ CollisionBox(vec2<float>(0, util::EXTENT), -infinity, 0, infinity, 0, infinity),
}}) {
tree.clear();
diff --git a/src/mbgl/text/collision_tile.hpp b/src/mbgl/text/collision_tile.hpp
index f535dfe4ff..eb5d4bc64c 100644
--- a/src/mbgl/text/collision_tile.hpp
+++ b/src/mbgl/text/collision_tile.hpp
@@ -55,7 +55,6 @@ private:
Tree tree;
std::array<float, 4> rotationMatrix;
std::array<float, 4> reverseRotationMatrix;
- const float extent = 4096;
std::array<CollisionBox, 4> edges;
};
diff --git a/src/mbgl/text/get_anchors.cpp b/src/mbgl/text/get_anchors.cpp
index 2f991d8e87..1a2142bfb2 100644
--- a/src/mbgl/text/get_anchors.cpp
+++ b/src/mbgl/text/get_anchors.cpp
@@ -1,6 +1,6 @@
#include <mbgl/text/get_anchors.hpp>
#include <mbgl/text/check_max_angle.hpp>
-
+#include <mbgl/util/constants.hpp>
#include <mbgl/util/interpolate.hpp>
#include <cmath>
@@ -31,7 +31,7 @@ Anchors resample(const std::vector<Coordinate> &line, const float offset, const
x = util::interpolate(float(a.x), float(b.x), t),
y = util::interpolate(float(a.y), float(b.y), t);
- if (x >= 0 && x < 4096 && y >= 0 && y < 4096) {
+ if (x >= 0 && x < util::EXTENT && y >= 0 && y < util::EXTENT) {
Anchor anchor(::round(x), ::round(y), angle, 0.5f, i);
if (!angleWindowSize || checkMaxAngle(line, anchor, labelLength, angleWindowSize, maxAngle)) {
@@ -71,7 +71,7 @@ Anchors getAnchors(const std::vector<Coordinate> &line, float spacing,
const float labelLength = fmax(textRight - textLeft, iconRight - iconLeft);
// Is the line continued from outside the tile boundary?
- const bool continuedLine = (line[0].x == 0 || line[0].x == 4096 || line[0].y == 0 || line[0].y == 4096);
+ const bool continuedLine = (line[0].x == 0 || line[0].x == util::EXTENT || line[0].y == 0 || line[0].y == util::EXTENT);
// Is the label long, relative to the spacing?
// If so, adjust the spacing so there is always a minimum space of `spacing / 4` between label edges.
diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp
index bbb3eef401..fd27fa5917 100644
--- a/src/mbgl/tile/geojson_tile.hpp
+++ b/src/mbgl/tile/geojson_tile.hpp
@@ -25,6 +25,7 @@ public:
FeatureType getType() const override;
optional<Value> getValue(const std::string&) const override;
GeometryCollection getGeometries() const override;
+ uint32_t getExtent() const override { return 4096; }
private:
const FeatureType type;
diff --git a/src/mbgl/util/constants.cpp b/src/mbgl/util/constants.cpp
index 9a5282d5e0..1921e29610 100644
--- a/src/mbgl/util/constants.cpp
+++ b/src/mbgl/util/constants.cpp
@@ -2,6 +2,18 @@
const float mbgl::util::tileSize = 512.0f;
+/*
+ * The maximum extent of a feature that can be safely stored in the buffer.
+ * In practice, all features are converted to this extent before being added.
+ *
+ * Positions are stored as signed 16bit integers.
+ * One bit is lost for signedness to support featuers extending past the left edge of the tile.
+ * One bit is lost because the line vertex buffer packs 1 bit of other data into the int.
+ * One bit is lost to support features extending past the extent on the right edge of the tile.
+ * This leaves us with 2^13 = 8192
+ */
+const int32_t mbgl::util::EXTENT = 8192;
+
const double mbgl::util::DEG2RAD = M_PI / 180.0;
const double mbgl::util::RAD2DEG = 180.0 / M_PI;
const double mbgl::util::M2PI = 2 * M_PI;
diff --git a/src/mbgl/util/get_geometries.cpp b/src/mbgl/util/get_geometries.cpp
new file mode 100644
index 0000000000..4d4d02c5ff
--- /dev/null
+++ b/src/mbgl/util/get_geometries.cpp
@@ -0,0 +1,19 @@
+#include <mbgl/util/get_geometries.hpp>
+#include <mbgl/util/constants.hpp>
+
+namespace mbgl {
+
+GeometryCollection getGeometries(const GeometryTileFeature& feature) {
+ const float scale = float(util::EXTENT) / feature.getExtent();
+ GeometryCollection geometryCollection = feature.getGeometries();
+ for (auto& line : geometryCollection) {
+ for (auto& point : line) {
+ point.x = std::round(point.x * scale);
+ point.y = std::round(point.y * scale);
+ }
+ }
+ return geometryCollection;
+}
+
+} // namespace mbgl
+
diff --git a/src/mbgl/util/get_geometries.hpp b/src/mbgl/util/get_geometries.hpp
new file mode 100644
index 0000000000..32dd389507
--- /dev/null
+++ b/src/mbgl/util/get_geometries.hpp
@@ -0,0 +1,12 @@
+#ifndef MBGL_UTIL_GET_GEOMETRIES
+#define MBGL_UTIL_GET_GEOMETRIES
+
+#include <mbgl/map/geometry_tile.hpp>
+
+namespace mbgl {
+
+GeometryCollection getGeometries(const GeometryTileFeature& feature);
+
+} // namespace mbgl
+
+#endif