separate bucket render properties and change naming

This commit is contained in:
Konstantin Käfer
2014-06-16 11:49:11 +02:00
parent 610a9e4a63
commit 71d2b230a1
16 changed files with 362 additions and 236 deletions

View File

@@ -41,7 +41,7 @@ public:
FillBucket(FillVertexBuffer& vertexBuffer,
TriangleElementsBuffer& triangleElementsBuffer,
LineElementsBuffer& lineElementsBuffer,
const BucketDescription& bucket_desc);
const BucketFillDescription& properties);
~FillBucket();
virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id);
@@ -55,7 +55,7 @@ public:
void drawVertices(OutlineShader& shader);
public:
const BucketGeometryDescription geom_desc;
const BucketFillDescription &properties;
private:
TESSalloc *allocator;

View File

@@ -26,7 +26,7 @@ class VectorTileFeature;
class IconBucket : public Bucket {
public:
IconBucket(IconVertexBuffer& vertexBuffer,
const BucketDescription& bucket_desc);
const BucketIconDescription& properties);
virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id);
virtual bool hasData() const;
@@ -37,7 +37,7 @@ public:
void drawIcons(DotShader& shader);
public:
const BucketGeometryDescription geometry;
const BucketIconDescription &properties;
private:

View File

@@ -25,7 +25,7 @@ public:
LineBucket(LineVertexBuffer& vertexBuffer,
TriangleElementsBuffer& triangleElementsBuffer,
PointElementsBuffer& pointElementsBuffer,
const BucketDescription& bucket_desc);
const BucketLineDescription& properties);
virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id);
virtual bool hasData() const;
@@ -39,7 +39,7 @@ public:
void drawPoints(LinejoinShader& shader);
public:
const BucketGeometryDescription geometry;
const BucketLineDescription &properties;
private:

View File

@@ -28,7 +28,7 @@ public:
TextBucket(
TextVertexBuffer &vertexBuffer,
TriangleElementsBuffer &triangleElementsBuffer,
const BucketDescription &bucket_desc, Placement &placement);
const BucketTextDescription &properties, Placement &placement);
virtual void render(Painter &painter, const std::string &layer_name, const Tile::ID &id);
virtual bool hasData() const;
@@ -43,7 +43,7 @@ public:
void drawGlyphs(TextShader &shader);
public:
const BucketGeometryDescription &geom_desc;
const BucketTextDescription &properties;
private:
TextVertexBuffer& vertexBuffer;

View File

@@ -82,31 +82,50 @@ inline float verticalAlignmentType(const std::string& alignment) {
else return 0.5;
};
class BucketFillDescription {
public:
};
class BucketGeometryDescription {
class BucketLineDescription {
public:
CapType cap = CapType::None;
JoinType join = JoinType::None;
std::string font;
std::string field;
std::string icon;
float size = 0.0f;
float miter_limit = 2.0f;
float round_limit = 1.0f;
TextPathType path = TextPathType::Horizontal;
float alignment = 0.5;
float vertical_alignment = 0.5;
float line_height = 1.2 * 24;
float max_width = 15.0f * 24;
float letter_spacing = 0;
vec2<float> translate {0, 0};
float padding = 2.0f;
float textMinDistance = 250.0f;
float rotate = 0.0f; // what is this?
float maxAngleDelta = M_PI;
bool alwaysVisible = false;
};
class BucketIconDescription {
public:
uint16_t size = 16;
vec2<float> translate {0, 0};
std::string icon;
};
class BucketTextDescription {
public:
std::string field;
TextPathType path = TextPathType::Horizontal;
std::string font;
float max_size = 16.0f;
float max_width = 15.0f * 24;
float line_height = 1.2f * 24;
float letter_spacing = 0.0f;
float alignment = 0.5f;
float vertical_alignment = 0.5;
vec2<float> translate {0, 0};
float max_angle_delta = M_PI;
float min_distance = 250.0f;
float rotate = 0.0f; // what is this?
float padding = 2.0f;
bool always_visible = false;
};
class BucketRasterDescription {
public:
};
typedef util::variant<BucketFillDescription, BucketLineDescription, BucketIconDescription,
BucketTextDescription, BucketRasterDescription> BucketRenderDescription;
class BucketDescription {
public:
@@ -120,7 +139,7 @@ public:
PropertyFilterExpression filter = std::true_type();
// Specifies how the geometry for this bucket should be created
BucketGeometryDescription geometry;
BucketRenderDescription render;
};
std::ostream& operator<<(std::ostream&, const BucketDescription& bucket);

View File

@@ -10,14 +10,14 @@
namespace llmr {
class TextBucket;
class BucketGeometryDescription;
class BucketTextDescription;
class Placement {
public:
Placement(int8_t zoom);
void addFeature(TextBucket &bucket, const std::vector<Coordinate> &line,
const BucketGeometryDescription &info,
const BucketTextDescription &info,
const GlyphPositions &face,
const Shaping &shaping);

View File

@@ -166,24 +166,38 @@ void TileParser::addBucketFeatures(Bucket &bucket, const VectorTileLayer &layer,
std::unique_ptr<Bucket> TileParser::createFillBucket(const VectorTileLayer &layer,
const BucketDescription &bucket_desc) {
if (!bucket_desc.render.valid() || !bucket_desc.render.is<BucketFillDescription>()) {
return nullptr;
}
std::unique_ptr<FillBucket> bucket = std::make_unique<FillBucket>(
tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer, bucket_desc);
tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer,
bucket_desc.render.get<BucketFillDescription>());
addBucketFeatures(bucket, layer, bucket_desc);
return obsolete() ? nullptr : std::move(bucket);
}
std::unique_ptr<Bucket> TileParser::createLineBucket(const VectorTileLayer &layer,
const BucketDescription &bucket_desc) {
if (!bucket_desc.render.valid() || !bucket_desc.render.is<BucketLineDescription>()) {
return nullptr;
}
std::unique_ptr<LineBucket> bucket = std::make_unique<LineBucket>(
tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer, bucket_desc);
tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer,
bucket_desc.render.get<BucketLineDescription>());
addBucketFeatures(bucket, layer, bucket_desc);
return obsolete() ? nullptr : std::move(bucket);
}
std::unique_ptr<Bucket> TileParser::createIconBucket(const VectorTileLayer &layer,
const BucketDescription &bucket_desc) {
std::unique_ptr<IconBucket> bucket =
std::make_unique<IconBucket>(tile.iconVertexBuffer, bucket_desc);
if (!bucket_desc.render.valid() || !bucket_desc.render.is<BucketIconDescription>()) {
return nullptr;
}
std::unique_ptr<IconBucket> bucket = std::make_unique<IconBucket>(
tile.iconVertexBuffer, bucket_desc.render.get<BucketIconDescription>());
addBucketFeatures(bucket, layer, bucket_desc, *spriteAtlas);
return obsolete() ? nullptr : std::move(bucket);
}
@@ -192,8 +206,15 @@ typedef std::pair<uint16_t, uint16_t> GlyphRange;
std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer &layer,
const BucketDescription &bucket_desc) {
if (!bucket_desc.render.valid() || !bucket_desc.render.is<BucketTextDescription>()) {
return nullptr;
}
const BucketTextDescription &properties = bucket_desc.render.get<BucketTextDescription>();
std::unique_ptr<TextBucket> bucket = std::make_unique<TextBucket>(
tile.textVertexBuffer, tile.triangleElementsBuffer, bucket_desc, placement);
tile.textVertexBuffer, tile.triangleElementsBuffer, properties, placement);
util::utf8_to_utf32 ucs4conv;
@@ -210,7 +231,7 @@ std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer &laye
VectorTileFeature feature{feature_pbf, layer};
const std::u32string string = ucs4conv.convert(
util::replaceTokens(bucket_desc.geometry.field, feature.properties));
util::replaceTokens(properties.field, feature.properties));
// Loop through all characters of this text and collect unique codepoints.
for (uint32_t chr : string) {
@@ -220,23 +241,23 @@ std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer &laye
labels.emplace_back(string, feature.geometry);
}
glyphStore->waitForGlyphRanges(bucket_desc.geometry.font, ranges);
glyphStore->waitForGlyphRanges(properties.font, ranges);
}
// Create a copy!
const FontStack &fontStack = glyphStore->getFontStack(bucket_desc.geometry.font);
const FontStack &fontStack = glyphStore->getFontStack(properties.font);
GlyphPositions face;
// Shape and place all labels.
for (const std::pair<std::u32string, pbf> &label : labels) {
// Shape labels.
const Shaping shaping = fontStack.getShaping(label.first, bucket_desc.geometry.max_width,
bucket_desc.geometry.line_height, bucket_desc.geometry.alignment,
bucket_desc.geometry.vertical_alignment, bucket_desc.geometry.letter_spacing);
const Shaping shaping = fontStack.getShaping(label.first, properties.max_width,
properties.line_height, properties.alignment,
properties.vertical_alignment, properties.letter_spacing);
// Place labels.
addGlyph(tile.id.to_uint64(), bucket_desc.geometry.font, label.first, fontStack, *glyphAtlas,
addGlyph(tile.id.to_uint64(), properties.font, label.first, fontStack, *glyphAtlas,
face);
bucket->addFeature(label.second, face, shaping);

View File

@@ -30,30 +30,26 @@ void FillBucket::free(void *, void *ptr) {
::free(ptr);
}
FillBucket::FillBucket(FillVertexBuffer& vertexBuffer,
TriangleElementsBuffer& triangleElementsBuffer,
LineElementsBuffer& lineElementsBuffer,
const BucketDescription& bucket_desc)
: geom_desc(bucket_desc.geometry),
allocator(new TESSalloc {
&alloc,
&realloc,
&free,
nullptr, // userData
64, // meshEdgeBucketSize
64, // meshVertexBucketSize
32, // meshFaceBucketSize
64, // dictNodeBucketSize
8, // regionBucketSize
128, // extraVertices allocated for the priority queue.
}),
tesselator(tessNewTess(allocator)),
vertexBuffer(vertexBuffer),
triangleElementsBuffer(triangleElementsBuffer),
lineElementsBuffer(lineElementsBuffer),
vertex_start(vertexBuffer.index()),
triangle_elements_start(triangleElementsBuffer.index()),
line_elements_start(lineElementsBuffer.index()) {
FillBucket::FillBucket(FillVertexBuffer &vertexBuffer,
TriangleElementsBuffer &triangleElementsBuffer,
LineElementsBuffer &lineElementsBuffer,
const BucketFillDescription &properties)
: properties(properties),
allocator(new TESSalloc{&alloc, &realloc, &free, nullptr, // userData
64, // meshEdgeBucketSize
64, // meshVertexBucketSize
32, // meshFaceBucketSize
64, // dictNodeBucketSize
8, // regionBucketSize
128, // extraVertices allocated for the priority queue.
}),
tesselator(tessNewTess(allocator)),
vertexBuffer(vertexBuffer),
triangleElementsBuffer(triangleElementsBuffer),
lineElementsBuffer(lineElementsBuffer),
vertex_start(vertexBuffer.index()),
triangle_elements_start(triangleElementsBuffer.index()),
line_elements_start(lineElementsBuffer.index()) {
assert(tesselator);
}

View File

@@ -19,8 +19,8 @@ struct geometry_too_long_exception : std::exception {};
using namespace llmr;
IconBucket::IconBucket(IconVertexBuffer& vertexBuffer,
const BucketDescription& bucket_desc)
: geometry(bucket_desc.geometry),
const BucketIconDescription& properties)
: properties(properties),
vertexBuffer(vertexBuffer),
vertex_start(vertexBuffer.index()) {
}
@@ -28,15 +28,15 @@ IconBucket::IconBucket(IconVertexBuffer& vertexBuffer,
void IconBucket::addFeature(const VectorTileFeature &feature, SpriteAtlas &sprite_atlas) {
std::string field;
if (geometry.field.size()) {
field = util::replaceTokens(geometry.field, feature.properties);
if (properties.icon.size()) {
field = util::replaceTokens(properties.icon, feature.properties);
}
if (!field.size()) {
field = "<circle>";
}
const Rect<uint16_t> rect = sprite_atlas.getIcon(geometry.size, field);
const Rect<uint16_t> rect = sprite_atlas.getIcon(properties.size, field);
const uint16_t tx = rect.x + rect.w / 2;
const uint16_t ty = rect.y + rect.h / 2;

View File

@@ -20,8 +20,8 @@ using namespace llmr;
LineBucket::LineBucket(LineVertexBuffer& vertexBuffer,
TriangleElementsBuffer& triangleElementsBuffer,
PointElementsBuffer& pointElementsBuffer,
const BucketDescription& bucket_desc)
: geometry(bucket_desc.geometry),
const BucketLineDescription& properties)
: properties(properties),
vertexBuffer(vertexBuffer),
triangleElementsBuffer(triangleElementsBuffer),
pointElementsBuffer(pointElementsBuffer),
@@ -60,9 +60,6 @@ struct TriangleElement {
typedef uint16_t PointElement;
void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
const JoinType join = geometry.join;
const CapType cap = geometry.cap;
const float miterLimit = geometry.miter_limit;
// TODO: use roundLimit
// const float roundLimit = geometry.round_limit;
@@ -80,8 +77,8 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
return;
}
CapType beginCap = cap;
CapType endCap = closed ? CapType::Butt : cap;
CapType beginCap = properties.cap;
CapType endCap = closed ? CapType::Butt : properties.cap;
JoinType currentJoin = JoinType::None;
@@ -111,7 +108,7 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
if (currentVertex) prevVertex = currentVertex;
currentVertex = vertices[i];
currentJoin = join;
currentJoin = properties.join;
if (prevVertex) distance += util::dist<double>(currentVertex, prevVertex);
@@ -164,7 +161,7 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
// Switch to miter joins if the angle is very low.
if (currentJoin != JoinType::Miter) {
if (std::fabs(joinAngularity) < 0.5 && roundness < miterLimit) {
if (std::fabs(joinAngularity) < 0.5 && roundness < properties.miter_limit) {
currentJoin = JoinType::Miter;
}
}
@@ -213,14 +210,14 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
// The two normals are almost parallel.
joinNormal.x = -nextNormal.y;
joinNormal.y = nextNormal.x;
} else if (roundness > miterLimit) {
} else if (roundness > properties.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 > miterLimit) {
if (roundness > properties.miter_limit) {
flip = -flip;
}

View File

@@ -41,7 +41,7 @@ void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, cons
spriteAtlas.bind(map.getState().isChanging());
const float iconSize = bucket.geometry.size * map.getState().getPixelRatio();
const float iconSize = bucket.properties.size * map.getState().getPixelRatio();
iconShader->setSize(iconSize);
#ifndef GL_ES_VERSION_2_0
glPointSize(iconSize);

View File

@@ -20,7 +20,7 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons
mat4 exMatrix;
matrix::copy(exMatrix, projMatrix);
if (bucket.geom_desc.path == TextPathType::Curve) {
if (bucket.properties.path == TextPathType::Curve) {
matrix::rotate_z(exMatrix, exMatrix, map.getState().getAngle());
}
@@ -30,7 +30,7 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons
}
// If layerStyle.size > bucket.info.fontSize then labels may collide
float fontSize = std::fmin(properties.size, bucket.geom_desc.size);
float fontSize = std::fmin(properties.size, bucket.properties.max_size);
matrix::scale(exMatrix, exMatrix, fontSize / 24.0f, fontSize / 24.0f, 1.0f);
const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
@@ -48,10 +48,10 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons
float angle = std::round((map.getState().getAngle() + rotate) / M_PI * 128);
// adjust min/max zooms for variable font sies
float zoomAdjust = log(fontSize / bucket.geom_desc.size) / log(2);
float zoomAdjust = log(fontSize / bucket.properties.max_size) / log(2);
textShader->setAngle((int32_t)(angle + 256) % 256);
textShader->setFlip(bucket.geom_desc.path == TextPathType::Curve ? 1 : 0);
textShader->setFlip(bucket.properties.path == TextPathType::Curve ? 1 : 0);
textShader->setZoom((map.getState().getNormalizedZoom() - zoomAdjust) * 10); // current zoom level
// Label fading

View File

@@ -22,8 +22,8 @@ using namespace llmr;
TextBucket::TextBucket(
TextVertexBuffer &vertexBuffer,
TriangleElementsBuffer &triangleElementsBuffer,
const BucketDescription &bucket_desc, Placement &placement)
: geom_desc(bucket_desc.geometry),
const BucketTextDescription &properties, Placement &placement)
: properties(properties),
vertexBuffer(vertexBuffer),
triangleElementsBuffer(triangleElementsBuffer),
placement(placement),
@@ -113,14 +113,14 @@ void TextBucket::addFeature(const pbf &geom_pbf,
while ((cmd = geometry.next(x, y)) != Geometry::end) {
if (cmd == Geometry::move_to) {
if (!line.empty()) {
placement.addFeature(*this, line, geom_desc, face, shaping);
placement.addFeature(*this, line, properties, face, shaping);
line.clear();
}
}
line.emplace_back(x, y);
}
if (line.size()) {
placement.addFeature(*this, line, geom_desc, face, shaping);
placement.addFeature(*this, line, properties, face, shaping);
}
}

View File

@@ -8,10 +8,6 @@ std::ostream& llmr::operator<<(std::ostream& os, const BucketDescription& bucket
os << " - type: " << (uint32_t)bucket.type << std::endl;
os << " - source_name: " << bucket.source_name << std::endl;
os << " - source_layer: " << bucket.source_layer << std::endl;
os << " - cap: " << (uint32_t)bucket.geometry.cap << std::endl;
os << " - join: " << (uint32_t)bucket.geometry.join << std::endl;
os << " - font: " << bucket.geometry.font << std::endl;
os << " - size: " << bucket.geometry.size << std::endl;
return os;
}

View File

@@ -73,134 +73,40 @@ PropertyFilterExpression StyleParser::parseFilterOrExpression(JSVal value) {
BucketDescription StyleParser::parseBucket(JSVal value) {
BucketDescription bucket;
rapidjson::Value::ConstMemberIterator itr = value.MemberBegin();
for (; itr != value.MemberEnd(); ++itr) {
const std::string name(itr->name.GetString(), itr->name.GetStringLength());
JSVal value = itr->value;
if (name == "type") {
if (value.IsString()) {
bucket.type = bucketType({ value.GetString(), value.GetStringLength() });
} else {
throw Style::exception("bucket type must be a string");
}
} else if (name == "feature_type") {
if (value.IsString()) {
bucket.feature_type = bucketType({ value.GetString(), value.GetStringLength() });
} else {
throw Style::exception("feature type must be a string");
}
} else if (name == "source") {
if (value.IsString()) {
bucket.source_name = { value.GetString(), value.GetStringLength() };
} else {
throw Style::exception("source name must be a string");
}
} else if (name == "layer") {
if (value.IsString()) {
bucket.source_layer = { value.GetString(), value.GetStringLength() };
} else {
throw Style::exception("layer name must be a string");
}
} else if (name == "cap") {
if (value.IsString()) {
bucket.geometry.cap = capType({ value.GetString(), value.GetStringLength() });
} else {
throw Style::exception("cap type must be a string");
}
} else if (name == "join") {
if (value.IsString()) {
bucket.geometry.join = joinType({ value.GetString(), value.GetStringLength() });
} else {
throw Style::exception("join type must be a string");
}
} else if (name == "font") {
if (value.IsString()) {
bucket.geometry.font = { value.GetString(), value.GetStringLength() };
} else {
throw Style::exception("font stack must be a string");
}
} else if (name == "fontSize" || name == "size") {
if (value.IsNumber()) {
bucket.geometry.size = value.GetDouble();
} else {
throw Style::exception("font size must be a number");
}
} else if (name == "text_field" || name == "icon") {
if (value.IsString()) {
bucket.geometry.field = { value.GetString(), value.GetStringLength() };
} else {
throw Style::exception("text field must be a string");
}
} else if (name == "path") {
if (value.IsString()) {
bucket.geometry.path = textPathType({ value.GetString(), value.GetStringLength() });
} else {
throw Style::exception("curve must be a string");
}
} else if (name == "alignment") {
if (value.IsString()) {
bucket.geometry.alignment = alignmentType({ value.GetString(), value.GetStringLength() });
} else {
throw Style::exception("alignment must be a string");
}
} else if (name == "translate") {
if (value.IsArray()) {
bucket.geometry.translate.x = value[(rapidjson::SizeType)0].GetDouble() * 24;
bucket.geometry.translate.y = value[(rapidjson::SizeType)1].GetDouble() * -24;
} else {
throw Style::exception("translate must be a string");
}
} else if (name == "verticalAlignment") {
if (value.IsString()) {
bucket.geometry.vertical_alignment = verticalAlignmentType({ value.GetString(), value.GetStringLength() });
} else {
throw Style::exception("verticalAlignment must be a string");
}
} else if (name == "lineHeight") {
if (value.IsNumber()) {
bucket.geometry.line_height = value.GetDouble() * 24;
} else {
throw Style::exception("line height must be a number");
}
} else if (name == "maxWidth") {
if (value.IsNumber()) {
bucket.geometry.max_width = value.GetDouble() * 24;
} else {
throw Style::exception("max width must be a number");
}
} else if (name == "letterSpacing") {
if (value.IsNumber()) {
bucket.geometry.letter_spacing = value.GetDouble() * 24;
} else {
throw Style::exception("letter spacing must be a number");
}
} else if (name == "miterLimit") {
if (value.IsNumber()) {
bucket.geometry.miter_limit = value.GetDouble();
} else {
throw Style::exception("miter limit must be a number");
}
} else if (name == "roundLimit") {
if (value.IsNumber()) {
bucket.geometry.round_limit = value.GetDouble();
} else {
throw Style::exception("round limit must be a number");
}
} else if (name == "textMinDistance") {
if (value.IsNumber()) {
bucket.geometry.textMinDistance = value.GetDouble();
} else {
throw Style::exception("text min distance must be a number");
}
} else if (name == "maxAngleDelta") {
if (value.IsNumber()) {
bucket.geometry.maxAngleDelta = value.GetDouble();
} else {
throw Style::exception("max angle delta must be a number");
}
if (value.HasMember("type")) {
JSVal type = value["type"];
if (type.IsString()) {
bucket.type = bucketType({ type.GetString(), type.GetStringLength() });
} else {
throw Style::exception("bucket type must be a string");
}
}
if (value.HasMember("feature_type")) {
JSVal feature_type = value["feature_type"];
if (feature_type.IsString()) {
bucket.feature_type = bucketType({ feature_type.GetString(), feature_type.GetStringLength() });
} else {
throw Style::exception("feature type must be a string");
}
}
if (value.HasMember("source")) {
JSVal source = value["source"];
if (source.IsString()) {
bucket.source_name = { source.GetString(), source.GetStringLength() };
} else {
throw Style::exception("source name must be a string");
}
}
if (value.HasMember("layer")) {
JSVal source_layer = value["layer"];
if (source_layer.IsString()) {
bucket.source_layer = { source_layer.GetString(), source_layer.GetStringLength() };
} else {
throw Style::exception("layer name must be a string");
}
}
if (value.HasMember("filter")) {
@@ -214,6 +120,206 @@ BucketDescription StyleParser::parseBucket(JSVal value) {
bucket.feature_type = bucket.type;
}
switch (bucket.type) {
case BucketType::Fill: {
bucket.render = BucketFillDescription{};
} break;
case BucketType::Line: {
bucket.render = BucketLineDescription{};
BucketLineDescription &render = bucket.render.get<BucketLineDescription>();
if (value.HasMember("cap")) {
JSVal property = value["cap"];
if (property.IsString()) {
render.cap = capType({property.GetString(), property.GetStringLength()});
} else {
throw Style::exception("cap type must be a string");
}
}
if (value.HasMember("join")) {
JSVal property = value["join"];
if (property.IsString()) {
render.join = joinType({property.GetString(), property.GetStringLength()});
} else {
throw Style::exception("join type must be a string");
}
}
if (value.HasMember("miterLimit")) {
JSVal property = value["miterLimit"];
if (property.IsNumber()) {
render.miter_limit = property.GetDouble();
} else {
throw Style::exception("miter limit must be a number");
}
}
if (value.HasMember("roundLimit")) {
JSVal property = value["roundLimit"];
if (property.IsNumber()) {
render.round_limit = property.GetDouble();
} else {
throw Style::exception("round limit must be a number");
}
}
} break;
case BucketType::Icon: {
bucket.render = BucketIconDescription{};
BucketIconDescription &render = bucket.render.get<BucketIconDescription>();
if (value.HasMember("size")) {
JSVal property = value["size"];
if (property.IsNumber()) {
render.size = property.GetDouble();
} else {
throw Style::exception("font size must be a number");
}
}
if (value.HasMember("icon")) {
JSVal property = value["icon"];
if (property.IsString()) {
render.icon = {property.GetString(), property.GetStringLength()};
} else {
throw Style::exception("text field must be a string");
}
}
if (value.HasMember("translate")) {
JSVal property = value["translate"];
if (property.IsArray()) {
render.translate.x = property[(rapidjson::SizeType)0].GetDouble() * 24;
render.translate.y = property[(rapidjson::SizeType)1].GetDouble() * -24;
} else {
throw Style::exception("translate must be a string");
}
}
} break;
case BucketType::Text: {
bucket.render = BucketTextDescription{};
BucketTextDescription &render = bucket.render.get<BucketTextDescription>();
if (value.HasMember("text_field")) {
JSVal property = value["text_field"];
if (property.IsString()) {
render.field = {property.GetString(), property.GetStringLength()};
} else {
throw Style::exception("text field must be a string");
}
}
if (value.HasMember("path")) {
JSVal property = value["path"];
if (property.IsString()) {
render.path = textPathType({property.GetString(), property.GetStringLength()});
} else {
throw Style::exception("curve must be a string");
}
}
if (value.HasMember("font")) {
JSVal property = value["font"];
if (property.IsString()) {
render.font = {property.GetString(), property.GetStringLength()};
} else {
throw Style::exception("font stack must be a string");
}
}
if (value.HasMember("fontSize")) {
JSVal property = value["fontSize"];
if (property.IsNumber()) {
render.max_size = property.GetDouble();
} else {
throw Style::exception("font size must be a number");
}
}
if (value.HasMember("maxWidth")) {
JSVal property = value["maxWidth"];
if (property.IsNumber()) {
render.max_width = property.GetDouble() * 24;
} else {
throw Style::exception("max width must be a number");
}
}
if (value.HasMember("lineHeight")) {
JSVal property = value["lineHeight"];
if (property.IsNumber()) {
render.line_height = property.GetDouble() * 24;
} else {
throw Style::exception("line height must be a number");
}
}
if (value.HasMember("letterSpacing")) {
JSVal property = value["letterSpacing"];
if (property.IsNumber()) {
render.letter_spacing = property.GetDouble() * 24;
} else {
throw Style::exception("letter spacing must be a number");
}
}
if (value.HasMember("alignment")) {
JSVal property = value["alignment"];
if (property.IsString()) {
render.alignment =
alignmentType({property.GetString(), property.GetStringLength()});
} else {
throw Style::exception("alignment must be a string");
}
}
if (value.HasMember("verticalAlignment")) {
JSVal property = value["verticalAlignment"];
if (property.IsString()) {
render.vertical_alignment =
verticalAlignmentType({property.GetString(), property.GetStringLength()});
} else {
throw Style::exception("verticalAlignment must be a string");
}
}
if (value.HasMember("translate")) {
JSVal property = value["translate"];
if (property.IsArray()) {
render.translate.x = property[(rapidjson::SizeType)0].GetDouble() * 24;
render.translate.y = property[(rapidjson::SizeType)1].GetDouble() * -24;
} else {
throw Style::exception("translate must be a string");
}
}
if (value.HasMember("maxAngleDelta")) {
JSVal property = value["maxAngleDelta"];
if (property.IsNumber()) {
render.max_angle_delta = property.GetDouble();
} else {
throw Style::exception("max angle delta must be a number");
}
}
if (value.HasMember("textMinDistance")) {
JSVal property = value["textMinDistance"];
if (property.IsNumber()) {
render.min_distance = property.GetDouble();
} else {
throw Style::exception("text min distance must be a number");
}
}
} break;
case BucketType::Raster: {
bucket.render = BucketRasterDescription{};
} break;
default:
break;
}
return bucket;
}

View File

@@ -244,19 +244,11 @@ void getGlyphs(PlacedGlyphs &glyphs, GlyphBoxes &boxes,
}
}
void Placement::addFeature(TextBucket& bucket,
const std::vector<Coordinate> &line,
const BucketGeometryDescription &info,
const GlyphPositions &face,
void Placement::addFeature(TextBucket &bucket, const std::vector<Coordinate> &line,
const BucketTextDescription &info, const GlyphPositions &face,
const Shaping &shaping) {
const bool horizontal = info.path == TextPathType::Horizontal;
const float padding = info.padding;
const float maxAngleDelta = info.maxAngleDelta;
const float textMinDistance = info.textMinDistance;
const float rotate = info.rotate;
const float fontScale =
(tileExtent / util::tileSize) / (glyphSize / info.size);
const float fontScale = (tileExtent / util::tileSize) / (glyphSize / info.max_size);
Anchors anchors;
@@ -268,7 +260,7 @@ void Placement::addFeature(TextBucket& bucket,
} else {
// Line labels
anchors = interpolate(line, textMinDistance, minScale);
anchors = interpolate(line, info.min_distance, minScale);
// Sort anchors by segment so that we can start placement with
// the anchors that can be shown at the lowest zoom levels.
@@ -279,11 +271,10 @@ void Placement::addFeature(TextBucket& bucket,
PlacedGlyphs glyphs;
GlyphBoxes boxes;
getGlyphs(glyphs, boxes, anchor, info.translate, shaping, face, fontScale, horizontal,
line, maxAngleDelta, rotate);
PlacementProperty place =
collision.place(boxes, anchor, anchor.scale, maxPlacementScale,
padding, horizontal, info.alwaysVisible);
getGlyphs(glyphs, boxes, anchor, info.translate, shaping, face, fontScale, horizontal, line,
info.max_angle_delta, info.rotate);
PlacementProperty place = collision.place(boxes, anchor, anchor.scale, maxPlacementScale,
info.padding, horizontal, info.always_visible);
if (place) {
bucket.addGlyphs(glyphs, place.zoom, place.rotationRange, zoom - zOffset);
}