Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Add tile template option to raster and vector sources #6316

Merged
merged 10 commits into from
Sep 23, 2016

Conversation

boundsj
Copy link
Contributor

@boundsj boundsj commented Sep 13, 2016

  • introduce MGLTileSet
  • add tileset initializer to MGLVectorSource
  • test MGLVectorSource in iosapp
  • add tileset initializer to MGLRasterSource
  • test MGLRasterSource in iosapp
  • unit tests
  • documentation updates

Fixes #6245

@boundsj boundsj added iOS Mapbox Maps SDK for iOS macOS Mapbox Maps SDK for macOS ⚠️ DO NOT MERGE Work in progress, proof of concept, or on hold runtime styling labels Sep 13, 2016
@boundsj boundsj added this to the ios-v3.4.0 milestone Sep 13, 2016
@boundsj boundsj self-assigned this Sep 13, 2016
@mention-bot
Copy link

@boundsj, thanks for your PR! By analyzing this pull request, we identified @1ec5, @incanus and @friedbunny to be potential reviewers.


@interface MGLRasterSource : MGLSource

@property (nonatomic, readonly, copy) NSURL *URL;
@property (nonatomic, readonly, assign) CGFloat tileSize;
@property (nonatomic, readonly, copy) NS_ARRAY_OF(NSString *) *tileURLTemplates;
@property (nonatomic, readonly) uint8_t minimumZoomLevel;
Copy link
Contributor

@1ec5 1ec5 Sep 13, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be NSUInteger-typed. In general, we should prefer Foundation typealiases over the compiler’s built-in numeric primitives in Objective-C code. It’s fine if the whole range of NSUInteger won’t work; if it fails hard, we can clamp the value to whatever range is supported.

@1ec5
Copy link
Contributor

1ec5 commented Sep 14, 2016

We should probably add an MGLTileSet class that exposes all the options mbgl::style::TileSet does and accept that in the MGLRasterSource initializer instead of the URL templates. Otherwise, it wouldn’t be possible to set any of the other TileJSON properties such as data or attribution (which will become important once #5999 lands).

@1ec5 1ec5 added the release blocker Blocks the next final release label Sep 14, 2016
@boundsj boundsj force-pushed the boundsj-support-tile-sets branch from 9d33392 to c0fb939 Compare September 14, 2016 18:32
@boundsj
Copy link
Contributor Author

boundsj commented Sep 14, 2016

We should probably add an MGLTileSet class

This work has started in c0fb939


@implementation MGLTileSet
{
BOOL _minimumZoomLevelIsSet;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the minimum and maximum zoom levels are optional, then do they need to be represented as NSNumbers publicly? Otherwise, if you use the -initWithTileURLTemplates: initializer, these properties end up being 0.

This reverts a previous change to vector / raster sources that
added initializers to those classes so they could take certain
tileset properties and create their own mbgl::Tileset objects.

Now, a new MGLTileSet class that wraps all available core Tileset
options can be created and passed into the sources. The sources
pass that tileset object along to core.
This also adds a temporary example to iosapp to show raster sources
working (actually vector on top of raster from 3rd party sources using
tile URL templates directly)
This changes the type of the minimum and maximum zoom level from
a BOOL to an NSNumber. With this commit, a client that does not
set the values will still see them represented as nil in the
underlying object even though those nil values will translate to
non nil defaults in core (0 for minimum and 22 for maximum).

In addition, this adds tests for MGLTileSet and an initial attempt
at documentation.
@boundsj
Copy link
Contributor Author

boundsj commented Sep 21, 2016

With the latest changes here, you can now mash up vector and raster sources created with tile sets:

    // Use raster tile URL templates directly (i.e. mapbox://tiles/mapbox.satellite/{z}/{x}/{y}{ratio}.png)
    // This is Stamen's terrain
    MGLTileSet *rasterTileSet = [[MGLTileSet alloc] initWithTileURLTemplates:@[@"http://a.tile.stamen.com/terrain-background/{z}/{x}/{y}.jpg"]];
    MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithSourceIdentifier:@"raster-source" tileSize:256 tileSet:rasterTileSet];
    [self.mapView.style addSource:rasterSource];

    MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithLayerIdentifier:@"raster-layer" source:rasterSource];
    [self.mapView.style addLayer:rasterLayer];

    // Use vector tile URL templates directly. This is Mapzen's vector tile service
    MGLTileSet *vectorTileSet = [[MGLTileSet alloc] initWithTileURLTemplates:@[@"https://vector.mapzen.com/osm/all/{z}/{x}/{y}.mvt?api_key=akey"]];
    MGLVectorSource *vectorSource = [[MGLVectorSource alloc] initWithSourceIdentifier:@"mapzen" tileSet:vectorTileSet];
    [self.mapView.style addSource:vectorSource];

    MGLFillStyleLayer *buildingsFillLayer = [[MGLFillStyleLayer alloc] initWithLayerIdentifier:@"filllayer" source:vectorSource sourceLayer:@"buildings"];
    buildingsFillLayer.fillColor = [UIColor magentaColor];
    [self.mapView.style addLayer:buildingsFillLayer];

Not exactly "Streets"

screen shot 2016-09-21 at 3 00 31 pm

The current implementation does not attempt to reflect the mbgl object's default minimum and maximum zoom values if the Objective-C object's properties are nil. However, documentation was added that states that the defaults will be used if the Objective-C tile set object is used to initialize a source and the min/max values are nil.

cc @1ec5

@interface MGLTileSet : NSObject

/**
A REQUIRED `NSArray` of `NSString` objects that represent the tile templates.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optionality should be indicated through nullability qualifiers; shouting isn't needed here.

the maximum zoom level at which to display tiles.
@return The initialized tile set object.
*/
- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates minimumZoomLevel:(NSNumber *)minimumZoomLevel maximumZoomLevel:(NSNumber *)maximumZoomLevel;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The zoom level parameters should either be nullable or, better yet, primitive typed.

// has the correct URL templates
XCTAssertEqual(mbglTileset.tiles[0], "tile.1");
XCTAssertEqual(mbglTileset.tiles[1], "tile.2");
XCTAssertEqual(mbglTileset.tiles[2], "tile.3");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also assert on the tile set count.

XCTAssertEqual([tileSet mbglTileset].zoomRange.max, 2);

// when the tile set has an attribution
tileSet.attribution = @"my tileset";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also test that Unicode characters are preserved.


// when the tile set has min and/or max zoom level set
tileSet.minimumZoomLevel = @(1);
tileSet.maximumZoomLevel = @(2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the developer sets a maximum zoom level less than the minimum, what happens? Would it be possible to test for an Objective-C exception being thrown (ideal)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0fc9cbc throws Objective-C exceptions if values are crossed initially or later on in setters. This avoids a more shocking C++ exception that happens later when the doomed threshold is crossed when the map is zoomed.

Alternatively, we could ignore invalid values and log a warning avoiding an exception altogether.

This updates the initializer to take an integer value for the zoom
level. Logic is also added to throw an exception early if the
initial values are invalid or if they are set to invalid values later
in property setters.
@boundsj boundsj changed the title [WIP] Add tile template option to vector source Add tile template option to vector source Sep 22, 2016
@boundsj boundsj removed the ⚠️ DO NOT MERGE Work in progress, proof of concept, or on hold label Sep 22, 2016
Copy link
Contributor

@1ec5 1ec5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost there.

of 0 to 22. The default value is 0 and the source will use the default value
An `NSNumber` object containing an integer; specifies the minimum zoom level at
which the source will display tiles. The value should be in the range of 0 to
22. The default value is 0 and the source will use the default value
if `minimumZoomLevel` is nil;
Copy link
Contributor

@1ec5 1ec5 Sep 22, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sentence and two more below end in semicolons instead of periods.

*/
@property (nonatomic, nullable) NSNumber *maximumZoomLevel;

/**
An OPTIONAL `NSString` object; Contains an attribution to be displayed
when the map is shown to a user. The default value is nil;
An `NSString` object; Contains an attribution to be displayed when the map is
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: replace the semicolon with “that” and lowercase “contains” (plus one more below).

@@ -43,7 +44,7 @@ - (void)testMBGLTileSet {
XCTAssertEqual([tileSet mbglTileset].zoomRange.max, 2);

// when the tile set has an attribution
tileSet.attribution = @"my tileset";
tileSet.attribution = @"my tileset ©";
Copy link
Contributor

@1ec5 1ec5 Sep 22, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

© is a decent test, since it falls outside of ASCII. In #5999, I used ©️, which pairs © with a variation selector for an emoji look. But something outside the Basic Multilingual Plane, for example in the Miscellaneous Symbols and Pictographs block, would be even better for detecting mojibake.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I think 0e31030 should probably wrap this up

Copy link
Contributor

@1ec5 1ec5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎈

@boundsj boundsj changed the title Add tile template option to vector source Add tile template option to rasater and vector sources Sep 23, 2016
@boundsj boundsj changed the title Add tile template option to rasater and vector sources Add tile template option to raster and vector sources Sep 23, 2016
@boundsj boundsj merged commit 3ddb8df into master Sep 23, 2016
@boundsj boundsj deleted the boundsj-support-tile-sets branch September 23, 2016 00:30
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
iOS Mapbox Maps SDK for iOS macOS Mapbox Maps SDK for macOS release blocker Blocks the next final release runtime styling
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants