diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/map/tile_parser.cpp | 45 | ||||
-rw-r--r-- | src/renderer/fill_bucket.cpp | 44 | ||||
-rw-r--r-- | src/renderer/icon_bucket.cpp | 10 | ||||
-rw-r--r-- | src/renderer/line_bucket.cpp | 19 | ||||
-rw-r--r-- | src/renderer/painter_icon.cpp | 2 | ||||
-rw-r--r-- | src/renderer/painter_text.cpp | 8 | ||||
-rw-r--r-- | src/renderer/text_bucket.cpp | 8 | ||||
-rw-r--r-- | src/style/bucket_description.cpp | 4 | ||||
-rw-r--r-- | src/style/style_parser.cpp | 294 | ||||
-rw-r--r-- | src/text/placement.cpp | 25 |
10 files changed, 283 insertions, 176 deletions
diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 21d2bf1bfc..1c1268c809 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -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); diff --git a/src/renderer/fill_bucket.cpp b/src/renderer/fill_bucket.cpp index 7021566592..d7ba048a5c 100644 --- a/src/renderer/fill_bucket.cpp +++ b/src/renderer/fill_bucket.cpp @@ -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); } diff --git a/src/renderer/icon_bucket.cpp b/src/renderer/icon_bucket.cpp index fd43f69514..b6c324d2ad 100644 --- a/src/renderer/icon_bucket.cpp +++ b/src/renderer/icon_bucket.cpp @@ -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; diff --git a/src/renderer/line_bucket.cpp b/src/renderer/line_bucket.cpp index 58dde3f50b..d6d3dcf77f 100644 --- a/src/renderer/line_bucket.cpp +++ b/src/renderer/line_bucket.cpp @@ -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; } diff --git a/src/renderer/painter_icon.cpp b/src/renderer/painter_icon.cpp index 8ddf493d0d..8c07349b2a 100644 --- a/src/renderer/painter_icon.cpp +++ b/src/renderer/painter_icon.cpp @@ -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); diff --git a/src/renderer/painter_text.cpp b/src/renderer/painter_text.cpp index 5307a12acf..baebe26699 100644 --- a/src/renderer/painter_text.cpp +++ b/src/renderer/painter_text.cpp @@ -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 diff --git a/src/renderer/text_bucket.cpp b/src/renderer/text_bucket.cpp index da6de38171..bd18f0576f 100644 --- a/src/renderer/text_bucket.cpp +++ b/src/renderer/text_bucket.cpp @@ -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); } } diff --git a/src/style/bucket_description.cpp b/src/style/bucket_description.cpp index b154c3a176..24d086f64d 100644 --- a/src/style/bucket_description.cpp +++ b/src/style/bucket_description.cpp @@ -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; } diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index b686c0ec55..edce8d2b65 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -73,145 +73,251 @@ 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() }); + 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")) { + bucket.filter = std::move(parseFilterOrExpression(value["filter"])); + } else { + // Allow a filter triple to be specified at the bucket root as well. + bucket.filter = std::move(parseFilterOrExpression(value)); + } + + if (bucket.feature_type == BucketType::None) { + 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("feature type must be a string"); + throw Style::exception("cap type must be a string"); } - } else if (name == "source") { - if (value.IsString()) { - bucket.source_name = { value.GetString(), value.GetStringLength() }; + } + if (value.HasMember("join")) { + JSVal property = value["join"]; + if (property.IsString()) { + render.join = joinType({property.GetString(), property.GetStringLength()}); } else { - throw Style::exception("source name must be a string"); + throw Style::exception("join type must be a string"); } - } else if (name == "layer") { - if (value.IsString()) { - bucket.source_layer = { value.GetString(), value.GetStringLength() }; + } + if (value.HasMember("miterLimit")) { + JSVal property = value["miterLimit"]; + if (property.IsNumber()) { + render.miter_limit = property.GetDouble(); } else { - throw Style::exception("layer name must be a string"); + throw Style::exception("miter limit must be a number"); } - } else if (name == "cap") { - if (value.IsString()) { - bucket.geometry.cap = capType({ value.GetString(), value.GetStringLength() }); + } + if (value.HasMember("roundLimit")) { + JSVal property = value["roundLimit"]; + if (property.IsNumber()) { + render.round_limit = property.GetDouble(); } else { - throw Style::exception("cap type must be a string"); + throw Style::exception("round limit must be a number"); } - } else if (name == "join") { - if (value.IsString()) { - bucket.geometry.join = joinType({ value.GetString(), value.GetStringLength() }); + } + } 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("join type must be a string"); + throw Style::exception("font size must be a number"); } - } else if (name == "font") { - if (value.IsString()) { - bucket.geometry.font = { value.GetString(), value.GetStringLength() }; + } + + if (value.HasMember("icon")) { + JSVal property = value["icon"]; + if (property.IsString()) { + render.icon = {property.GetString(), property.GetStringLength()}; } else { - throw Style::exception("font stack must be a string"); + throw Style::exception("text field must be a string"); } - } else if (name == "fontSize" || name == "size") { - if (value.IsNumber()) { - bucket.geometry.size = value.GetDouble(); + } + + 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("font size must be a number"); + throw Style::exception("translate must be a string"); } - } else if (name == "text_field" || name == "icon") { - if (value.IsString()) { - bucket.geometry.field = { value.GetString(), value.GetStringLength() }; + } + } 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"); } - } else if (name == "path") { - if (value.IsString()) { - bucket.geometry.path = textPathType({ value.GetString(), value.GetStringLength() }); + } + + 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"); } - } else if (name == "alignment") { - if (value.IsString()) { - bucket.geometry.alignment = alignmentType({ value.GetString(), value.GetStringLength() }); + } + + if (value.HasMember("font")) { + JSVal property = value["font"]; + if (property.IsString()) { + render.font = {property.GetString(), property.GetStringLength()}; } else { - throw Style::exception("alignment must be a string"); + throw Style::exception("font stack 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; + } + + if (value.HasMember("fontSize")) { + JSVal property = value["fontSize"]; + if (property.IsNumber()) { + render.max_size = property.GetDouble(); } else { - throw Style::exception("translate must be a string"); + throw Style::exception("font size must be a number"); } - } else if (name == "verticalAlignment") { - if (value.IsString()) { - bucket.geometry.vertical_alignment = verticalAlignmentType({ value.GetString(), value.GetStringLength() }); + } + + if (value.HasMember("maxWidth")) { + JSVal property = value["maxWidth"]; + if (property.IsNumber()) { + render.max_width = property.GetDouble() * 24; } else { - throw Style::exception("verticalAlignment must be a string"); + throw Style::exception("max width must be a number"); } - } else if (name == "lineHeight") { - if (value.IsNumber()) { - bucket.geometry.line_height = value.GetDouble() * 24; + } + + 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"); } - } 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; + } + + 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"); } - } else if (name == "miterLimit") { - if (value.IsNumber()) { - bucket.geometry.miter_limit = value.GetDouble(); + } + + if (value.HasMember("alignment")) { + JSVal property = value["alignment"]; + if (property.IsString()) { + render.alignment = + alignmentType({property.GetString(), property.GetStringLength()}); } else { - throw Style::exception("miter limit must be a number"); + throw Style::exception("alignment must be a string"); } - } else if (name == "roundLimit") { - if (value.IsNumber()) { - bucket.geometry.round_limit = value.GetDouble(); + } + + if (value.HasMember("verticalAlignment")) { + JSVal property = value["verticalAlignment"]; + if (property.IsString()) { + render.vertical_alignment = + verticalAlignmentType({property.GetString(), property.GetStringLength()}); } else { - throw Style::exception("round limit must be a number"); + throw Style::exception("verticalAlignment must be a string"); } - } else if (name == "textMinDistance") { - if (value.IsNumber()) { - bucket.geometry.textMinDistance = value.GetDouble(); + } + + 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("text min distance must be a number"); + throw Style::exception("translate must be a string"); } - } else if (name == "maxAngleDelta") { - if (value.IsNumber()) { - bucket.geometry.maxAngleDelta = value.GetDouble(); + } + + 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; - if (value.HasMember("filter")) { - bucket.filter = std::move(parseFilterOrExpression(value["filter"])); - } else { - // Allow a filter triple to be specified at the bucket root as well. - bucket.filter = std::move(parseFilterOrExpression(value)); - } + case BucketType::Raster: { + bucket.render = BucketRasterDescription{}; + } break; - if (bucket.feature_type == BucketType::None) { - bucket.feature_type = bucket.type; + default: + break; } return bucket; diff --git a/src/text/placement.cpp b/src/text/placement.cpp index b15e324965..112f1d79cf 100644 --- a/src/text/placement.cpp +++ b/src/text/placement.cpp @@ -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); } |