Add functions for layout properties.
This commit is contained in:
committed by
John Firebaugh
parent
230963b22d
commit
895d90409b
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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; }
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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() };
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user