diff options
author | Fredrik Karlsson <bjorn.fredrik.karlsson@gmail.com> | 2016-08-17 13:38:02 +0200 |
---|---|---|
committer | Fredrik Karlsson <bjorn.fredrik.karlsson@gmail.com> | 2016-09-02 22:42:05 +0200 |
commit | d77a13eb7320722c48c8a18240adf99615c4b85f (patch) | |
tree | 1017781b310e434f943e4ad38b57f319ad7a3a58 /platform/darwin/src | |
parent | 6a39cf5aaece81c7a531b12321dd503004cc45b8 (diff) | |
download | qtlocation-mapboxgl-d77a13eb7320722c48c8a18240adf99615c4b85f.tar.gz |
[ios] Added support for filters (NSPredicate)
[ios, macos] cleaned up filters
[ios] added a filter example
[ios] utest filters
[ios, macos] nested predicates
[ios] refactored
[ios] filter -> NSPredicate
[ios] fixed mbgl::Any/AllFilter -> NSPredicate
[ios] translate nested mbgl::NotIn filters
[ios] cleanup and added more utests
[ios] fixed a bug in the None filter conversion and improved utests
[ios, macos] doc
[macos] added missing category
[ios, macos] additional utests
[ios, macos] updated documentation
Diffstat (limited to 'platform/darwin/src')
21 files changed, 462 insertions, 47 deletions
diff --git a/platform/darwin/src/MGLBaseStyleLayer_Private.h b/platform/darwin/src/MGLBaseStyleLayer_Private.h index e3d43906a4..0cbb076b35 100644 --- a/platform/darwin/src/MGLBaseStyleLayer_Private.h +++ b/platform/darwin/src/MGLBaseStyleLayer_Private.h @@ -1,5 +1,7 @@ #import "MGLBaseStyleLayer.h" +#import "NSPredicate+MGLAdditions.h" + @interface MGLBaseStyleLayer (MGLBaseStyleLayer_Private) - (void)update; diff --git a/platform/darwin/src/MGLCircleStyleLayer.h b/platform/darwin/src/MGLCircleStyleLayer.h index 7d2ef05848..e4430044ad 100644 --- a/platform/darwin/src/MGLCircleStyleLayer.h +++ b/platform/darwin/src/MGLCircleStyleLayer.h @@ -18,6 +18,14 @@ typedef NS_ENUM(NSUInteger, MGLCircleStyleLayerCirclePitchScale) { @interface MGLCircleStyleLayer : MGLBaseStyleLayer <MGLStyleLayer> +/** + A predicate that corresponds to the layer's <a href='https://www.mapbox.com/mapbox-gl-style-spec/#types-filter'>filter</a>. + + The predicate's left expression must be a string that identifies a feature + property, or one of the special keys. + */ +@property (nonatomic, nullable) NSPredicate *predicate; + #pragma mark - Accessing the Paint Attributes /** diff --git a/platform/darwin/src/MGLCircleStyleLayer.mm b/platform/darwin/src/MGLCircleStyleLayer.mm index 27be01505c..6c038318cc 100644 --- a/platform/darwin/src/MGLCircleStyleLayer.mm +++ b/platform/darwin/src/MGLCircleStyleLayer.mm @@ -29,6 +29,16 @@ return self; } +- (void)setPredicate:(NSPredicate *)predicate +{ + self.layer->setFilter(predicate.mgl_filter); +} + +- (NSPredicate *)predicate +{ + return [NSPredicate mgl_predicateWithFilter:self.layer->getFilter()]; +} + #pragma mark - Accessing the Paint Attributes - (void)setCircleRadius:(id <MGLStyleAttributeValue, MGLStyleAttributeValue_Private>)circleRadius { diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm index 3bf1e61153..6d4f76a71d 100644 --- a/platform/darwin/src/MGLFeature.mm +++ b/platform/darwin/src/MGLFeature.mm @@ -3,6 +3,7 @@ #import "MGLPointAnnotation.h" #import "MGLPolyline.h" #import "MGLPolygon.h" +#import "MGLValueEvaluator.h" #import "MGLMultiPoint_Private.h" @@ -113,51 +114,7 @@ @end -/** - Recursively transforms a C++ type into the corresponding Foundation type. - */ -class PropertyValueEvaluator { -public: - id operator()(const mbgl::NullValue &) const { - return [NSNull null]; - } - - id operator()(const bool &value) const { - return value ? @YES : @NO; - } - - id operator()(const uint64_t &value) const { - return @(value); - } - - id operator()(const int64_t &value) const { - return @(value); - } - - id operator()(const double &value) const { - return @(value); - } - - id operator()(const std::string &value) const { - return @(value.c_str()); - } - - id operator()(const std::vector<mbgl::Value> &values) const { - NSMutableArray *objects = [NSMutableArray arrayWithCapacity:values.size()]; - for (const auto &v : values) { - [objects addObject:mbgl::Value::visit(v, *this)]; - } - return objects; - } - - id operator()(const std::unordered_map<std::string, mbgl::Value> &items) const { - NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:items.size()]; - for (auto &item : items) { - attributes[@(item.first.c_str())] = mbgl::Value::visit(item.second, *this); - } - return attributes; - } -}; + /** Transforms an `mbgl::geometry::geometry` type into an instance of the @@ -253,14 +210,14 @@ NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vec NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:feature.properties.size()]; for (auto &pair : feature.properties) { auto &value = pair.second; - PropertyValueEvaluator evaluator; + ValueEvaluator evaluator; attributes[@(pair.first.c_str())] = mbgl::Value::visit(value, evaluator); } GeometryEvaluator<double> evaluator; MGLShape <MGLFeaturePrivate> *shape = mapbox::geometry::geometry<double>::visit(feature.geometry, evaluator); if (feature.id) { - shape.identifier = mbgl::FeatureIdentifier::visit(*feature.id, PropertyValueEvaluator()); + shape.identifier = mbgl::FeatureIdentifier::visit(*feature.id, ValueEvaluator()); } shape.attributes = attributes; [shapes addObject:shape]; diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h index c03e8ecae1..2d51f071e5 100644 --- a/platform/darwin/src/MGLFillStyleLayer.h +++ b/platform/darwin/src/MGLFillStyleLayer.h @@ -13,6 +13,14 @@ typedef NS_ENUM(NSUInteger, MGLFillStyleLayerFillTranslateAnchor) { @interface MGLFillStyleLayer : MGLBaseStyleLayer <MGLStyleLayer> +/** + A predicate that corresponds to the layer's <a href='https://www.mapbox.com/mapbox-gl-style-spec/#types-filter'>filter</a>. + + The predicate's left expression must be a string that identifies a feature + property, or one of the special keys. + */ +@property (nonatomic, nullable) NSPredicate *predicate; + #pragma mark - Accessing the Paint Attributes /** diff --git a/platform/darwin/src/MGLFillStyleLayer.mm b/platform/darwin/src/MGLFillStyleLayer.mm index 192235f69e..c54ddba428 100644 --- a/platform/darwin/src/MGLFillStyleLayer.mm +++ b/platform/darwin/src/MGLFillStyleLayer.mm @@ -29,6 +29,16 @@ return self; } +- (void)setPredicate:(NSPredicate *)predicate +{ + self.layer->setFilter(predicate.mgl_filter); +} + +- (NSPredicate *)predicate +{ + return [NSPredicate mgl_predicateWithFilter:self.layer->getFilter()]; +} + #pragma mark - Accessing the Paint Attributes - (void)setFillAntialias:(id <MGLStyleAttributeValue, MGLStyleAttributeValue_Private>)fillAntialias { diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h index 435829c502..5c2a3afc2e 100644 --- a/platform/darwin/src/MGLLineStyleLayer.h +++ b/platform/darwin/src/MGLLineStyleLayer.h @@ -25,6 +25,14 @@ typedef NS_ENUM(NSUInteger, MGLLineStyleLayerLineTranslateAnchor) { @interface MGLLineStyleLayer : MGLBaseStyleLayer <MGLStyleLayer> +/** + A predicate that corresponds to the layer's <a href='https://www.mapbox.com/mapbox-gl-style-spec/#types-filter'>filter</a>. + + The predicate's left expression must be a string that identifies a feature + property, or one of the special keys. + */ +@property (nonatomic, nullable) NSPredicate *predicate; + #pragma mark - Accessing the Layout Attributes /** diff --git a/platform/darwin/src/MGLLineStyleLayer.mm b/platform/darwin/src/MGLLineStyleLayer.mm index ffb0d4e394..ce9ad75f87 100644 --- a/platform/darwin/src/MGLLineStyleLayer.mm +++ b/platform/darwin/src/MGLLineStyleLayer.mm @@ -29,6 +29,16 @@ return self; } +- (void)setPredicate:(NSPredicate *)predicate +{ + self.layer->setFilter(predicate.mgl_filter); +} + +- (NSPredicate *)predicate +{ + return [NSPredicate mgl_predicateWithFilter:self.layer->getFilter()]; +} + #pragma mark - Accessing the Layout Attributes - (void)setLineCap:(id <MGLStyleAttributeValue, MGLStyleAttributeValue_Private>)lineCap { diff --git a/platform/darwin/src/MGLStyleLayer.h.ejs b/platform/darwin/src/MGLStyleLayer.h.ejs index 2b36a3067a..8acda024c4 100644 --- a/platform/darwin/src/MGLStyleLayer.h.ejs +++ b/platform/darwin/src/MGLStyleLayer.h.ejs @@ -35,6 +35,16 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(type) %>StyleLayer<%- camelize(prope <% } -%> @interface MGL<%- camelize(type) %>StyleLayer : MGLBaseStyleLayer <MGLStyleLayer> +<% if (type !== 'background' && type !== 'raster') { -%> +/** + A predicate that corresponds to the layer's <a href='https://www.mapbox.com/mapbox-gl-style-spec/#types-filter'>filter</a>. + + The predicate's left expression must be a string that identifies a feature + property, or one of the special keys. + */ +@property (nonatomic, nullable) NSPredicate *predicate; + +<% } -%> <% if (layoutProperties.length) { -%> #pragma mark - Accessing the Layout Attributes @@ -53,6 +63,7 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(type) %>StyleLayer<%- camelize(prope <% } -%> <% } -%> +<% if (paintProperties.length) { -%> #pragma mark - Accessing the Paint Attributes <% for (const property of paintProperties) { -%> @@ -69,6 +80,7 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(type) %>StyleLayer<%- camelize(prope @property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) <%- propertyType(property, false, type) %> <%- camelizeWithLeadingLowercase(property.name) %>; <% } -%> +<% } -%> @end NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLStyleLayer.mm.ejs b/platform/darwin/src/MGLStyleLayer.mm.ejs index c35d254caf..4e59c3c6cb 100644 --- a/platform/darwin/src/MGLStyleLayer.mm.ejs +++ b/platform/darwin/src/MGLStyleLayer.mm.ejs @@ -34,6 +34,18 @@ return self; } +<% if (type !== 'background' && type !== 'raster') { -%> +- (void)setPredicate:(NSPredicate *)predicate +{ + self.layer->setFilter(predicate.mgl_filter); +} + +- (NSPredicate *)predicate +{ + return [NSPredicate mgl_predicateWithFilter:self.layer->getFilter()]; +} + +<% } -%> <% if (layoutProperties.length) { -%> #pragma mark - Accessing the Layout Attributes diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h index ef88ff996e..eacd158dda 100644 --- a/platform/darwin/src/MGLSymbolStyleLayer.h +++ b/platform/darwin/src/MGLSymbolStyleLayer.h @@ -69,6 +69,14 @@ typedef NS_ENUM(NSUInteger, MGLSymbolStyleLayerTextTranslateAnchor) { @interface MGLSymbolStyleLayer : MGLBaseStyleLayer <MGLStyleLayer> +/** + A predicate that corresponds to the layer's <a href='https://www.mapbox.com/mapbox-gl-style-spec/#types-filter'>filter</a>. + + The predicate's left expression must be a string that identifies a feature + property, or one of the special keys. + */ +@property (nonatomic, nullable) NSPredicate *predicate; + #pragma mark - Accessing the Layout Attributes /** diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm index 159e3c4d0b..b0553ea425 100644 --- a/platform/darwin/src/MGLSymbolStyleLayer.mm +++ b/platform/darwin/src/MGLSymbolStyleLayer.mm @@ -29,6 +29,16 @@ return self; } +- (void)setPredicate:(NSPredicate *)predicate +{ + self.layer->setFilter(predicate.mgl_filter); +} + +- (NSPredicate *)predicate +{ + return [NSPredicate mgl_predicateWithFilter:self.layer->getFilter()]; +} + #pragma mark - Accessing the Layout Attributes - (void)setSymbolPlacement:(id <MGLStyleAttributeValue, MGLStyleAttributeValue_Private>)symbolPlacement { diff --git a/platform/darwin/src/MGLValueEvaluator.h b/platform/darwin/src/MGLValueEvaluator.h new file mode 100644 index 0000000000..b53cdaa8d2 --- /dev/null +++ b/platform/darwin/src/MGLValueEvaluator.h @@ -0,0 +1,49 @@ +#import <Foundation/Foundation.h> + +#import <mbgl/util/geometry.hpp> + +/** + Recursively transforms a C++ type into the corresponding Foundation type. + */ +class ValueEvaluator { +public: + id operator()(const mbgl::NullValue &) const { + return [NSNull null]; + } + + id operator()(const bool &value) const { + return value ? @YES : @NO; + } + + id operator()(const uint64_t &value) const { + return @(value); + } + + id operator()(const int64_t &value) const { + return @(value); + } + + id operator()(const double &value) const { + return @(value); + } + + id operator()(const std::string &value) const { + return @(value.c_str()); + } + + id operator()(const std::vector<mbgl::Value> &values) const { + NSMutableArray *objects = [NSMutableArray arrayWithCapacity:values.size()]; + for (const auto &v : values) { + [objects addObject:mbgl::Value::visit(v, *this)]; + } + return objects; + } + + id operator()(const std::unordered_map<std::string, mbgl::Value> &items) const { + NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:items.size()]; + for (auto &item : items) { + attributes[@(item.first.c_str())] = mbgl::Value::visit(item.second, *this); + } + return attributes; + } +}; diff --git a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.h b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.h new file mode 100644 index 0000000000..2cd4dd1577 --- /dev/null +++ b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.h @@ -0,0 +1,7 @@ +#import <Foundation/Foundation.h> + +#include <mbgl/style/filter.hpp> + +@interface NSComparisonPredicate (MGLAdditions) + +@end diff --git a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm new file mode 100644 index 0000000000..ced6a1ac47 --- /dev/null +++ b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm @@ -0,0 +1,67 @@ +#import "NSComparisonPredicate+MGLAdditions.h" + +#import "NSPredicate+MGLAdditions.h" +#import "NSExpression+MGLAdditions.h" + +@implementation NSComparisonPredicate (MGLAdditions) + +- (mbgl::style::Filter)mgl_filter +{ + switch (self.predicateOperatorType) { + case NSEqualToPredicateOperatorType: { + auto filter = mbgl::style::EqualsFilter(); + filter.key = self.leftExpression.keyPath.UTF8String; + filter.value = self.rightExpression.mgl_filterValue; + return filter; + } + case NSNotEqualToPredicateOperatorType: { + auto filter = mbgl::style::NotEqualsFilter(); + filter.key = self.leftExpression.keyPath.UTF8String; + filter.value = self.rightExpression.mgl_filterValue; + return filter; + } + case NSGreaterThanPredicateOperatorType: { + auto filter = mbgl::style::GreaterThanFilter(); + filter.key = self.leftExpression.keyPath.UTF8String; + filter.value = self.rightExpression.mgl_filterValue; + return filter; + } + case NSGreaterThanOrEqualToPredicateOperatorType: { + auto filter = mbgl::style::GreaterThanEqualsFilter(); + filter.key = self.leftExpression.keyPath.UTF8String; + filter.value = self.rightExpression.mgl_filterValue; + return filter; + } + case NSLessThanPredicateOperatorType: { + auto filter = mbgl::style::LessThanFilter(); + filter.key = self.leftExpression.keyPath.UTF8String; + filter.value = self.rightExpression.mgl_filterValue; + return filter; + } + case NSLessThanOrEqualToPredicateOperatorType: { + auto filter = mbgl::style::LessThanEqualsFilter(); + filter.key = self.leftExpression.keyPath.UTF8String; + filter.value = self.rightExpression.mgl_filterValue; + return filter; + } + case NSInPredicateOperatorType: { + auto filter = mbgl::style::InFilter(); + filter.key = self.leftExpression.keyPath.UTF8String; + filter.values = self.rightExpression.mgl_filterValues; + return filter; + } + case NSMatchesPredicateOperatorType: + case NSLikePredicateOperatorType: + case NSBeginsWithPredicateOperatorType: + case NSEndsWithPredicateOperatorType: + case NSCustomSelectorPredicateOperatorType: + case NSContainsPredicateOperatorType: + case NSBetweenPredicateOperatorType: + [NSException raise:@"Unsupported operator type" + format:@"NSPredicateOperatorType:%lu is not supported.", (unsigned long)self.predicateOperatorType]; + } + + return {}; +} + +@end diff --git a/platform/darwin/src/NSCompoundPredicate+MGLAdditions.h b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.h new file mode 100644 index 0000000000..0f9909255d --- /dev/null +++ b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.h @@ -0,0 +1,7 @@ +#import <Foundation/Foundation.h> + +#include <mbgl/style/filter.hpp> + +@interface NSCompoundPredicate (MGLAdditions) + +@end diff --git a/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm new file mode 100644 index 0000000000..07114308c9 --- /dev/null +++ b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm @@ -0,0 +1,56 @@ +#import "NSCompoundPredicate+MGLAdditions.h" + +#import "NSPredicate+MGLAdditions.h" +#import "NSExpression+MGLAdditions.h" + +@implementation NSCompoundPredicate (MGLAdditions) + +- (std::vector<mbgl::style::Filter>)mgl_subfilters +{ + std::vector<mbgl::style::Filter>filters; + for (NSPredicate *predicate in self.subpredicates) { + filters.push_back(predicate.mgl_filter); + } + return filters; +} + +- (mbgl::style::Filter)mgl_filter +{ + switch (self.compoundPredicateType) { + case NSNotPredicateType: { + + // Translate a nested NSComparisonPredicate with operator type NSInPredicateOperatorType into a flat mbgl::NotIn filter. + NSArray<NSComparisonPredicate *> *comparisonPredicates = [self.subpredicates filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"class == %@", [NSComparisonPredicate class]]]; + NSArray<NSComparisonPredicate *> *notInPredicates = [comparisonPredicates filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSComparisonPredicate *_Nonnull predicate, NSDictionary<NSString *,id> * _Nullable bindings) { + return predicate.predicateOperatorType == NSInPredicateOperatorType; + }]]; + + if (notInPredicates.count) { + auto filter = mbgl::style::NotInFilter(); + filter.key = notInPredicates.firstObject.leftExpression.keyPath.UTF8String; + filter.values = notInPredicates.firstObject.rightExpression.mgl_filterValues; + return filter; + } else { + auto filter = mbgl::style::NoneFilter(); + filter.filters = [self mgl_subfilters]; + return filter; + } + } + case NSAndPredicateType: { + auto filter = mbgl::style::AllFilter(); + filter.filters = [self mgl_subfilters]; + return filter; + } + case NSOrPredicateType: { + auto filter = mbgl::style::AnyFilter(); + filter.filters = [self mgl_subfilters]; + return filter; + } + } + + [NSException raise:@"Compound predicate type not handled" + format:@""]; + return {}; +} + +@end diff --git a/platform/darwin/src/NSExpression+MGLAdditions.h b/platform/darwin/src/NSExpression+MGLAdditions.h new file mode 100644 index 0000000000..4e8c5ee071 --- /dev/null +++ b/platform/darwin/src/NSExpression+MGLAdditions.h @@ -0,0 +1,11 @@ +#import <Foundation/Foundation.h> + +#include <mbgl/style/filter.hpp> + +@interface NSExpression (MGLAdditions) + +- (mbgl::Value)mgl_filterValue; + +- (std::vector<mbgl::Value>)mgl_filterValues; + +@end diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm new file mode 100644 index 0000000000..5f1a1e765a --- /dev/null +++ b/platform/darwin/src/NSExpression+MGLAdditions.mm @@ -0,0 +1,43 @@ +#import "NSExpression+MGLAdditions.h" + +@implementation NSExpression (MGLAdditions) + +- (std::vector<mbgl::Value>)mgl_filterValues +{ + if ([self.constantValue isKindOfClass:NSArray.class]) { + NSArray *values = self.constantValue; + std::vector<mbgl::Value>convertedValues; + for (id value in values) { + convertedValues.push_back([self mgl_convertedValueWithValue:value]); + } + return convertedValues; + } + [NSException raise:@"Values not handled" format:@""]; + return { }; +} + +- (mbgl::Value)mgl_filterValue +{ + return [self mgl_convertedValueWithValue:self.constantValue]; +} + +- (mbgl::Value)mgl_convertedValueWithValue:(id)value +{ + if ([value isKindOfClass:NSString.class]) { + return { std::string([(NSString *)value UTF8String]) }; + } else if ([value isKindOfClass:NSNumber.class]) { + NSNumber *number = (NSNumber *)value; + if((strcmp([number objCType], @encode(int))) == 0) { + return { number.intValue }; + } else if ((strcmp([number objCType], @encode(double))) == 0) { + return { number.doubleValue }; + } else if ((strcmp([number objCType], @encode(bool))) == 0) { + return { number.boolValue }; + } + } + [NSException raise:@"Value not handled" + format:@"Can’t convert %s:%@ to mbgl::Value", [value objCType], value]; + return { }; +} + +@end diff --git a/platform/darwin/src/NSPredicate+MGLAdditions.h b/platform/darwin/src/NSPredicate+MGLAdditions.h new file mode 100644 index 0000000000..fd774dd58b --- /dev/null +++ b/platform/darwin/src/NSPredicate+MGLAdditions.h @@ -0,0 +1,13 @@ +#import <Foundation/Foundation.h> + +#import "NSExpression+MGLAdditions.h" +#include <mbgl/style/filter.hpp> + +@interface NSPredicate (MGLAdditions) + +- (mbgl::style::Filter)mgl_filter; + ++ (instancetype)mgl_predicateWithFilter:(mbgl::style::Filter)filter; + +@end + diff --git a/platform/darwin/src/NSPredicate+MGLAdditions.mm b/platform/darwin/src/NSPredicate+MGLAdditions.mm new file mode 100644 index 0000000000..9c3f9c888c --- /dev/null +++ b/platform/darwin/src/NSPredicate+MGLAdditions.mm @@ -0,0 +1,107 @@ +#import "NSPredicate+MGLAdditions.h" + +#import "MGLValueEvaluator.h" + +class FilterEvaluator { +public: + + NSArray* getPredicates(std::vector<mbgl::style::Filter> filters) { + NSMutableArray *predicates = [NSMutableArray arrayWithCapacity:filters.size()]; + for (auto filter : filters) { + [predicates addObject:mbgl::style::Filter::visit(filter, FilterEvaluator())]; + } + return predicates; + } + + NSArray* getValues(std::vector<mbgl::Value> values) { + NSMutableArray *array = [NSMutableArray arrayWithCapacity:values.size()]; + for (auto value : values) { + [array addObject:mbgl::Value::visit(value, ValueEvaluator())]; + } + return array; + } + + NSPredicate* operator()(mbgl::style::NullFilter filter) { + return nil; + } + + NSPredicate* operator()(mbgl::style::EqualsFilter filter) { + return [NSPredicate predicateWithFormat:@"%K == %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())]; + } + + NSPredicate* operator()(mbgl::style::NotEqualsFilter filter) { + return [NSPredicate predicateWithFormat:@"%K != %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())]; + } + + NSPredicate* operator()(mbgl::style::GreaterThanFilter filter) { + return [NSPredicate predicateWithFormat:@"%K > %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())]; + } + + NSPredicate* operator()(mbgl::style::GreaterThanEqualsFilter filter) { + return [NSPredicate predicateWithFormat:@"%K >= %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())]; + } + + NSPredicate* operator()(mbgl::style::LessThanFilter filter) { + return [NSPredicate predicateWithFormat:@"%K < %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())]; + } + + NSPredicate* operator()(mbgl::style::LessThanEqualsFilter filter) { + return [NSPredicate predicateWithFormat:@"%K <= %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())]; + } + + NSPredicate* operator()(mbgl::style::InFilter filter) { + return [NSPredicate predicateWithFormat:@"%K IN %@", @(filter.key.c_str()), getValues(filter.values)]; + } + + NSPredicate* operator()(mbgl::style::NotInFilter filter) { + return [NSPredicate predicateWithFormat:@"NOT %K IN %@", @(filter.key.c_str()), getValues(filter.values)]; + } + + NSPredicate* operator()(mbgl::style::AnyFilter filter) { + return [NSCompoundPredicate orPredicateWithSubpredicates:getPredicates(filter.filters)]; + } + + NSPredicate* operator()(mbgl::style::AllFilter filter) { + return [NSCompoundPredicate andPredicateWithSubpredicates:getPredicates(filter.filters)]; + } + + NSPredicate* operator()(mbgl::style::NoneFilter filter) { + NSArray *predicates = getPredicates(filter.filters); + if (predicates.count > 1) { + NSCompoundPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates]; + return [NSCompoundPredicate notPredicateWithSubpredicate:predicate]; + } else { + return [NSCompoundPredicate notPredicateWithSubpredicate:predicates.firstObject]; + } + } + + NSPredicate* operator()(mbgl::style::HasFilter filter) { + [NSException raise:@"Unsupported filter type" + format:@"Cannot convert mbgl::style::HasFilter to NSPredicate"]; + return nil; + } + + NSPredicate* operator()(mbgl::style::NotHasFilter filter) { + [NSException raise:@"Unsupported filter type" + format:@"Cannot convert mbgl::style::NotHasFilter to NSPredicate"]; + return nil; + } + +}; + +@implementation NSPredicate (MGLAdditions) + +- (mbgl::style::Filter)mgl_filter +{ + [NSException raise:@"Not supported" + format:@"NSPredicate doesn't implement ’-mgl_filter’. Try with NSComparisonPredicate or NSCompoundPredicate instead."]; + return {}; +} + ++ (instancetype)mgl_predicateWithFilter:(mbgl::style::Filter)filter +{ + FilterEvaluator evaluator; + return mbgl::style::Filter::visit(filter, evaluator); +} + +@end |