From 3442403e6707be66ff133bd4690eb380dcc65dce Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Fri, 30 May 2014 00:07:22 -0400 Subject: [PATCH 01/10] parse maxWidth, lineHeight and alignment, pass to FontStack::getShaping --- bin/style.js | 2 ++ include/llmr/style/bucket_description.hpp | 9 +++++++++ include/llmr/text/glyph_store.hpp | 9 ++++++++- include/llmr/text/placement.hpp | 2 -- src/map/tile_parser.cpp | 6 +++++- src/style/style_parser.cpp | 18 +++++++++++++++++ src/text/glyph_store.cpp | 14 ++++++++++++- src/text/placement.cpp | 24 ++++------------------- 8 files changed, 59 insertions(+), 25 deletions(-) diff --git a/bin/style.js b/bin/style.js index c831fd414..931bde011 100644 --- a/bin/style.js +++ b/bin/style.js @@ -765,6 +765,8 @@ module.exports = { "path": "horizontal", "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 18, + "text-max-width": 2, + "text-line-height": 1.4, "feature_type": "point", "type": "text" }, diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index 3cdc8ea4d..004932aa4 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -68,6 +68,12 @@ inline TextPathType textPathType(const std::string& path) { else return TextPathType::Horizontal; }; +inline float alignmentType(const std::string& alignment) { + if (alignment == "right") return 1.0f; + else if (alignment == "left") return 0.0f; + else return 0.5; +}; + class BucketGeometryDescription { public: CapType cap = CapType::None; @@ -79,6 +85,9 @@ public: float miter_limit = 2.0f; float round_limit = 1.0f; TextPathType path = TextPathType::Horizontal; + float alignment = 0.5; + float line_height = 1.2 * 24; + float max_width = 15.0f * 24; float padding = 2.0f; float textMinDistance = 250.0f; float rotate = 0.0f; // what is this? diff --git a/include/llmr/text/glyph_store.hpp b/include/llmr/text/glyph_store.hpp index eb5d6038f..74472194b 100644 --- a/include/llmr/text/glyph_store.hpp +++ b/include/llmr/text/glyph_store.hpp @@ -30,7 +30,14 @@ public: void insert(uint32_t id, const SDFGlyph &glyph); const std::map &getMetrics() const; const std::map &getSDFs() const; - const Shaping getShaping(const std::u32string &string) const; + const Shaping getShaping(const std::u32string &string, + const float &maxWidth, + const float &lineHeight, + const float &alignment) const; + Shaping lineWrap(Shaping shaped, + const float &lineHeight, + const float &maxWidth, + const float &alignment) const; private: std::map bitmaps; diff --git a/include/llmr/text/placement.hpp b/include/llmr/text/placement.hpp index 87c47345e..fb3ddaa66 100644 --- a/include/llmr/text/placement.hpp +++ b/include/llmr/text/placement.hpp @@ -20,8 +20,6 @@ public: const BucketGeometryDescription &info, const GlyphPositions &face, const Shaping &shaping); - float measureText(const GlyphPositions &face, - const Shaping &shaping); private: const int8_t zoom; diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index ff5d61a5e..431300318 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -15,6 +15,8 @@ #include #include +#include + using namespace llmr; TileParser::TileParser(const std::string& data, VectorTileData& tile, const Style& style, GlyphAtlas& glyphAtlas, GlyphStore &glyphStore, SpriteAtlas &spriteAtlas) @@ -202,6 +204,8 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye std::map shaping; GlyphPositions face; + // std::cerr << bucket_desc; + // Shape and place all labels. { FilteredVectorTileLayer filtered_layer(layer, bucket_desc); @@ -221,7 +225,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye const std::u32string string = ucs4conv.convert(toString(it_prop->second)); // Shape labels. - const Shaping shaped = fontStack.getShaping(string); + const Shaping shaped = fontStack.getShaping(string, bucket_desc.geometry.max_width, bucket_desc.geometry.line_height, bucket_desc.geometry.alignment); shaping.emplace(toString(it_prop->second), shaped); // Place labels. diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 6276d657d..ba189f76f 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -102,6 +102,24 @@ BucketDescription StyleParser::parseBucket(JSVal value) { } 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 == "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 == "miterLimit") { if (value.IsNumber()) { bucket.geometry.miter_limit = value.GetDouble(); diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index 3f741236f..a148ac928 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace llmr { @@ -28,7 +29,7 @@ const std::map &FontStack::getSDFs() const { return sdfs; } -const Shaping FontStack::getShaping(const std::u32string &string) const { +const Shaping FontStack::getShaping(const std::u32string &string, const float &maxWidth, const float &lineHeight, const float &alignment) const { std::lock_guard lock(mtx); uint32_t i = 0; uint32_t x = 0; @@ -40,6 +41,17 @@ const Shaping FontStack::getShaping(const std::u32string &string) const { i++; x += metrics.find(chr)->second.advance; } + + shaped = lineWrap(shaped, lineHeight, maxWidth, alignment); + + return shaped; +} + +Shaping FontStack::lineWrap(Shaping shaped, const float &lineHeight, const float &maxWidth, const float &alignment) const { + std::cerr << "\nlineHeight: " << lineHeight << + "\nmaxWidth: " << maxWidth << + "\nalignment: " << alignment << + "\n"; return shaped; } diff --git a/src/text/placement.cpp b/src/text/placement.cpp index f57436bcb..ed71f881e 100644 --- a/src/text/placement.cpp +++ b/src/text/placement.cpp @@ -137,15 +137,12 @@ void getSegmentGlyphs(std::back_insert_iterator glyphs, } void getGlyphs(PlacedGlyphs &glyphs, GlyphBoxes &boxes, - Anchor &anchor, float advance, const Shaping &shaping, + Anchor &anchor, vec2 origin, const Shaping &shaping, const GlyphPositions &face, float fontScale, bool horizontal, const std::vector &line, float maxAngleDelta, float rotate) { // The total text advance is the width of this label. - // TODO: figure out correct ascender height. - vec2 origin{-advance / 2, -17}; - // TODO: allow setting an alignment // var alignment = 'center'; // if (alignment == 'center') { @@ -261,10 +258,10 @@ void Placement::addFeature(TextBucket& bucket, const float fontScale = (tileExtent / util::tileSize) / (glyphSize / info.size); - const float advance = measureText(face, shaping); Anchors anchors; - // fprintf(stderr, "adding feature with advance %f\n", advance); + // TODO: figure out correct ascender height. + vec2 origin{0, -17}; if (line.size() == 1) { // Point labels @@ -285,7 +282,7 @@ void Placement::addFeature(TextBucket& bucket, PlacedGlyphs glyphs; GlyphBoxes boxes; - getGlyphs(glyphs, boxes, anchor, advance, shaping, face, fontScale, horizontal, + getGlyphs(glyphs, boxes, anchor, origin, shaping, face, fontScale, horizontal, line, maxAngleDelta, rotate); PlacementProperty place = collision.place(boxes, anchor, anchor.scale, maxPlacementScale, @@ -295,16 +292,3 @@ void Placement::addFeature(TextBucket& bucket, } } } - -float Placement::measureText(const GlyphPositions &face, - const Shaping &shaping) { - float advance = 0; - - // TODO: advance is not calculated correctly. we should instead use the - // bounding box of the glyph placement. - for (const GlyphPlacement &shape : shaping) { - advance += getGlyph(shape, face).metrics.advance; - } - - return advance; -} From 63729a500944a47c034713a531b7add337df6688 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 30 May 2014 01:02:33 -0400 Subject: [PATCH 02/10] fix `make run-linux` --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b10cdbb7b..5865996bc 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ linux: config.gypi linux/llmr-app.gyp node # Executes the Linux binary run-linux: linux - build/$(BUILDTYPE)/llmr + build/$(BUILDTYPE)/mapbox-gl From 9057c4980dc12515cd8d6f33d9253e61592272fe Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 30 May 2014 01:32:15 -0400 Subject: [PATCH 03/10] line wrapping --- bin/style.js | 4 +-- include/llmr/text/glyph.hpp | 4 +-- src/text/glyph_store.cpp | 51 ++++++++++++++++++++++++++++++++++--- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/bin/style.js b/bin/style.js index 931bde011..38ffd7c32 100644 --- a/bin/style.js +++ b/bin/style.js @@ -765,8 +765,8 @@ module.exports = { "path": "horizontal", "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 18, - "text-max-width": 2, - "text-line-height": 1.4, + "maxWidth": 2, + "lineHeight": 1.4, "feature_type": "point", "type": "text" }, diff --git a/include/llmr/text/glyph.hpp b/include/llmr/text/glyph.hpp index e6138e712..c13088c41 100644 --- a/include/llmr/text/glyph.hpp +++ b/include/llmr/text/glyph.hpp @@ -53,8 +53,8 @@ public: uint32_t face = 0; uint32_t glyph = 0; - uint32_t x = 0; - uint32_t y = 0; + int32_t x = 0; + int32_t y = 0; }; typedef std::vector Shaping; diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index a148ac928..6293aee23 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -47,11 +47,54 @@ const Shaping FontStack::getShaping(const std::u32string &string, const float &m return shaped; } +void alignHorizontally(Shaping &shaping, const std::map &metrics, + const uint32_t &start, const uint32_t &end, const float &alignment) { + + uint32_t lastAdvance = metrics.find(shaping[end].glyph)->second.advance; + int32_t lineIndent = (shaping[end].x + lastAdvance) * alignment; + + for (uint32_t j = start; j <= end; j++) { + shaping[j].x -= lineIndent; + } + } + Shaping FontStack::lineWrap(Shaping shaped, const float &lineHeight, const float &maxWidth, const float &alignment) const { - std::cerr << "\nlineHeight: " << lineHeight << - "\nmaxWidth: " << maxWidth << - "\nalignment: " << alignment << - "\n"; + uint32_t lastSafeBreak = 0; + uint32_t lengthBeforeCurrentLine = 0; + uint32_t lineStartIndex = 0; + uint32_t line = 0; + + for (uint32_t i = 0; i < shaped.size(); i++) { + GlyphPlacement &shape = shaped[i]; + + shape.x -= lengthBeforeCurrentLine; + shape.y += lineHeight * line; + + if (shape.x > maxWidth && lastSafeBreak != 0) { + + uint32_t lineLength = shaped[lastSafeBreak + 1].x; + + for (uint32_t k = lastSafeBreak + 1; k <= i; k++) { + shaped[k].y += lineHeight; + shaped[k].x -= lineLength; + } + + if (alignment) { + alignHorizontally(shaped, metrics, lineStartIndex, lastSafeBreak - 1, alignment); + } + + lineStartIndex = lastSafeBreak + 1; + lastSafeBreak = 0; + lengthBeforeCurrentLine += lineLength; + line++; + } + if (shape.glyph == 32) { + lastSafeBreak = i; + } + } + + alignHorizontally(shaped, metrics, lineStartIndex, shaped.size() - 1, alignment); + return shaped; } From 41c310c76238d3a2823c79592b553a6ff3205c47 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 30 May 2014 03:11:57 -0400 Subject: [PATCH 04/10] add verticalAlign for text Default is center. Other options are "top" and "bottom" --- include/llmr/style/bucket_description.hpp | 7 ++++++ include/llmr/text/glyph_store.hpp | 6 +++-- src/map/tile_parser.cpp | 4 +++- src/style/style_parser.cpp | 6 +++++ src/text/glyph_store.cpp | 29 ++++++++++++++++------- src/text/placement.cpp | 2 +- 6 files changed, 41 insertions(+), 13 deletions(-) diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index 004932aa4..b708ef686 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -74,6 +74,12 @@ inline float alignmentType(const std::string& alignment) { else return 0.5; }; +inline float verticalAlignmentType(const std::string& alignment) { + if (alignment == "bottom") return 1.0f; + else if (alignment == "top") return 0.0f; + else return 0.5; +}; + class BucketGeometryDescription { public: CapType cap = CapType::None; @@ -86,6 +92,7 @@ public: 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 padding = 2.0f; diff --git a/include/llmr/text/glyph_store.hpp b/include/llmr/text/glyph_store.hpp index 74472194b..f8b14683d 100644 --- a/include/llmr/text/glyph_store.hpp +++ b/include/llmr/text/glyph_store.hpp @@ -33,11 +33,13 @@ public: const Shaping getShaping(const std::u32string &string, const float &maxWidth, const float &lineHeight, - const float &alignment) const; + const float &alignment, + const float &verticalAlignment) const; Shaping lineWrap(Shaping shaped, const float &lineHeight, const float &maxWidth, - const float &alignment) const; + const float &alignment, + const float &verticalAlignment) const; private: std::map bitmaps; diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 431300318..f2b3ac05c 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -225,7 +225,9 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye const std::u32string string = ucs4conv.convert(toString(it_prop->second)); // Shape labels. - const Shaping shaped = fontStack.getShaping(string, bucket_desc.geometry.max_width, bucket_desc.geometry.line_height, bucket_desc.geometry.alignment); + const Shaping shaped = fontStack.getShaping(string, bucket_desc.geometry.max_width, + bucket_desc.geometry.line_height, bucket_desc.geometry.alignment, + bucket_desc.geometry.vertical_alignment); shaping.emplace(toString(it_prop->second), shaped); // Place labels. diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index ba189f76f..535e63916 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -108,6 +108,12 @@ BucketDescription StyleParser::parseBucket(JSVal value) { } else { throw Style::exception("alignment must be a string"); } + } else if (name == "verticalAlignment") { + if (value.IsString()) { + bucket.geometry.vertical_alignment = verticalAlignmentType({ value.GetString(), value.GetStringLength() }); + } else { + throw Style::exception("alignment must be a string"); + } } else if (name == "lineHeight") { if (value.IsNumber()) { bucket.geometry.line_height = value.GetDouble() * 24; diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index 6293aee23..ac647eb84 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -29,7 +29,8 @@ const std::map &FontStack::getSDFs() const { return sdfs; } -const Shaping FontStack::getShaping(const std::u32string &string, const float &maxWidth, const float &lineHeight, const float &alignment) const { +const Shaping FontStack::getShaping(const std::u32string &string, const float &maxWidth, + const float &lineHeight, const float &alignment, const float &verticalAlignment) const { std::lock_guard lock(mtx); uint32_t i = 0; uint32_t x = 0; @@ -42,23 +43,32 @@ const Shaping FontStack::getShaping(const std::u32string &string, const float &m x += metrics.find(chr)->second.advance; } - shaped = lineWrap(shaped, lineHeight, maxWidth, alignment); + shaped = lineWrap(shaped, lineHeight, maxWidth, alignment, verticalAlignment); return shaped; } +void alignVertically(Shaping &shaping, const uint32_t &lines, const float &lineHeight, const float &verticalAlign) { + const float dy = -(lineHeight * (lines - 1) + 24) * verticalAlign - 5; + for (GlyphPlacement &shape : shaping) { + shape.y += dy; + } +} + void alignHorizontally(Shaping &shaping, const std::map &metrics, const uint32_t &start, const uint32_t &end, const float &alignment) { - uint32_t lastAdvance = metrics.find(shaping[end].glyph)->second.advance; - int32_t lineIndent = (shaping[end].x + lastAdvance) * alignment; + uint32_t lastAdvance = metrics.find(shaping[end].glyph)->second.advance; + int32_t lineIndent = (shaping[end].x + lastAdvance) * alignment; - for (uint32_t j = start; j <= end; j++) { - shaping[j].x -= lineIndent; - } - } + for (uint32_t j = start; j <= end; j++) { + shaping[j].x -= lineIndent; + } +} + +Shaping FontStack::lineWrap(Shaping shaped, const float &lineHeight, const float &maxWidth, + const float &alignment, const float &verticalAlignment) const { -Shaping FontStack::lineWrap(Shaping shaped, const float &lineHeight, const float &maxWidth, const float &alignment) const { uint32_t lastSafeBreak = 0; uint32_t lengthBeforeCurrentLine = 0; uint32_t lineStartIndex = 0; @@ -94,6 +104,7 @@ Shaping FontStack::lineWrap(Shaping shaped, const float &lineHeight, const float } alignHorizontally(shaped, metrics, lineStartIndex, shaped.size() - 1, alignment); + alignVertically(shaped, line + 1, lineHeight, verticalAlignment); return shaped; } diff --git a/src/text/placement.cpp b/src/text/placement.cpp index ed71f881e..edefa6075 100644 --- a/src/text/placement.cpp +++ b/src/text/placement.cpp @@ -261,7 +261,7 @@ void Placement::addFeature(TextBucket& bucket, Anchors anchors; // TODO: figure out correct ascender height. - vec2 origin{0, -17}; + vec2 origin{0, 0}; if (line.size() == 1) { // Point labels From 7c653895c6f6f7dc07241031277610efb439a243 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 30 May 2014 03:50:25 -0400 Subject: [PATCH 05/10] translate as a text bucket property When used, text is translated before being checked for collisions. --- bin/style.js | 18 ++++++++++-------- include/llmr/style/bucket_description.hpp | 2 ++ src/style/style_parser.cpp | 9 ++++++++- src/text/placement.cpp | 5 +---- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/bin/style.js b/bin/style.js index 38ffd7c32..3d24d6e79 100644 --- a/bin/style.js +++ b/bin/style.js @@ -765,8 +765,7 @@ module.exports = { "path": "horizontal", "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 18, - "maxWidth": 2, - "lineHeight": 1.4, + "maxWidth": 6, "feature_type": "point", "type": "text" }, @@ -880,6 +879,9 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, + "maxWidth": 8, + "verticalAlignment": "top", + "translate": [0, -1], "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 11, "feature_type": "point", @@ -893,6 +895,9 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, + "maxWidth": 8, + "verticalAlignment": "top", + "translate": [0, -1], "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 10, "feature_type": "point", @@ -906,6 +911,9 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, + "maxWidth": 8, + "verticalAlignment": "top", + "translate": [0, -1], "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 10, "feature_type": "point", @@ -2417,7 +2425,6 @@ module.exports = { "stroke": "land", "strokeWidth": 0.3, "strokeBlur": 1, - "translate": [0, 14] }, "poi_label_3": { "color": "#444", @@ -2425,7 +2432,6 @@ module.exports = { "stroke": "land", "strokeWidth": 0.3, "strokeBlur": 1, - "translate": [0, 14], "opacity": [ "stops", {"z": 16.5, "val": 0}, @@ -2443,7 +2449,6 @@ module.exports = { "stroke": "land", "strokeWidth": 0.3, "strokeBlur": 1, - "translate": [0, 14] }, "poi_aerodrome": { "opacity": ["stops", @@ -3169,7 +3174,6 @@ module.exports = { "stroke": "text2_stroke_night", "strokeWidth": 0.3, "strokeBlur": 1, - "translate": [0, 14] }, "poi_label_3": { "color": "#fff", @@ -3177,7 +3181,6 @@ module.exports = { "stroke": "text2_stroke_night", "strokeWidth": 0.3, "strokeBlur": 1, - "translate": [0, 14], "opacity": [ "stops", {"z": 16.5, "val": 0}, @@ -3195,7 +3198,6 @@ module.exports = { "stroke": "text2_stroke_night", "strokeWidth": 0.3, "strokeBlur": 1, - "translate": [0, 14] }, "poi_aerodrome": { "opacity": ["stops", diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index b708ef686..e306b799f 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -6,6 +6,7 @@ #include #include "value.hpp" +#include "../util/vec.hpp" namespace llmr { @@ -95,6 +96,7 @@ public: float vertical_alignment = 0.5; float line_height = 1.2 * 24; float max_width = 15.0f * 24; + vec2 translate {0, 0}; float padding = 2.0f; float textMinDistance = 250.0f; float rotate = 0.0f; // what is this? diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 535e63916..1a1d8ee1e 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -108,11 +108,18 @@ BucketDescription StyleParser::parseBucket(JSVal value) { } 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("alignment must be a string"); + throw Style::exception("verticalAlignment must be a string"); } } else if (name == "lineHeight") { if (value.IsNumber()) { diff --git a/src/text/placement.cpp b/src/text/placement.cpp index edefa6075..b15e32496 100644 --- a/src/text/placement.cpp +++ b/src/text/placement.cpp @@ -260,9 +260,6 @@ void Placement::addFeature(TextBucket& bucket, Anchors anchors; - // TODO: figure out correct ascender height. - vec2 origin{0, 0}; - if (line.size() == 1) { // Point labels anchors = Anchors{{Anchor{ @@ -282,7 +279,7 @@ void Placement::addFeature(TextBucket& bucket, PlacedGlyphs glyphs; GlyphBoxes boxes; - getGlyphs(glyphs, boxes, anchor, origin, shaping, face, fontScale, horizontal, + getGlyphs(glyphs, boxes, anchor, info.translate, shaping, face, fontScale, horizontal, line, maxAngleDelta, rotate); PlacementProperty place = collision.place(boxes, anchor, anchor.scale, maxPlacementScale, From 9ac55e0d74df48344888b41e4f3e3f3a41d08ebf Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 30 May 2014 04:02:23 -0400 Subject: [PATCH 06/10] add text letterSpacing --- include/llmr/style/bucket_description.hpp | 1 + include/llmr/text/glyph_store.hpp | 3 ++- src/map/tile_parser.cpp | 2 +- src/style/style_parser.cpp | 6 ++++++ src/text/glyph_store.cpp | 6 ++++-- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index e306b799f..3b6fc4313 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -96,6 +96,7 @@ public: float vertical_alignment = 0.5; float line_height = 1.2 * 24; float max_width = 15.0f * 24; + float letter_spacing = 0; vec2 translate {0, 0}; float padding = 2.0f; float textMinDistance = 250.0f; diff --git a/include/llmr/text/glyph_store.hpp b/include/llmr/text/glyph_store.hpp index f8b14683d..49427a276 100644 --- a/include/llmr/text/glyph_store.hpp +++ b/include/llmr/text/glyph_store.hpp @@ -34,7 +34,8 @@ public: const float &maxWidth, const float &lineHeight, const float &alignment, - const float &verticalAlignment) const; + const float &verticalAlignment, + const float &letterSpacing) const; Shaping lineWrap(Shaping shaped, const float &lineHeight, const float &maxWidth, diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index f2b3ac05c..2d47542d9 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -227,7 +227,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye // Shape labels. const Shaping shaped = fontStack.getShaping(string, bucket_desc.geometry.max_width, bucket_desc.geometry.line_height, bucket_desc.geometry.alignment, - bucket_desc.geometry.vertical_alignment); + bucket_desc.geometry.vertical_alignment, bucket_desc.geometry.letter_spacing); shaping.emplace(toString(it_prop->second), shaped); // Place labels. diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 1a1d8ee1e..61f3c444c 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -133,6 +133,12 @@ BucketDescription StyleParser::parseBucket(JSVal value) { } 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(); diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index ac647eb84..4d7ff57ec 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -30,7 +30,9 @@ const std::map &FontStack::getSDFs() const { } const Shaping FontStack::getShaping(const std::u32string &string, const float &maxWidth, - const float &lineHeight, const float &alignment, const float &verticalAlignment) const { + const float &lineHeight, const float &alignment, const float &verticalAlignment, + const float &letterSpacing) const { + std::lock_guard lock(mtx); uint32_t i = 0; uint32_t x = 0; @@ -40,7 +42,7 @@ const Shaping FontStack::getShaping(const std::u32string &string, const float &m GlyphPlacement glyph = GlyphPlacement(0, chr, x, 0); shaped.push_back(glyph); i++; - x += metrics.find(chr)->second.advance; + x += metrics.find(chr)->second.advance + letterSpacing; } shaped = lineWrap(shaped, lineHeight, maxWidth, alignment, verticalAlignment); From c0c43ef518129da511ad774383e174d3ef935b5a Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 30 May 2014 13:06:08 -0400 Subject: [PATCH 07/10] fix compile error --- include/llmr/util/uv.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/llmr/util/uv.hpp b/include/llmr/util/uv.hpp index 0600b8550..27ac019f2 100644 --- a/include/llmr/util/uv.hpp +++ b/include/llmr/util/uv.hpp @@ -122,7 +122,7 @@ private: } private: - std::shared_ptr loop; + std::shared_ptr loop; uv_work_t req; T data; work_callback work_cb; From e69ec277ec8715990fe10265fdf198cfa6efaafd Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 30 May 2014 10:26:30 -0700 Subject: [PATCH 08/10] [build] on osx accept either libtool or glibtool --- setup-libraries.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup-libraries.sh b/setup-libraries.sh index 710562bf1..f37a67cb0 100755 --- a/setup-libraries.sh +++ b/setup-libraries.sh @@ -19,7 +19,9 @@ ensure_dep pkg-config ensure_dep node if [ ${UNAME} = 'Darwin' ]; then ensure_dep makedepend - ensure_dep glibtool + if [[ ! `which libtool` ]] && [[ ! `which glibtool` ]]; then + MISSING_DEPS="$MISSING_DEPS libtool" + fi elif [ ${UNAME} = 'Linux' ]; then ensure_dep libtool ensure_dep gccmakedep From de1fa07bc6fc94f9ca9448b04d74f8b449961830 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 30 May 2014 10:53:07 -0700 Subject: [PATCH 09/10] fix travis link in readme [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a8d3c31c9..6a788b9af 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Travis](https://api.travis-ci.com/mapbox/llmr-native.svg?token=yZ9zvfZwYkJNWivRLoyX)](https://magnum.travis-ci.com/mapbox/llmr-native) +[![Travis](https://api.travis-ci.com/mapbox/mapbox-gl-native.svg?token=yZ9zvfZwYkJNWivRLoyX)](https://magnum.travis-ci.com/mapbox/mapbox-gl-native) An OpenGL renderer for [Mapbox vector tiles](https://www.mapbox.com/blog/vector-tiles), implemented in C++11, currently targeting iOS, OS X, and Ubuntu Linux. From 59774f7e93e207c49364c8cb0908038606f5dd8c Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Fri, 30 May 2014 14:19:22 -0400 Subject: [PATCH 10/10] shaped to shaping, pass by reference instead of returning a copy --- include/llmr/text/glyph_store.hpp | 2 +- src/text/glyph_store.cpp | 28 +++++++++++++--------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/include/llmr/text/glyph_store.hpp b/include/llmr/text/glyph_store.hpp index 49427a276..56aa63f2e 100644 --- a/include/llmr/text/glyph_store.hpp +++ b/include/llmr/text/glyph_store.hpp @@ -36,7 +36,7 @@ public: const float &alignment, const float &verticalAlignment, const float &letterSpacing) const; - Shaping lineWrap(Shaping shaped, + Shaping lineWrap(Shaping &shaping, const float &lineHeight, const float &maxWidth, const float &alignment, diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index 4831d8130..d9f0fedff 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -35,18 +35,18 @@ const Shaping FontStack::getShaping(const std::u32string &string, const float &m std::lock_guard lock(mtx); uint32_t i = 0; uint32_t x = 0; - Shaping shaped; + Shaping shaping; // Loop through all characters of this label and shape. for (uint32_t chr : string) { GlyphPlacement glyph = GlyphPlacement(0, chr, x, 0); - shaped.push_back(glyph); + shaping.push_back(glyph); i++; x += metrics.find(chr)->second.advance + letterSpacing; } - shaped = lineWrap(shaped, lineHeight, maxWidth, alignment, verticalAlignment); + lineWrap(shaping, lineHeight, maxWidth, alignment, verticalAlignment); - return shaped; + return shaping; } void alignVertically(Shaping &shaping, const uint32_t &lines, const float &lineHeight, const float &verticalAlign) { @@ -67,7 +67,7 @@ void alignHorizontally(Shaping &shaping, const std::map } } -Shaping FontStack::lineWrap(Shaping shaped, const float &lineHeight, const float &maxWidth, +Shaping FontStack::lineWrap(Shaping &shaping, const float &lineHeight, const float &maxWidth, const float &alignment, const float &verticalAlignment) const { uint32_t lastSafeBreak = 0; @@ -75,23 +75,23 @@ Shaping FontStack::lineWrap(Shaping shaped, const float &lineHeight, const float uint32_t lineStartIndex = 0; uint32_t line = 0; - for (uint32_t i = 0; i < shaped.size(); i++) { - GlyphPlacement &shape = shaped[i]; + for (uint32_t i = 0; i < shaping.size(); i++) { + GlyphPlacement &shape = shaping[i]; shape.x -= lengthBeforeCurrentLine; shape.y += lineHeight * line; if (shape.x > maxWidth && lastSafeBreak != 0) { - uint32_t lineLength = shaped[lastSafeBreak + 1].x; + uint32_t lineLength = shaping[lastSafeBreak + 1].x; for (uint32_t k = lastSafeBreak + 1; k <= i; k++) { - shaped[k].y += lineHeight; - shaped[k].x -= lineLength; + shaping[k].y += lineHeight; + shaping[k].x -= lineLength; } if (alignment) { - alignHorizontally(shaped, metrics, lineStartIndex, lastSafeBreak - 1, alignment); + alignHorizontally(shaping, metrics, lineStartIndex, lastSafeBreak - 1, alignment); } lineStartIndex = lastSafeBreak + 1; @@ -104,10 +104,8 @@ Shaping FontStack::lineWrap(Shaping shaped, const float &lineHeight, const float } } - alignHorizontally(shaped, metrics, lineStartIndex, shaped.size() - 1, alignment); - alignVertically(shaped, line + 1, lineHeight, verticalAlignment); - - return shaped; + alignHorizontally(shaping, metrics, lineStartIndex, shaping.size() - 1, alignment); + alignVertically(shaping, line + 1, lineHeight, verticalAlignment); } GlyphPBF::GlyphPBF(const std::string &fontStack, GlyphRange glyphRange)