Use single geometry format

This commit is contained in:
John Firebaugh
2015-03-09 17:39:37 -07:00
parent 50b5c15653
commit b7f04ee7c2
7 changed files with 281 additions and 312 deletions

View File

@@ -11,7 +11,7 @@ namespace mbgl {
class PBFGeometry : private util::noncopyable {
public:
inline explicit PBFGeometry(pbf& data);
inline explicit PBFGeometry(pbf data);
enum command : uint8_t {
end = 0,
@@ -23,14 +23,14 @@ public:
inline command next(int32_t &rx, int32_t &ry);
private:
pbf& data;
pbf data;
uint8_t cmd;
uint32_t length;
int32_t x, y;
int32_t ox, oy;
};
PBFGeometry::PBFGeometry(pbf& data_)
PBFGeometry::PBFGeometry(pbf data_)
: data(data_),
cmd(1),
length(0),

View File

@@ -26,13 +26,7 @@ enum class GeometryFeatureType : uint8_t {
Polygon = 3
};
typedef Coordinate GeometryPoint;
typedef std::vector<GeometryPoint> GeometryLine;
typedef std::vector<GeometryLine> GeometryPolygon;
using Geometry = mapbox::util::variant<std::false_type, GeometryPoint, GeometryLine, GeometryPolygon>;
typedef std::vector<Geometry> GeometryCollection;
typedef std::vector<std::vector<Coordinate>> GeometryCollection;
class GeometryTileFeature : public mbgl::util::noncopyable {
public:

View File

@@ -53,52 +53,25 @@ mapbox::util::optional<Value> VectorTileFeature::getValue(const std::string& key
GeometryCollection VectorTileFeature::getGeometries() const {
GeometryCollection result;
pbf geom_pbf = geometry_pbf;
while (geom_pbf.next(4)) { // geometry
pbf current_geometry_pbf = geom_pbf.message();
PBFGeometry current_geometry(current_geometry_pbf);
PBFGeometry::command cmd;
int32_t x, y;
PBFGeometry geometry(geometry_pbf);
PBFGeometry::command cmd;
int32_t x, y;
if (type == GeometryFeatureType::Point) {
if ((cmd = current_geometry.next(x, y)) != PBFGeometry::end) {
GeometryPoint point(x, y);
result.emplace_back(GeometryPoint(x, y));
}
} else if (type == GeometryFeatureType::LineString) {
GeometryLine line;
while ((cmd = current_geometry.next(x, y)) != PBFGeometry::end) {
if (cmd == PBFGeometry::move_to) {
if (!line.empty()) {
result.push_back(line);
line.clear();
}
}
line.emplace_back(x, y);
}
if (line.size()) {
result.push_back(line);
}
} else if (type == GeometryFeatureType::Polygon) {
GeometryLine line;
while ((cmd = current_geometry.next(x, y)) != PBFGeometry::end) {
if (cmd == PBFGeometry::move_to) {
if (line.size()) {
result.push_back(line);
line.clear();
}
}
line.emplace_back(x, y);
}
std::vector<Coordinate> line;
if (line.size()) {
while ((cmd = geometry.next(x, y)) != PBFGeometry::end) {
if (cmd == PBFGeometry::move_to) {
if (!line.empty()) {
result.push_back(line);
line.clear();
}
} else {
throw std::runtime_error("unrecognized geometry type");
}
line.emplace_back(x, y);
}
if (!line.empty()) {
result.push_back(line);
}
return std::move(result);

View File

@@ -66,13 +66,14 @@ FillBucket::~FillBucket() {
void FillBucket::addGeometry(const GeometryCollection& geometryCollection) {
for (auto& line_ : geometryCollection) {
const GeometryLine& vertices = line_.get<GeometryLine>();
for (auto& v : vertices) {
line.emplace_back(ClipperLib::IntPoint(v.x, v.y));
for (auto& v : line_) {
line.emplace_back(v.x, v.y);
}
if (line.size()) {
clipper.AddPath(line, ClipperLib::ptSubject, true);
line.clear();
hasVertices = true;
}
clipper.AddPath(line, ClipperLib::ptSubject, true);
line.clear();
hasVertices = true;
}
tessellate();

View File

@@ -43,290 +43,292 @@ typedef uint16_t PointElement;
void LineBucket::addGeometry(const GeometryCollection& geometryCollection) {
for (auto& line : geometryCollection) {
const GeometryLine& vertices = line.get<GeometryLine>();
addGeometry(line);
}
}
auto &layout = *styleLayout;
// TODO: use roundLimit
// const float roundLimit = geometry.round_limit;
void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
auto &layout = *styleLayout;
// TODO: use roundLimit
// const float roundLimit = geometry.round_limit;
if (vertices.size() < 2) {
// fprintf(stderr, "a line must have at least two vertices\n");
return;
if (vertices.size() < 2) {
// fprintf(stderr, "a line must have at least two vertices\n");
return;
}
Coordinate firstVertex = vertices.front();
Coordinate lastVertex = vertices.back();
bool closed = firstVertex.x == lastVertex.x && firstVertex.y == lastVertex.y;
if (vertices.size() == 2 && closed) {
// fprintf(stderr, "a line may not have coincident points\n");
return;
}
CapType beginCap = layout.cap;
CapType endCap = closed ? CapType::Butt : layout.cap;
JoinType currentJoin = JoinType::Miter;
Coordinate currentVertex = Coordinate::null(),
prevVertex = Coordinate::null(),
nextVertex = Coordinate::null();
vec2<double> prevNormal = vec2<double>::null(),
nextNormal = vec2<double>::null();
int32_t e1 = -1, e2 = -1, e3 = -1;
int8_t flip = 1;
double distance = 0;
if (closed) {
currentVertex = vertices[vertices.size() - 2];
nextNormal = util::normal<double>(currentVertex, lastVertex);
}
int32_t start_vertex = (int32_t)vertexBuffer.index();
std::vector<TriangleElement> triangle_store;
std::vector<PointElement> point_store;
for (size_t i = 0; i < vertices.size(); ++i) {
if (nextNormal) prevNormal = { -nextNormal.x, -nextNormal.y };
if (currentVertex) prevVertex = currentVertex;
currentVertex = vertices[i];
currentJoin = layout.join;
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();
}
Coordinate firstVertex = vertices.front();
Coordinate lastVertex = vertices.back();
bool closed = firstVertex.x == lastVertex.x && firstVertex.y == lastVertex.y;
if (vertices.size() == 2 && closed) {
// fprintf(stderr, "a line may not have coincident points\n");
return;
// If the line is closed, we treat the last vertex like the first vertex.
if (!nextVertex && closed) {
nextVertex = vertices[1];
}
CapType beginCap = layout.cap;
CapType endCap = closed ? CapType::Butt : layout.cap;
JoinType currentJoin = JoinType::Miter;
Coordinate currentVertex = Coordinate::null(),
prevVertex = Coordinate::null(),
nextVertex = Coordinate::null();
vec2<double> prevNormal = vec2<double>::null(),
nextNormal = vec2<double>::null();
int32_t e1 = -1, e2 = -1, e3 = -1;
int8_t flip = 1;
double distance = 0;
if (closed) {
currentVertex = vertices[vertices.size() - 2];
nextNormal = util::normal<double>(currentVertex, lastVertex);
if (nextVertex) {
// if two consecutive vertices exist, skip one
if (currentVertex.x == nextVertex.x && currentVertex.y == nextVertex.y) continue;
}
int32_t start_vertex = (int32_t)vertexBuffer.index();
// 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 };
}
std::vector<TriangleElement> triangle_store;
std::vector<PointElement> point_store;
// 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 };
}
for (size_t i = 0; i < vertices.size(); ++i) {
if (nextNormal) prevNormal = { -nextNormal.x, -nextNormal.y };
if (currentVertex) prevVertex = currentVertex;
// 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
};
currentVertex = vertices[i];
currentJoin = layout.join;
// 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 = std::fmax(std::abs(joinNormal.x), std::abs(joinNormal.y));
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();
// Switch to miter joins if the angle is very low.
if (currentJoin != JoinType::Miter) {
if (std::fabs(joinAngularity) < 0.5 && roundness < layout.miter_limit) {
currentJoin = JoinType::Miter;
}
}
// Add offset square begin cap.
if (!prevVertex && beginCap == CapType::Square) {
// Add first vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
flip * (prevNormal.x + prevNormal.y), flip * (-prevNormal.x + prevNormal.y), // extrude normal
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// Add second vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
flip * (prevNormal.x - prevNormal.y), flip * (prevNormal.x + prevNormal.y), // extrude normal
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
}
// Add offset square end cap.
else if (!nextVertex && endCap == CapType::Square) {
// Add first vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
nextNormal.x - flip * nextNormal.y, flip * nextNormal.x + nextNormal.y, // extrude normal
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// Add second vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
nextNormal.x + flip * nextNormal.y, -flip * nextNormal.x + nextNormal.y, // extrude normal
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
}
else if (currentJoin == JoinType::Miter) {
// MITER JOIN
if (std::fabs(joinAngularity) < 0.01) {
// The two normals are almost parallel.
joinNormal.x = -nextNormal.y;
joinNormal.y = nextNormal.x;
} else if (roundness > layout.miter_limit) {
// 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;
}
// If the line is closed, we treat the last vertex like the first vertex.
if (!nextVertex && closed) {
nextVertex = vertices[1];
if (roundness > layout.miter_limit) {
flip = -flip;
}
if (nextVertex) {
// if two consecutive vertices exist, skip one
if (currentVertex.x == nextVertex.x && currentVertex.y == nextVertex.y) continue;
// Add first vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
flip * joinNormal.x, flip * joinNormal.y, // extrude normal
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// Add second vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
-flip * joinNormal.x, -flip * joinNormal.y, // extrude normal
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
if ((!prevVertex && beginCap == CapType::Round) ||
(!nextVertex && endCap == CapType::Round)) {
point_store.emplace_back(e1);
}
}
else {
// Close up the previous line
// Add first vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
flip * prevNormal.y, -flip * prevNormal.x, // extrude normal
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// Add second vertex.
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
-flip * prevNormal.y, flip * prevNormal.x, // extrude normal
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
prevNormal = { -nextNormal.x, -nextNormal.y };
flip = 1;
// begin/end caps
if ((!prevVertex && beginCap == CapType::Round) ||
(!nextVertex && endCap == CapType::Round)) {
point_store.emplace_back(e1);
}
// 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 = 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 (std::fabs(joinAngularity) < 0.5 && roundness < layout.miter_limit) {
currentJoin = JoinType::Miter;
}
}
// Add offset square begin cap.
if (!prevVertex && beginCap == CapType::Square) {
// Add first vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
flip * (prevNormal.x + prevNormal.y), flip * (-prevNormal.x + prevNormal.y), // extrude normal
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// Add second vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
flip * (prevNormal.x - prevNormal.y), flip * (prevNormal.x + prevNormal.y), // extrude normal
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
}
// Add offset square end cap.
else if (!nextVertex && endCap == CapType::Square) {
// Add first vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
nextNormal.x - flip * nextNormal.y, flip * nextNormal.x + nextNormal.y, // extrude normal
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// Add second vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
nextNormal.x + flip * nextNormal.y, -flip * nextNormal.x + nextNormal.y, // extrude normal
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
}
else if (currentJoin == JoinType::Miter) {
// MITER JOIN
if (std::fabs(joinAngularity) < 0.01) {
// The two normals are almost parallel.
joinNormal.x = -nextNormal.y;
joinNormal.y = nextNormal.x;
} else if (roundness > layout.miter_limit) {
// 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;
}
if (roundness > layout.miter_limit) {
flip = -flip;
}
// Add first vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
flip * joinNormal.x, flip * joinNormal.y, // extrude normal
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// Add second vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
-flip * joinNormal.x, -flip * joinNormal.y, // extrude normal
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
if ((!prevVertex && beginCap == CapType::Round) ||
(!nextVertex && endCap == CapType::Round)) {
point_store.emplace_back(e1);
}
}
else {
// Close up the previous line
// Add first vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
flip * prevNormal.y, -flip * prevNormal.x, // extrude normal
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// Add second vertex.
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
-flip * prevNormal.y, flip * prevNormal.x, // extrude normal
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
prevNormal = { -nextNormal.x, -nextNormal.y };
flip = 1;
// begin/end caps
if ((!prevVertex && beginCap == CapType::Round) ||
(!nextVertex && endCap == CapType::Round)) {
if (currentJoin == JoinType::Round) {
if (prevVertex && nextVertex && (!closed || i > 0)) {
point_store.emplace_back(e1);
}
if (currentJoin == JoinType::Round) {
if (prevVertex && nextVertex && (!closed || i > 0)) {
point_store.emplace_back(e1);
}
// Reset the previous vertices so that we don't accidentally create
// any triangles.
e1 = -1; e2 = -1; e3 = -1;
}
// Start the new quad.
// Add first vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
-flip * nextNormal.y, flip * nextNormal.x, // extrude normal
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// Add second vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
flip * nextNormal.y, -flip * nextNormal.x, // extrude normal
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// Reset the previous vertices so that we don't accidentally create
// any triangles.
e1 = -1; e2 = -1; e3 = -1;
}
// Start the new quad.
// Add first vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
-flip * nextNormal.y, flip * nextNormal.x, // extrude normal
0, 0, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
// Add second vertex
e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos
flip * nextNormal.y, -flip * nextNormal.x, // extrude normal
0, 1, distance) - start_vertex; // texture normal
if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3);
e1 = e2; e2 = e3;
}
}
size_t end_vertex = vertexBuffer.index();
size_t vertex_count = end_vertex - start_vertex;
// Store the triangle/line groups.
{
if (!triangleGroups.size() || (triangleGroups.back()->vertex_length + vertex_count > 65535)) {
// Move to a new group because the old one can't hold the geometry.
triangleGroups.emplace_back(util::make_unique<triangle_group_type>());
}
size_t end_vertex = vertexBuffer.index();
size_t vertex_count = end_vertex - start_vertex;
// Store the triangle/line groups.
{
if (!triangleGroups.size() || (triangleGroups.back()->vertex_length + vertex_count > 65535)) {
// Move to a new group because the old one can't hold the geometry.
triangleGroups.emplace_back(util::make_unique<triangle_group_type>());
}
assert(triangleGroups.back());
triangle_group_type& group = *triangleGroups.back();
for (const TriangleElement& triangle : triangle_store) {
triangleElementsBuffer.add(
group.vertex_length + triangle.a,
group.vertex_length + triangle.b,
group.vertex_length + triangle.c
);
}
group.vertex_length += vertex_count;
group.elements_length += triangle_store.size();
assert(triangleGroups.back());
triangle_group_type& group = *triangleGroups.back();
for (const TriangleElement& triangle : triangle_store) {
triangleElementsBuffer.add(
group.vertex_length + triangle.a,
group.vertex_length + triangle.b,
group.vertex_length + triangle.c
);
}
// Store the line join/cap groups.
{
if (!pointGroups.size() || (pointGroups.back()->vertex_length + vertex_count > 65535)) {
// Move to a new group because the old one can't hold the geometry.
pointGroups.emplace_back(util::make_unique<point_group_type>());
}
group.vertex_length += vertex_count;
group.elements_length += triangle_store.size();
}
assert(pointGroups.back());
point_group_type& group = *pointGroups.back();
for (PointElement point : point_store) {
pointElementsBuffer.add(group.vertex_length + point);
}
group.vertex_length += vertex_count;
group.elements_length += point_store.size();
// Store the line join/cap groups.
{
if (!pointGroups.size() || (pointGroups.back()->vertex_length + vertex_count > 65535)) {
// Move to a new group because the old one can't hold the geometry.
pointGroups.emplace_back(util::make_unique<point_group_type>());
}
assert(pointGroups.back());
point_group_type& group = *pointGroups.back();
for (PointElement point : point_store) {
pointElementsBuffer.add(group.vertex_length + point);
}
group.vertex_length += vertex_count;
group.elements_length += point_store.size();
}
}

View File

@@ -38,6 +38,7 @@ public:
bool hasData() const override;
void addGeometry(const GeometryCollection&);
void addGeometry(const std::vector<Coordinate>& line);
bool hasPoints() const;

View File

@@ -107,9 +107,7 @@ std::vector<SymbolFeature> SymbolBucket::processFeatures(const GeometryTileLayer
auto &multiline = ft.geometry;
GeometryCollection geometryCollection = feature->getGeometries();
multiline.emplace_back();
for (auto& geometry : geometryCollection) {
const GeometryLine& line = geometry.get<GeometryLine>();
for (auto& line : geometryCollection) {
multiline.emplace_back();
for (auto& point : line) {
multiline.back().emplace_back(point.x, point.y);