Files
MapLibreParticleLab/src/mbgl/style/expression/step.cpp
Thiago Marcos P. Santos 92608f5885 [core] Fix build on Android + GCC and Android + armeabi
Sadly we don't have bots for these two setups.
2017-11-12 13:17:57 -02:00

153 lines
4.9 KiB
C++

#include <mbgl/style/expression/step.hpp>
#include <mbgl/style/expression/get_covering_stops.hpp>
#include <mbgl/util/string.hpp>
namespace mbgl {
namespace style {
namespace expression {
EvaluationResult Step::evaluate(const EvaluationContext& params) const {
const EvaluationResult evaluatedInput = input->evaluate(params);
if (!evaluatedInput) { return evaluatedInput.error(); }
float x = *fromExpressionValue<float>(*evaluatedInput);
if (stops.empty()) {
return EvaluationError { "No stops in step curve." };
}
auto it = stops.upper_bound(x);
if (it == stops.end()) {
return stops.rbegin()->second->evaluate(params);
} else if (it == stops.begin()) {
return stops.begin()->second->evaluate(params);
} else {
return std::prev(it)->second->evaluate(params);
}
}
void Step::eachChild(const std::function<void(const Expression&)>& visit) const {
visit(*input);
for (auto it = stops.begin(); it != stops.end(); it++) {
visit(*it->second);
}
}
bool Step::operator==(const Expression& e) const {
if (auto rhs = dynamic_cast<const Step*>(&e)) {
return *input == *(rhs->input) && Expression::childrenEqual(stops, rhs->stops);
}
return false;
}
Range<float> Step::getCoveringStops(const double lower, const double upper) const {
return ::mbgl::style::expression::getCoveringStops(stops, lower, upper);
}
ParseResult Step::parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx) {
assert(isArray(value));
auto length = arrayLength(value);
if (length - 1 < 4) {
ctx.error("Expected at least 4 arguments, but found only " + util::toString(length - 1) + ".");
return ParseResult();
}
// [step, input, firstOutput_value, 2 * (n pairs)...]
if ((length - 1) % 2 != 0) {
ctx.error("Expected an even number of arguments.");
return ParseResult();
}
ParseResult input = ctx.parse(arrayMember(value, 1), 1, {type::Number});
if (!input) {
return input;
}
std::map<double, std::unique_ptr<Expression>> stops;
optional<type::Type> outputType;
if (ctx.getExpected() && *ctx.getExpected() != type::Value) {
outputType = ctx.getExpected();
}
double previous = - std::numeric_limits<double>::infinity();
// consume the first output value, which doesn't have a corresponding input value,
// before proceeding into the "stops" loop below.
auto firstOutput = ctx.parse(arrayMember(value, 2), 2, outputType);
if (!firstOutput) {
return ParseResult();
}
if (!outputType) {
outputType = (*firstOutput)->getType();
}
stops.emplace(-std::numeric_limits<double>::infinity(), std::move(*firstOutput));
for (std::size_t i = 3; i + 1 < length; i += 2) {
const optional<mbgl::Value> labelValue = toValue(arrayMember(value, i));
optional<double> label;
if (labelValue) {
labelValue->match(
[&](uint64_t n) {
if (n > std::numeric_limits<double>::max()) {
label = {std::numeric_limits<double>::infinity()};
} else {
label = {static_cast<double>(n)};
}
},
[&](int64_t n) {
if (n > std::numeric_limits<double>::max()) {
label = {std::numeric_limits<double>::infinity()};
} else {
label = {static_cast<double>(n)};
}
},
[&](double n) {
if (n > std::numeric_limits<double>::max()) {
label = {std::numeric_limits<double>::infinity()};
} else {
label = {static_cast<double>(n)};
}
},
[&](const auto&) {}
);
}
if (!label) {
ctx.error(R"(Input/output pairs for "step" expressions must be defined using literal numeric values (not computed expressions) for the input values.)", i);
return ParseResult();
}
if (*label <= previous) {
ctx.error(
R"(Input/output pairs for "step" expressions must be arranged with input values in strictly ascending order.)",
i
);
return ParseResult();
}
previous = *label;
auto output = ctx.parse(arrayMember(value, i + 1), i + 1, outputType);
if (!output) {
return ParseResult();
}
if (!outputType) {
outputType = (*output)->getType();
}
stops.emplace(*label, std::move(*output));
}
assert(outputType);
return ParseResult(std::make_unique<Step>(*outputType, std::move(*input), std::move(stops)));
}
} // namespace expression
} // namespace style
} // namespace mbgl