Add functions for layout properties.

This commit is contained in:
Lauren Budorick
2015-01-30 16:38:32 -08:00
committed by John Firebaugh
parent 230963b22d
commit 895d90409b
13 changed files with 365 additions and 116 deletions

View File

@@ -91,6 +91,100 @@ void TileParser::parseStyleLayers(util::ptr<StyleLayerGroup> group) {
}
}
template <typename T>
struct PropertyEvaluator {
typedef T result_type;
PropertyEvaluator(float z_) : z(z_) {}
template <typename P, typename std::enable_if<std::is_convertible<P, T>::value, int>::type = 0>
T operator()(const P &value) const {
return value;
}
T operator()(const Function<T> &value) const {
return mapbox::util::apply_visitor(FunctionEvaluator<T>(z), value);
}
template <typename P, typename std::enable_if<!std::is_convertible<P, T>::value, int>::type = 0>
T operator()(const P &) const {
return T();
}
private:
const float z;
};
template <typename T>
void TileParser::applyLayoutProperty(PropertyKey key, ClassProperties &classProperties, T &target, const float z) {
auto it = classProperties.properties.find(key);
if (it != classProperties.properties.end()) {
const PropertyEvaluator<T> evaluator(z);
target = mapbox::util::apply_visitor(evaluator, it->second);
}
}
template <>
void TileParser::applyLayoutProperties<FillProperties>(StyleBucket &bucket_desc, const float) {
bucket_desc.render.set<StyleBucketFill>();
// no-op; Fill buckets don't currently have any applicable layout properties
}
template<>
void TileParser::applyLayoutProperties<LineProperties>(StyleBucket &bucket_desc, const float z) {
bucket_desc.render.set<StyleBucketLine>();
StyleBucketLine &line = bucket_desc.render.get<StyleBucketLine>();
applyLayoutProperty(PropertyKey::LineCap, bucket_desc.layout, line.cap, z);
applyLayoutProperty(PropertyKey::LineJoin, bucket_desc.layout, line.join, z);
applyLayoutProperty(PropertyKey::LineMiterLimit, bucket_desc.layout, line.miter_limit, z);
applyLayoutProperty(PropertyKey::LineRoundLimit, bucket_desc.layout, line.round_limit, z);
}
template<>
void TileParser::applyLayoutProperties<SymbolProperties>(StyleBucket &bucket_desc, const float z) {
bucket_desc.render.set<StyleBucketSymbol>();
StyleBucketSymbol &symbol = bucket_desc.render.get<StyleBucketSymbol>();
applyLayoutProperty(PropertyKey::SymbolPlacement, bucket_desc.layout, symbol.placement, z);
if (symbol.placement == PlacementType::Line) {
symbol.icon.rotation_alignment = RotationAlignmentType::Map;
symbol.text.rotation_alignment = RotationAlignmentType::Map;
};
applyLayoutProperty(PropertyKey::SymbolMinDistance, bucket_desc.layout, symbol.min_distance, z);
applyLayoutProperty(PropertyKey::SymbolAvoidEdges, bucket_desc.layout, symbol.avoid_edges, z);
applyLayoutProperty(PropertyKey::IconAllowOverlap, bucket_desc.layout, symbol.icon.allow_overlap, z);
applyLayoutProperty(PropertyKey::IconIgnorePlacement, bucket_desc.layout, symbol.icon.ignore_placement, z);
applyLayoutProperty(PropertyKey::IconOptional, bucket_desc.layout, symbol.icon.optional, z);
applyLayoutProperty(PropertyKey::IconRotationAlignment, bucket_desc.layout, symbol.icon.rotation_alignment, z);
applyLayoutProperty(PropertyKey::IconMaxSize, bucket_desc.layout, symbol.icon.max_size, z);
applyLayoutProperty(PropertyKey::IconImage, bucket_desc.layout, symbol.icon.image, z);
applyLayoutProperty(PropertyKey::IconPadding, bucket_desc.layout, symbol.icon.padding, z);
applyLayoutProperty(PropertyKey::IconRotate, bucket_desc.layout, symbol.icon.rotate, z);
applyLayoutProperty(PropertyKey::IconKeepUpright, bucket_desc.layout, symbol.icon.keep_upright, z);
applyLayoutProperty(PropertyKey::IconOffsetX, bucket_desc.layout, symbol.icon.offset[0], z);
applyLayoutProperty(PropertyKey::IconOffsetY, bucket_desc.layout, symbol.icon.offset[1], z);
applyLayoutProperty(PropertyKey::TextRotationAlignment, bucket_desc.layout, symbol.text.rotation_alignment, z);
applyLayoutProperty(PropertyKey::TextField, bucket_desc.layout, symbol.text.field, z);
applyLayoutProperty(PropertyKey::TextFont, bucket_desc.layout, symbol.text.font, z);
applyLayoutProperty(PropertyKey::TextMaxSize, bucket_desc.layout, symbol.text.max_size, z);
applyLayoutProperty(PropertyKey::TextMaxWidth, bucket_desc.layout, symbol.text.max_width, z);
applyLayoutProperty(PropertyKey::TextLineHeight, bucket_desc.layout, symbol.text.line_height, z);
applyLayoutProperty(PropertyKey::TextLetterSpacing, bucket_desc.layout, symbol.text.letter_spacing, z);
applyLayoutProperty(PropertyKey::TextMaxAngle, bucket_desc.layout, symbol.text.max_angle, z);
applyLayoutProperty(PropertyKey::TextRotate, bucket_desc.layout, symbol.text.rotate, z);
applyLayoutProperty(PropertyKey::TextPadding, bucket_desc.layout, symbol.text.padding, z);
applyLayoutProperty(PropertyKey::TextIgnorePlacement, bucket_desc.layout, symbol.text.ignore_placement, z);
applyLayoutProperty(PropertyKey::TextOptional, bucket_desc.layout, symbol.text.optional, z);
applyLayoutProperty(PropertyKey::TextJustify, bucket_desc.layout, symbol.text.justify, z);
applyLayoutProperty(PropertyKey::TextAnchor, bucket_desc.layout, symbol.text.anchor, z);
applyLayoutProperty(PropertyKey::TextKeepUpright, bucket_desc.layout, symbol.text.keep_upright, z);
applyLayoutProperty(PropertyKey::TextTransform, bucket_desc.layout, symbol.text.transform, z);
applyLayoutProperty(PropertyKey::TextOffsetX, bucket_desc.layout, symbol.text.offset[0], z);
applyLayoutProperty(PropertyKey::TextOffsetY, bucket_desc.layout, symbol.text.offset[1], z);
applyLayoutProperty(PropertyKey::TextAllowOverlap, bucket_desc.layout, symbol.text.allow_overlap, z);
}
std::unique_ptr<Bucket> TileParser::createBucket(util::ptr<StyleBucket> bucket_desc) {
if (!bucket_desc) {
fprintf(stderr, "missing bucket desc\n");
@@ -105,13 +199,16 @@ std::unique_ptr<Bucket> TileParser::createBucket(util::ptr<StyleBucket> bucket_d
auto layer_it = vector_data.layers.find(bucket_desc->source_layer);
if (layer_it != vector_data.layers.end()) {
const VectorTileLayer &layer = layer_it->second;
if (bucket_desc->render.is<StyleBucketFill>()) {
if (bucket_desc->type == StyleLayerType::Fill) {
applyLayoutProperties<FillProperties>(*bucket_desc, tile.id.z);
return createFillBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketFill>());
} else if (bucket_desc->render.is<StyleBucketLine>()) {
} else if (bucket_desc->type == StyleLayerType::Line) {
applyLayoutProperties<LineProperties>(*bucket_desc, tile.id.z);
return createLineBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketLine>());
} else if (bucket_desc->render.is<StyleBucketSymbol>()) {
} else if (bucket_desc->type == StyleLayerType::Symbol) {
applyLayoutProperties<SymbolProperties>(*bucket_desc, tile.id.z);
return createSymbolBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketSymbol>());
} else if (bucket_desc->render.is<StyleBucketRaster>()) {
} else if (bucket_desc->type == StyleLayerType::Raster) {
return nullptr;
} else {
fprintf(stderr, "[WARNING] unknown bucket render type for layer '%s' (source layer '%s')\n", bucket_desc->name.c_str(), bucket_desc->source_layer.c_str());

View File

@@ -3,6 +3,8 @@
#include <mbgl/map/vector_tile.hpp>
#include <mbgl/style/filter_expression.hpp>
#include <mbgl/style/class_properties.hpp>
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/text/glyph.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/util/noncopyable.hpp>
@@ -48,6 +50,10 @@ public:
private:
bool obsolete() const;
void parseStyleLayers(util::ptr<StyleLayerGroup> group);
template <typename T> void applyLayoutProperties(StyleBucket &bucket, float z);
template <typename T> void applyLayoutProperty(PropertyKey key, ClassProperties &classProperties, T &, float z);
std::unique_ptr<Bucket> createBucket(util::ptr<StyleBucket> bucket_desc);
std::unique_ptr<Bucket> createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill);

View File

@@ -177,13 +177,13 @@ void SymbolBucket::addFeatures(const VectorTileLayer &layer, const FilterExpress
if (feature.label.length()) {
shaping = fontStack.getShaping(
/* string */ feature.label,
/* maxWidth */ properties.text.max_width,
/* lineHeight */ properties.text.line_height,
/* maxWidth: ems */ properties.text.max_width * 24,
/* lineHeight: ems */ properties.text.line_height * 24,
/* horizontalAlign */ horizontalAlign,
/* verticalAlign */ verticalAlign,
/* justify */ justify,
/* spacing */ properties.text.letter_spacing,
/* translate */ properties.text.offset);
/* spacing: ems */ properties.text.letter_spacing * 24,
/* translate */ vec2<float>(properties.text.offset[0], properties.text.offset[1]));
// Add the glyphs we need for this label to the glyph atlas.
if (shaping.size()) {

View File

@@ -8,7 +8,7 @@ AppliedClassProperty::AppliedClassProperty(ClassID class_id, std::chrono::steady
end(end_),
value(value_) {}
// Returns thie ID of the most recent
// Returns the ID of the most recent
ClassID AppliedClassProperties::mostRecent() const {
return properties.size() ? properties.back().name : ClassID::Fallback;
}

View File

@@ -26,7 +26,7 @@ public:
std::list<AppliedClassProperty> properties;
public:
// Returns thie ID of the most recent
// Returns the ID of the most recent
ClassID mostRecent() const;
void add(ClassID class_id, std::chrono::steady_clock::time_point begin, std::chrono::steady_clock::time_point end, const PropertyValue &value);
bool hasTransitions() const;

View File

@@ -1,5 +1,6 @@
#include <mbgl/style/property_fallback.hpp>
#include <mbgl/style/style_properties.hpp>
#include <mbgl/style/style_bucket.hpp>
namespace mbgl {
@@ -52,6 +53,48 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = {
{ PropertyKey::BackgroundOpacity, defaultStyleProperties<BackgroundProperties>().opacity },
{ PropertyKey::BackgroundColor, defaultStyleProperties<BackgroundProperties>().color },
{ PropertyKey::LineCap, defaultLayoutProperties<StyleBucketLine>().cap },
{ PropertyKey::LineJoin, defaultLayoutProperties<StyleBucketLine>().join },
{ PropertyKey::LineMiterLimit, defaultLayoutProperties<StyleBucketLine>().miter_limit },
{ PropertyKey::LineRoundLimit, defaultLayoutProperties<StyleBucketLine>().round_limit },
{ PropertyKey::SymbolPlacement, defaultLayoutProperties<StyleBucketSymbol>().placement },
{ PropertyKey::SymbolMinDistance, defaultLayoutProperties<StyleBucketSymbol>().min_distance },
{ PropertyKey::SymbolAvoidEdges, defaultLayoutProperties<StyleBucketSymbol>().avoid_edges },
{ PropertyKey::IconAllowOverlap, defaultLayoutProperties<StyleBucketSymbol>().icon.allow_overlap },
{ PropertyKey::IconIgnorePlacement, defaultLayoutProperties<StyleBucketSymbol>().icon.ignore_placement },
{ PropertyKey::IconOptional, defaultLayoutProperties<StyleBucketSymbol>().icon.optional },
{ PropertyKey::IconRotationAlignment, defaultLayoutProperties<StyleBucketSymbol>().icon.rotation_alignment },
{ PropertyKey::IconMaxSize, defaultLayoutProperties<StyleBucketSymbol>().icon.max_size },
{ PropertyKey::IconImage, defaultLayoutProperties<StyleBucketSymbol>().icon.image },
{ PropertyKey::IconRotate, defaultLayoutProperties<StyleBucketSymbol>().icon.rotate },
{ PropertyKey::IconPadding, defaultLayoutProperties<StyleBucketSymbol>().icon.padding },
{ PropertyKey::IconKeepUpright, defaultLayoutProperties<StyleBucketSymbol>().icon.keep_upright },
{ PropertyKey::IconOffsetX, defaultLayoutProperties<StyleBucketSymbol>().icon.offset[0] },
{ PropertyKey::IconOffsetY, defaultLayoutProperties<StyleBucketSymbol>().icon.offset[1] },
{ PropertyKey::TextRotationAlignment, defaultLayoutProperties<StyleBucketSymbol>().text.rotation_alignment },
{ PropertyKey::TextField, defaultLayoutProperties<StyleBucketSymbol>().text.field },
{ PropertyKey::TextFont, defaultLayoutProperties<StyleBucketSymbol>().text.font },
{ PropertyKey::TextMaxSize, defaultLayoutProperties<StyleBucketSymbol>().text.max_size },
{ PropertyKey::TextMaxWidth, defaultLayoutProperties<StyleBucketSymbol>().text.max_width },
{ PropertyKey::TextLineHeight, defaultLayoutProperties<StyleBucketSymbol>().text.line_height },
{ PropertyKey::TextLetterSpacing, defaultLayoutProperties<StyleBucketSymbol>().text.letter_spacing },
{ PropertyKey::TextJustify, defaultLayoutProperties<StyleBucketSymbol>().text.justify },
{ PropertyKey::TextAnchor, defaultLayoutProperties<StyleBucketSymbol>().text.anchor },
{ PropertyKey::TextMaxAngle, defaultLayoutProperties<StyleBucketSymbol>().text.max_angle },
{ PropertyKey::TextRotate, defaultLayoutProperties<StyleBucketSymbol>().text.rotate },
{ PropertyKey::TextPadding, defaultLayoutProperties<StyleBucketSymbol>().text.padding },
{ PropertyKey::TextKeepUpright, defaultLayoutProperties<StyleBucketSymbol>().text.keep_upright },
{ PropertyKey::TextTransform, defaultLayoutProperties<StyleBucketSymbol>().text.transform },
{ PropertyKey::TextOffsetX, defaultLayoutProperties<StyleBucketSymbol>().text.offset[0] },
{ PropertyKey::TextOffsetY, defaultLayoutProperties<StyleBucketSymbol>().text.offset[1] },
{ PropertyKey::TextAllowOverlap, defaultLayoutProperties<StyleBucketSymbol>().text.allow_overlap },
{ PropertyKey::TextIgnorePlacement, defaultLayoutProperties<StyleBucketSymbol>().text.ignore_placement },
{ PropertyKey::TextOptional, defaultLayoutProperties<StyleBucketSymbol>().text.optional },
};
const PropertyValue PropertyFallbackValue::defaultProperty = false;

View File

@@ -26,8 +26,16 @@ enum class PropertyKey {
LineDashArray, // for transitions only
LineImage,
LineCap,
LineJoin,
LineMiterLimit,
LineRoundLimit,
SymbolPlacement,
SymbolMinDistance,
SymbolAvoidEdges,
IconOpacity,
IconRotate,
IconSize,
IconColor,
IconHaloColor,
@@ -38,6 +46,18 @@ enum class PropertyKey {
IconTranslateY,
IconTranslateAnchor,
IconAllowOverlap,
IconIgnorePlacement,
IconOptional,
IconRotationAlignment,
IconMaxSize,
IconImage,
IconPadding,
IconRotate,
IconKeepUpright,
IconOffsetX,
IconOffsetY,
TextOpacity,
TextSize,
TextColor,
@@ -49,6 +69,26 @@ enum class PropertyKey {
TextTranslateY,
TextTranslateAnchor,
TextRotationAlignment,
TextField,
TextFont,
TextMaxSize,
TextMaxWidth,
TextLineHeight,
TextLetterSpacing,
TextMaxAngle,
TextRotate,
TextPadding,
TextIgnorePlacement,
TextOptional,
TextJustify,
TextAnchor,
TextKeepUpright,
TextTransform,
TextOffsetX,
TextOffsetY,
TextAllowOverlap,
RasterOpacity,
RasterHueRotate,
RasterBrightness, // for transitions only
@@ -60,7 +100,9 @@ enum class PropertyKey {
BackgroundOpacity,
BackgroundColor,
BackgroundImage
BackgroundImage,
Visibilty
};
}

View File

@@ -13,6 +13,15 @@ typedef mapbox::util::variant<
std::string,
TranslateAnchorType,
RotateAnchorType,
bool,
CapType,
JoinType,
VisibilityType,
PlacementType,
RotationAlignmentType,
TextTransformType,
TextJustifyType,
TextAnchorType,
Function<bool>,
Function<float>,
Function<Color>,

View File

@@ -2,14 +2,12 @@
namespace mbgl {
StyleBucket::StyleBucket(StyleLayerType type) {
switch (type) {
case StyleLayerType::Fill: render = StyleBucketFill{}; break;
case StyleLayerType::Line: render = StyleBucketLine{}; break;
case StyleLayerType::Symbol: render = StyleBucketSymbol{}; break;
case StyleLayerType::Raster: render = StyleBucketRaster{}; break;
default: break;
}
}
StyleBucket::StyleBucket(StyleLayerType type_) :type(type_) {}
template<> const StyleBucketFill &defaultLayoutProperties() { static StyleBucketFill p; return p; }
template<> const StyleBucketLine &defaultLayoutProperties() { static StyleBucketLine p; return p; }
template<> const StyleBucketSymbol &defaultLayoutProperties() { static StyleBucketSymbol p; return p; }
template<> const StyleBucketRaster &defaultLayoutProperties() { static StyleBucketRaster p; return p; }
template<> const StyleBucketBackground &defaultLayoutProperties() { static StyleBucketBackground p; return p; }
}

View File

@@ -9,6 +9,7 @@
#include <mbgl/util/variant.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/style/class_properties.hpp>
#include <forward_list>
@@ -52,7 +53,7 @@ public:
float rotate = 0.0f;
float padding = 2.0f;
bool keep_upright = false;
vec2<float> offset = {0, 0};
std::array<float, 2> offset = {{ 0, 0 }};
} icon;
struct {
@@ -60,9 +61,9 @@ public:
std::string field;
std::string font;
float max_size = 16.0f;
float max_width = 15.0f * 24 /* em */;
float line_height = 1.2f * 24 /* em */;
float letter_spacing = 0.0f * 24 /* em */;
float max_width = 15.0f /* em */;
float line_height = 1.2f /* em */;
float letter_spacing = 0.0f /* em */;
TextJustifyType justify = TextJustifyType::Center;
TextAnchorType anchor = TextAnchorType::Center;
float max_angle = 45.0f /* degrees */;
@@ -71,7 +72,7 @@ public:
float padding = 2.0f;
bool keep_upright = true;
TextTransformType transform = TextTransformType::None;
vec2<float> offset = {0, 0};
std::array<float, 2> offset = {{ 0, 0 }};
bool allow_overlap = false;
bool ignore_placement = false;
bool optional = false;
@@ -82,8 +83,12 @@ class StyleBucketRaster {
public:
};
class StyleBucketBackground {
public:
};
typedef mapbox::util::variant<StyleBucketFill, StyleBucketLine, StyleBucketSymbol,
StyleBucketRaster, std::false_type> StyleBucketRender;
StyleBucketRaster, StyleBucketBackground, std::false_type> StyleBucketRender;
class StyleBucket {
@@ -91,18 +96,20 @@ public:
typedef util::ptr<StyleBucket> Ptr;
StyleBucket(StyleLayerType type);
StyleLayerType type;
std::string name;
util::ptr<StyleSource> style_source;
std::string source_layer;
FilterExpression filter;
ClassProperties layout;
StyleBucketRender render = std::false_type();
float min_zoom = -std::numeric_limits<float>::infinity();
float max_zoom = std::numeric_limits<float>::infinity();
VisibilityType visibility = VisibilityType::Visible;
};
template <typename T>
const T &defaultLayoutProperties();
};

View File

@@ -327,6 +327,18 @@ bool StyleParser::setProperty(JSVal value, const char *property_name, PropertyKe
return parsed;
}
template<typename T>
void StyleParser::parseVisibility(StyleBucket &bucket, JSVal value) {
if (!value.HasMember("visibility")) {
return;
} else if (!value["visibility"].IsString()) {
Log::Warning(Event::ParseStyle, "value of 'visibility' must be a string");
bucket.visibility = VisibilityType::Visible;
return;
}
bucket.visibility = VisibilityTypeClass({ value["visibility"].GetString(), value["visibility"].GetStringLength() });
}
template<typename T>
bool StyleParser::parseOptionalProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value) {
if (!value.HasMember(property_name)) {
@@ -345,6 +357,15 @@ template<> std::tuple<bool, std::string> StyleParser::parseProperty(JSVal value,
return std::tuple<bool, std::string> { true, { value.GetString(), value.GetStringLength() } };
}
template<> std::tuple<bool, bool> StyleParser::parseProperty(JSVal value, const char *property_name) {
if (!value.IsBool()) {
Log::Warning(Event::ParseStyle, "value of '%s' must be a boolean", property_name);
return std::tuple<bool, bool> { false, true };
}
return std::tuple<bool, bool> { true, value.GetBool() };
}
template<> std::tuple<bool, TranslateAnchorType> StyleParser::parseProperty(JSVal value, const char *property_name) {
if (!value.IsString()) {
Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
@@ -363,6 +384,69 @@ template<> std::tuple<bool, RotateAnchorType> StyleParser::parseProperty<RotateA
return std::tuple<bool, RotateAnchorType> { true, RotateAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
}
template<> std::tuple<bool, CapType> StyleParser::parseProperty<CapType>(JSVal value, const char *property_name) {
if (!value.IsString()) {
Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
return std::tuple<bool, CapType> { false, CapType::Butt };
}
return std::tuple<bool, CapType> { true, CapTypeClass({ value.GetString(), value.GetStringLength() }) };
}
template<> std::tuple<bool, JoinType> StyleParser::parseProperty<JoinType>(JSVal value, const char *property_name) {
if (!value.IsString()) {
Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
return std::tuple<bool, JoinType> { false, JoinType::Miter };
}
return std::tuple<bool, JoinType> { true, JoinTypeClass({ value.GetString(), value.GetStringLength() }) };
}
template<> std::tuple<bool, PlacementType> StyleParser::parseProperty<PlacementType>(JSVal value, const char *property_name) {
if (!value.IsString()) {
Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
return std::tuple<bool, PlacementType> { false, PlacementType::Point };
}
return std::tuple<bool, PlacementType> { true, PlacementTypeClass({ value.GetString(), value.GetStringLength() }) };
}
template<> std::tuple<bool, TextAnchorType> StyleParser::parseProperty<TextAnchorType>(JSVal value, const char *property_name) {
if (!value.IsString()) {
Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
return std::tuple<bool, TextAnchorType> { false, TextAnchorType::Center };
}
return std::tuple<bool, TextAnchorType> { true, TextAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
}
template<> std::tuple<bool, TextJustifyType> StyleParser::parseProperty<TextJustifyType>(JSVal value, const char *property_name) {
if (!value.IsString()) {
Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
return std::tuple<bool, TextJustifyType> { false, TextJustifyType::Center };
}
return std::tuple<bool, TextJustifyType> { true, TextJustifyTypeClass({ value.GetString(), value.GetStringLength() }) };
}
template<> std::tuple<bool, TextTransformType> StyleParser::parseProperty<TextTransformType>(JSVal value, const char *property_name) {
if (!value.IsString()) {
Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
return std::tuple<bool, TextTransformType> { false, TextTransformType::None };
}
return std::tuple<bool, TextTransformType> { true, TextTransformTypeClass({ value.GetString(), value.GetStringLength() }) };
}
template<> std::tuple<bool, RotationAlignmentType> StyleParser::parseProperty<RotationAlignmentType>(JSVal value, const char *property_name) {
if (!value.IsString()) {
Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
return std::tuple<bool, RotationAlignmentType> { false, RotationAlignmentType::Map };
}
return std::tuple<bool, RotationAlignmentType> { true, RotationAlignmentTypeClass({ value.GetString(), value.GetStringLength() }) };
}
template<> std::tuple<bool, PropertyTransition> StyleParser::parseProperty(JSVal value, const char */*property_name*/) {
PropertyTransition transition;
if (value.IsObject()) {
@@ -642,6 +726,50 @@ void StyleParser::parsePaint(JSVal value, ClassProperties &klass) {
parseOptionalProperty<std::string>("background-image", Key::BackgroundImage, klass, value);
}
void StyleParser::parseLayout(JSVal value, util::ptr<StyleBucket> &bucket) {
using Key = PropertyKey;
parseVisibility<VisibilityType>(*bucket, value);
parseOptionalProperty<CapType>("line-cap", Key::LineCap, bucket->layout, value);
parseOptionalProperty<JoinType>("line-join", Key::LineJoin, bucket->layout, value);
parseOptionalProperty<Function<float>>("line-miter-limit", Key::LineMiterLimit, bucket->layout, value);
parseOptionalProperty<Function<float>>("line-round-limit", Key::LineRoundLimit, bucket->layout, value);
parseOptionalProperty<PlacementType>("symbol-placement", Key::SymbolPlacement, bucket->layout, value);
parseOptionalProperty<Function<float>>("symbol-min-distance", Key::SymbolMinDistance, bucket->layout, value);
parseOptionalProperty<bool>("symbol-avoid-edges", Key::SymbolAvoidEdges, bucket->layout, value);
parseOptionalProperty<bool>("icon-allow-overlap", Key::IconAllowOverlap, bucket->layout, value);
parseOptionalProperty<bool>("icon-ignore-placement", Key::IconIgnorePlacement, bucket->layout, value);
parseOptionalProperty<bool>("icon-optional", Key::IconOptional, bucket->layout, value);
parseOptionalProperty<RotationAlignmentType>("icon-rotation-alignment", Key::IconRotationAlignment, bucket->layout, value);
parseOptionalProperty<Function<float>>("icon-max-size", Key::IconMaxSize, bucket->layout, value);
parseOptionalProperty<std::string>("icon-image", Key::IconImage, bucket->layout, value);
parseOptionalProperty<Function<float>>("icon-rotate", Key::IconRotate, bucket->layout, value);
parseOptionalProperty<Function<float>>("icon-padding", Key::IconPadding, bucket->layout, value);
parseOptionalProperty<bool>("icon-keep-upright", Key::IconKeepUpright, bucket->layout, value);
parseOptionalProperty<Function<float>>("icon-offset", { Key::IconOffsetX, Key::IconOffsetY }, bucket->layout, value);
parseOptionalProperty<RotationAlignmentType>("text-rotation-alignment", Key::TextRotationAlignment, bucket->layout, value);
parseOptionalProperty<std::string>("text-field", Key::TextField, bucket->layout, value);
parseOptionalProperty<std::string>("text-font", Key::TextFont, bucket->layout, value);
parseOptionalProperty<Function<float>>("text-max-size", Key::TextMaxSize, bucket->layout, value);
parseOptionalProperty<Function<float>>("text-max-width", Key::TextMaxWidth, bucket->layout, value);
parseOptionalProperty<Function<float>>("text-line-height", Key::TextLineHeight, bucket->layout, value);
parseOptionalProperty<Function<float>>("text-letter-spacing", Key::TextLetterSpacing, bucket->layout, value);
parseOptionalProperty<TextJustifyType>("text-justify", Key::TextJustify, bucket->layout, value);
parseOptionalProperty<TextAnchorType>("text-anchor", Key::TextAnchor, bucket->layout, value);
parseOptionalProperty<Function<float>>("text-max-angle", Key::TextMaxAngle, bucket->layout, value);
parseOptionalProperty<Function<float>>("text-rotate", Key::TextRotate, bucket->layout, value);
parseOptionalProperty<Function<float>>("text-padding", Key::TextPadding, bucket->layout, value);
parseOptionalProperty<bool>("text-keep-upright", Key::TextKeepUpright, bucket->layout, value);
parseOptionalProperty<TextTransformType>("text-transform", Key::TextTransform, bucket->layout, value);
parseOptionalProperty<Function<float>>("text-offset", { Key::TextOffsetX, Key::TextOffsetY }, bucket->layout, value);
parseOptionalProperty<bool>("text-allow-overlap", Key::TextAllowOverlap, bucket->layout, value);
parseOptionalProperty<bool>("text-ignore-placement", Key::TextIgnorePlacement, bucket->layout, value);
parseOptionalProperty<bool>("text-optional", Key::TextOptional, bucket->layout, value);
}
void StyleParser::parseReference(JSVal value, util::ptr<StyleLayer> &layer) {
if (!value.IsString()) {
Log::Warning(Event::ParseStyle, "layer ref of '%s' must be a string", layer->id.c_str());
@@ -704,7 +832,7 @@ void StyleParser::parseBucket(JSVal value, util::ptr<StyleLayer> &layer) {
if (value.HasMember("layout")) {
JSVal value_render = replaceConstant(value["layout"]);
parseLayout(value_render, layer);
parseLayout(value_render, layer->bucket);
}
if (value.HasMember("minzoom")) {
@@ -726,89 +854,6 @@ void StyleParser::parseBucket(JSVal value, util::ptr<StyleLayer> &layer) {
}
}
void StyleParser::parseLayout(JSVal value, util::ptr<StyleLayer> &layer) {
if (!value.IsObject()) {
Log::Warning(Event::ParseStyle, "layout property of layer '%s' must be an object", layer->id.c_str());
return;
}
StyleBucket &bucket = *layer->bucket;
parseRenderProperty<VisibilityTypeClass>(value, bucket.visibility, "visibility");
switch (layer->type) {
case StyleLayerType::Fill: {
StyleBucketFill &render = bucket.render.get<StyleBucketFill>();
parseRenderProperty<WindingTypeClass>(value, render.winding, "fill-winding");
} break;
case StyleLayerType::Line: {
StyleBucketLine &render = bucket.render.get<StyleBucketLine>();
parseRenderProperty<CapTypeClass>(value, render.cap, "line-cap");
parseRenderProperty<JoinTypeClass>(value, render.join, "line-join");
parseRenderProperty(value, render.miter_limit, "line-miter-limit");
parseRenderProperty(value, render.round_limit, "line-round-limit");
} break;
case StyleLayerType::Symbol: {
StyleBucketSymbol &render = bucket.render.get<StyleBucketSymbol>();
parseRenderProperty<PlacementTypeClass>(value, render.placement, "symbol-placement");
if (render.placement == PlacementType::Line) {
// Change the default value in case of line placement.
render.text.rotation_alignment = RotationAlignmentType::Map;
render.icon.rotation_alignment = RotationAlignmentType::Map;
}
parseRenderProperty(value, render.min_distance, "symbol-min-distance");
parseRenderProperty(value, render.avoid_edges, "symbol-avoid-edges");
parseRenderProperty(value, render.icon.allow_overlap, "icon-allow-overlap");
parseRenderProperty(value, render.icon.ignore_placement, "icon-ignore-placement");
parseRenderProperty(value, render.icon.optional, "icon-optional");
parseRenderProperty<RotationAlignmentTypeClass>(value, render.icon.rotation_alignment, "icon-rotation-alignment");
parseRenderProperty(value, render.icon.max_size, "icon-max-size");
parseRenderProperty(value, render.icon.image, "icon-image");
parseRenderProperty(value, render.icon.rotate, "icon-rotate");
parseRenderProperty(value, render.icon.padding, "icon-padding");
parseRenderProperty(value, render.icon.keep_upright, "icon-keep-upright");
parseRenderProperty(value, render.icon.offset, "icon-offset");
parseRenderProperty<RotationAlignmentTypeClass>(value, render.text.rotation_alignment, "text-rotation-alignment");
parseRenderProperty(value, render.text.field, "text-field");
parseRenderProperty(value, render.text.font, "text-font");
parseRenderProperty(value, render.text.max_size, "text-max-size");
if (parseRenderProperty(value, render.text.max_width, "text-max-width")) {
render.text.max_width *= 24; // em
}
if (parseRenderProperty(value, render.text.line_height, "text-line-height")) {
render.text.line_height *= 24; // em
}
if (parseRenderProperty(value, render.text.letter_spacing, "text-letter-spacing")) {
render.text.letter_spacing *= 24; // em
}
parseRenderProperty<TextJustifyTypeClass>(value, render.text.justify, "text-justify");
parseRenderProperty<TextAnchorTypeClass>(value, render.text.anchor, "text-anchor");
parseRenderProperty(value, render.text.max_angle, "text-max-angle");
parseRenderProperty(value, render.text.rotate, "text-rotate");
parseRenderProperty(value, render.text.slant, "text-slant");
parseRenderProperty(value, render.text.padding, "text-padding");
parseRenderProperty(value, render.text.keep_upright, "text-keep-upright");
parseRenderProperty<TextTransformTypeClass>(value, render.text.transform, "text-transform");
parseRenderProperty(value, render.text.offset, "text-offset");
parseRenderProperty(value, render.text.allow_overlap, "text-allow-overlap");
parseRenderProperty(value, render.text.ignore_placement, "text-ignore-placement");
parseRenderProperty(value, render.text.optional, "text-optional");
} break;
default:
// There are no render properties for these layer types.
break;
}
}
void StyleParser::parseSprite(JSVal value) {
if (value.IsString()) {
sprite = { value.GetString(), value.GetStringLength() };

View File

@@ -53,7 +53,7 @@ private:
void parsePaint(JSVal, ClassProperties &properties);
void parseReference(JSVal value, util::ptr<StyleLayer> &layer);
void parseBucket(JSVal value, util::ptr<StyleLayer> &layer);
void parseLayout(JSVal value, util::ptr<StyleLayer> &layer);
void parseLayout(JSVal value, util::ptr<StyleBucket> &bucket);
void parseSprite(JSVal value);
void parseGlyphURL(JSVal value);
@@ -65,6 +65,8 @@ private:
// Parses optional properties into style class properties.
template <typename T>
void parseVisibility(StyleBucket &bucket, JSVal value);
template <typename T>
bool parseOptionalProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value);
template <typename T>
bool parseOptionalProperty(const char *property_name, const std::vector<PropertyKey> &keys, ClassProperties &klass, JSVal value);

View File

@@ -131,8 +131,8 @@ GlyphBox getMergedBoxes(const GlyphBoxes &glyphs, const Anchor &anchor) {
Placement Placement::getIcon(Anchor &anchor, const Rect<uint16_t> &image, float boxScale,
const std::vector<Coordinate> &line, const StyleBucketSymbol &props) {
const float dx = props.icon.offset.x;
const float dy = props.icon.offset.y;
const float dx = props.icon.offset[0];
const float dy = props.icon.offset[1];
float x1 = dx - image.originalW / 2.0f;
float x2 = x1 + image.w;
float y1 = dy - image.originalH / 2.0f;