Skip to content

Commit 3f0f75e

Browse files
Merge pull request #3 from AtlasProgramming/feature/2025-07-raw-bucket
Feature Collections
2 parents 588562e + b9b1240 commit 3f0f75e

19 files changed

Lines changed: 638 additions & 21 deletions

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,10 @@ list(APPEND SRC_FILES
977977
${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_properties.cpp
978978
${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_impl.cpp
979979
${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_factory.cpp
980+
${PROJECT_SOURCE_DIR}/src/mbgl/plugin/feature_collection.hpp
981+
${PROJECT_SOURCE_DIR}/src/mbgl/plugin/feature_collection.cpp
982+
${PROJECT_SOURCE_DIR}/src/mbgl/plugin/feature_collection_bucket.hpp
983+
${PROJECT_SOURCE_DIR}/src/mbgl/plugin/feature_collection_bucket.cpp
980984
)
981985

982986

bazel/core.bzl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ MLN_LAYER_PLUGIN_HEADERS = [
44
"src/mbgl/plugin/plugin_layer_impl.hpp",
55
"src/mbgl/plugin/plugin_layer_render.hpp",
66
"src/mbgl/plugin/plugin_layer_properties.hpp",
7+
"src/mbgl/plugin/feature_collection_bucket.hpp",
8+
"src/mbgl/plugin/feature_collection.hpp",
79
]
810

911
MLN_LAYER_PLUGIN_SOURCE = [
@@ -12,6 +14,8 @@ MLN_LAYER_PLUGIN_SOURCE = [
1214
"src/mbgl/plugin/plugin_layer_impl.cpp",
1315
"src/mbgl/plugin/plugin_layer_render.cpp",
1416
"src/mbgl/plugin/plugin_layer_properties.cpp",
17+
"src/mbgl/plugin/feature_collection_bucket.cpp",
18+
"src/mbgl/plugin/feature_collection.cpp",
1519
]
1620

1721
MLN_PUBLIC_GENERATED_STYLE_HEADERS = [
Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,39 @@
11
#import "PluginLayerExample.h"
22

3+
@interface PluginLayerExample () {
4+
5+
}
6+
7+
@property BOOL logFeatures;
8+
9+
@end
10+
11+
312
@implementation PluginLayerExample
413

514

615
// This is the layer type in the style that is used
716
+(MLNPluginLayerCapabilities *)layerCapabilities {
817

918
MLNPluginLayerCapabilities *tempResult = [[MLNPluginLayerCapabilities alloc] init];
10-
tempResult.layerID = @"plugin-layer-test";
19+
tempResult.layerID = @"maplibre::filter_features";
1120
tempResult.requiresPass3D = YES;
21+
tempResult.supportsReadingTileFeatures = YES;
1222
return tempResult;
1323

1424
}
1525

26+
-(id)init {
27+
if (self = [super init]) {
28+
self.logFeatures = NO;
29+
}
30+
return self;
31+
}
32+
1633
// The overrides
17-
-(void)onRenderLayer {
18-
NSLog(@"PluginLayerExample: On Render Layer");
34+
-(void)onRenderLayer:(MLNMapView *)mapView
35+
renderEncoder:(id<MTLRenderCommandEncoder>)renderEncoder {
36+
//NSLog(@"PluginLayerExample: On Render Layer");
1937

2038
}
2139

@@ -24,7 +42,54 @@ -(void)onUpdateLayer {
2442
}
2543

2644
-(void)onUpdateLayerProperties:(NSDictionary *)layerProperties {
27-
// NSLog(@"Layer Properties: %@", layerProperties);
45+
// NSLog(@"Layer Properties: %@", layerProperties);
46+
}
47+
48+
-(void)featureLoaded:(MLNPluginLayerTileFeature *)tileFeature {
49+
50+
// Writing a single string since the tile loading is multithreaded and the output can get interwoven
51+
NSMutableString *outputStr = [NSMutableString string];
52+
[outputStr appendFormat:@"Tile Feature (id:%@) Properties: %@\n", tileFeature.featureID, tileFeature.featureProperties];
53+
54+
for (NSValue *v in tileFeature.featureCoordinates) {
55+
56+
CLLocationCoordinate2D coord;
57+
[v getValue:&coord];
58+
59+
[outputStr appendFormat:@" -> (%f, %f) \n", coord.latitude, coord.longitude];
60+
61+
}
62+
63+
NSLog(@"Feature: %@", outputStr);
64+
}
65+
66+
-(void)featureUnloaded:(MLNPluginLayerTileFeature *)tileFeature {
67+
// NSLog(@"Tile Features Unloaded: %@", tileFeature.featureProperties);
68+
69+
}
70+
71+
72+
- (void)onFeatureLoaded:(MLNPluginLayerTileFeature *)tileFeature {
73+
74+
[self featureLoaded:tileFeature];
75+
76+
}
77+
78+
/// Called when a set of features are loaded from the tile
79+
- (void)onFeatureCollectionLoaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection {
80+
//NSLog(@"Feature Collection Loaded for tile: %@", tileFeatureCollection.tileID);
81+
for (MLNPluginLayerTileFeature *feature in tileFeatureCollection.features) {
82+
[self featureLoaded:feature];
83+
}
84+
85+
}
86+
87+
/// Called when a set of features are unloaded because the tile goes out of scene/etc
88+
- (void)onFeatureCollectionUnloaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection {
89+
//NSLog(@"Feature Collection Unloaded for tile: %@", tileFeatureCollection.tileID);
90+
for (MLNPluginLayerTileFeature *feature in tileFeatureCollection.features) {
91+
[self featureUnloaded:feature];
92+
}
2893
}
2994

3095
@end

platform/darwin/app/PluginLayerTestStyle.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,13 @@
583583
]
584584
}
585585
},
586+
{ "id": "centroid-features",
587+
"type": "maplibre::filter_features",
588+
"source": "maplibre",
589+
"source-layer": "countries",
590+
"maxzoom": 24,
591+
"minzoom": 1
592+
},
586593
{
587594
"id": "crimea-fill",
588595
"type": "fill",

platform/darwin/src/MLNPluginLayer.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,22 @@ MLN_EXPORT
4242

4343
@end
4444

45+
@interface MLNPluginLayerTileFeature : NSObject
46+
47+
// This is the unique feature ID in the tile source if applicable. Can be empty
48+
@property NSString *featureID;
49+
@property NSDictionary *featureProperties;
50+
@property NSArray *featureCoordinates;
51+
52+
@end
53+
54+
@interface MLNPluginLayerTileFeatureCollection : NSObject
55+
56+
@property NSArray *features;
57+
@property NSString *tileID; // z,x,y
58+
59+
@end
60+
4561
typedef enum {
4662
MLNPluginLayerTileKindGeometry,
4763
MLNPluginLayerTileKindRaster,
@@ -55,6 +71,9 @@ MLN_EXPORT
5571
@property (copy) NSString *layerID;
5672
@property BOOL requiresPass3D;
5773

74+
//! Set this to true if this layer can support reading features from the tiles
75+
@property BOOL supportsReadingTileFeatures;
76+
5877
//! This is a list of layer properties that this layer supports.
5978
@property (copy) NSArray<MLNPluginLayerProperty *> *layerProperties;
6079

@@ -104,6 +123,19 @@ MLN_EXPORT
104123
/// dynamic properties are updated
105124
- (void)onUpdateLayerProperties:(NSDictionary *)layerProperties;
106125

126+
/// Called when a feature is loaded from the tile
127+
- (void)onFeatureLoaded:(MLNPluginLayerTileFeature *)tileFeature;
128+
129+
/// Called when a set of features are loaded from the tile
130+
/*
131+
TODO: Think about returning that this layer doesn't care about this feature collection via a
132+
bool/etc and then the underlying layer won't have to track this collection.
133+
*/
134+
- (void)onFeatureCollectionLoaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection;
135+
136+
/// Called when a set of features are unloaded because the tile goes out of scene/etc
137+
- (void)onFeatureCollectionUnloaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection;
138+
107139
/// Added to a map view
108140
- (void)didMoveToMapView:(MLNMapView *)mapView;
109141

platform/darwin/src/MLNPluginLayer.mm

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
#import "MLNPluginLayer.h"
22

3+
@implementation MLNPluginLayerTileFeature
4+
5+
@end
6+
7+
@implementation MLNPluginLayerTileFeatureCollection
8+
9+
@end
10+
311
@implementation MLNPluginLayerProperty
412

513
+(MLNPluginLayerProperty *)propertyWithName:(NSString *)propertyName
@@ -66,12 +74,31 @@ -(void)onUpdateLayerProperties:(NSDictionary *)layerProperties {
6674
// Base class does nothing
6775
}
6876

77+
// If the layer properties indicate that this layer has a the ability to intercept
78+
// features, then this method will be called when a feature is loaded
79+
- (void)onFeatureLoaded:(MLNPluginLayerTileFeature *)tileFeature {
80+
// Base class does nothing
81+
}
82+
83+
// If the layer properties indicate that this layer has a the ability to intercept
84+
// features, then this method will be called when a feature is loaded
85+
- (void)onFeatureCollectionLoaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection {
86+
// Base class does nothing
87+
}
88+
89+
/// Called when a set of features are unloaded because the tile goes out of scene/etc
90+
- (void)onFeatureCollectionUnloaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection {
91+
// Base class does nothing
92+
}
93+
94+
6995
/// Added to a map view
7096
- (void)didMoveToMapView:(MLNMapView *)mapView {
7197
// Base class does nothing
7298
}
7399

74100

101+
75102
@end
76103

77104

platform/ios/app/MBXViewController.mm

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2332,17 +2332,18 @@ - (void)setStyles
23322332

23332333

23342334

2335-
2336-
/// Style that does not require an `apiKey` nor any further configuration
2337-
[self.styleNames addObject:@"MapLibre Basic"];
2338-
[self.styleURLs addObject:[NSURL URLWithString:@"https://demotiles.maplibre.org/style.json"]];
2339-
23402335
/// This is hte same style as above but copied locally and the three instances of the metal plug-in layer added to the style
23412336
/// Look for "type": "plugin-layer-metal-rendering" in the PluginLayerTestStyle.json for an example of how the layer is defined
23422337
[self.styleNames addObject:@"MapLibre Basic - Local With Plugin"];
23432338
NSURL *url = [[NSBundle mainBundle] URLForResource:@"PluginLayerTestStyle.json" withExtension:nil];
23442339
[self.styleURLs addObject:url];
23452340

2341+
2342+
/// Style that does not require an `apiKey` nor any further configuration
2343+
[self.styleNames addObject:@"MapLibre Basic"];
2344+
[self.styleURLs addObject:[NSURL URLWithString:@"https://demotiles.maplibre.org/style.json"]];
2345+
2346+
23462347
/// Add MapLibre Styles if an `apiKey` exists
23472348
NSString* apiKey = [MLNSettings apiKey];
23482349
if (apiKey.length)

0 commit comments

Comments
 (0)