Merge branch 'release-ios-v3.4.0' into 1ec5-release-ios-v3.4.0-beta.7

This commit is contained in:
Minh Nguyễn
2017-01-16 11:38:35 -08:00
199 changed files with 11328 additions and 3198 deletions

View File

@@ -163,6 +163,10 @@ macos-test: $(MACOS_PROJ_PATH)
xpackage: $(MACOS_PROJ_PATH)
SYMBOLS=$(SYMBOLS) ./platform/macos/scripts/package.sh
.PHONY: xdeploy
xdeploy:
caffeinate -i ./platform/macos/scripts/deploy-packages.sh
.PHONY: xdocument
xdocument:
OUTPUT=$(OUTPUT) ./platform/macos/scripts/document.sh
@@ -276,8 +280,13 @@ idocument:
.PHONY: darwin-style-code
darwin-style-code:
node platform/darwin/scripts/generate-style-code.js
node platform/darwin/scripts/update-examples.js
style-code: darwin-style-code
.PHONY: darwin-update-examples
darwin-update-examples:
node platform/darwin/scripts/update-examples.js
.PHONY: check-public-symbols
check-public-symbols:
node platform/darwin/scripts/check-public-symbols.js macOS

View File

@@ -6,85 +6,143 @@
#include <string>
#include <vector>
#include <tuple>
namespace mbgl {
namespace style {
class Filter;
class NullFilter {};
class NullFilter {
public:
friend bool operator==(const NullFilter&, const NullFilter&) {
return true;
}
};
class EqualsFilter {
public:
std::string key;
Value value;
friend bool operator==(const EqualsFilter& lhs, const EqualsFilter& rhs) {
return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value);
}
};
class NotEqualsFilter {
public:
std::string key;
Value value;
friend bool operator==(const NotEqualsFilter& lhs, const NotEqualsFilter& rhs) {
return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value);
}
};
class LessThanFilter {
public:
std::string key;
Value value;
friend bool operator==(const LessThanFilter& lhs, const LessThanFilter& rhs) {
return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value);
}
};
class LessThanEqualsFilter {
public:
std::string key;
Value value;
friend bool operator==(const LessThanEqualsFilter& lhs, const LessThanEqualsFilter& rhs) {
return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value);
}
};
class GreaterThanFilter {
public:
std::string key;
Value value;
friend bool operator==(const GreaterThanFilter& lhs, const GreaterThanFilter& rhs) {
return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value);
}
};
class GreaterThanEqualsFilter {
public:
std::string key;
Value value;
friend bool operator==(const GreaterThanEqualsFilter& lhs, const GreaterThanEqualsFilter& rhs) {
return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value);
}
};
class InFilter {
public:
std::string key;
std::vector<Value> values;
friend bool operator==(const InFilter& lhs, const InFilter& rhs) {
return std::tie(lhs.key, lhs.values) == std::tie(rhs.key, rhs.values);
}
};
class NotInFilter {
public:
std::string key;
std::vector<Value> values;
friend bool operator==(const NotInFilter& lhs, const NotInFilter& rhs) {
return std::tie(lhs.key, lhs.values) == std::tie(rhs.key, rhs.values);
}
};
class AnyFilter {
public:
std::vector<Filter> filters;
friend bool operator==(const AnyFilter& lhs, const AnyFilter& rhs) {
return lhs.filters == rhs.filters;
}
};
class AllFilter {
public:
std::vector<Filter> filters;
friend bool operator==(const AllFilter& lhs, const AllFilter& rhs) {
return lhs.filters == rhs.filters;
}
};
class NoneFilter {
public:
std::vector<Filter> filters;
friend bool operator==(const NoneFilter& lhs, const NoneFilter& rhs) {
return lhs.filters == rhs.filters;
}
};
class HasFilter {
public:
std::string key;
friend bool operator==(const HasFilter& lhs, const HasFilter& rhs) {
return lhs.key == rhs.key;
}
};
class NotHasFilter {
public:
std::string key;
friend bool operator==(const NotHasFilter& lhs, const NotHasFilter& rhs) {
return lhs.key == rhs.key;
}
};
using FilterBase = variant<

View File

@@ -43,7 +43,7 @@ public:
void setURL(const std::string& url);
void setGeoJSON(const GeoJSON&);
optional<std::string> getURL();
optional<std::string> getURL() const;
// Private implementation

View File

@@ -11,9 +11,12 @@ class RasterSource : public Source {
public:
RasterSource(std::string id, variant<std::string, Tileset> urlOrTileset, uint16_t tileSize);
optional<std::string> getURL() const;
// Private implementation
class Impl;
Impl* const impl;
};
template <>

View File

@@ -11,9 +11,12 @@ class VectorSource : public Source {
public:
VectorSource(std::string id, variant<std::string, Tileset> urlOrTileset);
optional<std::string> getURL() const;
// Private implementation
class Impl;
Impl* const impl;
};
template <>

View File

@@ -0,0 +1,321 @@
<%
const os = locals.os;
const iOS = os === 'iOS';
const macOS = os === 'macOS';
const cocoaPrefix = iOS ? 'UI' : 'NS';
const layers = locals.layers;
const renamedProperties = locals.renamedProperties;
-%>
<!--
This file is generated.
Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
-->
# Information for Style Authors
A _style_ defines a map view’s content and appearance. If you’ve authored a
style using
[Mapbox Studio’s Styles editor](https://www.mapbox.com/studio/styles/) or as
JSON in a text editor, you can use that style in this SDK and manipulate it
afterwards in code. This document provides information you can use to ensure a
seamless transition from Mapbox Studio to your application.
<% if (iOS) { -%>
## Designing for iOS
<% } else { -%>
## Designing for macOS
<% } -%>
When designing your style, consider the context in which your application shows
the style. There are a number of considerations specific to <%- os %> that may
not be obvious when designing your style in Mapbox Studio on the Web. A map view
is essentially a graphical user interface element, so many of same issues in
user interface design also apply when designing a map style.
### Color
Ensure sufficient contrast in your application’s user interface when your map
style is present. Standard user interface elements such as toolbars, sidebars,
and sheets often overlap the map view with a translucent, blurred background, so
make sure the contents of these elements remain legible with the map view
underneath.
<% if (iOS) { -%>
The user location annotation view, the attribution button, any buttons in
callout views, and any items in the navigation bar are influenced by your
application’s tint color, so choose a tint color that constrasts well with your
map style. If you intend your style to be used in the dark, consider the impact
that Night Shift may have on your style’s colors.
<% } -%>
### Typography and graphics
<% if (iOS) { -%>
Choose font and icon sizes appropriate to iOS devices. iPhones and iPads have
smaller screens than the typical browser window in which you would use Mapbox
Studio, especially when multitasking is enabled. Your user’s viewing distance
may be shorter than on a desktop computer. Some of your users may use the Larger
Dynamic Type and Accessibility Text features to increase the size of all text on
the device. You can use the
[runtime styling API](#manipulating-the-style-at-runtime) to adjust your style’s
font and icon sizes accordingly.
<% } -%>
Design sprite images and choose font weights that look crisp on both
standard-resolution displays and Retina displays. This SDK supports the same
resolutions as <%- os %>.
<% if (iOS) { -%>
Standard-resolution displays are limited to older devices that your application
may or may not support, depending on its minimum deployment target.
<% } else { -%>
Standard-resolution displays are often found on external monitors. Even with
built-in screens, some of your users may use the Larger Text option in Display
Preferences, which is essentially standard resolution, to make text easier to
read.
<% } -%>
Icon and text labels should be legible regardless of the map’s orientation.
<% if (iOS) { -%>
By default, this SDK makes it easy for your users to rotate or tilt the map
using multitouch gestures.
<% } else { -%>
By default, this SDK makes it easy for your users to rotate or tilt the map
using multitouch trackpad gestures or keyboard shortcuts.
<% } -%>
If you do not intend your design to accommodate rotation and tilting, disable
these gestures using the `MGLMapView.rotateEnabled` and
`MGLMapView.pitchEnabled` properties, respectively, or the corresponding
inspectables in Interface Builder.
### Interactivity
Pay attention to whether elements of your style appear to be interactive.
<% if (iOS) { -%>
A text label may look like a tappable button merely due to matching your
application’s tint color or the default blue tint color.
<% } else { -%>
An icon with a shadow or shading effect may appear to be clickable.
<% } -%>
You can make an icon or text label interactive by installing a gesture
recognizer and performing feature querying (e.g.,
`-[MGLMapView visibleFeaturesAtPoint:]`) to get details about the selected
feature.
<% if (macOS) { -%>
You can install cursor or tooltip tracking rectangles to indicate interactive
features as an alternative to prominent hover effects.
<% } -%>
<% if (iOS) { -%>
Make sure your users can easily distinguish any interactive elements from the
surrounding map, such as pins, the user location annotation view, or a route
line. Avoid relying on hover effects to indicate interactive elements. Leave
enough room between interactive elements to accommodate imprecise tapping
gestures.
<% } else { -%>
Make sure your users can easily distinguish any interactive elements from the
surrounding map, such as pins or a route line. If your application supports
printing, consider using the
[runtime styling API](#manipulating-the-style-at-runtime) to optimize your style
for ink economy before printing the map view.
<% } -%>
<% if (iOS) { -%>
For more information about user interface design, consult Apple’s
[_iOS Human Interface Guidelines_](https://developer.apple.com/ios/human-interface-guidelines/).
<% } else { -%>
For more information about user interface design, consult Apple’s
[_macOS Human Interface Guidelines_](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/OSXHIGuidelines/).
<% } -%>
## Applying your style
You set an `MGLMapView` object’s style either in code, by setting the
`MGLMapView.styleURL` property, or in Interface Builder, by setting the “Style
URL” inspectable. The URL must point to a local or remote style JSON file. The
style JSON file format is defined by the
[Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/). This
SDK supports the functionality defined by version 8 of the specification unless
otherwise noted in the
[style specification documentation](https://www.mapbox.com/mapbox-gl-style-spec/).
## Manipulating the style at runtime
The _runtime styling API_ enables you to modify every aspect of a style
dynamically as a user interacts with your application. The style itself is
represented at runtime by an `MGLStyle` object, which provides access to various
`MGLSource` and `MGLStyleLayer` objects that represent content sources and style
layers, respectively.
<% if (iOS) { -%>
For more information about the capabilities exposed by the runtime styling API,
see “[Runtime Styling](runtime-styling.html)”.
<% } -%>
The names of runtime styling classes and properties on <%- os %> are generally
consistent with the style specification and Mapbox Studio’s Styles editor. Any
exceptions are listed in this document.
To avoid conflicts with Objective-C keywords or Cocoa terminology, this SDK uses
the following terms for concepts defined in the style specification:
In the style specification | In the SDK
---------------------------|---------
class | style class
filter | predicate
id | identifier
image | style image
layer | style layer
property | attribute
SDF icon | template image
source | content source
## Specifying the map’s content
Each source defined by a style JSON file is represented at runtime by a content
source object that you can use to initialize new style layers. The content
source object is a member of one of the following subclasses of `MGLSource`:
In style JSON | In the SDK
--------------|-----------
`geojson` | `MGLShapeSource`
`raster` | `MGLRasterSource`
`vector` | `MGLVectorSource`
`image` and `video` sources are not supported.
### Tile sources
Raster and vector sources may be defined in TileJSON configuration files. This
SDK supports the properties defined in the style specification, which are a
subset of the keys defined in version 2.1.0 of the
[TileJSON](https://github.com/mapbox/tilejson-spec/tree/master/2.1.0)
specification. As an alternative to authoring a custom TileJSON file, you may
supply various tile source options when creating a raster or vector source.
These options are detailed in the `MGLTileSourceOption` documentation:
In style JSON | In TileJSON | In the SDK
--------------|---------------|-----------
`url` | — | `configurationURL` parameter in `-[MGLTileSource initWithIdentifier:configurationURL:]`
`tiles` | `tiles` | `tileURLTemplates` parameter in `-[MGLTileSource initWithIdentifier:tileURLTemplates:options:]`
`minzoom` | `minzoom` | `MGLTileSourceOptionMinimumZoomLevel`
`maxzoom` | `maxzoom` | `MGLTileSourceOptionMaximumZoomLevel`
`tileSize` | — | `MGLTileSourceOptionTileSize`
`attribution` | `attribution` | `MGLTileSourceOptionAttributionHTMLString` (but consider specifying `MGLTileSourceOptionAttributionInfos` instead for improved security)
`scheme` | `scheme` | `MGLTileSourceOptionTileCoordinateSystem`
### Shape sources
Shape sources also accept various options. These options are detailed in the
`MGLShapeSourceOption` documentation:
In style JSON | In the SDK
-----------------|-----------
`data` | `url` parameter in `-[MGLShapeSource initWithIdentifier:URL:options:]`
`maxzoom` | `MGLShapeSourceOptionMaximumZoomLevel`
`buffer` | `MGLShapeSourceOptionBuffer`
`tolerance` | `MGLShapeSourceOptionSimplificationTolerance`
`cluster` | `MGLShapeSourceOptionClustered`
`clusterRadius` | `MGLShapeSourceOptionClusterRadius`
`clusterMaxZoom` | `MGLShapeSourceOptionMaximumZoomLevelForClustering`
To create a shape source from local GeoJSON data, first
[convert the GeoJSON data into a shape](working-with-geojson-data.html#converting-geojson-data-into-shape-objects),
then use the `-[MGLShapeSource initWithIdentifier:shape:options:]` method.
## Configuring the map content’s appearance
Each layer defined by the style JSON file is represented at runtime by a style
layer object, which you can use to refine the map’s appearance. The style layer
object is a member of one of the following subclasses of `MGLStyleLayer`:
In style JSON | In the SDK
--------------|-----------
<% for (const layer of layers) { -%>
`<%- layer.type %>` | `MGL<%- camelize(layer.type) %>StyleLayer`
<% } -%>
You configure layout and paint attributes by setting properties on these style
layer objects. The property names generally correspond to the style JSON
properties, except for the use of camelCase instead of kebab-case. Properties
whose names differ from the style specification are listed below:
<% for (const type in renamedProperties) { -%>
<% if (renamedProperties.hasOwnProperty(type)) { -%>
### <%- camelize(type) %> style layers
In style JSON | In Objective-C | In Swift
--------------|----------------|---------
<% for (const name in renamedProperties[type]) { -%>
<% if (renamedProperties[type].hasOwnProperty(name)) { -%>
`<%- originalPropertyName(renamedProperties[type][name]) %>` | `MGL<%- camelize(type) %>StyleLayer.<%- objCName(renamedProperties[type][name]) %>` | `MGL<%- camelize(type) %>StyleLayer.<%- objCGetter(renamedProperties[type][name]) %>`
<% } -%>
<% } -%>
<% } -%>
<% } -%>
## Setting attribute values
Each property representing a layout or paint attribute is set to an
`MGLStyleValue` object, which is either an `MGLStyleConstantValue` object (for
constant values) or an `MGLStyleFunction` object (for zoom level functions). The
style value object is a container for the raw value or function parameters that
you want the attribute to be set to.
In contrast to the JSON type that the style specification defines for each
layout or paint property, the style value object often contains a more specific
Foundation or Cocoa type. General rules for attribute types are listed below.
Pay close attention to the SDK documentation for the attribute you want to get
or set.
In style JSON | In Objective-C | In Swift
--------------|-----------------------|---------
Color | `<%- cocoaPrefix %>Color` | `<%- cocoaPrefix %>Color`
Enum | `NSValue` (see `NSValue(MGLAdditions)`) | `NSValue` (see `NSValue(MGLAdditions)`)
String | `NSString` | `String`
Boolean | `NSNumber.boolValue` | `Bool`
Number | `NSNumber.floatValue` | `Float`
Array (`-dasharray`) | `NSArray<NSNumber>` | `[Float]`
Array (`-font`) | `NSArray<NSString>` | `[String]`
<% if (iOS) { -%>
Array (`-offset`, `-translate`) | `NSValue.CGVectorValue` | `NSValue.cgVectorValue`
Array (`-padding`) | `NSValue.UIEdgeInsetsValue` | `NSValue.uiEdgeInsetsValue`
<% } else { -%>
Array (`-offset`, `-translate`) | `NSValue` containing `CGVector` | `NSValue` containing `CGVector`
Array (`-padding`) | `NSValue.edgeInsetsValue` | `NSValue.edgeInsetsValue`
<% } -%>
For padding attributes, note that the arguments to
`<%- cocoaPrefix %>EdgeInsetsMake()` in Objective-C and
`EdgeInsets(top:left:bottom:right:)` in Swift are specified in counterclockwise
order, in contrast to the clockwise order defined by the style specification.
<% if (macOS) { -%>
Additionally, on macOS, a screen coordinate of (0, 0) is located at the
lower-left corner of the screen. Therefore, a positive `CGVector.dy` means an
offset or translation upward, while a negative `CGVector.dy` means an offset or
translation downward. This is the reverse of how `CGVector` is interpreted on
iOS.
<% } -%>
## Filtering sources
You can filter a shape or vector source by setting the
`MGLVectorStyleLayer.predicate` property to an `NSPredicate` object. Below is a
table of style JSON operators and the corresponding operators used in the
predicate format string:
In style JSON | In the format string
--------------------------|---------------------
`["has", key]` | `key != nil`
`["!has", key]` | `key == nil`
`["==", key, value]` | `key == value`
`["!=", key, value]` | `key != value`
`[">", key, value]` | `key > value`
`[">=", key, value]` | `key >= value`
`["<", key, value]` | `key < value`
`["<=", key, value]` | `key <= value`
`["in", key, v0, …, vn]` | `key IN {v0, …, vn}`
`["!in", key, v0, …, vn]` | `NOT key IN {v0, …, vn}`
`["all", f0, …, fn]` | `p0 AND … AND pn`
`["any", f0, …, fn]` | `p0 OR … OR pn`
`["none", f0, …, fn]` | `NOT (p0 OR … OR pn)`
See the `MGLVectorStyleLayer.predicate` documentation for a full description of
the supported operators and operand types.

View File

@@ -0,0 +1,99 @@
# Working with GeoJSON Data
This SDK offers several ways to work with [GeoJSON](http://geojson.org/) files.
GeoJSON is a standard file format for representing geographic data.
## Adding a GeoJSON file to the map
You can use
[Mapbox Studio’s Datasets editor](https://www.mapbox.com/studio/datasets/) to
upload a GeoJSON file and include it in your custom map style. The GeoJSON data
will be hosted on Mapbox servers. When a user loads your style, the SDK
automatically loads the GeoJSON data for display.
Alternatively, if you need to host the GeoJSON file elsewhere or bundle it with
your application, you can use a GeoJSON file as the basis of an `MGLShapeSource`
object. Pass the file’s URL into the
`-[MGLShapeSource initWithIdentifier:URL:options:]` initializer and add the
shape source to the map using the `-[MGLStyle addSource:]` method. The URL may
be a local file URL, an HTTP URL, or an HTTPS URL.
Once you’ve added the GeoJSON file to the map via an `MGLShapeSource` object,
you can configure the appearance of its data and control what data is visible
using `MGLStyleLayer` objects, you can
[access the data programmatically](#extracting-geojson-data-from-the-map).
## Converting GeoJSON data into shape objects
If you have GeoJSON data in the form of source code (also known as “GeoJSON
text”), you can convert it into an `MGLShape`, `MGLFeature`, or
`MGLShapeCollectionFeature` object that the `MGLShapeSource` class understands
natively. First, create an `NSData` object out of the source code string or file
contents, then pass that data object into the
`+[MGLShape shapeWithData:encoding:error:]` method. Finally, you can pass the
resulting shape or feature object into the
`-[MGLShapeSource initWithIdentifier:shape:options:]` initializer and add it to
the map, or you can use the object and its properties to power non-map-related
functionality in your application.
To include multiple shapes in the source, create and pass an `MGLShapeCollection` or
`MGLShapeCollectionFeature` object to
`-[MGLShapeSource initWithIdentifier:shape:options:]`. Alternatively, use the
`-[MGLShapeSource initWithIdentifier:features:options:]` or
`-[MGLShapeSource initWithIdentifier:shapes:options:]` method to create a shape source
with an array. `-[MGLShapeSource initWithIdentifier:features:options:]` accepts only `MGLFeature`
instances, such as `MGLPointFeature` objects, whose attributes you can use when
applying a predicate to `MGLVectorStyleLayer` or configuring a style layer’s
appearance.
## Extracting GeoJSON data from the map
Any `MGLShape`, `MGLFeature`, or `MGLShapeCollectionFeature` object has an
`-[MGLShape geoJSONDataUsingEncoding:]` method that you can use to create a
GeoJSON source code representation of the object. You can extract a feature
object from the map using a method such as
`-[MGLMapView visibleFeaturesAtPoint:]`.
## About GeoJSON deserialization
The process of converting GeoJSON text into `MGLShape`, `MGLFeature`, or
`MGLShapeCollectionFeature` objects is known as “GeoJSON deserialization”.
GeoJSON geometries, features, and feature collections are known in this SDK as
shapes, features, and shape collection features, respectively.
Each GeoJSON object type corresponds to a type provided by either this SDK or
the Core Location framework:
GeoJSON object type | SDK type
--------------------|---------
`Position` (longitude, latitude) | `CLLocationCoordinate2D` (latitude, longitude)
`Point` | `MGLPointAnnotation`
`MultiPoint` | `MGLPointCollection`
`LineString` | `MGLPolyline`
`MultiLineString` | `MGLMultiPolyline`
`Polygon` | `MGLPolygon`
Linear ring | `MGLPolygon.coordinates`, `MGLPolygon.interiorPolygons`
`MultiPolygon` | `MGLMultiPolygon`
`GeometryCollection` | `MGLShapeCollection`
`Feature` | `MGLFeature`
`FeatureCollection` | `MGLShapeCollectionFeature`
A `Feature` object in GeoJSON corresponds to an instance of an `MGLShape`
subclass conforming to the `MGLFeature` protocol. There is a distinct
`MGLFeature`-conforming class for each type of geometry that a GeoJSON feature
can contain. This allows features to be used as shapes where convenient. For
example, some features can be added to a map view as annotations.
In contrast to the GeoJSON standard, it is possible for `MGLShape` subclasses
other than `MGLPointAnnotation` to straddle the antimeridian.
The following GeoJSON data types correspond straightforwardly to Foundation data
types when they occur as feature identifiers or property values:
GeoJSON data type | Objective-C representation | Swift representation
-------------------|----------------------------|---------------------
`null` | `NSNull` | `NSNull`
`true`, `false` | `NSNumber.boolValue` | `Bool`
Integer | `NSNumber.unsignedLongLongValue`, `NSNumber.longLongValue` | `UInt64`, `Int64`
Floating-point number | `NSNumber.doubleValue` | `Double`
String | `NSString` | `String`

View File

@@ -51,6 +51,7 @@ $navigation_bg_color: #fbfbfb;
$navigation_task_color: $link_color;
$section_name_color: $color_darkblue;
$navigation_gloss_color: #999;
// ----- Content
@@ -367,6 +368,30 @@ pre code {
color: $navigation_task_color;
}
%nav-group-task-gloss {
color: $navigation_gloss_color;
font-size: 90%;
margin-left: 0.5em;
}
.nav-group-task[data-url^="Protocols/"] > .nav-group-task-link::after {
@extend %nav-group-task-gloss;
content: "(Protocol)";
}
.nav-group-task[data-name="MGLForegroundStyleLayer"],
.nav-group-task[data-name="MGLMultiPoint"],
.nav-group-task[data-name="MGLShape"],
.nav-group-task[data-name="MGLSource"],
.nav-group-task[data-name="MGLStyleLayer"],
.nav-group-task[data-name="MGLTileSource"],
.nav-group-task[data-name="MGLVectorStyleLayer"] {
.nav-group-task-link::after {
@extend %nav-group-task-gloss;
content: "(Abstract Class)";
}
}
.nav-group-name > .small-heading,
.nav-group-task-link {
display: block;

View File

@@ -40,3 +40,8 @@ $(".token").click(function(event) {
}
event.preventDefault();
});
// Dumb down quotes within code blocks that delimit strings instead of quotations.
$("code q").replaceWith(function () {
return ["\"", $(this).contents(), "\""];
});

View File

@@ -5,7 +5,7 @@
<a class="small-heading" href="{{path_to_root}}{{section}}.html">{{section}}<span class="anchor-icon" /></a>
<ul class="nav-group-tasks">
{{#children}}
<li class="nav-group-task" data-name="{{name}}">
<li class="nav-group-task" data-name="{{name}}" data-url="{{url}}">
<a title="{{name}}" class="nav-group-task-link" href="{{path_to_root}}{{url}}">{{name}}</a>
</li>
{{/children}}

View File

@@ -55,17 +55,38 @@ _.forOwn(cocoaConventions, function (properties, kind) {
})
});
String.prototype.wrap = function (cols, indent) {
let wrapRe = new RegExp(`(.{1,${cols - indent}})(?: +|\n|$)`, "gm");
return this.replace(wrapRe, "$1\n").replace(/\s+$/, "").indent(indent);
};
String.prototype.indent = function (cols) {
return this.replace(/^|\n/g, "$&" + " ".repeat(cols));
};
global.camelize = function (str) {
return str.replace(/(?:^|-)(.)/g, function (_, x) {
return x.toUpperCase();
});
};
global.camelizeWithLeadingLowercase = function (str) {
return str.replace(/-(.)/g, function (_, x) {
return x.toUpperCase();
});
};
global.objCName = function (property) {
return camelizeWithLeadingLowercase(property.name);
}
};
global.objCGetter = function (property) {
return camelizeWithLeadingLowercase(property.getter || property.name);
}
};
global.objCType = function (layerType, propertyName) {
return `${prefix}${camelize(propertyName)}`;
}
};
global.arrayType = function (property) {
return property.type === 'array' ? originalPropertyName(property).split('-').pop() : false;
@@ -74,7 +95,87 @@ global.arrayType = function (property) {
global.testImplementation = function (property, layerType, isFunction) {
let helperMsg = testHelperMessage(property, layerType, isFunction);
return `layer.${objCName(property)} = [MGLRuntimeStylingHelper ${helperMsg}];`;
}
};
global.objCTestValue = function (property, layerType, indent) {
let propertyName = originalPropertyName(property);
switch (property.type) {
case 'boolean':
return property.default ? '@NO' : '@YES';
case 'number':
return '@0xff';
case 'string':
return `@"${_.startCase(propertyName)}"`;
case 'enum':
let type = objCType(layerType, property.name);
let value = `${type}${camelize(_.last(_.keys(property.values)))}`;
return `[NSValue valueWith${type}:${value}]`;
case 'color':
return '[MGLColor redColor]';
case 'array':
switch (arrayType(property)) {
case 'dasharray':
return '@[@1, @2]';
case 'font':
return `@[@"${_.startCase(propertyName)}", @"${_.startCase(_.reverse(propertyName.split('')).join(''))}"]`;
case 'padding': {
let iosValue = '[NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(1, 1, 1, 1)]'.indent(indent * 4);
let macosValue = '[NSValue valueWithEdgeInsets:NSEdgeInsetsMake(1, 1, 1, 1)]'.indent(indent * 4);
return `\n#if TARGET_OS_IPHONE\n${iosValue}\n#else\n${macosValue}\n#endif\n${''.indent((indent - 1) * 4)}`;
}
case 'offset':
case 'translate':
let iosValue = '[NSValue valueWithCGVector:CGVectorMake(1, 1)]'.indent(indent * 4);
let macosValue = '[NSValue valueWithMGLVector:CGVectorMake(1, -1)]'.indent(indent * 4);
return `\n#if TARGET_OS_IPHONE\n${iosValue}\n#else\n${macosValue}\n#endif\n${''.indent((indent - 1) * 4)}`;
default:
throw new Error(`unknown array type for ${property.name}`);
}
default:
throw new Error(`unknown type for ${property.name}`);
}
};
global.mbglTestValue = function (property, layerType) {
let propertyName = originalPropertyName(property);
switch (property.type) {
case 'boolean':
return property.default ? 'false' : 'true';
case 'number':
return '0xff';
case 'string':
return `"${_.startCase(propertyName)}"`;
case 'enum': {
let type = camelize(originalPropertyName(property));
if (/-translate-anchor$/.test(originalPropertyName(property))) {
type = 'TranslateAnchor';
}
if (/-(rotation|pitch)-alignment$/.test(originalPropertyName(property))) {
type = 'Alignment';
}
let value = camelize(_.last(_.keys(property.values)));
return `mbgl::style::${type}Type::${value}`;
}
case 'color':
return '{ 1, 0, 0, 1 }';
case 'array':
switch (arrayType(property)) {
case 'dasharray':
return '{1, 2}';
case 'font':
return `{ "${_.startCase(propertyName)}", "${_.startCase(_.reverse(propertyName.split('')).join(''))}" }`;
case 'padding':
return '{ 1, 1, 1, 1 }';
case 'offset':
case 'translate':
return '{ 1, 1 }';
default:
throw new Error(`unknown array type for ${property.name}`);
}
default:
throw new Error(`unknown type for ${property.name}`);
}
};
global.testGetterImplementation = function (property, layerType, isFunction) {
let helperMsg = testHelperMessage(property, layerType, isFunction);
@@ -87,7 +188,7 @@ global.testGetterImplementation = function (property, layerType, isFunction) {
XCTAssertEqualObjects(gLayer.${objCName(property)}, ${value});`;
}
return `XCTAssertEqualObjects(gLayer.${objCName(property)}, ${value});`;
}
};
global.testHelperMessage = function (property, layerType, isFunction) {
let fnSuffix = isFunction ? 'Function' : '';
@@ -123,7 +224,7 @@ global.testHelperMessage = function (property, layerType, isFunction) {
}
};
global.propertyDoc = function (propertyName, property, layerType) {
global.propertyDoc = function (propertyName, property, layerType, kind) {
// Match references to other property names & values.
// Requires the format 'When `foo` is set to `bar`,'.
let doc = property.doc.replace(/`([^`]+?)` is set to `([^`]+?)`/g, function (m, peerPropertyName, propertyValue, offset, str) {
@@ -141,7 +242,7 @@ global.propertyDoc = function (propertyName, property, layerType) {
// Requires symbols to be surrounded by backticks.
doc = doc.replace(/`(.+?)`/g, function (m, symbol, offset, str) {
if ('values' in property && Object.keys(property.values).indexOf(symbol) !== -1) {
let objCType = objCType(layerType, property.name);
let objCType = global.objCType(layerType, property.name);
return '`' + `${objCType}${camelize(symbol)}` + '`';
}
if (str.substr(offset - 4, 3) !== 'CSS') {
@@ -154,11 +255,33 @@ global.propertyDoc = function (propertyName, property, layerType) {
if (!property.units.match(/s$/)) {
property.units += 's';
}
doc += `
This property is measured in ${property.units}.`;
doc += `\n\nThis property is measured in ${property.units}.`;
}
return doc.replace(/(p)ixel/gi, '$1oint').replace(/(\d)px\b/g, '$1pt');
doc = doc.replace(/(p)ixel/gi, '$1oint').replace(/(\d)px\b/g, '$1pt');
if (kind !== 'enum') {
if ('default' in property) {
doc += `\n\nThe default value of this property is ${propertyDefault(property, layerType)}.`;
if (!property.required) {
doc += ' Set this property to `nil` to reset it to the default value.';
}
}
if ('requires' in property) {
doc += '\n\n' + propertyReqs(property, spec[`${kind}_${layerType}`], layerType);
}
if ('original' in property) {
let anchor;
switch (kind) {
case 'layout':
anchor = `layout-${layerType}-${property.original}`;
break;
case 'paint':
anchor = `paint-${property.original}`;
break;
}
doc += `\n\nThis attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#${anchor}"><code>${property.original}</code></a> layout property in the Mapbox Style Specification.`;
}
}
return doc;
};
global.propertyReqs = function (property, propertiesByName, type) {
@@ -217,30 +340,32 @@ global.describeValue = function (value, property, layerType) {
throw new Error(`unrecognized color format in default value of ${property.name}`);
}
if (color.r === 0 && color.g === 0 && color.b === 0 && color.a === 0) {
return '`MGLColor.clearColor`';
return '`UIColor.clearColor`';
}
if (color.r === 0 && color.g === 0 && color.b === 0 && color.a === 1) {
return '`MGLColor.blackColor`';
return '`UIColor.blackColor`';
}
if (color.r === 1 && color.g === 1 && color.b === 1 && color.a === 1) {
return '`MGLColor.whiteColor`';
return '`UIColor.whiteColor`';
}
return 'an `MGLColor`' + ` object whose RGB value is ${color.r}, ${color.g}, ${color.b} and whose alpha value is ${color.a}`;
return 'a `UIColor`' + ` object whose RGB value is ${color.r}, ${color.g}, ${color.b} and whose alpha value is ${color.a}`;
case 'array':
let units = property.units || '';
if (units) {
units = ` ${units}`.replace(/pixel/, 'point');
}
if (property.name.indexOf('padding') !== -1) {
if (value[0] === 0 && value[1] === 0 && value[2] === 0 && value[3] === 0) {
return 'an `NSValue` object containing `NSEdgeInsetsZero` or `UIEdgeInsetsZero`';
}
return 'an `NSValue` object containing an `NSEdgeInsets` or `UIEdgeInsets` struct set to' + ` ${value[0]}${units} on the top, ${value[3]}${units} on the left, ${value[2]}${units} on the bottom, and ${value[1]}${units} on the right`;
switch (arrayType(property)) {
case 'padding':
if (value[0] === 0 && value[1] === 0 && value[2] === 0 && value[3] === 0) {
return 'an `NSValue` object containing `UIEdgeInsetsZero`';
}
return 'an `NSValue` object containing a `UIEdgeInsets` struct set to' + ` ${value[0]}${units} on the top, ${value[3]}${units} on the left, ${value[2]}${units} on the bottom, and ${value[1]}${units} on the right`;
case 'offset':
case 'translate':
return 'an `NSValue` object containing a `CGVector` struct set to' + ` ${value[0]}${units} rightward and ${value[1]}${units} downward`;
default:
return 'the array `' + value.join('`, `') + '`';
}
if (property.name.indexOf('offset') !== -1 || property.name.indexOf('translate') !== -1) {
return 'an `NSValue` object containing a `CGVector` struct set to' + ` ${value[0]}${units} from the left and ${value[1]}${units} from the top`;
}
return 'the array `' + value.join('`, `') + '`';
default:
throw new Error(`unknown type for ${property.name}`);
}
@@ -252,7 +377,7 @@ global.propertyDefault = function (property, layerType) {
global.originalPropertyName = function (property) {
return property.original || property.name;
}
};
global.propertyType = function (property) {
switch (property.type) {
@@ -317,100 +442,144 @@ global.valueTransformerArguments = function (property) {
}
};
global.mbglType = function(property) {
switch (property.type) {
case 'boolean':
return 'bool';
case 'number':
return 'float';
case 'string':
return 'std::string';
case 'enum': {
let type = camelize(originalPropertyName(property));
if (/-translate-anchor$/.test(originalPropertyName(property))) {
type = 'TranslateAnchor';
}
if (/-(rotation|pitch)-alignment$/.test(originalPropertyName(property))) {
type = 'Alignment';
}
return `mbgl::style::${type}Type`;
}
case 'color':
return 'mbgl::Color';
case 'array':
switch (arrayType(property)) {
case 'dasharray':
return 'std::vector<float>';
case 'font':
return 'std::vector<std::string>';
case 'padding':
return 'std::array<float, 4>';
case 'offset':
case 'translate':
return 'std::array<float, 2>';
default:
throw new Error(`unknown array type for ${property.name}`);
}
default:
throw new Error(`unknown type for ${property.name}`);
}
};
global.initLayer = function (layerType) {
if (layerType == "background") {
return `_layer = new mbgl::style::${camelize(layerType)}Layer(identifier.UTF8String);`
} else {
return `_layer = new mbgl::style::${camelize(layerType)}Layer(identifier.UTF8String, source.identifier.UTF8String);`
}
}
};
global.setSourceLayer = function() {
return `_layer->setSourceLayer(sourceLayer.UTF8String);`
}
global.mbglType = function(property) {
let mbglType = camelize(originalPropertyName(property)) + 'Type';
if (/-translate-anchor$/.test(originalPropertyName(property))) {
mbglType = 'TranslateAnchorType';
}
if (/-(rotation|pitch)-alignment$/.test(originalPropertyName(property))) {
mbglType = 'AlignmentType';
}
return mbglType;
}
return `_layer->setSourceLayer(sourceLayer.UTF8String);`
};
const layerH = ejs.compile(fs.readFileSync('platform/darwin/src/MGLStyleLayer.h.ejs', 'utf8'), { strict: true });
const layerM = ejs.compile(fs.readFileSync('platform/darwin/src/MGLStyleLayer.mm.ejs', 'utf8'), { strict: true});
const testLayers = ejs.compile(fs.readFileSync('platform/darwin/test/MGLStyleLayerTests.m.ejs', 'utf8'), { strict: true});
const categoryH = ejs.compile(fs.readFileSync('platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h.ejs', 'utf8'), { strict: true});
const categoryM = ejs.compile(fs.readFileSync('platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm.ejs', 'utf8'), { strict: true});
const testLayers = ejs.compile(fs.readFileSync('platform/darwin/test/MGLStyleLayerTests.mm.ejs', 'utf8'), { strict: true});
const guideMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/For Style Authors.md.ejs', 'utf8'), { strict: true });
const layers = Object.keys(spec.layer.type.values).map((type) => {
const layoutProperties = Object.keys(spec[`layout_${type}`]).reduce((memo, name) => {
const layers = _(spec.layer.type.values).map((value, layerType) => {
const layoutProperties = Object.keys(spec[`layout_${layerType}`]).reduce((memo, name) => {
if (name !== 'visibility') {
spec[`layout_${type}`][name].name = name;
memo.push(spec[`layout_${type}`][name]);
spec[`layout_${layerType}`][name].name = name;
memo.push(spec[`layout_${layerType}`][name]);
}
return memo;
}, []);
const paintProperties = Object.keys(spec[`paint_${type}`]).reduce((memo, name) => {
spec[`paint_${type}`][name].name = name;
memo.push(spec[`paint_${type}`][name]);
const paintProperties = Object.keys(spec[`paint_${layerType}`]).reduce((memo, name) => {
spec[`paint_${layerType}`][name].name = name;
memo.push(spec[`paint_${layerType}`][name]);
return memo;
}, []);
return {
type: type,
doc: spec.layer.type.values[layerType].doc,
type: layerType,
layoutProperties: _.sortBy(layoutProperties, ['name']),
paintProperties: _.sortBy(paintProperties, ['name']),
layoutPropertiesByName: spec[`layout_${type}`],
paintPropertiesByName: spec[`paint_${type}`],
};
});
}).sortBy(['type']).value();
function duplicatePlatformDecls(src) {
// Look for a documentation comment that contains “MGLColor” and the
// subsequent function, method, or property declaration. Try not to match
// greedily.
return src.replace(/(\/\*\*(?:\*[^\/]|[^*])*?\bMGLColor\b[\s\S]*?\*\/)(\s*.+?;)/g,
// Look for a documentation comment that contains “MGLColor” or “UIColor”
// and the subsequent function, method, or property declaration. Try not to
// match greedily.
return src.replace(/(\/\*\*(?:\*[^\/]|[^*])*?\*\/)(\s*[^;]+?\b(?:MGL|NS|UI)(?:Color|EdgeInsets(?:Zero)?)\b[^;]+?;)/g,
(match, comment, decl) => {
let iosComment = comment.replace(/\bMGLColor\b/g, 'UIColor')
let macosComment = comment.replace(/\b(?:MGL|UI)(Color|EdgeInsets(?:Zero)?)\b/g, 'NS$1')
// Use the correct indefinite article.
.replace(/\b(a)n(\s+`?UIColor)\b/gi, '$1$2');
let macosComment = comment.replace(/\bMGLColor\b/g, 'NSColor');
.replace(/\ba(\s+`?NS(?:Color|EdgeInsets))\b/gi, 'an$1');
let iosDecl = decl.replace(/\bMGL(Color|EdgeInsets)\b/g, 'UI$1');
let macosDecl = decl.replace(/\b(?:MGL|UI)(Color|EdgeInsets)\b/g, 'NS$1');
return `\
#if TARGET_OS_IPHONE
${iosComment}${decl}
${comment}${iosDecl}
#else
${macosComment}${macosDecl}
#endif`;
})
// Do the same for CGVector-typed properties.
.replace(/(\/\*\*(?:\*[^\/]|[^*])*?\b(?:CGVector|UIEdgeInsets(?:Zero)?)\b[\s\S]*?\*\/)(\s*.+?;)/g,
(match, comment, decl) => {
let macosComment = comment.replace(/\bdownward\b/g, 'upward')
.replace(/\bUI(EdgeInsets(?:Zero)?)\b/g, 'NS$1');
return `\
#if TARGET_OS_IPHONE
${comment}${decl}
#else
${macosComment}${decl}
#endif`;
});
}
var allLayoutProperties = [];
var allPaintProperties = [];
var allTypes = [];
var renamedPropertiesByLayerType = {};
for (var layer of layers) {
allLayoutProperties.push(layer.layoutProperties);
allPaintProperties.push(layer.paintProperties);
allTypes.push(layer.type);
const containsEnumerationProperties = _.filter(layer.layoutProperties, function(property){ return property["type"] === "enum"; }).length || _.filter(layer.paintProperties, function(property){ return property["type"] === "enum"; }).length;
layer.containsEnumerationProperties = containsEnumerationProperties;
layer.properties = _.concat(layer.layoutProperties, layer.paintProperties);
let enumProperties = _.filter(layer.properties, prop => prop.type === 'enum');
if (enumProperties.length) {
layer.enumProperties = enumProperties;
}
writeIfModified(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.h`, duplicatePlatformDecls(layerH(layer)));
writeIfModified(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.mm`, layerM(layer));
writeIfModified(`platform/darwin/test/${prefix}${camelize(layer.type)}${suffix}Tests.m`, testLayers(layer));
let renamedProperties = {};
_.assign(renamedProperties, _.filter(layer.properties, prop => 'original' in prop || 'getter' in prop));
if (!_.isEmpty(renamedProperties)) {
renamedPropertiesByLayerType[layer.type] = renamedProperties;
}
fs.writeFileSync(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.h`, duplicatePlatformDecls(layerH(layer)));
fs.writeFileSync(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.mm`, layerM(layer));
fs.writeFileSync(`platform/darwin/test/${prefix}${camelize(layer.type)}${suffix}Tests.mm`, testLayers(layer));
}
fs.writeFileSync(`platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h`, categoryH({
layoutProperties: _.flatten(allLayoutProperties),
paintProperties: _.flatten(allPaintProperties),
types: allTypes
fs.writeFileSync(`platform/ios/docs/guides/For Style Authors.md`, guideMD({
os: 'iOS',
renamedProperties: renamedPropertiesByLayerType,
layers: layers,
}));
fs.writeFileSync(`platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm`, categoryM({
layoutProperties: _.flatten(allLayoutProperties),
paintProperties: _.flatten(allPaintProperties)
fs.writeFileSync(`platform/macos/docs/guides/For Style Authors.md`, guideMD({
os: 'macOS',
renamedProperties: renamedPropertiesByLayerType,
layers: layers,
}));

View File

@@ -9,13 +9,26 @@
"icon-size": "icon-scale",
"symbol-avoid-edges": "symbol-avoids-edges",
"text-allow-overlap": "text-allows-overlap",
"text-field": "text",
"text-font": "text-font-names",
"text-ignore-placement": "text-ignores-placement",
"text-justify": "text-justification",
"text-keep-upright": "keeps-text-upright",
"text-max-angle": "maximum-text-angle",
"text-max-width": "maximum-text-width",
"text-optional": "is-text-optional",
"text-rotate": "text-rotation"
"text-rotate": "text-rotation",
"text-size": "text-font-size"
},
"paint_circle": {
"circle-pitch-scale": "circle-scale-alignment",
"circle-translate": "circle-translation",
"circle-translate-anchor": "circle-translation-anchor"
},
"paint_fill": {
"fill-antialias": "is-fill-antialiased",
"fill-translate": "fill-translation",
"fill-translate-anchor": "fill-translation-anchor"
},
"paint_raster": {
"raster-brightness-min": "minimum-raster-brightness",
@@ -23,9 +36,14 @@
"raster-hue-rotate": "raster-hue-rotation"
},
"paint_line": {
"line-dasharray": "line-dash-pattern"
"line-dasharray": "line-dash-pattern",
"line-translate": "line-translation",
"line-translate-anchor": "line-translation-anchor"
},
"paint_fill": {
"fill-antialias": "is-fill-antialiased"
"paint_symbol": {
"icon-translate": "icon-translation",
"icon-translate-anchor": "icon-translation-anchor",
"text-translate": "text-translation",
"text-translate-anchor": "text-translation-anchor"
}
}

View File

@@ -1,4 +1,28 @@
{
"layer": {
"type": {
"values": {
"fill": {
"doc": "An `MGLFillStyleLayer` is a style layer that renders one or more filled (and optionally stroked) polygons on the map.\n\nUse a fill style layer to configure the visual appearance of polygon or multipolygon features in vector tiles loaded by an `MGLVectorSource` object or `MGLPolygon`, `MGLPolygonFeature`, `MGLMultiPolygon`, or `MGLMultiPolygonFeature` instances in an `MGLShapeSource` object."
},
"line": {
"doc": "An `MGLLineStyleLayer` is a style layer that renders one or more stroked polylines on the map.\n\nUse a line style layer to configure the visual appearance of polyline or multipolyline features in vector tiles loaded by an `MGLVectorSource` object or `MGLPolyline`, `MGLPolylineFeature`, `MGLMultiPolyline`, or `MGLMultiPolylineFeature` instances in an `MGLShapeSource` object."
},
"symbol": {
"doc": "An `MGLSymbolStyleLayer` is a style layer that renders icon and text labels at points or along lines on the map.\n\nUse a symbol style layer to configure the visual appearance of labels for features in vector tiles loaded by an `MGLVectorSource` object or `MGLShape` or `MGLFeature` instances in an `MGLShapeSource` object."
},
"circle": {
"doc": "An `MGLCircleStyleLayer` is a style layer that renders one or more filled circles on the map.\n\nUse a circle style layer to configure the visual appearance of point or point collection features in vector tiles loaded by an `MGLVectorSource` object or `MGLPointAnnotation`, `MGLPointFeature`, `MGLPointCollection`, or `MGLPointCollectionFeature` instances in an `MGLShapeSource` object.\n\nA circle style layer renders circles whose radii are measured in screen units. To display circles on the map whose radii correspond to real-world distances, use many-sided regular polygons and configure their appearance using an `MGLFillStyleLayer` object."
},
"raster": {
"doc": "An `MGLRasterStyleLayer` is a style layer that renders raster tiles on the map.\n\nUse a raster style layer to configure the color parameters of raster tiles loaded by an `MGLRasterSource` object. For example, you could use a raster style layer to render <a href=\"https://www.mapbox.com/satellite/\">Mapbox Satellite</a> imagery, a <a href=\"https://www.mapbox.com/help/define-tileset/#raster-tilesets\">raster tile set</a> uploaded to Mapbox Studio, or a raster map authored in <a href=\"https://tilemill-project.github.io/tilemill/\">TileMill</a>, the classic Mapbox Editor, or Mapbox Studio Classic."
},
"background": {
"doc": "An `MGLBackgroundStyleLayer` is a style layer that covers the entire map. Use a background style layer to configure a color or pattern to show below all other map content. If the style’s other layers use the Mapbox Streets source, the background style layer is responsible for drawing land, whereas the oceans and other bodies of water are drawn by `MGLFillStyleLayer` objects.\n\nA background style layer is typically the bottommost layer in a style, because it covers the entire map and can occlude any layers below it. You can therefore access it by getting the last item in the `MGLStyle.layers` array.\n\nIf the background style layer is transparent or omitted from the style, any portion of the map view that does not show another style layer is transparent."
}
}
}
},
"layout_symbol": {
"icon-text-fit-padding": {
"doc": "Size of the additional area added to dimensions determined by `icon-text-fit`."
@@ -6,6 +30,9 @@
"icon-offset": {
"doc": "Offset distance of icon from its anchor."
},
"text-font": {
"doc": "An array of font face names used to display the text.\n\nEach font name must be included in the `{fontstack}` portion of the JSON stylesheet’s <a href=\"https://www.mapbox.com/mapbox-gl-style-spec/#glyphs\"><code>glyphs</code></a> property. You can register a custom font when designing the style in Mapbox Studio. Fonts installed on the system are not used.\n\nThe first font named in the array is applied to the text. For each character in the text, if the first font lacks a glyph for the character, the next font is applied as a fallback, and so on."
},
"text-offset": {
"doc": "Offset distance of text from its anchor."
},

View File

@@ -0,0 +1,152 @@
'use strict';
const fs = require('fs');
const execFileSync = require('child_process').execFileSync;
const _ = require('lodash');
const examplesSrc = fs.readFileSync('platform/darwin/test/MGLDocumentationExampleTests.swift', 'utf8');
// Regex extracts the following block
// /** Front matter to describe the example. **/
// func testMGLClass$member() {
// ...
// //#-example-code
// let sampleCode: String?
// //#-end-example-code
// ...
// }
//
// into the following regex groups:
// 1 (test method name): "MGLClass" or "MGLClass$member" or "MGLClass$initWithArg_anotherArg_"
// 2 (indentation): " "
// 3 (sample code): "let sampleCode: String?"
const exampleRegex = /func test([\w$]+)\s*\(\)\s*\{[^]*?\n([ \t]+)\/\/#-example-code\n([^]+?)\n\2\/\/#-end-example-code\n/gm;
/**
* Returns the given source with example code inserted into the documentation
* comment for the symbol at the given one-based line.
*
* @param {String} src Source code to insert the example code into.
* @param {Number} line One-based line number of the symbol being documented.
* @param {String} exampleCode Example code to insert.
* @returns {String} `src` with `exampleCode` inserted just above `line`.
*/
function completeSymbolInSource(src, line, exampleCode) {
// Split the file contents right before the symbol declaration (but after its documentation comment).
let srcUpToSymbol = src.split('\n', line - 1).join('\n');
let srcFromSymbol = src.substr(srcUpToSymbol.length);
// Match the documentation comment block that is not followed by the beginning or end of a declaration.
let commentMatch = srcUpToSymbol.match(/\/\*\*\s*(?:[^*]|\*(?!\/))+?\s*\*\/[^;{}]*?$/);
// Replace the Swift code block with the test method’s contents.
let completedComment = commentMatch[0].replace(/^([ \t]*)```swift\n[^]*?```/m, function (m, indentation) {
// Apply the original indentation to each line.
return ('```swift\n' + exampleCode + '\n```').replace(/^/gm, indentation);
});
// Splice the modified comment into the overall file contents.
srcUpToSymbol = (srcUpToSymbol.substr(0, commentMatch.index) + completedComment +
srcUpToSymbol.substr(commentMatch.index + commentMatch[0].length));
return srcUpToSymbol + srcFromSymbol;
}
let examples = {};
let match;
while ((match = exampleRegex.exec(examplesSrc)) !== null) {
let testMethodName = match[1],
indentation = match[2],
exampleCode = match[3];
// Trim leading whitespace from the example code.
exampleCode = exampleCode.replace(new RegExp('^' + indentation, 'gm'), '');
examples[testMethodName] = exampleCode;
}
function completeExamples(os) {
console.log(`Installing ${os} SDK examples…`);
let sdk = os === 'iOS' ? 'iphonesimulator' : 'macosx';
let sysroot = execFileSync('xcrun', ['--show-sdk-path', '--sdk', sdk]).toString().trim();
let umbrellaPath = `platform/${os.toLowerCase()}/src/Mapbox.h`;
let docArgs = ['doc', '--objc', umbrellaPath, '--',
'-x', 'objective-c', '-I', 'platform/darwin/src/', '-isysroot', sysroot];
let docStr = execFileSync('sourcekitten', docArgs).toString().trim();
let docJson = JSON.parse(docStr);
_.forEach(docJson, function (result) {
_.forEach(result, function (structure, path) {
let src;
let newSrc;
// Recursively search for code blocks in documentation comments and populate
// them with example code from the test methods. Find and replace the code
// blocks in reverse to keep the SourceKitten line numbers accurate.
_.forEachRight(structure['key.substructure'], function completeSubstructure(substructure, idx, substructures, symbolPath) {
if (!symbolPath) {
symbolPath = [substructure['key.name']];
}
_.forEachRight(substructure['key.substructure'], function (substructure, idx, substructures) {
completeSubstructure(substructure, idx, substructures, _.concat(symbolPath, substructure['key.name']));
});
let comment = substructure['key.doc.comment'];
if (!comment || !comment.match(/^(?:\s*)```swift\n/m)) {
return;
}
// Lazily read in the existing file.
if (!src) {
newSrc = src = fs.readFileSync(path, 'utf8');
}
// Get the contents of the test method whose name matches the symbol path.
let testMethodName = symbolPath.join('$').replace(/\$[+-]/, '$').replace(/:/g, '_');
let example = examples[testMethodName];
if (!example) {
console.error(`MGLDocumentationExampleTests.${testMethodName}() not found.`);
process.exit(1);
}
// Resolve conditional compilation blocks.
example = example.replace(/^(\s*)#if\s+os\((iOS|macOS)\)\n([^]*?)(?:^\1#else\n([^]*?))?^\1#endif\n/gm,
function (m, indentation, ifOs, ifCase, elseCase) {
return (os === ifOs ? ifCase : elseCase).replace(new RegExp('^ ', 'gm'), '');
});
// Insert the test method contents into the documentation comment just
// above the substructure.
let startLine = substructure['key.parsed_scope.start'];
newSrc = completeSymbolInSource(newSrc, startLine, example);
});
if (!src) {
return;
}
// Write out the modified file contents.
if (src === newSrc) {
console.log('Skipping', path);
} else {
console.log('Updating', path);
if (['0', 'false'].indexOf(process.env.DRY_RUN || '0') !== -1) {
fs.writeFileSync(path, newSrc);
}
}
});
});
}
function ensureSourceKittenIsInstalled() {
try {
execFileSync('which', ['sourcekitten']);
} catch (e) {
console.log(`Installing SourceKitten via Homebrew…`);
execFileSync('brew', ['install', 'sourcekitten']);
}
}
ensureSourceKittenIsInstalled();
// Where a particular comment is part of both SDKs, prefer the iOS example.
completeExamples('macOS');
completeExamples('iOS');

View File

@@ -51,7 +51,7 @@ MGL_EXPORT
coordinate and zoom level.
@param centerCoordinate The map’s center coordinate.
@param zoomLevel The map’s zoom level. See `MGLMapView`’s `zoomLevel` property
@param zoomLevel The map’s zoom level. See the `MGLMapView.zoomLevel` property
for more information.
@return A modified URL containing a fragment that points to the specified
viewport. If the `feedbackLink` property is set to `NO`, this method returns

View File

@@ -26,9 +26,20 @@
// Apply a bogus, easily detectable style rule to any feedback link, since
// NSAttributedString doesn’t preserve the class attribute.
NSMutableString *css = [NSMutableString stringWithString:
@"html { font-family: -apple-system, -apple-system-font, sans-serif; }"
@".mapbox-improve-map { -webkit-text-stroke-width: 1000px; }"];
if (fontSize) {
[css appendFormat:@"html { font-size: %.1fpx; }", fontSize];
NSString *sizeRule = [NSString stringWithFormat:@"font-size: %.1fpx;", fontSize];
#if !TARGET_OS_IPHONE
if (fontSize == [NSFont systemFontSizeForControlSize:NSMiniControlSize]) {
sizeRule = @"font: -webkit-mini-control";
} else if (fontSize == [NSFont systemFontSizeForControlSize:NSSmallControlSize]) {
sizeRule = @"font: -webkit-small-control";
} else if (fontSize == [NSFont systemFontSizeForControlSize:NSRegularControlSize]) {
sizeRule = @"font: -webkit-control";
}
#endif
[css appendFormat:@"html { %@ }", sizeRule];
}
if (linkColor) {
CGFloat red;

View File

@@ -8,10 +8,18 @@
NS_ASSUME_NONNULL_BEGIN
/**
A map style's background layer is the bottommost layer and is used to style a color
or pattern to show below all other map features. You can query an `MGLMapView` for its
`style` and obtain the background layer using the `-[MGLStyle layerWithIdentifier:]`
method and passing `background` for the identifier.
An `MGLBackgroundStyleLayer` is a style layer that covers the entire map. Use a
background style layer to configure a color or pattern to show below all other
map content. If the style’s other layers use the Mapbox Streets source, the
background style layer is responsible for drawing land, whereas the oceans and
other bodies of water are drawn by `MGLFillStyleLayer` objects.
A background style layer is typically the bottommost layer in a style, because
it covers the entire map and can occlude any layers below it. You can therefore
access it by getting the last item in the `MGLStyle.layers` array.
If the background style layer is transparent or omitted from the style, any
portion of the map view that does not show another style layer is transparent.
*/
MGL_EXPORT
@interface MGLBackgroundStyleLayer : MGLStyleLayer
@@ -24,31 +32,41 @@ MGL_EXPORT
/**
The color with which the background will be drawn.
The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `backgroundPattern` is set to `nil`. Otherwise, it is ignored.
The default value of this property is an `MGLStyleValue` object containing
`UIColor.blackColor`. Set this property to `nil` to reset it to the default
value.
This property is only applied to the style if `backgroundPattern` is set to
`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *backgroundColor;
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *backgroundColor;
#else
/**
The color with which the background will be drawn.
The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `backgroundPattern` is set to `nil`. Otherwise, it is ignored.
The default value of this property is an `MGLStyleValue` object containing
`NSColor.blackColor`. Set this property to `nil` to reset it to the default
value.
This property is only applied to the style if `backgroundPattern` is set to
`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *backgroundColor;
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *backgroundColor;
#endif
/**
The opacity at which the background will be drawn.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *backgroundOpacity;
/**
Name of image in style images to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
Name of image in style images to use for drawing an image background. For
seamless patterns, image width and height must be a factor of two (2, 4, 8,
..., 512).
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *backgroundPattern;

View File

@@ -1,5 +1,5 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "MGLMapView_Private.h"
@@ -8,6 +8,7 @@
#import "MGLStyleValue_Private.h"
#import "MGLBackgroundStyleLayer.h"
#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/background_layer.hpp>
@interface MGLBackgroundStyleLayer ()

View File

@@ -10,40 +10,71 @@ NS_ASSUME_NONNULL_BEGIN
/**
Controls the scaling behavior of the circle when the map is pitched.
Values of this type are used in the `circlePitchScale` property of `MGLCircleStyleLayer`.
Values of this type are used in the `MGLCircleStyleLayer.circleScaleAlignment`
property.
*/
typedef NS_ENUM(NSUInteger, MGLCirclePitchScale) {
typedef NS_ENUM(NSUInteger, MGLCircleScaleAlignment) {
/**
Circles are scaled according to their apparent distance to the camera.
*/
MGLCirclePitchScaleMap,
MGLCircleScaleAlignmentMap,
/**
Circles are not scaled.
*/
MGLCirclePitchScaleViewport,
MGLCircleScaleAlignmentViewport,
};
/**
Controls the translation reference point.
Values of this type are used in the `circleTranslateAnchor` property of `MGLCircleStyleLayer`.
Values of this type are used in the `MGLCircleStyleLayer.circleTranslationAnchor`
property.
*/
typedef NS_ENUM(NSUInteger, MGLCircleTranslateAnchor) {
typedef NS_ENUM(NSUInteger, MGLCircleTranslationAnchor) {
/**
The circle is translated relative to the map.
*/
MGLCircleTranslateAnchorMap,
MGLCircleTranslationAnchorMap,
/**
The circle is translated relative to the viewport.
*/
MGLCircleTranslateAnchorViewport,
MGLCircleTranslationAnchorViewport,
};
/**
A circle layer which allows customization of styling properties at runtime. You may
instantiate a new circle layer to add to a map style or you may query an
`MGLMapView` for its `style` and obtain existing layers using the
`-[MGLStyle layerWithIdentifier:]` method.
An `MGLCircleStyleLayer` is a style layer that renders one or more filled
circles on the map.
Use a circle style layer to configure the visual appearance of point or point
collection features in vector tiles loaded by an `MGLVectorSource` object or
`MGLPointAnnotation`, `MGLPointFeature`, `MGLPointCollection`, or
`MGLPointCollectionFeature` instances in an `MGLShapeSource` object.
A circle style layer renders circles whose radii are measured in screen units.
To display circles on the map whose radii correspond to real-world distances,
use many-sided regular polygons and configure their appearance using an
`MGLFillStyleLayer` object.
You can access an existing circle style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
otherwise, find it using the `MGLStyle.layers` property. You can also create a
new circle style layer and add it to the style using a method such as
`-[MGLStyle addLayer:]`.
### Example
```swift
let layer = MGLCircleStyleLayer(identifier: "circles", source: population)
layer.sourceLayerIdentifier = "population"
layer.circleColor = MGLStyleValue(rawValue: .green)
layer.circleRadius = MGLStyleValue(interpolationBase: 1.75, stops: [
12: MGLStyleValue(rawValue: 2),
22: MGLStyleValue(rawValue: 180)
])
layer.circleOpacity = MGLStyleValue(rawValue: 0.7)
layer.predicate = NSPredicate(format: "%K == %@", "marital-status", "married")
mapView.style?.addLayer(layer)
```
*/
MGL_EXPORT
@interface MGLCircleStyleLayer : MGLVectorStyleLayer
@@ -51,9 +82,12 @@ MGL_EXPORT
#pragma mark - Accessing the Paint Attributes
/**
Amount to blur the circle. 1 blurs the circle such that only the centerpoint is full opacity.
Amount to blur the circle. 1 blurs the circle such that only the centerpoint is
full opacity.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleBlur;
@@ -61,90 +95,185 @@ MGL_EXPORT
/**
The fill color of the circle.
The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing
`UIColor.blackColor`. Set this property to `nil` to reset it to the default
value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *circleColor;
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *circleColor;
#else
/**
The fill color of the circle.
The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing
`NSColor.blackColor`. Set this property to `nil` to reset it to the default
value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *circleColor;
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *circleColor;
#endif
/**
The opacity at which the circle will be drawn.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleOpacity;
/**
Controls the scaling behavior of the circle when the map is pitched.
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLCirclePitchScaleMap`. Set this property to `nil` to reset it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circlePitchScale;
/**
Circle radius.
This property is measured in points.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `5`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `5`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleRadius;
/**
Controls the scaling behavior of the circle when the map is pitched.
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing `MGLCircleScaleAlignmentMap`. Set this property to
`nil` to reset it to the default value.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-pitch-scale"><code>circle-pitch-scale</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleScaleAlignment;
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circlePitchScale __attribute__((unavailable("Use circleScaleAlignment instead.")));
#if TARGET_OS_IPHONE
/**
The stroke color of the circle.
The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing
`UIColor.blackColor`. Set this property to `nil` to reset it to the default
value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *circleStrokeColor;
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *circleStrokeColor;
#else
/**
The stroke color of the circle.
The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing
`NSColor.blackColor`. Set this property to `nil` to reset it to the default
value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *circleStrokeColor;
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *circleStrokeColor;
#endif
/**
The opacity of the circle's stroke.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleStrokeOpacity;
/**
The width of the circle's stroke. Strokes are placed outside of the `circleRadius`.
The width of the circle's stroke. Strokes are placed outside of the
"circle-radius".
This property is measured in points.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleStrokeWidth;
#if TARGET_OS_IPHONE
/**
The geometry's offset.
This property is measured in points.
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing a `CGVector` struct set to 0 points from the left and 0 points from the top. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points downward. Set this property to `nil` to reset it to the default value.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-translate"><code>circle-translate</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslate;
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslation;
#else
/**
The geometry's offset.
This property is measured in points.
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points upward. Set this property to `nil` to reset it to the default value.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-translate"><code>circle-translate</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslation;
#endif
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslate __attribute__((unavailable("Use circleTranslation instead.")));
/**
Controls the translation reference point.
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLCircleTranslateAnchorMap`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `circleTranslate` is non-`nil`. Otherwise, it is ignored.
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing `MGLCircleTranslationAnchorMap`. Set this property
to `nil` to reset it to the default value.
This property is only applied to the style if `circleTranslation` is non-`nil`.
Otherwise, it is ignored.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-translate-anchor"><code>circle-translate-anchor</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslateAnchor;
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslationAnchor;
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslateAnchor __attribute__((unavailable("Use circleTranslationAnchor instead.")));
@end
/**
Methods for wrapping an enumeration value for a style layer attribute in an
`MGLCircleStyleLayer` object and unwrapping its raw value.
*/
@interface NSValue (MGLCircleStyleLayerAdditions)
#pragma mark Working with Circle Style Layer Attribute Values
/**
Creates a new value object containing the given `MGLCircleScaleAlignment` enumeration.
@param circleScaleAlignment The value for the new object.
@return A new value object that contains the enumeration value.
*/
+ (instancetype)valueWithMGLCircleScaleAlignment:(MGLCircleScaleAlignment)circleScaleAlignment;
/**
The `MGLCircleScaleAlignment` enumeration representation of the value.
*/
@property (readonly) MGLCircleScaleAlignment MGLCircleScaleAlignmentValue;
/**
Creates a new value object containing the given `MGLCircleTranslationAnchor` enumeration.
@param circleTranslationAnchor The value for the new object.
@return A new value object that contains the enumeration value.
*/
+ (instancetype)valueWithMGLCircleTranslationAnchor:(MGLCircleTranslationAnchor)circleTranslationAnchor;
/**
The `MGLCircleTranslationAnchor` enumeration representation of the value.
*/
@property (readonly) MGLCircleTranslationAnchor MGLCircleTranslationAnchorValue;
@end

View File

@@ -1,5 +1,5 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "MGLMapView_Private.h"
@@ -8,17 +8,19 @@
#import "MGLStyleValue_Private.h"
#import "MGLCircleStyleLayer.h"
#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
namespace mbgl {
MBGL_DEFINE_ENUM(MGLCirclePitchScale, {
{ MGLCirclePitchScaleMap, "map" },
{ MGLCirclePitchScaleViewport, "viewport" },
MBGL_DEFINE_ENUM(MGLCircleScaleAlignment, {
{ MGLCircleScaleAlignmentMap, "map" },
{ MGLCircleScaleAlignmentViewport, "viewport" },
});
MBGL_DEFINE_ENUM(MGLCircleTranslateAnchor, {
{ MGLCircleTranslateAnchorMap, "map" },
{ MGLCircleTranslateAnchorViewport, "viewport" },
MBGL_DEFINE_ENUM(MGLCircleTranslationAnchor, {
{ MGLCircleTranslationAnchorMap, "map" },
{ MGLCircleTranslationAnchorViewport, "viewport" },
});
}
@@ -54,6 +56,13 @@ namespace mbgl {
super.rawLayer = rawLayer;
}
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
return @(self.rawLayer->getSourceID().c_str());
}
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -73,7 +82,7 @@ namespace mbgl {
{
MGLAssertStyleLayerIsValid();
self.rawLayer->setFilter(predicate.mgl_filter);
self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter());
}
- (NSPredicate *)predicate
@@ -166,20 +175,6 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setCirclePitchScale:(MGLStyleValue<NSValue *> *)circlePitchScale {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCirclePitchScale>().toEnumPropertyValue(circlePitchScale);
self.rawLayer->setCirclePitchScale(mbglValue);
}
- (MGLStyleValue<NSValue *> *)circlePitchScale {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCirclePitchScale() ?: self.rawLayer->getDefaultCirclePitchScale();
return MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCirclePitchScale>().toEnumStyleValue(propertyValue);
}
- (void)setCircleRadius:(MGLStyleValue<NSNumber *> *)circleRadius {
MGLAssertStyleLayerIsValid();
@@ -194,6 +189,27 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setCircleScaleAlignment:(MGLStyleValue<NSValue *> *)circleScaleAlignment {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCircleScaleAlignment>().toEnumPropertyValue(circleScaleAlignment);
self.rawLayer->setCirclePitchScale(mbglValue);
}
- (MGLStyleValue<NSValue *> *)circleScaleAlignment {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCirclePitchScale() ?: self.rawLayer->getDefaultCirclePitchScale();
return MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCircleScaleAlignment>().toEnumStyleValue(propertyValue);
}
- (void)setCirclePitchScale:(MGLStyleValue<NSValue *> *)circlePitchScale {
}
- (MGLStyleValue<NSValue *> *)circlePitchScale {
return self.circleScaleAlignment;
}
- (void)setCircleStrokeColor:(MGLStyleValue<MGLColor *> *)circleStrokeColor {
MGLAssertStyleLayerIsValid();
@@ -236,33 +252,71 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setCircleTranslate:(MGLStyleValue<NSValue *> *)circleTranslate {
- (void)setCircleTranslation:(MGLStyleValue<NSValue *> *)circleTranslation {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(circleTranslate);
auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(circleTranslation);
self.rawLayer->setCircleTranslate(mbglValue);
}
- (MGLStyleValue<NSValue *> *)circleTranslate {
- (MGLStyleValue<NSValue *> *)circleTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCircleTranslate() ?: self.rawLayer->getDefaultCircleTranslate();
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
- (void)setCircleTranslateAnchor:(MGLStyleValue<NSValue *> *)circleTranslateAnchor {
- (void)setCircleTranslate:(MGLStyleValue<NSValue *> *)circleTranslate {
}
- (MGLStyleValue<NSValue *> *)circleTranslate {
return self.circleTranslation;
}
- (void)setCircleTranslationAnchor:(MGLStyleValue<NSValue *> *)circleTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslateAnchor>().toEnumPropertyValue(circleTranslateAnchor);
auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslationAnchor>().toEnumPropertyValue(circleTranslationAnchor);
self.rawLayer->setCircleTranslateAnchor(mbglValue);
}
- (MGLStyleValue<NSValue *> *)circleTranslateAnchor {
- (MGLStyleValue<NSValue *> *)circleTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCircleTranslateAnchor() ?: self.rawLayer->getDefaultCircleTranslateAnchor();
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslateAnchor>().toEnumStyleValue(propertyValue);
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslationAnchor>().toEnumStyleValue(propertyValue);
}
- (void)setCircleTranslateAnchor:(MGLStyleValue<NSValue *> *)circleTranslateAnchor {
}
- (MGLStyleValue<NSValue *> *)circleTranslateAnchor {
return self.circleTranslationAnchor;
}
@end
@implementation NSValue (MGLCircleStyleLayerAdditions)
+ (NSValue *)valueWithMGLCircleScaleAlignment:(MGLCircleScaleAlignment)circleScaleAlignment {
return [NSValue value:&circleScaleAlignment withObjCType:@encode(MGLCircleScaleAlignment)];
}
- (MGLCircleScaleAlignment)MGLCircleScaleAlignmentValue {
MGLCircleScaleAlignment circleScaleAlignment;
[self getValue:&circleScaleAlignment];
return circleScaleAlignment;
}
+ (NSValue *)valueWithMGLCircleTranslationAnchor:(MGLCircleTranslationAnchor)circleTranslationAnchor {
return [NSValue value:&circleTranslationAnchor withObjCType:@encode(MGLCircleTranslationAnchor)];
}
- (MGLCircleTranslationAnchor)MGLCircleTranslationAnchorValue {
MGLCircleTranslationAnchor circleTranslationAnchor;
[self getValue:&circleTranslationAnchor];
return circleTranslationAnchor;
}
@end

View File

@@ -11,30 +11,41 @@ NS_ASSUME_NONNULL_BEGIN
/**
The `MGLFeature` protocol is used to provide details about geographic features
contained in a map view’s
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile sources</a>.
Each concrete subclass of `MGLShape` in turn has a subclass that conforms to
this protocol.
contained in an `MGLShapeSource` or `MGLVectorSource` object. Each concrete
subclass of `MGLShape` in turn has a subclass that conforms to this protocol. A
feature object associates a shape with an optional identifier and attributes.
Typically, you do not create feature objects yourself but rather obtain them
using `-[MGLMapView visibleFeaturesAtPoint:]` and related methods. Each feature
object associates a shape with an identifier and attributes as specified by the
source. Like ordinary `MGLAnnotation` objects, some kinds of `MGLFeature`
objects can also be added to a map view using an `MGLShapeSource` or
`-[MGLMapView addAnnotations:]` and related methods.
You can add custom data to display on the map by creating feature objects and
adding them to an `MGLShapeSource` using the
`-[MGLShapeSource initWithIdentifier:shape:options:]` method or
`MGLShapeSource.shape` property. Similarly, you can add `MGLPointFeature`,
`MGLPolylineFeature`, and `MGLPolygonFeature` objects to the map as annotations
using `-[MGLMapView addAnnotations:]` and related methods.
In addition to adding data to the map, you can also extract data from the map:
`-[MGLMapView visibleFeaturesAtPoint:]` and related methods return feature
objects that correspond to features in the source. This enables you to inspect
the properties of features in vector tiles loaded by `MGLVectorSource` objects.
You also reuse these feature objects as overlay annotations.
*/
@protocol MGLFeature <MGLAnnotation>
/**
An object that uniquely identifies the feature in its containing
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
An object that uniquely identifies the feature in its containing content
source.
The identifier corresponds to the
You can configure an `MGLVectorStyleLayer` object to include or exclude a
specific feature in an `MGLShapeSource` or `MGLVectorSource`. In the
`MGLVectorStyleLayer.predicate` property, compare the special `$id` attribute
to the feature’s identifier.
In vector tiles loaded by `MGLVectorSource` objects, the identifier corresponds
to the
<a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1#42-features">feature identifier</a>
(`id`) in the tile source. If the source does not specify the feature’s
identifier, the value of this property is `nil`. If specified, the identifier
may be an integer, floating-point number, or string. These data types are
mapped to instances of the following Foundation classes:
(`id`). If the source does not specify the feature’s identifier, the value of
this property is `nil`. If specified, the identifier may be an integer,
floating-point number, or string. These data types are mapped to instances of
the following Foundation classes:
<table>
<thead>
@@ -50,22 +61,40 @@ NS_ASSUME_NONNULL_BEGIN
For details about the identifiers used in most Mapbox-provided styles, consult
the
<a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets</a>
layer reference. Note that while it is possible to change this value on feature
instances obtained from `-[MGLMapView visibleFeaturesAtPoint:]` and related
methods, there will be no effect on the map. Setting this value can be useful
when the feature instance is used to initialize an `MGLShapeSource` and that
source is added to the map and styled.
layer reference.
The identifier should be set before adding the feature to an `MGLShapeSource`
object; setting it afterwards has no effect on the map’s contents. While it is
possible to change this value on feature instances obtained from
`-[MGLMapView visibleFeaturesAtPoint:]` and related methods, doing so likewise
has no effect on the map’s contents.
*/
@property (nonatomic, copy, nullable) id identifier;
/**
A dictionary of attributes for this feature specified by the
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
A dictionary of attributes for this feature.
The keys and values of this dictionary are determined by the tile source. In
the tile source, each attribute name is a string, while each attribute value
may be a null value, Boolean value, integer, floating-point number, or string.
These data types are mapped to instances of the following Foundation classes:
You can configure an `MGLVectorStyleLayer` object to include or exclude a
specific feature in an `MGLShapeSource` or `MGLVectorSource`. In the
`MGLVectorStyleLayer.predicate` property, compare a key of the attribute
dictionary to the value you want to include. For example, if you want an
`MGLLineStyleLayer` object to display only important features, you might assign
a value above 50 to the important features’ `importance` attribute, then set
`MGLVectorStyleLayer.predicate` to an `NSPredicate` with the format
`importance > 50`.
You can also configure some attributes of an `MGLSymbolStyleLayer` object to
include the value of an attribute in this dictionary whenever it renders this
feature. For example, to label features in an `MGLShapeSource` object by their
names, you can assign a `name` attribute to each of the source’s features, then
set `MGLSymbolStyleLayer.textField` to an `MGLStyleValue` object containing the
string `{name}`.
In vector tiles loaded by `MGLVectorSource` objects, the keys and values of
each feature’s attribute dictionary are determined by the source. Each
attribute name is a string, while each attribute value may be a null value,
Boolean value, integer, floating-point number, or string. These data types are
mapped to instances of the following Foundation classes:
<table>
<thead>
@@ -85,7 +114,9 @@ NS_ASSUME_NONNULL_BEGIN
<a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets</a>
and
<a href="https://www.mapbox.com/vector-tiles/mapbox-terrain/">Mapbox Terrain</a>
layer references. Note that while it is possible to change this value on feature
layer references.
Note that while it is possible to change this value on feature
instances obtained from `-[MGLMapView visibleFeaturesAtPoint:]` and related
methods, there will be no effect on the map. Setting this value can be useful
when the feature instance is used to initialize an `MGLShapeSource` and that
@@ -115,56 +146,75 @@ NS_ASSUME_NONNULL_BEGIN
@end
/**
The `MGLPointFeature` class represents a point in a
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
An `MGLPointFeature` object associates a point shape with an optional
identifier and attributes.
*/
MGL_EXPORT
@interface MGLPointFeature : MGLPointAnnotation <MGLFeature>
@end
/**
The `MGLPolylineFeature` class represents a polyline in a
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
An `MGLPolylineFeature` object associates a polyline shape with an optional
identifier and attributes.
A polyline feature is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.4">LineString</a>
feature in GeoJSON.
*/
MGL_EXPORT
@interface MGLPolylineFeature : MGLPolyline <MGLFeature>
@end
/**
The `MGLPolygonFeature` class represents a polygon in a
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
An `MGLPolygonFeature` object associates a polygon shape with an optional
identifier and attributes.
*/
MGL_EXPORT
@interface MGLPolygonFeature : MGLPolygon <MGLFeature>
@end
/**
The `MGLPointCollectionFeature` class represents a multipoint in a
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
An `MGLPointCollectionFeature` object associates a point collection with an
optional identifier and attributes.
A point collection feature is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.3">MultiPoint</a>
feature in GeoJSON.
*/
MGL_EXPORT
@interface MGLPointCollectionFeature : MGLPointCollection <MGLFeature>
@end
// https://github.com/mapbox/mapbox-gl-native/issues/7473
@compatibility_alias MGLMultiPointFeature MGLPointCollectionFeature;
/**
The `MGLMultiPolylineFeature` class represents a multipolyline in a
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
An `MGLMultiPolylineFeature` object associates a multipolyline shape with an
optional identifier and attributes.
A multipolyline feature is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.5">MultiLineString</a>
feature in GeoJSON.
*/
MGL_EXPORT
@interface MGLMultiPolylineFeature : MGLMultiPolyline <MGLFeature>
@end
/**
The `MGLMultiPolygonFeature` class represents a multipolygon in a
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
An `MGLMultiPolygonFeature` object associates a multipolygon shape with an
optional identifier and attributes.
*/
MGL_EXPORT
@interface MGLMultiPolygonFeature : MGLMultiPolygon <MGLFeature>
@end
/**
The `MGLShapeCollectionFeature` class represents a shape collection in a
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
An `MGLShapeCollectionFeature` object associates a shape collection with an
optional identifier and attributes.
A shape collection feature is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.3">feature collection</a>
in GeoJSON.
*/
MGL_EXPORT
@interface MGLShapeCollectionFeature : MGLShapeCollection <MGLFeature>

View File

@@ -10,6 +10,7 @@
#import "MGLPolyline+MGLAdditions.h"
#import "MGLPolygon+MGLAdditions.h"
#import "NSDictionary+MGLAdditions.h"
#import "NSArray+MGLAdditions.h"
#import "NSExpression+MGLAdditions.h"
@@ -25,6 +26,10 @@
@synthesize identifier;
@synthesize attributes;
MGL_DEFINE_FEATURE_INIT_WITH_CODER();
MGL_DEFINE_FEATURE_ENCODE();
MGL_DEFINE_FEATURE_IS_EQUAL();
- (id)attributeForKey:(NSString *)key {
return self.attributes[key];
}
@@ -47,6 +52,10 @@
@synthesize identifier;
@synthesize attributes;
MGL_DEFINE_FEATURE_INIT_WITH_CODER();
MGL_DEFINE_FEATURE_ENCODE();
MGL_DEFINE_FEATURE_IS_EQUAL();
- (id)attributeForKey:(NSString *)key {
return self.attributes[key];
}
@@ -69,6 +78,10 @@
@synthesize identifier;
@synthesize attributes;
MGL_DEFINE_FEATURE_INIT_WITH_CODER();
MGL_DEFINE_FEATURE_ENCODE();
MGL_DEFINE_FEATURE_IS_EQUAL();
- (id)attributeForKey:(NSString *)key {
return self.attributes[key];
}
@@ -91,6 +104,10 @@
@synthesize identifier;
@synthesize attributes;
MGL_DEFINE_FEATURE_INIT_WITH_CODER();
MGL_DEFINE_FEATURE_ENCODE();
MGL_DEFINE_FEATURE_IS_EQUAL();
- (id)attributeForKey:(NSString *)key {
return self.attributes[key];
}
@@ -113,6 +130,10 @@
@synthesize identifier;
@synthesize attributes;
MGL_DEFINE_FEATURE_INIT_WITH_CODER();
MGL_DEFINE_FEATURE_ENCODE();
MGL_DEFINE_FEATURE_IS_EQUAL();
- (id)attributeForKey:(NSString *)key {
return self.attributes[key];
}
@@ -135,6 +156,10 @@
@synthesize identifier;
@synthesize attributes;
MGL_DEFINE_FEATURE_INIT_WITH_CODER();
MGL_DEFINE_FEATURE_ENCODE();
MGL_DEFINE_FEATURE_IS_EQUAL();
- (id)attributeForKey:(NSString *)key {
return self.attributes[key];
}
@@ -159,10 +184,14 @@
@dynamic shapes;
+ (instancetype)shapeCollectionWithShapes:(NSArray *)shapes {
+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)shapes {
return [super shapeCollectionWithShapes:shapes];
}
MGL_DEFINE_FEATURE_INIT_WITH_CODER();
MGL_DEFINE_FEATURE_ENCODE();
MGL_DEFINE_FEATURE_IS_EQUAL();
- (id)attributeForKey:(NSString *)key {
return self.attributes[key];
}

View File

@@ -39,3 +39,31 @@ mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *at
NS_DICTIONARY_OF(NSString *, id) *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier);
NS_ASSUME_NONNULL_END
#define MGL_DEFINE_FEATURE_INIT_WITH_CODER() \
- (instancetype)initWithCoder:(NSCoder *)decoder { \
if (self = [super initWithCoder:decoder]) { \
NSSet<Class> *identifierClasses = [NSSet setWithArray:@[[NSString class], [NSNumber class]]]; \
identifier = [decoder decodeObjectOfClasses:identifierClasses forKey:@"identifier"]; \
attributes = [decoder decodeObjectOfClass:[NSDictionary class] forKey:@"attributes"]; \
} \
return self; \
}
#define MGL_DEFINE_FEATURE_ENCODE() \
- (void)encodeWithCoder:(NSCoder *)coder { \
[super encodeWithCoder:coder]; \
[coder encodeObject:identifier forKey:@"identifier"]; \
[coder encodeObject:attributes forKey:@"attributes"]; \
}
#define MGL_DEFINE_FEATURE_IS_EQUAL() \
- (BOOL)isEqual:(id)other { \
if (other == self) return YES; \
if (![other isKindOfClass:[self class]]) return NO; \
__typeof(self) otherFeature = other; \
return [super isEqual:other] && [self geoJSONObject] == [otherFeature geoJSONObject]; \
} \
- (NSUInteger)hash { \
return [super hash] + [[self geoJSONDictionary] hash]; \
}

View File

@@ -10,24 +10,44 @@ NS_ASSUME_NONNULL_BEGIN
/**
Controls the translation reference point.
Values of this type are used in the `fillTranslateAnchor` property of `MGLFillStyleLayer`.
Values of this type are used in the `MGLFillStyleLayer.fillTranslationAnchor`
property.
*/
typedef NS_ENUM(NSUInteger, MGLFillTranslateAnchor) {
typedef NS_ENUM(NSUInteger, MGLFillTranslationAnchor) {
/**
The fill is translated relative to the map.
*/
MGLFillTranslateAnchorMap,
MGLFillTranslationAnchorMap,
/**
The fill is translated relative to the viewport.
*/
MGLFillTranslateAnchorViewport,
MGLFillTranslationAnchorViewport,
};
/**
A fill layer which allows customization of styling properties at runtime. You may
instantiate a new fill layer to add to a map style or you may query an
`MGLMapView` for its `style` and obtain existing layers using the
`-[MGLStyle layerWithIdentifier:]` method.
An `MGLFillStyleLayer` is a style layer that renders one or more filled (and
optionally stroked) polygons on the map.
Use a fill style layer to configure the visual appearance of polygon or
multipolygon features in vector tiles loaded by an `MGLVectorSource` object or
`MGLPolygon`, `MGLPolygonFeature`, `MGLMultiPolygon`, or
`MGLMultiPolygonFeature` instances in an `MGLShapeSource` object.
You can access an existing fill style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
otherwise, find it using the `MGLStyle.layers` property. You can also create a
new fill style layer and add it to the style using a method such as
`-[MGLStyle addLayer:]`.
### Example
```swift
let layer = MGLFillStyleLayer(identifier: "parks", source: parks)
layer.sourceLayerIdentifier = "parks"
layer.fillColor = MGLStyleValue(rawValue: .green)
layer.predicate = NSPredicate(format: "type == %@", "national-park")
mapView.style?.addLayer(layer)
```
*/
MGL_EXPORT
@interface MGLFillStyleLayer : MGLVectorStyleLayer
@@ -37,71 +57,154 @@ MGL_EXPORT
/**
Whether or not the fill should be antialiased.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing `YES`. Set this property to `nil` to reset it to
the default value.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-antialias"><code>fill-antialias</code></a> paint property in the Mapbox Style Specification.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-antialias"><code>fill-antialias</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable, getter=isFillAntialiased) MGLStyleValue<NSNumber *> *fillAntialiased;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillAntialias __attribute__((unavailable("Use fillAntialiased instead.")));
#if TARGET_OS_IPHONE
/**
The color of the filled part of this layer.
The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `fillPattern` is set to `nil`. Otherwise, it is ignored.
The default value of this property is an `MGLStyleValue` object containing
`UIColor.blackColor`. Set this property to `nil` to reset it to the default
value.
This property is only applied to the style if `fillPattern` is set to `nil`.
Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *fillColor;
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *fillColor;
#else
/**
The color of the filled part of this layer.
The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `fillPattern` is set to `nil`. Otherwise, it is ignored.
The default value of this property is an `MGLStyleValue` object containing
`NSColor.blackColor`. Set this property to `nil` to reset it to the default
value.
This property is only applied to the style if `fillPattern` is set to `nil`.
Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *fillColor;
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *fillColor;
#endif
/**
The opacity of the entire fill layer. In contrast to the `fillColor`, this value will also affect the 1pt stroke around the fill, if the stroke is used.
The opacity of the entire fill layer. In contrast to the `fillColor`, this
value will also affect the 1pt stroke around the fill, if the stroke is used.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillOpacity;
#if TARGET_OS_IPHONE
/**
The outline color of the fill. Matches the value of `fillColor` if unspecified.
This property is only applied to the style if `fillPattern` is set to `nil`, and `fillAntialiased` is set to an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Otherwise, it is ignored.
This property is only applied to the style if `fillPattern` is set to `nil`,
and `fillAntialiased` is set to an `MGLStyleValue` object containing an
`NSNumber` object containing `YES`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *fillOutlineColor;
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *fillOutlineColor;
#else
/**
The outline color of the fill. Matches the value of `fillColor` if unspecified.
This property is only applied to the style if `fillPattern` is set to `nil`,
and `fillAntialiased` is set to an `MGLStyleValue` object containing an
`NSNumber` object containing `YES`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *fillOutlineColor;
#endif
/**
Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
Name of image in sprite to use for drawing image fills. For seamless patterns,
image width and height must be a factor of two (2, 4, 8, ..., 512).
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *fillPattern;
#if TARGET_OS_IPHONE
/**
The geometry's offset.
This property is measured in points.
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing a `CGVector` struct set to 0 points from the left and 0 points from the top. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points downward. Set this property to `nil` to reset it to the default value.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-translate"><code>fill-translate</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslate;
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslation;
#else
/**
The geometry's offset.
This property is measured in points.
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points upward. Set this property to `nil` to reset it to the default value.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-translate"><code>fill-translate</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslation;
#endif
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslate __attribute__((unavailable("Use fillTranslation instead.")));
/**
Controls the translation reference point.
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLFillTranslateAnchorMap`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `fillTranslate` is non-`nil`. Otherwise, it is ignored.
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing `MGLFillTranslationAnchorMap`. Set this property to
`nil` to reset it to the default value.
This property is only applied to the style if `fillTranslation` is non-`nil`.
Otherwise, it is ignored.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-translate-anchor"><code>fill-translate-anchor</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslateAnchor;
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslationAnchor;
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslateAnchor __attribute__((unavailable("Use fillTranslationAnchor instead.")));
@end
/**
Methods for wrapping an enumeration value for a style layer attribute in an
`MGLFillStyleLayer` object and unwrapping its raw value.
*/
@interface NSValue (MGLFillStyleLayerAdditions)
#pragma mark Working with Fill Style Layer Attribute Values
/**
Creates a new value object containing the given `MGLFillTranslationAnchor` enumeration.
@param fillTranslationAnchor The value for the new object.
@return A new value object that contains the enumeration value.
*/
+ (instancetype)valueWithMGLFillTranslationAnchor:(MGLFillTranslationAnchor)fillTranslationAnchor;
/**
The `MGLFillTranslationAnchor` enumeration representation of the value.
*/
@property (readonly) MGLFillTranslationAnchor MGLFillTranslationAnchorValue;
@end

View File

@@ -1,5 +1,5 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "MGLMapView_Private.h"
@@ -8,12 +8,14 @@
#import "MGLStyleValue_Private.h"
#import "MGLFillStyleLayer.h"
#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
namespace mbgl {
MBGL_DEFINE_ENUM(MGLFillTranslateAnchor, {
{ MGLFillTranslateAnchorMap, "map" },
{ MGLFillTranslateAnchorViewport, "viewport" },
MBGL_DEFINE_ENUM(MGLFillTranslationAnchor, {
{ MGLFillTranslationAnchorMap, "map" },
{ MGLFillTranslationAnchorViewport, "viewport" },
});
}
@@ -49,6 +51,13 @@ namespace mbgl {
super.rawLayer = rawLayer;
}
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
return @(self.rawLayer->getSourceID().c_str());
}
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -68,7 +77,7 @@ namespace mbgl {
{
MGLAssertStyleLayerIsValid();
self.rawLayer->setFilter(predicate.mgl_filter);
self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter());
}
- (NSPredicate *)predicate
@@ -133,9 +142,11 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setFillAntialias:(MGLStyleValue<NSNumber *> *)fillAntialias {
NSAssert(NO, @"Use -setFillAntialiased: instead.");
}
- (MGLStyleValue<NSNumber *> *)fillAntialias {
return self.isFillAntialiased;
}
- (void)setFillColor:(MGLStyleValue<MGLColor *> *)fillColor {
@@ -194,33 +205,61 @@ namespace mbgl {
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}
- (void)setFillTranslate:(MGLStyleValue<NSValue *> *)fillTranslate {
- (void)setFillTranslation:(MGLStyleValue<NSValue *> *)fillTranslation {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(fillTranslate);
auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(fillTranslation);
self.rawLayer->setFillTranslate(mbglValue);
}
- (MGLStyleValue<NSValue *> *)fillTranslate {
- (MGLStyleValue<NSValue *> *)fillTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillTranslate() ?: self.rawLayer->getDefaultFillTranslate();
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
- (void)setFillTranslateAnchor:(MGLStyleValue<NSValue *> *)fillTranslateAnchor {
- (void)setFillTranslate:(MGLStyleValue<NSValue *> *)fillTranslate {
}
- (MGLStyleValue<NSValue *> *)fillTranslate {
return self.fillTranslation;
}
- (void)setFillTranslationAnchor:(MGLStyleValue<NSValue *> *)fillTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslateAnchor>().toEnumPropertyValue(fillTranslateAnchor);
auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslationAnchor>().toEnumPropertyValue(fillTranslationAnchor);
self.rawLayer->setFillTranslateAnchor(mbglValue);
}
- (MGLStyleValue<NSValue *> *)fillTranslateAnchor {
- (MGLStyleValue<NSValue *> *)fillTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillTranslateAnchor() ?: self.rawLayer->getDefaultFillTranslateAnchor();
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslateAnchor>().toEnumStyleValue(propertyValue);
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslationAnchor>().toEnumStyleValue(propertyValue);
}
- (void)setFillTranslateAnchor:(MGLStyleValue<NSValue *> *)fillTranslateAnchor {
}
- (MGLStyleValue<NSValue *> *)fillTranslateAnchor {
return self.fillTranslationAnchor;
}
@end
@implementation NSValue (MGLFillStyleLayerAdditions)
+ (NSValue *)valueWithMGLFillTranslationAnchor:(MGLFillTranslationAnchor)fillTranslationAnchor {
return [NSValue value:&fillTranslationAnchor withObjCType:@encode(MGLFillTranslationAnchor)];
}
- (MGLFillTranslationAnchor)MGLFillTranslationAnchorValue {
MGLFillTranslationAnchor fillTranslationAnchor;
[self getValue:&fillTranslationAnchor];
return fillTranslationAnchor;
}
@end

View File

@@ -10,19 +10,24 @@ NS_ASSUME_NONNULL_BEGIN
/**
The display of line endings.
Values of this type are used in the `lineCap` property of `MGLLineStyleLayer`.
Values of this type are used in the `MGLLineStyleLayer.lineCap`
property.
*/
typedef NS_ENUM(NSUInteger, MGLLineCap) {
/**
A cap with a squared-off end which is drawn to the exact endpoint of the line.
A cap with a squared-off end which is drawn to the exact endpoint of the
line.
*/
MGLLineCapButt,
/**
A cap with a rounded end which is drawn beyond the endpoint of the line at a radius of one-half of the line's width and centered on the endpoint of the line.
A cap with a rounded end which is drawn beyond the endpoint of the line at
a radius of one-half of the line's width and centered on the endpoint of
the line.
*/
MGLLineCapRound,
/**
A cap with a squared-off end which is drawn beyond the endpoint of the line at a distance of one-half of the line's width.
A cap with a squared-off end which is drawn beyond the endpoint of the line
at a distance of one-half of the line's width.
*/
MGLLineCapSquare,
};
@@ -30,19 +35,24 @@ typedef NS_ENUM(NSUInteger, MGLLineCap) {
/**
The display of lines when joining.
Values of this type are used in the `lineJoin` property of `MGLLineStyleLayer`.
Values of this type are used in the `MGLLineStyleLayer.lineJoin`
property.
*/
typedef NS_ENUM(NSUInteger, MGLLineJoin) {
/**
A join with a squared-off end which is drawn beyond the endpoint of the line at a distance of one-half of the line's width.
A join with a squared-off end which is drawn beyond the endpoint of the
line at a distance of one-half of the line's width.
*/
MGLLineJoinBevel,
/**
A join with a rounded end which is drawn beyond the endpoint of the line at a radius of one-half of the line's width and centered on the endpoint of the line.
A join with a rounded end which is drawn beyond the endpoint of the line at
a radius of one-half of the line's width and centered on the endpoint of
the line.
*/
MGLLineJoinRound,
/**
A join with a sharp, angled corner which is drawn with the outer sides beyond the endpoint of the path until they meet.
A join with a sharp, angled corner which is drawn with the outer sides
beyond the endpoint of the path until they meet.
*/
MGLLineJoinMiter,
};
@@ -50,24 +60,49 @@ typedef NS_ENUM(NSUInteger, MGLLineJoin) {
/**
Controls the translation reference point.
Values of this type are used in the `lineTranslateAnchor` property of `MGLLineStyleLayer`.
Values of this type are used in the `MGLLineStyleLayer.lineTranslationAnchor`
property.
*/
typedef NS_ENUM(NSUInteger, MGLLineTranslateAnchor) {
typedef NS_ENUM(NSUInteger, MGLLineTranslationAnchor) {
/**
The line is translated relative to the map.
*/
MGLLineTranslateAnchorMap,
MGLLineTranslationAnchorMap,
/**
The line is translated relative to the viewport.
*/
MGLLineTranslateAnchorViewport,
MGLLineTranslationAnchorViewport,
};
/**
A line layer which allows customization of styling properties at runtime. You may
instantiate a new line layer to add to a map style or you may query an
`MGLMapView` for its `style` and obtain existing layers using the
`-[MGLStyle layerWithIdentifier:]` method.
An `MGLLineStyleLayer` is a style layer that renders one or more stroked
polylines on the map.
Use a line style layer to configure the visual appearance of polyline or
multipolyline features in vector tiles loaded by an `MGLVectorSource` object or
`MGLPolyline`, `MGLPolylineFeature`, `MGLMultiPolyline`, or
`MGLMultiPolylineFeature` instances in an `MGLShapeSource` object.
You can access an existing line style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
otherwise, find it using the `MGLStyle.layers` property. You can also create a
new line style layer and add it to the style using a method such as
`-[MGLStyle addLayer:]`.
### Example
```swift
let layer = MGLLineStyleLayer(identifier: "trails-path", source: trails)
layer.sourceLayerIdentifier = "trails"
layer.lineWidth = MGLStyleValue(interpolationBase: 1.5, stops: [
14: MGLStyleValue(rawValue: 2),
18: MGLStyleValue(rawValue: 20),
])
layer.lineColor = MGLStyleValue(rawValue: .brown)
layer.lineCap = MGLStyleValue(rawValue: NSValue(mglLineCap: .round))
layer.predicate = NSPredicate(format: "%K == %@", "trail-type", "mountain-biking")
mapView.style?.addLayer(layer)
```
*/
MGL_EXPORT
@interface MGLLineStyleLayer : MGLVectorStyleLayer
@@ -77,32 +112,44 @@ MGL_EXPORT
/**
The display of line endings.
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLLineCapButt`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing `MGLLineCapButt`. Set this property to `nil` to
reset it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineCap;
/**
The display of lines when joining.
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLLineJoinMiter`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing `MGLLineJoinMiter`. Set this property to `nil` to
reset it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineJoin;
/**
Used to automatically convert miter joins to bevel joins for sharp angles.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `2`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `2`. Set this property to `nil` to reset
it to the default value.
This property is only applied to the style if `lineJoin` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLLineJoinMiter`. Otherwise, it is ignored.
This property is only applied to the style if `lineJoin` is set to an
`MGLStyleValue` object containing an `NSValue` object containing
`MGLLineJoinMiter`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineMiterLimit;
/**
Used to automatically convert round joins to miter joins for shallow angles.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1.05`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1.05`. Set this property to `nil` to
reset it to the default value.
This property is only applied to the style if `lineJoin` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLLineJoinRound`. Otherwise, it is ignored.
This property is only applied to the style if `lineJoin` is set to an
`MGLStyleValue` object containing an `NSValue` object containing
`MGLLineJoinRound`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineRoundLimit;
@@ -110,10 +157,12 @@ MGL_EXPORT
/**
Blur applied to the line, in points.
This property is measured in points.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineBlur;
@@ -121,93 +170,199 @@ MGL_EXPORT
/**
The color with which the line will be drawn.
The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `linePattern` is set to `nil`. Otherwise, it is ignored.
The default value of this property is an `MGLStyleValue` object containing
`UIColor.blackColor`. Set this property to `nil` to reset it to the default
value.
This property is only applied to the style if `linePattern` is set to `nil`.
Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *lineColor;
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *lineColor;
#else
/**
The color with which the line will be drawn.
The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `linePattern` is set to `nil`. Otherwise, it is ignored.
The default value of this property is an `MGLStyleValue` object containing
`NSColor.blackColor`. Set this property to `nil` to reset it to the default
value.
This property is only applied to the style if `linePattern` is set to `nil`.
Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *lineColor;
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *lineColor;
#endif
/**
Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to points, multiply the length by the current line width.
This property is measured in line widths.
This property is only applied to the style if `linePattern` is set to `nil`. Otherwise, it is ignored.
Specifies the lengths of the alternating dashes and gaps that form the dash
pattern. The lengths are later scaled by the line width. To convert a dash
length to points, multiply the length by the current line width.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-dasharray"><code>line-dasharray</code></a> paint property in the Mapbox Style Specification.
This property is measured in line widths.
This property is only applied to the style if `linePattern` is set to `nil`.
Otherwise, it is ignored.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-dasharray"><code>line-dasharray</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSNumber *> *> *lineDashPattern;
@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSNumber *> *> *lineDasharray __attribute__((unavailable("Use lineDashPattern instead.")));
/**
Draws a line casing outside of a line's actual path. Value indicates the width of the inner gap.
Draws a line casing outside of a line's actual path. Value indicates the width
of the inner gap.
This property is measured in points.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineGapWidth;
/**
The line's offset. For linear features, a positive value offsets the line to the right, relative to the direction of the line, and a negative value to the left. For polygon features, a positive value results in an inset, and a negative value results in an outset.
The line's offset. For linear features, a positive value offsets the line to
the right, relative to the direction of the line, and a negative value to the
left. For polygon features, a positive value results in an inset, and a
negative value results in an outset.
This property is measured in points.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineOffset;
/**
The opacity at which the line will be drawn.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineOpacity;
/**
Name of image in style images to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512).
Name of image in style images to use for drawing image lines. For seamless
patterns, image width must be a factor of two (2, 4, 8, ..., 512).
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *linePattern;
#if TARGET_OS_IPHONE
/**
The geometry's offset.
This property is measured in points.
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing a `CGVector` struct set to 0 points from the left and 0 points from the top. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points downward. Set this property to `nil` to reset it to the default value.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-translate"><code>line-translate</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslate;
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslation;
#else
/**
The geometry's offset.
This property is measured in points.
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points upward. Set this property to `nil` to reset it to the default value.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-translate"><code>line-translate</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslation;
#endif
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslate __attribute__((unavailable("Use lineTranslation instead.")));
/**
Controls the translation reference point.
The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLLineTranslateAnchorMap`. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `lineTranslate` is non-`nil`. Otherwise, it is ignored.
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing `MGLLineTranslationAnchorMap`. Set this property to
`nil` to reset it to the default value.
This property is only applied to the style if `lineTranslation` is non-`nil`.
Otherwise, it is ignored.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-translate-anchor"><code>line-translate-anchor</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslateAnchor;
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslationAnchor;
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslateAnchor __attribute__((unavailable("Use lineTranslationAnchor instead.")));
/**
Stroke thickness.
This property is measured in points.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineWidth;
@end
/**
Methods for wrapping an enumeration value for a style layer attribute in an
`MGLLineStyleLayer` object and unwrapping its raw value.
*/
@interface NSValue (MGLLineStyleLayerAdditions)
#pragma mark Working with Line Style Layer Attribute Values
/**
Creates a new value object containing the given `MGLLineCap` enumeration.
@param lineCap The value for the new object.
@return A new value object that contains the enumeration value.
*/
+ (instancetype)valueWithMGLLineCap:(MGLLineCap)lineCap;
/**
The `MGLLineCap` enumeration representation of the value.
*/
@property (readonly) MGLLineCap MGLLineCapValue;
/**
Creates a new value object containing the given `MGLLineJoin` enumeration.
@param lineJoin The value for the new object.
@return A new value object that contains the enumeration value.
*/
+ (instancetype)valueWithMGLLineJoin:(MGLLineJoin)lineJoin;
/**
The `MGLLineJoin` enumeration representation of the value.
*/
@property (readonly) MGLLineJoin MGLLineJoinValue;
/**
Creates a new value object containing the given `MGLLineTranslationAnchor` enumeration.
@param lineTranslationAnchor The value for the new object.
@return A new value object that contains the enumeration value.
*/
+ (instancetype)valueWithMGLLineTranslationAnchor:(MGLLineTranslationAnchor)lineTranslationAnchor;
/**
The `MGLLineTranslationAnchor` enumeration representation of the value.
*/
@property (readonly) MGLLineTranslationAnchor MGLLineTranslationAnchorValue;
@end
NS_ASSUME_NONNULL_END

View File

@@ -1,5 +1,5 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "MGLMapView_Private.h"
@@ -8,7 +8,9 @@
#import "MGLStyleValue_Private.h"
#import "MGLLineStyleLayer.h"
#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/line_layer.hpp>
namespace mbgl {
MBGL_DEFINE_ENUM(MGLLineCap, {
@@ -23,9 +25,9 @@ namespace mbgl {
{ MGLLineJoinMiter, "miter" },
});
MBGL_DEFINE_ENUM(MGLLineTranslateAnchor, {
{ MGLLineTranslateAnchorMap, "map" },
{ MGLLineTranslateAnchorViewport, "viewport" },
MBGL_DEFINE_ENUM(MGLLineTranslationAnchor, {
{ MGLLineTranslationAnchorMap, "map" },
{ MGLLineTranslationAnchorViewport, "viewport" },
});
}
@@ -61,6 +63,13 @@ namespace mbgl {
super.rawLayer = rawLayer;
}
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
return @(self.rawLayer->getSourceID().c_str());
}
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -80,7 +89,7 @@ namespace mbgl {
{
MGLAssertStyleLayerIsValid();
self.rawLayer->setFilter(predicate.mgl_filter);
self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter());
}
- (NSPredicate *)predicate
@@ -231,9 +240,11 @@ namespace mbgl {
return MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toStyleValue(propertyValue);
}
- (void)setLineDasharray:(MGLStyleValue<NSArray<NSNumber *> *> *)lineDasharray {
NSAssert(NO, @"Use -setLineDashPattern: instead.");
}
- (MGLStyleValue<NSArray<NSNumber *> *> *)lineDasharray {
return self.lineDashPattern;
}
- (void)setLineGapWidth:(MGLStyleValue<NSNumber *> *)lineGapWidth {
@@ -292,32 +303,46 @@ namespace mbgl {
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}
- (void)setLineTranslate:(MGLStyleValue<NSValue *> *)lineTranslate {
- (void)setLineTranslation:(MGLStyleValue<NSValue *> *)lineTranslation {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(lineTranslate);
auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(lineTranslation);
self.rawLayer->setLineTranslate(mbglValue);
}
- (MGLStyleValue<NSValue *> *)lineTranslate {
- (MGLStyleValue<NSValue *> *)lineTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineTranslate() ?: self.rawLayer->getDefaultLineTranslate();
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
- (void)setLineTranslateAnchor:(MGLStyleValue<NSValue *> *)lineTranslateAnchor {
- (void)setLineTranslate:(MGLStyleValue<NSValue *> *)lineTranslate {
}
- (MGLStyleValue<NSValue *> *)lineTranslate {
return self.lineTranslation;
}
- (void)setLineTranslationAnchor:(MGLStyleValue<NSValue *> *)lineTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslateAnchor>().toEnumPropertyValue(lineTranslateAnchor);
auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslationAnchor>().toEnumPropertyValue(lineTranslationAnchor);
self.rawLayer->setLineTranslateAnchor(mbglValue);
}
- (MGLStyleValue<NSValue *> *)lineTranslateAnchor {
- (MGLStyleValue<NSValue *> *)lineTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineTranslateAnchor() ?: self.rawLayer->getDefaultLineTranslateAnchor();
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslateAnchor>().toEnumStyleValue(propertyValue);
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslationAnchor>().toEnumStyleValue(propertyValue);
}
- (void)setLineTranslateAnchor:(MGLStyleValue<NSValue *> *)lineTranslateAnchor {
}
- (MGLStyleValue<NSValue *> *)lineTranslateAnchor {
return self.lineTranslationAnchor;
}
- (void)setLineWidth:(MGLStyleValue<NSNumber *> *)lineWidth {
@@ -335,4 +360,38 @@ namespace mbgl {
}
@end
@implementation NSValue (MGLLineStyleLayerAdditions)
+ (NSValue *)valueWithMGLLineCap:(MGLLineCap)lineCap {
return [NSValue value:&lineCap withObjCType:@encode(MGLLineCap)];
}
- (MGLLineCap)MGLLineCapValue {
MGLLineCap lineCap;
[self getValue:&lineCap];
return lineCap;
}
+ (NSValue *)valueWithMGLLineJoin:(MGLLineJoin)lineJoin {
return [NSValue value:&lineJoin withObjCType:@encode(MGLLineJoin)];
}
- (MGLLineJoin)MGLLineJoinValue {
MGLLineJoin lineJoin;
[self getValue:&lineJoin];
return lineJoin;
}
+ (NSValue *)valueWithMGLLineTranslationAnchor:(MGLLineTranslationAnchor)lineTranslationAnchor {
return [NSValue value:&lineTranslationAnchor withObjCType:@encode(MGLLineTranslationAnchor)];
}
- (MGLLineTranslationAnchor)MGLLineTranslationAnchorValue {
MGLLineTranslationAnchor lineTranslationAnchor;
[self getValue:&lineTranslationAnchor];
return lineTranslationAnchor;
}
@end

View File

@@ -8,10 +8,15 @@ NS_ASSUME_NONNULL_BEGIN
/**
The `MGLMultiPoint` class is an abstract superclass used to define shapes
composed of multiple vertices. You should not create instances of this class
directly. Instead, you should create instances of the `MGLPolyline` or
`MGLPolygon` classes. However, you can use the method and properties of this
class to access information about the vertices of the line or polygon.
composed of multiple vertices.
You do not create instances of this class directly. Instead, you create
instances of the `MGLPolyline` or `MGLPolygon` classes. However, you can use
the method and properties of this class to access information about the
vertices of the line or polygon.
Do not confuse `MGLMultiPoint` with `MGLPointCollection`, which represents a
collection of related but disconnected points.
*/
MGL_EXPORT
@interface MGLMultiPoint : MGLShape
@@ -57,7 +62,7 @@ MGL_EXPORT
the map, it is redrawn immediately.
@param coords The array of coordinates to insert into the shape. The data in
this array is copied to the shape’s `coordinate` property.
this array is copied to the shape’s `coordinates` property.
@param count The number of items in the `coords` array.
@param index The zero-based index at which the first coordinate in `coords`
will appear in the `coordinates` property.
@@ -69,7 +74,7 @@ MGL_EXPORT
the map, it is redrawn immediately.
@param coords The array of coordinates to add to the shape. The data in this
array is copied to the shape’s `coordinate` property.
array is copied to the shape’s `coordinates` property.
@param count The number of items in the `coords` array.
*/
- (void)appendCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count;
@@ -92,7 +97,7 @@ MGL_EXPORT
being the second vertex, and so on. The `length` field indicates the number
of vertices to replace.
@param coords The array of coordinates defining part of the shape. The data in
this array is copied to the shape’s `coordinate` property.
this array is copied to the shape’s `coordinates` property.
*/
- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords;

View File

@@ -1,10 +1,9 @@
#import "MGLMultiPoint_Private.h"
#import "MGLGeometry_Private.h"
#import "MGLShape_Private.h"
#import "NSCoder+MGLAdditions.h"
#import "MGLTypes.h"
#include <mbgl/util/geo.hpp>
#include <mbgl/util/optional.hpp>
@implementation MGLMultiPoint
{
mbgl::optional<mbgl::LatLngBounds> _bounds;
@@ -27,6 +26,39 @@
return self;
}
- (instancetype)initWithCoder:(NSCoder *)decoder
{
if (self = [super initWithCoder:decoder]) {
_coordinates = [decoder mgl_decodeLocationCoordinates2DForKey:@"coordinates"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[super encodeWithCoder:coder];
[coder mgl_encodeLocationCoordinates2D:_coordinates forKey:@"coordinates"];
}
- (BOOL)isEqual:(id)other
{
if (self == other) return YES;
if (![other isKindOfClass:[MGLMultiPoint class]]) return NO;
MGLMultiPoint *otherMultipoint = other;
return ([super isEqual:otherMultipoint]
&& _coordinates == otherMultipoint->_coordinates);
}
- (NSUInteger)hash
{
NSUInteger hash = [super hash];
for (auto coord : _coordinates) {
hash += @(coord.latitude+coord.longitude).hash;
}
return hash;
}
- (CLLocationCoordinate2D)coordinate
{
NSAssert([self pointCount] > 0, @"A multipoint must have coordinates");

View File

@@ -1,5 +1,4 @@
#import "MGLNetworkConfiguration.h"
#import "NSProcessInfo+MGLAdditions.h"
@implementation MGLNetworkConfiguration
@@ -12,9 +11,6 @@
}
+ (instancetype)sharedManager {
if (NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent) {
return nil;
}
static dispatch_once_t onceToken;
static MGLNetworkConfiguration *_sharedManager;
void (^setupBlock)() = ^{

View File

@@ -26,8 +26,8 @@ typedef NS_ENUM (NSInteger, MGLOfflinePackState) {
The pack is incomplete and is not currently downloading.
This is the initial state of a pack that is created using the
`-[MGLOfflinePack addPackForRegion:withContext:completionHandler:]` method,
as well as after the `-[MGLOfflinePack suspend]` method is
`-[MGLOfflineStorage addPackForRegion:withContext:completionHandler:]`
method, as well as after the `-[MGLOfflinePack suspend]` method is
called.
*/
MGLOfflinePackStateInactive = 1,

View File

@@ -19,7 +19,8 @@ NS_ASSUME_NONNULL_BEGIN
`userInfo` dictionary contains the pack’s current state in the
`MGLOfflinePackStateUserInfoKey` key and details about the pack’s current
progress in the `MGLOfflinePackProgressUserInfoKey` key. You may also consult
the pack’s `state` and `progress` properties, which provide the same values.
the `MGLOfflinePack.state` and `MGLOfflinePack.progress` properties, which
provide the same values.
If you only need to observe changes in a particular pack’s progress, you can
alternatively observe KVO change notifications to the pack’s `progress` key
@@ -183,8 +184,8 @@ MGL_EXPORT
- (void)addPackForRegion:(id <MGLOfflineRegion>)region withContext:(NSData *)context completionHandler:(nullable MGLOfflinePackAdditionCompletionHandler)completion;
/**
Unregisters the given offline pack and frees any resources that are no longer
required by any remaining packs.
Unregisters the given offline pack and allows resources that are no longer
required by any remaining packs to be potentially freed.
As soon as this method is called on a pack, the pack becomes invalid; any
attempt to send it a message will result in an exception being thrown. If an
@@ -196,6 +197,13 @@ MGL_EXPORT
KVO change notifications on the shared offline storage object’s `packs` key
path. Removals from that array result in an `NSKeyValueChangeRemoval` change.
When you remove an offline pack, any resources that are required by that pack,
but not other packs, become eligible for deletion from offline storage. Because
the backing store used for offline storage is also used as a general purpose
cache for map resources, such resources may not be immediately removed if the
implementation determines that they remain useful for general performance of
the map.
@param pack The offline pack to remove.
@param completion The completion handler to call once the pack has been
removed. This handler is executed asynchronously on the main queue.

View File

@@ -4,6 +4,7 @@
#import "MGLStyle_Private.h"
#import "MGLStyleLayer_Private.h"
#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/math/wrap.hpp>
@@ -52,10 +53,19 @@ void MGLFinishCustomStyleLayer(void *context) {
}
/**
An `MGLOpenGLStyleLayer` is a style layer that is rendered by OpenGL code in
Objective-C blocks or Swift closures that you specify. You may initialize a new
OpenGL style layer to add to an `MGLStyle` or obtain one from an `MGLMapView`’s
current style using the `-[MGLStyle layerWithIdentifier:]` method.
An `MGLOpenGLStyleLayer` is a style layer that is rendered by OpenGL code that
you provide.
By default, this class does nothing. You can subclass this class to provide
custom OpenGL drawing code that is run on each frame of the map. Your subclass
should override the `-didMoveToMapView:`, `-willMoveFromMapView:`, and
`-drawInMapView:withContext:` methods.
You can access an existing OpenGL style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
otherwise, find it using the `MGLStyle.layers` property. You can also create a
new OpenGL style layer and add it to the style using a method such as
`-[MGLStyle addLayer:]`.
@warning This API is undocumented and therefore unsupported. It may change at
any time without notice.

View File

@@ -9,9 +9,8 @@ NS_ASSUME_NONNULL_BEGIN
/**
The `MGLOverlay` protocol defines a specific type of annotation that represents
both a point and an area on a map. Overlay objects are essentially data objects
that contain the geographic data needed to represent the map area. For example,
overlays can take the form of common shapes such as rectangles and circles.
They can also describe polygons and other complex shapes.
that contain the geographic data needed to represent the map area. Overlays can
take the form of a polyline or polygon.
You use overlays to layer more sophisticated content on top of a map view. For
example, you could use an overlay to show the boundaries of a national park or

View File

@@ -7,16 +7,38 @@
NS_ASSUME_NONNULL_BEGIN
/**
The `MGLPointAnnotation` class defines a concrete annotation object located at
a specified point. You can use this class, rather than define your own, in
situations where all you want to do is associate a point on the map with a
title.
An `MGLPointAnnotation` object represents a one-dimensional shape located at a
single geographical coordinate. Depending on how it is used, an
`MGLPointAnnotation` object is known as a point annotation or point shape. For
example, you could use a point shape to represent a city at low zoom levels, an
address at high zoom levels, or the location of a long press gesture.
You can add point shapes to the map by adding them to an `MGLShapeSource`
object. Configure the appearance of an `MGLShapeSource`’s or
`MGLVectorSource`’s point shapes collectively using an `MGLCircleStyleLayer` or
`MGLSymbolStyleLayer` object.
For more interactivity, add a selectable point annotation to a map view using
the `-[MGLMapView addAnnotation:]` method. Alternatively, define your own model
class that conforms to the `MGLAnnotation` protocol. Configure a point
annotation’s appearance using
`-[MGLMapViewDelegate mapView:imageForAnnotation:]` or
`-[MGLMapViewDelegate mapView:viewForAnnotation:]` (iOS only). A point
annotation’s `MGLShape.title` and `MGLShape.subtitle` properties define the
default content of the annotation’s callout (on iOS) or popover (on macOS).
To group multiple related points together in one shape, use an
`MGLPointCollection` or `MGLShapeCollection` object.
A point shape is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.2">Point</a> geometry
in GeoJSON.
*/
MGL_EXPORT
@interface MGLPointAnnotation : MGLShape
/**
The coordinate point of the annotation, specified as a latitude and longitude.
The coordinate point of the shape, specified as a latitude and longitude.
*/
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;

View File

@@ -1,6 +1,7 @@
#import "MGLPointAnnotation.h"
#import "MGLShape_Private.h"
#import "NSCoder+MGLAdditions.h"
#import <mbgl/util/geometry.hpp>
@@ -9,6 +10,41 @@
@synthesize coordinate;
+ (BOOL)supportsSecureCoding
{
return YES;
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
if (self = [super initWithCoder:coder]) {
self.coordinate = [coder decodeMGLCoordinateForKey:@"coordinate"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[super encodeWithCoder:coder];
[coder encodeMGLCoordinate:coordinate forKey:@"coordinate"];
}
- (BOOL)isEqual:(id)other
{
if (other == self) return YES;
if (![other isKindOfClass:[MGLPointAnnotation class]]) return NO;
MGLPointAnnotation *otherAnnotation = other;
return ([super isEqual:other]
&& self.coordinate.latitude == otherAnnotation.coordinate.latitude
&& self.coordinate.longitude == otherAnnotation.coordinate.longitude);
}
- (NSUInteger)hash
{
return [super hash] + @(self.coordinate.latitude).hash + @(self.coordinate.longitude).hash;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; title = %@; subtitle = %@; coordinate = %f, %f>",

View File

@@ -6,15 +6,26 @@
#import "MGLShape.h"
/**
The `MGLPointCollection` class is used to define an array of disconnected
coordinates. The points in the collection may be related but are not
connected visually in any way.
An `MGLPointCollection` object represents a shape consisting of one or more
disconnected vertices, specified as `CLLocationCoordinate2D` instances. The
points in the collection may be related but are not connected spatially. For
example, you could use a point collection to represent all the trees in an
orchard.
@note `MGLPointCollection` objects cannot be added to a map view using
`-[MGLMapView addAnnotations:]` and related methods. However, when used in a
`MGLPointCollectionFeature` to initialize a `MGLShapeSource` that is added
to the map view's style, the point collection represents as a group of distinct
annotations.
You can add point collections to the map by adding them to an `MGLShapeSource`
object. Configure the appearance of an `MGLShapeSource`’s or
`MGLVectorSource`’s point collections collectively using an
`MGLCircleStyleLayer` or `MGLSymbolStyleLayer` object.
You cannot add an `MGLPointCollection` object directly to a map view as an
annotation. However, you can create individual `MGLPointAnnotation` objects
from the `coordinates` array and add those annotation objects to the map view
using the `-[MGLMapView addAnnotations:]` method.
A point collection is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.3">MultiPoint</a>
geometry in GeoJSON. Do not confuse `MGLPointCollection` with `MGLMultiPoint`,
the abstract superclass of `MGLPolyline` and `MGLPolygon`.
*/
MGL_EXPORT
@interface MGLPointCollection : MGLShape <MGLOverlay>

View File

@@ -1,5 +1,6 @@
#import "MGLPointCollection_Private.h"
#import "MGLGeometry_Private.h"
#import "NSArray+MGLAdditions.h"
#import <mbgl/util/geojson.hpp>
#import <mbgl/util/geometry.hpp>
@@ -8,12 +9,10 @@ NS_ASSUME_NONNULL_BEGIN
@implementation MGLPointCollection
{
MGLCoordinateBounds _overlayBounds;
mbgl::optional<mbgl::LatLngBounds> _bounds;
std::vector<CLLocationCoordinate2D> _coordinates;
}
@synthesize overlayBounds = _overlayBounds;
+ (instancetype)pointCollectionWithCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count
{
return [[self alloc] initWithCoordinates:coords count:count];
@@ -25,16 +24,43 @@ NS_ASSUME_NONNULL_BEGIN
if (self)
{
_coordinates = { coords, coords + count };
mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
for (auto coordinate : _coordinates)
{
bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude));
}
_overlayBounds = MGLCoordinateBoundsFromLatLngBounds(bounds);
}
return self;
}
- (nullable instancetype)initWithCoder:(NSCoder *)decoder {
if (self = [super initWithCoder:decoder]) {
NSArray *coordinates = [decoder decodeObjectOfClass:[NSArray class] forKey:@"coordinates"];
_coordinates = [coordinates mgl_coordinates];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[super encodeWithCoder:coder];
[coder encodeObject:[NSArray mgl_coordinatesFromCoordinates:_coordinates] forKey:@"coordinates"];
}
- (BOOL)isEqual:(id)other {
if (self == other) return YES;
if (![other isKindOfClass:[MGLPointCollection class]]) return NO;
MGLPointCollection *otherCollection = (MGLPointCollection *)other;
return ([super isEqual:other]
&& ((![self geoJSONDictionary] && ![otherCollection geoJSONDictionary]) || [[self geoJSONDictionary] isEqualToDictionary:[otherCollection geoJSONDictionary]]));
}
- (MGLCoordinateBounds)overlayBounds {
if (!_bounds) {
mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
for (auto coordinate : _coordinates) {
bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude));
}
_bounds = bounds;
}
return MGLCoordinateBoundsFromLatLngBounds(*_bounds);
}
- (NSUInteger)pointCount
{
return _coordinates.size();
@@ -65,7 +91,7 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds
{
return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
return MGLCoordinateBoundsIntersectsCoordinateBounds(self.overlayBounds, overlayBounds);
}
- (mbgl::Geometry<double>)geometryObject

View File

@@ -10,10 +10,39 @@
NS_ASSUME_NONNULL_BEGIN
/**
The `MGLPolygon` class represents a shape consisting of one or more points that
define a closed polygon. The points are connected end-to-end in the order they
are provided. The first and last points are connected to each other to create
the closed shape.
An `MGLPolygon` object represents a closed shape consisting of four or more
vertices, specified as `CLLocationCoordinate2D` instances, and the edges that
connect them. For example, you could use a polygon shape to represent a
building, a lake, or an area you want to highlight.
You can add polygon shapes to the map by adding them to an `MGLShapeSource`
object. Configure the appearance of an `MGLShapeSource`’s or
`MGLVectorSource`’s polygons collectively using an `MGLFillStyleLayer` or
`MGLSymbolStyleLayer` object.
Alternatively, you can add a polygon overlay directly to a map view using the
`-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]` method. Configure
a polygon overlay’s appearance using
`-[MGLMapViewDelegate mapView:strokeColorForShapeAnnotation:]` and
`-[MGLMapViewDelegate mapView:fillColorForPolygonAnnotation:]`.
The vertices are automatically connected in the order in which you provide
them. You should close the polygon by specifying the same
`CLLocationCoordinate2D` as the first and last vertices; otherwise, the
polygon’s fill may not cover the area you expect it to. To avoid filling the
space within the shape, give the polygon a transparent fill or use an
`MGLPolyline` object.
A polygon may have one or more interior polygons, or holes, that you specify as
`MGLPolygon` objects with the `+polygonWithCoordinates:count:interiorPolygons:`
method. For example, if a polygon represents a lake, it could exclude an island
within the lake using an interior polygon. Interior polygons may not themselves
have interior polygons. To represent a shape that includes a polygon within a
hole or, more generally, to group multiple polygons together in one shape, use
an `MGLMultiPolygon` or `MGLShapeCollection` object.
To make the polygon straddle the antimeridian, specify some longitudes less
than −180 degrees or greater than 180 degrees.
*/
MGL_EXPORT
@interface MGLPolygon : MGLMultiPoint <MGLOverlay>
@@ -57,14 +86,21 @@ MGL_EXPORT
@end
/**
The `MGLMultiPolygon` class represents a shape consisting of one or more
polygons that do not overlap. For example, you would use an `MGLMultiPolygon`
object to represent an atoll together with an island in the atoll’s lagoon:
the atoll itself would be one `MGLPolygon` object, while the inner island would
be another.
An `MGLMultiPolygon` object represents a shape consisting of one or more
polygons that do not overlap. For example, you could use a multipolygon shape
to represent the body of land that consists of an island surrounded by an
atoll: the inner island would be one `MGLPolygon` object, while the surrounding
atoll would be another. You could also use a multipolygon shape to represent a
group of disconnected but related buildings.
@note `MGLMultiPolygon` objects cannot be added to a map view using
`-[MGLMapView addAnnotations:]` and related methods.
You can add multipolygon shapes to the map by adding them to an
`MGLShapeSource` object. Configure the appearance of an `MGLShapeSource`’s or
`MGLVectorSource`’s multipolygons collectively using an `MGLFillStyleLayer` or
`MGLSymbolStyleLayer` object.
You cannot add an `MGLMultiPolygon` object directly to a map view using
`-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]`. However, you can
add the `polygons` array’s items as overlays individually.
*/
MGL_EXPORT
@interface MGLMultiPolygon : MGLShape <MGLOverlay>

View File

@@ -28,6 +28,32 @@
return self;
}
- (instancetype)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:decoder];
if (self) {
_interiorPolygons = [decoder decodeObjectOfClass:[NSArray class] forKey:@"interiorPolygons"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[super encodeWithCoder:coder];
[coder encodeObject:self.interiorPolygons forKey:@"interiorPolygons"];
}
- (BOOL)isEqual:(id)other {
if (self == other) return YES;
if (![other isKindOfClass:[MGLPolygon class]]) return NO;
MGLPolygon *otherPolygon = (MGLPolygon *)other;
return ([super isEqual:otherPolygon] &&
[[self geoJSONDictionary] isEqualToDictionary:[otherPolygon geoJSONDictionary]]);
}
- (NSUInteger)hash {
return [super hash] + [[self geoJSONDictionary] hash];
}
- (mbgl::LinearRing<double>)ring {
NSUInteger count = self.pointCount;
CLLocationCoordinate2D *coordinates = self.coordinates;
@@ -100,6 +126,35 @@
return self;
}
- (instancetype)initWithCoder:(NSCoder *)decoder {
if (self = [super initWithCoder:decoder]) {
_polygons = [decoder decodeObjectOfClass:[NSArray class] forKey:@"polygons"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[super encodeWithCoder:coder];
[coder encodeObject:_polygons forKey:@"polygons"];
}
- (BOOL)isEqual:(id)other {
if (self == other) return YES;
if (![other isKindOfClass:[MGLMultiPolygon class]]) return NO;
MGLMultiPolygon *otherMultiPolygon = other;
return [super isEqual:other]
&& [self.polygons isEqualToArray:otherMultiPolygon.polygons];
}
- (NSUInteger)hash {
NSUInteger hash = [super hash];
for (MGLPolygon *polygon in self.polygons) {
hash += [polygon hash];
}
return hash;
}
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
}

View File

@@ -10,10 +10,35 @@
NS_ASSUME_NONNULL_BEGIN
/**
The `MGLPolyline` class represents a shape consisting of one or more points
that define connecting line segments. The points are connected end-to-end in
the order they are provided. The first and last points are not connected to
each other.
An `MGLPolyline` object represents a shape consisting of two or more vertices,
specified as `CLLocationCoordinate2D` instances, and the line segments that
connect them. For example, you could use an polyline to represent a road or the
path along which something moves.
You can add polyline shapes to the map by adding them to an `MGLShapeSource`
object. Configure the appearance of an `MGLShapeSource`’s or
`MGLVectorSource`’s polylines collectively using an `MGLLineStyleLayer` or
`MGLSymbolStyleLayer` object.
Alternatively, you can add a polyline overlay directly to a map view using the
`-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]` method. Configure
a polyline overlay’s appearance using
`-[MGLMapViewDelegate mapView:strokeColorForShapeAnnotation:]` and
`-[MGLMapViewDelegate mapView:lineWidthForPolylineAnnotation:]`.
The vertices are automatically connected in the order in which you provide
them. The first and last vertices are not connected to each other, but you can
specify the same `CLLocationCoordinate2D` as the first and last vertices in
order to close the polyline. To fill the space within the shape, use an
`MGLPolygon` object. To group multiple polylines together in one shape, use an
`MGLMultiPolyline` or `MGLShapeCollection` object.
To make the polyline straddle the antimeridian, specify some longitudes less
than −180 degrees or greater than 180 degrees.
A polyline is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.4">LineString</a>
geometry in GeoJSON.
*/
MGL_EXPORT
@interface MGLPolyline : MGLMultiPoint <MGLOverlay>
@@ -32,14 +57,23 @@ MGL_EXPORT
@end
/**
The `MGLMultiPolyline` class represents a shape consisting of one or more
polylines. For example, you could use an `MGLMultiPolyline` object to represent
both sides of a divided highway (dual carriageway), excluding the median
(central reservation): each carriageway would be a distinct `MGLPolyline`
object.
An `MGLMultiPolyline` object represents a shape consisting of one or more
polylines. For example, you could use a multipolyline shape to represent both
sides of a divided highway (dual carriageway), excluding the median (central
reservation): each carriageway would be a distinct `MGLPolyline` object.
@note `MGLMultiPolyline` objects cannot be added to a map view using
`-[MGLMapView addAnnotations:]` and related methods.
You can add multipolyline shapes to the map by adding them to an
`MGLShapeSource` object. Configure the appearance of an `MGLShapeSource`’s or
`MGLVectorSource`’s multipolylines collectively using an `MGLLineStyleLayer` or
`MGLSymbolStyleLayer` object.
You cannot add an `MGLMultiPolyline` object directly to a map view using
`-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]`. However, you can
add the `polylines` array’s items as overlays individually.
A multipolyline is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.5">MultiLineString</a>
geometry in GeoJSON.
*/
MGL_EXPORT
@interface MGLMultiPolyline : MGLShape <MGLOverlay>

View File

@@ -80,6 +80,36 @@
return self;
}
- (instancetype)initWithCoder:(NSCoder *)decoder {
if (self = [super initWithCoder:decoder]) {
_polylines = [decoder decodeObjectOfClass:[NSArray class] forKey:@"polylines"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[super encodeWithCoder:coder];
[coder encodeObject:_polylines forKey:@"polylines"];
}
- (BOOL)isEqual:(id)other
{
if (self == other) return YES;
if (![other isKindOfClass:[MGLMultiPolyline class]]) return NO;
MGLMultiPolyline *otherMultipoline = other;
return ([super isEqual:otherMultipoline]
&& [self.polylines isEqualToArray:otherMultipoline.polylines]);
}
- (NSUInteger)hash {
NSUInteger hash = [super hash];
for (MGLPolyline *polyline in self.polylines) {
hash += [polyline hash];
}
return hash;
}
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
}

View File

@@ -36,6 +36,20 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionTileSize;
`MGLRasterSource` object that you can use to initialize new style layers. You
can also add and remove sources dynamically using methods such as
`-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`.
### Example
```swift
let source = MGLRasterSource(identifier: "clouds", tileURLTemplates: ["https://example.com/raster-tiles/{z}/{x}/{y}.png"], options: [
.minimumZoomLevel: 9,
.maximumZoomLevel: 16,
.tileSize: 512,
.attributionInfos: [
MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
]
])
mapView.style?.addSource(source)
```
*/
MGL_EXPORT
@interface MGLRasterSource : MGLTileSource

View File

@@ -5,6 +5,7 @@
#import "MGLTileSource_Private.h"
#import "NSURL+MGLAdditions.h"
#include <mbgl/map/map.hpp>
#include <mbgl/style/sources/raster_source.hpp>
const MGLTileSourceOption MGLTileSourceOptionTileSize = @"MGLTileSourceOptionTileSize";
@@ -50,7 +51,7 @@ static const CGFloat MGLRasterSourceRetinaTileSize = 512;
if (self = [super initWithIdentifier:identifier tileURLTemplates:tileURLTemplates options:options]) {
mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
uint16_t tileSize;
uint16_t tileSize = MGLRasterSourceRetinaTileSize;
if (NSNumber *tileSizeNumber = options[MGLTileSourceOptionTileSize]) {
if (![tileSizeNumber isKindOfClass:[NSNumber class]]) {
[NSException raise:NSInvalidArgumentException
@@ -95,6 +96,11 @@ static const CGFloat MGLRasterSourceRetinaTileSize = 512;
super.rawSource = 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;

View File

@@ -8,10 +8,30 @@
NS_ASSUME_NONNULL_BEGIN
/**
A raster layer which allows customization of styling properties at runtime. You may
instantiate a new raster layer to add to a map style or you may query an
`MGLMapView` for its `style` and obtain existing layers using the
`-[MGLStyle layerWithIdentifier:]` method.
An `MGLRasterStyleLayer` is a style layer that renders raster tiles on the map.
Use a raster style layer to configure the color parameters of raster tiles
loaded by an `MGLRasterSource` object. For example, you could use a raster
style layer to render <a href="https://www.mapbox.com/satellite/">Mapbox
Satellite</a> imagery, a <a
href="https://www.mapbox.com/help/define-tileset/#raster-tilesets">raster tile
set</a> uploaded to Mapbox Studio, or a raster map authored in <a
href="https://tilemill-project.github.io/tilemill/">TileMill</a>, the classic
Mapbox Editor, or Mapbox Studio Classic.
You can access an existing raster style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
otherwise, find it using the `MGLStyle.layers` property. You can also create a
new raster style layer and add it to the style using a method such as
`-[MGLStyle addLayer:]`.
### Example
```swift
let layer = MGLRasterStyleLayer(identifier: "clouds", source: source)
layer.rasterOpacity = MGLStyleValue(rawValue: 0.5)
mapView.style?.addLayer(layer)
```
*/
MGL_EXPORT
@interface MGLRasterStyleLayer : MGLForegroundStyleLayer
@@ -19,70 +39,89 @@ MGL_EXPORT
#pragma mark - Accessing the Paint Attributes
/**
Increase or reduce the brightness of the image. The value is the maximum brightness.
Increase or reduce the brightness of the image. The value is the maximum
brightness.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-max"><code>raster-brightness-max</code></a> paint property in the Mapbox Style Specification.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-max"><code>raster-brightness-max</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumRasterBrightness;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterBrightnessMax __attribute__((unavailable("Use maximumRasterBrightness instead.")));
/**
Increase or reduce the brightness of the image. The value is the minimum brightness.
Increase or reduce the brightness of the image. The value is the minimum
brightness.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-min"><code>raster-brightness-min</code></a> paint property in the Mapbox Style Specification.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-min"><code>raster-brightness-min</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *minimumRasterBrightness;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterBrightnessMin __attribute__((unavailable("Use minimumRasterBrightness instead.")));
/**
Increase or reduce the contrast of the image.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterContrast;
/**
Fade duration when a new tile is added.
This property is measured in milliseconds.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `300`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `300`. Set this property to `nil` to
reset it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterFadeDuration;
/**
Rotates hues around the color wheel.
This property is measured in degrees.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-hue-rotate"><code>raster-hue-rotate</code></a> paint property in the Mapbox Style Specification.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-hue-rotate"><code>raster-hue-rotate</code></a>
layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterHueRotation;
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterHueRotate __attribute__((unavailable("Use rasterHueRotation instead.")));
/**
The opacity at which the image will be drawn.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterOpacity;
/**
Increase or reduce the saturation of the image.
The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterSaturation;

View File

@@ -1,5 +1,5 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "MGLMapView_Private.h"
@@ -8,6 +8,7 @@
#import "MGLStyleValue_Private.h"
#import "MGLRasterStyleLayer.h"
#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
@interface MGLRasterStyleLayer ()
@@ -41,6 +42,13 @@
super.rawLayer = rawLayer;
}
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
return @(self.rawLayer->getSourceID().c_str());
}
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
@@ -96,9 +104,11 @@
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setRasterBrightnessMax:(MGLStyleValue<NSNumber *> *)rasterBrightnessMax {
NSAssert(NO, @"Use -setMaximumRasterBrightness: instead.");
}
- (MGLStyleValue<NSNumber *> *)rasterBrightnessMax {
return self.maximumRasterBrightness;
}
- (void)setMinimumRasterBrightness:(MGLStyleValue<NSNumber *> *)minimumRasterBrightness {
@@ -115,9 +125,11 @@
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setRasterBrightnessMin:(MGLStyleValue<NSNumber *> *)rasterBrightnessMin {
NSAssert(NO, @"Use -setMinimumRasterBrightness: instead.");
}
- (MGLStyleValue<NSNumber *> *)rasterBrightnessMin {
return self.minimumRasterBrightness;
}
- (void)setRasterContrast:(MGLStyleValue<NSNumber *> *)rasterContrast {
@@ -162,9 +174,11 @@
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setRasterHueRotate:(MGLStyleValue<NSNumber *> *)rasterHueRotate {
NSAssert(NO, @"Use -setRasterHueRotation: instead.");
}
- (MGLStyleValue<NSNumber *> *)rasterHueRotate {
return self.rasterHueRotation;
}
- (void)setRasterOpacity:(MGLStyleValue<NSNumber *> *)rasterOpacity {

View File

@@ -6,14 +6,30 @@
NS_ASSUME_NONNULL_BEGIN
/**
The `MGLShape` class is an abstract class that defines the basic properties for
all shape-based annotation objects. This class must be subclassed and cannot be
used as is. Subclasses are responsible for defining the geometry of the shape
and providing an appropriate value for the coordinate property inherited from
the `MGLAnnotation` protocol.
`MGLShape` is an abstract class that represents a shape or annotation. Shapes
constitute the content of a map – not only the overlays atop the map, but also
the content that forms the base map.
You do not create instances of this class directly or create subclasses of this
class. Instead, you create instances of `MGLPointAnnotation`,
`MGLPointCollection`, `MGLPolyline`, `MGLMultiPolyline`, `MGLPolygon`,
`MGLMultiPolygon`, or `MGLShapeCollection`. The shape classes correspond to the
<a href="https://tools.ietf.org/html/rfc7946#section-3.1">Geometry</a> object
types in the GeoJSON standard, but some have nonstandard names for backwards
compatibility.
Although you do not create instances of this class directly, you can use its
`+[MGLShape shapeWithData:encoding:error:]` factory method to create one of the
concrete subclasses of `MGLShape` noted above from GeoJSON data.
You can add shapes to the map by adding them to an `MGLShapeSource` object.
Configure the appearance of an `MGLShapeSource`’s or `MGLVectorSource`’s shapes
collectively using a concrete instance of `MGLVectorStyleLayer`. Alternatively,
you can add some kinds of shapes directly to a map view as annotations or
overlays.
*/
MGL_EXPORT
@interface MGLShape : NSObject <MGLAnnotation>
@interface MGLShape : NSObject <MGLAnnotation, NSSecureCoding>
#pragma mark Creating a Shape
@@ -27,6 +43,14 @@ MGL_EXPORT
collection object, the returned value is an instance of
`MGLShapeCollectionFeature`.
### Example
```swift
let url = mainBundle.url(forResource: "amsterdam", withExtension: "geojson")!
let data = try! Data(contentsOf: url)
let feature = try! MGLShape(data: data, encoding: String.Encoding.utf8.rawValue) as! MGLShapeCollectionFeature
```
@param data String data containing GeoJSON source code.
@param encoding The encoding used by `data`.
@param outError Upon return, if an error has occurred, a pointer to an
@@ -40,21 +64,34 @@ MGL_EXPORT
#pragma mark Accessing the Shape Attributes
/**
The title of the shape annotation. The default value of this property is `nil`.
The title of the shape annotation.
The default value of this property is `nil`.
This property is ignored when the shape is used in an `MGLShapeSource`. To name
a shape used in a shape source, create an `MGLFeature` and add an attribute to
the `MGLFeature.attributes` property.
*/
@property (nonatomic, copy, nullable) NSString *title;
/**
The subtitle of the shape annotation. The default value of this property is
`nil`.
This property is ignored when the shape is used in an `MGLShapeSource`. To
provide additional information about a shape used in a shape source, create an
`MGLFeature` and add an attribute to the `MGLFeature.attributes` property.
*/
@property (nonatomic, copy, nullable) NSString *subtitle;
#if !TARGET_OS_IPHONE
/**
The tooltip of the shape annotation. The default value of this property is
`nil`.
The tooltip of the shape annotation.
The default value of this property is `nil`.
This property is ignored when the shape is used in an `MGLShapeSource`.
*/
@property (nonatomic, copy, nullable) NSString *toolTip;

View File

@@ -2,6 +2,15 @@
#import "MGLFeature_Private.h"
#import "NSString+MGLAdditions.h"
#import "MGLTypes.h"
#import <mbgl/util/geo.hpp>
bool operator==(const CLLocationCoordinate2D lhs, const CLLocationCoordinate2D rhs) {
return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude;
}
@implementation MGLShape
+ (nullable MGLShape *)shapeWithData:(NSData *)data encoding:(NSStringEncoding)encoding error:(NSError * _Nullable *)outError {
@@ -42,10 +51,61 @@
return [string dataUsingEncoding:NSUTF8StringEncoding];
}
- (CLLocationCoordinate2D)coordinate {
[NSException raise:@"MGLAbstractClassException"
format:@"MGLShape is an abstract class"];
+ (BOOL)supportsSecureCoding
{
return YES;
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
if (self = [super init]) {
_title = [coder decodeObjectOfClass:[NSString class] forKey:@"title"];
_subtitle = [coder decodeObjectOfClass:[NSString class] forKey:@"subtitle"];
#if !TARGET_OS_IPHONE
_toolTip = [coder decodeObjectOfClass:[NSString class] forKey:@"toolTip"];
#endif
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeObject:_title forKey:@"title"];
[coder encodeObject:_subtitle forKey:@"subtitle"];
#if !TARGET_OS_IPHONE
[coder encodeObject:_toolTip forKey:@"toolTip"];
#endif
}
- (BOOL)isEqual:(id)other
{
if (other == self) { return YES; }
id <MGLAnnotation> annotation = other;
#if TARGET_OS_IPHONE
return ((!_title && ![annotation title]) || [_title isEqualToString:[annotation title]])
&& ((!_subtitle && ![annotation subtitle]) || [_subtitle isEqualToString:[annotation subtitle]]);
#else
return ((!_title && ![annotation title]) || [_title isEqualToString:[annotation title]])
&& ((!_subtitle && ![annotation subtitle]) || [_subtitle isEqualToString:[annotation subtitle]])
&& ((!_toolTip && ![annotation toolTip]) || [_toolTip isEqualToString:[annotation toolTip]]);
#endif
}
- (NSUInteger)hash
{
NSUInteger hash = _title.hash + _subtitle.hash;
#if !TARGET_OS_IPHONE
hash += _toolTip.hash;
#endif
return hash;
}
- (CLLocationCoordinate2D)coordinate
{
[[NSException exceptionWithName:@"MGLAbstractClassException"
reason:@"MGLShape is an abstract class"
userInfo:nil] raise];
return kCLLocationCoordinate2DInvalid;
}

View File

@@ -8,12 +8,30 @@
NS_ASSUME_NONNULL_BEGIN
/**
The `MGLShapeCollection` class represents a shape consisting of one or more
An `MGLShapeCollection` object represents a shape consisting of zero or more
distinct but related shapes that are instances of `MGLShape`. The constituent
shapes can be a mixture of different kinds of shapes.
@note `MGLShapeCollection` objects cannot be added to a map view using
`-[MGLMapView addAnnotations:]` and related methods.
`MGLShapeCollection` is most commonly used to add multiple shapes to a single
`MGLShapeSource`. Configure the appearance of an `MGLShapeSource`’s or
`MGLVectorSource`’s shape collection collectively using an
`MGLSymbolStyleLayer` object, or use multiple instances of
`MGLCircleStyleLayer`, `MGLFillStyleLayer`, and `MGLLineStyleLayer` to
configure the appearance of each kind of shape inside the collection.
You cannot add an `MGLShapeCollection` object directly to a map view as an
annotation. However, you can create individual `MGLPointAnnotation`,
`MGLPolyline`, and `MGLPolygon` objects from the `shapes` array and add those
annotation objects to the map view using the `-[MGLMapView addAnnotations:]`
method.
To represent a collection of point, polyline, or polygon shapes, it may be more
convenient to use an `MGLPointCollection`, `MGLMultiPolyline`, or
`MGLMultiPolygon` object, respectively.
A multipolyline is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.8">GeometryCollection</a>
geometry in GeoJSON.
*/
MGL_EXPORT
@interface MGLShapeCollection : MGLShape

View File

@@ -12,12 +12,40 @@
- (instancetype)initWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes {
if (self = [super init]) {
NSAssert(shapes.count, @"Cannot create an empty shape collection");
_shapes = shapes.copy;
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)decoder {
if (self = [super initWithCoder:decoder]) {
_shapes = [decoder decodeObjectOfClass:[NSArray class] forKey:@"shapes"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[super encodeWithCoder:coder];
[coder encodeObject:_shapes forKey:@"shapes"];
}
- (BOOL)isEqual:(id)other {
if (self == other) return YES;
if (![other isKindOfClass:[MGLShapeCollection class]]) return NO;
MGLShapeCollection *otherShapeCollection = other;
return [super isEqual:otherShapeCollection]
&& [_shapes isEqualToArray:otherShapeCollection.shapes];
}
- (NSUInteger)hash {
NSUInteger hash = [super hash];
for (MGLShape *shape in _shapes) {
hash += [shape hash];
}
return hash;
}
- (CLLocationCoordinate2D)coordinate {
return _shapes.firstObject.coordinate;
}

View File

@@ -17,6 +17,10 @@ typedef NSString *MGLShapeSourceOption NS_STRING_ENUM;
An `NSNumber` object containing a Boolean enabling or disabling clustering.
If the `shape` property contains point shapes, setting this option to
`YES` clusters the points by radius into groups. The default value is `NO`.
This attribute corresponds to the
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-cluster"><code>cluster</code></a>
source property in the Mapbox Style Specification.
*/
extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClustered;
@@ -32,6 +36,10 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius;
which to cluster points if clustering is enabled. Defaults to one zoom level
less than the value of `MGLShapeSourceOptionMaximumZoomLevel` so that, at the
maximum zoom level, the shapes are not clustered.
This attribute corresponds to the
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-clusterMaxZoom"><code>clusterMaxZoom</code></a>
source property in the Mapbox Style Specification.
*/
extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering;
@@ -39,6 +47,10 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLeve
An `NSNumber` object containing an integer; specifies the maximum zoom level at
which to create vector tiles. A greater value produces greater detail at high
zoom levels. The default value is 18.
This attribute corresponds to the
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-maxzoom"><code>maxzoom</code></a>
source property in the Mapbox Style Specification.
*/
extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel;
@@ -47,6 +59,10 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLeve
buffer on each side. A value of 0 produces no buffer. A value of 512 produces a
buffer as wide as the tile itself. Larger values produce fewer rendering
artifacts near tile edges and slower performance. The default value is 128.
This attribute corresponds to the
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-buffer"><code>buffer</code></a>
source property in the Mapbox Style Specification.
*/
extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionBuffer;
@@ -54,6 +70,10 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionBuffer;
An `NSNumber` object containing a double; specifies the Douglas-Peucker
simplification tolerance. A greater value produces simpler geometries and
improves performance. The default value is 0.375.
This attribute corresponds to the
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-tolerance"><code>tolerance</code></a>
source property in the Mapbox Style Specification.
*/
extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance;
@@ -75,6 +95,18 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionSimplificationT
Any vector style layer initialized with a shape source should have a `nil`
value in its `sourceLayerIdentifier` property.
### Example
```swift
var coordinates: [CLLocationCoordinate2D] = [
CLLocationCoordinate2D(latitude: 37.77, longitude: -122.42),
CLLocationCoordinate2D(latitude: 38.91, longitude: -77.04),
]
let polyline = MGLPolylineFeature(coordinates: &coordinates, count: UInt(coordinates.count))
let source = MGLShapeSource(identifier: "lines", features: [polyline], options: nil)
mapView.style?.addSource(source)
```
*/
MGL_EXPORT
@interface MGLShapeSource : MGLSource
@@ -100,7 +132,9 @@ MGL_EXPORT
To specify attributes about the shape, use an instance of an `MGLShape`
subclass that conforms to the `MGLFeature` protocol, such as `MGLPointFeature`.
To include multiple shapes in the source, use an `MGLShapeCollection` or
`MGLShapeCollectionFeature` object.
`MGLShapeCollectionFeature` object, or use the
`-initWithIdentifier:features:options:` or
`-initWithIdentifier:shapes:options:` methods.
To create a shape from GeoJSON source code, use the
`+[MGLShape shapeWithData:encoding:error:]` method.
@@ -112,6 +146,45 @@ MGL_EXPORT
*/
- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
/**
Returns a shape source with an identifier, an array of features, and a dictionary
of options for the source.
Unlike `-initWithIdentifier:shapes:options:`, this method accepts `MGLFeature`
instances, such as `MGLPointFeature` objects, whose attributes you can use when
applying a predicate to `MGLVectorStyleLayer` or configuring a style layer’s
appearance.
To create a shape from GeoJSON source code, use the
`+[MGLShape shapeWithData:encoding:error:]` method.
@param identifier A string that uniquely identifies the source.
@param features An array of objects that conform to the MGLFeature protocol.
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier features:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)features options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options;
/**
Returns a shape source with an identifier, an array of shapes, and a dictionary of
options for the source.
Any `MGLFeature` instance passed into this initializer is treated as an ordinary
shape, causing any attributes to be inaccessible to an `MGLVectorStyleLayer` when
evaluating a predicate or configuring certain layout or paint attributes. To
preserve the attributes associated with each feature, use the
`-initWithIdentifier:features:options:` method instead.
To create a shape from GeoJSON source code, use the
`+[MGLShape shapeWithData:encoding:error:]` method.
@param identifier A string that uniquely identifies the source.
@param shapes An array of shapes; each shape is a member of a concrete subclass of MGLShape.
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NS_ARRAY_OF(MGLShape *) *)shapes options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options;
#pragma mark Accessing a Source’s Content
/**
@@ -121,6 +194,9 @@ MGL_EXPORT
If the receiver was initialized using `-initWithIdentifier:URL:options:`, this
property is set to `nil`. This property is unavailable until the receiver is
passed into `-[MGLStyle addSource:]`.
You can get/set the shapes within a collection via this property. Actions must
be performed on the application's main thread.
*/
@property (nonatomic, copy, nullable) MGLShape *shape;

View File

@@ -7,6 +7,7 @@
#import "NSURL+MGLAdditions.h"
#include <mbgl/map/map.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
const MGLShapeSourceOption MGLShapeSourceOptionClustered = @"MGLShapeSourceOptionClustered";
@@ -55,6 +56,21 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
return self;
}
- (instancetype)initWithIdentifier:(NSString *)identifier features:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)features options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
for (id <MGLFeature> feature in features) {
if (![feature conformsToProtocol:@protocol(MGLFeature)]) {
[NSException raise:NSInvalidArgumentException format:@"The object %@ included in the features argument does not conform to the MGLFeature protocol.", feature];
}
}
MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:features];
return [self initWithIdentifier:identifier shape:shapeCollectionFeature options:options];
}
- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NS_ARRAY_OF(MGLShape *) *)shapes options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
MGLShapeCollection *shapeCollection = [MGLShapeCollection shapeCollectionWithShapes:shapes];
return [self initWithIdentifier:identifier shape:shapeCollection options:options];
}
- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource {
return [super initWithRawSource:rawSource];
}

View File

@@ -2,6 +2,9 @@
#import <mbgl/util/geojson.hpp>
#import <mbgl/util/geometry.hpp>
#import <mbgl/util/geo.hpp>
bool operator==(const CLLocationCoordinate2D lhs, const CLLocationCoordinate2D rhs);
@interface MGLShape (Private)

View File

@@ -18,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN
Do not create instances of this class directly, and do not create your own
subclasses of this class. Instead, create instances of `MGLShapeSource` and the
concrete subclasses of `MGLTileSource`.
concrete subclasses of `MGLTileSource`, `MGLVectorSource` and `MGLRasterSource`.
*/
MGL_EXPORT
@interface MGLSource : NSObject

View File

@@ -41,10 +41,10 @@ static MGL_EXPORT const NSInteger MGLStyleDefaultVersion = 9;
via `-[MGLMapView style]` by updating the style's data sources or layers.
@note Wait until the map style has finished loading before modifying a map's
style via any of the MGLStyle instance methods below.
You can use the `MGLMapViewDelegate` methods `-mapViewDidFinishLoadingMap:`
or `-mapView:didFinishLoadingStyle:` as indicators that it's safe
to modify the map's style.
style via any of the `MGLStyle` instance methods below. You can use the
`-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
`-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` methods as indicators
that it's safe to modify the map's style.
*/
MGL_EXPORT
@interface MGLStyle : NSObject
@@ -191,7 +191,7 @@ MGL_EXPORT
/**
A set containing the style’s sources.
*/
@property (nonatomic, strong) NS_MUTABLE_SET_OF(MGLSource *) *sources;
@property (nonatomic, strong) NS_SET_OF(__kindof MGLSource *) *sources;
/**
Returns a source with the given identifier in the current style.
@@ -215,8 +215,13 @@ MGL_EXPORT
@note Adding the same source instance more than once will result in a
`MGLRedundantSourceException`. Reusing the same source identifier, even with
different source instances, will result in a
`MGLRedundantSourceIdentifierException`.
`MGLRedundantSourceIdentifierException`.
@note Sources should be added in
`-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
`-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` to ensure that the map
has loaded the style and is ready to accept a new source.
@param source The source to add to the current style.
*/
- (void)addSource:(MGLSource *)source;
@@ -239,10 +244,10 @@ MGL_EXPORT
#pragma mark Managing Style Layers
/**
The layers included in the style, arranged according to their front-to-back
The layers included in the style, arranged according to their back-to-front
ordering on the screen.
*/
@property (nonatomic, strong) NS_MUTABLE_ARRAY_OF(MGLStyleLayer *) *layers;
@property (nonatomic, strong) NS_ARRAY_OF(__kindof MGLStyleLayer *) *layers;
/**
Returns a style layer with the given identifier in the current style.
@@ -266,7 +271,12 @@ MGL_EXPORT
@note Adding the same layer instance more than once will result in a
`MGLRedundantLayerException`. Reusing the same layer identifer, even with
different layer instances, will also result in an exception.
different layer instances, will also result in an exception.
@note Layers should be added in
`-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
`-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` to ensure that the map
has loaded the style and is ready to accept a new layer.
@param layer The layer object to add to the map view. This object must be an
instance of a concrete subclass of `MGLStyleLayer`.
@@ -278,7 +288,12 @@ MGL_EXPORT
@note Adding the same layer instance more than once will result in a
`MGLRedundantLayerException`. Reusing the same layer identifer, even with
different layer instances, will also result in an exception.
different layer instances, will also result in an exception.
@note Layers should be added in
`-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
`-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` to ensure that the map
has loaded the style and is ready to accept a new layer.
@param layer The layer to insert.
@param index The index at which to insert the layer. An index of 0 would send

View File

@@ -24,6 +24,7 @@
#import "MGLAttributionInfo_Private.h"
#include <mbgl/map/map.hpp>
#include <mbgl/util/default_styles.hpp>
#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
@@ -130,9 +131,9 @@ static NSURL *MGLStyleURL_emerald;
#pragma mark Sources
- (NS_MUTABLE_SET_OF(MGLSource *) *)sources {
- (NS_SET_OF(__kindof MGLSource *) *)sources {
auto rawSources = self.mapView.mbglMap->getSources();
NSMutableSet *sources = [NSMutableSet setWithCapacity:rawSources.size()];
NS_MUTABLE_SET_OF(__kindof MGLSource *) *sources = [NSMutableSet setWithCapacity:rawSources.size()];
for (auto rawSource = rawSources.begin(); rawSource != rawSources.end(); ++rawSource) {
MGLSource *source = [self sourceFromMBGLSource:*rawSource];
[sources addObject:source];
@@ -140,7 +141,7 @@ static NSURL *MGLStyleURL_emerald;
return sources;
}
- (void)setSources:(NS_MUTABLE_SET_OF(MGLSource *) *)sources {
- (void)setSources:(NS_SET_OF(__kindof MGLSource *) *)sources {
for (MGLSource *source in self.sources) {
[self removeSource:source];
}
@@ -225,22 +226,22 @@ static NSURL *MGLStyleURL_emerald;
#pragma mark Style layers
- (NS_MUTABLE_ARRAY_OF(MGLStyleLayer *) *)layers
- (NS_ARRAY_OF(__kindof MGLStyleLayer *) *)layers
{
auto layers = self.mapView.mbglMap->getLayers();
NSMutableArray *styleLayers = [NSMutableArray arrayWithCapacity:layers.size()];
for (auto layer = layers.rbegin(); layer != layers.rend(); ++layer) {
MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:*layer];
NS_MUTABLE_ARRAY_OF(__kindof MGLStyleLayer *) *styleLayers = [NSMutableArray arrayWithCapacity:layers.size()];
for (auto layer : layers) {
MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:layer];
[styleLayers addObject:styleLayer];
}
return styleLayers;
}
- (void)setLayers:(NS_MUTABLE_ARRAY_OF(MGLStyleLayer *) *)layers {
for (MGLStyleLayer *layer in self.layers.reverseObjectEnumerator) {
- (void)setLayers:(NS_ARRAY_OF(__kindof MGLStyleLayer *) *)layers {
for (MGLStyleLayer *layer in self.layers) {
[self removeLayer:layer];
}
for (MGLStyleLayer *layer in layers.reverseObjectEnumerator) {
for (MGLStyleLayer *layer in layers) {
[self addLayer:layer];
}
}
@@ -253,12 +254,12 @@ static NSURL *MGLStyleURL_emerald;
- (MGLStyleLayer *)objectInLayersAtIndex:(NSUInteger)index
{
auto layers = self.mapView.mbglMap->getLayers();
if (index > layers.size() - 1) {
if (index >= layers.size()) {
[NSException raise:NSRangeException
format:@"No style layer at index %lu.", (unsigned long)index];
return nil;
}
auto layer = layers.at(layers.size() - 1 - index);
auto layer = layers.at(index);
return [self layerFromMBGLLayer:layer];
}
@@ -290,13 +291,14 @@ static NSURL *MGLStyleURL_emerald;
format:@"Cannot insert style layer at out-of-bounds index %lu.", (unsigned long)index];
} else if (index == 0) {
try {
[styleLayer addToMapView:self.mapView belowLayer:nil];
MGLStyleLayer *sibling = layers.size() ? [self layerFromMBGLLayer:layers.at(0)] : nil;
[styleLayer addToMapView:self.mapView belowLayer:sibling];
} catch (const std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
} else {
try {
MGLStyleLayer *sibling = [self layerFromMBGLLayer:layers.at(layers.size() - index)];
MGLStyleLayer *sibling = [self layerFromMBGLLayer:layers.at(index)];
[styleLayer addToMapView:self.mapView belowLayer:sibling];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
@@ -307,11 +309,11 @@ static NSURL *MGLStyleURL_emerald;
- (void)removeObjectFromLayersAtIndex:(NSUInteger)index
{
auto layers = self.mapView.mbglMap->getLayers();
if (index > layers.size() - 1) {
if (index >= layers.size()) {
[NSException raise:NSRangeException
format:@"Cannot remove style layer at out-of-bounds index %lu.", (unsigned long)index];
}
auto layer = layers.at(layers.size() - 1 - index);
auto layer = layers.at(index);
MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:layer];
[styleLayer removeFromMapView:self.mapView];
}

View File

@@ -1,9 +1,9 @@
<%
const doc = locals.doc;
const type = locals.type;
const layoutProperties = locals.layoutProperties;
const paintProperties = locals.paintProperties;
const layoutPropertiesByName = locals.layoutPropertiesByName;
const paintPropertiesByName = locals.paintPropertiesByName;
const enumProperties = locals.enumProperties;
-%>
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
@@ -21,14 +21,15 @@ NS_ASSUME_NONNULL_BEGIN
<% for (const property of layoutProperties) { -%>
<% if (property.type == "enum") { -%>
/**
<%- propertyDoc(property.name, property, type) %>
<%- propertyDoc(property.name, property, type, 'enum').wrap(80, 1) %>
Values of this type are used in the `<%- camelizeWithLeadingLowercase(property.name) %>` property of `MGL<%- camelize(type) %>StyleLayer`.
Values of this type are used in the `MGL<%- camelize(type) %>StyleLayer.<%- camelizeWithLeadingLowercase(property.name) %>`
property.
*/
typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) {
<% for (const value in property.values) { -%>
/**
<%- propertyDoc(property.name, property.values[value], type) %>
<%- propertyDoc(property.name, property.values[value], type, 'enum').wrap(80, 4+1) %>
*/
MGL<%- camelize(property.name) %><%- camelize(value) %>,
<% } -%>
@@ -39,14 +40,15 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) {
<% for (const property of paintProperties) { -%>
<% if (property.type == "enum") { -%>
/**
<%- propertyDoc(property.name, property, type) %>
<%- propertyDoc(property.name, property, type, 'enum').wrap(80, 1) %>
Values of this type are used in the `<%- camelizeWithLeadingLowercase(property.name) %>` property of `MGL<%- camelize(type) %>StyleLayer`.
Values of this type are used in the `MGL<%- camelize(type) %>StyleLayer.<%- camelizeWithLeadingLowercase(property.name) %>`
property.
*/
typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) {
<% for (const value in property.values) { -%>
/**
<%- propertyDoc(property.name, property.values[value], type) %>
<%- propertyDoc(property.name, property.values[value], type, 'enum').wrap(80, 4+1) %>
*/
MGL<%- camelize(property.name) %><%- camelize(value) %>,
<% } -%>
@@ -56,17 +58,22 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) {
<% } -%>
<% if (type == 'background') { -%>
/**
A map style's background layer is the bottommost layer and is used to style a color
or pattern to show below all other map features. You can query an `MGLMapView` for its
`style` and obtain the background layer using the `-[MGLStyle layerWithIdentifier:]`
method and passing `background` for the identifier.
<%- doc.wrap(80, 1) %>
*/
<% } else { -%>
/**
A <%- type %> layer which allows customization of styling properties at runtime. You may
instantiate a new <%- type %> layer to add to a map style or you may query an
`MGLMapView` for its `style` and obtain existing layers using the
`-[MGLStyle layerWithIdentifier:]` method.
<%- doc.wrap(80, 1) %>
You can access an existing <%- type %> style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
otherwise, find it using the `MGLStyle.layers` property. You can also create a
new <%- type %> style layer and add it to the style using a method such as
`-[MGLStyle addLayer:]`.
### Example
```swift
```
*/
<% } -%>
MGL_EXPORT
@@ -85,18 +92,7 @@ MGL_EXPORT
<% for (const property of layoutProperties) { -%>
/**
<%- propertyDoc(property.name, property, type) %>
<% if ('default' in property) { -%>
The default value of this property is <%- propertyDefault(property, type) %>.<% if (!property.required) { %> Set this property to `nil` to reset it to the default value.<% } %>
<% } if (property.requires) { -%>
<%- propertyReqs(property, layoutPropertiesByName, type) %>
<% } -%>
<% if (property.original) { -%>
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-<%- type -%>-<%- property.original -%>"><code><%- property.original -%></code></a> layout property in the Mapbox Style Specification.
<% } -%>
<%- propertyDoc(property.name, property, type, 'layout').wrap(80, 1) %>
*/
@property (nonatomic<% if (!property.required) { %>, null_resettable<% } if (property.getter) { %>, getter=<%- objCGetter(property) -%><% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>;
@@ -111,22 +107,11 @@ MGL_EXPORT
<% for (const property of paintProperties) { -%>
/**
<%- propertyDoc(property.name, property, type) %>
<% if ('default' in property) { -%>
The default value of this property is <%- propertyDefault(property, type) %>.<% if (!property.required) { %> Set this property to `nil` to reset it to the default value.<% } %>
<% } if (property.requires) { -%>
<%- propertyReqs(property, paintPropertiesByName, type) %>
<% } -%>
<% if (property.original) { -%>
This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-<%- property.original -%>"><code><%- property.original -%></code></a> paint property in the Mapbox Style Specification.
<% } -%>
<%- propertyDoc(property.name, property, type, 'paint').wrap(80, 1) %>
*/
@property (nonatomic<% if (!property.required) { %>, null_resettable<% } if (property.getter) { %>, getter=<%- objCGetter(property) -%><% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>;
<% if (property.original) { %>
<% if (property.original) { -%>
@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> __attribute__((unavailable("Use <%- camelizeWithLeadingLowercase(property.name) %> instead.")));
<% } -%>
@@ -134,4 +119,31 @@ MGL_EXPORT
<% } -%>
@end
<% if (enumProperties) { -%>
/**
Methods for wrapping an enumeration value for a style layer attribute in an
`MGL<%- camelize(type) %>StyleLayer` object and unwrapping its raw value.
*/
@interface NSValue (MGL<%- camelize(type) %>StyleLayerAdditions)
#pragma mark Working with <%- camelize(type) %> Style Layer Attribute Values
<% for (let property of enumProperties) { -%>
/**
Creates a new value object containing the given `MGL<%- camelize(property.name) %>` enumeration.
@param <%- objCName(property) %> The value for the new object.
@return A new value object that contains the enumeration value.
*/
+ (instancetype)valueWithMGL<%- camelize(property.name) %>:(MGL<%- camelize(property.name) %>)<%- objCName(property) %>;
/**
The `MGL<%- camelize(property.name) %>` enumeration representation of the value.
*/
@property (readonly) MGL<%- camelize(property.name) %> MGL<%- camelize(property.name) %>Value;
<% } -%>
@end
<% } -%>
NS_ASSUME_NONNULL_END

View File

@@ -2,10 +2,10 @@
const type = locals.type;
const layoutProperties = locals.layoutProperties;
const paintProperties = locals.paintProperties;
const containsEnumerationProperties = locals.containsEnumerationProperties;
const enumProperties = locals.enumProperties;
-%>
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "MGLMapView_Private.h"
@@ -14,8 +14,10 @@
#import "MGLStyleValue_Private.h"
#import "MGL<%- camelize(type) %>StyleLayer.h"
#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp>
<% if (containsEnumerationProperties) { -%>
<% if (enumProperties) { -%>
namespace mbgl {
<% if (layoutProperties.length) { -%>
@@ -89,7 +91,15 @@ namespace mbgl {
super.rawLayer = rawLayer;
}
<% if (type !== 'background' && type !== 'raster') { -%>
<% if (type !== 'background') { -%>
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
return @(self.rawLayer->getSourceID().c_str());
}
<% if (type !== 'raster') { -%>
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -109,7 +119,7 @@ namespace mbgl {
{
MGLAssertStyleLayerIsValid();
self.rawLayer->setFilter(predicate.mgl_filter);
self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter());
}
- (NSPredicate *)predicate
@@ -119,7 +129,7 @@ namespace mbgl {
return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()];
}
<% } -%>
<% }} -%>
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
@@ -167,7 +177,7 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
<% if (property.type == "enum") { -%>
auto mbglValue = MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>);
auto mbglValue = MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>);
self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
<% } else { -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>);
@@ -180,15 +190,14 @@ namespace mbgl {
auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
<% if (property.type == "enum") { -%>
return MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
return MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
<% } else { -%>
return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(propertyValue);
<% } -%>
}
<% if (property.original) { %>
<% if (property.original) { -%>
- (void)set<%- camelize(originalPropertyName(property)) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
self.<%- camelizeWithLeadingLowercase(property.name) %> = <%- camelizeWithLeadingLowercase(originalPropertyName(property)) %>;
}
- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
@@ -206,7 +215,7 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
<% if (property.type == "enum") { -%>
auto mbglValue = MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>);
auto mbglValue = MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>);
self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
<% } else { -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>);
@@ -219,15 +228,18 @@ namespace mbgl {
auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
<% if (property.type == "enum") { -%>
return MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
return MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
<% } else { -%>
return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(propertyValue);
<% } -%>
}
<% if (property.original) { %>
<% if (property.original) { -%>
- (void)set<%- camelize(originalPropertyName(property)) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
NSAssert(NO, @"Use -set<%- camelize(property.name) %>: instead.");
}
- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
return self.<%- objCGetter(property) %>;
}
<% } -%>
@@ -235,3 +247,21 @@ namespace mbgl {
<% } -%>
@end
<% if (enumProperties) { -%>
@implementation NSValue (MGL<%- camelize(type) %>StyleLayerAdditions)
<% for (let property of enumProperties) { -%>
+ (NSValue *)valueWithMGL<%- camelize(property.name) %>:(MGL<%- camelize(property.name) %>)<%- objCName(property) %> {
return [NSValue value:&<%- objCName(property) %> withObjCType:@encode(MGL<%- camelize(property.name) %>)];
}
- (MGL<%- camelize(property.name) %>)MGL<%- camelize(property.name) %>Value {
MGL<%- camelize(property.name) %> <%- objCName(property) %>;
[self getValue:&<%- objCName(property) %>];
return <%- objCName(property) %>;
}
<% } -%>
@end
<% } -%>

View File

@@ -18,13 +18,13 @@ NS_ASSUME_NONNULL_BEGIN
The `MGLStyleValue` class takes a generic parameter `T` that indicates the
Foundation class being wrapped by this class. Common values for `T` include:
<ul>
<li>`NSNumber` (for Boolean values, floating-point numbers, and enumerations)</li>
<li>`NSValue` (for `CGVector`, `NSEdgeInset`, and `UIEdgeInset`s)</li>
<li>`NSString`</li>
<li>`NSColor` or `UIColor`</li>
<li>`NSArray`</li>
<li><code>NSNumber</code> (for Boolean values and floating-point numbers)</li>
<li><code>NSValue</code> (for <code>CGVector</code>, <code>NSEdgeInsets</code>, <code>UIEdgeInsets</code>, and enumerations)</li>
<li><code>NSString</code></li>
<li><code>NSColor</code> or <code>UIColor</code></li>
<li><code>NSArray</code></li>
</ul>
*/
MGL_EXPORT
@@ -52,13 +52,13 @@ MGL_EXPORT
/**
Creates and returns an `MGLStyleFunction` object representing a zoom level
function with an exponential base and any number of stops.
function with an exponential interpolation base and any number of stops.
@param base The exponential base of the interpolation curve.
@param interpolationBase The exponential base of the interpolation curve.
@param stops A dictionary associating zoom levels with style values.
@return An `MGLStyleFunction` object with the given base and stops.
@return An `MGLStyleFunction` object with the given interpolation base and stops.
*/
+ (instancetype)valueWithBase:(CGFloat)base stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops;
+ (instancetype)valueWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops;
@end
@@ -131,38 +131,38 @@ MGL_EXPORT
/**
Creates and returns an `MGLStyleFunction` object representing a zoom level
function with an exponential base and any number of stops.
function with an exponential interpolation base and any number of stops.
@param base The exponential base of the interpolation curve.
@param interpolationBase The exponential base of the interpolation curve.
@param stops A dictionary associating zoom levels with style values.
@return An `MGLStyleFunction` object with the given base and stops.
@return An `MGLStyleFunction` object with the given interpolation base and stops.
*/
+ (instancetype)functionWithBase:(CGFloat)base stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops;
+ (instancetype)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops;
#pragma mark Initializing a Style Function
/**
Returns an `MGLStyleFunction` object representing a zoom level function with an
exponential base and any number of stops.
exponential interpolation base and any number of stops.
@param base The exponential base of the interpolation curve.
@param interpolationBase The exponential base of the interpolation curve.
@param stops A dictionary associating zoom levels with style values.
@return An `MGLStyleFunction` object with the given base and stops.
@return An `MGLStyleFunction` object with the given interpolation base and stops.
*/
- (instancetype)initWithBase:(CGFloat)base stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops NS_DESIGNATED_INITIALIZER;
#pragma mark Accessing the Parameters of a Function
/**
The exponential base of the function’s interpolation curve.
The exponential interpolation base of the function’s interpolation curve.
The exponential base controls the rate at which the function’s output values
The exponential interpolation base controls the rate at which the function’s output values
increase. A value of 1 causes the function to increase linearly by zoom level.
A higher exponential base causes the function’s output values to vary
A higher exponential interpolation base causes the function’s output values to vary
exponentially, increasing more rapidly towards the high end of the function’s
range. The default value of this property is 1, for a linear curve.
*/
@property (nonatomic) CGFloat base;
@property (nonatomic) CGFloat interpolationBase;
/**
A dictionary associating zoom levels with style values.

View File

@@ -6,8 +6,8 @@
return [MGLStyleConstantValue valueWithRawValue:rawValue];
}
+ (instancetype)valueWithBase:(CGFloat)base stops:(NSDictionary *)stops {
return [MGLStyleFunction functionWithBase:base stops:stops];
+ (instancetype)valueWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
return [MGLStyleFunction functionWithInterpolationBase:interpolationBase stops:stops];
}
+ (instancetype)valueWithStops:(NSDictionary *)stops {
@@ -49,44 +49,44 @@
@implementation MGLStyleFunction
+ (instancetype)functionWithBase:(CGFloat)base stops:(NSDictionary *)stops {
return [[self alloc] initWithBase:base stops:stops];
+ (instancetype)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
return [[self alloc] initWithInterpolationBase:interpolationBase stops:stops];
}
+ (instancetype)functionWithStops:(NSDictionary *)stops {
return [[self alloc] initWithBase:1 stops:stops];
return [[self alloc] initWithInterpolationBase:1 stops:stops];
}
- (instancetype)init {
return [self initWithBase:1 stops:@{}];
return [self initWithInterpolationBase:1 stops:@{}];
}
- (instancetype)initWithBase:(CGFloat)base stops:(NSDictionary *)stops {
- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
if (self = [super init]) {
if (!stops.count)
{
[NSException raise:NSInvalidArgumentException format:@"%@ requires at least one stop.", self];
}
_base = base;
_interpolationBase = interpolationBase;
_stops = stops;
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"<%@: %p, base = %f; stops = %@>",
return [NSString stringWithFormat:@"<%@: %p, interpolationBase = %f; stops = %@>",
NSStringFromClass([self class]), (void *)self,
self.base,
self.interpolationBase,
self.stops];
}
- (BOOL)isEqual:(MGLStyleFunction *)other {
return ([other isKindOfClass:[self class]] && other.base == self.base
return ([other isKindOfClass:[self class]] && other.interpolationBase == self.interpolationBase
&& [other.stops isEqualToDictionary:self.stops]);
}
- (NSUInteger)hash {
return self.base + self.stops.hash;
return self.interpolationBase + self.stops.hash;
}
@end

View File

@@ -4,7 +4,6 @@
#import "NSValue+MGLStyleAttributeAdditions.h"
#import "MGLTypes.h"
#import "MGLLineStyleLayer.h"
#import <mbgl/util/enum.hpp>
#if TARGET_OS_IPHONE
@@ -42,7 +41,7 @@ public:
for (const auto &mbglStop : mbglStops) {
stops[@(mbglStop.first)] = toEnumStyleConstantValue<>(mbglStop.second);
}
return [MGLStyleFunction<NSValue *> functionWithBase:mbglValue.asFunction().getBase() stops:stops];
return [MGLStyleFunction<NSValue *> functionWithInterpolationBase:mbglValue.asFunction().getBase() stops:stops];
} else {
return nil;
}
@@ -62,7 +61,7 @@ public:
NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
mbglStops.emplace_back(zoomKey.floatValue, mbglStopValue.asConstant());
}];
return mbgl::style::Function<MBGLType>({{mbglStops}}, function.base);
return mbgl::style::Function<MBGLType>({{mbglStops}}, function.interpolationBase);
} else if (value) {
[NSException raise:@"MGLAbstractClassException" format:
@"The style value %@ cannot be applied to the style. "
@@ -92,7 +91,7 @@ public:
NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
mbglStops.emplace_back(zoomKey.floatValue, mbglStopValue.asConstant());
}];
return mbgl::style::Function<MBGLEnum>({{mbglStops}}, function.base);
return mbgl::style::Function<MBGLEnum>({{mbglStops}}, function.interpolationBase);
} else if (value) {
[NSException raise:@"MGLAbstractClassException" format:
@"The style value %@ cannot be applied to the style. "
@@ -118,7 +117,7 @@ private:
auto rawValue = toMGLRawStyleValue(mbglStop.second);
stops[@(mbglStop.first)] = [MGLStyleValue valueWithRawValue:rawValue];
}
return [MGLStyleFunction<ObjCType> functionWithBase:mbglFunction.getBase() stops:stops];
return [MGLStyleFunction<ObjCType> functionWithInterpolationBase:mbglFunction.getBase() stops:stops];
}
template <typename MBGLEnum = MBGLType,

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "MGLMapView_Private.h"
@@ -8,7 +8,9 @@
#import "MGLStyleValue_Private.h"
#import "MGLSymbolStyleLayer.h"
#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
namespace mbgl {
MBGL_DEFINE_ENUM(MGLIconRotationAlignment, {
@@ -65,14 +67,14 @@ namespace mbgl {
{ MGLTextTransformLowercase, "lowercase" },
});
MBGL_DEFINE_ENUM(MGLIconTranslateAnchor, {
{ MGLIconTranslateAnchorMap, "map" },
{ MGLIconTranslateAnchorViewport, "viewport" },
MBGL_DEFINE_ENUM(MGLIconTranslationAnchor, {
{ MGLIconTranslationAnchorMap, "map" },
{ MGLIconTranslationAnchorViewport, "viewport" },
});
MBGL_DEFINE_ENUM(MGLTextTranslateAnchor, {
{ MGLTextTranslateAnchorMap, "map" },
{ MGLTextTranslateAnchorViewport, "viewport" },
MBGL_DEFINE_ENUM(MGLTextTranslationAnchor, {
{ MGLTextTranslationAnchorMap, "map" },
{ MGLTextTranslationAnchorViewport, "viewport" },
});
}
@@ -108,6 +110,13 @@ namespace mbgl {
super.rawLayer = rawLayer;
}
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
return @(self.rawLayer->getSourceID().c_str());
}
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -127,7 +136,7 @@ namespace mbgl {
{
MGLAssertStyleLayerIsValid();
self.rawLayer->setFilter(predicate.mgl_filter);
self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter());
}
- (NSPredicate *)predicate
@@ -192,9 +201,7 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setIconAllowOverlap:(MGLStyleValue<NSNumber *> *)iconAllowOverlap {
self.iconAllowsOverlap = iconAllowOverlap;
}
- (MGLStyleValue<NSNumber *> *)iconAllowOverlap {
@@ -215,9 +222,7 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setIconIgnorePlacement:(MGLStyleValue<NSNumber *> *)iconIgnorePlacement {
self.iconIgnoresPlacement = iconIgnorePlacement;
}
- (MGLStyleValue<NSNumber *> *)iconIgnorePlacement {
@@ -238,9 +243,7 @@ namespace mbgl {
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}
- (void)setIconImage:(MGLStyleValue<NSString *> *)iconImage {
self.iconImageName = iconImage;
}
- (MGLStyleValue<NSString *> *)iconImage {
@@ -303,9 +306,7 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setIconRotate:(MGLStyleValue<NSNumber *> *)iconRotate {
self.iconRotation = iconRotate;
}
- (MGLStyleValue<NSNumber *> *)iconRotate {
@@ -340,9 +341,7 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setIconSize:(MGLStyleValue<NSNumber *> *)iconSize {
self.iconScale = iconSize;
}
- (MGLStyleValue<NSNumber *> *)iconSize {
@@ -391,9 +390,7 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setIconKeepUpright:(MGLStyleValue<NSNumber *> *)iconKeepUpright {
self.keepsIconUpright = iconKeepUpright;
}
- (MGLStyleValue<NSNumber *> *)iconKeepUpright {
@@ -414,9 +411,7 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setTextKeepUpright:(MGLStyleValue<NSNumber *> *)textKeepUpright {
self.keepsTextUpright = textKeepUpright;
}
- (MGLStyleValue<NSNumber *> *)textKeepUpright {
@@ -437,9 +432,7 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setTextMaxAngle:(MGLStyleValue<NSNumber *> *)textMaxAngle {
self.maximumTextAngle = textMaxAngle;
}
- (MGLStyleValue<NSNumber *> *)textMaxAngle {
@@ -460,9 +453,7 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setTextMaxWidth:(MGLStyleValue<NSNumber *> *)textMaxWidth {
self.maximumTextWidth = textMaxWidth;
}
- (MGLStyleValue<NSNumber *> *)textMaxWidth {
@@ -483,9 +474,7 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setSymbolAvoidEdges:(MGLStyleValue<NSNumber *> *)symbolAvoidEdges {
self.symbolAvoidsEdges = symbolAvoidEdges;
}
- (MGLStyleValue<NSNumber *> *)symbolAvoidEdges {
@@ -520,6 +509,27 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setText:(MGLStyleValue<NSString *> *)text {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(text);
self.rawLayer->setTextField(mbglValue);
}
- (MGLStyleValue<NSString *> *)text {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextField() ?: self.rawLayer->getDefaultTextField();
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}
- (void)setTextField:(MGLStyleValue<NSString *> *)textField {
}
- (MGLStyleValue<NSString *> *)textField {
return self.text;
}
- (void)setTextAllowsOverlap:(MGLStyleValue<NSNumber *> *)textAllowsOverlap {
MGLAssertStyleLayerIsValid();
@@ -534,9 +544,7 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setTextAllowOverlap:(MGLStyleValue<NSNumber *> *)textAllowOverlap {
self.textAllowsOverlap = textAllowOverlap;
}
- (MGLStyleValue<NSNumber *> *)textAllowOverlap {
@@ -557,34 +565,48 @@ namespace mbgl {
return MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toEnumStyleValue(propertyValue);
}
- (void)setTextField:(MGLStyleValue<NSString *> *)textField {
- (void)setTextFontNames:(MGLStyleValue<NSArray<NSString *> *> *)textFontNames {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(textField);
self.rawLayer->setTextField(mbglValue);
}
- (MGLStyleValue<NSString *> *)textField {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextField() ?: self.rawLayer->getDefaultTextField();
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}
- (void)setTextFont:(MGLStyleValue<NSArray<NSString *> *> *)textFont {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toPropertyValue(textFont);
auto mbglValue = MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toPropertyValue(textFontNames);
self.rawLayer->setTextFont(mbglValue);
}
- (MGLStyleValue<NSArray<NSString *> *> *)textFont {
- (MGLStyleValue<NSArray<NSString *> *> *)textFontNames {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextFont() ?: self.rawLayer->getDefaultTextFont();
return MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toStyleValue(propertyValue);
}
- (void)setTextFont:(MGLStyleValue<NSArray<NSString *> *> *)textFont {
}
- (MGLStyleValue<NSArray<NSString *> *> *)textFont {
return self.textFontNames;
}
- (void)setTextFontSize:(MGLStyleValue<NSNumber *> *)textFontSize {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textFontSize);
self.rawLayer->setTextSize(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)textFontSize {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextSize() ?: self.rawLayer->getDefaultTextSize();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setTextSize:(MGLStyleValue<NSNumber *> *)textSize {
}
- (MGLStyleValue<NSNumber *> *)textSize {
return self.textFontSize;
}
- (void)setTextIgnoresPlacement:(MGLStyleValue<NSNumber *> *)textIgnoresPlacement {
MGLAssertStyleLayerIsValid();
@@ -599,9 +621,7 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setTextIgnorePlacement:(MGLStyleValue<NSNumber *> *)textIgnorePlacement {
self.textIgnoresPlacement = textIgnorePlacement;
}
- (MGLStyleValue<NSNumber *> *)textIgnorePlacement {
@@ -622,9 +642,7 @@ namespace mbgl {
return MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toEnumStyleValue(propertyValue);
}
- (void)setTextJustify:(MGLStyleValue<NSValue *> *)textJustify {
self.textJustification = textJustify;
}
- (MGLStyleValue<NSValue *> *)textJustify {
@@ -729,9 +747,7 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setTextRotate:(MGLStyleValue<NSNumber *> *)textRotate {
self.textRotation = textRotate;
}
- (MGLStyleValue<NSNumber *> *)textRotate {
@@ -752,20 +768,6 @@ namespace mbgl {
return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextRotationAlignment>().toEnumStyleValue(propertyValue);
}
- (void)setTextSize:(MGLStyleValue<NSNumber *> *)textSize {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textSize);
self.rawLayer->setTextSize(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)textSize {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextSize() ?: self.rawLayer->getDefaultTextSize();
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setTextTransform:(MGLStyleValue<NSValue *> *)textTransform {
MGLAssertStyleLayerIsValid();
@@ -852,32 +854,46 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setIconTranslate:(MGLStyleValue<NSValue *> *)iconTranslate {
- (void)setIconTranslation:(MGLStyleValue<NSValue *> *)iconTranslation {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(iconTranslate);
auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(iconTranslation);
self.rawLayer->setIconTranslate(mbglValue);
}
- (MGLStyleValue<NSValue *> *)iconTranslate {
- (MGLStyleValue<NSValue *> *)iconTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconTranslate() ?: self.rawLayer->getDefaultIconTranslate();
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
- (void)setIconTranslateAnchor:(MGLStyleValue<NSValue *> *)iconTranslateAnchor {
- (void)setIconTranslate:(MGLStyleValue<NSValue *> *)iconTranslate {
}
- (MGLStyleValue<NSValue *> *)iconTranslate {
return self.iconTranslation;
}
- (void)setIconTranslationAnchor:(MGLStyleValue<NSValue *> *)iconTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslateAnchor>().toEnumPropertyValue(iconTranslateAnchor);
auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslationAnchor>().toEnumPropertyValue(iconTranslationAnchor);
self.rawLayer->setIconTranslateAnchor(mbglValue);
}
- (MGLStyleValue<NSValue *> *)iconTranslateAnchor {
- (MGLStyleValue<NSValue *> *)iconTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconTranslateAnchor() ?: self.rawLayer->getDefaultIconTranslateAnchor();
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslateAnchor>().toEnumStyleValue(propertyValue);
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslationAnchor>().toEnumStyleValue(propertyValue);
}
- (void)setIconTranslateAnchor:(MGLStyleValue<NSValue *> *)iconTranslateAnchor {
}
- (MGLStyleValue<NSValue *> *)iconTranslateAnchor {
return self.iconTranslationAnchor;
}
- (void)setTextColor:(MGLStyleValue<MGLColor *> *)textColor {
@@ -950,33 +966,151 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setTextTranslate:(MGLStyleValue<NSValue *> *)textTranslate {
- (void)setTextTranslation:(MGLStyleValue<NSValue *> *)textTranslation {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(textTranslate);
auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(textTranslation);
self.rawLayer->setTextTranslate(mbglValue);
}
- (MGLStyleValue<NSValue *> *)textTranslate {
- (MGLStyleValue<NSValue *> *)textTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextTranslate() ?: self.rawLayer->getDefaultTextTranslate();
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
- (void)setTextTranslateAnchor:(MGLStyleValue<NSValue *> *)textTranslateAnchor {
- (void)setTextTranslate:(MGLStyleValue<NSValue *> *)textTranslate {
}
- (MGLStyleValue<NSValue *> *)textTranslate {
return self.textTranslation;
}
- (void)setTextTranslationAnchor:(MGLStyleValue<NSValue *> *)textTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslateAnchor>().toEnumPropertyValue(textTranslateAnchor);
auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslationAnchor>().toEnumPropertyValue(textTranslationAnchor);
self.rawLayer->setTextTranslateAnchor(mbglValue);
}
- (MGLStyleValue<NSValue *> *)textTranslateAnchor {
- (MGLStyleValue<NSValue *> *)textTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextTranslateAnchor() ?: self.rawLayer->getDefaultTextTranslateAnchor();
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslateAnchor>().toEnumStyleValue(propertyValue);
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslationAnchor>().toEnumStyleValue(propertyValue);
}
- (void)setTextTranslateAnchor:(MGLStyleValue<NSValue *> *)textTranslateAnchor {
}
- (MGLStyleValue<NSValue *> *)textTranslateAnchor {
return self.textTranslationAnchor;
}
@end
@implementation NSValue (MGLSymbolStyleLayerAdditions)
+ (NSValue *)valueWithMGLIconRotationAlignment:(MGLIconRotationAlignment)iconRotationAlignment {
return [NSValue value:&iconRotationAlignment withObjCType:@encode(MGLIconRotationAlignment)];
}
- (MGLIconRotationAlignment)MGLIconRotationAlignmentValue {
MGLIconRotationAlignment iconRotationAlignment;
[self getValue:&iconRotationAlignment];
return iconRotationAlignment;
}
+ (NSValue *)valueWithMGLIconTextFit:(MGLIconTextFit)iconTextFit {
return [NSValue value:&iconTextFit withObjCType:@encode(MGLIconTextFit)];
}
- (MGLIconTextFit)MGLIconTextFitValue {
MGLIconTextFit iconTextFit;
[self getValue:&iconTextFit];
return iconTextFit;
}
+ (NSValue *)valueWithMGLSymbolPlacement:(MGLSymbolPlacement)symbolPlacement {
return [NSValue value:&symbolPlacement withObjCType:@encode(MGLSymbolPlacement)];
}
- (MGLSymbolPlacement)MGLSymbolPlacementValue {
MGLSymbolPlacement symbolPlacement;
[self getValue:&symbolPlacement];
return symbolPlacement;
}
+ (NSValue *)valueWithMGLTextAnchor:(MGLTextAnchor)textAnchor {
return [NSValue value:&textAnchor withObjCType:@encode(MGLTextAnchor)];
}
- (MGLTextAnchor)MGLTextAnchorValue {
MGLTextAnchor textAnchor;
[self getValue:&textAnchor];
return textAnchor;
}
+ (NSValue *)valueWithMGLTextJustification:(MGLTextJustification)textJustification {
return [NSValue value:&textJustification withObjCType:@encode(MGLTextJustification)];
}
- (MGLTextJustification)MGLTextJustificationValue {
MGLTextJustification textJustification;
[self getValue:&textJustification];
return textJustification;
}
+ (NSValue *)valueWithMGLTextPitchAlignment:(MGLTextPitchAlignment)textPitchAlignment {
return [NSValue value:&textPitchAlignment withObjCType:@encode(MGLTextPitchAlignment)];
}
- (MGLTextPitchAlignment)MGLTextPitchAlignmentValue {
MGLTextPitchAlignment textPitchAlignment;
[self getValue:&textPitchAlignment];
return textPitchAlignment;
}
+ (NSValue *)valueWithMGLTextRotationAlignment:(MGLTextRotationAlignment)textRotationAlignment {
return [NSValue value:&textRotationAlignment withObjCType:@encode(MGLTextRotationAlignment)];
}
- (MGLTextRotationAlignment)MGLTextRotationAlignmentValue {
MGLTextRotationAlignment textRotationAlignment;
[self getValue:&textRotationAlignment];
return textRotationAlignment;
}
+ (NSValue *)valueWithMGLTextTransform:(MGLTextTransform)textTransform {
return [NSValue value:&textTransform withObjCType:@encode(MGLTextTransform)];
}
- (MGLTextTransform)MGLTextTransformValue {
MGLTextTransform textTransform;
[self getValue:&textTransform];
return textTransform;
}
+ (NSValue *)valueWithMGLIconTranslationAnchor:(MGLIconTranslationAnchor)iconTranslationAnchor {
return [NSValue value:&iconTranslationAnchor withObjCType:@encode(MGLIconTranslationAnchor)];
}
- (MGLIconTranslationAnchor)MGLIconTranslationAnchorValue {
MGLIconTranslationAnchor iconTranslationAnchor;
[self getValue:&iconTranslationAnchor];
return iconTranslationAnchor;
}
+ (NSValue *)valueWithMGLTextTranslationAnchor:(MGLTextTranslationAnchor)textTranslationAnchor {
return [NSValue value:&textTranslationAnchor withObjCType:@encode(MGLTextTranslationAnchor)];
}
- (MGLTextTranslationAnchor)MGLTextTranslationAnchorValue {
MGLTextTranslationAnchor textTranslationAnchor;
[self getValue:&textTranslationAnchor];
return textTranslationAnchor;
}
@end

View File

@@ -20,6 +20,10 @@ typedef NSString *MGLTileSourceOption NS_STRING_ENUM;
The value should be between 0 and 22, inclusive, and less than
`MGLTileSourceOptionMaximumZoomLevel`, if specified. The default value for this
option is 0.
This option corresponds to the `minzoom` key in the
<a href="https://github.com/mapbox/tilejson-spec/tree/master/2.1.0">TileJSON</a>
specification.
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionMinimumZoomLevel;
@@ -30,6 +34,10 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionMinimumZoomLevel;
The value should be between 0 and 22, inclusive, and less than
`MGLTileSourceOptionMinimumZoomLevel`, if specified. The default value for this
option is 22.
This option corresponds to the `maxzoom` key in the
<a href="https://github.com/mapbox/tilejson-spec/tree/master/2.1.0">TileJSON</a>
specification.
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionMaximumZoomLevel;
@@ -42,6 +50,10 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionMaximumZoomLevel;
By default, no attribution statements are displayed. If the
`MGLTileSourceOptionAttributionInfos` option is specified, this option is
ignored.
This option corresponds to the `attribution` key in the
<a href="https://github.com/mapbox/tilejson-spec/tree/master/2.1.0">TileJSON</a>
specification.
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLString;
@@ -61,6 +73,10 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionInfos;
By default, no attribution statements are displayed. If the
`MGLTileSourceOptionAttributionInfos` option is specified, this option is
ignored.
This option corresponds to the `attribution` key in the
<a href="https://github.com/mapbox/tilejson-spec/tree/master/2.1.0">TileJSON</a>
specification.
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLString;
@@ -80,6 +96,10 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionInfos;
the constants described in `MGLTileCoordinateSystem`.
The default value for this option is `MGLTileCoordinateSystemXYZ`.
This option corresponds to the `scheme` key in the
<a href="https://github.com/mapbox/tilejson-spec/tree/master/2.1.0">TileJSON</a>
specification.
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem;
@@ -150,13 +170,101 @@ MGL_EXPORT
/**
Returns a tile source initialized an identifier, tile URL templates, and
options.
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
#### Tile URL templates
Tile URL templates are strings that specify the URLs of the tile images to
load. Each template resembles an absolute URL, but with any number of
placeholder strings that the source evaluates based on the tile it needs to
load. For example:
<ul>
<li><code>http://www.example.com/tiles/{z}/{x}/{y}.pbf</code> could be
evaluated as <code>http://www.example.com/tiles/14/6/9.pbf</code>.</li>
<li><code>http://www.example.com/tiles/{z}/{x}/{y}{ratio}.png</code> could be
evaluated as <code>http://www.example.com/tiles/14/6/9@2x.png</code>.</li>
</ul>
Tile sources support the following placeholder strings in tile URL templates,
all of which are optional:
<table>
<thead>
<tr><th>Placeholder string</th><th>Description</th></tr>
</thead>
<tbody>
<tr>
<td><code>{x}</code></td>
<td>The index of the tile along the map’s x axis according to Spherical
Mercator projection. If the value is 0, the tile’s left edge corresponds
to the 180th meridian west. If the value is 2<sup><var>z</var></sup>−1,
the tile’s right edge corresponds to the 180th meridian east.</td>
</tr>
<tr>
<td><code>{y}</code></td>
<td>The index of the tile along the map’s y axis according to Spherical
Mercator projection. If the value is 0, the tile’s tile edge corresponds
to arctan(sinh(π)), or approximately 85.0511 degrees north. If the value
is 2<sup><var>z</var></sup>−1, the tile’s bottom edge corresponds to
−arctan(sinh(π)), or approximately 85.0511 degrees south. The y axis is
inverted if the <code>options</code> parameter contains
<code>MGLTileSourceOptionTileCoordinateSystem</code> with a value of
<code>MGLTileCoordinateSystemTMS</code>.</td>
</tr>
<tr>
<td><code>{z}</code></td>
<td>The tile’s zoom level. At zoom level 0, each tile covers the entire
world map; at zoom level 1, it covers ¼ of the world; at zoom level 2,
<sup>1</sup>⁄<sub>16</sub> of the world, and so on. For tiles loaded by
a <code>MGLRasterSource</code> object, whether the tile zoom level
matches the map’s current zoom level depends on the value of the
source’s tile size as specified in the
<code>MGLTileSourceOptionTileSize</code> key of the
<code>options</code> parameter.</td>
</tr>
<tr>
<td><code>{bbox-epsg-3857}</code></td>
<td>The tile’s bounding box, expressed as a comma-separated list of the
tile’s western, southern, eastern, and northern extents according to
Spherical Mercator (EPSG:3857) projection. The bounding box is typically
used with map services conforming to the
<a href="http://www.opengeospatial.org/standards/wms">Web Map Service</a>
protocol.</td>
</tr>
<tr>
<td><code>{quadkey}</code></td>
<td>A quadkey indicating both the tile’s location and its zoom level. The
quadkey is typically used with
<a href="https://msdn.microsoft.com/en-us/library/bb259689.aspx">Bing Maps</a>.
</td>
</tr>
<tr>
<td><code>{ratio}</code></td>
<td>A suffix indicating the resolution of the tile image. The suffix is the
empty string for standard resolution displays and <code>@2x</code> for
Retina displays, including displays for which
<code>NSScreen.backingScaleFactor</code> or <code>UIScreen.scale</code>
is 3.</td>
</tr>
<tr>
<td><code>{prefix}</code></td>
<td>Two hexadecimal digits chosen such that each visible tile has a
different prefix. The prefix is typically used for domain sharding.</td>
</tr>
</tbody>
</table>
For more information about the `{x}`, `{y}`, and `{z}` placeholder strings,
consult the
<a href="https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">OpenStreetMap Wiki</a>.
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param tileURLTemplates An array of tile URL template strings.
@param tileURLTemplates An array of tile URL template strings. Only the first
string is used; any additional strings are ignored.
@param options A dictionary containing configuration options. See
`MGLTileSourceOption` for available keys and values. Pass in `nil` to use
the default values.
@@ -164,6 +272,17 @@ MGL_EXPORT
*/
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options;
#pragma mark Accessing a Source’s Content
/**
The URL to the TileJSON configuration file that specifies the contents of the
source.
If the receiver was initialized using
`-initWithIdentifier:tileURLTemplates:options`, this property is set to `nil`.
*/
@property (nonatomic, copy, nullable, readonly) NSURL *configurationURL;
#pragma mark Accessing Attribution Strings
/**

View File

@@ -27,6 +27,12 @@ const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem = @"MGLTileSou
return [super initWithIdentifier:identifier];
}
- (NSURL *)configurationURL {
[NSException raise:@"MGLAbstractClassException"
format:@"MGLTileSource is an abstract class"];
return nil;
}
- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos {
return [self attributionInfosWithFontSize:0 linkColor:nil];
}

View File

@@ -25,6 +25,19 @@ NS_ASSUME_NONNULL_BEGIN
(<var>extent</var>&nbsp;×&nbsp;2)&nbsp;−&nbsp;1, inclusive. Any vector style
layer initialized with a vector source must have a non-`nil` value in its
`sourceLayerIdentifier` property.
### Example
```swift
let source = MGLVectorSource(identifier: "pois", tileURLTemplates: ["https://example.com/vector-tiles/{z}/{x}/{y}.mvt"], options: [
.minimumZoomLevel: 9,
.maximumZoomLevel: 16,
.attributionInfos: [
MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
]
])
mapView.style?.addSource(source)
```
*/
MGL_EXPORT
@interface MGLVectorSource : MGLTileSource

View File

@@ -5,6 +5,7 @@
#import "MGLTileSource_Private.h"
#import "NSURL+MGLAdditions.h"
#include <mbgl/map/map.hpp>
#include <mbgl/style/sources/vector_source.hpp>
@interface MGLVectorSource ()
@@ -69,6 +70,11 @@
super.rawSource = 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;

View File

@@ -61,11 +61,15 @@ MGL_EXPORT
<li><code>NSContainsPredicateOperatorType</code> (<code>CONTAINS</code>)</li>
</ul>
To test whether a feature has or lacks a specific attribute, compare the attribute to `NULL` or `NIL`. Predicates created using the `+[NSPredicate predicateWithValue:]` method are also supported. String operators and custom operators are not supported.
To test whether a feature has or lacks a specific attribute, compare the
attribute to `NULL` or `NIL`. Predicates created using the
`+[NSPredicate predicateWithValue:]` method are also supported. String
operators and custom operators are not supported.
For details about the predicate format string syntax, consult the “Predicate
Format String Syntax” chapter of the “Predicate Programming Guide” in Apple
developer documentation.
Format String Syntax” chapter of the
“<a href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/">Predicate Programming Guide</a>”
in Apple developer documentation.
The predicate's left-hand expression must be a string that identifies a feature
attribute or, alternatively, one of the following special attributes:
@@ -121,15 +125,29 @@ MGL_EXPORT
Automatic type casting is not performed. Therefore, a feature only matches this
predicate if its value for the attribute in question is of the same type as the
value specified in the predicate. Also, operator modifiers `c`, `d`, and the
combined `cd` for case and diacritic insensitivity are unsupported for
comparison and aggregate operators that are used in the predicate.
value specified in the predicate. Also, operator modifiers such as `c` (for
case insensitivity), `d` (for diacritic insensitivity), and `l` (for locale
sensitivity) are unsupported for comparison and aggregate operators that are
used in the predicate.
It is possible to create expressions that contain special characters in the
predicate format syntax. This includes the `$` in the `$id` and `$type` special
style attributes and also `hyphen-minus` and `tag:subtag`. However, you must use
`%K` in the format string to represent these variables:
`@"%K == 'LineString'", @"$type"`.
### Example
To filter the layer to include only the features whose `index` attribute is 5
or 10 and whose `ele` attribute is at least 1,500, you could create an
`NSCompoundPredicate` along these lines:
```swift
let layer = MGLLineStyleLayer(identifier: "contour", source: terrain)
layer.sourceLayerIdentifier = "contours"
layer.predicate = NSPredicate(format: "(index == 5 || index == 10) && ele >= 1500.0")
mapView.style?.addLayer(layer)
```
*/
@property (nonatomic, nullable) NSPredicate *predicate;

View File

@@ -4,12 +4,12 @@
- (void)setPredicate:(NSPredicate *)predicate {
[NSException raise:@"MGLAbstractClassException"
format:@"MGLVectorLayer is an abstract class"];
format:@"MGLVectorStyleLayer is an abstract class"];
}
- (NSPredicate *)predicate {
[NSException raise:@"MGLAbstractClassException"
format:@"MGLVectorLayer is an abstract class"];
format:@"MGLVectorStyleLayer is an abstract class"];
return nil;
}

View File

@@ -1,4 +1,5 @@
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <mbgl/util/feature.hpp>
@@ -9,4 +10,18 @@
/** Returns a string resulting from inserting a separator between each attributed string in the array */
- (NSAttributedString *)mgl_attributedComponentsJoinedByString:(NSString *)separator;
/**
Converts std::vector<CLLocationCoordinate> into an NSArray containing dictionary
representations of coordinates with the following structure:
[{"latitude": lat, "longitude": lng}]
*/
+ (NSArray *)mgl_coordinatesFromCoordinates:(std::vector<CLLocationCoordinate2D>)coords;
/**
Converts the receiver into a std::vector<CLLocationCoordinate>.
Receiver must conform to the following structure:
[{"latitude": lat, "longitude": lng}]
*/
- (std::vector<CLLocationCoordinate2D>)mgl_coordinates;
@end

View File

@@ -17,9 +17,9 @@
vector.push_back(propertyMap);
} else {
NSExpression *expression = [NSExpression expressionForConstantValue:value];
vector.push_back([expression mgl_filterValue]);
vector.push_back(expression.mgl_constantMBGLValue);
}
}
}
return vector;
}
@@ -38,4 +38,28 @@
return attributedString;
}
+ (NSArray *)mgl_coordinatesFromCoordinates:(std::vector<CLLocationCoordinate2D>)coords {
NSMutableArray *coordinates = [NSMutableArray array];
for (auto coord : coords) {
[coordinates addObject:@{@"latitude": @(coord.latitude),
@"longitude": @(coord.longitude)}];
}
return coordinates;
}
- (std::vector<CLLocationCoordinate2D>)mgl_coordinates {
NSUInteger numberOfCoordinates = [self count];
CLLocationCoordinate2D *coords = (CLLocationCoordinate2D *)malloc(numberOfCoordinates * sizeof(CLLocationCoordinate2D));
for (NSUInteger i = 0; i < numberOfCoordinates; i++) {
coords[i] = CLLocationCoordinate2DMake([self[i][@"latitude"] doubleValue],
[self[i][@"longitude"] doubleValue]);
}
std::vector<CLLocationCoordinate2D> coordinates = { coords, coords + numberOfCoordinates };
free(coords);
return coordinates;
}
@end

View File

@@ -0,0 +1,16 @@
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <mbgl/util/feature.hpp>
@interface NSCoder (MGLAdditions)
- (void)encodeMGLCoordinate:(CLLocationCoordinate2D)coordinate forKey:(NSString *)key;
- (CLLocationCoordinate2D)decodeMGLCoordinateForKey:(NSString *)key;
- (void)mgl_encodeLocationCoordinates2D:(std::vector<CLLocationCoordinate2D>)coordinates forKey:(NSString *)key;
- (std::vector<CLLocationCoordinate2D>)mgl_decodeLocationCoordinates2DForKey:(NSString *)key;
@end

View File

@@ -0,0 +1,26 @@
#import "NSCoder+MGLAdditions.h"
#import "NSArray+MGLAdditions.h"
#import "NSValue+MGLAdditions.h"
@implementation NSCoder (MGLAdditions)
- (void)mgl_encodeLocationCoordinates2D:(std::vector<CLLocationCoordinate2D>)coordinates forKey:(NSString *)key {
[self encodeObject:[NSArray mgl_coordinatesFromCoordinates:coordinates] forKey:key];
}
- (std::vector<CLLocationCoordinate2D>)mgl_decodeLocationCoordinates2DForKey:(NSString *)key {
NSArray *coordinates = [self decodeObjectOfClass:[NSArray class] forKey:key];
return [coordinates mgl_coordinates];
}
- (void)encodeMGLCoordinate:(CLLocationCoordinate2D)coordinate forKey:(NSString *)key {
[self encodeObject:@{@"latitude": @(coordinate.latitude), @"longitude": @(coordinate.longitude)} forKey:key];
}
- (CLLocationCoordinate2D)decodeMGLCoordinateForKey:(NSString *)key {
NSDictionary *coordinate = [self decodeObjectForKey:key];
return CLLocationCoordinate2DMake([coordinate[@"latitude"] doubleValue], [coordinate[@"longitude"] doubleValue]);
}
@end

View File

@@ -7,95 +7,189 @@
- (mbgl::style::Filter)mgl_filter
{
NSExpression *leftExpression = self.leftExpression;
NSExpression *rightExpression = self.rightExpression;
NSExpressionType leftType = leftExpression.expressionType;
NSExpressionType rightType = rightExpression.expressionType;
BOOL isReversed = ((leftType == NSConstantValueExpressionType || leftType == NSAggregateExpressionType)
&& rightType == NSKeyPathExpressionType);
switch (self.predicateOperatorType) {
case NSEqualToPredicateOperatorType: {
if (self.rightExpression.constantValue)
{
auto filter = mbgl::style::EqualsFilter();
filter.key = self.leftExpression.keyPath.UTF8String;
filter.value = self.rightExpression.mgl_filterValue;
return filter;
}
else
{
auto filter = mbgl::style::NotHasFilter();
filter.key = self.leftExpression.keyPath.UTF8String;
return filter;
mbgl::style::EqualsFilter eqFilter;
eqFilter.key = self.mgl_keyPath.UTF8String;
eqFilter.value = self.mgl_constantValue;
// Convert == nil to NotHasFilter.
if (eqFilter.value.is<mbgl::NullValue>()) {
mbgl::style::NotHasFilter notHasFilter;
notHasFilter.key = eqFilter.key;
return notHasFilter;
}
return eqFilter;
}
case NSNotEqualToPredicateOperatorType: {
if (self.rightExpression.constantValue)
{
auto filter = mbgl::style::NotEqualsFilter();
filter.key = self.leftExpression.keyPath.UTF8String;
filter.value = self.rightExpression.mgl_filterValue;
return filter;
}
else
{
auto filter = mbgl::style::HasFilter();
filter.key = self.leftExpression.keyPath.UTF8String;
return filter;
mbgl::style::NotEqualsFilter neFilter;
neFilter.key = self.mgl_keyPath.UTF8String;
neFilter.value = self.mgl_constantValue;
// Convert != nil to HasFilter.
if (neFilter.value.is<mbgl::NullValue>()) {
mbgl::style::HasFilter hasFilter;
hasFilter.key = neFilter.key;
return hasFilter;
}
return neFilter;
}
case NSGreaterThanPredicateOperatorType: {
auto filter = mbgl::style::GreaterThanFilter();
filter.key = self.leftExpression.keyPath.UTF8String;
filter.value = self.rightExpression.mgl_filterValue;
return filter;
if (isReversed) {
mbgl::style::LessThanFilter ltFilter;
ltFilter.key = self.mgl_keyPath.UTF8String;
ltFilter.value = self.mgl_constantValue;
return ltFilter;
} else {
mbgl::style::GreaterThanFilter gtFilter;
gtFilter.key = self.mgl_keyPath.UTF8String;
gtFilter.value = self.mgl_constantValue;
return gtFilter;
}
}
case NSGreaterThanOrEqualToPredicateOperatorType: {
auto filter = mbgl::style::GreaterThanEqualsFilter();
filter.key = self.leftExpression.keyPath.UTF8String;
filter.value = self.rightExpression.mgl_filterValue;
return filter;
if (isReversed) {
mbgl::style::LessThanEqualsFilter lteFilter;
lteFilter.key = self.mgl_keyPath.UTF8String;
lteFilter.value = self.mgl_constantValue;
return lteFilter;
} else {
mbgl::style::GreaterThanEqualsFilter gteFilter;
gteFilter.key = self.mgl_keyPath.UTF8String;
gteFilter.value = self.mgl_constantValue;
return gteFilter;
}
}
case NSLessThanPredicateOperatorType: {
auto filter = mbgl::style::LessThanFilter();
filter.key = self.leftExpression.keyPath.UTF8String;
filter.value = self.rightExpression.mgl_filterValue;
return filter;
if (isReversed) {
mbgl::style::GreaterThanFilter gtFilter;
gtFilter.key = self.mgl_keyPath.UTF8String;
gtFilter.value = self.mgl_constantValue;
return gtFilter;
} else {
mbgl::style::LessThanFilter ltFilter;
ltFilter.key = self.mgl_keyPath.UTF8String;
ltFilter.value = self.mgl_constantValue;
return ltFilter;
}
}
case NSLessThanOrEqualToPredicateOperatorType: {
auto filter = mbgl::style::LessThanEqualsFilter();
filter.key = self.leftExpression.keyPath.UTF8String;
filter.value = self.rightExpression.mgl_filterValue;
return filter;
if (isReversed) {
mbgl::style::GreaterThanEqualsFilter gteFilter;
gteFilter.key = self.mgl_keyPath.UTF8String;
gteFilter.value = self.mgl_constantValue;
return gteFilter;
} else {
mbgl::style::LessThanEqualsFilter lteFilter;
lteFilter.key = self.mgl_keyPath.UTF8String;
lteFilter.value = self.mgl_constantValue;
return lteFilter;
}
}
case NSInPredicateOperatorType: {
auto filter = mbgl::style::InFilter();
filter.key = self.leftExpression.keyPath.UTF8String;
filter.values = self.rightExpression.mgl_filterValues;
return filter;
if (isReversed) {
if (leftType == NSConstantValueExpressionType && [leftExpression.constantValue isKindOfClass:[NSString class]]) {
[NSException raise:NSInvalidArgumentException
format:@"CONTAINS not supported for string comparison."];
}
[NSException raise:NSInvalidArgumentException
format:@"Predicate cannot compare values IN attribute."];
}
mbgl::style::InFilter inFilter;
inFilter.key = leftExpression.keyPath.UTF8String;
inFilter.values = rightExpression.mgl_aggregateMBGLValue;
return inFilter;
}
case NSContainsPredicateOperatorType: {
auto filter = mbgl::style::InFilter();
filter.key = [self.rightExpression.constantValue UTF8String];
filter.values = self.leftExpression.mgl_filterValues;
return filter;
if (!isReversed) {
if (rightType == NSConstantValueExpressionType && [rightExpression.constantValue isKindOfClass:[NSString class]]) {
[NSException raise:NSInvalidArgumentException
format:@"IN not supported for string comparison."];
}
[NSException raise:NSInvalidArgumentException
format:@"Predicate cannot compare attribute CONTAINS values."];
}
mbgl::style::InFilter inFilter;
inFilter.key = rightExpression.keyPath.UTF8String;
inFilter.values = leftExpression.mgl_aggregateMBGLValue;
return inFilter;
}
case NSBetweenPredicateOperatorType: {
auto filter = mbgl::style::AllFilter();
auto gteFilter = mbgl::style::GreaterThanEqualsFilter();
gteFilter.key = self.leftExpression.keyPath.UTF8String;
gteFilter.value = self.rightExpression.mgl_filterValues[0];
filter.filters.push_back(gteFilter);
auto lteFilter = mbgl::style::LessThanEqualsFilter();
lteFilter.key = self.leftExpression.keyPath.UTF8String;
lteFilter.value = self.rightExpression.mgl_filterValues[1];
filter.filters.push_back(lteFilter);
return filter;
if (isReversed) {
[NSException raise:NSInvalidArgumentException
format:@"Predicate cannot compare bounds BETWEEN attribute."];
}
if (![rightExpression.constantValue isKindOfClass:[NSArray class]]) {
[NSException raise:NSInvalidArgumentException
format:@"Right side of BETWEEN predicate must be an array."]; // not NSSet
}
auto values = rightExpression.mgl_aggregateMBGLValue;
if (values.size() != 2) {
[NSException raise:NSInvalidArgumentException
format:@"Right side of BETWEEN predicate must have two items."];
}
mbgl::style::AllFilter allFilter;
mbgl::style::GreaterThanEqualsFilter gteFilter;
gteFilter.key = leftExpression.keyPath.UTF8String;
gteFilter.value = values[0];
allFilter.filters.push_back(gteFilter);
mbgl::style::LessThanEqualsFilter lteFilter;
lteFilter.key = leftExpression.keyPath.UTF8String;
lteFilter.value = values[1];
allFilter.filters.push_back(lteFilter);
return allFilter;
}
case NSMatchesPredicateOperatorType:
case NSLikePredicateOperatorType:
case NSBeginsWithPredicateOperatorType:
case NSEndsWithPredicateOperatorType:
case NSCustomSelectorPredicateOperatorType:
[NSException raise:@"Unsupported operator type"
[NSException raise:NSInvalidArgumentException
format:@"NSPredicateOperatorType:%lu is not supported.", (unsigned long)self.predicateOperatorType];
}
return {};
}
- (NSString *)mgl_keyPath {
NSExpression *leftExpression = self.leftExpression;
NSExpression *rightExpression = self.rightExpression;
NSExpressionType leftType = leftExpression.expressionType;
NSExpressionType rightType = rightExpression.expressionType;
if (leftType == NSKeyPathExpressionType && rightType == NSConstantValueExpressionType) {
return leftExpression.keyPath;
} else if (leftType == NSConstantValueExpressionType && rightType == NSKeyPathExpressionType) {
return rightExpression.keyPath;
}
[NSException raise:NSInvalidArgumentException
format:@"Comparison predicate must compare an attribute (as a key path) to a constant or vice versa."];
return nil;
}
- (mbgl::Value)mgl_constantValue {
NSExpression *leftExpression = self.leftExpression;
NSExpression *rightExpression = self.rightExpression;
NSExpressionType leftType = leftExpression.expressionType;
NSExpressionType rightType = rightExpression.expressionType;
mbgl::Value value;
if (leftType == NSKeyPathExpressionType && rightType == NSConstantValueExpressionType) {
value = rightExpression.mgl_constantMBGLValue;
} else if (leftType == NSConstantValueExpressionType && rightType == NSKeyPathExpressionType) {
value = leftExpression.mgl_constantMBGLValue;
} else {
[NSException raise:NSInvalidArgumentException
format:@"Comparison predicate must compare an attribute (as a key path) to a constant or vice versa."];
}
return value;
}
@end

View File

@@ -18,32 +18,49 @@
{
switch (self.compoundPredicateType) {
case NSNotPredicateType: {
NSAssert(self.subpredicates.count <= 1, @"NOT predicate cannot have multiple subpredicates.");
NSPredicate *subpredicate = self.subpredicates.firstObject;
mbgl::style::Filter subfilter = subpredicate.mgl_filter;
// 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;
// Convert NOT(!= nil) to NotHasFilter.
if (subfilter.is<mbgl::style::HasFilter>()) {
auto hasFilter = subfilter.get<mbgl::style::HasFilter>();
return mbgl::style::NotHasFilter { .key = hasFilter.key };
}
// Convert NOT(== nil) to HasFilter.
if (subfilter.is<mbgl::style::NotHasFilter>()) {
auto hasFilter = subfilter.get<mbgl::style::NotHasFilter>();
return mbgl::style::HasFilter { .key = hasFilter.key };
}
// Convert NOT(IN) or NOT(CONTAINS) to NotInFilter.
if (subfilter.is<mbgl::style::InFilter>()) {
auto inFilter = subfilter.get<mbgl::style::InFilter>();
mbgl::style::NotInFilter notInFilter;
notInFilter.key = inFilter.key;
notInFilter.values = inFilter.values;
return notInFilter;
}
// Convert NOT(), NOT(AND), NOT(NOT), NOT(==), etc. into NoneFilter.
mbgl::style::NoneFilter noneFilter;
if (subfilter.is<mbgl::style::AnyFilter>()) {
// Flatten NOT(OR).
noneFilter.filters = subfilter.get<mbgl::style::AnyFilter>().filters;
} else if (subpredicate) {
noneFilter.filters = { subfilter };
}
return noneFilter;
}
case NSAndPredicateType: {
auto filter = mbgl::style::AllFilter();
filter.filters = [self mgl_subfilters];
mbgl::style::AllFilter filter;
filter.filters = self.mgl_subfilters;
return filter;
}
case NSOrPredicateType: {
auto filter = mbgl::style::AnyFilter();
filter.filters = [self mgl_subfilters];
mbgl::style::AnyFilter filter;
filter.filters = self.mgl_subfilters;
return filter;
}
}

View File

@@ -15,7 +15,7 @@
propertyMap[[key UTF8String]] = [array mgl_vector];
} else {
NSExpression *expression = [NSExpression expressionForConstantValue:self[key]];
propertyMap[[key UTF8String]] = [expression mgl_filterValue];
propertyMap[[key UTF8String]] = expression.mgl_constantMBGLValue;
}
}
return propertyMap;

View File

@@ -2,10 +2,14 @@
#include <mbgl/style/filter.hpp>
NS_ASSUME_NONNULL_BEGIN
@interface NSExpression (MGLAdditions)
- (mbgl::Value)mgl_filterValue;
- (std::vector<mbgl::Value>)mgl_filterValues;
- (mbgl::FeatureIdentifier)mgl_featureIdentifier;
@property (nonatomic, readonly) mbgl::Value mgl_constantMBGLValue;
@property (nonatomic, readonly) std::vector<mbgl::Value> mgl_aggregateMBGLValue;
@property (nonatomic, readonly) mbgl::FeatureIdentifier mgl_featureIdentifier;
@end
NS_ASSUME_NONNULL_END

View File

@@ -2,27 +2,25 @@
@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]);
- (std::vector<mbgl::Value>)mgl_aggregateMBGLValue {
if ([self.constantValue isKindOfClass:[NSArray class]] || [self.constantValue isKindOfClass:[NSSet class]]) {
std::vector<mbgl::Value> convertedValues;
for (id value in self.constantValue) {
NSExpression *expression = value;
if (![expression isKindOfClass:[NSExpression class]]) {
expression = [NSExpression expressionForConstantValue:expression];
}
convertedValues.push_back(expression.mgl_constantMBGLValue);
}
return convertedValues;
}
[NSException raise:@"Values not handled" format:@""];
return { };
[NSException raise:NSInvalidArgumentException
format:@"Constant value expression must contain an array or set."];
return {};
}
- (mbgl::Value)mgl_filterValue
{
return [self mgl_convertedValueWithValue:self.constantValue];
}
- (mbgl::Value)mgl_convertedValueWithValue:(id)value
{
- (mbgl::Value)mgl_constantMBGLValue {
id value = self.constantValue;
if ([value isKindOfClass:NSString.class]) {
return { std::string([(NSString *)value UTF8String]) };
} else if ([value isKindOfClass:NSNumber.class]) {
@@ -42,7 +40,10 @@
// We still do this conversion in order to provide a valid value.
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"One-time warning: Float values are converted to double and can introduce imprecision; please use double values explicitly in predicate arguments.");
NSLog(@"Float value in expression will be converted to a double; some imprecision may result. "
@"Use double values explicitly when specifying constant expression values and "
@"when specifying arguments to predicate and expression format strings. "
@"This will be logged only once.");
});
return { (double)number.doubleValue };
} else if ([number compare:@(0)] == NSOrderedDescending ||
@@ -55,33 +56,27 @@
// We use long long here to avoid any truncation.
return { (int64_t)number.longLongValue };
}
} else if (value && value != [NSNull null]) {
[NSException raise:NSInvalidArgumentException
format:@"Can’t convert %s:%@ to mbgl::Value", [value objCType], value];
}
[NSException raise:@"Value not handled"
format:@"Can’t convert %s:%@ to mbgl::Value", [value objCType], value];
return { };
return {};
}
- (mbgl::FeatureIdentifier)mgl_featureIdentifier
{
id value = self.constantValue;
mbgl::Value mbglValue = [self mgl_filterValue];
- (mbgl::FeatureIdentifier)mgl_featureIdentifier {
mbgl::Value mbglValue = self.mgl_constantMBGLValue;
if ([value isKindOfClass:NSString.class]) {
if (mbglValue.is<std::string>()) {
return mbglValue.get<std::string>();
} else if ([value isKindOfClass:NSNumber.class]) {
NSNumber *number = (NSNumber *)value;
if ((strcmp([number objCType], @encode(char)) == 0) ||
(strcmp([number objCType], @encode(BOOL)) == 0)) {
return uint64_t(mbglValue.get<bool>());
} else if ( strcmp([number objCType], @encode(double)) == 0 ||
strcmp([number objCType], @encode(float)) == 0) {
return mbglValue.get<double>();
} else if ([number compare:@(0)] == NSOrderedDescending ||
[number compare:@(0)] == NSOrderedSame) {
return mbglValue.get<uint64_t>();
} else if ([number compare:@(0)] == NSOrderedAscending) {
return mbglValue.get<int64_t>();
}
}
if (mbglValue.is<double>()) {
return mbglValue.get<double>();
}
if (mbglValue.is<uint64_t>()) {
return mbglValue.get<uint64_t>();
}
if (mbglValue.is<int64_t>()) {
return mbglValue.get<int64_t>();
}
return {};

View File

@@ -5,7 +5,7 @@
class FilterEvaluator {
public:
NSArray* getPredicates(std::vector<mbgl::style::Filter> filters) {
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())];
@@ -13,73 +13,118 @@ public:
return predicates;
}
NSArray* getValues(std::vector<mbgl::Value> values) {
NSExpression *getValues(std::vector<mbgl::Value> values) {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:values.size()];
for (auto value : values) {
[array addObject:mbgl::Value::visit(value, ValueEvaluator())];
id constantValue = mbgl::Value::visit(value, ValueEvaluator());
[array addObject:[NSExpression expressionForConstantValue:constantValue]];
}
return array;
return [NSExpression expressionForAggregate:array];
}
NSPredicate* operator()(mbgl::style::NullFilter filter) {
NSPredicate *operator()(mbgl::style::NullFilter filter) {
return nil;
}
NSPredicate* operator()(mbgl::style::EqualsFilter filter) {
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) {
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) {
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) {
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) {
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) {
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) {
NSPredicate *operator()(mbgl::style::InFilter filter) {
return [NSPredicate predicateWithFormat:@"%K IN %@", @(filter.key.c_str()), getValues(filter.values)];
}
NSPredicate* operator()(mbgl::style::NotInFilter filter) {
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::AnyFilter filter) {
NSArray *subpredicates = getPredicates(filter.filters);
if (subpredicates.count) {
return [NSCompoundPredicate orPredicateWithSubpredicates:subpredicates];
}
return [NSPredicate predicateWithValue:NO];
}
NSPredicate* operator()(mbgl::style::AllFilter filter) {
return [NSCompoundPredicate andPredicateWithSubpredicates:getPredicates(filter.filters)];
NSPredicate *operator()(mbgl::style::AllFilter filter) {
// Convert [all, [>=, key, lower], [<=, key, upper]] to key BETWEEN {lower, upper}
if (filter.filters.size() == 2) {
auto leftFilter = filter.filters[0];
auto rightFilter = filter.filters[1];
std::string lowerKey;
std::string upperKey;
mbgl::Value lowerBound;
mbgl::Value upperBound;
if (leftFilter.is<mbgl::style::GreaterThanEqualsFilter>()) {
lowerKey = leftFilter.get<mbgl::style::GreaterThanEqualsFilter>().key;
lowerBound = leftFilter.get<mbgl::style::GreaterThanEqualsFilter>().value;
} else if (rightFilter.is<mbgl::style::GreaterThanEqualsFilter>()) {
lowerKey = rightFilter.get<mbgl::style::GreaterThanEqualsFilter>().key;
lowerBound = rightFilter.get<mbgl::style::GreaterThanEqualsFilter>().value;
}
if (leftFilter.is<mbgl::style::LessThanEqualsFilter>()) {
upperKey = leftFilter.get<mbgl::style::LessThanEqualsFilter>().key;
upperBound = leftFilter.get<mbgl::style::LessThanEqualsFilter>().value;
} else if (rightFilter.is<mbgl::style::LessThanEqualsFilter>()) {
upperKey = rightFilter.get<mbgl::style::LessThanEqualsFilter>().key;
upperBound = rightFilter.get<mbgl::style::LessThanEqualsFilter>().value;
}
if (!lowerBound.is<mbgl::NullValue>() && !upperBound.is<mbgl::NullValue>()
&& lowerKey == upperKey) {
return [NSPredicate predicateWithFormat:@"%K BETWEEN {%@, %@}",
@(lowerKey.c_str()),
mbgl::Value::visit(lowerBound, ValueEvaluator()),
mbgl::Value::visit(upperBound, ValueEvaluator())];
}
}
NSArray *subpredicates = getPredicates(filter.filters);
if (subpredicates.count) {
return [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
}
return [NSPredicate predicateWithValue:YES];
}
NSPredicate* operator()(mbgl::style::NoneFilter filter) {
NSArray *predicates = getPredicates(filter.filters);
if (predicates.count > 1) {
NSCompoundPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
NSPredicate *operator()(mbgl::style::NoneFilter filter) {
NSArray *subpredicates = getPredicates(filter.filters);
if (subpredicates.count > 1) {
NSCompoundPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subpredicates];
return [NSCompoundPredicate notPredicateWithSubpredicate:predicate];
} else if (subpredicates.count) {
return [NSCompoundPredicate notPredicateWithSubpredicate:subpredicates.firstObject];
} else {
return [NSCompoundPredicate notPredicateWithSubpredicate:predicates.firstObject];
return [NSPredicate predicateWithValue:YES];
}
}
NSPredicate* operator()(mbgl::style::HasFilter filter) {
NSPredicate *operator()(mbgl::style::HasFilter filter) {
return [NSPredicate predicateWithFormat:@"%K != nil", @(filter.key.c_str())];
}
NSPredicate* operator()(mbgl::style::NotHasFilter filter) {
NSPredicate *operator()(mbgl::style::NotHasFilter filter) {
return [NSPredicate predicateWithFormat:@"%K == nil", @(filter.key.c_str())];
}
@@ -91,18 +136,22 @@ public:
{
if ([self isEqual:[NSPredicate predicateWithValue:YES]])
{
auto filter = mbgl::style::AllFilter();
return filter;
return mbgl::style::AllFilter();
}
if ([self isEqual:[NSPredicate predicateWithValue:NO]])
{
auto filter = mbgl::style::AnyFilter();
return filter;
return mbgl::style::AnyFilter();
}
[NSException raise:@"Not supported"
format:@"Try with NSComparisonPredicate or NSCompoundPredicate instead."];
if ([self.predicateFormat hasPrefix:@"BLOCKPREDICATE("])
{
[NSException raise:NSInvalidArgumentException
format:@"Block-based predicates are not supported."];
}
[NSException raise:NSInvalidArgumentException
format:@"Unrecognized predicate type."];
return {};
}

View File

@@ -10,6 +10,15 @@ NS_ASSUME_NONNULL_BEGIN
/** Returns the receiver if non-empty or nil if empty. */
- (nullable NSString *)mgl_stringOrNilIfEmpty;
/**
Returns a title-cased representation of the receiver using the specified
locale.
@param The locale. For strings presented to users, pass in the current locale
(`+[NSLocale currentLocale]`). To use the system locale, pass in `nil`.
*/
- (NSString *)mgl_titleCasedStringWithLocale:(NSLocale *)locale;
@end
@interface NSAttributedString (MGLAdditions)

View File

@@ -10,6 +10,28 @@
return self.length ? self : nil;
}
- (NSString *)mgl_titleCasedStringWithLocale:(NSLocale *)locale {
NSMutableString *string = self.mutableCopy;
[string enumerateLinguisticTagsInRange:string.mgl_wholeRange scheme:NSLinguisticTagSchemeLexicalClass options:0 orthography:nil usingBlock:^(NSString * _Nonnull tag, NSRange tokenRange, NSRange sentenceRange, BOOL * _Nonnull stop) {
NSString *word = [string substringWithRange:tokenRange];
if (word.length > 3
|| !([tag isEqualToString:NSLinguisticTagConjunction]
|| [tag isEqualToString:NSLinguisticTagPreposition]
|| [tag isEqualToString:NSLinguisticTagDeterminer]
|| [tag isEqualToString:NSLinguisticTagParticle]
|| [tag isEqualToString:NSLinguisticTagClassifier])) {
unichar firstLetter = [[word capitalizedStringWithLocale:locale] characterAtIndex:0];
NSString *suffix = [word substringFromIndex:1];
if (!([word hasPrefix:@"i"] && suffix.length
&& [[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:[suffix characterAtIndex:0]])) {
word = [NSString stringWithFormat:@"%C%@", firstLetter, suffix];
}
}
[string replaceCharactersInRange:tokenRange withString:word];
}];
return string;
}
@end
@implementation NSAttributedString (MGLAdditions)

View File

@@ -12,6 +12,11 @@
+ (instancetype)mgl_valueWithOffsetArray:(std::array<float, 2>)offsetArray
{
CGVector vector = CGVectorMake(offsetArray[0], offsetArray[1]);
#if !TARGET_OS_IPHONE
// Style specification assumes an origin at the upper-left corner.
// macOS defines an origin at the lower-left corner.
vector.dy *= -1;
#endif
return [NSValue value:&vector withObjCType:@encode(CGVector)];
}
@@ -33,6 +38,9 @@
NSAssert(strcmp(self.objCType, @encode(CGVector)) == 0, @"Value does not represent a CGVector");
CGVector vector;
[self getValue:&vector];
#if !TARGET_OS_IPHONE
vector.dy *= -1;
#endif
return {
static_cast<float>(vector.dx),
static_cast<float>(vector.dy),

View File

@@ -1,232 +0,0 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import <Foundation/Foundation.h>
#import "MGLFillStyleLayer.h"
#import "MGLLineStyleLayer.h"
#import "MGLSymbolStyleLayer.h"
#import "MGLCircleStyleLayer.h"
#import "MGLRasterStyleLayer.h"
#import "MGLBackgroundStyleLayer.h"
NS_ASSUME_NONNULL_BEGIN
/**
Methods for round-tripping values for Mapbox style layer enumeration values.
*/
@interface NSValue (MGLStyleEnumAttributeAdditions)
#pragma mark Working with Style Layer Enumeration Attribute Values
/**
Creates a new value object containing the given `MGLLineCap` enumeration.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLLineCap:(MGLLineCap)lineCap;
/**
The `MGLLineCap` enumeration representation of the value.
*/
@property (readonly) MGLLineCap MGLLineCapValue;
/**
Creates a new value object containing the given `MGLLineJoin` enumeration.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLLineJoin:(MGLLineJoin)lineJoin;
/**
The `MGLLineJoin` enumeration representation of the value.
*/
@property (readonly) MGLLineJoin MGLLineJoinValue;
/**
Creates a new value object containing the given `MGLIconRotationAlignment` enumeration.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLIconRotationAlignment:(MGLIconRotationAlignment)iconRotationAlignment;
/**
The `MGLIconRotationAlignment` enumeration representation of the value.
*/
@property (readonly) MGLIconRotationAlignment MGLIconRotationAlignmentValue;
/**
Creates a new value object containing the given `MGLIconTextFit` enumeration.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLIconTextFit:(MGLIconTextFit)iconTextFit;
/**
The `MGLIconTextFit` enumeration representation of the value.
*/
@property (readonly) MGLIconTextFit MGLIconTextFitValue;
/**
Creates a new value object containing the given `MGLSymbolPlacement` enumeration.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLSymbolPlacement:(MGLSymbolPlacement)symbolPlacement;
/**
The `MGLSymbolPlacement` enumeration representation of the value.
*/
@property (readonly) MGLSymbolPlacement MGLSymbolPlacementValue;
/**
Creates a new value object containing the given `MGLTextAnchor` enumeration.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLTextAnchor:(MGLTextAnchor)textAnchor;
/**
The `MGLTextAnchor` enumeration representation of the value.
*/
@property (readonly) MGLTextAnchor MGLTextAnchorValue;
/**
Creates a new value object containing the given `MGLTextJustification` enumeration.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLTextJustification:(MGLTextJustification)textJustification;
/**
The `MGLTextJustification` enumeration representation of the value.
*/
@property (readonly) MGLTextJustification MGLTextJustificationValue;
/**
Creates a new value object containing the given `MGLTextPitchAlignment` enumeration.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLTextPitchAlignment:(MGLTextPitchAlignment)textPitchAlignment;
/**
The `MGLTextPitchAlignment` enumeration representation of the value.
*/
@property (readonly) MGLTextPitchAlignment MGLTextPitchAlignmentValue;
/**
Creates a new value object containing the given `MGLTextRotationAlignment` enumeration.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLTextRotationAlignment:(MGLTextRotationAlignment)textRotationAlignment;
/**
The `MGLTextRotationAlignment` enumeration representation of the value.
*/
@property (readonly) MGLTextRotationAlignment MGLTextRotationAlignmentValue;
/**
Creates a new value object containing the given `MGLTextTransform` enumeration.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLTextTransform:(MGLTextTransform)textTransform;
/**
The `MGLTextTransform` enumeration representation of the value.
*/
@property (readonly) MGLTextTransform MGLTextTransformValue;
/**
Creates a new value object containing the given `MGLFillTranslateAnchor` structure.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLFillTranslateAnchor:(MGLFillTranslateAnchor)fillTranslateAnchor;
/**
The `MGLFillTranslateAnchor` enumeration representation of the value.
*/
@property (readonly) MGLFillTranslateAnchor MGLFillTranslateAnchorValue;
/**
Creates a new value object containing the given `MGLLineTranslateAnchor` structure.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLLineTranslateAnchor:(MGLLineTranslateAnchor)lineTranslateAnchor;
/**
The `MGLLineTranslateAnchor` enumeration representation of the value.
*/
@property (readonly) MGLLineTranslateAnchor MGLLineTranslateAnchorValue;
/**
Creates a new value object containing the given `MGLIconTranslateAnchor` structure.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLIconTranslateAnchor:(MGLIconTranslateAnchor)iconTranslateAnchor;
/**
The `MGLIconTranslateAnchor` enumeration representation of the value.
*/
@property (readonly) MGLIconTranslateAnchor MGLIconTranslateAnchorValue;
/**
Creates a new value object containing the given `MGLTextTranslateAnchor` structure.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLTextTranslateAnchor:(MGLTextTranslateAnchor)textTranslateAnchor;
/**
The `MGLTextTranslateAnchor` enumeration representation of the value.
*/
@property (readonly) MGLTextTranslateAnchor MGLTextTranslateAnchorValue;
/**
Creates a new value object containing the given `MGLCirclePitchScale` structure.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLCirclePitchScale:(MGLCirclePitchScale)circlePitchScale;
/**
The `MGLCirclePitchScale` enumeration representation of the value.
*/
@property (readonly) MGLCirclePitchScale MGLCirclePitchScaleValue;
/**
Creates a new value object containing the given `MGLCircleTranslateAnchor` structure.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGLCircleTranslateAnchor:(MGLCircleTranslateAnchor)circleTranslateAnchor;
/**
The `MGLCircleTranslateAnchor` enumeration representation of the value.
*/
@property (readonly) MGLCircleTranslateAnchor MGLCircleTranslateAnchorValue;
@end
NS_ASSUME_NONNULL_END

View File

@@ -1,66 +0,0 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
<%
const types = locals.types;
const layoutProperties = locals.layoutProperties;
const paintProperties = locals.paintProperties;
-%>
#import <Foundation/Foundation.h>
<% if (types) { -%>
<% for (const type of types) { -%>
#import "MGL<%- camelize(type) %>StyleLayer.h"
<% } -%>
<% } -%>
NS_ASSUME_NONNULL_BEGIN
/**
Methods for round-tripping values for Mapbox style layer enumeration values.
*/
@interface NSValue (MGLStyleEnumAttributeAdditions)
#pragma mark Working with Style Layer Enumeration Attribute Values
<% if (layoutProperties.length) { -%>
<% for (const property of layoutProperties) { -%>
<% if (property.type == "enum") { -%>
/**
Creates a new value object containing the given `MGL<%- camelize(property.name) %>` enumeration.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGL<%- camelize(property.name) %>:(MGL<%- camelize(property.name) %>)<%- objCName(property) %>;
/**
The `MGL<%- camelize(property.name) %>` enumeration representation of the value.
*/
@property (readonly) MGL<%- camelize(property.name) %> MGL<%- camelize(property.name) %>Value;
<% } -%>
<% } -%>
<% } -%>
<% if (paintProperties.length) { -%>
<% for (const property of paintProperties) { -%>
<% if (property.type == "enum") { -%>
/**
Creates a new value object containing the given `MGL<%- camelize(property.name) %>` structure.
@param type The value for the new object.
@return A new value object that contains the style enumeration type.
*/
+ (instancetype)valueWithMGL<%- camelize(property.name) %>:(MGL<%- camelize(property.name) %>)<%- objCName(property) %>;
/**
The `MGL<%- camelize(property.name) %>` enumeration representation of the value.
*/
@property (readonly) MGL<%- camelize(property.name) %> MGL<%- camelize(property.name) %>Value;
<% } -%>
<% } -%>
<% } -%>
@end
NS_ASSUME_NONNULL_END

View File

@@ -1,169 +0,0 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "NSValue+MGLStyleEnumAttributeAdditions.h"
@implementation NSValue (MGLStyleEnumAttributeAdditions)
+ (NSValue *)valueWithMGLLineCap:(MGLLineCap)lineCap {
return [NSValue value:&lineCap withObjCType:@encode(MGLLineCap)];
}
- (MGLLineCap)MGLLineCapValue {
MGLLineCap value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLLineJoin:(MGLLineJoin)lineJoin {
return [NSValue value:&lineJoin withObjCType:@encode(MGLLineJoin)];
}
- (MGLLineJoin)MGLLineJoinValue {
MGLLineJoin value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLIconRotationAlignment:(MGLIconRotationAlignment)iconRotationAlignment {
return [NSValue value:&iconRotationAlignment withObjCType:@encode(MGLIconRotationAlignment)];
}
- (MGLIconRotationAlignment)MGLIconRotationAlignmentValue {
MGLIconRotationAlignment value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLIconTextFit:(MGLIconTextFit)iconTextFit {
return [NSValue value:&iconTextFit withObjCType:@encode(MGLIconTextFit)];
}
- (MGLIconTextFit)MGLIconTextFitValue {
MGLIconTextFit value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLSymbolPlacement:(MGLSymbolPlacement)symbolPlacement {
return [NSValue value:&symbolPlacement withObjCType:@encode(MGLSymbolPlacement)];
}
- (MGLSymbolPlacement)MGLSymbolPlacementValue {
MGLSymbolPlacement value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLTextAnchor:(MGLTextAnchor)textAnchor {
return [NSValue value:&textAnchor withObjCType:@encode(MGLTextAnchor)];
}
- (MGLTextAnchor)MGLTextAnchorValue {
MGLTextAnchor value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLTextJustification:(MGLTextJustification)textJustification {
return [NSValue value:&textJustification withObjCType:@encode(MGLTextJustification)];
}
- (MGLTextJustification)MGLTextJustificationValue {
MGLTextJustification value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLTextPitchAlignment:(MGLTextPitchAlignment)textPitchAlignment {
return [NSValue value:&textPitchAlignment withObjCType:@encode(MGLTextPitchAlignment)];
}
- (MGLTextPitchAlignment)MGLTextPitchAlignmentValue {
MGLTextPitchAlignment value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLTextRotationAlignment:(MGLTextRotationAlignment)textRotationAlignment {
return [NSValue value:&textRotationAlignment withObjCType:@encode(MGLTextRotationAlignment)];
}
- (MGLTextRotationAlignment)MGLTextRotationAlignmentValue {
MGLTextRotationAlignment value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLTextTransform:(MGLTextTransform)textTransform {
return [NSValue value:&textTransform withObjCType:@encode(MGLTextTransform)];
}
- (MGLTextTransform)MGLTextTransformValue {
MGLTextTransform value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLFillTranslateAnchor:(MGLFillTranslateAnchor)fillTranslateAnchor {
return [NSValue value:&fillTranslateAnchor withObjCType:@encode(MGLFillTranslateAnchor)];
}
- (MGLFillTranslateAnchor)MGLFillTranslateAnchorValue {
MGLFillTranslateAnchor value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLLineTranslateAnchor:(MGLLineTranslateAnchor)lineTranslateAnchor {
return [NSValue value:&lineTranslateAnchor withObjCType:@encode(MGLLineTranslateAnchor)];
}
- (MGLLineTranslateAnchor)MGLLineTranslateAnchorValue {
MGLLineTranslateAnchor value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLIconTranslateAnchor:(MGLIconTranslateAnchor)iconTranslateAnchor {
return [NSValue value:&iconTranslateAnchor withObjCType:@encode(MGLIconTranslateAnchor)];
}
- (MGLIconTranslateAnchor)MGLIconTranslateAnchorValue {
MGLIconTranslateAnchor value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLTextTranslateAnchor:(MGLTextTranslateAnchor)textTranslateAnchor {
return [NSValue value:&textTranslateAnchor withObjCType:@encode(MGLTextTranslateAnchor)];
}
- (MGLTextTranslateAnchor)MGLTextTranslateAnchorValue {
MGLTextTranslateAnchor value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLCirclePitchScale:(MGLCirclePitchScale)circlePitchScale {
return [NSValue value:&circlePitchScale withObjCType:@encode(MGLCirclePitchScale)];
}
- (MGLCirclePitchScale)MGLCirclePitchScaleValue {
MGLCirclePitchScale value;
[self getValue:&value];
return value;
}
+ (NSValue *)valueWithMGLCircleTranslateAnchor:(MGLCircleTranslateAnchor)circleTranslateAnchor {
return [NSValue value:&circleTranslateAnchor withObjCType:@encode(MGLCircleTranslateAnchor)];
}
- (MGLCircleTranslateAnchor)MGLCircleTranslateAnchorValue {
MGLCircleTranslateAnchor value;
[self getValue:&value];
return value;
}
@end

View File

@@ -1,46 +0,0 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
<%
const type = locals.type;
const layoutProperties = locals.layoutProperties;
const paintProperties = locals.paintProperties;
-%>
#import "NSValue+MGLStyleEnumAttributeAdditions.h"
@implementation NSValue (MGLStyleEnumAttributeAdditions)
<% if (layoutProperties.length) { -%>
<% for (const property of layoutProperties) { -%>
<% if (property.type == "enum") { -%>
+ (NSValue *)valueWithMGL<%- camelize(property.name) %>:(MGL<%- camelize(property.name) %>)<%- objCName(property) %> {
return [NSValue value:&<%- objCName(property) %> withObjCType:@encode(MGL<%- camelize(property.name) %>)];
}
- (MGL<%- camelize(property.name) %>)MGL<%- camelize(property.name) %>Value {
MGL<%- camelize(property.name) %> value;
[self getValue:&value];
return value;
}
<% } -%>
<% } -%>
<% } -%>
<% if (paintProperties.length) { -%>
<% for (const property of paintProperties) { -%>
<% if (property.type == "enum") { -%>
+ (NSValue *)valueWithMGL<%- camelize(property.name) %>:(MGL<%- camelize(property.name) %>)<%- objCName(property) %> {
return [NSValue value:&<%- objCName(property) %> withObjCType:@encode(MGL<%- camelize(property.name) %>)];
}
- (MGL<%- camelize(property.name) %>)MGL<%- camelize(property.name) %>Value {
MGL<%- camelize(property.name) %> value;
[self getValue:&value];
return value;
}
<% } -%>
<% } -%>
<% } -%>
@end

View File

@@ -1,44 +0,0 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLStyleLayerTests.h"
@interface MGLBackgroundLayerTests : MGLStyleLayerTests
@end
@implementation MGLBackgroundLayerTests
+ (NSString *)layerType {
return @"background";
}
- (void)testBackgroundLayer {
MGLBackgroundStyleLayer *layer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"layerID"];
[self.mapView.style addLayer:layer];
layer.backgroundColor = [MGLRuntimeStylingHelper testColor];
layer.backgroundOpacity = [MGLRuntimeStylingHelper testNumber];
layer.backgroundPattern = [MGLRuntimeStylingHelper testString];
MGLBackgroundStyleLayer *gLayer = (MGLBackgroundStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"];
XCTAssertTrue([gLayer isKindOfClass:[MGLBackgroundStyleLayer class]]);
XCTAssertEqualObjects(gLayer.backgroundColor, [MGLRuntimeStylingHelper testColor]);
XCTAssertEqualObjects(gLayer.backgroundOpacity, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.backgroundPattern, [MGLRuntimeStylingHelper testString]);
layer.backgroundColor = [MGLRuntimeStylingHelper testColorFunction];
layer.backgroundOpacity = [MGLRuntimeStylingHelper testNumberFunction];
layer.backgroundPattern = [MGLRuntimeStylingHelper testStringFunction];
XCTAssertEqualObjects(gLayer.backgroundColor, [MGLRuntimeStylingHelper testColorFunction]);
XCTAssertEqualObjects(gLayer.backgroundOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.backgroundPattern, [MGLRuntimeStylingHelper testStringFunction]);
}
- (void)testPropertyNames {
[self testPropertyName:@"background-color" isBoolean:NO];
[self testPropertyName:@"background-opacity" isBoolean:NO];
[self testPropertyName:@"background-pattern" isBoolean:NO];
}
@end

View File

@@ -0,0 +1,134 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLStyleLayerTests.h"
#import "MGLStyleLayer_Private.h"
#include <mbgl/style/layers/background_layer.hpp>
@interface MGLBackgroundLayerTests : MGLStyleLayerTests
@end
@implementation MGLBackgroundLayerTests
+ (NSString *)layerType {
return @"background";
}
- (void)testProperties {
MGLBackgroundStyleLayer *layer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"layerID"];
XCTAssertNotEqual(layer.rawLayer, nullptr);
XCTAssertTrue(layer.rawLayer->is<mbgl::style::BackgroundLayer>());
auto rawLayer = layer.rawLayer->as<mbgl::style::BackgroundLayer>();
// background-color
{
XCTAssertTrue(rawLayer->getBackgroundColor().isUndefined(),
@"background-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.backgroundColor;
MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
layer.backgroundColor = styleValue;
mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getBackgroundColor(), propertyValue,
@"Setting backgroundColor to a constant value should update background-color.");
XCTAssertEqualObjects(layer.backgroundColor, styleValue,
@"backgroundColor should round-trip constant values.");
styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
@18: styleValue,
}];
layer.backgroundColor = styleValue;
propertyValue = { mbgl::style::Function<mbgl::Color> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getBackgroundColor(), propertyValue,
@"Setting backgroundColor to a function should update background-color.");
XCTAssertEqualObjects(layer.backgroundColor, styleValue,
@"backgroundColor should round-trip functions.");
layer.backgroundColor = nil;
XCTAssertTrue(rawLayer->getBackgroundColor().isUndefined(),
@"Unsetting backgroundColor should return background-color to the default value.");
XCTAssertEqualObjects(layer.backgroundColor, defaultStyleValue,
@"backgroundColor should return the default value after being unset.");
}
// background-opacity
{
XCTAssertTrue(rawLayer->getBackgroundOpacity().isUndefined(),
@"background-opacity should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.backgroundOpacity;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.backgroundOpacity = styleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getBackgroundOpacity(), propertyValue,
@"Setting backgroundOpacity to a constant value should update background-opacity.");
XCTAssertEqualObjects(layer.backgroundOpacity, styleValue,
@"backgroundOpacity should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.backgroundOpacity = styleValue;
propertyValue = { mbgl::style::Function<float> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getBackgroundOpacity(), propertyValue,
@"Setting backgroundOpacity to a function should update background-opacity.");
XCTAssertEqualObjects(layer.backgroundOpacity, styleValue,
@"backgroundOpacity should round-trip functions.");
layer.backgroundOpacity = nil;
XCTAssertTrue(rawLayer->getBackgroundOpacity().isUndefined(),
@"Unsetting backgroundOpacity should return background-opacity to the default value.");
XCTAssertEqualObjects(layer.backgroundOpacity, defaultStyleValue,
@"backgroundOpacity should return the default value after being unset.");
}
// background-pattern
{
XCTAssertTrue(rawLayer->getBackgroundPattern().isUndefined(),
@"background-pattern should be unset initially.");
MGLStyleValue<NSString *> *defaultStyleValue = layer.backgroundPattern;
MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Background Pattern"];
layer.backgroundPattern = styleValue;
mbgl::style::PropertyValue<std::string> propertyValue = { "Background Pattern" };
XCTAssertEqual(rawLayer->getBackgroundPattern(), propertyValue,
@"Setting backgroundPattern to a constant value should update background-pattern.");
XCTAssertEqualObjects(layer.backgroundPattern, styleValue,
@"backgroundPattern should round-trip constant values.");
styleValue = [MGLStyleValue<NSString *> valueWithStops:@{
@18: styleValue,
}];
layer.backgroundPattern = styleValue;
propertyValue = { mbgl::style::Function<std::string> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getBackgroundPattern(), propertyValue,
@"Setting backgroundPattern to a function should update background-pattern.");
XCTAssertEqualObjects(layer.backgroundPattern, styleValue,
@"backgroundPattern should round-trip functions.");
layer.backgroundPattern = nil;
XCTAssertTrue(rawLayer->getBackgroundPattern().isUndefined(),
@"Unsetting backgroundPattern should return background-pattern to the default value.");
XCTAssertEqualObjects(layer.backgroundPattern, defaultStyleValue,
@"backgroundPattern should return the default value after being unset.");
}
}
- (void)testPropertyNames {
[self testPropertyName:@"background-color" isBoolean:NO];
[self testPropertyName:@"background-opacity" isBoolean:NO];
[self testPropertyName:@"background-pattern" isBoolean:NO];
}
@end

View File

@@ -1,85 +0,0 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLStyleLayerTests.h"
@interface MGLCircleLayerTests : MGLStyleLayerTests
@end
@implementation MGLCircleLayerTests
+ (NSString *)layerType {
return @"circle";
}
- (void)testCircleLayer {
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
NSURL *url = [NSURL fileURLWithPath:filePath];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
[self.mapView.style addSource:source];
MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
[self.mapView.style addLayer:layer];
layer.circleBlur = [MGLRuntimeStylingHelper testNumber];
layer.circleColor = [MGLRuntimeStylingHelper testColor];
layer.circleOpacity = [MGLRuntimeStylingHelper testNumber];
layer.circlePitchScale = [MGLRuntimeStylingHelper testEnum:MGLCirclePitchScaleViewport type:@encode(MGLCirclePitchScale)];
layer.circleRadius = [MGLRuntimeStylingHelper testNumber];
layer.circleStrokeColor = [MGLRuntimeStylingHelper testColor];
layer.circleStrokeOpacity = [MGLRuntimeStylingHelper testNumber];
layer.circleStrokeWidth = [MGLRuntimeStylingHelper testNumber];
layer.circleTranslate = [MGLRuntimeStylingHelper testOffset];
layer.circleTranslateAnchor = [MGLRuntimeStylingHelper testEnum:MGLCircleTranslateAnchorViewport type:@encode(MGLCircleTranslateAnchor)];
MGLCircleStyleLayer *gLayer = (MGLCircleStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"];
XCTAssertTrue([gLayer isKindOfClass:[MGLCircleStyleLayer class]]);
XCTAssertEqualObjects(gLayer.circleBlur, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.circleColor, [MGLRuntimeStylingHelper testColor]);
XCTAssertEqualObjects(gLayer.circleOpacity, [MGLRuntimeStylingHelper testNumber]);
XCTAssert([gLayer.circlePitchScale isKindOfClass:[MGLStyleConstantValue class]]);
XCTAssertEqualObjects(gLayer.circlePitchScale, [MGLRuntimeStylingHelper testEnum:MGLCirclePitchScaleViewport type:@encode(MGLCirclePitchScale)]);
XCTAssertEqualObjects(gLayer.circleRadius, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.circleStrokeColor, [MGLRuntimeStylingHelper testColor]);
XCTAssertEqualObjects(gLayer.circleStrokeOpacity, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.circleStrokeWidth, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.circleTranslate, [MGLRuntimeStylingHelper testOffset]);
XCTAssert([gLayer.circleTranslateAnchor isKindOfClass:[MGLStyleConstantValue class]]);
XCTAssertEqualObjects(gLayer.circleTranslateAnchor, [MGLRuntimeStylingHelper testEnum:MGLCircleTranslateAnchorViewport type:@encode(MGLCircleTranslateAnchor)]);
layer.circleBlur = [MGLRuntimeStylingHelper testNumberFunction];
layer.circleColor = [MGLRuntimeStylingHelper testColorFunction];
layer.circleOpacity = [MGLRuntimeStylingHelper testNumberFunction];
layer.circlePitchScale = [MGLRuntimeStylingHelper testEnumFunction:MGLCirclePitchScaleViewport type:@encode(MGLCirclePitchScale)];
layer.circleRadius = [MGLRuntimeStylingHelper testNumberFunction];
layer.circleStrokeColor = [MGLRuntimeStylingHelper testColorFunction];
layer.circleStrokeOpacity = [MGLRuntimeStylingHelper testNumberFunction];
layer.circleStrokeWidth = [MGLRuntimeStylingHelper testNumberFunction];
layer.circleTranslate = [MGLRuntimeStylingHelper testOffsetFunction];
layer.circleTranslateAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLCircleTranslateAnchorViewport type:@encode(MGLCircleTranslateAnchor)];
XCTAssertEqualObjects(gLayer.circleBlur, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.circleColor, [MGLRuntimeStylingHelper testColorFunction]);
XCTAssertEqualObjects(gLayer.circleOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.circlePitchScale, [MGLRuntimeStylingHelper testEnumFunction:MGLCirclePitchScaleViewport type:@encode(MGLCirclePitchScale)]);
XCTAssertEqualObjects(gLayer.circleRadius, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.circleStrokeColor, [MGLRuntimeStylingHelper testColorFunction]);
XCTAssertEqualObjects(gLayer.circleStrokeOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.circleStrokeWidth, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.circleTranslate, [MGLRuntimeStylingHelper testOffsetFunction]);
XCTAssertEqualObjects(gLayer.circleTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLCircleTranslateAnchorViewport type:@encode(MGLCircleTranslateAnchor)]);
}
- (void)testPropertyNames {
[self testPropertyName:@"circle-blur" isBoolean:NO];
[self testPropertyName:@"circle-color" isBoolean:NO];
[self testPropertyName:@"circle-opacity" isBoolean:NO];
[self testPropertyName:@"circle-pitch-scale" isBoolean:NO];
[self testPropertyName:@"circle-radius" isBoolean:NO];
[self testPropertyName:@"circle-stroke-color" isBoolean:NO];
[self testPropertyName:@"circle-stroke-opacity" isBoolean:NO];
[self testPropertyName:@"circle-stroke-width" isBoolean:NO];
[self testPropertyName:@"circle-translate" isBoolean:NO];
[self testPropertyName:@"circle-translate-anchor" isBoolean:NO];
}
@end

View File

@@ -0,0 +1,413 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLStyleLayerTests.h"
#import "MGLStyleLayer_Private.h"
#include <mbgl/style/layers/circle_layer.hpp>
@interface MGLCircleLayerTests : MGLStyleLayerTests
@end
@implementation MGLCircleLayerTests
+ (NSString *)layerType {
return @"circle";
}
- (void)testPredicates {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
XCTAssertNil(layer.sourceLayerIdentifier);
layer.sourceLayerIdentifier = @"layerID";
XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
layer.sourceLayerIdentifier = nil;
XCTAssertNil(layer.sourceLayerIdentifier);
XCTAssertNil(layer.predicate);
layer.predicate = [NSPredicate predicateWithValue:NO];
XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
layer.predicate = nil;
XCTAssertNil(layer.predicate);
}
- (void)testProperties {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
XCTAssertNotEqual(layer.rawLayer, nullptr);
XCTAssertTrue(layer.rawLayer->is<mbgl::style::CircleLayer>());
auto rawLayer = layer.rawLayer->as<mbgl::style::CircleLayer>();
// circle-blur
{
XCTAssertTrue(rawLayer->getCircleBlur().isUndefined(),
@"circle-blur should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleBlur;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.circleBlur = styleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
@"Setting circleBlur to a constant value should update circle-blur.");
XCTAssertEqualObjects(layer.circleBlur, styleValue,
@"circleBlur should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.circleBlur = styleValue;
propertyValue = { mbgl::style::Function<float> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
@"Setting circleBlur to a function should update circle-blur.");
XCTAssertEqualObjects(layer.circleBlur, styleValue,
@"circleBlur should round-trip functions.");
layer.circleBlur = nil;
XCTAssertTrue(rawLayer->getCircleBlur().isUndefined(),
@"Unsetting circleBlur should return circle-blur to the default value.");
XCTAssertEqualObjects(layer.circleBlur, defaultStyleValue,
@"circleBlur should return the default value after being unset.");
}
// circle-color
{
XCTAssertTrue(rawLayer->getCircleColor().isUndefined(),
@"circle-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.circleColor;
MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
layer.circleColor = styleValue;
mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
@"Setting circleColor to a constant value should update circle-color.");
XCTAssertEqualObjects(layer.circleColor, styleValue,
@"circleColor should round-trip constant values.");
styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
@18: styleValue,
}];
layer.circleColor = styleValue;
propertyValue = { mbgl::style::Function<mbgl::Color> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
@"Setting circleColor to a function should update circle-color.");
XCTAssertEqualObjects(layer.circleColor, styleValue,
@"circleColor should round-trip functions.");
layer.circleColor = nil;
XCTAssertTrue(rawLayer->getCircleColor().isUndefined(),
@"Unsetting circleColor should return circle-color to the default value.");
XCTAssertEqualObjects(layer.circleColor, defaultStyleValue,
@"circleColor should return the default value after being unset.");
}
// circle-opacity
{
XCTAssertTrue(rawLayer->getCircleOpacity().isUndefined(),
@"circle-opacity should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleOpacity;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.circleOpacity = styleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
@"Setting circleOpacity to a constant value should update circle-opacity.");
XCTAssertEqualObjects(layer.circleOpacity, styleValue,
@"circleOpacity should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.circleOpacity = styleValue;
propertyValue = { mbgl::style::Function<float> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
@"Setting circleOpacity to a function should update circle-opacity.");
XCTAssertEqualObjects(layer.circleOpacity, styleValue,
@"circleOpacity should round-trip functions.");
layer.circleOpacity = nil;
XCTAssertTrue(rawLayer->getCircleOpacity().isUndefined(),
@"Unsetting circleOpacity should return circle-opacity to the default value.");
XCTAssertEqualObjects(layer.circleOpacity, defaultStyleValue,
@"circleOpacity should return the default value after being unset.");
}
// circle-radius
{
XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(),
@"circle-radius should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleRadius;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.circleRadius = styleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
@"Setting circleRadius to a constant value should update circle-radius.");
XCTAssertEqualObjects(layer.circleRadius, styleValue,
@"circleRadius should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.circleRadius = styleValue;
propertyValue = { mbgl::style::Function<float> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
@"Setting circleRadius to a function should update circle-radius.");
XCTAssertEqualObjects(layer.circleRadius, styleValue,
@"circleRadius should round-trip functions.");
layer.circleRadius = nil;
XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(),
@"Unsetting circleRadius should return circle-radius to the default value.");
XCTAssertEqualObjects(layer.circleRadius, defaultStyleValue,
@"circleRadius should return the default value after being unset.");
}
// circle-pitch-scale
{
XCTAssertTrue(rawLayer->getCirclePitchScale().isUndefined(),
@"circle-pitch-scale should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleScaleAlignment;
MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentViewport]];
layer.circleScaleAlignment = styleValue;
mbgl::style::PropertyValue<mbgl::style::CirclePitchScaleType> propertyValue = { mbgl::style::CirclePitchScaleType::Viewport };
XCTAssertEqual(rawLayer->getCirclePitchScale(), propertyValue,
@"Setting circleScaleAlignment to a constant value should update circle-pitch-scale.");
XCTAssertEqualObjects(layer.circleScaleAlignment, styleValue,
@"circleScaleAlignment should round-trip constant values.");
styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
@18: styleValue,
}];
layer.circleScaleAlignment = styleValue;
propertyValue = { mbgl::style::Function<mbgl::style::CirclePitchScaleType> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getCirclePitchScale(), propertyValue,
@"Setting circleScaleAlignment to a function should update circle-pitch-scale.");
XCTAssertEqualObjects(layer.circleScaleAlignment, styleValue,
@"circleScaleAlignment should round-trip functions.");
layer.circleScaleAlignment = nil;
XCTAssertTrue(rawLayer->getCirclePitchScale().isUndefined(),
@"Unsetting circleScaleAlignment should return circle-pitch-scale to the default value.");
XCTAssertEqualObjects(layer.circleScaleAlignment, defaultStyleValue,
@"circleScaleAlignment should return the default value after being unset.");
}
// circle-stroke-color
{
XCTAssertTrue(rawLayer->getCircleStrokeColor().isUndefined(),
@"circle-stroke-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.circleStrokeColor;
MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
layer.circleStrokeColor = styleValue;
mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
@"Setting circleStrokeColor to a constant value should update circle-stroke-color.");
XCTAssertEqualObjects(layer.circleStrokeColor, styleValue,
@"circleStrokeColor should round-trip constant values.");
styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
@18: styleValue,
}];
layer.circleStrokeColor = styleValue;
propertyValue = { mbgl::style::Function<mbgl::Color> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
@"Setting circleStrokeColor to a function should update circle-stroke-color.");
XCTAssertEqualObjects(layer.circleStrokeColor, styleValue,
@"circleStrokeColor should round-trip functions.");
layer.circleStrokeColor = nil;
XCTAssertTrue(rawLayer->getCircleStrokeColor().isUndefined(),
@"Unsetting circleStrokeColor should return circle-stroke-color to the default value.");
XCTAssertEqualObjects(layer.circleStrokeColor, defaultStyleValue,
@"circleStrokeColor should return the default value after being unset.");
}
// circle-stroke-opacity
{
XCTAssertTrue(rawLayer->getCircleStrokeOpacity().isUndefined(),
@"circle-stroke-opacity should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleStrokeOpacity;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.circleStrokeOpacity = styleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
@"Setting circleStrokeOpacity to a constant value should update circle-stroke-opacity.");
XCTAssertEqualObjects(layer.circleStrokeOpacity, styleValue,
@"circleStrokeOpacity should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.circleStrokeOpacity = styleValue;
propertyValue = { mbgl::style::Function<float> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
@"Setting circleStrokeOpacity to a function should update circle-stroke-opacity.");
XCTAssertEqualObjects(layer.circleStrokeOpacity, styleValue,
@"circleStrokeOpacity should round-trip functions.");
layer.circleStrokeOpacity = nil;
XCTAssertTrue(rawLayer->getCircleStrokeOpacity().isUndefined(),
@"Unsetting circleStrokeOpacity should return circle-stroke-opacity to the default value.");
XCTAssertEqualObjects(layer.circleStrokeOpacity, defaultStyleValue,
@"circleStrokeOpacity should return the default value after being unset.");
}
// circle-stroke-width
{
XCTAssertTrue(rawLayer->getCircleStrokeWidth().isUndefined(),
@"circle-stroke-width should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleStrokeWidth;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.circleStrokeWidth = styleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
@"Setting circleStrokeWidth to a constant value should update circle-stroke-width.");
XCTAssertEqualObjects(layer.circleStrokeWidth, styleValue,
@"circleStrokeWidth should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.circleStrokeWidth = styleValue;
propertyValue = { mbgl::style::Function<float> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
@"Setting circleStrokeWidth to a function should update circle-stroke-width.");
XCTAssertEqualObjects(layer.circleStrokeWidth, styleValue,
@"circleStrokeWidth should round-trip functions.");
layer.circleStrokeWidth = nil;
XCTAssertTrue(rawLayer->getCircleStrokeWidth().isUndefined(),
@"Unsetting circleStrokeWidth should return circle-stroke-width to the default value.");
XCTAssertEqualObjects(layer.circleStrokeWidth, defaultStyleValue,
@"circleStrokeWidth should return the default value after being unset.");
}
// circle-translate
{
XCTAssertTrue(rawLayer->getCircleTranslate().isUndefined(),
@"circle-translate should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleTranslation;
MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
layer.circleTranslation = styleValue;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getCircleTranslate(), propertyValue,
@"Setting circleTranslation to a constant value should update circle-translate.");
XCTAssertEqualObjects(layer.circleTranslation, styleValue,
@"circleTranslation should round-trip constant values.");
styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
@18: styleValue,
}];
layer.circleTranslation = styleValue;
propertyValue = { mbgl::style::Function<std::array<float, 2>> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getCircleTranslate(), propertyValue,
@"Setting circleTranslation to a function should update circle-translate.");
XCTAssertEqualObjects(layer.circleTranslation, styleValue,
@"circleTranslation should round-trip functions.");
layer.circleTranslation = nil;
XCTAssertTrue(rawLayer->getCircleTranslate().isUndefined(),
@"Unsetting circleTranslation should return circle-translate to the default value.");
XCTAssertEqualObjects(layer.circleTranslation, defaultStyleValue,
@"circleTranslation should return the default value after being unset.");
}
// circle-translate-anchor
{
XCTAssertTrue(rawLayer->getCircleTranslateAnchor().isUndefined(),
@"circle-translate-anchor should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleTranslationAnchor;
MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorViewport]];
layer.circleTranslationAnchor = styleValue;
mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
XCTAssertEqual(rawLayer->getCircleTranslateAnchor(), propertyValue,
@"Setting circleTranslationAnchor to a constant value should update circle-translate-anchor.");
XCTAssertEqualObjects(layer.circleTranslationAnchor, styleValue,
@"circleTranslationAnchor should round-trip constant values.");
styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
@18: styleValue,
}];
layer.circleTranslationAnchor = styleValue;
propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getCircleTranslateAnchor(), propertyValue,
@"Setting circleTranslationAnchor to a function should update circle-translate-anchor.");
XCTAssertEqualObjects(layer.circleTranslationAnchor, styleValue,
@"circleTranslationAnchor should round-trip functions.");
layer.circleTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getCircleTranslateAnchor().isUndefined(),
@"Unsetting circleTranslationAnchor should return circle-translate-anchor to the default value.");
XCTAssertEqualObjects(layer.circleTranslationAnchor, defaultStyleValue,
@"circleTranslationAnchor should return the default value after being unset.");
}
}
- (void)testPropertyNames {
[self testPropertyName:@"circle-blur" isBoolean:NO];
[self testPropertyName:@"circle-color" isBoolean:NO];
[self testPropertyName:@"circle-opacity" isBoolean:NO];
[self testPropertyName:@"circle-radius" isBoolean:NO];
[self testPropertyName:@"circle-scale-alignment" isBoolean:NO];
[self testPropertyName:@"circle-stroke-color" isBoolean:NO];
[self testPropertyName:@"circle-stroke-opacity" isBoolean:NO];
[self testPropertyName:@"circle-stroke-width" isBoolean:NO];
[self testPropertyName:@"circle-translation" isBoolean:NO];
[self testPropertyName:@"circle-translation-anchor" isBoolean:NO];
}
- (void)testValueAdditions {
XCTAssertEqual([NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentMap].MGLCircleScaleAlignmentValue, MGLCircleScaleAlignmentMap);
XCTAssertEqual([NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentViewport].MGLCircleScaleAlignmentValue, MGLCircleScaleAlignmentViewport);
XCTAssertEqual([NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorMap].MGLCircleTranslationAnchorValue, MGLCircleTranslationAnchorMap);
XCTAssertEqual([NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorViewport].MGLCircleTranslationAnchorValue, MGLCircleTranslationAnchorViewport);
}
@end

View File

@@ -0,0 +1,469 @@
#import <Mapbox/Mapbox.h>
#import <XCTest/XCTest.h>
#if TARGET_OS_IPHONE
#import "MGLUserLocation_Private.h"
#endif
@interface MGLCodingTests : XCTestCase
@end
@implementation MGLCodingTests
- (NSString *)temporaryFilePathForClass:(Class)clazz {
return [NSTemporaryDirectory() stringByAppendingPathComponent:NSStringFromClass(clazz)];
}
- (void)testPointAnnotation {
MGLPointAnnotation *annotation = [[MGLPointAnnotation alloc] init];
annotation.coordinate = CLLocationCoordinate2DMake(0.5, 0.5);
annotation.title = @"title";
annotation.subtitle = @"subtitle";
NSString *filePath = [self temporaryFilePathForClass:MGLPointAnnotation.class];
[NSKeyedArchiver archiveRootObject:annotation toFile:filePath];
MGLPointAnnotation *unarchivedAnnotation = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
XCTAssertEqualObjects(annotation, unarchivedAnnotation);
}
- (void)testPointFeature {
MGLPointFeature *pointFeature = [[MGLPointFeature alloc] init];
pointFeature.title = @"title";
pointFeature.subtitle = @"subtitle";
pointFeature.identifier = @(123);
pointFeature.attributes = @{@"bbox": @[@1, @2, @3, @4]};
NSString *filePath = [self temporaryFilePathForClass:MGLPointFeature.class];
[NSKeyedArchiver archiveRootObject:pointFeature toFile:filePath];
MGLPointFeature *unarchivedPointFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
XCTAssertEqualObjects(pointFeature, unarchivedPointFeature);
}
- (void)testPolyline {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(0.129631234123, 1.7812739312551),
CLLocationCoordinate2DMake(2.532083092342, 3.5216418292392)
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates];
polyline.title = @"title";
polyline.subtitle = @"subtitle";
NSString *filePath = [self temporaryFilePathForClass:[MGLPolyline class]];
[NSKeyedArchiver archiveRootObject:polyline toFile:filePath];
MGLPolyline *unarchivedPolyline = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
XCTAssertEqualObjects(polyline, unarchivedPolyline);
CLLocationCoordinate2D otherCoordinates[] = {
CLLocationCoordinate2DMake(-1, -2)
};
[unarchivedPolyline replaceCoordinatesInRange:NSMakeRange(0, 1) withCoordinates:otherCoordinates];
XCTAssertNotEqualObjects(polyline, unarchivedPolyline);
}
- (void)testPolygon {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(0.664482398, 1.8865675),
CLLocationCoordinate2DMake(2.13224687, 3.9984632)
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates];
polygon.title = nil;
polygon.subtitle = @"subtitle";
NSString *filePath = [self temporaryFilePathForClass:[MGLPolygon class]];
[NSKeyedArchiver archiveRootObject:polygon toFile:filePath];
MGLPolygon *unarchivedPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
XCTAssertEqualObjects(polygon, unarchivedPolygon);
}
- (void)testPolygonWithInteriorPolygons {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(0, 1),
CLLocationCoordinate2DMake(10, 20)
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
CLLocationCoordinate2D interiorCoordinates[] = {
CLLocationCoordinate2DMake(4, 4),
CLLocationCoordinate2DMake(6, 6)
};
NSUInteger numberOfInteriorCoordinates = sizeof(interiorCoordinates) / sizeof(CLLocationCoordinate2D);
MGLPolygon *interiorPolygon = [MGLPolygon polygonWithCoordinates:interiorCoordinates count:numberOfInteriorCoordinates];
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates interiorPolygons:@[interiorPolygon]];
NSString *filePath = [self temporaryFilePathForClass:[MGLPolygon class]];
[NSKeyedArchiver archiveRootObject:polygon toFile:filePath];
MGLPolygon *unarchivedPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
XCTAssertEqualObjects(polygon, unarchivedPolygon);
}
- (void)testPolylineFeature {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(0, 1),
CLLocationCoordinate2DMake(10, 20)
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coordinates count:numberOfCoordinates];
polylineFeature.attributes = @{@"bbox": @[@0, @1, @2, @3]};
polylineFeature.identifier = @"identifier";
NSString *filePath = [self temporaryFilePathForClass:[MGLPolylineFeature class]];
[NSKeyedArchiver archiveRootObject:polylineFeature toFile:filePath];
MGLPolylineFeature *unarchivedPolylineFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
XCTAssertEqualObjects(polylineFeature, unarchivedPolylineFeature);
unarchivedPolylineFeature.attributes = @{@"bbox": @[@4, @3, @2, @1]};
XCTAssertNotEqualObjects(polylineFeature, unarchivedPolylineFeature);
}
- (void)testPolygonFeature {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(0, 1),
CLLocationCoordinate2DMake(10, 20)
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:numberOfCoordinates];
NSString *filePath = [self temporaryFilePathForClass:[MGLPolygonFeature class]];
[NSKeyedArchiver archiveRootObject:polygonFeature toFile:filePath];
MGLPolygonFeature *unarchivedPolygonFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
XCTAssertEqualObjects(polygonFeature, unarchivedPolygonFeature);
unarchivedPolygonFeature.identifier = @"test";
XCTAssertNotEqualObjects(polygonFeature, unarchivedPolygonFeature);
}
- (void)testPointCollection {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(0, 1),
CLLocationCoordinate2DMake(10, 11),
CLLocationCoordinate2DMake(20, 21),
CLLocationCoordinate2DMake(30, 31),
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
MGLPointCollection *pointCollection = [MGLPointCollection pointCollectionWithCoordinates:coordinates count:numberOfCoordinates];
NSString *filePath = [self temporaryFilePathForClass:[MGLPointCollection class]];
[NSKeyedArchiver archiveRootObject:pointCollection toFile:filePath];
MGLPointCollection *unarchivedPointCollection = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
XCTAssertEqualObjects(pointCollection, unarchivedPointCollection);
}
- (void)testPointCollectionFeature {
NSMutableArray *features = [NSMutableArray array];
for (NSUInteger i = 0; i < 100; i++) {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
feature.coordinate = CLLocationCoordinate2DMake(arc4random() % 90, arc4random() % 180);
[features addObject:feature];
}
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(0, 1),
CLLocationCoordinate2DMake(10, 11),
CLLocationCoordinate2DMake(20, 21),
CLLocationCoordinate2DMake(30, 31),
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
MGLPointCollectionFeature *collection = [MGLPointCollectionFeature pointCollectionWithCoordinates:coordinates count:numberOfCoordinates];
collection.identifier = @"identifier";
collection.attributes = @{@"bbox": @[@1, @2, @3, @4]};
NSString *filePath = [self temporaryFilePathForClass:[MGLPointCollectionFeature class]];
[NSKeyedArchiver archiveRootObject:collection toFile:filePath];
MGLPointCollectionFeature *unarchivedCollection = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
XCTAssertEqualObjects(collection, unarchivedCollection);
unarchivedCollection.identifier = @"newIdentifier";
XCTAssertNotEqualObjects(collection, unarchivedCollection);
}
- (void)testMultiPolyline {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(0, 1),
CLLocationCoordinate2DMake(10, 11),
CLLocationCoordinate2DMake(20, 21),
CLLocationCoordinate2DMake(30, 31),
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
NSMutableArray *polylines = [NSMutableArray array];
for (NSUInteger i = 0; i < 100; i++) {
MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates];
[polylines addObject:polyline];
}
MGLMultiPolyline *multiPolyline = [MGLMultiPolyline multiPolylineWithPolylines:polylines];
NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolyline class]];
[NSKeyedArchiver archiveRootObject:multiPolyline toFile:filePath];
MGLMultiPolyline *unarchivedMultiPolyline = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
MGLMultiPolyline *anotherMultipolyline = [MGLMultiPolyline multiPolylineWithPolylines:[polylines subarrayWithRange:NSMakeRange(0, polylines.count/2)]];
XCTAssertEqualObjects(multiPolyline, unarchivedMultiPolyline);
XCTAssertNotEqualObjects(unarchivedMultiPolyline, anotherMultipolyline);
}
- (void)testMultiPolygon {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(0, 1),
CLLocationCoordinate2DMake(10, 11),
CLLocationCoordinate2DMake(20, 21),
CLLocationCoordinate2DMake(30, 31),
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
NSMutableArray *polygons = [NSMutableArray array];
for (NSUInteger i = 0; i < 100; i++) {
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates];
[polygons addObject:polygon];
}
MGLMultiPolygon *multiPolygon = [MGLMultiPolygon multiPolygonWithPolygons:polygons];
NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolygon class]];
[NSKeyedArchiver archiveRootObject:multiPolygon toFile:filePath];
MGLMultiPolygon *unarchivedMultiPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
MGLMultiPolygon *anotherMultiPolygon = [MGLMultiPolygon multiPolygonWithPolygons:[polygons subarrayWithRange:NSMakeRange(0, polygons.count/2)]];
XCTAssertEqualObjects(multiPolygon, unarchivedMultiPolygon);
XCTAssertNotEqualObjects(anotherMultiPolygon, unarchivedMultiPolygon);
}
- (void)testShapeCollection {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(10.12315786, 11.23451186),
CLLocationCoordinate2DMake(20.91836515, 21.93689215),
CLLocationCoordinate2DMake(30.55697246, 31.33988123),
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates];
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates];
MGLShapeCollection *shapeCollection = [MGLShapeCollection shapeCollectionWithShapes:@[polyline, polygon]];
NSString *filePath = [self temporaryFilePathForClass:[MGLShapeCollection class]];
[NSKeyedArchiver archiveRootObject:shapeCollection toFile:filePath];
MGLShapeCollection *unarchivedShapeCollection = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
MGLShapeCollection *anotherShapeCollection = [MGLShapeCollection shapeCollectionWithShapes:@[polygon]];
XCTAssertEqualObjects(shapeCollection, unarchivedShapeCollection);
XCTAssertNotEqualObjects(shapeCollection, anotherShapeCollection);
}
- (void)testMultiPolylineFeature {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(10.12315786, 11.23451186),
CLLocationCoordinate2DMake(20.91836515, 21.93689215),
CLLocationCoordinate2DMake(30.55697246, 31.33988123),
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
NSMutableArray *polylines = [NSMutableArray array];
for (NSUInteger i = 0; i < 100; i++) {
MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coordinates count:numberOfCoordinates];
polylineFeature.identifier = @(arc4random() % 100).stringValue;
[polylines addObject:polylineFeature];
}
MGLMultiPolylineFeature *multiPolylineFeature = [MGLMultiPolylineFeature multiPolylineWithPolylines:polylines];
multiPolylineFeature.attributes = @{@"bbox": @[@4, @3, @2, @1]};
NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolylineFeature class]];
[NSKeyedArchiver archiveRootObject:multiPolylineFeature toFile:filePath];
MGLMultiPolylineFeature *unarchivedMultiPolylineFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
MGLMultiPolylineFeature *anotherMultiPolylineFeature = [MGLMultiPolylineFeature multiPolylineWithPolylines:[polylines subarrayWithRange:NSMakeRange(0, polylines.count/2)]];
XCTAssertEqualObjects(multiPolylineFeature, unarchivedMultiPolylineFeature);
XCTAssertNotEqualObjects(unarchivedMultiPolylineFeature, anotherMultiPolylineFeature);
}
- (void)testMultiPolygonFeature {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(10.12315786, 11.23451185),
CLLocationCoordinate2DMake(20.88471238, 21.93684215),
CLLocationCoordinate2DMake(30.15697236, 31.32988123),
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
NSMutableArray *polygons = [NSMutableArray array];
for (NSUInteger i = 0; i < 100; i++ ) {
MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:numberOfCoordinates];
polygonFeature.identifier = @(arc4random_uniform(100)).stringValue;
[polygons addObject:polygonFeature];
}
MGLMultiPolygonFeature *multiPolygonFeature = [MGLMultiPolygonFeature multiPolygonWithPolygons:polygons];
multiPolygonFeature.attributes = @{@"bbox": @[@(arc4random_uniform(100)),
@(arc4random_uniform(100)),
@(arc4random_uniform(100)),
@(arc4random_uniform(100))]};
NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolylineFeature class]];
[NSKeyedArchiver archiveRootObject:multiPolygonFeature toFile:filePath];
MGLMultiPolygonFeature *unarchivedMultiPolygonFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
MGLMultiPolygonFeature *anotherMultiPolygonFeature = [MGLMultiPolygonFeature multiPolygonWithPolygons:[polygons subarrayWithRange:NSMakeRange(0, polygons.count/2)]];
XCTAssertEqualObjects(multiPolygonFeature, unarchivedMultiPolygonFeature);
XCTAssertNotEqualObjects(anotherMultiPolygonFeature, unarchivedMultiPolygonFeature);
}
- (void)testShapeCollectionFeature {
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(10.12315786, 11.23451186),
CLLocationCoordinate2DMake(20.91836515, 21.93689215),
CLLocationCoordinate2DMake(30.55697246, 31.33988123),
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
MGLPolylineFeature *polyline = [MGLPolylineFeature polylineWithCoordinates:coordinates count:numberOfCoordinates];
MGLPolygonFeature *polygon = [MGLPolygonFeature polygonWithCoordinates:coordinates count:numberOfCoordinates];
MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[polyline, polygon]];
shapeCollectionFeature.identifier = @(arc4random_uniform(100)).stringValue;
shapeCollectionFeature.attributes = @{@"bbox":@[@(arc4random_uniform(100)),
@(arc4random_uniform(100)),
@(arc4random_uniform(100)),
@(arc4random_uniform(100))]};
NSString *filePath = [self temporaryFilePathForClass:[MGLShapeCollectionFeature class]];
[NSKeyedArchiver archiveRootObject:shapeCollectionFeature toFile:filePath];
MGLShapeCollectionFeature *unarchivedShapeCollectionFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
XCTAssertEqualObjects(shapeCollectionFeature, unarchivedShapeCollectionFeature);
}
- (void)testAnnotationImage {
#if TARGET_OS_IPHONE
UIGraphicsBeginImageContext(CGSizeMake(10, 10));
[[UIColor redColor] setFill];
UIRectFill(CGRectMake(0, 0, 10, 10));
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
#else
NSImage *image = [[NSImage alloc] initWithSize:CGSizeMake(10, 10)];
[image lockFocus];
[[NSColor redColor] drawSwatchInRect:CGRectMake(0, 0, 10, 10)];
[image unlockFocus];
#endif
MGLAnnotationImage *annotationImage = [MGLAnnotationImage annotationImageWithImage:image reuseIdentifier:@(arc4random_uniform(100)).stringValue];
NSString *filePath = [self temporaryFilePathForClass:[MGLAnnotationImage class]];
[NSKeyedArchiver archiveRootObject:annotationImage toFile:filePath];
MGLAnnotationImage *unarchivedAnnotationImage = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
XCTAssertEqualObjects(annotationImage, unarchivedAnnotationImage);
}
#if TARGET_OS_IPHONE
- (void)testAnnotationView {
MGLAnnotationView *annotationView = [[MGLAnnotationView alloc] initWithReuseIdentifier:@"id"];
annotationView.enabled = NO;
annotationView.selected = YES;
annotationView.draggable = YES;
annotationView.centerOffset = CGVectorMake(10, 10);
annotationView.scalesWithViewingDistance = NO;
NSString *filePath = [self temporaryFilePathForClass:[MGLAnnotationView class]];
[NSKeyedArchiver archiveRootObject:annotationView toFile:filePath];
MGLAnnotationView *unarchivedAnnotationView = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
XCTAssertEqual(annotationView.enabled, unarchivedAnnotationView.enabled);
XCTAssertEqual(annotationView.selected, unarchivedAnnotationView.selected);
XCTAssertEqual(annotationView.draggable, unarchivedAnnotationView.draggable);
XCTAssertEqualObjects(NSStringFromCGVector(annotationView.centerOffset), NSStringFromCGVector(unarchivedAnnotationView.centerOffset));
XCTAssertEqual(annotationView.scalesWithViewingDistance, unarchivedAnnotationView.scalesWithViewingDistance);
}
#endif
#if TARGET_OS_IPHONE
- (void)testUserLocation {
MGLUserLocation *userLocation = [[MGLUserLocation alloc] init];
userLocation.location = [[CLLocation alloc] initWithLatitude:1 longitude:1];
NSString *filePath = [self temporaryFilePathForClass:[MGLUserLocation class]];
[NSKeyedArchiver archiveRootObject:userLocation toFile:filePath];
MGLUserLocation *unarchivedUserLocation = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
XCTAssertEqualObjects(userLocation, unarchivedUserLocation);
unarchivedUserLocation.location = [[CLLocation alloc] initWithLatitude:10 longitude:10];
XCTAssertNotEqualObjects(userLocation, unarchivedUserLocation);
}
#endif
#if TARGET_OS_IPHONE
- (void)testUserLocationAnnotationView {
MGLUserLocationAnnotationView *annotationView = [[MGLUserLocationAnnotationView alloc] init];
annotationView.enabled = NO;
annotationView.selected = YES;
annotationView.draggable = YES;
annotationView.centerOffset = CGVectorMake(10, 10);
annotationView.scalesWithViewingDistance = NO;
NSString *filePath = [self temporaryFilePathForClass:[MGLUserLocationAnnotationView class]];
[NSKeyedArchiver archiveRootObject:annotationView toFile:filePath];
MGLUserLocationAnnotationView *unarchivedAnnotationView = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
XCTAssertEqual(annotationView.enabled, unarchivedAnnotationView.enabled);
XCTAssertEqual(annotationView.selected, unarchivedAnnotationView.selected);
XCTAssertEqual(annotationView.draggable, unarchivedAnnotationView.draggable);
XCTAssertEqualObjects(NSStringFromCGVector(annotationView.centerOffset), NSStringFromCGVector(unarchivedAnnotationView.centerOffset));
XCTAssertEqual(annotationView.scalesWithViewingDistance, unarchivedAnnotationView.scalesWithViewingDistance);
}
#endif
@end

View File

@@ -0,0 +1,220 @@
import XCTest
import Mapbox
#if os(iOS)
import UIKit
#else
import Cocoa
#endif
/**
Test cases that ensure the inline examples in the project documentation
compile.
To add an example:
1. Add a test case named in the form testMGLClass or testMGLClass$method.
2. Wrap the code you'd like to appear in the documentation within the
following comment blocks:
```
//#-example-code
...
//#-end-example-code
```
3. Insert an empty Swift code block inside the header file where you'd like the
example code to be inserted.
4. Run `make darwin-update-examples` to extract example code from the test
method below and insert it into the header.
*/
class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
var mapView: MGLMapView!
var styleLoadingExpectation: XCTestExpectation!
override func setUp() {
super.setUp()
let styleURL = Bundle(for: MGLDocumentationExampleTests.self).url(forResource: "one-liner", withExtension: "json")
mapView = MGLMapView(frame: CGRect(x: 0, y: 0, width: 256, height: 256), styleURL: styleURL)
mapView.delegate = self
styleLoadingExpectation = expectation(description: "Map view should finish loading style")
waitForExpectations(timeout: 1, handler: nil)
}
override func tearDown() {
mapView = nil
styleLoadingExpectation = nil
super.tearDown()
}
func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
styleLoadingExpectation.fulfill()
}
func testMGLShape$shapeWithData_encoding_error_() {
let mainBundle = Bundle(for: MGLDocumentationExampleTests.self)
//#-example-code
let url = mainBundle.url(forResource: "amsterdam", withExtension: "geojson")!
let data = try! Data(contentsOf: url)
let feature = try! MGLShape(data: data, encoding: String.Encoding.utf8.rawValue) as! MGLShapeCollectionFeature
//#-end-example-code
XCTAssertNotNil(feature.shapes.first as? MGLPolygonFeature)
}
func testMGLShapeSource() {
//#-example-code
var coordinates: [CLLocationCoordinate2D] = [
CLLocationCoordinate2D(latitude: 37.77, longitude: -122.42),
CLLocationCoordinate2D(latitude: 38.91, longitude: -77.04),
]
let polyline = MGLPolylineFeature(coordinates: &coordinates, count: UInt(coordinates.count))
let source = MGLShapeSource(identifier: "lines", features: [polyline], options: nil)
mapView.style?.addSource(source)
//#-end-example-code
XCTAssertNotNil(mapView.style?.source(withIdentifier: "lines"))
}
func testMGLRasterSource() {
//#-example-code
let source = MGLRasterSource(identifier: "clouds", tileURLTemplates: ["https://example.com/raster-tiles/{z}/{x}/{y}.png"], options: [
.minimumZoomLevel: 9,
.maximumZoomLevel: 16,
.tileSize: 512,
.attributionInfos: [
MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
]
])
mapView.style?.addSource(source)
//#-end-example-code
XCTAssertNotNil(mapView.style?.source(withIdentifier: "clouds"))
}
func testMGLVectorSource() {
//#-example-code
let source = MGLVectorSource(identifier: "pois", tileURLTemplates: ["https://example.com/vector-tiles/{z}/{x}/{y}.mvt"], options: [
.minimumZoomLevel: 9,
.maximumZoomLevel: 16,
.attributionInfos: [
MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
]
])
mapView.style?.addSource(source)
//#-end-example-code
XCTAssertNotNil(mapView.style?.source(withIdentifier: "pois"))
}
func testMGLCircleStyleLayer() {
let population = MGLVectorSource(identifier: "population", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style?.addSource(population)
//#-example-code
let layer = MGLCircleStyleLayer(identifier: "circles", source: population)
layer.sourceLayerIdentifier = "population"
layer.circleColor = MGLStyleValue(rawValue: .green)
layer.circleRadius = MGLStyleValue(interpolationBase: 1.75, stops: [
12: MGLStyleValue(rawValue: 2),
22: MGLStyleValue(rawValue: 180)
])
layer.circleOpacity = MGLStyleValue(rawValue: 0.7)
layer.predicate = NSPredicate(format: "%K == %@", "marital-status", "married")
mapView.style?.addLayer(layer)
//#-end-example-code
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "circles"))
}
func testMGLLineStyleLayer() {
let trails = MGLVectorSource(identifier: "trails", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style?.addSource(trails)
//#-example-code
let layer = MGLLineStyleLayer(identifier: "trails-path", source: trails)
layer.sourceLayerIdentifier = "trails"
layer.lineWidth = MGLStyleValue(interpolationBase: 1.5, stops: [
14: MGLStyleValue(rawValue: 2),
18: MGLStyleValue(rawValue: 20),
])
layer.lineColor = MGLStyleValue(rawValue: .brown)
layer.lineCap = MGLStyleValue(rawValue: NSValue(mglLineCap: .round))
layer.predicate = NSPredicate(format: "%K == %@", "trail-type", "mountain-biking")
mapView.style?.addLayer(layer)
//#-end-example-code
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "trails-path"))
}
func testMGLFillStyleLayer() {
let parks = MGLVectorSource(identifier: "parks", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style?.addSource(parks)
//#-example-code
let layer = MGLFillStyleLayer(identifier: "parks", source: parks)
layer.sourceLayerIdentifier = "parks"
layer.fillColor = MGLStyleValue(rawValue: .green)
layer.predicate = NSPredicate(format: "type == %@", "national-park")
mapView.style?.addLayer(layer)
//#-end-example-code
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "parks"))
}
func testMGLSymbolStyleLayer() {
let pois = MGLVectorSource(identifier: "pois", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style?.addSource(pois)
//#-example-code
let layer = MGLSymbolStyleLayer(identifier: "coffeeshops", source: pois)
layer.sourceLayerIdentifier = "pois"
layer.iconImageName = MGLStyleValue(rawValue: "coffee")
layer.iconScale = MGLStyleValue(rawValue: 0.5)
layer.text = MGLStyleValue(rawValue: "{name}")
#if os(macOS)
var vector = CGVector(dx: 10, dy: 0)
layer.textTranslation = MGLStyleValue(rawValue: NSValue(bytes: &vector, objCType: "{CGVector=dd}"))
#else
layer.textTranslation = MGLStyleValue(rawValue: NSValue(cgVector: CGVector(dx: 10, dy: 0)))
#endif
layer.textJustification = MGLStyleValue(rawValue: NSValue(mglTextJustification: .left))
layer.textAnchor = MGLStyleValue(rawValue: NSValue(mglTextAnchor: .left))
layer.predicate = NSPredicate(format: "%K == %@", "venue-type", "coffee")
mapView.style?.addLayer(layer)
//#-end-example-code
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "coffeeshops"))
}
func testMGLRasterStyleLayer() {
let source = MGLRasterSource(identifier: "clouds", tileURLTemplates: ["https://example.com/raster-tiles/{z}/{x}/{y}.png"], options: [
.minimumZoomLevel: 9,
.maximumZoomLevel: 16,
.tileSize: 512,
.attributionInfos: [
MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
]
])
mapView.style?.addSource(source)
//#-example-code
let layer = MGLRasterStyleLayer(identifier: "clouds", source: source)
layer.rasterOpacity = MGLStyleValue(rawValue: 0.5)
mapView.style?.addLayer(layer)
//#-end-example-code
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "clouds"))
}
func testMGLVectorStyleLayer$predicate() {
let terrain = MGLVectorSource(identifier: "terrain", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style?.addSource(terrain)
//#-example-code
let layer = MGLLineStyleLayer(identifier: "contour", source: terrain)
layer.sourceLayerIdentifier = "contours"
layer.predicate = NSPredicate(format: "(index == 5 || index == 10) && ele >= 1500.0")
mapView.style?.addLayer(layer)
//#-end-example-code
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "contour"))
}
}

View File

@@ -28,27 +28,35 @@
- (void)testExpressionConversionString
{
NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@"bar"];
mbgl::Value convertedValue = predicate.rightExpression.mgl_filterValue;
XCTAssert(convertedValue.is<std::string>() == true);
mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<std::string>());
XCTAssertEqualObjects(@(convertedValue.get<std::string>().c_str()), @"bar");
}
- (void)testExpressionConversionStringWithUnicode
{
NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@"🆔🆗🇦🇶"];
mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<std::string>());
XCTAssertEqual(convertedValue.get<std::string>(), "🆔🆗🇦🇶");
}
#pragma mark - Boolean Tests
- (void)testExpressionConversionBooleanTrue
{
NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@YES];
mbgl::Value convertedValue = predicate.rightExpression.mgl_filterValue;
XCTAssert(convertedValue.is<bool>() == true);
XCTAssert(convertedValue.get<bool>() == true);
mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<bool>());
XCTAssertEqual(convertedValue.get<bool>(), true);
}
- (void)testExpressionConversionBooleanFalse
{
NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@NO];
mbgl::Value convertedValue = predicate.rightExpression.mgl_filterValue;
XCTAssert(convertedValue.is<bool>() == true);
XCTAssert(convertedValue.get<bool>() == false);
mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<bool>());
XCTAssertEqual(convertedValue.get<bool>(), false);
}
#pragma mark - Floating Point Tests
@@ -59,12 +67,12 @@
mbgl::Value convertedValue;
predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithDouble:DBL_MIN]];
convertedValue = predicate.rightExpression.mgl_filterValue;
convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<double>());
XCTAssertEqual(convertedValue.get<double>(), DBL_MIN);
predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithDouble:DBL_MAX]];
convertedValue = predicate.rightExpression.mgl_filterValue;
convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<double>());
XCTAssertEqual(convertedValue.get<double>(), DBL_MAX);
}
@@ -72,7 +80,7 @@
- (void)testExpressionConversionFloat
{
// Because we can't guarantee precision when using float, and because
// we warn the user to this effect in mgl_convertedValueWithValue:,
// we warn the user to this effect in -[NSExpression mgl_constantMBGLValue],
// we just check that things are in the ballpark here with integer values
// and some lower-precision checks.
@@ -80,26 +88,24 @@
mbgl::Value convertedValue;
predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:-1]];
convertedValue = predicate.rightExpression.mgl_filterValue;
convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<double>());
XCTAssertEqual(convertedValue.get<double>(), -1);
predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:1]];
convertedValue = predicate.rightExpression.mgl_filterValue;
convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<double>());
XCTAssertEqual(convertedValue.get<double>(), 1);
predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:-23.232342]];
convertedValue = predicate.rightExpression.mgl_filterValue;
convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<double>());
XCTAssertLessThan(-23.24, convertedValue.get<double>());
XCTAssertGreaterThan(-23.23, convertedValue.get<double>());
XCTAssertEqualWithAccuracy(convertedValue.get<double>(), -23.232342, 0.000001);
predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:23.232342]];
convertedValue = predicate.rightExpression.mgl_filterValue;
convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<double>());
XCTAssertLessThan(23.23, convertedValue.get<double>());
XCTAssertGreaterThan(23.24, convertedValue.get<double>());
XCTAssertEqualWithAccuracy(convertedValue.get<double>(), 23.232342, 0.000001);
}
#pragma mark - Integer Tests
@@ -132,7 +138,7 @@
for (NSNumber *min in minValues)
{
predicate = [self equalityComparisonPredicateWithRightConstantValue:min];
convertedValue = predicate.rightExpression.mgl_filterValue;
convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<int64_t>());
XCTAssertEqual(convertedValue.get<int64_t>(), min.longLongValue);
}
@@ -144,7 +150,7 @@
for (NSNumber *max in maxValues)
{
predicate = [self equalityComparisonPredicateWithRightConstantValue:max];
convertedValue = predicate.rightExpression.mgl_filterValue;
convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<uint64_t>());
XCTAssertEqual(convertedValue.get<uint64_t>(), max.unsignedLongLongValue);
}
@@ -179,7 +185,7 @@
for (NSNumber *min in minValues)
{
predicate = [self equalityComparisonPredicateWithRightConstantValue:min];
convertedValue = predicate.rightExpression.mgl_filterValue;
convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<uint64_t>());
XCTAssertEqual(convertedValue.get<uint64_t>(), min.unsignedLongLongValue);
}
@@ -191,10 +197,19 @@
for (NSNumber *max in maxValues)
{
predicate = [self equalityComparisonPredicateWithRightConstantValue:max];
convertedValue = predicate.rightExpression.mgl_filterValue;
convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<uint64_t>());
XCTAssertEqual(convertedValue.get<uint64_t>(), max.unsignedLongLongValue);
}
}
#pragma mark - Null Tests
- (void)testExpressionConversionNull
{
NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNull null]];
mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<mbgl::NullValue>());
}
@end

View File

@@ -322,6 +322,15 @@
@[@(coord2.longitude), @(coord2.latitude)]]}
]};
XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry);
// When the shape collection is created with an empty array of shapes
shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[]];
// it has the correct (empty) geometry
geoJSONFeature = [shapeCollectionFeature geoJSONDictionary];
expectedGeometry = @{@"type": @"GeometryCollection",
@"geometries": @[]};
XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry);
}
@end

View File

@@ -1,69 +0,0 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLStyleLayerTests.h"
@interface MGLFillLayerTests : MGLStyleLayerTests
@end
@implementation MGLFillLayerTests
+ (NSString *)layerType {
return @"fill";
}
- (void)testFillLayer {
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
NSURL *url = [NSURL fileURLWithPath:filePath];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
[self.mapView.style addSource:source];
MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
[self.mapView.style addLayer:layer];
layer.fillAntialiased = [MGLRuntimeStylingHelper testBool];
layer.fillColor = [MGLRuntimeStylingHelper testColor];
layer.fillOpacity = [MGLRuntimeStylingHelper testNumber];
layer.fillOutlineColor = [MGLRuntimeStylingHelper testColor];
layer.fillPattern = [MGLRuntimeStylingHelper testString];
layer.fillTranslate = [MGLRuntimeStylingHelper testOffset];
layer.fillTranslateAnchor = [MGLRuntimeStylingHelper testEnum:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)];
MGLFillStyleLayer *gLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"];
XCTAssertTrue([gLayer isKindOfClass:[MGLFillStyleLayer class]]);
XCTAssertEqualObjects(gLayer.fillAntialiased, [MGLRuntimeStylingHelper testBool]);
XCTAssertEqualObjects(gLayer.fillColor, [MGLRuntimeStylingHelper testColor]);
XCTAssertEqualObjects(gLayer.fillOpacity, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.fillOutlineColor, [MGLRuntimeStylingHelper testColor]);
XCTAssertEqualObjects(gLayer.fillPattern, [MGLRuntimeStylingHelper testString]);
XCTAssertEqualObjects(gLayer.fillTranslate, [MGLRuntimeStylingHelper testOffset]);
XCTAssert([gLayer.fillTranslateAnchor isKindOfClass:[MGLStyleConstantValue class]]);
XCTAssertEqualObjects(gLayer.fillTranslateAnchor, [MGLRuntimeStylingHelper testEnum:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)]);
layer.fillAntialiased = [MGLRuntimeStylingHelper testBoolFunction];
layer.fillColor = [MGLRuntimeStylingHelper testColorFunction];
layer.fillOpacity = [MGLRuntimeStylingHelper testNumberFunction];
layer.fillOutlineColor = [MGLRuntimeStylingHelper testColorFunction];
layer.fillPattern = [MGLRuntimeStylingHelper testStringFunction];
layer.fillTranslate = [MGLRuntimeStylingHelper testOffsetFunction];
layer.fillTranslateAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)];
XCTAssertEqualObjects(gLayer.fillAntialiased, [MGLRuntimeStylingHelper testBoolFunction]);
XCTAssertEqualObjects(gLayer.fillColor, [MGLRuntimeStylingHelper testColorFunction]);
XCTAssertEqualObjects(gLayer.fillOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.fillOutlineColor, [MGLRuntimeStylingHelper testColorFunction]);
XCTAssertEqualObjects(gLayer.fillPattern, [MGLRuntimeStylingHelper testStringFunction]);
XCTAssertEqualObjects(gLayer.fillTranslate, [MGLRuntimeStylingHelper testOffsetFunction]);
XCTAssertEqualObjects(gLayer.fillTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)]);
}
- (void)testPropertyNames {
[self testPropertyName:@"is-fill-antialiased" isBoolean:YES];
[self testPropertyName:@"fill-color" isBoolean:NO];
[self testPropertyName:@"fill-opacity" isBoolean:NO];
[self testPropertyName:@"fill-outline-color" isBoolean:NO];
[self testPropertyName:@"fill-pattern" isBoolean:NO];
[self testPropertyName:@"fill-translate" isBoolean:NO];
[self testPropertyName:@"fill-translate-anchor" isBoolean:NO];
}
@end

View File

@@ -0,0 +1,306 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLStyleLayerTests.h"
#import "MGLStyleLayer_Private.h"
#include <mbgl/style/layers/fill_layer.hpp>
@interface MGLFillLayerTests : MGLStyleLayerTests
@end
@implementation MGLFillLayerTests
+ (NSString *)layerType {
return @"fill";
}
- (void)testPredicates {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
XCTAssertNil(layer.sourceLayerIdentifier);
layer.sourceLayerIdentifier = @"layerID";
XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
layer.sourceLayerIdentifier = nil;
XCTAssertNil(layer.sourceLayerIdentifier);
XCTAssertNil(layer.predicate);
layer.predicate = [NSPredicate predicateWithValue:NO];
XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
layer.predicate = nil;
XCTAssertNil(layer.predicate);
}
- (void)testProperties {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
XCTAssertNotEqual(layer.rawLayer, nullptr);
XCTAssertTrue(layer.rawLayer->is<mbgl::style::FillLayer>());
auto rawLayer = layer.rawLayer->as<mbgl::style::FillLayer>();
// fill-antialias
{
XCTAssertTrue(rawLayer->getFillAntialias().isUndefined(),
@"fill-antialias should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillAntialiased;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@NO];
layer.fillAntialiased = styleValue;
mbgl::style::PropertyValue<bool> propertyValue = { false };
XCTAssertEqual(rawLayer->getFillAntialias(), propertyValue,
@"Setting fillAntialiased to a constant value should update fill-antialias.");
XCTAssertEqualObjects(layer.fillAntialiased, styleValue,
@"fillAntialiased should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.fillAntialiased = styleValue;
propertyValue = { mbgl::style::Function<bool> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getFillAntialias(), propertyValue,
@"Setting fillAntialiased to a function should update fill-antialias.");
XCTAssertEqualObjects(layer.fillAntialiased, styleValue,
@"fillAntialiased should round-trip functions.");
layer.fillAntialiased = nil;
XCTAssertTrue(rawLayer->getFillAntialias().isUndefined(),
@"Unsetting fillAntialiased should return fill-antialias to the default value.");
XCTAssertEqualObjects(layer.fillAntialiased, defaultStyleValue,
@"fillAntialiased should return the default value after being unset.");
}
// fill-color
{
XCTAssertTrue(rawLayer->getFillColor().isUndefined(),
@"fill-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.fillColor;
MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
layer.fillColor = styleValue;
mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getFillColor(), propertyValue,
@"Setting fillColor to a constant value should update fill-color.");
XCTAssertEqualObjects(layer.fillColor, styleValue,
@"fillColor should round-trip constant values.");
styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
@18: styleValue,
}];
layer.fillColor = styleValue;
propertyValue = { mbgl::style::Function<mbgl::Color> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getFillColor(), propertyValue,
@"Setting fillColor to a function should update fill-color.");
XCTAssertEqualObjects(layer.fillColor, styleValue,
@"fillColor should round-trip functions.");
layer.fillColor = nil;
XCTAssertTrue(rawLayer->getFillColor().isUndefined(),
@"Unsetting fillColor should return fill-color to the default value.");
XCTAssertEqualObjects(layer.fillColor, defaultStyleValue,
@"fillColor should return the default value after being unset.");
}
// fill-opacity
{
XCTAssertTrue(rawLayer->getFillOpacity().isUndefined(),
@"fill-opacity should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillOpacity;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.fillOpacity = styleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue,
@"Setting fillOpacity to a constant value should update fill-opacity.");
XCTAssertEqualObjects(layer.fillOpacity, styleValue,
@"fillOpacity should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.fillOpacity = styleValue;
propertyValue = { mbgl::style::Function<float> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue,
@"Setting fillOpacity to a function should update fill-opacity.");
XCTAssertEqualObjects(layer.fillOpacity, styleValue,
@"fillOpacity should round-trip functions.");
layer.fillOpacity = nil;
XCTAssertTrue(rawLayer->getFillOpacity().isUndefined(),
@"Unsetting fillOpacity should return fill-opacity to the default value.");
XCTAssertEqualObjects(layer.fillOpacity, defaultStyleValue,
@"fillOpacity should return the default value after being unset.");
}
// fill-outline-color
{
XCTAssertTrue(rawLayer->getFillOutlineColor().isUndefined(),
@"fill-outline-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.fillOutlineColor;
MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
layer.fillOutlineColor = styleValue;
mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue,
@"Setting fillOutlineColor to a constant value should update fill-outline-color.");
XCTAssertEqualObjects(layer.fillOutlineColor, styleValue,
@"fillOutlineColor should round-trip constant values.");
styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
@18: styleValue,
}];
layer.fillOutlineColor = styleValue;
propertyValue = { mbgl::style::Function<mbgl::Color> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue,
@"Setting fillOutlineColor to a function should update fill-outline-color.");
XCTAssertEqualObjects(layer.fillOutlineColor, styleValue,
@"fillOutlineColor should round-trip functions.");
layer.fillOutlineColor = nil;
XCTAssertTrue(rawLayer->getFillOutlineColor().isUndefined(),
@"Unsetting fillOutlineColor should return fill-outline-color to the default value.");
XCTAssertEqualObjects(layer.fillOutlineColor, defaultStyleValue,
@"fillOutlineColor should return the default value after being unset.");
}
// fill-pattern
{
XCTAssertTrue(rawLayer->getFillPattern().isUndefined(),
@"fill-pattern should be unset initially.");
MGLStyleValue<NSString *> *defaultStyleValue = layer.fillPattern;
MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Fill Pattern"];
layer.fillPattern = styleValue;
mbgl::style::PropertyValue<std::string> propertyValue = { "Fill Pattern" };
XCTAssertEqual(rawLayer->getFillPattern(), propertyValue,
@"Setting fillPattern to a constant value should update fill-pattern.");
XCTAssertEqualObjects(layer.fillPattern, styleValue,
@"fillPattern should round-trip constant values.");
styleValue = [MGLStyleValue<NSString *> valueWithStops:@{
@18: styleValue,
}];
layer.fillPattern = styleValue;
propertyValue = { mbgl::style::Function<std::string> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getFillPattern(), propertyValue,
@"Setting fillPattern to a function should update fill-pattern.");
XCTAssertEqualObjects(layer.fillPattern, styleValue,
@"fillPattern should round-trip functions.");
layer.fillPattern = nil;
XCTAssertTrue(rawLayer->getFillPattern().isUndefined(),
@"Unsetting fillPattern should return fill-pattern to the default value.");
XCTAssertEqualObjects(layer.fillPattern, defaultStyleValue,
@"fillPattern should return the default value after being unset.");
}
// fill-translate
{
XCTAssertTrue(rawLayer->getFillTranslate().isUndefined(),
@"fill-translate should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillTranslation;
MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
layer.fillTranslation = styleValue;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getFillTranslate(), propertyValue,
@"Setting fillTranslation to a constant value should update fill-translate.");
XCTAssertEqualObjects(layer.fillTranslation, styleValue,
@"fillTranslation should round-trip constant values.");
styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
@18: styleValue,
}];
layer.fillTranslation = styleValue;
propertyValue = { mbgl::style::Function<std::array<float, 2>> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getFillTranslate(), propertyValue,
@"Setting fillTranslation to a function should update fill-translate.");
XCTAssertEqualObjects(layer.fillTranslation, styleValue,
@"fillTranslation should round-trip functions.");
layer.fillTranslation = nil;
XCTAssertTrue(rawLayer->getFillTranslate().isUndefined(),
@"Unsetting fillTranslation should return fill-translate to the default value.");
XCTAssertEqualObjects(layer.fillTranslation, defaultStyleValue,
@"fillTranslation should return the default value after being unset.");
}
// fill-translate-anchor
{
XCTAssertTrue(rawLayer->getFillTranslateAnchor().isUndefined(),
@"fill-translate-anchor should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillTranslationAnchor;
MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLFillTranslationAnchor:MGLFillTranslationAnchorViewport]];
layer.fillTranslationAnchor = styleValue;
mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
XCTAssertEqual(rawLayer->getFillTranslateAnchor(), propertyValue,
@"Setting fillTranslationAnchor to a constant value should update fill-translate-anchor.");
XCTAssertEqualObjects(layer.fillTranslationAnchor, styleValue,
@"fillTranslationAnchor should round-trip constant values.");
styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
@18: styleValue,
}];
layer.fillTranslationAnchor = styleValue;
propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getFillTranslateAnchor(), propertyValue,
@"Setting fillTranslationAnchor to a function should update fill-translate-anchor.");
XCTAssertEqualObjects(layer.fillTranslationAnchor, styleValue,
@"fillTranslationAnchor should round-trip functions.");
layer.fillTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getFillTranslateAnchor().isUndefined(),
@"Unsetting fillTranslationAnchor should return fill-translate-anchor to the default value.");
XCTAssertEqualObjects(layer.fillTranslationAnchor, defaultStyleValue,
@"fillTranslationAnchor should return the default value after being unset.");
}
}
- (void)testPropertyNames {
[self testPropertyName:@"is-fill-antialiased" isBoolean:YES];
[self testPropertyName:@"fill-color" isBoolean:NO];
[self testPropertyName:@"fill-opacity" isBoolean:NO];
[self testPropertyName:@"fill-outline-color" isBoolean:NO];
[self testPropertyName:@"fill-pattern" isBoolean:NO];
[self testPropertyName:@"fill-translation" isBoolean:NO];
[self testPropertyName:@"fill-translation-anchor" isBoolean:NO];
}
- (void)testValueAdditions {
XCTAssertEqual([NSValue valueWithMGLFillTranslationAnchor:MGLFillTranslationAnchorMap].MGLFillTranslationAnchorValue, MGLFillTranslationAnchorMap);
XCTAssertEqual([NSValue valueWithMGLFillTranslationAnchor:MGLFillTranslationAnchorViewport].MGLFillTranslationAnchorValue, MGLFillTranslationAnchorViewport);
}
@end

View File

@@ -1,194 +0,0 @@
#import "MGLStyleLayerTests.h"
#import "NSPredicate+MGLAdditions.h"
#import "MGLValueEvaluator.h"
@interface MGLFilterTests : MGLStyleLayerTests {
MGLShapeSource *source;
MGLLineStyleLayer *layer;
}
@end
@implementation MGLFilterTests
- (void)setUp
{
[super setUp];
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
NSURL *url = [NSURL fileURLWithPath:filePath];
NSData *geoJSONData = [NSData dataWithContentsOfURL:url];
NSError *error;
MGLShape *shape = [MGLShape shapeWithData:geoJSONData encoding:NSUTF8StringEncoding error:&error];
XCTAssertNil(error);
XCTAssertNotNil(shape);
source = [[MGLShapeSource alloc] initWithIdentifier:@"test-source" shape:shape options:nil];
[self.mapView.style addSource:source];
layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"test-layer" source:source];
}
- (void)tearDown
{
[self.mapView.style removeLayer:layer];
[self.mapView.style removeSource:source];
}
- (NSArray<NSPredicate *> *)predicates
{
NSPredicate *equalPredicate = [NSPredicate predicateWithFormat:@"type == 'neighbourhood'"];
NSPredicate *notEqualPredicate = [NSPredicate predicateWithFormat:@"type != 'park'"];
NSPredicate *greaterThanPredicate = [NSPredicate predicateWithFormat:@"%K > %@", @"stroke-width", @2.1];
NSPredicate *greaterThanOrEqualToPredicate = [NSPredicate predicateWithFormat:@"%K >= %@", @"stroke-width", @2.1];
NSPredicate *lessThanOrEqualToPredicate = [NSPredicate predicateWithFormat:@"%K <= %@", @"stroke-width", @2.1];
NSPredicate *lessThanPredicate = [NSPredicate predicateWithFormat:@"%K < %@", @"stroke-width", @2.1];
NSPredicate *inPredicate = [NSPredicate predicateWithFormat:@"type IN %@", @[@"park", @"neighbourhood"]];
NSPredicate *notInPredicate = [NSPredicate predicateWithFormat:@"NOT (type IN %@)", @[@"park", @"neighbourhood"]];
NSPredicate *inNotInPredicate = [NSPredicate predicateWithFormat:@"type IN %@ AND NOT (type IN %@)", @[@"park"], @[@"neighbourhood", @"test"]];
NSPredicate *typePredicate = [NSPredicate predicateWithFormat:@"%K == %@", @"$type", @"Feature"];
NSPredicate *idPredicate = [NSPredicate predicateWithFormat:@"%K == %@", @"$id", @"1234123"];
NSPredicate *specialCharsPredicate = [NSPredicate predicateWithFormat:@"%K == %@", @"ty-’pè", @"sŒm-ethįng"];
NSPredicate *booleanPredicate = [NSPredicate predicateWithFormat:@"cluster != YES"];
NSPredicate *nilEqualsPredicate = [NSPredicate predicateWithFormat:@"type == %@", nil];
NSPredicate *nilNotEqualsPredicate = [NSPredicate predicateWithFormat:@"type != %@", nil];
return @[
equalPredicate,
notEqualPredicate,
greaterThanPredicate,
greaterThanOrEqualToPredicate,
lessThanOrEqualToPredicate,
lessThanPredicate,
inPredicate,
notInPredicate,
inNotInPredicate,
typePredicate,
idPredicate,
specialCharsPredicate,
booleanPredicate,
nilEqualsPredicate,
nilNotEqualsPredicate
];
}
- (void)testAllPredicates
{
for (NSPredicate *predicate in self.predicates) {
layer.predicate = predicate;
XCTAssertEqualObjects(layer.predicate, predicate);
}
[self.mapView.style addLayer:layer];
}
- (void)testContainsPredicate
{
// core does not have a "contains" filter but we can achieve the equivalent by creating an `mbgl::style::InFilter`
// and searching the value for the key
NSPredicate *expectedPredicate = [NSPredicate predicateWithFormat:@"park IN %@", @[@"park", @"neighbourhood"]];
NSPredicate *containsPredicate = [NSPredicate predicateWithFormat:@"%@ CONTAINS %@", @[@"park", @"neighbourhood"], @"park"];
layer.predicate = containsPredicate;
XCTAssertEqualObjects(layer.predicate, expectedPredicate);
[self.mapView.style addLayer:layer];
}
- (void)testBetweenPredicate
{
// core does not have a "between" filter but we can achieve the equivalent by creating a set of greater than or equal / less than or equal
// filters for the lower and upper bounds (inclusive)
NSPredicate *expectedPredicate = [NSCompoundPredicate predicateWithFormat:@"%K >= 2 AND %K <= 3", @"stroke-width", @"stroke-width"];
NSPredicate *betweenPredicate = [NSPredicate predicateWithFormat:@"%K BETWEEN %@", @"stroke-width", @[@2.0, @3.0]];
layer.predicate = betweenPredicate;
XCTAssertEqualObjects(layer.predicate, expectedPredicate);
[self.mapView.style addLayer:layer];
}
- (void)testTruePredicate
{
// This comes out of the class cluster as an NSTruePredicate and it is equal to `[NSPredicate predicateWithValue:YES]`
NSPredicate *truePredicate = [NSPredicate predicateWithFormat:@"TRUEPREDICATE"];
layer.predicate = truePredicate;
XCTAssertEqualObjects(layer.predicate.description, truePredicate.description);
[self.mapView.style addLayer:layer];
}
- (void)testFalsePredicate
{
// This comes out of the class cluster as an NSFalsePredicate and it is equal to `[NSPredicate predicateWithValue:NO]`
NSPredicate *falsePredicate = [NSPredicate predicateWithFormat:@"FALSEPREDICATE"];
layer.predicate = falsePredicate;
XCTAssertEqualObjects(layer.predicate.description, falsePredicate.description);
[self.mapView.style addLayer:layer];
}
- (void)testIntermittentEncoding
{
NSPredicate *specialCharsPredicate = [NSPredicate predicateWithFormat:@"%K == %@", @"ty-’pè", @"sŒm-ethįng"];
layer.predicate = specialCharsPredicate;
NSComparisonPredicate *getPredicate = (NSComparisonPredicate *)layer.predicate;
mbgl::style::EqualsFilter filter = layer.predicate.mgl_filter.get<mbgl::style::EqualsFilter>();
id objcKey = getPredicate.leftExpression.keyPath;
id cppKey = @(filter.key.c_str());
id objcValue = mbgl::Value::visit(getPredicate.rightExpression.mgl_filterValue, ValueEvaluator());
id cppValue = mbgl::Value::visit(filter.value, ValueEvaluator());
XCTAssertEqualObjects(objcKey, cppKey);
XCTAssertEqualObjects(objcValue, cppValue);
[self.mapView.style addLayer:layer];
}
- (void)testNestedFilters
{
NSPredicate *equalPredicate = [NSPredicate predicateWithFormat:@"type == 'neighbourhood'"];
NSPredicate *notEqualPredicate = [NSPredicate predicateWithFormat:@"type != 'park'"];
NSPredicate *allPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[equalPredicate, notEqualPredicate]];
NSPredicate *anyPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[equalPredicate, notEqualPredicate]];
layer.predicate = allPredicate;
XCTAssertEqualObjects(layer.predicate, allPredicate);
layer.predicate = anyPredicate;
XCTAssertEqualObjects(layer.predicate, anyPredicate);
[self.mapView.style addLayer:layer];
}
- (void)testAndPredicates
{
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:self.predicates];
layer.predicate = predicate;
XCTAssertEqualObjects(predicate, layer.predicate);
[self.mapView.style addLayer:layer];
}
- (void)testOrPredicates
{
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:self.predicates];
layer.predicate = predicate;
XCTAssertEqualObjects(predicate, layer.predicate);
[self.mapView.style addLayer:layer];
}
- (void)testNotAndPredicates
{
NSPredicate *predicates = [NSCompoundPredicate andPredicateWithSubpredicates:self.predicates];
NSCompoundPredicate *predicate = [NSCompoundPredicate notPredicateWithSubpredicate:predicates];
layer.predicate = predicate;
XCTAssertEqualObjects(predicate, layer.predicate);
[self.mapView.style addLayer:layer];
}
- (void)testNotOrPredicates
{
NSPredicate *predicates = [NSCompoundPredicate orPredicateWithSubpredicates:self.predicates];
NSCompoundPredicate *predicate = [NSCompoundPredicate notPredicateWithSubpredicate:predicates];
layer.predicate = predicate;
XCTAssertEqualObjects(predicate, layer.predicate);
[self.mapView.style addLayer:layer];
}
@end

View File

@@ -1,106 +0,0 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLStyleLayerTests.h"
@interface MGLLineLayerTests : MGLStyleLayerTests
@end
@implementation MGLLineLayerTests
+ (NSString *)layerType {
return @"line";
}
- (void)testLineLayer {
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
NSURL *url = [NSURL fileURLWithPath:filePath];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
[self.mapView.style addSource:source];
MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
[self.mapView.style addLayer:layer];
layer.lineCap = [MGLRuntimeStylingHelper testEnum:MGLLineCapSquare type:@encode(MGLLineCap)];
layer.lineJoin = [MGLRuntimeStylingHelper testEnum:MGLLineJoinMiter type:@encode(MGLLineJoin)];
layer.lineMiterLimit = [MGLRuntimeStylingHelper testNumber];
layer.lineRoundLimit = [MGLRuntimeStylingHelper testNumber];
layer.lineBlur = [MGLRuntimeStylingHelper testNumber];
layer.lineColor = [MGLRuntimeStylingHelper testColor];
layer.lineDashPattern = [MGLRuntimeStylingHelper testDashArray];
layer.lineGapWidth = [MGLRuntimeStylingHelper testNumber];
layer.lineOffset = [MGLRuntimeStylingHelper testNumber];
layer.lineOpacity = [MGLRuntimeStylingHelper testNumber];
layer.linePattern = [MGLRuntimeStylingHelper testString];
layer.lineTranslate = [MGLRuntimeStylingHelper testOffset];
layer.lineTranslateAnchor = [MGLRuntimeStylingHelper testEnum:MGLLineTranslateAnchorViewport type:@encode(MGLLineTranslateAnchor)];
layer.lineWidth = [MGLRuntimeStylingHelper testNumber];
MGLLineStyleLayer *gLayer = (MGLLineStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"];
XCTAssertTrue([gLayer isKindOfClass:[MGLLineStyleLayer class]]);
XCTAssert([gLayer.lineCap isKindOfClass:[MGLStyleConstantValue class]]);
XCTAssertEqualObjects(gLayer.lineCap, [MGLRuntimeStylingHelper testEnum:MGLLineCapSquare type:@encode(MGLLineCap)]);
XCTAssert([gLayer.lineJoin isKindOfClass:[MGLStyleConstantValue class]]);
XCTAssertEqualObjects(gLayer.lineJoin, [MGLRuntimeStylingHelper testEnum:MGLLineJoinMiter type:@encode(MGLLineJoin)]);
XCTAssertEqualObjects(gLayer.lineMiterLimit, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.lineRoundLimit, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.lineBlur, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.lineColor, [MGLRuntimeStylingHelper testColor]);
XCTAssertEqualObjects(gLayer.lineDashPattern, [MGLRuntimeStylingHelper testDashArray]);
XCTAssertEqualObjects(gLayer.lineGapWidth, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.lineOffset, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.lineOpacity, [MGLRuntimeStylingHelper testNumber]);
XCTAssertEqualObjects(gLayer.linePattern, [MGLRuntimeStylingHelper testString]);
XCTAssertEqualObjects(gLayer.lineTranslate, [MGLRuntimeStylingHelper testOffset]);
XCTAssert([gLayer.lineTranslateAnchor isKindOfClass:[MGLStyleConstantValue class]]);
XCTAssertEqualObjects(gLayer.lineTranslateAnchor, [MGLRuntimeStylingHelper testEnum:MGLLineTranslateAnchorViewport type:@encode(MGLLineTranslateAnchor)]);
XCTAssertEqualObjects(gLayer.lineWidth, [MGLRuntimeStylingHelper testNumber]);
layer.lineCap = [MGLRuntimeStylingHelper testEnumFunction:MGLLineCapSquare type:@encode(MGLLineCap)];
layer.lineJoin = [MGLRuntimeStylingHelper testEnumFunction:MGLLineJoinMiter type:@encode(MGLLineJoin)];
layer.lineMiterLimit = [MGLRuntimeStylingHelper testNumberFunction];
layer.lineRoundLimit = [MGLRuntimeStylingHelper testNumberFunction];
layer.lineBlur = [MGLRuntimeStylingHelper testNumberFunction];
layer.lineColor = [MGLRuntimeStylingHelper testColorFunction];
layer.lineDashPattern = [MGLRuntimeStylingHelper testDashArrayFunction];
layer.lineGapWidth = [MGLRuntimeStylingHelper testNumberFunction];
layer.lineOffset = [MGLRuntimeStylingHelper testNumberFunction];
layer.lineOpacity = [MGLRuntimeStylingHelper testNumberFunction];
layer.linePattern = [MGLRuntimeStylingHelper testStringFunction];
layer.lineTranslate = [MGLRuntimeStylingHelper testOffsetFunction];
layer.lineTranslateAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLLineTranslateAnchorViewport type:@encode(MGLLineTranslateAnchor)];
layer.lineWidth = [MGLRuntimeStylingHelper testNumberFunction];
XCTAssertEqualObjects(gLayer.lineCap, [MGLRuntimeStylingHelper testEnumFunction:MGLLineCapSquare type:@encode(MGLLineCap)]);
XCTAssertEqualObjects(gLayer.lineJoin, [MGLRuntimeStylingHelper testEnumFunction:MGLLineJoinMiter type:@encode(MGLLineJoin)]);
XCTAssertEqualObjects(gLayer.lineMiterLimit, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.lineRoundLimit, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.lineBlur, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.lineColor, [MGLRuntimeStylingHelper testColorFunction]);
XCTAssertEqualObjects(gLayer.lineDashPattern, [MGLRuntimeStylingHelper testDashArrayFunction]);
XCTAssertEqualObjects(gLayer.lineGapWidth, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.lineOffset, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.lineOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
XCTAssertEqualObjects(gLayer.linePattern, [MGLRuntimeStylingHelper testStringFunction]);
XCTAssertEqualObjects(gLayer.lineTranslate, [MGLRuntimeStylingHelper testOffsetFunction]);
XCTAssertEqualObjects(gLayer.lineTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLLineTranslateAnchorViewport type:@encode(MGLLineTranslateAnchor)]);
XCTAssertEqualObjects(gLayer.lineWidth, [MGLRuntimeStylingHelper testNumberFunction]);
}
- (void)testPropertyNames {
[self testPropertyName:@"line-cap" isBoolean:NO];
[self testPropertyName:@"line-join" isBoolean:NO];
[self testPropertyName:@"line-miter-limit" isBoolean:NO];
[self testPropertyName:@"line-round-limit" isBoolean:NO];
[self testPropertyName:@"line-blur" isBoolean:NO];
[self testPropertyName:@"line-color" isBoolean:NO];
[self testPropertyName:@"line-dash-pattern" isBoolean:NO];
[self testPropertyName:@"line-gap-width" isBoolean:NO];
[self testPropertyName:@"line-offset" isBoolean:NO];
[self testPropertyName:@"line-opacity" isBoolean:NO];
[self testPropertyName:@"line-pattern" isBoolean:NO];
[self testPropertyName:@"line-translate" isBoolean:NO];
[self testPropertyName:@"line-translate-anchor" isBoolean:NO];
[self testPropertyName:@"line-width" isBoolean:NO];
}
@end

View File

@@ -0,0 +1,557 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLStyleLayerTests.h"
#import "MGLStyleLayer_Private.h"
#include <mbgl/style/layers/line_layer.hpp>
@interface MGLLineLayerTests : MGLStyleLayerTests
@end
@implementation MGLLineLayerTests
+ (NSString *)layerType {
return @"line";
}
- (void)testPredicates {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
XCTAssertNil(layer.sourceLayerIdentifier);
layer.sourceLayerIdentifier = @"layerID";
XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
layer.sourceLayerIdentifier = nil;
XCTAssertNil(layer.sourceLayerIdentifier);
XCTAssertNil(layer.predicate);
layer.predicate = [NSPredicate predicateWithValue:NO];
XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
layer.predicate = nil;
XCTAssertNil(layer.predicate);
}
- (void)testProperties {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
XCTAssertNotEqual(layer.rawLayer, nullptr);
XCTAssertTrue(layer.rawLayer->is<mbgl::style::LineLayer>());
auto rawLayer = layer.rawLayer->as<mbgl::style::LineLayer>();
// line-cap
{
XCTAssertTrue(rawLayer->getLineCap().isUndefined(),
@"line-cap should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineCap;
MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineCap:MGLLineCapSquare]];
layer.lineCap = styleValue;
mbgl::style::PropertyValue<mbgl::style::LineCapType> propertyValue = { mbgl::style::LineCapType::Square };
XCTAssertEqual(rawLayer->getLineCap(), propertyValue,
@"Setting lineCap to a constant value should update line-cap.");
XCTAssertEqualObjects(layer.lineCap, styleValue,
@"lineCap should round-trip constant values.");
styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
@18: styleValue,
}];
layer.lineCap = styleValue;
propertyValue = { mbgl::style::Function<mbgl::style::LineCapType> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getLineCap(), propertyValue,
@"Setting lineCap to a function should update line-cap.");
XCTAssertEqualObjects(layer.lineCap, styleValue,
@"lineCap should round-trip functions.");
layer.lineCap = nil;
XCTAssertTrue(rawLayer->getLineCap().isUndefined(),
@"Unsetting lineCap should return line-cap to the default value.");
XCTAssertEqualObjects(layer.lineCap, defaultStyleValue,
@"lineCap should return the default value after being unset.");
}
// line-join
{
XCTAssertTrue(rawLayer->getLineJoin().isUndefined(),
@"line-join should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineJoin;
MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineJoin:MGLLineJoinMiter]];
layer.lineJoin = styleValue;
mbgl::style::PropertyValue<mbgl::style::LineJoinType> propertyValue = { mbgl::style::LineJoinType::Miter };
XCTAssertEqual(rawLayer->getLineJoin(), propertyValue,
@"Setting lineJoin to a constant value should update line-join.");
XCTAssertEqualObjects(layer.lineJoin, styleValue,
@"lineJoin should round-trip constant values.");
styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
@18: styleValue,
}];
layer.lineJoin = styleValue;
propertyValue = { mbgl::style::Function<mbgl::style::LineJoinType> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getLineJoin(), propertyValue,
@"Setting lineJoin to a function should update line-join.");
XCTAssertEqualObjects(layer.lineJoin, styleValue,
@"lineJoin should round-trip functions.");
layer.lineJoin = nil;
XCTAssertTrue(rawLayer->getLineJoin().isUndefined(),
@"Unsetting lineJoin should return line-join to the default value.");
XCTAssertEqualObjects(layer.lineJoin, defaultStyleValue,
@"lineJoin should return the default value after being unset.");
}
// line-miter-limit
{
XCTAssertTrue(rawLayer->getLineMiterLimit().isUndefined(),
@"line-miter-limit should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineMiterLimit;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.lineMiterLimit = styleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineMiterLimit(), propertyValue,
@"Setting lineMiterLimit to a constant value should update line-miter-limit.");
XCTAssertEqualObjects(layer.lineMiterLimit, styleValue,
@"lineMiterLimit should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.lineMiterLimit = styleValue;
propertyValue = { mbgl::style::Function<float> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getLineMiterLimit(), propertyValue,
@"Setting lineMiterLimit to a function should update line-miter-limit.");
XCTAssertEqualObjects(layer.lineMiterLimit, styleValue,
@"lineMiterLimit should round-trip functions.");
layer.lineMiterLimit = nil;
XCTAssertTrue(rawLayer->getLineMiterLimit().isUndefined(),
@"Unsetting lineMiterLimit should return line-miter-limit to the default value.");
XCTAssertEqualObjects(layer.lineMiterLimit, defaultStyleValue,
@"lineMiterLimit should return the default value after being unset.");
}
// line-round-limit
{
XCTAssertTrue(rawLayer->getLineRoundLimit().isUndefined(),
@"line-round-limit should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineRoundLimit;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.lineRoundLimit = styleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineRoundLimit(), propertyValue,
@"Setting lineRoundLimit to a constant value should update line-round-limit.");
XCTAssertEqualObjects(layer.lineRoundLimit, styleValue,
@"lineRoundLimit should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.lineRoundLimit = styleValue;
propertyValue = { mbgl::style::Function<float> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getLineRoundLimit(), propertyValue,
@"Setting lineRoundLimit to a function should update line-round-limit.");
XCTAssertEqualObjects(layer.lineRoundLimit, styleValue,
@"lineRoundLimit should round-trip functions.");
layer.lineRoundLimit = nil;
XCTAssertTrue(rawLayer->getLineRoundLimit().isUndefined(),
@"Unsetting lineRoundLimit should return line-round-limit to the default value.");
XCTAssertEqualObjects(layer.lineRoundLimit, defaultStyleValue,
@"lineRoundLimit should return the default value after being unset.");
}
// line-blur
{
XCTAssertTrue(rawLayer->getLineBlur().isUndefined(),
@"line-blur should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineBlur;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.lineBlur = styleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineBlur(), propertyValue,
@"Setting lineBlur to a constant value should update line-blur.");
XCTAssertEqualObjects(layer.lineBlur, styleValue,
@"lineBlur should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.lineBlur = styleValue;
propertyValue = { mbgl::style::Function<float> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getLineBlur(), propertyValue,
@"Setting lineBlur to a function should update line-blur.");
XCTAssertEqualObjects(layer.lineBlur, styleValue,
@"lineBlur should round-trip functions.");
layer.lineBlur = nil;
XCTAssertTrue(rawLayer->getLineBlur().isUndefined(),
@"Unsetting lineBlur should return line-blur to the default value.");
XCTAssertEqualObjects(layer.lineBlur, defaultStyleValue,
@"lineBlur should return the default value after being unset.");
}
// line-color
{
XCTAssertTrue(rawLayer->getLineColor().isUndefined(),
@"line-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.lineColor;
MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
layer.lineColor = styleValue;
mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getLineColor(), propertyValue,
@"Setting lineColor to a constant value should update line-color.");
XCTAssertEqualObjects(layer.lineColor, styleValue,
@"lineColor should round-trip constant values.");
styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
@18: styleValue,
}];
layer.lineColor = styleValue;
propertyValue = { mbgl::style::Function<mbgl::Color> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getLineColor(), propertyValue,
@"Setting lineColor to a function should update line-color.");
XCTAssertEqualObjects(layer.lineColor, styleValue,
@"lineColor should round-trip functions.");
layer.lineColor = nil;
XCTAssertTrue(rawLayer->getLineColor().isUndefined(),
@"Unsetting lineColor should return line-color to the default value.");
XCTAssertEqualObjects(layer.lineColor, defaultStyleValue,
@"lineColor should return the default value after being unset.");
}
// line-dasharray
{
XCTAssertTrue(rawLayer->getLineDasharray().isUndefined(),
@"line-dasharray should be unset initially.");
MGLStyleValue<NSArray<NSNumber *> *> *defaultStyleValue = layer.lineDashPattern;
MGLStyleValue<NSArray<NSNumber *> *> *styleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithRawValue:@[@1, @2]];
layer.lineDashPattern = styleValue;
mbgl::style::PropertyValue<std::vector<float>> propertyValue = { {1, 2} };
XCTAssertEqual(rawLayer->getLineDasharray(), propertyValue,
@"Setting lineDashPattern to a constant value should update line-dasharray.");
XCTAssertEqualObjects(layer.lineDashPattern, styleValue,
@"lineDashPattern should round-trip constant values.");
styleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithStops:@{
@18: styleValue,
}];
layer.lineDashPattern = styleValue;
propertyValue = { mbgl::style::Function<std::vector<float>> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getLineDasharray(), propertyValue,
@"Setting lineDashPattern to a function should update line-dasharray.");
XCTAssertEqualObjects(layer.lineDashPattern, styleValue,
@"lineDashPattern should round-trip functions.");
layer.lineDashPattern = nil;
XCTAssertTrue(rawLayer->getLineDasharray().isUndefined(),
@"Unsetting lineDashPattern should return line-dasharray to the default value.");
XCTAssertEqualObjects(layer.lineDashPattern, defaultStyleValue,
@"lineDashPattern should return the default value after being unset.");
}
// line-gap-width
{
XCTAssertTrue(rawLayer->getLineGapWidth().isUndefined(),
@"line-gap-width should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineGapWidth;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.lineGapWidth = styleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue,
@"Setting lineGapWidth to a constant value should update line-gap-width.");
XCTAssertEqualObjects(layer.lineGapWidth, styleValue,
@"lineGapWidth should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.lineGapWidth = styleValue;
propertyValue = { mbgl::style::Function<float> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue,
@"Setting lineGapWidth to a function should update line-gap-width.");
XCTAssertEqualObjects(layer.lineGapWidth, styleValue,
@"lineGapWidth should round-trip functions.");
layer.lineGapWidth = nil;
XCTAssertTrue(rawLayer->getLineGapWidth().isUndefined(),
@"Unsetting lineGapWidth should return line-gap-width to the default value.");
XCTAssertEqualObjects(layer.lineGapWidth, defaultStyleValue,
@"lineGapWidth should return the default value after being unset.");
}
// line-offset
{
XCTAssertTrue(rawLayer->getLineOffset().isUndefined(),
@"line-offset should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineOffset;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.lineOffset = styleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineOffset(), propertyValue,
@"Setting lineOffset to a constant value should update line-offset.");
XCTAssertEqualObjects(layer.lineOffset, styleValue,
@"lineOffset should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.lineOffset = styleValue;
propertyValue = { mbgl::style::Function<float> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getLineOffset(), propertyValue,
@"Setting lineOffset to a function should update line-offset.");
XCTAssertEqualObjects(layer.lineOffset, styleValue,
@"lineOffset should round-trip functions.");
layer.lineOffset = nil;
XCTAssertTrue(rawLayer->getLineOffset().isUndefined(),
@"Unsetting lineOffset should return line-offset to the default value.");
XCTAssertEqualObjects(layer.lineOffset, defaultStyleValue,
@"lineOffset should return the default value after being unset.");
}
// line-opacity
{
XCTAssertTrue(rawLayer->getLineOpacity().isUndefined(),
@"line-opacity should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineOpacity;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.lineOpacity = styleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue,
@"Setting lineOpacity to a constant value should update line-opacity.");
XCTAssertEqualObjects(layer.lineOpacity, styleValue,
@"lineOpacity should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.lineOpacity = styleValue;
propertyValue = { mbgl::style::Function<float> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue,
@"Setting lineOpacity to a function should update line-opacity.");
XCTAssertEqualObjects(layer.lineOpacity, styleValue,
@"lineOpacity should round-trip functions.");
layer.lineOpacity = nil;
XCTAssertTrue(rawLayer->getLineOpacity().isUndefined(),
@"Unsetting lineOpacity should return line-opacity to the default value.");
XCTAssertEqualObjects(layer.lineOpacity, defaultStyleValue,
@"lineOpacity should return the default value after being unset.");
}
// line-pattern
{
XCTAssertTrue(rawLayer->getLinePattern().isUndefined(),
@"line-pattern should be unset initially.");
MGLStyleValue<NSString *> *defaultStyleValue = layer.linePattern;
MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Line Pattern"];
layer.linePattern = styleValue;
mbgl::style::PropertyValue<std::string> propertyValue = { "Line Pattern" };
XCTAssertEqual(rawLayer->getLinePattern(), propertyValue,
@"Setting linePattern to a constant value should update line-pattern.");
XCTAssertEqualObjects(layer.linePattern, styleValue,
@"linePattern should round-trip constant values.");
styleValue = [MGLStyleValue<NSString *> valueWithStops:@{
@18: styleValue,
}];
layer.linePattern = styleValue;
propertyValue = { mbgl::style::Function<std::string> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getLinePattern(), propertyValue,
@"Setting linePattern to a function should update line-pattern.");
XCTAssertEqualObjects(layer.linePattern, styleValue,
@"linePattern should round-trip functions.");
layer.linePattern = nil;
XCTAssertTrue(rawLayer->getLinePattern().isUndefined(),
@"Unsetting linePattern should return line-pattern to the default value.");
XCTAssertEqualObjects(layer.linePattern, defaultStyleValue,
@"linePattern should return the default value after being unset.");
}
// line-translate
{
XCTAssertTrue(rawLayer->getLineTranslate().isUndefined(),
@"line-translate should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineTranslation;
MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
layer.lineTranslation = styleValue;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getLineTranslate(), propertyValue,
@"Setting lineTranslation to a constant value should update line-translate.");
XCTAssertEqualObjects(layer.lineTranslation, styleValue,
@"lineTranslation should round-trip constant values.");
styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
@18: styleValue,
}];
layer.lineTranslation = styleValue;
propertyValue = { mbgl::style::Function<std::array<float, 2>> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getLineTranslate(), propertyValue,
@"Setting lineTranslation to a function should update line-translate.");
XCTAssertEqualObjects(layer.lineTranslation, styleValue,
@"lineTranslation should round-trip functions.");
layer.lineTranslation = nil;
XCTAssertTrue(rawLayer->getLineTranslate().isUndefined(),
@"Unsetting lineTranslation should return line-translate to the default value.");
XCTAssertEqualObjects(layer.lineTranslation, defaultStyleValue,
@"lineTranslation should return the default value after being unset.");
}
// line-translate-anchor
{
XCTAssertTrue(rawLayer->getLineTranslateAnchor().isUndefined(),
@"line-translate-anchor should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineTranslationAnchor;
MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineTranslationAnchor:MGLLineTranslationAnchorViewport]];
layer.lineTranslationAnchor = styleValue;
mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
XCTAssertEqual(rawLayer->getLineTranslateAnchor(), propertyValue,
@"Setting lineTranslationAnchor to a constant value should update line-translate-anchor.");
XCTAssertEqualObjects(layer.lineTranslationAnchor, styleValue,
@"lineTranslationAnchor should round-trip constant values.");
styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
@18: styleValue,
}];
layer.lineTranslationAnchor = styleValue;
propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getLineTranslateAnchor(), propertyValue,
@"Setting lineTranslationAnchor to a function should update line-translate-anchor.");
XCTAssertEqualObjects(layer.lineTranslationAnchor, styleValue,
@"lineTranslationAnchor should round-trip functions.");
layer.lineTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getLineTranslateAnchor().isUndefined(),
@"Unsetting lineTranslationAnchor should return line-translate-anchor to the default value.");
XCTAssertEqualObjects(layer.lineTranslationAnchor, defaultStyleValue,
@"lineTranslationAnchor should return the default value after being unset.");
}
// line-width
{
XCTAssertTrue(rawLayer->getLineWidth().isUndefined(),
@"line-width should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineWidth;
MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.lineWidth = styleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
@"Setting lineWidth to a constant value should update line-width.");
XCTAssertEqualObjects(layer.lineWidth, styleValue,
@"lineWidth should round-trip constant values.");
styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
@18: styleValue,
}];
layer.lineWidth = styleValue;
propertyValue = { mbgl::style::Function<float> {
{{ 18, propertyValue.asConstant() }},
1,
}};
XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
@"Setting lineWidth to a function should update line-width.");
XCTAssertEqualObjects(layer.lineWidth, styleValue,
@"lineWidth should round-trip functions.");
layer.lineWidth = nil;
XCTAssertTrue(rawLayer->getLineWidth().isUndefined(),
@"Unsetting lineWidth should return line-width to the default value.");
XCTAssertEqualObjects(layer.lineWidth, defaultStyleValue,
@"lineWidth should return the default value after being unset.");
}
}
- (void)testPropertyNames {
[self testPropertyName:@"line-cap" isBoolean:NO];
[self testPropertyName:@"line-join" isBoolean:NO];
[self testPropertyName:@"line-miter-limit" isBoolean:NO];
[self testPropertyName:@"line-round-limit" isBoolean:NO];
[self testPropertyName:@"line-blur" isBoolean:NO];
[self testPropertyName:@"line-color" isBoolean:NO];
[self testPropertyName:@"line-dash-pattern" isBoolean:NO];
[self testPropertyName:@"line-gap-width" isBoolean:NO];
[self testPropertyName:@"line-offset" isBoolean:NO];
[self testPropertyName:@"line-opacity" isBoolean:NO];
[self testPropertyName:@"line-pattern" isBoolean:NO];
[self testPropertyName:@"line-translation" isBoolean:NO];
[self testPropertyName:@"line-translation-anchor" isBoolean:NO];
[self testPropertyName:@"line-width" isBoolean:NO];
}
- (void)testValueAdditions {
XCTAssertEqual([NSValue valueWithMGLLineCap:MGLLineCapButt].MGLLineCapValue, MGLLineCapButt);
XCTAssertEqual([NSValue valueWithMGLLineCap:MGLLineCapRound].MGLLineCapValue, MGLLineCapRound);
XCTAssertEqual([NSValue valueWithMGLLineCap:MGLLineCapSquare].MGLLineCapValue, MGLLineCapSquare);
XCTAssertEqual([NSValue valueWithMGLLineJoin:MGLLineJoinBevel].MGLLineJoinValue, MGLLineJoinBevel);
XCTAssertEqual([NSValue valueWithMGLLineJoin:MGLLineJoinRound].MGLLineJoinValue, MGLLineJoinRound);
XCTAssertEqual([NSValue valueWithMGLLineJoin:MGLLineJoinMiter].MGLLineJoinValue, MGLLineJoinMiter);
XCTAssertEqual([NSValue valueWithMGLLineTranslationAnchor:MGLLineTranslationAnchorMap].MGLLineTranslationAnchorValue, MGLLineTranslationAnchorMap);
XCTAssertEqual([NSValue valueWithMGLLineTranslationAnchor:MGLLineTranslationAnchorViewport].MGLLineTranslationAnchorValue, MGLLineTranslationAnchorViewport);
}
@end

View File

@@ -0,0 +1,42 @@
#import <XCTest/XCTest.h>
#import "NSString+MGLAdditions.h"
@interface MGLNSStringAdditionsTests : XCTestCase
@end
@implementation MGLNSStringAdditionsTests
- (void)testTitleCasedString {
NSLocale *locale = [NSLocale currentLocale];
XCTAssertEqualObjects([@"© OpenStreetMap" mgl_titleCasedStringWithLocale:locale], @"© OpenStreetMap");
XCTAssertEqualObjects([@"© OSM" mgl_titleCasedStringWithLocale:locale], @"© OSM");
XCTAssertEqualObjects([@"Improve this map" mgl_titleCasedStringWithLocale:locale], @"Improve This Map");
XCTAssertEqualObjects([@"Improve This Map" mgl_titleCasedStringWithLocale:locale], @"Improve This Map");
XCTAssertEqualObjects([@"Improve the map" mgl_titleCasedStringWithLocale:locale], @"Improve the Map");
XCTAssertEqualObjects([@"Improve The Map" mgl_titleCasedStringWithLocale:locale], @"Improve The Map");
XCTAssertEqualObjects([@"Improve a map" mgl_titleCasedStringWithLocale:locale], @"Improve a Map");
XCTAssertEqualObjects([@"Improve A Map" mgl_titleCasedStringWithLocale:locale], @"Improve A Map");
XCTAssertEqualObjects([@"Improve for the map" mgl_titleCasedStringWithLocale:locale], @"Improve for the Map");
XCTAssertEqualObjects([@"Improve For The Map" mgl_titleCasedStringWithLocale:locale], @"Improve For The Map");
XCTAssertEqualObjects([@"Improve and map" mgl_titleCasedStringWithLocale:locale], @"Improve and Map");
XCTAssertEqualObjects([@"Improve And Map" mgl_titleCasedStringWithLocale:locale], @"Improve And Map");
XCTAssertEqualObjects([@"Improve while mapping" mgl_titleCasedStringWithLocale:locale], @"Improve While Mapping");
XCTAssertEqualObjects([@"Improve While Mapping" mgl_titleCasedStringWithLocale:locale], @"Improve While Mapping");
XCTAssertEqualObjects([@"Improve with the map" mgl_titleCasedStringWithLocale:locale], @"Improve With the Map");
XCTAssertEqualObjects([@"Improve With The Map" mgl_titleCasedStringWithLocale:locale], @"Improve With The Map");
XCTAssertEqualObjects([@"Improve this iPhone" mgl_titleCasedStringWithLocale:locale], @"Improve This iPhone");
XCTAssertEqualObjects([@"Improve This iPhone" mgl_titleCasedStringWithLocale:locale], @"Improve This iPhone");
}
@end

Some files were not shown because too many files have changed in this diff Show More