Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

v8 Omnibus 2 #993

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/mbgl/map/tile_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ std::unique_ptr<StyleLayoutSymbol> parseStyleLayoutSymbol(const StyleBucket &buc
symbol.icon.rotation_alignment = RotationAlignmentType::Map;
symbol.text.rotation_alignment = RotationAlignmentType::Map;
};
applyLayoutProperty(PropertyKey::SymbolMinDistance, bucket_desc.layout, symbol.min_distance, z);
applyLayoutProperty(PropertyKey::SymbolSpacing, bucket_desc.layout, symbol.spacing, z);
applyLayoutProperty(PropertyKey::SymbolAvoidEdges, bucket_desc.layout, symbol.avoid_edges, z);

applyLayoutProperty(PropertyKey::IconAllowOverlap, bucket_desc.layout, symbol.icon.allow_overlap, z);
Expand Down
2 changes: 1 addition & 1 deletion src/mbgl/renderer/symbol_bucket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ void SymbolBucket::addFeature(const std::vector<Coordinate> &line, const Shaping
}

// Line labels
anchors = resample(line, layout.min_distance, minScale, collision.maxPlacementScale,
anchors = resample(line, layout.spacing, minScale, collision.maxPlacementScale,
collision.tilePixelRatio, resampleOffset);

// Sort anchors by segment so that we can start placement with the
Expand Down
185 changes: 185 additions & 0 deletions src/mbgl/style/color_operations.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#include <mbgl/style/color_operations.hpp>
#include <mbgl/style/value.hpp>
#include <mbgl/platform/log.hpp>
#include <csscolorparser/csscolorparser.hpp>

#include <string>
#include <array>
#include <cmath>

namespace mbgl {

CSSColorParser::Color parseColorOp(const rapidjson::Value& value, const std::unordered_map<std::string, const rapidjson::Value *>& constants) {
CSSColorParser::Color empty;

if (value.Size() < 3) {
Log::Warning(Event::ParseStyle, "color operation must have at least 3 elements");
return empty;
}
if (!value[0u].IsString()) {
Log::Warning(Event::ParseStyle, "color operator must be a string");
return empty;
}

if (!value[1u].IsNumber()) {
Log::Warning(Event::ParseStyle, "degree of change must be a number");
return empty;
}

std::string op = { value[0u].GetString(), value[0u].GetStringLength() };
double degree = value[1u].GetDouble();

ColorOperation opResult = ColorOperation(degree, parseColorarr(value[2u], constants));
CSSColorParser::Color result;

if (op == "lighten") {
Lighten * light = static_cast<Lighten*> (&opResult);
result = light->evaluate();
} else if (op == "saturate") {
Saturate * saturate = static_cast<Saturate*> (&opResult);
result = saturate->evaluate();
} else if (op == "fade") {
Fade * fade = static_cast<Fade*> (&opResult);
result = fade->evaluate();
} else if (op == "spin") {
Spin * spin = static_cast<Spin*> (&opResult);
result = spin->evaluate();
} else if (op == "mix") {
if (!value[3u].IsString() && !value[3u].IsArray()) {
Log::Warning(Event::ParseStyle, "Mix must have a valid second color");
return empty;
}
Mix mix = Mix(opResult, parseColorarr(value[3u], constants));
result = mix.evaluate();
} else {
Log::Warning(Event::ParseStyle, "color operator must be one of \"lighten\", \"saturate\", \"fade\", \"spin\", \"mix\"");
}
return result;

}

CSSColorParser::Color parseColorarr(const rapidjson::Value& color, const std::unordered_map<std::string, const rapidjson::Value *>& constants) {
CSSColorParser::Color css_color;
if (color.IsArray()) {
css_color = parseColorOp(color, constants);
} else if (color.IsString()) {
std::string strcolor { color.GetString(), color.GetStringLength() };
if (strcolor.length() && strcolor[0] == '@') {
auto it = constants.find(strcolor);
if (it != constants.end()) {
const rapidjson::Value& replaced = *it->second;
strcolor.replace(strcolor.begin(), strcolor.end(), { replaced.GetString(), replaced.GetStringLength()});
}
}
css_color = CSSColorParser::parse(strcolor);
} else {
Log::Warning(Event::ParseStyle, "color must be a string or array");
return css_color;
}
return css_color;
}

std::array<double, 4> ColorOperation::toHSL() {

double r = color_.r / 255.0;
double g = color_.g / 255.0;
double b = color_.b / 255.0;
double a = color_.a;

double max = std::max(r, std::max(g, b)),
min = std::min(r, std::min(g, b));

double h, s, l = (max + min) / 2,
d = max - min;

if (max == min) {
h = s = 0;
} else {
if (l > 0.5) {
s = d / (2 - max - min);
} else {
s = d / (max + min);
}
if (max == r) {
h = (g - b) / d + (g < b ? 6 : 0);
} else if (max == g) {
h = (b - r) / d + 2;
} else {
h = (r - g) / d + 4;
}
h /= 6;
}
h *= 360;
return {{h, s, l, a}};
}

double ColorOperation::clamp(double val) {
double max = std::max(0.0, val);
return std::min(1.0, max);
}

CSSColorParser::Color toColor(std::array<double, 4> hsl) {
std::string str = "hsla(";
str.append(std::to_string(hsl[0]));
str = str + ", ";
str.append(std::to_string(hsl[1]*100));
str = str + "%, ";
str.append(std::to_string(hsl[2]*100));
str = str + "%, ";
str.append(std::to_string(hsl[3]));
str = str + ")";
return CSSColorParser::parse(str);
}

CSSColorParser::Color Lighten::evaluate() {
std::array<double, 4> hsl = this->toHSL();

hsl[2] += this->degree_ / 100.0;
hsl[2] = clamp(hsl[2]);
return toColor(hsl);
}

CSSColorParser::Color Saturate::evaluate() {
std::array<double, 4> hsl = this->toHSL();

hsl[1] += this->degree_ / 100.0;
hsl[1] = clamp(hsl[1]);
return toColor(hsl);
}

CSSColorParser::Color Fade::evaluate() {
std::array<double, 4> hsl = this->toHSL();

hsl[3] -= this->degree_ / 100.0;
hsl[3] = clamp(hsl[3]);
return toColor(hsl);
}

CSSColorParser::Color Spin::evaluate() {
std::array<double, 4> hsl = this->toHSL();

double hue = fmod((hsl[0] + this->degree_), 360.0);
if (hue < 0) {
hsl[0] = 360 + hue;
} else {
hsl[0] = hue;
}
return toColor(hsl);
}

CSSColorParser::Color Mix::evaluate() {
double p = this->degree_ / 100.0;
double w = p * 2 - 1;
double a = this->ColorOperation::toHSL()[3] - this->Mix::toHSL()[3];

double w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
double w2 = 1 - w1;

std::array<double, 3> rgb = {{color_.r * w1 + color2_.r * w2,
color_.g * w1 + color2_.g * w2,
color_.b * w1 + color2_.b * w2}};

double alpha = color_.a * p + color2_.a * (1 - p);
return CSSColorParser::Color(rgb[0], rgb[1], rgb[2], alpha);
}
}
60 changes: 60 additions & 0 deletions src/mbgl/style/color_operations.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#ifndef MBGL_STYLE_COLOR_OPERATIONS
#define MBGL_STYLE_COLOR_OPERATIONS

#include <csscolorparser/csscolorparser.hpp>
#include "rapidjson/document.h"
#include <mbgl/style/value.hpp>

#include <string>
#include <array>
#include <unordered_map>

namespace mbgl {

CSSColorParser::Color parseColorOp(const rapidjson::Value&, const std::unordered_map<std::string, const rapidjson::Value *>&);
CSSColorParser::Color parseColorarr(const rapidjson::Value&, const std::unordered_map<std::string, const rapidjson::Value *>& constants);

class ColorOperation {
protected:
double degree_;
CSSColorParser::Color color_;
public:
ColorOperation() : degree_(0), color_() {}
ColorOperation(double degree, CSSColorParser::Color color) : degree_(degree), color_(color) {}
virtual ~ColorOperation() {}
std::array<double, 4> toHSL();
double clamp(double);

};

class Lighten : public ColorOperation {
public:
CSSColorParser::Color evaluate();
};

class Saturate : public ColorOperation {
public:
CSSColorParser::Color evaluate();
};

class Fade : public ColorOperation {
public:
CSSColorParser::Color evaluate();
};

class Spin : public ColorOperation {
public:
CSSColorParser::Color evaluate();
};

class Mix : public ColorOperation {
protected:
CSSColorParser::Color color2_;
public:
Mix(ColorOperation colorOp, CSSColorParser::Color color2) : ColorOperation(colorOp), color2_(color2) {}
CSSColorParser::Color evaluate();
std::array<double, 4> toHSL() { return ColorOperation(0, color2_).ColorOperation::toHSL();}
};
}

#endif
2 changes: 1 addition & 1 deletion src/mbgl/style/property_fallback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = {
{ PropertyKey::LineRoundLimit, defaultStyleLayout<StyleLayoutLine>().round_limit },

{ PropertyKey::SymbolPlacement, defaultStyleLayout<StyleLayoutSymbol>().placement },
{ PropertyKey::SymbolMinDistance, defaultStyleLayout<StyleLayoutSymbol>().min_distance },
{ PropertyKey::SymbolSpacing, defaultStyleLayout<StyleLayoutSymbol>().spacing },
{ PropertyKey::SymbolAvoidEdges, defaultStyleLayout<StyleLayoutSymbol>().avoid_edges },

{ PropertyKey::IconAllowOverlap, defaultStyleLayout<StyleLayoutSymbol>().icon.allow_overlap },
Expand Down
2 changes: 1 addition & 1 deletion src/mbgl/style/property_key.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ enum class PropertyKey {
LineRoundLimit,

SymbolPlacement,
SymbolMinDistance,
SymbolSpacing,
SymbolAvoidEdges,

IconOpacity,
Expand Down
2 changes: 1 addition & 1 deletion src/mbgl/style/style_layout.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class StyleLayoutSymbol {
StyleLayoutSymbol& operator=(const StyleLayoutSymbol &) = delete;

PlacementType placement = PlacementType::Point;
float min_distance = 250.0f;
float spacing = 250.0f;
bool avoid_edges = false;

struct {
Expand Down
Loading