parse maxWidth, lineHeight and alignment, pass to FontStack::getShaping
This commit is contained in:
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -30,7 +30,14 @@ public:
|
||||
void insert(uint32_t id, const SDFGlyph &glyph);
|
||||
const std::map<uint32_t, GlyphMetrics> &getMetrics() const;
|
||||
const std::map<uint32_t, SDFGlyph> &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<uint32_t, std::string> bitmaps;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <llmr/util/std.hpp>
|
||||
#include <llmr/util/utf.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
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<Bucket> TileParser::createTextBucket(const VectorTileLayer& laye
|
||||
std::map<Value, Shaping> 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<Bucket> 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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <llmr/platform/platform.hpp>
|
||||
#include <uv.h>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
@@ -28,7 +29,7 @@ const std::map<uint32_t, SDFGlyph> &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<std::mutex> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -137,15 +137,12 @@ void getSegmentGlyphs(std::back_insert_iterator<GlyphInstances> glyphs,
|
||||
}
|
||||
|
||||
void getGlyphs(PlacedGlyphs &glyphs, GlyphBoxes &boxes,
|
||||
Anchor &anchor, float advance, const Shaping &shaping,
|
||||
Anchor &anchor, vec2<float> origin, const Shaping &shaping,
|
||||
const GlyphPositions &face, float fontScale,
|
||||
bool horizontal, const std::vector<Coordinate> &line,
|
||||
float maxAngleDelta, float rotate) {
|
||||
// The total text advance is the width of this label.
|
||||
|
||||
// TODO: figure out correct ascender height.
|
||||
vec2<float> 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<float> 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user