#import "MGLVectorTileSource_Private.h" #import "MGLFeature_Private.h" #import "MGLSource_Private.h" #import "MGLTileSource_Private.h" #import "MGLStyle_Private.h" #import "MGLMapView_Private.h" #import "NSPredicate+MGLPrivateAdditions.h" #import "NSURL+MGLAdditions.h" #include #include #include @interface MGLVectorTileSource () @property (nonatomic, readonly) mbgl::style::VectorSource *rawSource; @end @implementation MGLVectorTileSource - (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL { auto source = std::make_unique(identifier.UTF8String, configurationURL.mgl_URLByStandardizingScheme.absoluteString.UTF8String); return self = [super initWithPendingSource:std::move(source)]; } - (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray *)tileURLTemplates options:(nullable NSDictionary *)options { mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options); auto source = std::make_unique(identifier.UTF8String, tileSet); return self = [super initWithPendingSource:std::move(source)]; } - (mbgl::style::VectorSource *)rawSource { return (mbgl::style::VectorSource *)super.rawSource; } - (NSURL *)configurationURL { auto url = self.rawSource->getURL(); return url ? [NSURL URLWithString:@(url->c_str())] : nil; } - (NSString *)attributionHTMLString { auto attribution = self.rawSource->getAttribution(); return attribution ? @(attribution->c_str()) : nil; } - (NSArray> *)featuresInSourceLayersWithIdentifiers:(NSSet *)sourceLayerIdentifiers predicate:(nullable NSPredicate *)predicate { mbgl::optional> optionalSourceLayerIDs; if (sourceLayerIdentifiers) { __block std::vector layerIDs; layerIDs.reserve(sourceLayerIdentifiers.count); [sourceLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) { layerIDs.push_back(identifier.UTF8String); }]; optionalSourceLayerIDs = layerIDs; } mbgl::optional optionalFilter; if (predicate) { optionalFilter = predicate.mgl_filter; } std::vector features; if (self.mapView) { features = self.mapView.renderer->querySourceFeatures(self.rawSource->getID(), { optionalSourceLayerIDs, optionalFilter }); } return MGLFeaturesFromMBGLFeatures(features); } @end @implementation MGLVectorTileSource (Private) /** An array of locale codes with dedicated name fields in the Mapbox Streets source. https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview */ static NSArray * const MGLMapboxStreetsLanguages = @[ @"ar", @"de", @"en", @"es", @"fr", @"pt", @"ru", @"zh", @"zh-Hans", ]; /** Like `MGLMapboxStreetsLanguages`, but deanglicized for use with `+[NSBundle preferredLocalizationsFromArray:forPreferences:]`. */ static NSArray * const MGLMapboxStreetsAlternativeLanguages = @[ @"mul", @"ar", @"de", @"es", @"fr", @"pt", @"ru", @"zh", @"zh-Hans", ]; + (NSSet *)mapboxStreetsLanguages { static dispatch_once_t onceToken; static NSSet *mapboxStreetsLanguages; dispatch_once(&onceToken, ^{ mapboxStreetsLanguages = [NSSet setWithArray:MGLMapboxStreetsLanguages]; }); return mapboxStreetsLanguages; } + (NSString *)preferredMapboxStreetsLanguage { return [self preferredMapboxStreetsLanguageForPreferences:[NSLocale preferredLanguages]]; } + (NSString *)preferredMapboxStreetsLanguageForPreferences:(NSArray *)preferencesArray { BOOL acceptsEnglish = [preferencesArray filteredArrayUsingPredicate: [NSPredicate predicateWithBlock:^BOOL(NSString * _Nullable language, NSDictionary * _Nullable bindings) { return [[NSLocale localeWithLocaleIdentifier:language].languageCode isEqualToString:@"en"]; }]].count; NSArray *availableLanguages = acceptsEnglish ? MGLMapboxStreetsLanguages : MGLMapboxStreetsAlternativeLanguages; NSArray *preferredLanguages = [NSBundle preferredLocalizationsFromArray:availableLanguages forPreferences:preferencesArray]; NSString *mostSpecificLanguage; for (NSString *language in preferredLanguages) { if (language.length > mostSpecificLanguage.length) { mostSpecificLanguage = language; } } return [mostSpecificLanguage isEqualToString:@"mul"] ? nil : mostSpecificLanguage; } - (BOOL)isMapboxStreets { NSURL *url = self.configurationURL; if (![url.scheme isEqualToString:@"mapbox"]) { return NO; } NSArray *identifiers = [url.host componentsSeparatedByString:@","]; return [identifiers containsObject:@"mapbox.mapbox-streets-v7"] || [identifiers containsObject:@"mapbox.mapbox-streets-v6"]; } @end