parse geometry collections from the pbfs; iterate geometries in buckets
This commit is contained in:
committed by
John Firebaugh
parent
685aa01043
commit
405137700b
@@ -32,13 +32,15 @@ typedef std::vector<GeometryLine> GeometryPolygon;
|
||||
|
||||
using Geometry = mapbox::util::variant<std::false_type, GeometryPoint, GeometryLine, GeometryPolygon>;
|
||||
|
||||
typedef std::vector<Geometry> GeometryCollection;
|
||||
|
||||
std::ostream& operator<<(std::ostream&, const GeometryFeatureType& type);
|
||||
|
||||
class GeometryTileLayer;
|
||||
|
||||
class GeometryTileFeature {
|
||||
public:
|
||||
virtual Geometry nextGeometry() = 0;
|
||||
virtual GeometryCollection nextGeometry() = 0;
|
||||
|
||||
public:
|
||||
uint64_t id = 0;
|
||||
|
||||
@@ -220,10 +220,12 @@ template <class Bucket>
|
||||
if (obsolete())
|
||||
return;
|
||||
|
||||
Geometry geometry = feature->nextGeometry();
|
||||
while (!geometry.is<std::false_type>()) {
|
||||
GeometryCollection geometry = feature->nextGeometry();
|
||||
if (geometry.size()) {
|
||||
bucket->addGeometry(geometry);
|
||||
geometry = feature->nextGeometry();
|
||||
} else if (debug::tileParseWarnings) {
|
||||
fprintf(stderr, "[WARNING] geometry is empty\n");
|
||||
}
|
||||
|
||||
feature = filtered_layer->nextMatchingFeature();
|
||||
|
||||
@@ -43,47 +43,50 @@ VectorTileFeature::VectorTileFeature(pbf feature_pbf, const util::ptr<GeometryTi
|
||||
}
|
||||
}
|
||||
|
||||
Geometry VectorTileFeature::nextGeometry() {
|
||||
GeometryCollection VectorTileFeature::nextGeometry() {
|
||||
|
||||
GeometryCollection result;
|
||||
|
||||
pbf current_geometry_pbf = geometry_pbf.message();
|
||||
PBFGeometry current_geometry(current_geometry_pbf);
|
||||
int32_t x, y;
|
||||
Geometry result;
|
||||
result.set<std::false_type>();
|
||||
|
||||
if (multigeometry || geometry_pbf.next(4)) {
|
||||
while (geometry_pbf.next(4)) { // geometry
|
||||
if (type == GeometryFeatureType::Point) {
|
||||
current_geometry.next(x, y);
|
||||
GeometryPoint point(x, y);
|
||||
result.set<GeometryPoint>(point);
|
||||
result.emplace_back(GeometryPoint(x, y));
|
||||
} else if (type == GeometryFeatureType::LineString) {
|
||||
GeometryLine line;
|
||||
PBFGeometry::command cmd;
|
||||
while ((cmd = current_geometry.next(x, y)) != PBFGeometry::end) {
|
||||
if (cmd == PBFGeometry::move_to) {
|
||||
multigeometry = true;
|
||||
result.set<GeometryLine>(line);
|
||||
break;
|
||||
} else {
|
||||
line.emplace_back(x, y);
|
||||
if (!line.empty()) {
|
||||
result.push_back(line);
|
||||
line.clear();
|
||||
}
|
||||
}
|
||||
line.emplace_back(x, y);
|
||||
}
|
||||
if (!multigeometry) {
|
||||
result.set<GeometryLine>(line);
|
||||
if (line.size()) {
|
||||
result.push_back(line);
|
||||
}
|
||||
} else if (type == GeometryFeatureType::Polygon) {
|
||||
GeometryPolygon polygon;
|
||||
GeometryLine line;
|
||||
PBFGeometry::command cmd;
|
||||
while ((cmd = current_geometry.next(x, y)) != PBFGeometry::end) {
|
||||
if (cmd == PBFGeometry::move_to) {
|
||||
multigeometry = true;
|
||||
result.set<GeometryPolygon>(polygon);
|
||||
break;
|
||||
} else {
|
||||
// polygon.emplace_back(x, y);
|
||||
if (line.size()) {
|
||||
result.push_back(line);
|
||||
line.clear();
|
||||
}
|
||||
}
|
||||
line.emplace_back(x, y);
|
||||
}
|
||||
if (!multigeometry) {
|
||||
result.set<GeometryPolygon>(polygon);
|
||||
|
||||
if (line.size()) {
|
||||
result.push_back(line);
|
||||
line.clear();
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("unrecognized geometry type");
|
||||
|
||||
@@ -15,11 +15,10 @@ class VectorTileFeature : public GeometryTileFeature {
|
||||
public:
|
||||
VectorTileFeature(pbf, const util::ptr<GeometryTileLayer>);
|
||||
|
||||
Geometry nextGeometry();
|
||||
GeometryCollection nextGeometry();
|
||||
|
||||
private:
|
||||
pbf geometry_pbf;
|
||||
bool multigeometry = false;
|
||||
};
|
||||
|
||||
class FilteredVectorTileLayer : public GeometryFilteredTileLayer {
|
||||
|
||||
@@ -64,12 +64,11 @@ FillBucket::~FillBucket() {
|
||||
}
|
||||
}
|
||||
|
||||
void FillBucket::addGeometry(const Geometry& fill) {
|
||||
const GeometryPolygon& polygon = fill.get<GeometryPolygon>();
|
||||
|
||||
for (auto line_it = polygon.begin(); line_it != polygon.end(); line_it++) {
|
||||
for (auto point_it = line_it->begin(); point_it != line_it->end(); point_it++) {
|
||||
line.emplace_back(point_it->x, point_it->y);
|
||||
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));
|
||||
}
|
||||
clipper.AddPath(line, ClipperLib::ptSubject, true);
|
||||
line.clear();
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
const mat4 &matrix) override;
|
||||
bool hasData() const override;
|
||||
|
||||
void addGeometry(const Geometry& fill);
|
||||
void addGeometry(const GeometryCollection&);
|
||||
void tessellate();
|
||||
|
||||
void drawElements(PlainShader& shader);
|
||||
|
||||
@@ -41,290 +41,292 @@ struct TriangleElement {
|
||||
|
||||
typedef uint16_t PointElement;
|
||||
|
||||
void LineBucket::addGeometry(const Geometry &line) {
|
||||
const GeometryLine& vertices = line.get<GeometryLine>();
|
||||
void LineBucket::addGeometry(const GeometryCollection& geometryCollection) {
|
||||
for (auto& line : geometryCollection) {
|
||||
const GeometryLine& vertices = line.get<GeometryLine>();
|
||||
|
||||
auto &layout = *styleLayout;
|
||||
// TODO: use roundLimit
|
||||
// const float roundLimit = geometry.round_limit;
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
if (vertices.size() < 2) {
|
||||
// fprintf(stderr, "a line must have at least two vertices\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// If the line is closed, we treat the last vertex like the first vertex.
|
||||
if (!nextVertex && closed) {
|
||||
nextVertex = vertices[1];
|
||||
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 (nextVertex) {
|
||||
// if two consecutive vertices exist, skip one
|
||||
if (currentVertex.x == nextVertex.x && currentVertex.y == nextVertex.y) continue;
|
||||
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);
|
||||
}
|
||||
|
||||
// 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 };
|
||||
}
|
||||
int32_t start_vertex = (int32_t)vertexBuffer.index();
|
||||
|
||||
// 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 };
|
||||
}
|
||||
std::vector<TriangleElement> triangle_store;
|
||||
std::vector<PointElement> point_store;
|
||||
|
||||
// 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
|
||||
};
|
||||
for (size_t i = 0; i < vertices.size(); ++i) {
|
||||
if (nextNormal) prevNormal = { -nextNormal.x, -nextNormal.y };
|
||||
if (currentVertex) prevVertex = currentVertex;
|
||||
|
||||
// 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));
|
||||
currentVertex = vertices[i];
|
||||
currentJoin = layout.join;
|
||||
|
||||
if (prevVertex) distance += util::dist<double>(currentVertex, prevVertex);
|
||||
|
||||
// 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;
|
||||
// Find the next vertex.
|
||||
if (i + 1 < vertices.size()) {
|
||||
nextVertex = vertices[i + 1];
|
||||
} else {
|
||||
nextVertex = Coordinate::null();
|
||||
}
|
||||
|
||||
if (roundness > layout.miter_limit) {
|
||||
flip = -flip;
|
||||
// If the line is closed, we treat the last vertex like the first vertex.
|
||||
if (!nextVertex && closed) {
|
||||
nextVertex = vertices[1];
|
||||
}
|
||||
|
||||
// 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);
|
||||
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 (currentJoin == JoinType::Round) {
|
||||
if (prevVertex && nextVertex && (!closed || i > 0)) {
|
||||
// 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)) {
|
||||
point_store.emplace_back(e1);
|
||||
}
|
||||
|
||||
// Reset the previous vertices so that we don't accidentally create
|
||||
// any triangles.
|
||||
e1 = -1; e2 = -1; e3 = -1;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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>());
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
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>());
|
||||
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>());
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
group.vertex_length += vertex_count;
|
||||
group.elements_length += triangle_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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
const mat4 &matrix) override;
|
||||
bool hasData() const override;
|
||||
|
||||
void addGeometry(const Geometry& line);
|
||||
void addGeometry(const GeometryCollection&);
|
||||
|
||||
bool hasPoints() const;
|
||||
|
||||
|
||||
@@ -97,15 +97,14 @@ std::vector<SymbolFeature> SymbolBucket::processFeatures(const util::ptr<Geometr
|
||||
|
||||
auto &multiline = ft.geometry;
|
||||
|
||||
Geometry geometry = feature->nextGeometry();
|
||||
const GeometryLine& line = geometry.get<GeometryLine>();
|
||||
bool first = true;
|
||||
for (auto point_it = line.begin(); point_it != line.end(); point_it++) {
|
||||
if (first) {
|
||||
multiline.emplace_back();
|
||||
first = false;
|
||||
GeometryCollection geometryCollection = feature->nextGeometry();
|
||||
multiline.emplace_back();
|
||||
for (auto& geometry : geometryCollection) {
|
||||
const GeometryLine& line = geometry.get<GeometryLine>();
|
||||
multiline.emplace_back();
|
||||
for (auto& point : line) {
|
||||
multiline.back().emplace_back(point.x, point.y);
|
||||
}
|
||||
multiline.back().emplace_back(point_it->x, point_it->y);
|
||||
}
|
||||
|
||||
features.push_back(std::move(ft));
|
||||
|
||||
Reference in New Issue
Block a user