create line geometry
This commit is contained in:
@@ -14,6 +14,28 @@ class VectorTileLayer;
|
||||
|
||||
struct pbf;
|
||||
|
||||
struct Coordinate {
|
||||
Coordinate() : x(0), y(0) {}
|
||||
Coordinate(int16_t x, int16_t y) : x(x), y(y) {}
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
|
||||
inline bool operator==(const Coordinate& other) const {
|
||||
return x == other.x && y == other.y;
|
||||
}
|
||||
|
||||
inline operator bool() const {
|
||||
return *this == null;
|
||||
}
|
||||
|
||||
static const Coordinate null;
|
||||
};
|
||||
|
||||
/*
|
||||
* Allows iterating over the features of a VectorTileLayer using a
|
||||
* BucketDescription as filter. Only features matching the descriptions will
|
||||
* be returned (as pbf).
|
||||
*/
|
||||
class FilteredVectorTileLayer {
|
||||
public:
|
||||
class iterator {
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace llmr {
|
||||
|
||||
class Style;
|
||||
class FillBuffer;
|
||||
class BucketDescription;
|
||||
struct Coordinate;
|
||||
struct pbf;
|
||||
|
||||
class FillBucket : public Bucket {
|
||||
@@ -17,7 +19,8 @@ public:
|
||||
|
||||
virtual void render(Painter& painter, const std::string& layer_name);
|
||||
|
||||
void addGeometry(pbf& data);
|
||||
void addGeometry(pbf& data, const BucketDescription& bucket_desc);
|
||||
void addGeometry(const std::vector<Coordinate>& line, const BucketDescription& bucket_desc);
|
||||
void drawElements(int32_t attrib);
|
||||
void drawVertices(int32_t attrib);
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace llmr {
|
||||
|
||||
class Style;
|
||||
class LineBuffer;
|
||||
class BucketDescription;
|
||||
struct Coordinate;
|
||||
struct pbf;
|
||||
|
||||
class LineBucket : public Bucket {
|
||||
@@ -17,11 +19,13 @@ public:
|
||||
|
||||
virtual void render(Painter& painter, const std::string& layer_name);
|
||||
|
||||
void addGeometry(pbf& data);
|
||||
void addGeometry(pbf& data, const BucketDescription& bucket_desc);
|
||||
void addGeometry(const std::vector<Coordinate>& line, const BucketDescription& bucket_desc);
|
||||
|
||||
private:
|
||||
std::shared_ptr<LineBuffer> buffer;
|
||||
|
||||
uint32_t start;
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -18,12 +18,15 @@ enum class BucketType {
|
||||
enum class CapType {
|
||||
None = 0,
|
||||
Round = 1,
|
||||
Butt = 2,
|
||||
Square = 3
|
||||
};
|
||||
|
||||
enum class JoinType {
|
||||
None = 0,
|
||||
Butt = 1,
|
||||
Bevel = 2
|
||||
Bevel = 2,
|
||||
Round = 3
|
||||
};
|
||||
|
||||
|
||||
@@ -42,6 +45,8 @@ public:
|
||||
JoinType join = JoinType::None;
|
||||
std::string font;
|
||||
float font_size = 0.0f;
|
||||
float miter_limit = 2.0f;
|
||||
float round_limit = 1.0f;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream&, const BucketDescription& bucket);
|
||||
|
||||
@@ -22,7 +22,6 @@ enum class Winding {
|
||||
// Bevel = 2
|
||||
// };
|
||||
|
||||
|
||||
enum class Property {
|
||||
Null = 1,
|
||||
Constant = 2,
|
||||
@@ -59,6 +58,7 @@ struct LineClass {
|
||||
FunctionProperty<float> width;
|
||||
FunctionProperty<float> offset;
|
||||
Color color = {{ 0, 0, 0, 1 }};
|
||||
FunctionProperty<float> opacity = 1;
|
||||
};
|
||||
|
||||
// LineProperties is the one we resolve this to.
|
||||
@@ -67,6 +67,7 @@ struct LineProperties {
|
||||
float width = 0;
|
||||
float offset = 0;
|
||||
Color color = {{ 0, 0, 0, 1 }};
|
||||
float opacity = 1.0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "vec.hpp"
|
||||
|
||||
namespace llmr {
|
||||
namespace util {
|
||||
|
||||
@@ -10,6 +12,22 @@ inline double angle_between(double ax, double ay, double bx, double by) {
|
||||
return atan2((ax * by - ay * bx), ax * bx + ay * by);
|
||||
}
|
||||
|
||||
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);
|
||||
return { dx / c, dy / c };
|
||||
}
|
||||
|
||||
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);
|
||||
return c;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,29 @@
|
||||
#ifndef llmr_util_vec2_
|
||||
#define llmr_util_vec2_
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
template <typename T = double>
|
||||
struct vec2 {
|
||||
struct null {};
|
||||
|
||||
T x, y;
|
||||
|
||||
inline vec2() {}
|
||||
inline vec2(null) : x(std::numeric_limits<T>::quiet_NaN()), y(std::numeric_limits<T>::quiet_NaN()) {}
|
||||
|
||||
inline vec2(const vec2& o) : x(o.x), y(o.y) {}
|
||||
inline vec2(T x, T y) : x(x), y(y) {}
|
||||
inline bool operator==(const vec2& rhs) const {
|
||||
return x == rhs.x && y == rhs.y;
|
||||
}
|
||||
|
||||
template<typename U = T, typename std::enable_if<std::numeric_limits<U>::has_quiet_NaN, int>::type = 0>
|
||||
inline operator bool() const {
|
||||
return isnan(x) || isnan(y);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T = double>
|
||||
|
||||
@@ -8,11 +8,14 @@ enum bucket_type {
|
||||
|
||||
enum cap_type {
|
||||
round = 1;
|
||||
butt = 2;
|
||||
square = 3;
|
||||
}
|
||||
|
||||
enum join_type {
|
||||
butt = 1;
|
||||
bevel = 2;
|
||||
round = 3;
|
||||
}
|
||||
|
||||
enum winding_type {
|
||||
|
||||
@@ -170,7 +170,7 @@ std::shared_ptr<Bucket> Tile::createFillBucket(const VectorTileLayer& layer, con
|
||||
while (feature.next(4)) { // geometry
|
||||
pbf geometry_pbf = feature.message();
|
||||
if (geometry_pbf) {
|
||||
bucket->addGeometry(geometry_pbf);
|
||||
bucket->addGeometry(geometry_pbf, bucket_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,7 +186,7 @@ std::shared_ptr<Bucket> Tile::createLineBucket(const VectorTileLayer& layer, con
|
||||
while (feature.next(4)) { // geometry
|
||||
pbf geometry_pbf = feature.message();
|
||||
if (geometry_pbf) {
|
||||
bucket->addGeometry(geometry_pbf);
|
||||
bucket->addGeometry(geometry_pbf, bucket_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
|
||||
using namespace llmr;
|
||||
|
||||
const Coordinate Coordinate::null(
|
||||
std::numeric_limits<int16_t>::min(),
|
||||
std::numeric_limits<int16_t>::min()
|
||||
);
|
||||
|
||||
VectorTile::VectorTile() {}
|
||||
|
||||
VectorTile::VectorTile(pbf tile) {
|
||||
@@ -151,19 +156,3 @@ bool FilteredVectorTileLayer::iterator::operator!=(const iterator& other) const
|
||||
const pbf& FilteredVectorTileLayer::iterator:: operator*() const {
|
||||
return feature;
|
||||
}
|
||||
|
||||
// class FilteredVectorTileLayer {
|
||||
// public:
|
||||
// class iterator {
|
||||
// public:
|
||||
// void operator++();
|
||||
// bool operator!=(const iterator& other) const;
|
||||
// const VectorTileFeature& operator*() const;
|
||||
|
||||
// private:
|
||||
// iterator(const pbf& data);
|
||||
// VectorTileFeature feature;
|
||||
// pbf data;
|
||||
// };
|
||||
|
||||
// };
|
||||
|
||||
@@ -22,78 +22,77 @@ FillBucket::FillBucket(const std::shared_ptr<FillBuffer>& buffer)
|
||||
length(0) {
|
||||
}
|
||||
|
||||
void FillBucket::addGeometry(pbf& geom) {
|
||||
std::vector<std::vector<std::pair<int16_t, int16_t>>> lines;
|
||||
void FillBucket::addGeometry(pbf& geom, const BucketDescription& bucket_desc) {
|
||||
std::vector<Coordinate> line;
|
||||
Geometry::command cmd;
|
||||
|
||||
{
|
||||
std::vector<std::pair<int16_t, int16_t>> line;
|
||||
Geometry::command cmd;
|
||||
int32_t x, y;
|
||||
Geometry geometry(geom);
|
||||
while ((cmd = geometry.next(x, y)) != Geometry::end) {
|
||||
if (cmd == Geometry::move_to) {
|
||||
if (line.size()) {
|
||||
lines.push_back(line);
|
||||
line.clear();
|
||||
}
|
||||
Coordinate coord;
|
||||
Geometry geometry(geom);
|
||||
int32_t x, y;
|
||||
while ((cmd = geometry.next(x, y)) != Geometry::end) {
|
||||
if (cmd == Geometry::move_to) {
|
||||
if (line.size()) {
|
||||
addGeometry(line, bucket_desc);
|
||||
line.clear();
|
||||
}
|
||||
line.emplace_back(x, y);
|
||||
}
|
||||
if (line.size()) {
|
||||
lines.push_back(line);
|
||||
}
|
||||
line.emplace_back(x, y);
|
||||
}
|
||||
if (line.size()) {
|
||||
addGeometry(line, bucket_desc);
|
||||
}
|
||||
}
|
||||
|
||||
void FillBucket::addGeometry(const std::vector<Coordinate>& line, const BucketDescription& bucket_desc) {
|
||||
// Alias this.
|
||||
FillBuffer& buffer = *this->buffer;
|
||||
|
||||
for (const std::vector<std::pair<int16_t, int16_t>>& line : lines) {
|
||||
uint32_t vertex_start = buffer.vertex_length();
|
||||
uint32_t vertex_start = buffer.vertex_length();
|
||||
|
||||
buffer.addDegenerate();
|
||||
for (const std::pair<int16_t, int16_t>& coord : line) {
|
||||
buffer.addCoordinate(coord.first, coord.second);
|
||||
}
|
||||
|
||||
uint32_t vertex_end = buffer.vertex_length();
|
||||
|
||||
if (vertex_end - vertex_start > 65535) {
|
||||
throw geometry_too_long_exception();
|
||||
}
|
||||
|
||||
FillBucket& index = *this;
|
||||
if (!index.groups.size()) {
|
||||
index.groups.emplace_back();
|
||||
}
|
||||
|
||||
uint32_t vertex_count = vertex_end - vertex_start;
|
||||
index.length += vertex_count;
|
||||
|
||||
if (index.groups.back().vertex_length + vertex_count > 65535) {
|
||||
// Move to a new group because the old one can't hold the geometry.
|
||||
index.groups.emplace_back();
|
||||
}
|
||||
|
||||
group& group = index.groups.back();
|
||||
|
||||
// We're generating triangle fans, so we always start with the first
|
||||
// coordinate in this polygon.
|
||||
// The first valid index that is not a degenerate.
|
||||
uint16_t firstIndex = group.vertex_length + 1;
|
||||
|
||||
assert(firstIndex + vertex_count - 1 < 65536);
|
||||
|
||||
uint32_t elements_start = buffer.elements_length();
|
||||
|
||||
for (uint32_t i = 2; i < vertex_count; i++) {
|
||||
buffer.addElements(firstIndex, firstIndex + i - 1, firstIndex + i);
|
||||
}
|
||||
|
||||
uint32_t elements_end = buffer.elements_length();
|
||||
uint32_t elements_count = elements_end - elements_start;
|
||||
group.vertex_length += vertex_count;
|
||||
group.elements_length += elements_count;
|
||||
buffer.addDegenerate();
|
||||
for (const Coordinate& coord : line) {
|
||||
buffer.addCoordinate(coord.x, coord.y);
|
||||
}
|
||||
|
||||
uint32_t vertex_end = buffer.vertex_length();
|
||||
|
||||
if (vertex_end - vertex_start > 65535) {
|
||||
throw geometry_too_long_exception();
|
||||
}
|
||||
|
||||
FillBucket& index = *this;
|
||||
if (!index.groups.size()) {
|
||||
index.groups.emplace_back();
|
||||
}
|
||||
|
||||
uint32_t vertex_count = vertex_end - vertex_start;
|
||||
index.length += vertex_count;
|
||||
|
||||
if (index.groups.back().vertex_length + vertex_count > 65535) {
|
||||
// Move to a new group because the old one can't hold the geometry.
|
||||
index.groups.emplace_back();
|
||||
}
|
||||
|
||||
group& group = index.groups.back();
|
||||
|
||||
// We're generating triangle fans, so we always start with the first
|
||||
// coordinate in this polygon.
|
||||
// The first valid index that is not a degenerate.
|
||||
uint16_t firstIndex = group.vertex_length + 1;
|
||||
|
||||
assert(firstIndex + vertex_count - 1 < 65536);
|
||||
|
||||
uint32_t elements_start = buffer.elements_length();
|
||||
|
||||
for (uint32_t i = 2; i < vertex_count; i++) {
|
||||
buffer.addElements(firstIndex, firstIndex + i - 1, firstIndex + i);
|
||||
}
|
||||
|
||||
uint32_t elements_end = buffer.elements_length();
|
||||
uint32_t elements_count = elements_end - elements_start;
|
||||
group.vertex_length += vertex_count;
|
||||
group.elements_length += elements_count;
|
||||
|
||||
}
|
||||
|
||||
void FillBucket::drawElements(int32_t attrib) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <llmr/renderer/painter.hpp>
|
||||
#include <llmr/style/style.hpp>
|
||||
|
||||
#include <llmr/util/math.hpp>
|
||||
#include <llmr/platform/gl.hpp>
|
||||
|
||||
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
|
||||
@@ -16,11 +17,245 @@ struct geometry_too_long_exception : std::exception {};
|
||||
using namespace llmr;
|
||||
|
||||
LineBucket::LineBucket(const std::shared_ptr<LineBuffer>& buffer)
|
||||
: buffer(buffer) {
|
||||
: buffer(buffer),
|
||||
start(buffer->length()),
|
||||
length(0) {
|
||||
}
|
||||
|
||||
void LineBucket::addGeometry(pbf& geom) {
|
||||
void LineBucket::addGeometry(pbf& geom, const BucketDescription& bucket_desc) {
|
||||
std::vector<Coordinate> line;
|
||||
Geometry::command cmd;
|
||||
|
||||
Coordinate coord;
|
||||
Geometry geometry(geom);
|
||||
int32_t x, y;
|
||||
while ((cmd = geometry.next(x, y)) != Geometry::end) {
|
||||
if (cmd == Geometry::move_to) {
|
||||
if (line.size()) {
|
||||
addGeometry(line, bucket_desc);
|
||||
line.clear();
|
||||
}
|
||||
}
|
||||
line.emplace_back(x, y);
|
||||
}
|
||||
if (line.size()) {
|
||||
addGeometry(line, bucket_desc);
|
||||
}
|
||||
}
|
||||
|
||||
void LineBucket::addGeometry(const std::vector<Coordinate>& vertices, const BucketDescription& bucket_desc) {
|
||||
JoinType join = bucket_desc.join;
|
||||
CapType cap = bucket_desc.cap;
|
||||
float miterLimit = bucket_desc.miter_limit;
|
||||
float roundLimit = bucket_desc.round_limit;
|
||||
|
||||
if (vertices.size() < 1) {
|
||||
// alert('a line must have at least one vertex');
|
||||
return;
|
||||
}
|
||||
|
||||
// Point
|
||||
if (vertices.size() == 1) {
|
||||
Coordinate coord = vertices.front();
|
||||
buffer->add(coord.x, coord.y, 1, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
Coordinate firstVertex = vertices.front();
|
||||
Coordinate lastVertex = vertices.back();
|
||||
bool closed = firstVertex.x == lastVertex.x && firstVertex.y == lastVertex.y;
|
||||
|
||||
if (vertices.size() == 2 && closed) {
|
||||
// alert('a line may not have coincident points');
|
||||
return;
|
||||
}
|
||||
|
||||
CapType beginCap = cap;
|
||||
CapType endCap = closed ? CapType::Butt : cap;
|
||||
|
||||
Coordinate currentVertex = Coordinate::null,
|
||||
prevVertex = Coordinate::null,
|
||||
nextVertex = Coordinate::null;
|
||||
vec2<double> prevNormal = vec2<double>::null(),
|
||||
nextNormal = vec2<double>::null();
|
||||
|
||||
int8_t flip = 1;
|
||||
double distance = 0;
|
||||
|
||||
if (closed) {
|
||||
currentVertex = vertices[vertices.size() - 2];
|
||||
nextNormal = util::normal<double>(currentVertex, lastVertex);
|
||||
}
|
||||
|
||||
// Start all lines with a degenerate vertex
|
||||
buffer->addDegenerate();
|
||||
|
||||
for (size_t i = 0; i < vertices.size(); i++) {
|
||||
if (nextNormal) prevNormal = { -nextNormal.x, -nextNormal.y };
|
||||
if (currentVertex) prevVertex = currentVertex;
|
||||
|
||||
currentVertex = vertices[i];
|
||||
|
||||
if (prevVertex) distance += util::dist<double>(currentVertex, prevVertex);
|
||||
|
||||
// Find the next vertex.
|
||||
if (i + 1 < vertices.size()) {
|
||||
nextVertex = vertices[i + 1];
|
||||
} else {
|
||||
nextVertex = Coordinate::null;
|
||||
}
|
||||
|
||||
bool segment = false;
|
||||
|
||||
if (closed && i >= 2 && (i + 1 < vertices.size())) {
|
||||
segment = true;
|
||||
}
|
||||
|
||||
// If the line is closed, we treat the last vertex like the first vertex.
|
||||
if (!nextVertex && closed) {
|
||||
nextVertex = vertices[1];
|
||||
}
|
||||
|
||||
|
||||
if (nextVertex) {
|
||||
// if two consecutive vertices exist, skip one
|
||||
if (currentVertex.x == nextVertex.x && currentVertex.y == nextVertex.y) continue;
|
||||
}
|
||||
|
||||
// Calculate the normal towards the next vertex in this line. In case
|
||||
// there is no next vertex, pretend that the line is continuing straight,
|
||||
// meaning that we are just reversing the previous normal
|
||||
if (nextVertex) {
|
||||
nextNormal = util::normal<double>(currentVertex, nextVertex);
|
||||
} else {
|
||||
nextNormal = { -prevNormal.x, -prevNormal.y };
|
||||
}
|
||||
|
||||
// If we still don't have a previous normal, this is the beginning of a
|
||||
// non-closed line, so we're doing a straight "join".
|
||||
if (!prevNormal) {
|
||||
prevNormal = { -nextNormal.x, -nextNormal.y };
|
||||
}
|
||||
|
||||
// Determine the normal of the join extrusion. It is the angle bisector
|
||||
// of the segments between the previous line and the next line.
|
||||
vec2<double> joinNormal = {
|
||||
prevNormal.x + nextNormal.x,
|
||||
prevNormal.y + nextNormal.y
|
||||
};
|
||||
|
||||
// Cross product yields 0..1 depending on whether they are parallel
|
||||
// or perpendicular.
|
||||
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));
|
||||
|
||||
|
||||
bool roundJoin = false;
|
||||
// Determine whether we should actually draw a round/bevelled/butt line join. It looks
|
||||
// better if we do, but we can get away with drawing a mitered join for
|
||||
// joins that have a very small angle. For this, we have the "roundLimit"
|
||||
// parameter. We do this to reduce the number of vertices we have to
|
||||
// write into the line vertex buffer. Note that joinAngularity may be 0,
|
||||
// so the roundness grows to infinity. This is intended.
|
||||
if ((join == JoinType::Round || join == JoinType::Bevel || join == JoinType::Butt) && roundness > roundLimit) {
|
||||
roundJoin = true;
|
||||
}
|
||||
|
||||
// Close up the previous line for a round join
|
||||
if (roundJoin && prevVertex && nextVertex) {
|
||||
// Add first vertex
|
||||
buffer->add(currentVertex.x, currentVertex.y, // vertex pos
|
||||
flip * prevNormal.y, -flip * prevNormal.x, // extrude normal
|
||||
0, 0, distance); // texture normal
|
||||
|
||||
// Add second vertex.
|
||||
buffer->add(currentVertex.x, currentVertex.y, // vertex pos
|
||||
-flip * prevNormal.y, flip * prevNormal.x, // extrude normal
|
||||
0, 1, distance); // texture normal
|
||||
|
||||
// Degenerate triangle
|
||||
if (join == JoinType::Round || join == JoinType::Butt) {
|
||||
buffer->addDegenerate();
|
||||
}
|
||||
|
||||
if (join == JoinType::Round) prevVertex = Coordinate::null;
|
||||
|
||||
prevNormal = { -nextNormal.x, -nextNormal.y };
|
||||
flip = 1;
|
||||
}
|
||||
|
||||
// Add a cap.
|
||||
if (!prevVertex && (beginCap == CapType::Round || beginCap == CapType::Square || (roundJoin && join == JoinType::Round))) {
|
||||
int8_t tex = beginCap == CapType::Round || roundJoin ? 1 : 0;
|
||||
|
||||
// Add first vertex
|
||||
buffer->add(currentVertex.x, currentVertex.y, // vertex pos
|
||||
flip * (prevNormal.x + prevNormal.y), flip * (-prevNormal.x + prevNormal.y), // extrude normal
|
||||
tex, 0, distance); // texture normal
|
||||
|
||||
// Add second vertex
|
||||
buffer->add(currentVertex.x, currentVertex.y, // vertex pos
|
||||
flip * (prevNormal.x - prevNormal.y), flip * (prevNormal.x + prevNormal.y), // extrude normal
|
||||
tex, 1, distance); // texture normal
|
||||
}
|
||||
|
||||
if (roundJoin) {
|
||||
// ROUND JOIN
|
||||
// Add first vertex
|
||||
buffer->add(currentVertex.x, currentVertex.y, // vertex pos
|
||||
-flip * nextNormal.y, flip * nextNormal.x, // extrude normal
|
||||
0, 0, distance); // texture normal
|
||||
|
||||
// Add second vertex
|
||||
buffer->add(currentVertex.x, currentVertex.y, // vertex pos
|
||||
flip * nextNormal.y, -flip * nextNormal.x, // extrude normal
|
||||
0, 1, distance); // texture normal
|
||||
} else if ((nextVertex || endCap != CapType::Square) && (prevVertex || beginCap != CapType::Square)) {
|
||||
// MITER JOIN
|
||||
if (fabs(joinAngularity) < 0.01) {
|
||||
// The two normals are almost parallel.
|
||||
joinNormal.x = -nextNormal.y;
|
||||
joinNormal.y = nextNormal.x;
|
||||
} else if (roundness > miterLimit) {
|
||||
// If the miter grows too large, flip the direction to make a
|
||||
// bevel join.
|
||||
joinNormal.x = (prevNormal.x - nextNormal.x) / joinAngularity;
|
||||
joinNormal.y = (prevNormal.y - nextNormal.y) / joinAngularity;
|
||||
flip = -flip;
|
||||
}
|
||||
|
||||
// Add first vertex
|
||||
buffer->add(currentVertex.x, currentVertex.y, // vertex pos
|
||||
flip * joinNormal.x, flip * joinNormal.y, // extrude normal
|
||||
0, 0, distance); // texture normal
|
||||
|
||||
// Add second vertex
|
||||
buffer->add(currentVertex.x, currentVertex.y, // vertex pos
|
||||
-flip * joinNormal.x, -flip * joinNormal.y, // extrude normal
|
||||
0, 1, distance); // texture normal
|
||||
}
|
||||
|
||||
// Add the end cap, but only if this vertex is distinct from the begin
|
||||
// vertex.
|
||||
if (!nextVertex && (endCap == CapType::Round || endCap == CapType::Square)) {
|
||||
int8_t capTex = endCap == CapType::Round ? 1 : 0;
|
||||
|
||||
// Add first vertex
|
||||
buffer->add(currentVertex.x, currentVertex.y, // vertex pos
|
||||
nextNormal.x - flip * nextNormal.y, flip * nextNormal.x + nextNormal.y, // extrude normal
|
||||
capTex, 0, distance); // texture normal
|
||||
|
||||
// Add second vertex
|
||||
buffer->add(currentVertex.x, currentVertex.y, // vertex pos
|
||||
nextNormal.x + flip * nextNormal.y, -flip * nextNormal.x + nextNormal.y, // extrude normal
|
||||
capTex, 1, distance); // texture normal
|
||||
}
|
||||
}
|
||||
|
||||
// Update the length.
|
||||
length = buffer->length() - start;
|
||||
}
|
||||
|
||||
void LineBucket::render(Painter& painter, const std::string& layer_name) {
|
||||
|
||||
@@ -330,6 +330,8 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name) {
|
||||
|
||||
void Painter::renderLine(LineBucket& bucket, const std::string& layer_name) {
|
||||
const LineProperties& properties = style.computed.lines[layer_name];
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Painter::renderDebug(const Tile::Ptr& tile) {
|
||||
|
||||
@@ -206,6 +206,8 @@ void Style::cascade(float z) {
|
||||
const std::string& layer_name = fill_pair.first;
|
||||
const llmr::FillClass& layer = fill_pair.second;
|
||||
|
||||
// TODO: This should be restricted to fill styles that have actual
|
||||
// values so as to not override with default values.
|
||||
llmr::FillProperties& fill = computed.fills[layer_name];
|
||||
fill.hidden = layer.hidden(z);
|
||||
fill.winding = layer.winding;
|
||||
@@ -220,11 +222,14 @@ void Style::cascade(float z) {
|
||||
const std::string& layer_name = line_pair.first;
|
||||
const llmr::LineClass& layer = line_pair.second;
|
||||
|
||||
// TODO: This should be restricted to fill styles that have actual
|
||||
// values so as to not override with default values.
|
||||
llmr::LineProperties& stroke = computed.lines[layer_name];
|
||||
stroke.hidden = layer.hidden(z);
|
||||
stroke.width = layer.width(z);
|
||||
stroke.offset = layer.offset(z);
|
||||
stroke.color = layer.color;
|
||||
stroke.opacity = layer.opacity(z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user