diff options
author | Lauren Budorick <lauren@mapbox.com> | 2017-04-27 15:56:55 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-27 15:56:55 -0700 |
commit | f6e79d70735361438655f279c8699a786d25458c (patch) | |
tree | cc01ae7aba097bae4aa84beb12ac6b8f34f4d51a /include/mbgl | |
parent | 839ad87f37a4880804fb4c79157d998ac59954b5 (diff) | |
download | qtlocation-mapboxgl-f6e79d70735361438655f279c8699a786d25458c.tar.gz |
[core] Render fill-extrusion layers (#8431)
Diffstat (limited to 'include/mbgl')
-rw-r--r-- | include/mbgl/map/map.hpp | 5 | ||||
-rw-r--r-- | include/mbgl/style/conversion/constant.hpp | 49 | ||||
-rw-r--r-- | include/mbgl/style/conversion/layer.hpp | 3 | ||||
-rw-r--r-- | include/mbgl/style/conversion/light.hpp | 122 | ||||
-rw-r--r-- | include/mbgl/style/conversion/position.hpp | 29 | ||||
-rw-r--r-- | include/mbgl/style/layer.hpp | 2 | ||||
-rw-r--r-- | include/mbgl/style/light.hpp | 52 | ||||
-rw-r--r-- | include/mbgl/style/position.hpp | 68 | ||||
-rw-r--r-- | include/mbgl/style/types.hpp | 5 | ||||
-rw-r--r-- | include/mbgl/util/indexed_tuple.hpp | 56 | ||||
-rw-r--r-- | include/mbgl/util/interpolate.hpp | 12 | ||||
-rw-r--r-- | include/mbgl/util/type_list.hpp | 40 |
12 files changed, 408 insertions, 35 deletions
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 0e3cee4e70..84ea3104d8 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -30,6 +30,7 @@ namespace style { class Image; class Source; class Layer; +class Light; } // namespace style class Map : private util::noncopyable { @@ -179,6 +180,10 @@ public: void removeImage(const std::string&); const style::Image* getImage(const std::string&); + // Light + void setLight(std::unique_ptr<style::Light>); + style::Light* getLight(); + // Defaults std::string getStyleName() const; LatLng getDefaultLatLng() const; diff --git a/include/mbgl/style/conversion/constant.hpp b/include/mbgl/style/conversion/constant.hpp index 1e1fdc2ee8..07c0a35fae 100644 --- a/include/mbgl/style/conversion/constant.hpp +++ b/include/mbgl/style/conversion/constant.hpp @@ -4,6 +4,7 @@ #include <mbgl/util/optional.hpp> #include <mbgl/util/color.hpp> #include <mbgl/util/enum.hpp> +#include <mbgl/util/string.hpp> #include <array> #include <string> @@ -92,45 +93,25 @@ struct Converter<Color> { } }; -template <> -struct Converter<std::array<float, 2>> { +template <size_t N> +struct Converter<std::array<float, N>> { template <class V> - optional<std::array<float, 2>> operator()(const V& value, Error& error) const { - if (!isArray(value) || arrayLength(value) != 2) { - error = { "value must be an array of two numbers" }; + optional<std::array<float, N>> operator()(const V& value, Error& error) const { + if (!isArray(value) || arrayLength(value) != N) { + error = { "value must be an array of " + util::toString(N) + " numbers" }; return {}; } - optional<float> first = toNumber(arrayMember(value, 0)); - optional<float> second = toNumber(arrayMember(value, 1)); - if (!first || !second) { - error = { "value must be an array of two numbers" }; - return {}; - } - - return std::array<float, 2> {{ *first, *second }}; - } -}; - -template <> -struct Converter<std::array<float, 4>> { - template <class V> - optional<std::array<float, 4>> operator()(const V& value, Error& error) const { - if (!isArray(value) || arrayLength(value) != 4) { - error = { "value must be an array of four numbers" }; - return {}; - } - - optional<float> first = toNumber(arrayMember(value, 0)); - optional<float> second = toNumber(arrayMember(value, 1)); - optional<float> third = toNumber(arrayMember(value, 2)); - optional<float> fourth = toNumber(arrayMember(value, 3)); - if (!first || !second) { - error = { "value must be an array of four numbers" }; - return {}; + std::array<float, N> result; + for (size_t i = 0; i < N; i++) { + optional<float> n = toNumber(arrayMember(value, i)); + if (!n) { + error = { "value must be an array of " + util::toString(N) + " numbers" }; + return {}; + } + result[i] = *n; } - - return std::array<float, 4> {{ *first, *second, *third, *fourth }}; + return result; } }; diff --git a/include/mbgl/style/conversion/layer.hpp b/include/mbgl/style/conversion/layer.hpp index efb1df8fef..3a64c36bf5 100644 --- a/include/mbgl/style/conversion/layer.hpp +++ b/include/mbgl/style/conversion/layer.hpp @@ -4,6 +4,7 @@ #include <mbgl/style/layers/background_layer.hpp> #include <mbgl/style/layers/circle_layer.hpp> #include <mbgl/style/layers/fill_layer.hpp> +#include <mbgl/style/layers/fill_extrusion_layer.hpp> #include <mbgl/style/layers/line_layer.hpp> #include <mbgl/style/layers/raster_layer.hpp> #include <mbgl/style/layers/symbol_layer.hpp> @@ -92,6 +93,8 @@ public: if (*type == "fill") { converted = convertVectorLayer<FillLayer>(*id, value, error); + } else if (*type == "fill-extrusion") { + converted = convertVectorLayer<FillExtrusionLayer>(*id, value, error); } else if (*type == "line") { converted = convertVectorLayer<LineLayer>(*id, value, error); } else if (*type == "circle") { diff --git a/include/mbgl/style/conversion/light.hpp b/include/mbgl/style/conversion/light.hpp new file mode 100644 index 0000000000..631ed04ccb --- /dev/null +++ b/include/mbgl/style/conversion/light.hpp @@ -0,0 +1,122 @@ +#pragma once + +#include <mbgl/style/light.hpp> +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/position.hpp> +#include <mbgl/style/conversion/property_value.hpp> +#include <mbgl/style/conversion/transition_options.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +template <> +struct Converter<Light> { +public: + template <class V> + optional<Light> operator()(const V& value, Error& error) const { + if (!isObject(value)) { + error = { "light must be an object" }; + return {}; + } + + Light light; + + const auto anchor = objectMember(value, "anchor"); + if (anchor) { + optional<PropertyValue<LightAnchorType>> convertedAnchor = + convert<PropertyValue<LightAnchorType>>(*anchor, error); + + if (convertedAnchor) { + light.get<LightAnchor>().value = *convertedAnchor; + } else { + return {}; + } + } + + const auto anchorTransition = objectMember(value, "anchor-transition"); + if (anchorTransition) { + optional<TransitionOptions> transition = + convert<TransitionOptions>(*anchorTransition, error); + if (transition) { + light.get<LightAnchor>().transition = *transition; + } else { + return {}; + } + } + + const auto color = objectMember(value, "color"); + if (color) { + optional<PropertyValue<Color>> convertedColor = + convert<PropertyValue<Color>>(*color, error); + + if (convertedColor) { + light.get<LightColor>().value = *convertedColor; + } else { + return {}; + } + } + + const auto colorTransition = objectMember(value, "color-transition"); + if (colorTransition) { + optional<TransitionOptions> transition = + convert<TransitionOptions>(*colorTransition, error); + if (transition) { + light.get<LightColor>().transition = *transition; + } else { + return {}; + } + } + + const auto position = objectMember(value, "position"); + if (position) { + optional<PropertyValue<Position>> convertedPosition = + convert<PropertyValue<Position>>(*position, error); + + if (convertedPosition) { + light.get<LightPosition>().value = *convertedPosition; + } else { + return {}; + } + } + + const auto positionTransition = objectMember(value, "position-transition"); + if (positionTransition) { + optional<TransitionOptions> transition = + convert<TransitionOptions>(*positionTransition, error); + if (transition) { + light.get<LightPosition>().transition = *transition; + } else { + return {}; + } + } + + const auto intensity = objectMember(value, "intensity"); + if (intensity) { + optional<PropertyValue<float>> convertedIntensity = + convert<PropertyValue<float>>(*intensity, error); + + if (convertedIntensity) { + light.get<LightIntensity>().value = *convertedIntensity; + } else { + return {}; + } + } + + const auto intensityTransition = objectMember(value, "intensity-transition"); + if (intensityTransition) { + optional<TransitionOptions> transition = + convert<TransitionOptions>(*intensityTransition, error); + if (transition) { + light.get<LightIntensity>().transition = *transition; + } else { + return {}; + } + } + return { light }; + }; +}; + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/conversion/position.hpp b/include/mbgl/style/conversion/position.hpp new file mode 100644 index 0000000000..7036b03822 --- /dev/null +++ b/include/mbgl/style/conversion/position.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/position.hpp> +#include <mbgl/util/optional.hpp> + +#include <array> + +namespace mbgl { +namespace style { +namespace conversion { + +template <> +struct Converter<Position> { + template <class V> + optional<Position> operator()(const V& value, Error& error) const { + optional<std::array<float, 3>> spherical = convert<std::array<float, 3>>(value, error); + + if (!spherical) { + return {}; + } + + return Position(*spherical); + } +}; + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp index f09eb0165a..56f2c48fa7 100644 --- a/include/mbgl/style/layer.hpp +++ b/include/mbgl/style/layer.hpp @@ -66,7 +66,7 @@ public: // Convenience method for dynamic dispatch on the concrete layer type. Using // method overloading, this allows consolidation of logic common to vector-based - // layers (Fill, Line, Circle, or Symbol). For example: + // layers (Fill, FillExtrusion, Line, Circle, or Symbol). For example: // // struct Visitor { // void operator()(CustomLayer&) { ... } diff --git a/include/mbgl/style/light.hpp b/include/mbgl/style/light.hpp new file mode 100644 index 0000000000..bec8e6ddeb --- /dev/null +++ b/include/mbgl/style/light.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include <mbgl/style/property_value.hpp> +#include <mbgl/style/transition_options.hpp> +#include <mbgl/style/types.hpp> +#include <mbgl/style/position.hpp> +#include <mbgl/util/color.hpp> +#include <mbgl/util/indexed_tuple.hpp> + +namespace mbgl { +namespace style { + +template <class T> +class LightProperty { +public: + using Type = T; + using ValueType = PropertyValue<T>; + + PropertyValue<T> value; + TransitionOptions transition; +}; + +struct LightAnchor : LightProperty<LightAnchorType> { + static LightAnchorType defaultValue() { + return LightAnchorType::Viewport; + } +}; + +struct LightPosition : LightProperty<Position> { + static Position defaultValue() { + std::array<float, 3> default_ = { { 1.15, 210, 30 } }; + return Position{ { default_ } }; + } +}; + +struct LightColor : LightProperty<Color> { + static Color defaultValue() { + return Color::white(); + } +}; + +struct LightIntensity : LightProperty<float> { + static float defaultValue() { + return 0.5; + } +}; + +using LightProperties = TypeList<LightAnchor, LightPosition, LightColor, LightIntensity>; +class Light : public IndexedTuple<LightProperties, LightProperties> {}; + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/position.hpp b/include/mbgl/style/position.hpp new file mode 100644 index 0000000000..3be8d1c55e --- /dev/null +++ b/include/mbgl/style/position.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include <mbgl/util/constants.hpp> + +#include <array> + +namespace mbgl { +namespace style { +class Position { +public: + Position() = default; + Position(std::array<float, 3>& position_) + : radial(position_[0]), azimuthal(position_[1]), polar(position_[2]) { + calculateCartesian(); + }; + + friend bool operator==(const Position& lhs, const Position& rhs) { + return lhs.radial == rhs.radial && lhs.azimuthal == rhs.azimuthal && lhs.polar == rhs.polar; + // TODO this doesn't address wrapping, which would be better addressed by comparing cartesian coordinates but being calculated floats are ont to be trusted. + } + + friend bool operator!=(const Position& lhs, const Position& rhs) { + return !(lhs == rhs); + } + + const std::array<float, 3> getCartesian() const { + return { { x, y, z } }; + }; + + const std::array<float, 3> getSpherical() const { + return { { radial, azimuthal, polar } }; + }; + + void set(std::array<float, 3>& position_) { + radial = position_[0]; + azimuthal = position_[1]; + polar = position_[2]; + calculateCartesian(); + }; + + // Utility function to be used only during interpolation; this leaves spherical coordinates undefined. + void setCartesian(std::array<float, 3>& position_) { + x = position_[0]; + y = position_[1]; + z = position_[2]; + } + +private: + float radial; + float azimuthal; + float polar; + float x; + float y; + float z; + + void calculateCartesian() { + // We abstract "north"/"up" (compass-wise) to be 0° when really this is 90° (π/2): we + // correct for that here + const float _a = (azimuthal + 90) * util::DEG2RAD; + const float _p = polar * util::DEG2RAD; + + x = radial * std::cos(_a) * std::sin(_p); + y = radial * std::sin(_a) * std::sin(_p); + z = radial * std::cos(_p); + }; +}; +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/types.hpp b/include/mbgl/style/types.hpp index 1f2f5c3105..e0436efb67 100644 --- a/include/mbgl/style/types.hpp +++ b/include/mbgl/style/types.hpp @@ -92,5 +92,10 @@ enum class IconTextFitType : uint8_t { Height }; +enum class LightAnchorType: bool { + Map, + Viewport +}; + } // namespace style } // namespace mbgl diff --git a/include/mbgl/util/indexed_tuple.hpp b/include/mbgl/util/indexed_tuple.hpp new file mode 100644 index 0000000000..a414639530 --- /dev/null +++ b/include/mbgl/util/indexed_tuple.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include <mbgl/util/type_list.hpp> + +#include <type_traits> +#include <tuple> + +namespace mbgl { + +template <class T, class... Ts> +struct TypeIndex; + +template <class T, class... Ts> +struct TypeIndex<T, T, Ts...> : std::integral_constant<std::size_t, 0> {}; + +template <class T, class U, class... Ts> +struct TypeIndex<T, U, Ts...> : std::integral_constant<std::size_t, 1 + TypeIndex<T, Ts...>::value> {}; + +template <class...> class IndexedTuple; + +// A tuple of Ts, where individual members can be accessed via `t.get<I>()` for I ∈ Is. +// +// See https://github.com/mapbox/cpp/blob/master/C%2B%2B%20Structural%20Metaprogramming.md +// for motivation. +// +template <class... Is, class... Ts> +class IndexedTuple<TypeList<Is...>, TypeList<Ts...>> : public std::tuple<Ts...> { +public: + static_assert(sizeof...(Is) == sizeof...(Ts), "IndexedTuple size mismatch"); + + using std::tuple<Ts...>::tuple; + + template <class I> + static constexpr std::size_t Index = TypeIndex<I, Is...>::value; + + template <class I> + auto& get() { + return std::get<Index<I>>(*this); + } + + template <class I> + const auto& get() const { + return std::get<Index<I>>(*this); + } + + template <class... Js, class... Us> + IndexedTuple<TypeList<Is..., Js...>, TypeList<Ts..., Us...>> + concat(const IndexedTuple<TypeList<Js...>, TypeList<Us...>>& other) const { + return IndexedTuple<TypeList<Is..., Js...>, TypeList<Ts..., Us...>> { + get<Is>()..., + other.template get<Js>()... + }; + } +}; + +} // namespace mbgl diff --git a/include/mbgl/util/interpolate.hpp b/include/mbgl/util/interpolate.hpp index d463ffc056..a2103f18b2 100644 --- a/include/mbgl/util/interpolate.hpp +++ b/include/mbgl/util/interpolate.hpp @@ -2,6 +2,7 @@ #include <mbgl/util/color.hpp> #include <mbgl/util/range.hpp> +#include <mbgl/style/position.hpp> #include <array> #include <vector> @@ -47,6 +48,17 @@ public: }; template <> +struct Interpolator<style::Position> { +public: + style::Position operator()(const style::Position& a, const style::Position& b, const double t) { + auto pos = style::Position(); + auto interpolated = interpolate(a.getCartesian(), b.getCartesian(), t); + pos.setCartesian(interpolated); + return { pos }; + } +}; + +template <> struct Interpolator<Color> { public: Color operator()(const Color& a, const Color& b, const double t) { diff --git a/include/mbgl/util/type_list.hpp b/include/mbgl/util/type_list.hpp new file mode 100644 index 0000000000..4a5e95c8a4 --- /dev/null +++ b/include/mbgl/util/type_list.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include <type_traits> +#include <tuple> + +namespace mbgl { + +template <class...> +class TypeList {}; + +namespace detail { + +template <class, class> +struct TypeCons; + +template <class T, class... Ts> +struct TypeCons<T, TypeList<Ts...>> { + using Type = TypeList<T, Ts...>; +}; + +template <class, template <class> class> +struct TypeFilter; + +template <template <class> class Predicate> +struct TypeFilter<TypeList<>, Predicate> { + using Type = TypeList<>; +}; + +template <template <class> class Predicate, class T, class... Ts> +struct TypeFilter<TypeList<T, Ts...>, Predicate> { + using Tail = typename TypeFilter<TypeList<Ts...>, Predicate>::Type; + using Type = std::conditional_t<Predicate<T>::value, typename TypeCons<T, Tail>::Type, Tail>; +}; + +} // namespace detail + +template <class TypeList, template <class> class Predicate> +using FilteredTypeList = typename detail::TypeFilter<TypeList, Predicate>::Type; + +} // namespace mbgl |