Refactor: use conversion system to convert MGLStyleFunction to mbgl core types (#8026)
This leverages the work already happening in `mbgl::style::conversion` to convert style functions from style-spec definitions into `mbgl::style::{Camera,Source,Composite}Function`s. In particular, this allows the conversions system to handle the differing typing requirements based on whether the output type of the style function is interpolatable or non-interpolatable.
This commit is contained in:
@@ -200,7 +200,7 @@ struct Converter<CameraFunction<T>> {
|
||||
|
||||
template <class T, class V>
|
||||
Result<optional<T>> convertDefaultValue(const V& value) {
|
||||
auto defaultValueValue = objectMember(value, "defaultValue");
|
||||
auto defaultValueValue = objectMember(value, "default");
|
||||
if (!defaultValueValue) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Submodule mapbox-gl-js updated: dee3911a7b...abdd41a90f
135
platform/darwin/src/MGLConversion.h
Normal file
135
platform/darwin/src/MGLConversion.h
Normal file
@@ -0,0 +1,135 @@
|
||||
#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
|
||||
|
||||
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<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 {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace conversion
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
#import "NSValue+MGLStyleAttributeAdditions.h"
|
||||
#import "MGLTypes.h"
|
||||
|
||||
#import "MGLConversion.h"
|
||||
#include <mbgl/style/conversion/data_driven_property_value.hpp>
|
||||
#include <mbgl/style/conversion.hpp>
|
||||
|
||||
#import <mbgl/util/enum.hpp>
|
||||
|
||||
#include <mbgl/style/data_driven_property_value.hpp>
|
||||
@@ -117,157 +121,11 @@ public:
|
||||
mbgl::style::DataDrivenPropertyValue<MBGLType> toDataDrivenPropertyValue(MGLStyleValue<ObjCType> *value) {
|
||||
if ([value isKindOfClass:[MGLStyleConstantValue class]]) {
|
||||
return toMBGLConstantValue((MGLStyleConstantValue<ObjCType> *)value);
|
||||
} else if ([value isKindOfClass:[MGLCameraStyleFunction class]]) {
|
||||
MGLCameraStyleFunction<ObjCType> *cameraStyleFunction = (MGLCameraStyleFunction<ObjCType> *)value;
|
||||
switch (cameraStyleFunction.interpolationMode) {
|
||||
case MGLInterpolationModeExponential:
|
||||
return toMBGLExponentialCameraFunction(cameraStyleFunction);
|
||||
break;
|
||||
case MGLInterpolationModeInterval:
|
||||
return toMBGLIntervalCameraFunction(cameraStyleFunction);
|
||||
break;
|
||||
default:
|
||||
[NSException raise:NSInvalidArgumentException
|
||||
format:@"A camera function must use either exponential or interval stops."];
|
||||
return {};
|
||||
}
|
||||
} else if ([value isKindOfClass:[MGLSourceStyleFunction class]]) {
|
||||
MGLSourceStyleFunction<ObjCType> *sourceStyleFunction = (MGLSourceStyleFunction<ObjCType> *)value;
|
||||
switch (sourceStyleFunction.interpolationMode) {
|
||||
case MGLInterpolationModeExponential:
|
||||
return toMBGLExponentialSourceFunction(sourceStyleFunction);
|
||||
break;
|
||||
case MGLInterpolationModeInterval:
|
||||
return toMBGLIntervalSourceFunction(sourceStyleFunction);
|
||||
break;
|
||||
case MGLInterpolationModeCategorical:
|
||||
return toMBGLCategoricalSourceFunction(sourceStyleFunction);
|
||||
break;
|
||||
case MGLInterpolationModeIdentity:
|
||||
return toMBGLIdentitySourceFunction(sourceStyleFunction);
|
||||
break;
|
||||
default:
|
||||
[NSException raise:NSInvalidArgumentException
|
||||
format:@"A camera function must use exponential, interval, categorical, or identity stops."];
|
||||
return {};
|
||||
}
|
||||
} else if ([value isKindOfClass:[MGLCompositeStyleFunction class]]) {
|
||||
MGLCompositeStyleFunction<ObjCType> *compositeStyleFunction = (MGLCompositeStyleFunction<ObjCType> *)value;
|
||||
switch (compositeStyleFunction.interpolationMode) {
|
||||
case MGLInterpolationModeExponential: {
|
||||
__block std::map<float, std::map<float, MBGLType>> outerStops = {};
|
||||
[compositeStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, NSDictionary * _Nonnull stopValue, BOOL * _Nonnull stop) {
|
||||
std::map<float, MBGLType> stops = {};
|
||||
for (NSNumber *key in stopValue.allKeys) {
|
||||
NSCAssert([key isKindOfClass:[NSNumber class]], @"Stop keys should be NSNumbers");
|
||||
MGLStyleValue<ObjCType> *value = stopValue[key];
|
||||
NSCAssert([value isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues");
|
||||
auto mbglStopValue = toPropertyValue(value);
|
||||
NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
|
||||
stops[key.floatValue] = mbglStopValue.asConstant();
|
||||
}
|
||||
outerStops[zoomKey.floatValue] = stops;
|
||||
}];
|
||||
mbgl::style::CompositeFunction<MBGLType> compositeFunction {
|
||||
compositeStyleFunction.attributeName.UTF8String,
|
||||
mbgl::style::CompositeExponentialStops<MBGLType> { outerStops, (float)compositeStyleFunction.interpolationBase }
|
||||
};
|
||||
if (compositeStyleFunction.defaultValue) {
|
||||
NSCAssert([compositeStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant");
|
||||
MBGLType mbglValue;
|
||||
id mglValue = [(MGLStyleConstantValue<ObjCType> *)compositeStyleFunction.defaultValue rawValue];
|
||||
getMBGLValue(mglValue, mbglValue);
|
||||
compositeFunction.defaultValue = mbglValue;
|
||||
}
|
||||
return compositeFunction;
|
||||
}
|
||||
break;
|
||||
case MGLInterpolationModeInterval: {
|
||||
__block std::map<float, std::map<float, MBGLType>> outerStops = {};
|
||||
[compositeStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, NSDictionary * _Nonnull stopValue, BOOL * _Nonnull stop) {
|
||||
std::map<float, MBGLType> stops = {};
|
||||
for (NSNumber *key in stopValue.allKeys) {
|
||||
NSCAssert([key isKindOfClass:[NSNumber class]], @"Stop keys should be NSNumbers");
|
||||
MGLStyleValue<ObjCType> *value = stopValue[key];
|
||||
NSCAssert([value isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues");
|
||||
auto mbglStopValue = toPropertyValue(value);
|
||||
NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
|
||||
stops[key.floatValue] = mbglStopValue.asConstant();
|
||||
}
|
||||
outerStops[zoomKey.floatValue] = stops;
|
||||
}];
|
||||
mbgl::style::CompositeFunction<MBGLType> compositeFunction {
|
||||
compositeStyleFunction.attributeName.UTF8String,
|
||||
mbgl::style::CompositeIntervalStops<MBGLType> { outerStops }
|
||||
};
|
||||
if (compositeStyleFunction.defaultValue) {
|
||||
NSCAssert([compositeStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant");
|
||||
MBGLType mbglValue;
|
||||
id mglValue = [(MGLStyleConstantValue<ObjCType> *)compositeStyleFunction.defaultValue rawValue];
|
||||
getMBGLValue(mglValue, mbglValue);
|
||||
compositeFunction.defaultValue = mbglValue;
|
||||
}
|
||||
return compositeFunction;
|
||||
}
|
||||
break;
|
||||
case MGLInterpolationModeCategorical: {
|
||||
__block std::map<float, std::map<mbgl::style::CategoricalValue, MBGLType>> outerStops = {};
|
||||
[compositeStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, NSDictionary * _Nonnull stopValue, BOOL * _Nonnull stop) {
|
||||
__block std::map<mbgl::style::CategoricalValue, MBGLType> stops = {};
|
||||
[stopValue enumerateKeysAndObjectsUsingBlock:^(id _Nonnull categoryKey, MGLStyleValue<ObjCType> * _Nonnull innerValue, BOOL * _Nonnull stop) {
|
||||
NSCAssert([innerValue isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues");
|
||||
auto mbglStopValue = toPropertyValue(innerValue);
|
||||
NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
|
||||
|
||||
if ([categoryKey isKindOfClass:[NSString class]]) {
|
||||
const std::string& convertedValueKey = [((NSString *)categoryKey) UTF8String];
|
||||
stops[mbgl::style::CategoricalValue(convertedValueKey)] = mbglStopValue.asConstant();
|
||||
} else if ([categoryKey isKindOfClass:[NSNumber class]]) {
|
||||
NSNumber *key = (NSNumber *)categoryKey;
|
||||
if ((strcmp([key objCType], @encode(char)) == 0) ||
|
||||
(strcmp([key objCType], @encode(BOOL)) == 0)) {
|
||||
stops[mbgl::style::CategoricalValue((bool)[key boolValue])] = mbglStopValue.asConstant();
|
||||
} else if (strcmp([key objCType], @encode(double)) == 0 ||
|
||||
strcmp([key objCType], @encode(float)) == 0) {
|
||||
NSCAssert(mbglStopValue.isConstant(), @"Categorical stop keys must be strings, booleans, or integers");
|
||||
} else if ([key compare:@(0)] == NSOrderedDescending ||
|
||||
[key compare:@(0)] == NSOrderedSame ||
|
||||
[key compare:@(0)] == NSOrderedAscending) {
|
||||
stops[mbgl::style::CategoricalValue((int64_t)[key integerValue])] = mbglStopValue.asConstant();
|
||||
}
|
||||
}
|
||||
}];
|
||||
outerStops[zoomKey.floatValue] = stops;
|
||||
}];
|
||||
mbgl::style::CompositeFunction<MBGLType> compositeFunction {
|
||||
compositeStyleFunction.attributeName.UTF8String,
|
||||
mbgl::style::CompositeCategoricalStops<MBGLType> { outerStops }
|
||||
};
|
||||
if (compositeStyleFunction.defaultValue) {
|
||||
NSCAssert([compositeStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant");
|
||||
MBGLType mbglValue;
|
||||
id mglValue = [(MGLStyleConstantValue<ObjCType> *)compositeStyleFunction.defaultValue rawValue];
|
||||
getMBGLValue(mglValue, mbglValue);
|
||||
compositeFunction.defaultValue = mbglValue;
|
||||
}
|
||||
return compositeFunction;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
[NSException raise:NSInvalidArgumentException
|
||||
format:@"A composite function must use exponential, interval, or categorical stops."];
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
} else if ([value isMemberOfClass:[MGLStyleFunction class]]) {
|
||||
MGLStyleFunction<ObjCType> *styleFunction = (MGLStyleFunction<ObjCType> *)value;
|
||||
return toMBGLExponentialCameraFunction(styleFunction);
|
||||
} else if (value) {
|
||||
[NSException raise:@"MGLAbstractClassException" format:
|
||||
@"The style value %@ cannot be applied to the style. "
|
||||
@"Make sure the style value was created as a member of a concrete subclass of MGLStyleValue.",
|
||||
NSStringFromClass([value class])];
|
||||
return {};
|
||||
} else if ([value isKindOfClass:[MGLStyleFunction class]]) {
|
||||
auto rawValue = toRawStyleSpecValue((MGLStyleFunction<ObjCType> *) value);
|
||||
auto result = mbgl::style::conversion::convert<mbgl::style::DataDrivenPropertyValue<MBGLType>>(rawValue);
|
||||
NSCAssert(result, @(result.error().message.c_str()));
|
||||
return *result;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
@@ -322,6 +180,102 @@ private: // Private utilities for converting from mgl to mbgl values
|
||||
getMBGLValue(value.rawValue, mbglValue);
|
||||
return mbglValue;
|
||||
}
|
||||
|
||||
NSObject* toRawStyleSpecValue(MGLColor *color) {
|
||||
return @(color.mgl_color.stringify().c_str());
|
||||
}
|
||||
|
||||
NSObject* toRawStyleSpecValue(NSObject *rawMGLValue) {
|
||||
if ([rawMGLValue isKindOfClass:[NSValue class]]) {
|
||||
const auto rawNSValue = (NSValue *)rawMGLValue;
|
||||
if (strcmp([rawNSValue objCType], @encode(CGVector)) == 0) {
|
||||
// offset [x, y]
|
||||
std::array<float, 2> mglValue = rawNSValue.mgl_offsetArrayValue;
|
||||
return [NSArray arrayWithObjects:@(mglValue[0]), @(mglValue[1]), nil];
|
||||
}
|
||||
}
|
||||
// noop pass-through plain NSObject-based items
|
||||
return rawMGLValue;
|
||||
}
|
||||
|
||||
NSObject* toRawStyleSpecValue(MGLStyleFunction<ObjCType>* styleFunction) {
|
||||
NSMutableDictionary * rawFunction = [NSMutableDictionary new];
|
||||
// interpolationMode => type
|
||||
switch (styleFunction.interpolationMode) {
|
||||
case MGLInterpolationModeExponential:
|
||||
rawFunction[@"type"] = @"exponential";
|
||||
break;
|
||||
case MGLInterpolationModeInterval:
|
||||
rawFunction[@"type"] = @"interval";
|
||||
break;
|
||||
case MGLInterpolationModeCategorical:
|
||||
rawFunction[@"type"] = @"categorical";
|
||||
break;
|
||||
case MGLInterpolationModeIdentity:
|
||||
rawFunction[@"type"] = @"identity";
|
||||
break;
|
||||
}
|
||||
|
||||
// interpolationBase => base
|
||||
if (styleFunction.interpolationBase) {
|
||||
rawFunction[@"base"] = @(styleFunction.interpolationBase);
|
||||
}
|
||||
|
||||
// stops and default value
|
||||
if ([styleFunction isKindOfClass:[MGLCameraStyleFunction class]]) {
|
||||
// zoom-only function (no default value)
|
||||
__block NSMutableArray *stops = [[NSMutableArray alloc] init];
|
||||
[styleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleConstantValue<ObjCType> * _Nonnull outputValue, BOOL * _Nonnull stop) {
|
||||
NSArray *rawStop = @[zoomKey, toRawStyleSpecValue([outputValue rawValue])];
|
||||
[stops addObject:rawStop];
|
||||
}];
|
||||
rawFunction[@"stops"] = stops;
|
||||
|
||||
} else if ([styleFunction isKindOfClass:[MGLSourceStyleFunction class]]) {
|
||||
auto sourceStyleFunction = (MGLSourceStyleFunction<ObjCType> *)styleFunction;
|
||||
rawFunction[@"property"] = sourceStyleFunction.attributeName;
|
||||
// property-only function
|
||||
__block NSMutableArray *stops = [[NSMutableArray alloc] init];
|
||||
[styleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSObject * _Nonnull propertyKey, MGLStyleConstantValue<ObjCType> * _Nonnull outputValue, BOOL * _Nonnull stop) {
|
||||
NSArray *rawStop = @[propertyKey, toRawStyleSpecValue([outputValue rawValue])];
|
||||
[stops addObject:rawStop];
|
||||
}];
|
||||
rawFunction[@"stops"] = stops;
|
||||
|
||||
// defaultValue => default
|
||||
if (sourceStyleFunction.defaultValue) {
|
||||
NSCAssert([sourceStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant");
|
||||
rawFunction[@"default"] = toRawStyleSpecValue([(MGLStyleConstantValue<ObjCType> *)sourceStyleFunction.defaultValue rawValue]);
|
||||
}
|
||||
} else if ([styleFunction isKindOfClass:[MGLCompositeStyleFunction class]]) {
|
||||
// zoom-and-property function
|
||||
auto compositeStyleFunction = (MGLCompositeStyleFunction<ObjCType> *)styleFunction;
|
||||
rawFunction[@"property"] = compositeStyleFunction.attributeName;
|
||||
|
||||
__block NSMutableArray *stops = [[NSMutableArray alloc] init];
|
||||
[compositeStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, NSDictionary * _Nonnull stopValue, BOOL * _Nonnull stop) {
|
||||
for (NSObject *valueKey in stopValue.allKeys) {
|
||||
NSDictionary *stopKey = @{
|
||||
@"zoom": zoomKey,
|
||||
@"value": valueKey
|
||||
};
|
||||
MGLStyleConstantValue<ObjCType> *outputValue = stopValue[valueKey];
|
||||
NSCAssert([outputValue isKindOfClass:[MGLStyleConstantValue<ObjCType> class]], @"Stop outputs should be MGLStyleConstantValues");
|
||||
NSArray *rawStop = @[stopKey, toRawStyleSpecValue([outputValue rawValue])];
|
||||
[stops addObject:rawStop];
|
||||
}
|
||||
}];
|
||||
rawFunction[@"stops"] = stops;
|
||||
|
||||
// defaultValue => default
|
||||
if (compositeStyleFunction.defaultValue) {
|
||||
NSCAssert([compositeStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant");
|
||||
rawFunction[@"default"] = toRawStyleSpecValue([(MGLStyleConstantValue<ObjCType> *)compositeStyleFunction.defaultValue rawValue]);
|
||||
}
|
||||
}
|
||||
|
||||
return rawFunction;
|
||||
}
|
||||
|
||||
mbgl::style::CameraFunction<MBGLType> toMBGLExponentialCameraFunction(MGLStyleFunction<ObjCType> *styleFunction) {
|
||||
__block std::map<float, MBGLType> stops = {};
|
||||
|
||||
@@ -1,8 +1,88 @@
|
||||
import XCTest
|
||||
import Mapbox
|
||||
|
||||
|
||||
#if os(iOS) || os(watchOS) || os(tvOS)
|
||||
typealias MGLColor = UIColor
|
||||
#elseif os(macOS)
|
||||
typealias MGLColor = NSColor
|
||||
#endif
|
||||
|
||||
extension MGLStyleValueTests {
|
||||
func assertColorsEqualWithAccuracy(_ actual: MGLColor, _ expected: MGLColor, accuracy: Float = 1/255) {
|
||||
var actualComponents : [CGFloat] = [0, 0, 0, 0]
|
||||
var expectedComponents : [CGFloat] = [0, 0, 0, 0]
|
||||
actual.getRed(&(actualComponents[0]), green: &(actualComponents[1]), blue: &(actualComponents[2]), alpha: &(actualComponents[3]))
|
||||
expected.getRed(&(expectedComponents[0]), green: &(expectedComponents[1]), blue: &(expectedComponents[2]), alpha: &(expectedComponents[3]))
|
||||
for (ac, ec) in zip(actualComponents, expectedComponents) {
|
||||
XCTAssertEqualWithAccuracy(Float(ac), Float(ec), accuracy: accuracy)
|
||||
}
|
||||
}
|
||||
|
||||
func assertColorValuesEqual(_ actual: MGLStyleValue<MGLColor>, _ expected: MGLStyleValue<MGLColor>) {
|
||||
guard type(of: actual) == type(of: expected) else {
|
||||
XCTFail("Expected \(type(of: expected)), but found \(type(of: actual)) instead.")
|
||||
return
|
||||
}
|
||||
|
||||
if let actualConstant = actual as? MGLStyleConstantValue<MGLColor> {
|
||||
assertColorsEqualWithAccuracy(actualConstant.rawValue, (expected as! MGLStyleConstantValue<MGLColor>).rawValue)
|
||||
} else if let actualFunction = actual as? MGLStyleFunction<MGLColor>,
|
||||
let expectedFunction = expected as? MGLStyleFunction<MGLColor> {
|
||||
|
||||
// unless we have stops, there's no need for a custom comparison - default to plain == assertion
|
||||
guard let actualStops = actualFunction.stops, let expectedStops = expectedFunction.stops else {
|
||||
XCTAssertEqual(actualFunction, expectedFunction)
|
||||
return
|
||||
}
|
||||
|
||||
guard expectedStops is [String: Any] || expectedStops is [Float:Any] else {
|
||||
XCTFail("Stop levels must be String or Float.")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertEqual(actualFunction.interpolationBase, expectedFunction.interpolationBase)
|
||||
XCTAssertEqual(actualFunction.interpolationMode, expectedFunction.interpolationMode)
|
||||
if let actualFunction = actualFunction as? MGLSourceStyleFunction<MGLColor>,
|
||||
let expectedFunction = expectedFunction as? MGLSourceStyleFunction<MGLColor> {
|
||||
XCTAssertEqual(actualFunction.defaultValue, expectedFunction.defaultValue)
|
||||
} else if let actualFunction = actualFunction as? MGLCompositeStyleFunction<MGLColor>,
|
||||
let expectedFunction = expectedFunction as? MGLCompositeStyleFunction<MGLColor> {
|
||||
XCTAssertEqual(actualFunction.defaultValue, expectedFunction.defaultValue)
|
||||
}
|
||||
|
||||
func assertStopEqual (_ actualValue: Any?, _ expectedValue: Any?) {
|
||||
guard type(of: actualValue) == type(of: expectedValue) else {
|
||||
XCTFail("Expected stop value of type \(type(of: expectedValue)), but found \(type(of: actualValue)) instead.")
|
||||
return
|
||||
}
|
||||
if let actualValue = actualValue as? MGLStyleConstantValue<MGLColor>,
|
||||
let expectedValue = expectedValue as? MGLStyleConstantValue<MGLColor> {
|
||||
assertColorsEqualWithAccuracy(actualValue.rawValue, expectedValue.rawValue)
|
||||
} else if let actualValue = actualValue as? MGLStyleConstantValue<AnyObject>,
|
||||
let expectedValue = expectedValue as? MGLStyleConstantValue<AnyObject> {
|
||||
XCTAssertEqual(actualValue, expectedValue)
|
||||
} else {
|
||||
XCTFail("Unsupported stop value type \(type(of: actualValue)).")
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertEqual(actualStops.count, expectedStops.count)
|
||||
if let actualStops = actualStops as? [String:Any], let expectedStops = expectedStops as? [String: Any] {
|
||||
for (key, value) in actualStops {
|
||||
assertStopEqual(value, expectedStops[key])
|
||||
}
|
||||
} else if let actualStops = actualStops as? [Float:Any], let expectedStops = expectedStops as? [Float:Any] {
|
||||
for (key, value) in actualStops {
|
||||
assertStopEqual(value, expectedStops[key])
|
||||
}
|
||||
} else {
|
||||
XCTFail("Expected stops of type \(type(of: Array(expectedStops.keys)).Index.self), but found \(type(of: Array(actualStops.keys)).Index.self) instead.")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
XCTFail("MGLStyleValue<MGLColor> must be either a constant or a style function.")
|
||||
}
|
||||
}
|
||||
|
||||
func testConstantValues() {
|
||||
let shapeSource = MGLShapeSource(identifier: "source", shape: nil, options: nil)
|
||||
@@ -44,7 +124,7 @@ extension MGLStyleValueTests {
|
||||
var circleTranslationTwo = CGVector(dx: 0, dy: 0)
|
||||
let circleTranslationValueTwo = NSValue(bytes: &circleTranslationTwo, objCType: "{CGVector=dd}")
|
||||
|
||||
let circleTranslationStops = [
|
||||
let circleTranslationStops : [Float:MGLStyleValue<NSValue>] = [
|
||||
0: MGLStyleValue<NSValue>(rawValue: circleTranslationValueOne),
|
||||
10: MGLStyleValue<NSValue>(rawValue: circleTranslationValueTwo)
|
||||
]
|
||||
@@ -59,7 +139,7 @@ extension MGLStyleValueTests {
|
||||
XCTAssertEqual(circleStyleLayer.circleTranslation, expectedCircleTranslationValue)
|
||||
|
||||
// non-data-driven (enumeration property value), camera function with MGLCircleScaleAlignment enum (NSValue) stop values
|
||||
let scaleAlignmentStops = [
|
||||
let scaleAlignmentStops : [Float:MGLStyleValue<NSValue>] = [
|
||||
0: MGLStyleValue(rawValue: NSValue(mglCircleScaleAlignment: .map)),
|
||||
10: MGLStyleValue(rawValue: NSValue(mglCircleScaleAlignment: .viewport))
|
||||
]
|
||||
@@ -75,135 +155,67 @@ extension MGLStyleValueTests {
|
||||
func testFunctionsWithDataDrivenProperties() {
|
||||
let shapeSource = MGLShapeSource(identifier: "test", shape: nil, options: nil)
|
||||
let circleStyleLayer = MGLCircleStyleLayer(identifier: "circleLayer", source: shapeSource)
|
||||
|
||||
#if os(iOS) || os(watchOS) || os(tvOS)
|
||||
|
||||
// data-driven, camera function with exponential color stop values
|
||||
let redGreenStops = [
|
||||
0: MGLStyleValue<UIColor>(rawValue: .red),
|
||||
10: MGLStyleValue<UIColor>(rawValue: .red),
|
||||
15: MGLStyleValue<UIColor>(rawValue: .green)
|
||||
]
|
||||
let expectedCircleColorValue = MGLStyleValue<UIColor>(
|
||||
interpolationMode: .exponential,
|
||||
cameraStops: redGreenStops,
|
||||
options: [.interpolationBase: 10.0]
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedCircleColorValue
|
||||
XCTAssertEqual(circleStyleLayer.circleColor, expectedCircleColorValue)
|
||||
|
||||
// data-driven, source function with categorical color stop values with string attribute keys
|
||||
let redOnlyStops = [
|
||||
"red": MGLStyleValue<UIColor>(rawValue: .red)
|
||||
]
|
||||
let expectedRedCategoricalValue = MGLStyleValue<UIColor>(
|
||||
interpolationMode: .categorical,
|
||||
sourceStops: redOnlyStops,
|
||||
attributeName: "red",
|
||||
options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .cyan)]
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedRedCategoricalValue
|
||||
XCTAssertEqual(circleStyleLayer.circleColor, expectedRedCategoricalValue)
|
||||
|
||||
// data-driven, source function with categorical color stop values with integer attribute keys
|
||||
let greenOrangeStops = [
|
||||
0: MGLStyleValue<UIColor>(rawValue: .green),
|
||||
100: MGLStyleValue<UIColor>(rawValue: .orange)
|
||||
]
|
||||
let expectedGreenOrangeCategoricalValue = MGLStyleValue<UIColor>(
|
||||
interpolationMode: .categorical,
|
||||
sourceStops: greenOrangeStops,
|
||||
attributeName: "temp",
|
||||
options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .red)]
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedGreenOrangeCategoricalValue
|
||||
XCTAssertEqual(circleStyleLayer.circleColor, expectedGreenOrangeCategoricalValue)
|
||||
|
||||
// data-driven, source function with exponential color stop values
|
||||
let expectedRedGreenSourceExponentialValue = MGLStyleValue<UIColor>(
|
||||
interpolationMode: .exponential,
|
||||
sourceStops: redGreenStops,
|
||||
attributeName: "temp",
|
||||
options: nil
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedRedGreenSourceExponentialValue
|
||||
XCTAssertEqual(circleStyleLayer.circleColor, expectedRedGreenSourceExponentialValue)
|
||||
|
||||
// data-driven, identity source function
|
||||
let expectedSourceIdentityValue = MGLStyleValue<UIColor>(
|
||||
interpolationMode: .identity,
|
||||
sourceStops: nil,
|
||||
attributeName: "size",
|
||||
options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .green)]
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedSourceIdentityValue
|
||||
XCTAssertEqual(circleStyleLayer.circleColor, expectedSourceIdentityValue)
|
||||
|
||||
#elseif os(macOS)
|
||||
|
||||
// data-driven, camera function with exponential color stop values
|
||||
let redGreenStops = [
|
||||
0: MGLStyleValue<NSColor>(rawValue: .red),
|
||||
10: MGLStyleValue<NSColor>(rawValue: .red),
|
||||
15: MGLStyleValue<NSColor>(rawValue: .green)
|
||||
]
|
||||
let expectedCircleColorValue = MGLStyleValue<NSColor>(
|
||||
interpolationMode: .exponential,
|
||||
cameraStops: redGreenStops,
|
||||
options: [.interpolationBase: 10.0]
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedCircleColorValue
|
||||
XCTAssertEqual(circleStyleLayer.circleColor, expectedCircleColorValue)
|
||||
|
||||
// data-driven, source function with categorical color stop values with string typed keys
|
||||
let redOnlyStops = [
|
||||
"red": MGLStyleValue<NSColor>(rawValue: .red)
|
||||
]
|
||||
let expectedRedCategoricalValue = MGLStyleValue<NSColor>(
|
||||
interpolationMode: .categorical,
|
||||
|
||||
sourceStops: redOnlyStops,
|
||||
attributeName: "red",
|
||||
options: [.defaultValue: MGLStyleValue<NSColor>(rawValue: .cyan)]
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedRedCategoricalValue
|
||||
XCTAssertEqual(circleStyleLayer.circleColor, expectedRedCategoricalValue)
|
||||
|
||||
// data-driven, source function with categorical color stop values with integer attribute keys
|
||||
let greenOrangeStops = [
|
||||
0: MGLStyleValue<NSColor>(rawValue: .green),
|
||||
100: MGLStyleValue<NSColor>(rawValue: .orange)
|
||||
]
|
||||
let expectedGreenOrangeCategoricalValue = MGLStyleValue<NSColor>(
|
||||
interpolationMode: .categorical,
|
||||
sourceStops: greenOrangeStops,
|
||||
attributeName: "temp",
|
||||
options: [.defaultValue: MGLStyleValue<NSColor>(rawValue: .red)]
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedGreenOrangeCategoricalValue
|
||||
XCTAssertEqual(circleStyleLayer.circleColor, expectedGreenOrangeCategoricalValue)
|
||||
|
||||
// data-driven, source function with exponential color stop values
|
||||
let expectedRedGreenSourceExponentialValue = MGLStyleValue<NSColor>(
|
||||
interpolationMode: .exponential,
|
||||
sourceStops: redGreenStops,
|
||||
attributeName: "temp",
|
||||
options: nil
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedRedGreenSourceExponentialValue
|
||||
XCTAssertEqual(circleStyleLayer.circleColor, expectedRedGreenSourceExponentialValue)
|
||||
|
||||
// data-driven, identity source function
|
||||
let expectedSourceIdentityValue = MGLStyleValue<NSColor>(
|
||||
interpolationMode: .identity,
|
||||
sourceStops: nil,
|
||||
attributeName: "size",
|
||||
options: nil
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedSourceIdentityValue
|
||||
XCTAssertEqual(circleStyleLayer.circleColor, expectedSourceIdentityValue)
|
||||
|
||||
#endif
|
||||
|
||||
// data-driven, camera function with exponential color stop values
|
||||
let redGreenStops : [Float:MGLStyleValue<MGLColor>] = [
|
||||
0: MGLStyleValue<MGLColor>(rawValue: .red),
|
||||
10: MGLStyleValue<MGLColor>(rawValue: .red),
|
||||
15: MGLStyleValue<MGLColor>(rawValue: .green)
|
||||
]
|
||||
let expectedCircleColorValue = MGLStyleValue<MGLColor>(
|
||||
interpolationMode: .exponential,
|
||||
cameraStops: redGreenStops,
|
||||
options: [.interpolationBase: 10.0]
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedCircleColorValue
|
||||
assertColorValuesEqual(circleStyleLayer.circleColor as! MGLStyleFunction<MGLColor>, expectedCircleColorValue as! MGLStyleFunction<MGLColor>)
|
||||
|
||||
// data-driven, source function with categorical color stop values with string attribute keys
|
||||
let redOnlyStops = [
|
||||
"red": MGLStyleValue<MGLColor>(rawValue: .red)
|
||||
]
|
||||
let expectedRedCategoricalValue = MGLStyleValue<MGLColor>(
|
||||
interpolationMode: .categorical,
|
||||
sourceStops: redOnlyStops,
|
||||
attributeName: "red",
|
||||
options: [.defaultValue: MGLStyleValue<MGLColor>(rawValue: .cyan)]
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedRedCategoricalValue
|
||||
assertColorValuesEqual(circleStyleLayer.circleColor, expectedRedCategoricalValue)
|
||||
|
||||
// data-driven, source function with categorical color stop values with integer attribute keys
|
||||
let greenOrangeStops : [Float:MGLStyleValue<MGLColor>] = [
|
||||
0: MGLStyleValue<MGLColor>(rawValue: .green),
|
||||
100: MGLStyleValue<MGLColor>(rawValue: .orange)
|
||||
]
|
||||
let expectedGreenOrangeCategoricalValue = MGLStyleValue<MGLColor>(
|
||||
interpolationMode: .categorical,
|
||||
sourceStops: greenOrangeStops,
|
||||
attributeName: "temp",
|
||||
options: [.defaultValue: MGLStyleValue<MGLColor>(rawValue: .red)]
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedGreenOrangeCategoricalValue
|
||||
assertColorValuesEqual(circleStyleLayer.circleColor, expectedGreenOrangeCategoricalValue)
|
||||
|
||||
// data-driven, source function with exponential color stop values
|
||||
let expectedRedGreenSourceExponentialValue = MGLStyleValue<MGLColor>(
|
||||
interpolationMode: .exponential,
|
||||
sourceStops: redGreenStops,
|
||||
attributeName: "temp",
|
||||
options: nil
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedRedGreenSourceExponentialValue
|
||||
assertColorValuesEqual(circleStyleLayer.circleColor, expectedRedGreenSourceExponentialValue)
|
||||
|
||||
// data-driven, identity source function
|
||||
let expectedSourceIdentityValue = MGLStyleValue<MGLColor>(
|
||||
interpolationMode: .identity,
|
||||
sourceStops: nil,
|
||||
attributeName: "size",
|
||||
options: [.defaultValue: MGLStyleValue<MGLColor>(rawValue: .green)]
|
||||
)
|
||||
circleStyleLayer.circleColor = expectedSourceIdentityValue
|
||||
assertColorValuesEqual(circleStyleLayer.circleColor, expectedSourceIdentityValue)
|
||||
|
||||
// data-driven, source function with categorical color stop values with boolean attribute keys
|
||||
let booleanCategoricalStops = [
|
||||
@@ -223,7 +235,7 @@ extension MGLStyleValueTests {
|
||||
let smallRadius = MGLStyleValue<NSNumber>(rawValue: 5)
|
||||
let mediumRadius = MGLStyleValue<NSNumber>(rawValue: 10)
|
||||
let largeRadius = MGLStyleValue<NSNumber>(rawValue: 20)
|
||||
let radiusCompositeCategoricalStops: [NSNumber: [String: MGLStyleValue<NSNumber>]] = [
|
||||
let radiusCompositeCategoricalStops: [Float: [String: MGLStyleValue<NSNumber>]] = [
|
||||
0: ["green": smallRadius],
|
||||
10: ["green": smallRadius],
|
||||
15: ["green": largeRadius],
|
||||
@@ -240,7 +252,7 @@ extension MGLStyleValueTests {
|
||||
XCTAssertEqual(circleStyleLayer.circleRadius, expectedCompositeCategoricalValue)
|
||||
|
||||
// data-driven, composite function with inner exponential color stop values nested in outer camera stops
|
||||
let radiusCompositeExponentialOrIntervalStops: [NSNumber: [NSNumber: MGLStyleValue<NSNumber>]] = [
|
||||
let radiusCompositeExponentialOrIntervalStops: [Float: [Float: MGLStyleValue<NSNumber>]] = [
|
||||
0: [0: smallRadius],
|
||||
10: [200: smallRadius],
|
||||
20: [200: largeRadius]
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1753ED421E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; };
|
||||
1753ED431E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; };
|
||||
30E578171DAA85520050F07E /* UIImage+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E578111DAA7D690050F07E /* UIImage+MGLAdditions.h */; };
|
||||
30E578181DAA85520050F07E /* UIImage+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E578111DAA7D690050F07E /* UIImage+MGLAdditions.h */; };
|
||||
30E578191DAA855E0050F07E /* UIImage+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 30E578121DAA7D690050F07E /* UIImage+MGLAdditions.mm */; };
|
||||
@@ -518,6 +520,7 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1753ED411E53CE6F00A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = "<group>"; };
|
||||
20DABE861DF78148007AC5FF /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Foundation.strings"; sourceTree = "<group>"; };
|
||||
20DABE881DF78148007AC5FF /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
20DABE8A1DF78149007AC5FF /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Root.strings"; sourceTree = "<group>"; };
|
||||
@@ -947,6 +950,7 @@
|
||||
35599DA21D4682B60048254D /* Styling */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1753ED411E53CE6F00A9FD90 /* MGLConversion.h */,
|
||||
35599DB81D46AD7F0048254D /* Categories */,
|
||||
353933F01D3FB6BA003F57D7 /* Layers */,
|
||||
35136D491D4277EA00C20EFD /* Sources */,
|
||||
@@ -1574,6 +1578,7 @@
|
||||
DAD1656C1CF41981001FF4B9 /* MGLFeature.h in Headers */,
|
||||
40EDA1C01CFE0E0200D9EA68 /* MGLAnnotationContainerView.h in Headers */,
|
||||
DA88484F1CBAFB9800AB86E3 /* MGLAnnotationImage_Private.h in Headers */,
|
||||
1753ED421E53CE6F00A9FD90 /* MGLConversion.h in Headers */,
|
||||
DA8847F21CBAFA5100AB86E3 /* MGLMapCamera.h in Headers */,
|
||||
3538AA1D1D542239008EC33D /* MGLForegroundStyleLayer.h in Headers */,
|
||||
DA8847F51CBAFA5100AB86E3 /* MGLOfflineRegion.h in Headers */,
|
||||
@@ -1659,6 +1664,7 @@
|
||||
DAF0D8141DFE0EC500B28378 /* MGLVectorSource_Private.h in Headers */,
|
||||
DABFB8731CBE9A9900D62B32 /* Mapbox.h in Headers */,
|
||||
357FE2DE1E02D2B20068B753 /* NSCoder+MGLAdditions.h in Headers */,
|
||||
1753ED431E53CE6F00A9FD90 /* MGLConversion.h in Headers */,
|
||||
354B83971D2E873E005D9406 /* MGLUserLocationAnnotationView.h in Headers */,
|
||||
DAF0D8111DFE0EA000B28378 /* MGLRasterSource_Private.h in Headers */,
|
||||
DABFB86B1CBE99E500D62B32 /* MGLTilePyramidOfflineRegion.h in Headers */,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1753ED401E53CE6100A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */; };
|
||||
30E5781B1DAA857E0050F07E /* NSImage+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E578141DAA7D920050F07E /* NSImage+MGLAdditions.h */; };
|
||||
3508EC641D749D39009B0EE4 /* NSExpression+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 3508EC621D749D39009B0EE4 /* NSExpression+MGLAdditions.h */; };
|
||||
3508EC651D749D39009B0EE4 /* NSExpression+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3508EC631D749D39009B0EE4 /* NSExpression+MGLAdditions.mm */; };
|
||||
@@ -258,6 +259,7 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = "<group>"; };
|
||||
30E578141DAA7D920050F07E /* NSImage+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSImage+MGLAdditions.h"; path = "src/NSImage+MGLAdditions.h"; sourceTree = SOURCE_ROOT; };
|
||||
3508EC621D749D39009B0EE4 /* NSExpression+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSExpression+MGLAdditions.h"; sourceTree = "<group>"; };
|
||||
3508EC631D749D39009B0EE4 /* NSExpression+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSExpression+MGLAdditions.mm"; sourceTree = "<group>"; };
|
||||
@@ -613,6 +615,7 @@
|
||||
3527429B1D4C259500A1ECE6 /* Styling */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */,
|
||||
352742791D4C235C00A1ECE6 /* Categories */,
|
||||
35136D471D42295400C20EFD /* Layers */,
|
||||
3527427E1D4C242B00A1ECE6 /* Sources */,
|
||||
@@ -1007,6 +1010,7 @@
|
||||
3508EC641D749D39009B0EE4 /* NSExpression+MGLAdditions.h in Headers */,
|
||||
DAE6C38D1CC31E2A00DB3429 /* MGLOfflineRegion_Private.h in Headers */,
|
||||
DA7DC9831DED647F0027472F /* MGLRasterSource_Private.h in Headers */,
|
||||
1753ED401E53CE6100A9FD90 /* MGLConversion.h in Headers */,
|
||||
408AA8651DAEEE3400022900 /* MGLPolygon+MGLAdditions.h in Headers */,
|
||||
DA8F259C1D51CB000010E6B5 /* MGLStyleValue_Private.h in Headers */,
|
||||
DAE6C35B1CC31E0400DB3429 /* MGLAnnotation.h in Headers */,
|
||||
|
||||
Reference in New Issue
Block a user