diff options
Diffstat (limited to 'platform')
23 files changed, 781 insertions, 658 deletions
diff --git a/platform/android/build.gradle b/platform/android/build.gradle index e298b84da8..ec23fde819 100644 --- a/platform/android/build.gradle +++ b/platform/android/build.gradle @@ -3,7 +3,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.1' + classpath 'com.android.tools.build:gradle:2.3.3' classpath 'com.amazonaws:aws-devicefarm-gradle-plugin:1.2' classpath 'com.stanfy.spoon:spoon-gradle-plugin:1.2.1' } diff --git a/platform/android/config.cmake b/platform/android/config.cmake index 8dd537d36e..da752e4cb8 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -146,7 +146,7 @@ add_library(mbgl-android STATIC # Style conversion Java -> C++ platform/android/src/style/android_conversion.hpp - platform/android/src/style/conversion/geojson.hpp + platform/android/src/style/android_conversion.cpp platform/android/src/style/value.cpp platform/android/src/style/value.hpp platform/android/src/style/conversion/url_or_tileset.hpp diff --git a/platform/android/src/style/android_conversion.cpp b/platform/android/src/style/android_conversion.cpp new file mode 100644 index 0000000000..43940c2acd --- /dev/null +++ b/platform/android/src/style/android_conversion.cpp @@ -0,0 +1,106 @@ +#include "android_conversion.hpp" +#include <mbgl/style/conversion/geojson.hpp> + + +namespace mbgl { +namespace style { +namespace conversion { + +using AndroidValue = mbgl::android::Value; + +template<> bool ValueTraits<AndroidValue>::isUndefined(const AndroidValue& value) { + return value.isNull(); +} + +template<> bool ValueTraits<AndroidValue>::isArray(const AndroidValue& value) { + return value.isArray(); +} + +template<> bool ValueTraits<AndroidValue>::isObject(const AndroidValue& value) { + return value.isObject(); +} + +template<> std::size_t ValueTraits<AndroidValue>::arrayLength(const AndroidValue& value) { + return value.getLength();; +} + +template<> AndroidValue ValueTraits<AndroidValue>::arrayMember(const AndroidValue& value, std::size_t i) { + return value.get(i); +} + +template<> optional<AndroidValue> ValueTraits<AndroidValue>::objectMember(const AndroidValue& value, const char* key) { + AndroidValue member = value.get(key); + + if (!member.isNull()) { + return member; + } else { + return {}; + } +} + +template<> optional<Error> ValueTraits<AndroidValue>::eachMember(const AndroidValue&, const std::function<optional<Error> (const std::string&, const AndroidValue&)>&) { + // TODO + mbgl::Log::Warning(mbgl::Event::Android, "eachMember not implemented"); + return {}; +} + +template<> optional<bool> ValueTraits<AndroidValue>::toBool(const AndroidValue& value) { + if (value.isBool()) { + return value.toBool(); + } else { + return {}; + } +} + +template<> optional<float> ValueTraits<AndroidValue>::toNumber(const AndroidValue& value) { + if (value.isNumber()) { + auto num = value.toFloat(); + return num; + } else { + return {}; + } +} + +template<> optional<double> ValueTraits<AndroidValue>::toDouble(const AndroidValue& value) { + if (value.isNumber()) { + return value.toDouble(); + } else { + return {}; + } +} + +template<> optional<std::string> ValueTraits<AndroidValue>::toString(const AndroidValue& value) { + if (value.isString()) { + return value.toString(); + } else { + return {}; + } +} + +template<> optional<mbgl::Value> ValueTraits<AndroidValue>::toValue(const AndroidValue& value) { + if (value.isNull()) { + return {}; + } else if (value.isBool()) { + return { value.toBool() }; + } else if (value.isString()) { + return { value.toString() }; + } else if (value.isNumber()) { + auto doubleVal = value.toDouble(); + return { doubleVal - (int) doubleVal > 0.0 ? doubleVal : value.toLong() }; + } else { + return {}; + } +} + +template<> optional<GeoJSON> ValueTraits<AndroidValue>::toGeoJSON(const AndroidValue &value, Error &error) { + if(value.isNull() || !value.isString()) { + error = { "no json data found" }; + return {}; + } + + return parseGeoJSON(value.toString(), error); +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp index 082fe411e2..3969553816 100644 --- a/platform/android/src/style/android_conversion.hpp +++ b/platform/android/src/style/android_conversion.hpp @@ -13,89 +13,9 @@ namespace mbgl { namespace style { namespace conversion { -inline bool isUndefined(const mbgl::android::Value& value) { - return value.isNull(); -} - -inline bool isArray(const mbgl::android::Value& value) { - return value.isArray(); -} - -inline bool isObject(const mbgl::android::Value& value) { - return value.isObject(); -} - -inline std::size_t arrayLength(const mbgl::android::Value& value) { - return value.getLength();; -} - -inline mbgl::android::Value arrayMember(const mbgl::android::Value& value, std::size_t i) { - return value.get(i); -} - -inline optional<mbgl::android::Value> objectMember(const mbgl::android::Value& value, const char* key) { - mbgl::android::Value member = value.get(key); - - if (!member.isNull()) { - return member; - } else { - return {}; - } -} - -template <class Fn> -optional<Error> eachMember(const mbgl::android::Value&, Fn&&) { - // TODO - mbgl::Log::Warning(mbgl::Event::Android, "eachMember not implemented"); - return {}; -} - -inline optional<bool> toBool(const mbgl::android::Value& value) { - if (value.isBool()) { - return value.toBool(); - } else { - return {}; - } -} - -inline optional<float> toNumber(const mbgl::android::Value& value) { - if (value.isNumber()) { - auto num = value.toFloat(); - return num; - } else { - return {}; - } -} - -inline optional<double> toDouble(const mbgl::android::Value& value) { - if (value.isNumber()) { - return value.toDouble(); - } else { - return {}; - } -} - -inline optional<std::string> toString(const mbgl::android::Value& value) { - if (value.isString()) { - return value.toString(); - } else { - return {}; - } -} - -inline optional<Value> toValue(const mbgl::android::Value& value) { - if (value.isNull()) { - return {}; - } else if (value.isBool()) { - return { value.toBool() }; - } else if (value.isString()) { - return { value.toString() }; - } else if (value.isNumber()) { - auto doubleVal = value.toDouble(); - return { doubleVal - (int) doubleVal > 0.0 ? doubleVal : value.toLong() }; - } else { - return {}; - } +template <class T, class...Args> +optional<T> convert(const mbgl::android::Value& value, Error& error, Args&&...args) { + return convert<T>(Value(value), error, std::forward<Args>(args)...); } } // namespace conversion diff --git a/platform/android/src/style/conversion/geojson.hpp b/platform/android/src/style/conversion/geojson.hpp deleted file mode 100644 index 748fe7361e..0000000000 --- a/platform/android/src/style/conversion/geojson.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include <mapbox/geojson.hpp> -#include <mbgl/style/conversion.hpp> -#include <mbgl/style/conversion/geojson.hpp> -#include <jni/jni.hpp> - -namespace mbgl { -namespace style { -namespace conversion { - -template <> -optional<GeoJSON> Converter<GeoJSON>::operator()(const mbgl::android::Value& value, Error& error) const { - if(value.isNull() || !value.isString()) { - error = { "no json data found" }; - return {}; - } - - return convert<GeoJSON>(value.toString(), error); -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/platform/android/src/style/conversion/url_or_tileset.hpp b/platform/android/src/style/conversion/url_or_tileset.hpp index 00ef913d41..dae1209697 100644 --- a/platform/android/src/style/conversion/url_or_tileset.hpp +++ b/platform/android/src/style/conversion/url_or_tileset.hpp @@ -17,18 +17,19 @@ namespace android { // This conversion is expected not to fail because it's used only in contexts where // the value was originally a String or TileSet object on the Java side. If it fails // to convert, it's a bug in our serialization or Java-side static typing. -inline variant<std::string, Tileset> convertURLOrTileset(const Value& value) { +inline variant<std::string, Tileset> convertURLOrTileset(const mbgl::android::Value& value) { using namespace mbgl::style::conversion; - if (isObject(value)) { + const mbgl::style::conversion::Value converted(value); + if (isObject(converted)) { Error error; - optional<Tileset> tileset = convert<Tileset>(value, error); + optional<Tileset> tileset = convert<Tileset>(converted, error); if (!tileset) { throw std::logic_error(error.message); } return { *tileset }; } else { - return { *toString(value) }; + return { *toString(converted) }; } } diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp index 02a1f0be82..54d896ec7c 100644 --- a/platform/android/src/style/layers/layer.cpp +++ b/platform/android/src/style/layers/layer.cpp @@ -4,11 +4,20 @@ #include <jni/jni.hpp> #include <mbgl/style/style.hpp> +#include <mbgl/style/filter.hpp> #include <mbgl/style/transition_options.hpp> +#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> #include <mbgl/util/logging.hpp> // Java -> C++ conversion #include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/filter.hpp> #include <mbgl/style/conversion/layer.hpp> #include <mbgl/style/conversion/source.hpp> diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp index 90ef851eba..4468b453f3 100644 --- a/platform/android/src/style/sources/geojson_source.cpp +++ b/platform/android/src/style/sources/geojson_source.cpp @@ -5,15 +5,15 @@ // Java -> C++ conversion #include "../android_conversion.hpp" #include "../conversion/filter.hpp" -#include "../conversion/geojson.hpp" +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/geojson.hpp> +#include <mbgl/style/conversion/geojson_options.hpp> // C++ -> Java conversion #include "../../conversion/conversion.hpp" #include "../../conversion/collection.hpp" #include "../../geojson/conversion/feature.hpp" #include "../conversion/url_or_tileset.hpp" -#include <mbgl/style/conversion.hpp> -#include <mbgl/style/conversion/geojson_options.hpp> #include <string> @@ -29,7 +29,7 @@ namespace android { return style::GeoJSONOptions(); } Error error; - optional<style::GeoJSONOptions> result = convert<style::GeoJSONOptions>(Value(env, options), error); + optional<style::GeoJSONOptions> result = convert<style::GeoJSONOptions>(mbgl::android::Value(env, options), error); if (!result) { throw std::logic_error(error.message); } @@ -54,7 +54,7 @@ namespace android { // Convert the jni object Error error; - optional<GeoJSON> converted = convert<GeoJSON>(Value(env, json), error); + optional<GeoJSON> converted = convert<GeoJSON>(mbgl::android::Value(env, json), error); if(!converted) { mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + error.message); return; diff --git a/platform/darwin/src/MGLConversion.h b/platform/darwin/src/MGLConversion.h index d6363b28eb..a354c28cd9 100644 --- a/platform/darwin/src/MGLConversion.h +++ b/platform/darwin/src/MGLConversion.h @@ -1,9 +1,4 @@ -#import <Foundation/Foundation.h> - -#include <mbgl/util/logging.hpp> #include <mbgl/style/conversion.hpp> -#include <mbgl/util/feature.hpp> -#include <mbgl/util/optional.hpp> NS_ASSUME_NONNULL_BEGIN @@ -11,133 +6,10 @@ namespace mbgl { namespace style { namespace conversion { -/** - A minimal wrapper class conforming to the requirements for `objectMember(v, name)` (see mbgl/style/conversion.hpp) - This is necessary because using `NSObject*` as the value type in `optional<NSObject*>` causes problems for the ARC, - due to things like `optional(const value_type& __v)` - */ -class OptionalNSObjectValue { -public: - OptionalNSObjectValue(NSObject * _Nullable _value) : value(_value) {} - - explicit operator bool() const { - return value; - } - - NSObject * _Nullable operator*() { - NSCAssert(this, @"Expected non-null value."); - return value; - } -private: - NSObject * _Nullable value; -}; - -inline bool isUndefined(const id value) { - return !value || value == [NSNull null]; -} - -inline bool isArray(const id value) { - return [value isKindOfClass:[NSArray class]]; -} - -inline bool isObject(const id value) { - return [value isKindOfClass:[NSDictionary class]]; -} - -inline std::size_t arrayLength(const id value) { - NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for getLength()."); - NSArray *array = value; - auto length = [array count]; - NSCAssert(length <= std::numeric_limits<size_t>::max(), @"Array length out of bounds."); - return length; -} - -inline NSObject *arrayMember(const id value, std::size_t i) { - NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for get(int)."); - NSCAssert(i < NSUIntegerMax, @"Index must be less than NSUIntegerMax"); - return [value objectAtIndex: i]; -} - -inline OptionalNSObjectValue objectMember(const id value, const char *key) { - NSCAssert([value isKindOfClass:[NSDictionary class]], @"Value must be an NSDictionary for get(string)."); - NSObject *member = [value objectForKey: @(key)]; - if (member && member != [NSNull null]) { - return { member }; - } else { - return { nullptr }; - } -} - -// Not implemented (unneeded for MGLStyleFunction conversion): -// optional<Error> eachMember(const NSObject*, Fn&&) - -inline bool _isBool(const id value) { - if (![value isKindOfClass:[NSNumber class]]) return false; - // char: 32-bit boolean - // BOOL: 64-bit boolean - NSNumber *number = value; - return ((strcmp([number objCType], @encode(char)) == 0) || - (strcmp([number objCType], @encode(BOOL)) == 0)); -} - -inline bool _isNumber(const id value) { - return [value isKindOfClass:[NSNumber class]] && !_isBool(value); -} - -inline bool _isString(const id value) { - return [value isKindOfClass:[NSString class]]; -} - -inline optional<bool> toBool(const id value) { - if (_isBool(value)) { - return ((NSNumber *)value).boolValue; - } else { - return {}; - } -} - -inline optional<float> toNumber(const id value) { - if (_isNumber(value)) { - return ((NSNumber *)value).floatValue; - } else { - return {}; - } -} - -inline optional<double> toDouble(const id value) { - if (_isNumber(value)) { - return ((NSNumber *)value).doubleValue; - } else { - return {}; - } -} - -inline optional<std::string> toString(const id value) { - if (_isString(value)) { - return std::string(static_cast<const char *>([value UTF8String])); - } else { - return {}; - } -} - -inline optional<mbgl::Value> toValue(const id value) { - if (isUndefined(value)) { - return {}; - } else if (_isBool(value)) { - return { *toBool(value) }; - } else if ( _isString(value)) { - return { *toString(value) }; - } else if (_isNumber(value)) { - // Need to cast to a double here as the float is otherwise considered a bool... - return { static_cast<double>(*toNumber(value)) }; - } else { - return {}; - } -} +Value makeValue(const id value); } // namespace conversion } // namespace style } // namespace mbgl NS_ASSUME_NONNULL_END - diff --git a/platform/darwin/src/MGLConversion.mm b/platform/darwin/src/MGLConversion.mm new file mode 100644 index 0000000000..f508039227 --- /dev/null +++ b/platform/darwin/src/MGLConversion.mm @@ -0,0 +1,151 @@ +#import <Foundation/Foundation.h> + +#include "MGLConversion.h" + +NS_ASSUME_NONNULL_BEGIN + +namespace mbgl { +namespace style { +namespace conversion { + +class Holder { +public: + Holder(const id v) : value(v) {} + const id value; +}; + +using MGLValue = Holder; + +template<> bool ValueTraits<MGLValue>::isUndefined(const MGLValue& holder) { + const id value = holder.value; + return !value || value == [NSNull null]; +} + +template<> bool ValueTraits<MGLValue>::isArray(const MGLValue& holder) { + const id value = holder.value; + return [value isKindOfClass:[NSArray class]]; +} + +template<> bool ValueTraits<MGLValue>::isObject(const MGLValue& holder) { + const id value = holder.value; + return [value isKindOfClass:[NSDictionary class]]; +} + +template<> std::size_t ValueTraits<MGLValue>::arrayLength(const MGLValue& holder) { + const id value = holder.value; + NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for getLength()."); + NSArray *array = value; + auto length = [array count]; + NSCAssert(length <= std::numeric_limits<size_t>::max(), @"Array length out of bounds."); + return length; +} + +template<> MGLValue ValueTraits<MGLValue>::arrayMember(const MGLValue& holder, std::size_t i) { + const id value = holder.value; + NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for get(int)."); + NSCAssert(i < NSUIntegerMax, @"Index must be less than NSUIntegerMax"); + return {[value objectAtIndex: i]}; +} + +template<> optional<MGLValue> ValueTraits<MGLValue>::objectMember(const MGLValue& holder, const char *key) { + const id value = holder.value; + NSCAssert([value isKindOfClass:[NSDictionary class]], @"Value must be an NSDictionary for get(string)."); + NSObject *member = [value objectForKey: @(key)]; + if (member && member != [NSNull null]) { + return {member}; + } else { + return {}; + } +} + +template<> optional<Error> ValueTraits<MGLValue>::eachMember(const MGLValue& holder, const std::function<optional<Error> (const std::string&, const MGLValue&)>& fn) { + // Not implemented (unneeded for MGLStyleFunction conversion). + NSCAssert(NO, @"eachMember not implemented"); + return {}; +} + +inline bool _isBool(const id value) { + if (![value isKindOfClass:[NSNumber class]]) return false; + // char: 32-bit boolean + // BOOL: 64-bit boolean + NSNumber *number = value; + return ((strcmp([number objCType], @encode(char)) == 0) || + (strcmp([number objCType], @encode(BOOL)) == 0)); +} + +inline bool _isNumber(const id value) { + return [value isKindOfClass:[NSNumber class]] && !_isBool(value); +} + +inline bool _isString(const id value) { + return [value isKindOfClass:[NSString class]]; +} + +template<> optional<bool> ValueTraits<MGLValue>::toBool(const MGLValue& holder) { + const id value = holder.value; + if (_isBool(value)) { + return ((NSNumber *)value).boolValue; + } else { + return {}; + } +} + +template<> optional<float> ValueTraits<MGLValue>::toNumber(const MGLValue& holder) { + const id value = holder.value; + if (_isNumber(value)) { + return ((NSNumber *)value).floatValue; + } else { + return {}; + } +} + +template<> optional<double> ValueTraits<MGLValue>::toDouble(const MGLValue& holder) { + const id value = holder.value; + if (_isNumber(value)) { + return ((NSNumber *)value).doubleValue; + } else { + return {}; + } +} + +template<> optional<std::string> ValueTraits<MGLValue>::toString(const MGLValue& holder) { + const id value = holder.value; + if (_isString(value)) { + return std::string(static_cast<const char *>([value UTF8String])); + } else { + return {}; + } +} + +template<> optional<mbgl::Value> ValueTraits<MGLValue>::toValue(const MGLValue& holder) { + const id value = holder.value; + if (isUndefined(value)) { + return {}; + } else if (_isBool(value)) { + return { *toBool(holder) }; + } else if ( _isString(value)) { + return { *toString(holder) }; + } else if (_isNumber(value)) { + // Need to cast to a double here as the float is otherwise considered a bool... + return { static_cast<double>(*toNumber(holder)) }; + } else { + return {}; + } +} + +template<> optional<GeoJSON> ValueTraits<MGLValue>::toGeoJSON(const MGLValue& holder, Error& error) { + error = { "toGeoJSON not implemented" }; + return {}; +} + +Value makeValue(const id value) { + return {Holder(value)}; +} + + +} // namespace conversion +} // namespace style +} // namespace mbgl + +NS_ASSUME_NONNULL_END + diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h index 2155c657bd..a6da6017d4 100644 --- a/platform/darwin/src/MGLStyleValue_Private.h +++ b/platform/darwin/src/MGLStyleValue_Private.h @@ -124,9 +124,9 @@ public: if ([value isKindOfClass:[MGLConstantStyleValue class]]) { return toMBGLConstantValue((MGLConstantStyleValue<ObjCType> *)value); } else if ([value isKindOfClass:[MGLStyleFunction class]]) { - auto rawValue = toRawStyleSpecValue((MGLStyleFunction<ObjCType> *) value); mbgl::style::conversion::Error error; - auto result = mbgl::style::conversion::convert<mbgl::style::DataDrivenPropertyValue<MBGLType>>(rawValue, error); + auto result = mbgl::style::conversion::convert<mbgl::style::DataDrivenPropertyValue<MBGLType>>( + mbgl::style::conversion::makeValue(toRawStyleSpecValue((MGLStyleFunction<ObjCType> *) value)), error); NSCAssert(result, @(error.message.c_str())); return *result; } else { diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index a3ccc9337b..63fc76b2df 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -14,6 +14,8 @@ 071BBB071EE77631001FB02A /* MGLImageSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */; }; 1753ED421E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; }; 1753ED431E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; }; + 17DBEF831F95066000E60A6B /* MGLConversion.mm in Sources */ = {isa = PBXBuildFile; fileRef = 17DBEF821F95066000E60A6B /* MGLConversion.mm */; }; + 17DBEF841F95066000E60A6B /* MGLConversion.mm in Sources */ = {isa = PBXBuildFile; fileRef = 17DBEF821F95066000E60A6B /* MGLConversion.mm */; }; 1F06668A1EC64F8E001C16D7 /* MGLLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F0666881EC64F8E001C16D7 /* MGLLight.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F06668D1EC64F8E001C16D7 /* MGLLight.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F0666891EC64F8E001C16D7 /* MGLLight.mm */; }; 1F7454921ECBB42C00021D39 /* MGLLight.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F0666891EC64F8E001C16D7 /* MGLLight.mm */; }; @@ -572,6 +574,7 @@ 071BBAFD1EE75CD4001FB02A /* MGLImageSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLImageSource.mm; sourceTree = "<group>"; }; 071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLImageSourceTests.m; path = ../../darwin/test/MGLImageSourceTests.m; sourceTree = "<group>"; }; 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = "<group>"; }; + 17DBEF821F95066000E60A6B /* MGLConversion.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLConversion.mm; sourceTree = "<group>"; }; 1F0666881EC64F8E001C16D7 /* MGLLight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight.h; sourceTree = "<group>"; }; 1F0666891EC64F8E001C16D7 /* MGLLight.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLight.mm; sourceTree = "<group>"; }; 1F7454941ECD450D00021D39 /* MGLLight_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight_Private.h; sourceTree = "<group>"; }; @@ -1094,6 +1097,7 @@ 35599DA21D4682B60048254D /* Styling */ = { isa = PBXGroup; children = ( + 17DBEF821F95066000E60A6B /* MGLConversion.mm */, 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */, 35599DB81D46AD7F0048254D /* Categories */, 353933F01D3FB6BA003F57D7 /* Layers */, @@ -2324,6 +2328,7 @@ DA8848501CBAFB9800AB86E3 /* MGLAnnotationImage.m in Sources */, DA8848281CBAFA6200AB86E3 /* MGLShape.mm in Sources */, DA35A2B31CCA141D00E826B2 /* MGLCompassDirectionFormatter.m in Sources */, + 17DBEF831F95066000E60A6B /* MGLConversion.mm in Sources */, DD0902A91DB1929D00C5BDCE /* MGLNetworkConfiguration.m in Sources */, 35D13AB91D3D15E300AFB4E0 /* MGLStyleLayer.mm in Sources */, DA35A2CB1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */, @@ -2411,6 +2416,7 @@ DAA4E41F1CBB730400178DFB /* MGLMultiPoint.mm in Sources */, DD0902AA1DB1929D00C5BDCE /* MGLNetworkConfiguration.m in Sources */, DA35A2B41CCA141D00E826B2 /* MGLCompassDirectionFormatter.m in Sources */, + 17DBEF841F95066000E60A6B /* MGLConversion.mm in Sources */, 35D13ABA1D3D15E300AFB4E0 /* MGLStyleLayer.mm in Sources */, 071BBAFF1EE7613E001FB02A /* MGLImageSource.mm in Sources */, DA35A2CC1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */, diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj index 34f8860686..6f99382b02 100644 --- a/platform/macos/macos.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -73,6 +73,7 @@ 40B77E451DB11BC9003DA2FE /* NSArray+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 40B77E431DB11BB0003DA2FE /* NSArray+MGLAdditions.h */; }; 40B77E461DB11BCD003DA2FE /* NSArray+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 40B77E421DB11BB0003DA2FE /* NSArray+MGLAdditions.mm */; }; 40E1601D1DF217D6005EA6D9 /* MGLStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 40E1601B1DF216E6005EA6D9 /* MGLStyleLayerTests.m */; }; + 5241C2BE1F7AFFAF00DDB20E /* MGLConversion.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5241C2BD1F7AFFAF00DDB20E /* MGLConversion.mm */; }; 52B5D17F1E5E26DF00BBCB48 /* libmbgl-loop-darwin.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */; }; 52B5D1801E5E26DF00BBCB48 /* libmbgl-loop-darwin.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */; }; 5548BE781D09E718005DDE81 /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */; }; @@ -349,6 +350,7 @@ 40B77E431DB11BB0003DA2FE /* NSArray+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+MGLAdditions.h"; sourceTree = "<group>"; }; 40E1601A1DF216E6005EA6D9 /* MGLStyleLayerTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyleLayerTests.h; sourceTree = "<group>"; }; 40E1601B1DF216E6005EA6D9 /* MGLStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLStyleLayerTests.m; sourceTree = "<group>"; }; + 5241C2BD1F7AFFAF00DDB20E /* MGLConversion.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLConversion.mm; sourceTree = "<group>"; }; 52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-loop-darwin.a"; path = "cmake/Debug/libmbgl-loop-darwin.a"; sourceTree = "<group>"; }; 556660C51E1BEA0100E2C41B /* MGLFoundation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLFoundation.h; sourceTree = "<group>"; }; @@ -698,6 +700,7 @@ isa = PBXGroup; children = ( 1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */, + 5241C2BD1F7AFFAF00DDB20E /* MGLConversion.mm */, 352742791D4C235C00A1ECE6 /* Categories */, 35136D471D42295400C20EFD /* Layers */, 3527427E1D4C242B00A1ECE6 /* Sources */, @@ -727,6 +730,14 @@ name = "Test Helpers"; sourceTree = "<group>"; }; + 5241C2BA1F7AF16100DDB20E /* Recovered References */ = { + isa = PBXGroup; + children = ( + 30E578141DAA7D920050F07E /* NSImage+MGLAdditions.h */, + ); + name = "Recovered References"; + sourceTree = "<group>"; + }; DA839E891CC2E3400062CAFB = { isa = PBXGroup; children = ( @@ -736,6 +747,7 @@ DAE6C31E1CC308BC00DB3429 /* Frameworks */, DAE6C3C41CC31F7800DB3429 /* Configuration */, DA839E931CC2E3400062CAFB /* Products */, + 5241C2BA1F7AF16100DDB20E /* Recovered References */, ); sourceTree = "<group>"; }; @@ -1433,6 +1445,7 @@ 1FCDF1431F2A4F3600A46694 /* MGLVectorSource+MGLAdditions.m in Sources */, DD0902B21DB1AC6400C5BDCE /* MGLNetworkConfiguration.m in Sources */, 1F7454A51ECFB00300021D39 /* MGLLight.mm in Sources */, + 5241C2BE1F7AFFAF00DDB20E /* MGLConversion.mm in Sources */, DAE6C3B11CC31EF300DB3429 /* MGLAnnotationImage.m in Sources */, 3508EC651D749D39009B0EE4 /* NSExpression+MGLAdditions.mm in Sources */, DACC22151CF3D3E200D220D9 /* MGLFeature.mm in Sources */, diff --git a/platform/node/src/node_conversion.cpp b/platform/node/src/node_conversion.cpp new file mode 100644 index 0000000000..ed082615d0 --- /dev/null +++ b/platform/node/src/node_conversion.cpp @@ -0,0 +1,137 @@ +#include "node_conversion.hpp" +#include <mbgl/style/conversion/geojson.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +template<> bool ValueTraits<v8::Local<v8::Value>>::isUndefined(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + + return value->IsUndefined() || value->IsNull(); +} + +template<> bool ValueTraits<v8::Local<v8::Value>>::isArray(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + + return value->IsArray(); +} + +template<> std::size_t ValueTraits<v8::Local<v8::Value>>::arrayLength(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + // const_cast because v8::Local<T>::As is not marked const until node v8.0 + v8::Local<v8::Array> array = const_cast<v8::Local<v8::Value>&>(value).As<v8::Array>(); + return array->Length(); +} + +template<> v8::Local<v8::Value> ValueTraits<v8::Local<v8::Value>>::arrayMember(const v8::Local<v8::Value>& value, std::size_t i) { + Nan::EscapableHandleScope scope; + // const_cast because v8::Local<T>::As is not marked const until node v8.0 + v8::Local<v8::Array> array = const_cast<v8::Local<v8::Value>&>(value).As<v8::Array>(); + return scope.Escape(Nan::Get(array, i).ToLocalChecked()); +} + +template<> bool ValueTraits<v8::Local<v8::Value>>::isObject(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + + return value->IsObject() && !value->IsArray(); +} + +template<> optional<v8::Local<v8::Value>> ValueTraits<v8::Local<v8::Value>>::objectMember(const v8::Local<v8::Value>& value, const char * name) { + Nan::EscapableHandleScope scope; + + if (!Nan::Has(Nan::To<v8::Object>(value).ToLocalChecked(), Nan::New(name).ToLocalChecked()).FromJust()) { + return {}; + } + Nan::MaybeLocal<v8::Value> result = Nan::Get(Nan::To<v8::Object>(value).ToLocalChecked(), Nan::New(name).ToLocalChecked()); + if (result.IsEmpty()) { + return {}; + } + return {scope.Escape(result.ToLocalChecked())}; +} + +template<> optional<Error> ValueTraits<v8::Local<v8::Value>>::eachMember(const v8::Local<v8::Value>& value, const std::function<optional<Error> (const std::string&, const v8::Local<v8::Value>&)>& fn) { + Nan::HandleScope scope; + + v8::Local<v8::Array> names = Nan::GetOwnPropertyNames(Nan::To<v8::Object>(value).ToLocalChecked()).ToLocalChecked(); + for (uint32_t i = 0; i < names->Length(); ++i) { + v8::Local<v8::Value> k = Nan::Get(names, i).ToLocalChecked(); + v8::Local<v8::Value> v = Nan::Get(Nan::To<v8::Object>(value).ToLocalChecked(), k).ToLocalChecked(); + optional<Error> result = fn(*Nan::Utf8String(k), v); + if (result) { + return result; + } + } + return {}; +} + +template<> optional<bool> ValueTraits<v8::Local<v8::Value>>::toBool(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + + if (!value->IsBoolean()) { + return {}; + } + return value->BooleanValue(); +} + +template<> optional<float> ValueTraits<v8::Local<v8::Value>>::toNumber(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + + if (!value->IsNumber()) { + return {}; + } + return value->NumberValue(); +} + +template<> optional<double> ValueTraits<v8::Local<v8::Value>>::toDouble(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + + if (!value->IsNumber()) { + return {}; + } + return value->NumberValue(); +} + +template<> optional<std::string> ValueTraits<v8::Local<v8::Value>>::toString(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + + if (!value->IsString()) { + return {}; + } + return std::string(*Nan::Utf8String(value)); +} + +template<> optional<mbgl::Value> ValueTraits<v8::Local<v8::Value>>::toValue(const v8::Local<v8::Value>& value) { + + if (value->IsFalse()) { + return { false }; + } else if (value->IsTrue()) { + return { true }; + } else if (value->IsString()) { + return { std::string(*Nan::Utf8String(value)) }; + } else if (value->IsUint32()) { + return { std::uint64_t(value->Uint32Value()) }; + } else if (value->IsInt32()) { + return { std::int64_t(value->Int32Value()) }; + } else if (value->IsNumber()) { + return { value->NumberValue() }; + } else { + return {}; + } +} + +template<> optional<GeoJSON> ValueTraits<v8::Local<v8::Value>>::toGeoJSON(const v8::Local<v8::Value>& value, Error& error) { + try { + Nan::JSON JSON; + + std::string string = *Nan::Utf8String(JSON.Stringify(value->ToObject()).ToLocalChecked()); + return parseGeoJSON(string, error); + } catch (const std::exception& ex) { + error = { ex.what() }; + return {}; + } +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/platform/node/src/node_conversion.hpp b/platform/node/src/node_conversion.hpp index d266745548..7f0a7ed39e 100644 --- a/platform/node/src/node_conversion.hpp +++ b/platform/node/src/node_conversion.hpp @@ -14,107 +14,11 @@ namespace mbgl { namespace style { namespace conversion { -inline bool isUndefined(v8::Local<v8::Value> value) { - Nan::HandleScope scope; - return value->IsUndefined() || value->IsNull(); +template <class T, class...Args> +optional<T> convert(const v8::Local<v8::Value>& value, Error& error, Args&&...args) { + return convert<T>(Value(value), error, std::forward<Args>(args)...); } -inline bool isArray(v8::Local<v8::Value> value) { - Nan::HandleScope scope; - return value->IsArray(); -} - -inline std::size_t arrayLength(v8::Local<v8::Value> value) { - Nan::HandleScope scope; - return value.As<v8::Array>()->Length(); -} - -inline v8::Local<v8::Value> arrayMember(v8::Local<v8::Value> value, std::size_t i) { - Nan::EscapableHandleScope scope; - return scope.Escape(Nan::Get(value.As<v8::Array>(), i).ToLocalChecked()); -} - -inline bool isObject(v8::Local<v8::Value> value) { - Nan::HandleScope scope; - return value->IsObject() && !value->IsArray(); -} - -inline optional<v8::Local<v8::Value>> objectMember(v8::Local<v8::Value> value, const char * name) { - Nan::EscapableHandleScope scope; - if (!Nan::Has(Nan::To<v8::Object>(value).ToLocalChecked(), Nan::New(name).ToLocalChecked()).FromJust()) { - return {}; - } - Nan::MaybeLocal<v8::Value> result = Nan::Get(Nan::To<v8::Object>(value).ToLocalChecked(), Nan::New(name).ToLocalChecked()); - if (result.IsEmpty()) { - return {}; - } - return scope.Escape(result.ToLocalChecked()); -} - -template <class Fn> -optional<Error> eachMember(v8::Local<v8::Value> value, Fn&& fn) { - Nan::HandleScope scope; - v8::Local<v8::Array> names = Nan::GetOwnPropertyNames(Nan::To<v8::Object>(value).ToLocalChecked()).ToLocalChecked(); - for (uint32_t i = 0; i < names->Length(); ++i) { - v8::Local<v8::Value> k = Nan::Get(names, i).ToLocalChecked(); - v8::Local<v8::Value> v = Nan::Get(Nan::To<v8::Object>(value).ToLocalChecked(), k).ToLocalChecked(); - optional<Error> result = fn(*Nan::Utf8String(k), v); - if (result) { - return result; - } - } - return {}; -} - -inline optional<bool> toBool(v8::Local<v8::Value> value) { - Nan::HandleScope scope; - if (!value->IsBoolean()) { - return {}; - } - return value->BooleanValue(); -} - -inline optional<float> toNumber(v8::Local<v8::Value> value) { - Nan::HandleScope scope; - if (!value->IsNumber()) { - return {}; - } - return value->NumberValue(); -} - -inline optional<double> toDouble(v8::Local<v8::Value> value) { - Nan::HandleScope scope; - if (!value->IsNumber()) { - return {}; - } - return value->NumberValue(); -} - -inline optional<std::string> toString(v8::Local<v8::Value> value) { - Nan::HandleScope scope; - if (!value->IsString()) { - return {}; - } - return std::string(*Nan::Utf8String(value)); -} - -inline optional<Value> toValue(v8::Local<v8::Value> value) { - if (value->IsFalse()) { - return { false }; - } else if (value->IsTrue()) { - return { true }; - } else if (value->IsString()) { - return { std::string(*Nan::Utf8String(value)) }; - } else if (value->IsUint32()) { - return { std::uint64_t(value->Uint32Value()) }; - } else if (value->IsInt32()) { - return { std::int64_t(value->Int32Value()) }; - } else if (value->IsNumber()) { - return { value->NumberValue() }; - } else { - return {}; - } -} } // namespace conversion } // namespace style diff --git a/platform/node/src/node_geojson.hpp b/platform/node/src/node_geojson.hpp deleted file mode 100644 index 8a3927e2cf..0000000000 --- a/platform/node/src/node_geojson.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#include <mbgl/style/conversion/geojson.hpp> - -#include <string> -namespace mbgl { -namespace style { -namespace conversion { - -template <> -optional<GeoJSON> Converter<GeoJSON>::operator()(const v8::Local<v8::Value>& value, Error& error) const { - Nan::JSON JSON; - std::string string = *Nan::Utf8String(JSON.Stringify(value->ToObject()).ToLocalChecked()); - return convert<GeoJSON>(string, error); -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp index da359f251c..bd5ba7b152 100644 --- a/platform/node/src/node_map.cpp +++ b/platform/node/src/node_map.cpp @@ -2,7 +2,6 @@ #include "node_request.hpp" #include "node_feature.hpp" #include "node_conversion.hpp" -#include "node_geojson.hpp" #include <mbgl/util/exception.hpp> #include <mbgl/renderer/renderer.hpp> @@ -10,6 +9,15 @@ #include <mbgl/style/conversion/source.hpp> #include <mbgl/style/conversion/layer.hpp> #include <mbgl/style/conversion/filter.hpp> + +#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> + #include <mbgl/style/style.hpp> #include <mbgl/style/image.hpp> #include <mbgl/map/map_observer.hpp> @@ -740,7 +748,7 @@ void NodeMap::SetLayoutProperty(const Nan::FunctionCallbackInfo<v8::Value>& info return Nan::ThrowTypeError("Second argument must be a string"); } - mbgl::optional<Error> error = setLayoutProperty(*layer, *Nan::Utf8String(info[1]), info[2]); + mbgl::optional<Error> error = setLayoutProperty(*layer, *Nan::Utf8String(info[1]), Value(info[2])); if (error) { return Nan::ThrowTypeError(error->message.c_str()); } @@ -772,7 +780,7 @@ void NodeMap::SetPaintProperty(const Nan::FunctionCallbackInfo<v8::Value>& info) return Nan::ThrowTypeError("Second argument must be a string"); } - mbgl::optional<Error> error = setPaintProperty(*layer, *Nan::Utf8String(info[1]), info[2]); + mbgl::optional<Error> error = setPaintProperty(*layer, *Nan::Utf8String(info[1]), Value(info[2])); if (error) { return Nan::ThrowTypeError(error->message.c_str()); } diff --git a/platform/qt/qt.cmake b/platform/qt/qt.cmake index 2346d7d820..918e6b93cd 100644 --- a/platform/qt/qt.cmake +++ b/platform/qt/qt.cmake @@ -60,6 +60,10 @@ set(MBGL_QT_FILESOURCE_FILES add_library(qmapboxgl SHARED platform/qt/include/qmapbox.hpp platform/qt/include/qmapboxgl.hpp + platform/qt/src/qt_conversion.cpp + platform/qt/src/qt_conversion.hpp + platform/qt/src/qt_geojson.cpp + platform/qt/src/qt_geojson.hpp platform/qt/src/qmapbox.cpp platform/qt/src/qmapboxgl.cpp platform/qt/src/qmapboxgl_p.hpp diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index 074ef280aa..740bb90202 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -14,7 +14,17 @@ #include <mbgl/style/conversion.hpp> #include <mbgl/style/conversion/layer.hpp> #include <mbgl/style/conversion/source.hpp> +#include <mbgl/style/conversion/filter.hpp> +#include <mbgl/style/conversion/geojson.hpp> +#include <mbgl/style/filter.hpp> #include <mbgl/style/layers/custom_layer.hpp> +#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> #include <mbgl/style/sources/geojson_source.hpp> #include <mbgl/style/transition_options.hpp> #include <mbgl/style/image.hpp> diff --git a/platform/qt/src/qt_conversion.cpp b/platform/qt/src/qt_conversion.cpp new file mode 100644 index 0000000000..35a6ef4fc9 --- /dev/null +++ b/platform/qt/src/qt_conversion.cpp @@ -0,0 +1,133 @@ +#include <mbgl/util/feature.hpp> +#include <mbgl/style/conversion/geojson.hpp> +#include <QColor> +#include <QMapbox> +#include "qt_geojson.hpp" + +namespace mbgl { +namespace style { +namespace conversion { + +template<> bool ValueTraits<QVariant>::isUndefined(const QVariant& value) { + return value.isNull() || !value.isValid(); +} + +template<> bool ValueTraits<QVariant>::isArray(const QVariant& value) { + return value.canConvert(QVariant::List); +} + +template<> std::size_t ValueTraits<QVariant>::arrayLength(const QVariant& value) { + return value.toList().size(); +} + +template<> QVariant ValueTraits<QVariant>::arrayMember(const QVariant& value, std::size_t i) { + return value.toList()[i]; +} + +template<> bool ValueTraits<QVariant>::isObject(const QVariant& value) { + return value.canConvert(QVariant::Map) + || value.type() == QVariant::ByteArray +#if QT_VERSION >= 0x050000 + || QString(value.typeName()) == QStringLiteral("QMapbox::Feature"); +#else + || QString(value.typeName()) == QString("QMapbox::Feature"); +#endif +} + +template<> optional<QVariant> ValueTraits<QVariant>::objectMember(const QVariant& value, const char* key) { + auto map = value.toMap(); + auto iter = map.constFind(key); + + if (iter != map.constEnd()) { + return iter.value(); + } else { + return {}; + } +} + +using EachMemberFn = std::function<optional<Error>(const std::string&, const QVariant&)>; + +template<> optional<Error> ValueTraits<QVariant>::eachMember(const QVariant& value, const EachMemberFn& fn) { + auto map = value.toMap(); + auto iter = map.constBegin(); + + while (iter != map.constEnd()) { + optional<Error> result = fn(iter.key().toStdString(), iter.value()); + if (result) { + return result; + } + + ++iter; + } + + return {}; +} + +template<> optional<bool> ValueTraits<QVariant>::toBool(const QVariant& value) { + if (value.type() == QVariant::Bool) { + return value.toBool(); + } else { + return {}; + } +} + +template<> optional<float> ValueTraits<QVariant>::toNumber(const QVariant& value) { + if (value.type() == QVariant::Int || value.type() == QVariant::Double) { + return value.toFloat(); + } else { + return {}; + } +} +template<> optional<double> ValueTraits<QVariant>::toDouble(const QVariant& value) { + if (value.type() == QVariant::Int || value.type() == QVariant::Double) { + return value.toDouble(); + } else { + return {}; + } +} + +template<> optional<std::string> ValueTraits<QVariant>::toString(const QVariant& value) { + if (value.type() == QVariant::String) { + return value.toString().toStdString(); + } else if (value.type() == QVariant::Color) { + return value.value<QColor>().name().toStdString(); + } else { + return {}; + } +} + +template<> optional<mbgl::Value> ValueTraits<QVariant>::toValue(const QVariant& value) { + if (value.type() == QVariant::Bool) { + return { value.toBool() }; + } else if (value.type() == QVariant::String) { + return { value.toString().toStdString() }; + } else if (value.type() == QVariant::Color) { + return { value.value<QColor>().name().toStdString() }; + } else if (value.type() == QVariant::Int) { + return { int64_t(value.toInt()) }; + } else if (value.canConvert(QVariant::Double)) { + return { value.toDouble() }; + } else { + return {}; + } +} + +template <> optional<GeoJSON> ValueTraits<QVariant>::toGeoJSON(const QVariant& value, Error& error) { +#if QT_VERSION >= 0x050000 + if (value.typeName() == QStringLiteral("QMapbox::Feature")) { +#else + if (value.typeName() == QString("QMapbox::Feature")) { +#endif + return GeoJSON { asMapboxGLFeature(value.value<QMapbox::Feature>()) }; + } else if (value.type() != QVariant::ByteArray) { + error = { "JSON data must be in QByteArray" }; + return {}; + } + + QByteArray data = value.toByteArray(); + return parseGeoJSON(std::string(data.constData(), data.size()), error); +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/platform/qt/src/qt_conversion.hpp b/platform/qt/src/qt_conversion.hpp index 40d7e5b928..bd830f8432 100644 --- a/platform/qt/src/qt_conversion.hpp +++ b/platform/qt/src/qt_conversion.hpp @@ -1,120 +1,16 @@ #pragma once #include <mbgl/style/conversion.hpp> -#include <mbgl/util/feature.hpp> #include <mbgl/util/optional.hpp> - -#include <QMapbox> - -#include <QColor> #include <QVariant> namespace mbgl { namespace style { namespace conversion { -inline bool isUndefined(const QVariant& value) { - return value.isNull() || !value.isValid(); -} - -inline bool isArray(const QVariant& value) { - return value.canConvert(QVariant::List); -} - -inline std::size_t arrayLength(const QVariant& value) { - return value.toList().size(); -} - -inline QVariant arrayMember(const QVariant& value, std::size_t i) { - return value.toList()[i]; -} - -inline bool isObject(const QVariant& value) { - return value.canConvert(QVariant::Map) - || value.type() == QVariant::ByteArray -#if QT_VERSION >= 0x050000 - || QString(value.typeName()) == QStringLiteral("QMapbox::Feature"); -#else - || QString(value.typeName()) == QString("QMapbox::Feature"); -#endif -} - -inline optional<QVariant> objectMember(const QVariant& value, const char* key) { - auto map = value.toMap(); - auto iter = map.constFind(key); - - if (iter != map.constEnd()) { - return iter.value(); - } else { - return {}; - } -} - -using EachMemberFn = std::function<optional<Error>(const std::string&, const QVariant&)>; - -optional<Error> eachMember(const QVariant& value, EachMemberFn&& fn) { - auto map = value.toMap(); - auto iter = map.constBegin(); - - while (iter != map.constEnd()) { - optional<Error> result = fn(iter.key().toStdString(), iter.value()); - if (result) { - return result; - } - - ++iter; - } - - return {}; -} - -inline optional<bool> toBool(const QVariant& value) { - if (value.type() == QVariant::Bool) { - return value.toBool(); - } else { - return {}; - } -} - -inline optional<float> toNumber(const QVariant& value) { - if (value.type() == QVariant::Int || value.type() == QVariant::Double) { - return value.toFloat(); - } else { - return {}; - } -} -inline optional<double> toDouble(const QVariant& value) { - if (value.type() == QVariant::Int || value.type() == QVariant::Double) { - return value.toDouble(); - } else { - return {}; - } -} - -inline optional<std::string> toString(const QVariant& value) { - if (value.type() == QVariant::String) { - return value.toString().toStdString(); - } else if (value.type() == QVariant::Color) { - return value.value<QColor>().name().toStdString(); - } else { - return {}; - } -} - -inline optional<Value> toValue(const QVariant& value) { - if (value.type() == QVariant::Bool) { - return { value.toBool() }; - } else if (value.type() == QVariant::String) { - return { value.toString().toStdString() }; - } else if (value.type() == QVariant::Color) { - return { value.value<QColor>().name().toStdString() }; - } else if (value.type() == QVariant::Int) { - return { int64_t(value.toInt()) }; - } else if (value.canConvert(QVariant::Double)) { - return { value.toDouble() }; - } else { - return {}; - } +template <class T, class...Args> +optional<T> convert(const QVariant& value, Error& error, Args&&...args) { + return convert<T>(Value(value), error, std::forward<Args>(args)...); } } // namespace conversion diff --git a/platform/qt/src/qt_geojson.cpp b/platform/qt/src/qt_geojson.cpp new file mode 100644 index 0000000000..80377de64d --- /dev/null +++ b/platform/qt/src/qt_geojson.cpp @@ -0,0 +1,166 @@ +#include "qt_geojson.hpp" +#include <mapbox/geojson.hpp> +#include <mbgl/util/geometry.hpp> +#include <mbgl/util/feature.hpp> + +namespace QMapbox { + +mbgl::Point<double> asMapboxGLPoint(const QMapbox::Coordinate &coordinate) { + return mbgl::Point<double> { coordinate.second, coordinate.first }; +} + +mbgl::MultiPoint<double> asMapboxGLMultiPoint(const QMapbox::Coordinates &multiPoint) { + mbgl::MultiPoint<double> mbglMultiPoint; + mbglMultiPoint.reserve(multiPoint.size()); + for (const auto &point: multiPoint) { + mbglMultiPoint.emplace_back(asMapboxGLPoint(point)); + } + return mbglMultiPoint; +}; + +mbgl::LineString<double> asMapboxGLLineString(const QMapbox::Coordinates &lineString) { + mbgl::LineString<double> mbglLineString; + mbglLineString.reserve(lineString.size()); + for (const auto &coordinate : lineString) { + mbglLineString.emplace_back(asMapboxGLPoint(coordinate)); + } + return mbglLineString; +}; + +mbgl::MultiLineString<double> asMapboxGLMultiLineString(const QMapbox::CoordinatesCollection &multiLineString) { + mbgl::MultiLineString<double> mbglMultiLineString; + mbglMultiLineString.reserve(multiLineString.size()); + for (const auto &lineString : multiLineString) { + mbglMultiLineString.emplace_back(std::forward<mbgl::LineString<double>>(asMapboxGLLineString(lineString))); + } + return mbglMultiLineString; +}; + +mbgl::Polygon<double> asMapboxGLPolygon(const QMapbox::CoordinatesCollection &polygon) { + mbgl::Polygon<double> mbglPolygon; + mbglPolygon.reserve(polygon.size()); + for (const auto &linearRing : polygon) { + mbgl::LinearRing<double> mbglLinearRing; + mbglLinearRing.reserve(linearRing.size()); + for (const auto &coordinate: linearRing) { + mbglLinearRing.emplace_back(asMapboxGLPoint(coordinate)); + } + mbglPolygon.emplace_back(std::move(mbglLinearRing)); + } + return mbglPolygon; +}; + +mbgl::MultiPolygon<double> asMapboxGLMultiPolygon(const QMapbox::CoordinatesCollections &multiPolygon) { + mbgl::MultiPolygon<double> mbglMultiPolygon; + mbglMultiPolygon.reserve(multiPolygon.size()); + for (const auto &polygon : multiPolygon) { + mbglMultiPolygon.emplace_back(std::forward<mbgl::Polygon<double>>(asMapboxGLPolygon(polygon))); + } + return mbglMultiPolygon; +}; + +mbgl::Value asMapboxGLPropertyValue(const QVariant &value) { + auto valueList = [](const QVariantList &list) { + std::vector<mbgl::Value> mbglList; + mbglList.reserve(list.size()); + for (const auto& listValue : list) { + mbglList.emplace_back(asMapboxGLPropertyValue(listValue)); + } + return mbglList; + }; + + auto valueMap = [](const QVariantMap &map) { + std::unordered_map<std::string, mbgl::Value> mbglMap; + mbglMap.reserve(map.size()); + auto it = map.constBegin(); + while (it != map.constEnd()) { + mbglMap.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value()))); + ++it; + } + return mbglMap; + }; + + switch (value.type()) { +#if QT_VERSION >= 0x050000 + case QMetaType::UnknownType: +#else + case QVariant::Invalid: +#endif + return mbgl::NullValue {}; + case QMetaType::Bool: + return { value.toBool() }; + case QMetaType::ULongLong: + return { uint64_t(value.toULongLong()) }; + case QMetaType::LongLong: + return { int64_t(value.toLongLong()) }; + case QMetaType::Double: + return { value.toDouble() }; + case QMetaType::QString: + return { value.toString().toStdString() }; + case QMetaType::QVariantList: + return valueList(value.toList()); + case QMetaType::QVariantMap: + return valueMap(value.toMap()); + default: + qWarning() << "Unsupported feature property value:" << value; + return {}; + } +} + +mbgl::FeatureIdentifier asMapboxGLFeatureIdentifier(const QVariant &id) { + switch (id.type()) { +#if QT_VERSION >= 0x050000 + case QMetaType::UnknownType: +#else + case QVariant::Invalid: +#endif + return {}; + case QMetaType::ULongLong: + return { uint64_t(id.toULongLong()) }; + case QMetaType::LongLong: + return { int64_t(id.toLongLong()) }; + case QMetaType::Double: + return { id.toDouble() }; + case QMetaType::QString: + return { id.toString().toStdString() }; + default: + qWarning() << "Unsupported feature identifier:" << id; + return {}; + } +} + +mbgl::Feature asMapboxGLFeature(const QMapbox::Feature &feature) { + mbgl::PropertyMap properties; + properties.reserve(feature.properties.size()); + auto it = feature.properties.constBegin(); + while (it != feature.properties.constEnd()) { + properties.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value()))); + } + + mbgl::FeatureIdentifier id = asMapboxGLFeatureIdentifier(feature.id); + + if (feature.type == QMapbox::Feature::PointType) { + const QMapbox::Coordinates &points = feature.geometry.first().first(); + if (points.size() == 1) { + return { asMapboxGLPoint(points.first()), std::move(properties), std::move(id) }; + } else { + return { asMapboxGLMultiPoint(points), std::move(properties), std::move(id) }; + } + } else if (feature.type == QMapbox::Feature::LineStringType) { + const QMapbox::CoordinatesCollection &lineStrings = feature.geometry.first(); + if (lineStrings.size() == 1) { + return { asMapboxGLLineString(lineStrings.first()), std::move(properties), std::move(id) }; + } else { + return { asMapboxGLMultiLineString(lineStrings), std::move(properties), std::move(id) }; + } + } else { // PolygonType + const QMapbox::CoordinatesCollections &polygons = feature.geometry; + if (polygons.size() == 1) { + return { asMapboxGLPolygon(polygons.first()), std::move(properties), std::move(id) }; + } else { + return { asMapboxGLMultiPolygon(polygons), std::move(properties), std::move(id) }; + } + } +}; + +} // namespace QMapbox diff --git a/platform/qt/src/qt_geojson.hpp b/platform/qt/src/qt_geojson.hpp index a6958b7edc..a9c10272ab 100644 --- a/platform/qt/src/qt_geojson.hpp +++ b/platform/qt/src/qt_geojson.hpp @@ -1,7 +1,8 @@ #pragma once #include <mapbox/geojson.hpp> -#include <mbgl/style/conversion/geojson.hpp> +#include <mbgl/util/geometry.hpp> +#include <mbgl/util/feature.hpp> #include <QMapbox> @@ -13,187 +14,14 @@ namespace QMapbox { -mbgl::Point<double> asMapboxGLPoint(const QMapbox::Coordinate &coordinate) { - return mbgl::Point<double> { coordinate.second, coordinate.first }; -} - -mbgl::MultiPoint<double> asMapboxGLMultiPoint(const QMapbox::Coordinates &multiPoint) { - mbgl::MultiPoint<double> mbglMultiPoint; - mbglMultiPoint.reserve(multiPoint.size()); - for (const auto &point: multiPoint) { - mbglMultiPoint.emplace_back(asMapboxGLPoint(point)); - } - return mbglMultiPoint; -}; - -mbgl::LineString<double> asMapboxGLLineString(const QMapbox::Coordinates &lineString) { - mbgl::LineString<double> mbglLineString; - mbglLineString.reserve(lineString.size()); - for (const auto &coordinate : lineString) { - mbglLineString.emplace_back(asMapboxGLPoint(coordinate)); - } - return mbglLineString; -}; - -mbgl::MultiLineString<double> asMapboxGLMultiLineString(const QMapbox::CoordinatesCollection &multiLineString) { - mbgl::MultiLineString<double> mbglMultiLineString; - mbglMultiLineString.reserve(multiLineString.size()); - for (const auto &lineString : multiLineString) { - mbglMultiLineString.emplace_back(std::forward<mbgl::LineString<double>>(asMapboxGLLineString(lineString))); - } - return mbglMultiLineString; -}; - -mbgl::Polygon<double> asMapboxGLPolygon(const QMapbox::CoordinatesCollection &polygon) { - mbgl::Polygon<double> mbglPolygon; - mbglPolygon.reserve(polygon.size()); - for (const auto &linearRing : polygon) { - mbgl::LinearRing<double> mbglLinearRing; - mbglLinearRing.reserve(linearRing.size()); - for (const auto &coordinate: linearRing) { - mbglLinearRing.emplace_back(asMapboxGLPoint(coordinate)); - } - mbglPolygon.emplace_back(std::move(mbglLinearRing)); - } - return mbglPolygon; -}; - -mbgl::MultiPolygon<double> asMapboxGLMultiPolygon(const QMapbox::CoordinatesCollections &multiPolygon) { - mbgl::MultiPolygon<double> mbglMultiPolygon; - mbglMultiPolygon.reserve(multiPolygon.size()); - for (const auto &polygon : multiPolygon) { - mbglMultiPolygon.emplace_back(std::forward<mbgl::Polygon<double>>(asMapboxGLPolygon(polygon))); - } - return mbglMultiPolygon; -}; - -mbgl::Value asMapboxGLPropertyValue(const QVariant &value) { - auto valueList = [](const QVariantList &list) { - std::vector<mbgl::Value> mbglList; - mbglList.reserve(list.size()); - for (const auto& listValue : list) { - mbglList.emplace_back(asMapboxGLPropertyValue(listValue)); - } - return mbglList; - }; - - auto valueMap = [](const QVariantMap &map) { - std::unordered_map<std::string, mbgl::Value> mbglMap; - mbglMap.reserve(map.size()); - auto it = map.constBegin(); - while (it != map.constEnd()) { - mbglMap.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value()))); - ++it; - } - return mbglMap; - }; - - switch (value.type()) { -#if QT_VERSION >= 0x050000 - case QMetaType::UnknownType: -#else - case QVariant::Invalid: -#endif - return mbgl::NullValue {}; - case QMetaType::Bool: - return { value.toBool() }; - case QMetaType::ULongLong: - return { uint64_t(value.toULongLong()) }; - case QMetaType::LongLong: - return { int64_t(value.toLongLong()) }; - case QMetaType::Double: - return { value.toDouble() }; - case QMetaType::QString: - return { value.toString().toStdString() }; - case QMetaType::QVariantList: - return valueList(value.toList()); - case QMetaType::QVariantMap: - return valueMap(value.toMap()); - default: - qWarning() << "Unsupported feature property value:" << value; - return {}; - } -} - -mbgl::FeatureIdentifier asMapboxGLFeatureIdentifier(const QVariant &id) { - switch (id.type()) { -#if QT_VERSION >= 0x050000 - case QMetaType::UnknownType: -#else - case QVariant::Invalid: -#endif - return {}; - case QMetaType::ULongLong: - return { uint64_t(id.toULongLong()) }; - case QMetaType::LongLong: - return { int64_t(id.toLongLong()) }; - case QMetaType::Double: - return { id.toDouble() }; - case QMetaType::QString: - return { id.toString().toStdString() }; - default: - qWarning() << "Unsupported feature identifier:" << id; - return {}; - } -} - -mbgl::Feature asMapboxGLFeature(const QMapbox::Feature &feature) { - mbgl::PropertyMap properties; - properties.reserve(feature.properties.size()); - auto it = feature.properties.constBegin(); - while (it != feature.properties.constEnd()) { - properties.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value()))); - } - - mbgl::FeatureIdentifier id = asMapboxGLFeatureIdentifier(feature.id); - - if (feature.type == QMapbox::Feature::PointType) { - const QMapbox::Coordinates &points = feature.geometry.first().first(); - if (points.size() == 1) { - return { asMapboxGLPoint(points.first()), std::move(properties), std::move(id) }; - } else { - return { asMapboxGLMultiPoint(points), std::move(properties), std::move(id) }; - } - } else if (feature.type == QMapbox::Feature::LineStringType) { - const QMapbox::CoordinatesCollection &lineStrings = feature.geometry.first(); - if (lineStrings.size() == 1) { - return { asMapboxGLLineString(lineStrings.first()), std::move(properties), std::move(id) }; - } else { - return { asMapboxGLMultiLineString(lineStrings), std::move(properties), std::move(id) }; - } - } else { // PolygonType - const QMapbox::CoordinatesCollections &polygons = feature.geometry; - if (polygons.size() == 1) { - return { asMapboxGLPolygon(polygons.first()), std::move(properties), std::move(id) }; - } else { - return { asMapboxGLMultiPolygon(polygons), std::move(properties), std::move(id) }; - } - } -}; +mbgl::Point<double> asMapboxGLPoint(const QMapbox::Coordinate &coordinate); +mbgl::MultiPoint<double> asMapboxGLMultiPoint(const QMapbox::Coordinates &multiPoint); +mbgl::LineString<double> asMapboxGLLineString(const QMapbox::Coordinates &lineString); +mbgl::MultiLineString<double> asMapboxGLMultiLineString(const QMapbox::CoordinatesCollection &multiLineString); +mbgl::Polygon<double> asMapboxGLPolygon(const QMapbox::CoordinatesCollection &polygon); +mbgl::MultiPolygon<double> asMapboxGLMultiPolygon(const QMapbox::CoordinatesCollections &multiPolygon); +mbgl::Value asMapboxGLPropertyValue(const QVariant &value); +mbgl::FeatureIdentifier asMapboxGLFeatureIdentifier(const QVariant &id); +mbgl::Feature asMapboxGLFeature(const QMapbox::Feature &feature); } // namespace QMapbox - -namespace mbgl { -namespace style { -namespace conversion { - -template <> -optional<GeoJSON> Converter<GeoJSON>::operator()(const QVariant& value, Error& error) const { -#if QT_VERSION >= 0x050000 - if (value.typeName() == QStringLiteral("QMapbox::Feature")) { -#else - if (value.typeName() == QString("QMapbox::Feature")) { -#endif - return GeoJSON { asMapboxGLFeature(value.value<QMapbox::Feature>()) }; - } else if (value.type() != QVariant::ByteArray) { - error = { "JSON data must be in QByteArray" }; - return {}; - } - - QByteArray data = value.toByteArray(); - return convert<GeoJSON>(std::string(data.constData(), data.size()), error); -} - -} // namespace conversion -} // namespace style -} // namespace mbgl |