[iOS][macOS] Add ImageSource bindings

This commit is contained in:
Asheem Mamoowala
2017-05-25 14:36:05 -07:00
parent 7b05606464
commit ab5b310a9e
40 changed files with 788 additions and 39 deletions

View File

@@ -0,0 +1,81 @@
#include "image_source.hpp"
// Java -> C++ conversion
#include "../android_conversion.hpp"
// C++ -> Java conversion
#include "../../conversion/conversion.hpp"
#include <mbgl/style/conversion.hpp>
#include <string>
namespace mbgl {
namespace android {
ImageSource::ImageSource(jni::JNIEnv& env, jni::String sourceId)
: Source(env, std::make_unique<mbgl::style::ImageSource>(
jni::Make<std::string>(env, sourceId)
)
) {
}
ImageSource::ImageSource(mbgl::Map& map, mbgl::style::ImageSource& coreSource)
: Source(map, coreSource) {
}
ImageSource::~ImageSource() = default;
void GeoJSONSource::setGeoJSONString(jni::JNIEnv& env, jni::String json) {
using namespace mbgl::style::conversion;
// Convert the jni object
Error error;
optional<GeoJSON> converted = convert<GeoJSON>(Value(env, json), error);
if(!converted) {
mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + error.message);
return;
}
// Update the core source
source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(*converted);
}
void ImageSource::setURL(jni::JNIEnv& env, jni::String url) {
// Update the core source
source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setURL(jni::Make<std::string>(env, url));
}
jni::String ImageSource::getURL(jni::JNIEnv& env) {
std::string url = source.as<mbgl::style::ImageSource>()->ImageSource::getURL();
return !url.empty() ? jni::Make<jni::String>(env, url) : jni::String();
}
jni::Class<ImageSource> ImageSource::javaClass;
jni::jobject* ImageSource::createJavaPeer(jni::JNIEnv& env) {
static auto constructor = ImageSource::javaClass.template GetConstructor<jni::jlong>(env);
return ImageSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
}
void ImageSource::registerNative(jni::JNIEnv& env) {
// Lookup the class
ImageSource::javaClass = *jni::Class<ImageSource>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
// Register the peer
jni::RegisterNativePeer<ImageSource>(
env, ImageSource::javaClass, "nativePtr",
std::make_unique<ImageSource, JNIEnv&, jni::String, jni::Object<>>,
"initialize",
"finalize",
METHOD(&ImageSource::setGeoJSONString, "nativeSetGeoJsonString"),
METHOD(&ImageSource::setURL, "nativeSetUrl"),
METHOD(&ImageSource::getURL, "nativeGetUrl"),
METHOD(&ImageSource::getURL, "nativeGetUrl"),
);
}
} // namespace android
} // namespace mbgl

View File

@@ -0,0 +1,33 @@
#pragma once
#include "source.hpp"
#include <mbgl/style/sources/image_source.hpp>
#include <jni/jni.hpp>
namespace mbgl {
namespace android {
class ImageSource : public Source {
public:
static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/ImageSource"; };
static jni::Class<ImageSource> javaClass;
static void registerNative(jni::JNIEnv&);
ImageSource(jni::JNIEnv&, jni::String, jni::Object<>);
ImageSource(mbgl::Map&, mbgl::style::ImageSource&);
~ImageSource();
void setURL(jni::JNIEnv&, jni::String);
jni::String getURL(jni::JNIEnv&);
jni::jobject* createJavaPeer(jni::JNIEnv&);
}; // class ImageSource
} // namespace android
} // namespace mbgl

View File

@@ -45,6 +45,23 @@ typedef struct MGLCoordinateBounds {
CLLocationCoordinate2D ne;
} MGLCoordinateBounds;
/**
A quadrilateral area as measured on a two-dimensional map projection.
`MGLCoordinateQuad` differs from `MGLCoordinateBounds` in that it allows
representation of non-axis aligned bounds and non-rectangular quadrilaterals
*/
typedef struct MGLCoordinateQuad {
/** Coordinate at the top left corner. */
CLLocationCoordinate2D topLeft;
/** Coordinate at the top right corner. */
CLLocationCoordinate2D topRight;
/** Coordinate at the bottom right corner. */
CLLocationCoordinate2D bottomRight;
/** Coordinate at the bottom left corner. */
CLLocationCoordinate2D bottomLeft;
} MGLCoordinateQuad;
/**
Creates a new `MGLCoordinateBounds` structure from the given southwest and
northeast coordinates.

View File

@@ -8,6 +8,7 @@
#import <mbgl/util/geo.hpp>
#import <mbgl/util/geometry.hpp>
#import <array>
typedef double MGLLocationRadians;
typedef double MGLRadianDistance;
typedef double MGLRadianDirection;
@@ -56,6 +57,27 @@ NS_INLINE mbgl::LatLngBounds MGLLatLngBoundsFromCoordinateBounds(MGLCoordinateBo
MGLLatLngFromLocationCoordinate2D(coordinateBounds.ne));
}
NS_INLINE std::array<mbgl::LatLng, 4> MGLLatLngArrayFromCoordinateQuad(MGLCoordinateQuad quad) {
return { MGLLatLngFromLocationCoordinate2D(quad.topLeft),
MGLLatLngFromLocationCoordinate2D(quad.topRight),
MGLLatLngFromLocationCoordinate2D(quad.bottomRight),
MGLLatLngFromLocationCoordinate2D(quad.bottomLeft) };
}
NS_INLINE MGLCoordinateQuad MGLCoordinateQuadFromLatLngArray(std::array<mbgl::LatLng, 4> quad) {
return { MGLLocationCoordinate2DFromLatLng(quad[0]),
MGLLocationCoordinate2DFromLatLng(quad[1]),
MGLLocationCoordinate2DFromLatLng(quad[2]),
MGLLocationCoordinate2DFromLatLng(quad[3]) };
}
NS_INLINE MGLCoordinateQuad MGLCoordinateQuadFromCoordinateBounds(MGLCoordinateBounds bounds) {
return { { bounds.ne.latitude, bounds.sw.longitude },
bounds.ne,
{ bounds.sw.latitude, bounds.ne.longitude },
bounds.sw };
}
#if TARGET_OS_IPHONE
NS_INLINE mbgl::EdgeInsets MGLEdgeInsetsFromNSEdgeInsets(UIEdgeInsets insets) {
return { insets.top, insets.left, insets.bottom, insets.right };

View File

@@ -0,0 +1,135 @@
#import "MGLSource.h"
#import "MGLFoundation.h"
#import "MGLTypes.h"
#import "MGLGeometry.h"
NS_ASSUME_NONNULL_BEGIN
MGL_EXPORT
/**
`MGLImageSource` is a map content source that supplies a georeferenced raster
image to be shown on the map. The geographic location of the raster image content,
supplied with `MGLCoordinateQuad`, can be non-axis aligned.
`MGLImageSource` supports raster content from `NSURL` or an `MGLImage`.
Supported image formats are : PNG, TIFF, JPEG, GIF (single frame rendering),
and BMP.
An image source is added to an `MGLStyle` object along with one or more
`MGLRasterStyleLayer` objects. Use a raster style layer to control the
appearance of content supplied by the image source.
Each
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-image"><code>image</code></a>
source defined by the style JSON file is represented at runtime by an
`MGLImageSource` 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 coordinates: MGLCoordinateQuad = MGLCoordinateQuad(
topLeft: CLLocationCoordinate2D(latitude: 46.437, longitude: -80.425),
topRight: CLLocationCoordinate2D(latitude: 46.437, longitude: -71.516),
bottomRight: CLLocationCoordinate2D(latitude: 37.936, longitude: -71.516),
bottomLeft: CLLocationCoordinate2D(latitude: 37.936, longitude: -80.425))
let source = MGLImageSource(identifier: "images", coordinates: coordinates, imageURL: URL(string: "https://www.mapbox.com/mapbox-gl-js/assets/radar.gif")!)
mapView.style?.addSource(source)
```
*/
@interface MGLImageSource : MGLSource
#pragma mark Initializing a Source
/**
Returns a georeferenced image source with an identifier and coordinates
@param identifier A string that uniquely identifies the source.
@param coordinateQuad The top left, top right, bottom right, and bottom left coordinates for the image.
@return An initialized image source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier coordinates:(MGLCoordinateQuad)coordinateQuad NS_DESIGNATED_INITIALIZER;
/**
Returns a georeferenced image source with an identifier, coordinates and a URL
@param identifier A string that uniquely identifies the source.
@param coordinateQuad the top left, top right, bottom right, and bottom left coordinates for the image.
@param url An HTTP(S) URL, absolute file URL, or local file URL relative to the
current application’s resource bundle.
@return An initialized shape source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier coordinates:(MGLCoordinateQuad)coordinateQuad imageURL:(NSURL *)url;
/**
Returns a georeferenced image source with an identifier, coordinates and an image
@param identifier A string that uniquely identifies the source.
@param coordinateQuad The top left, top right, bottom right, and bottom left coordinates for the image.
@param image The image to display for the sourcde.
@return An initialized shape source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier coordinates:(MGLCoordinateQuad)coordinateQuad image:(MGLImage *)image;
/**
Returns a georeferenced image source with an identifier and coordinates
@param identifier A string that uniquely identifies the source.
@param bounds The aligned coordinate bounds for the image.
@return An initialized image source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier bounds:(MGLCoordinateBounds)bounds;
/**
Returns a georeferenced image source with an identifier, coordinates and a URL
@param identifier A string that uniquely identifies the source.
@param bounds The aligned coordinate bounds for the image.@param url An HTTP(S) URL, absolute file URL, or local file URL relative to the
current application’s resource bundle.
@return An initialized shape source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier bounds:(MGLCoordinateBounds)bounds imageURL:(NSURL *)url;
/**
Returns a georeferenced image source with an identifier, coordinates and an image
@param identifier A string that uniquely identifies the source.
@param bounds The aligned coordinate bounds for the image.
@param image The image to display for the sourcde.
@return An initialized shape source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier bounds:(MGLCoordinateBounds)bounds image:(MGLImage *)image;
#pragma mark Accessing a Source’s Content
/**
The URL to the source image.
If the receiver was initialized using `-initWithIdentifier:coordinates:` or
`-initWithIdentifier:coordinates:image:`, or the `image` property is set,
this property is set to `nil`.
*/
@property (nonatomic, copy, nullable)NSURL *URL;
/**
The source image.
If the receiver was initialized using `-initWithIdentifier:coordinates:` or
`-initWithIdentifier:coordinates:imageURL:`, or if the `URL` property is set,
this property is set to `nil`.
*/
@property (nonatomic, retain, nullable)MGLImage *image;
/**
The coordinates at which the source image will be placed.
If the receiver was initialized using `-initWithIdentifier:bounds:`,
`-initWithIdentifier:bounds:image:`, or `initWithIdentifier:bounds:imageURL`,
the bounds will be converted to an `MGLCoordinateQuad`.
*/
@property (nonatomic) MGLCoordinateQuad coordinates;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,105 @@
#import "MGLImageSource_Private.h"
#import "MGLGeometry_Private.h"
#import "MGLSource_Private.h"
#import "MGLTileSource_Private.h"
#import "NSURL+MGLAdditions.h"
#if TARGET_OS_IPHONE
#import "UIImage+MGLAdditions.h"
#else
#import "NSImage+MGLAdditions.h"
#endif
#include <mbgl/style/sources/image_source.hpp>
#include <mbgl/util/premultiply.hpp>
@interface MGLImageSource ()
@property (nonatomic, readonly) mbgl::style::ImageSource *rawSource;
@end
@implementation MGLImageSource
- (instancetype)initWithIdentifier:(NSString *)identifier coordinates:(MGLCoordinateQuad)coordinateQuad {
const auto coordsArray = MGLLatLngArrayFromCoordinateQuad(coordinateQuad);
auto source = std::make_unique<mbgl::style::ImageSource>(identifier.UTF8String, coordsArray);
return self = [super initWithPendingSource:std::move(source)];
}
- (instancetype)initWithIdentifier:(NSString *)identifier coordinates:(MGLCoordinateQuad)coordinateQuad imageURL:(NSURL *)url {
self = [self initWithIdentifier:identifier coordinates: coordinateQuad];
self.URL = url;
return self;
}
- (instancetype)initWithIdentifier:(NSString *)identifier coordinates:(MGLCoordinateQuad)coordinateQuad image:(MGLImage *)image {
self = [self initWithIdentifier:identifier coordinates: coordinateQuad];
self.image = image;
return self;
}
- (instancetype)initWithIdentifier:(NSString *)identifier bounds:(MGLCoordinateBounds)bounds {
self = [self initWithIdentifier:identifier coordinates:MGLCoordinateQuadFromCoordinateBounds(bounds)];
return self;
}
- (instancetype)initWithIdentifier:(NSString *)identifier bounds:(MGLCoordinateBounds)bounds imageURL:(NSURL *)url {
self = [self initWithIdentifier:identifier coordinates:MGLCoordinateQuadFromCoordinateBounds(bounds) imageURL:url];
return self;
}
- (instancetype)initWithIdentifier:(NSString *)identifier bounds:(MGLCoordinateBounds)bounds image:(MGLImage *)image {
self = [self initWithIdentifier:identifier coordinates:MGLCoordinateQuadFromCoordinateBounds(bounds) image:image];
return self;
}
- (NSURL *)URL {
auto url = self.rawSource->getURL();
return url ? [NSURL URLWithString:@(url->c_str())] : nil;
}
- (void)setURL:(NSURL *)url {
if (url) {
self.rawSource->setURL(url.mgl_URLByStandardizingScheme.absoluteString.UTF8String);
_image = nil;
} else {
self.image = nullptr;
}
}
- (void)setImage:(MGLImage *)image {
if (image != nullptr) {
mbgl::UnassociatedImage unassociatedImage = mbgl::util::unpremultiply(image.mgl_PremultipliedImage);
self.rawSource->setImage(std::move(unassociatedImage));
}
_image = image;
}
- (MGLCoordinateQuad)coordinates {
return MGLCoordinateQuadFromLatLngArray(self.rawSource->getCoordinates());
}
- (void)setCoordinates: (MGLCoordinateQuad)coordinateQuad {
self.rawSource->setCoordinates(MGLLatLngArrayFromCoordinateQuad(coordinateQuad));
}
- (NSString *)description {
return [NSString stringWithFormat:@"<%@: %p; identifier = %@; URL = %@; image = %@>",
NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.image];
}
- (mbgl::style::ImageSource *)rawSource {
return (mbgl::style::ImageSource *)super.rawSource;
}
- (NSString *)attributionHTMLString {
auto attribution = self.rawSource->getAttribution();
return attribution ? @(attribution->c_str()) : nil;
}
@end

View File

@@ -0,0 +1,9 @@
#import "MGLImageSource.h"
NS_ASSUME_NONNULL_BEGIN
@interface MGLImageSource (Private)
@end
NS_ASSUME_NONNULL_END

View File

@@ -154,6 +154,8 @@ typedef NS_ENUM(NSUInteger, MGLResourceKind) {
/** JSON part of a sprite sheet. It is constructed of the prefix in
https://www.mapbox.com/mapbox-gl-js/style-spec/#root-sprite and a JSON file extension. */
MGLResourceKindSpriteJSON,
/** Image **/
MGLResourceKindImage,
};
/**

View File

@@ -99,6 +99,9 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
case mbgl::Resource::Kind::SpriteJSON:
kind = MGLResourceKindSpriteJSON;
break;
case mbgl::Resource::Kind::Image:
kind = MGLResourceKindImage;
break;
case mbgl::Resource::Kind::Unknown:
kind = MGLResourceKindUnknown;
break;

View File

@@ -23,6 +23,7 @@
#import "MGLVectorSource.h"
#import "MGLRasterSource.h"
#import "MGLShapeSource.h"
#import "MGLImageSource.h"
#import "MGLAttributionInfo_Private.h"
@@ -41,6 +42,7 @@
#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/style/sources/vector_source.hpp>
#include <mbgl/style/sources/raster_source.hpp>
#include <mbgl/style/sources/image_source.hpp>
#if TARGET_OS_IPHONE
#import "UIImage+MGLAdditions.h"
@@ -178,6 +180,8 @@ static NSURL *MGLStyleURL_emerald;
return [[MGLShapeSource alloc] initWithRawSource:geoJSONSource];
} else if (auto rasterSource = rawSource->as<mbgl::style::RasterSource>()) {
return [[MGLRasterSource alloc] initWithRawSource:rasterSource];
} else if (auto imageSource = rawSource->as<mbgl::style::ImageSource>()) {
return [[MGLImageSource alloc] initWithRawSource:imageSource];
} else {
return [[MGLSource alloc] initWithRawSource:rawSource];
}

View File

@@ -56,6 +56,20 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (readonly) MGLCoordinateBounds MGLCoordinateBoundsValue;
/**
Creates a new value object containing the specified Mapbox coordinate
quad structure.
@param quad The value for the new object.
@return A new value object that contains the coordinate quad information.
*/
+ (instancetype)valueWithMGLCoordinateQuad:(MGLCoordinateQuad)quad;
/**
The Mapbox coordinate quad structure representation of the value.
*/
- (MGLCoordinateQuad)MGLCoordinateQuadValue;
#pragma mark Working with Offline Map Values
/**

View File

@@ -34,6 +34,16 @@
return bounds;
}
+ (instancetype)valueWithMGLCoordinateQuad:(MGLCoordinateQuad)quad {
return [self valueWithBytes:&quad objCType:@encode(MGLCoordinateQuad)];
}
- (MGLCoordinateQuad)MGLCoordinateQuadValue {
MGLCoordinateQuad quad;
[self getValue:&quad];
return quad;
}
#pragma mark Offline maps
+ (NSValue *)valueWithMGLOfflinePackProgress:(MGLOfflinePackProgress)progress {

View File

@@ -104,6 +104,20 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
XCTAssertNotNil(mapView.style?.source(withIdentifier: "pois"))
}
func testMGLImageSource() {
//#-example-code
let coordinates: MGLCoordinateQuad = MGLCoordinateQuad(
topLeft: CLLocationCoordinate2D(latitude: 46.437, longitude: -80.425),
topRight: CLLocationCoordinate2D(latitude: 46.437, longitude: -71.516),
bottomRight: CLLocationCoordinate2D(latitude: 37.936, longitude: -71.516),
bottomLeft: CLLocationCoordinate2D(latitude: 37.936, longitude: -80.425))
let source = MGLImageSource(identifier: "images", coordinates: coordinates, imageURL: URL(string: "https://www.mapbox.com/mapbox-gl-js/assets/radar.gif")!)
mapView.style?.addSource(source)
//#-end-example-code
XCTAssertNotNil(mapView.style?.source(withIdentifier: "images"))
}
func testMGLCircleStyleLayer() {
let population = MGLVectorSource(identifier: "population", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style?.addSource(population)

View File

@@ -144,4 +144,23 @@
XCTAssertEqualObjects(serializedGeoJSON, geoJSON, @"MGLPointFeature should serialize as a GeoJSON point feature.");
}
- (void)testMGLCoordinateBoundsToMGLCoordinateQuad {
MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(37.936, -80.425),
CLLocationCoordinate2DMake(46.437, -71.516));
MGLCoordinateQuad quad = MGLCoordinateQuadFromCoordinateBounds(bounds);
XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:bounds.sw],
[NSValue valueWithMGLCoordinate:quad.bottomLeft],
@"Bounds southwest should be bottom left of quad.");
XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:bounds.ne],
[NSValue valueWithMGLCoordinate:quad.topRight],
@"Bounds northeast should be top right of quad.");
XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(46.437, -80.425)],
[NSValue valueWithMGLCoordinate:quad.topLeft],
@"Quad top left should be computed correctly.");
XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(37.936, -71.516)],
[NSValue valueWithMGLCoordinate:quad.bottomRight],
@"Quad bottom right should be computed correctly.");
}
@end

View File

@@ -0,0 +1,42 @@
#import <XCTest/XCTest.h>
#import <Mapbox/Mapbox.h>
@interface MGLImageSourceTests : XCTestCase
@end
@implementation MGLImageSourceTests
- (void)testMGLImageSourceWithImageURL {
MGLCoordinateQuad quad = { { 80, 37}, { 81, 37}, { 81, 39}, { 80, 39}};
MGLImageSource *source = [[MGLImageSource alloc] initWithIdentifier:@"source-id" coordinates:quad imageURL: [NSURL URLWithString:@"http://host/image.png"]];
XCTAssertNotNil(source.URL);
XCTAssertEqualObjects(source.URL.absoluteString, @"http://host/image.png");
XCTAssertNil(source.image);
}
- (void)testMGLImageSourceWithImage {
NSString *imageName = @"RadarImage";
#if TARGET_OS_IPHONE
MGLImage *image = [MGLImage imageNamed:imageName
inBundle:[NSBundle bundleForClass:[self class]]
compatibleWithTraitCollection:nil];
#else
MGLImage *image = [[NSBundle bundleForClass:[self class]] imageForResource:imageName];
#endif
XCTAssertNotNil(image);
MGLCoordinateQuad quad = { { 80, 37}, { 81, 37}, { 81, 39}, { 80, 39}};
MGLImageSource *source = [[MGLImageSource alloc] initWithIdentifier:@"source-id" coordinates:quad image:image];
XCTAssertNotNil(source.image);
XCTAssertEqualObjects(source.image, image);
XCTAssertNil(source.URL);
}
@end

View File

@@ -210,9 +210,9 @@
MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
[self.style addSource:rasterSource];
// Attempt to remove a shape source with the same identifier as the raster source
MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"some-identifier" shape:nil options:nil];
[self.style removeSource:shapeSource];
// Attempt to remove an image source with the same identifier as the raster source
MGLImageSource *imageSource = [[MGLImageSource alloc] initWithIdentifier:@"some-identifier" coordinates: { }];
[self.style removeSource:imageSource];
// The raster source should still be added
XCTAssertTrue([[self.style sourceWithIdentifier:rasterSource.identifier] isMemberOfClass:[MGLRasterSource class]]);
@@ -220,16 +220,16 @@
[self.style removeSource:rasterSource];
// Add the shape source
[self.style addSource:shapeSource];
[self.style addSource:imageSource];
// Attempt to remove a vector source with the same identifer as the shape source
MGLVectorSource *vectorSource = [[MGLVectorSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
[self.style removeSource:vectorSource];
// The shape source should still be added
XCTAssertTrue([[self.style sourceWithIdentifier:shapeSource.identifier] isMemberOfClass:[MGLShapeSource class]]);
// The image source should still be added
XCTAssertTrue([[self.style sourceWithIdentifier:imageSource.identifier] isMemberOfClass:[MGLImageSource class]]);
// Remove the shape source
[self.style removeSource:shapeSource];
// Remove the image source
[self.style removeSource:imageSource];
// Add the vector source
[self.style addSource:vectorSource];
@@ -237,7 +237,7 @@
// Attempt to remove the previously created raster source that has the same identifer as the shape source
[self.style removeSource:rasterSource];
// The vector source should still be added
XCTAssertTrue([[self.style sourceWithIdentifier:shapeSource.identifier] isMemberOfClass:[MGLVectorSource class]]);
XCTAssertTrue([[self.style sourceWithIdentifier:imageSource.identifier] isMemberOfClass:[MGLVectorSource class]]);
}
- (void)testRemovingSourceInUse {

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "radar.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -72,6 +72,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsRuntimeStylingRows) {
MBXSettingsRuntimeStylingUpdateShapeSourceFeatures,
MBXSettingsRuntimeStylingVectorSource,
MBXSettingsRuntimeStylingRasterSource,
MBXSettingsRuntimeStylingImageSource,
MBXSettingsRuntimeStylingCountryLabels,
MBXSettingsRuntimeStylingRouteLine,
MBXSettingsRuntimeStylingDDSPolygon,
@@ -345,6 +346,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
@"Update Shape Source: Features",
@"Style Vector Source",
@"Style Raster Source",
@"Style Image Source",
[NSString stringWithFormat:@"Label Countries in %@", (_usingLocaleBasedCountryLabels ? @"Local Language" : [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:[self bestLanguageForUser]])],
@"Add Route Line",
@"Dynamically Style Polygon",
@@ -585,6 +587,9 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
case MBXSettingsRuntimeStylingRasterSource:
[self styleRasterSource];
break;
case MBXSettingsRuntimeStylingImageSource:
[self styleImageSource];
break;
case MBXSettingsRuntimeStylingCountryLabels:
[self styleCountryLabelsLanguage];
break;
@@ -1308,6 +1313,21 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[self.mapView.style addLayer:rasterLayer];
}
- (void)styleImageSource
{
MGLCoordinateQuad coordinateQuad = {
{ 46.437, -80.425 },
{ 46.437, -71.516 },
{ 37.936, -71.516 },
{ 37.936, -80.425 } };
MGLImageSource *imageSource = [[MGLImageSource alloc] initWithIdentifier:@"style-image-source-id" coordinates:coordinateQuad imageURL:[NSURL URLWithString:@"https://www.mapbox.com/mapbox-gl-js/assets/radar.gif"]];
[self.mapView.style addSource:imageSource];
MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"style-raster-image-layer-id" source:imageSource];
[self.mapView.style addLayer:rasterLayer];
}
-(void)styleCountryLabelsLanguage
{
NSArray<NSString *> *labelLayers = @[

View File

@@ -7,6 +7,13 @@
objects = {
/* Begin PBXBuildFile section */
071BBAFF1EE7613E001FB02A /* MGLImageSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 071BBAFD1EE75CD4001FB02A /* MGLImageSource.mm */; };
071BBB001EE7613F001FB02A /* MGLImageSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 071BBAFD1EE75CD4001FB02A /* MGLImageSource.mm */; };
071BBB011EE76142001FB02A /* MGLImageSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 071BBAFB1EE75CD4001FB02A /* MGLImageSource_Private.h */; };
071BBB021EE76143001FB02A /* MGLImageSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 071BBAFB1EE75CD4001FB02A /* MGLImageSource_Private.h */; };
071BBB031EE76146001FB02A /* MGLImageSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 071BBAFC1EE75CD4001FB02A /* MGLImageSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
071BBB041EE76147001FB02A /* MGLImageSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 071BBAFC1EE75CD4001FB02A /* MGLImageSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
071BBB071EE77631001FB02A /* MGLImageSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */; };
1753ED421E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; };
1753ED431E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; };
1F06668A1EC64F8E001C16D7 /* MGLLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F0666881EC64F8E001C16D7 /* MGLLight.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -538,6 +545,10 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
071BBAFB1EE75CD4001FB02A /* MGLImageSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLImageSource_Private.h; sourceTree = "<group>"; };
071BBAFC1EE75CD4001FB02A /* MGLImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLImageSource.h; sourceTree = "<group>"; };
071BBAFD1EE75CD4001FB02A /* MGLImageSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLImageSource.mm; sourceTree = "<group>"; };
071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLImageSourceTests.m; path = ../../darwin/test/MGLImageSourceTests.m; sourceTree = "<group>"; };
1753ED411E53CE6F00A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = "<group>"; };
1F0666881EC64F8E001C16D7 /* MGLLight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight.h; sourceTree = "<group>"; };
1F0666891EC64F8E001C16D7 /* MGLLight.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLight.mm; sourceTree = "<group>"; };
@@ -976,6 +987,9 @@
35136D491D4277EA00C20EFD /* Sources */ = {
isa = PBXGroup;
children = (
071BBAFC1EE75CD4001FB02A /* MGLImageSource.h */,
071BBAFB1EE75CD4001FB02A /* MGLImageSource_Private.h */,
071BBAFD1EE75CD4001FB02A /* MGLImageSource.mm */,
3566C76A1D4A8DFA008152BC /* MGLRasterSource.h */,
DAF0D80F1DFE0EA000B28378 /* MGLRasterSource_Private.h */,
3566C76B1D4A8DFA008152BC /* MGLRasterSource.mm */,
@@ -1133,6 +1147,7 @@
40CFA64E1D78754A008103BD /* Sources */ = {
isa = PBXGroup;
children = (
071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */,
40CFA6501D787579008103BD /* MGLShapeSourceTests.mm */,
920A3E5C1E6F995200C16EFC /* MGLSourceQueryTests.m */,
4085AF081D933DEA00F11B22 /* MGLTileSetTests.mm */,
@@ -1665,6 +1680,7 @@
DA8848311CBAFA6200AB86E3 /* NSString+MGLAdditions.h in Headers */,
353933F81D3FB79F003F57D7 /* MGLLineStyleLayer.h in Headers */,
DAAF722D1DA903C700312FA4 /* MGLStyleValue_Private.h in Headers */,
071BBB031EE76146001FB02A /* MGLImageSource.h in Headers */,
DA8847F41CBAFA5100AB86E3 /* MGLOfflinePack.h in Headers */,
DA88482E1CBAFA6200AB86E3 /* NSException+MGLAdditions.h in Headers */,
DA8848551CBAFB9800AB86E3 /* MGLLocationManager.h in Headers */,
@@ -1705,6 +1721,7 @@
DA8847F21CBAFA5100AB86E3 /* MGLMapCamera.h in Headers */,
3538AA1D1D542239008EC33D /* MGLForegroundStyleLayer.h in Headers */,
DA8847F51CBAFA5100AB86E3 /* MGLOfflineRegion.h in Headers */,
071BBB011EE76142001FB02A /* MGLImageSource_Private.h in Headers */,
DA737EE11D056A4E005BDA16 /* MGLMapViewDelegate.h in Headers */,
DA8848851CBB033F00AB86E3 /* FABKitProtocol.h in Headers */,
DA88481B1CBAFA6200AB86E3 /* MGLGeometry_Private.h in Headers */,
@@ -1740,6 +1757,7 @@
FA68F14B1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.h in Headers */,
353933FC1D3FB7C0003F57D7 /* MGLRasterStyleLayer.h in Headers */,
3566C76D1D4A8DFA008152BC /* MGLRasterSource.h in Headers */,
071BBB021EE76143001FB02A /* MGLImageSource_Private.h in Headers */,
DAED38641D62D0FC00D7640F /* NSURL+MGLAdditions.h in Headers */,
DABFB85E1CBE99E500D62B32 /* MGLAnnotation.h in Headers */,
DABFB8641CBE99E500D62B32 /* MGLOfflineStorage.h in Headers */,
@@ -1748,6 +1766,7 @@
3566C7671D4A77BA008152BC /* MGLShapeSource.h in Headers */,
DA35A29F1CC9E94C00E826B2 /* MGLCoordinateFormatter.h in Headers */,
404C26E31D89B877000AA13D /* MGLTileSource.h in Headers */,
071BBB041EE76147001FB02A /* MGLImageSource.h in Headers */,
DABFB8611CBE99E500D62B32 /* MGLMultiPoint.h in Headers */,
3510FFF11D6D9D8C00F413B2 /* NSExpression+MGLAdditions.h in Headers */,
35D3A1E71E9BE7EC002B38EE /* MGLScaleBar.h in Headers */,
@@ -1958,7 +1977,6 @@
TargetAttributes = {
DA1DC9491CB6C1C2006E619F = {
CreatedOnToolsVersion = 7.3;
DevelopmentTeam = GJZR2MEM28;
LastSwiftMigration = 0820;
};
DA25D5B81CCD9EDE00607828 = {
@@ -2139,6 +2157,7 @@
35D9DDE21DA25EEC00DAAD69 /* MGLCodingTests.m in Sources */,
DA1F8F3D1EBD287B00367E42 /* MGLDocumentationGuideTests.swift in Sources */,
3598544D1E1D38AA00B29F84 /* MGLDistanceFormatterTests.m in Sources */,
071BBB071EE77631001FB02A /* MGLImageSourceTests.m in Sources */,
DA2DBBCE1D51E80400D38FF9 /* MGLStyleLayerTests.m in Sources */,
DA35A2C61CCA9F8300E826B2 /* MGLCompassDirectionFormatterTests.m in Sources */,
DAE7DEC21E245455007505A6 /* MGLNSStringAdditionsTests.m in Sources */,
@@ -2215,6 +2234,7 @@
DD0902A91DB1929D00C5BDCE /* MGLNetworkConfiguration.m in Sources */,
35D13AB91D3D15E300AFB4E0 /* MGLStyleLayer.mm in Sources */,
DA35A2CB1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */,
071BBB001EE7613F001FB02A /* MGLImageSource.mm in Sources */,
DA8848321CBAFA6200AB86E3 /* NSString+MGLAdditions.m in Sources */,
408AA8581DAEDA1E00022900 /* NSDictionary+MGLAdditions.mm in Sources */,
DA35A2A11CC9E95F00E826B2 /* MGLCoordinateFormatter.m in Sources */,
@@ -2296,6 +2316,7 @@
DD0902AA1DB1929D00C5BDCE /* MGLNetworkConfiguration.m in Sources */,
DA35A2B41CCA141D00E826B2 /* MGLCompassDirectionFormatter.m in Sources */,
35D13ABA1D3D15E300AFB4E0 /* MGLStyleLayer.mm in Sources */,
071BBAFF1EE7613E001FB02A /* MGLImageSource.mm in Sources */,
DA35A2CC1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */,
408AA8591DAEDA1E00022900 /* NSDictionary+MGLAdditions.mm in Sources */,
DAA4E4281CBB730400178DFB /* MGLTypes.m in Sources */,
@@ -2616,6 +2637,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/app/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@@ -2629,6 +2651,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/app/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";

View File

@@ -52,6 +52,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLVectorSource.h"
#import "MGLShapeSource.h"
#import "MGLRasterSource.h"
#import "MGLImageSource.h"
#import "MGLTilePyramidOfflineRegion.h"
#import "MGLTypes.h"
#import "MGLUserLocation.h"

View File

@@ -10,6 +10,8 @@ NS_ASSUME_NONNULL_BEGIN
- (std::unique_ptr<mbgl::style::Image>)mgl_styleImageWithIdentifier:(NSString *)identifier;
- (mbgl::PremultipliedImage)mgl_PremultipliedImage;
@end
NS_ASSUME_NONNULL_END

View File

@@ -25,8 +25,11 @@
- (std::unique_ptr<mbgl::style::Image>)mgl_styleImageWithIdentifier:(NSString *)identifier {
BOOL isTemplate = self.renderingMode == UIImageRenderingModeAlwaysTemplate;
return std::make_unique<mbgl::style::Image>([identifier UTF8String],
MGLPremultipliedImageFromCGImage(self.CGImage),
self.mgl_PremultipliedImage,
float(self.scale), isTemplate);
}
-(mbgl::PremultipliedImage)mgl_PremultipliedImage {
return MGLPremultipliedImageFromCGImage(self.CGImage);
}
@end

View File

@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "southeast_radar_0.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "southeast_radar_1.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "southeast_radar_2.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "southeast_radar_3.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

View File

@@ -554,6 +554,12 @@
<action selector="insertCustomStyleLayer:" target="-1" id="LE5-lz-kx3"/>
</connections>
</menuItem>
<menuItem title="Add Animated Image Source" id="tjA-fT-GbA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="addAnimatedImageSource:" target="-1" id="TuN-Pa-hTG"/>
</connections>
</menuItem>
<menuItem title="Show All Annnotations" keyEquivalent="A" id="yMj-uM-8SN">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>

View File

@@ -617,6 +617,34 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
cos(angle) * 20);
}
- (IBAction) addAnimatedImageSource:(id)sender {
MGLImage *image = [[NSBundle bundleForClass:[self class]] imageForResource:@"southeast_0"];
MGLCoordinateBounds bounds = { {22.551103322318994, -90.24006072802854}, {36.928147474567794, -75.1441643681673} };
MGLImageSource *imageSource = [[MGLImageSource alloc] initWithIdentifier:@"radar-source" bounds:bounds image:image];
[self.mapView.style addSource:imageSource];
MGLRasterStyleLayer * imageLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"radar-layer" source:imageSource];
[self.mapView.style addLayer:imageLayer];
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(updateAnimatedImageSource:)
userInfo:imageSource
repeats:YES];
}
- (void)updateAnimatedImageSource:(NSTimer *)timer {
MGLImageSource *imageSource = (MGLImageSource *)timer.userInfo;
double timeInterval = timer.fireDate.timeIntervalSinceReferenceDate;
int radarSuffix = (int)timeInterval % 4;
MGLImage *image = [[NSBundle bundleForClass:[self class]] imageForResource:[NSString stringWithFormat:@"southeast_%d", radarSuffix]];
[imageSource setValue:image forKey:@"image"];
}
- (IBAction)insertCustomStyleLayer:(id)sender {
[self.undoManager registerUndoWithTarget:self handler:^(id _Nonnull target) {
[self removeCustomStyleLayer:sender];
@@ -695,14 +723,18 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
MGLTransition transition = { .duration = 5, .delay = 1 };
self.mapView.style.transition = transition;
MGLFillStyleLayer *fillStyleLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"water"];
MGLStyleLayer *waterLayer = [self.mapView.style layerWithIdentifier:@"water"];
MGLStyleValue *colorFunction = [MGLStyleValue<NSColor *> valueWithInterpolationMode:MGLInterpolationModeExponential cameraStops:@{
@0.0: [MGLStyleValue<NSColor *> valueWithRawValue:[NSColor redColor]],
@10.0: [MGLStyleValue<NSColor *> valueWithRawValue:[NSColor yellowColor]],
@20.0: [MGLStyleValue<NSColor *> valueWithRawValue:[NSColor blackColor]],
} options:nil];
fillStyleLayer.fillColor = colorFunction;
if ([waterLayer respondsToSelector:@selector(fillColor)]) {
[waterLayer setValue:colorFunction forKey:@"fillColor"];
} else if ([waterLayer respondsToSelector:@selector(lineColor)]) {
[waterLayer setValue:colorFunction forKey:@"lineColor"];
}
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
NSURL *geoJSONURL = [NSURL fileURLWithPath:filePath];
@@ -714,21 +746,34 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
fillLayer.predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"type", @"park"];
[self.mapView.style addLayer:fillLayer];
MGLSource *streetsSource = [self.mapView.style sourceWithIdentifier:@"composite"];
if (streetsSource) {
NSImage *image = [NSImage imageNamed:NSImageNameIChatTheaterTemplate];
[self.mapView.style setImage:image forName:NSImageNameIChatTheaterTemplate];
MGLSource *streetsSource = [self.mapView.style sourceWithIdentifier:@"composite"];
MGLSymbolStyleLayer *theaterLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"theaters" source:streetsSource];
theaterLayer.sourceLayerIdentifier = @"poi_label";
theaterLayer.predicate = [NSPredicate predicateWithFormat:@"maki == 'theatre'"];
theaterLayer.iconImageName = [MGLStyleValue valueWithRawValue:NSImageNameIChatTheaterTemplate];
theaterLayer.iconScale = [MGLStyleValue valueWithRawValue:@2];
theaterLayer.iconColor = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential cameraStops:@{
@16.0: [MGLStyleValue valueWithRawValue:[NSColor redColor]],
@18.0: [MGLStyleValue valueWithRawValue:[NSColor yellowColor]],
@20.0: [MGLStyleValue valueWithRawValue:[NSColor blackColor]],
} options:nil];
[self.mapView.style addLayer:theaterLayer];
MGLSymbolStyleLayer *theaterLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"theaters" source:streetsSource];
theaterLayer.sourceLayerIdentifier = @"poi_label";
theaterLayer.predicate = [NSPredicate predicateWithFormat:@"maki == 'theatre'"];
theaterLayer.iconImageName = [MGLStyleValue valueWithRawValue:NSImageNameIChatTheaterTemplate];
theaterLayer.iconScale = [MGLStyleValue valueWithRawValue:@2];
theaterLayer.iconColor = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential cameraStops:@{
@16.0: [MGLStyleValue valueWithRawValue:[NSColor redColor]],
@18.0: [MGLStyleValue valueWithRawValue:[NSColor yellowColor]],
@20.0: [MGLStyleValue valueWithRawValue:[NSColor blackColor]],
} options:nil];
[self.mapView.style addLayer:theaterLayer];
}
MGLImage *image = [[NSBundle bundleForClass:[self class]] imageForResource:@"RadarImage"];
MGLCoordinateQuad quad = { {46.437, -80.425},
{46.437, -71.516},
{37.936, -71.516},
{37.936, -80.425} };
MGLImageSource *imageSource = [[MGLImageSource alloc] initWithIdentifier:@"radar-source" coordinates:quad image:image];
[self.mapView.style addSource:imageSource];
MGLRasterStyleLayer * imageLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"radar-layer" source:imageSource];
[self.mapView.style addLayer:imageLayer];
}
- (IBAction)dropPin:(NSMenuItem *)sender {
@@ -937,6 +982,9 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
if (menuItem.action == @selector(drawAnimatedAnnotation:)) {
return !_isShowingAnimatedAnnotation;
}
if (menuItem.action == @selector(addAnimatedImageSource:)) {
return YES;
}
if (menuItem.action == @selector(insertCustomStyleLayer:)) {
return ![self.mapView.style layerWithIdentifier:@"mbx-custom"];
}

View File

@@ -7,6 +7,9 @@
objects = {
/* Begin PBXBuildFile section */
0721493F1EE200E900085505 /* MGLImageSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 07A019EB1ED662D800ACD43E /* MGLImageSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
07A019EF1ED665CD00ACD43E /* MGLImageSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 07A019EC1ED662D800ACD43E /* MGLImageSource.mm */; };
07BA4CAC1EE21887004528F5 /* MGLImageSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 07BA4CAB1EE21887004528F5 /* MGLImageSourceTests.m */; };
1753ED401E53CE6100A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */; };
1F7454A31ECFB00300021D39 /* MGLLight_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F7454A01ECFB00300021D39 /* MGLLight_Private.h */; };
1F7454A41ECFB00300021D39 /* MGLLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F7454A11ECFB00300021D39 /* MGLLight.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -271,6 +274,10 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
07A019EA1ED662D800ACD43E /* MGLImageSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLImageSource_Private.h; sourceTree = "<group>"; };
07A019EB1ED662D800ACD43E /* MGLImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLImageSource.h; sourceTree = "<group>"; };
07A019EC1ED662D800ACD43E /* MGLImageSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLImageSource.mm; sourceTree = "<group>"; };
07BA4CAB1EE21887004528F5 /* MGLImageSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLImageSourceTests.m; sourceTree = "<group>"; };
1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = "<group>"; };
1F7454A01ECFB00300021D39 /* MGLLight_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight_Private.h; sourceTree = "<group>"; };
1F7454A11ECFB00300021D39 /* MGLLight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight.h; sourceTree = "<group>"; };
@@ -664,6 +671,9 @@
DA8F25951D51CAC70010E6B5 /* MGLVectorSource.h */,
DA7DC9801DED5F5C0027472F /* MGLVectorSource_Private.h */,
DA8F25961D51CAC70010E6B5 /* MGLVectorSource.mm */,
07A019EA1ED662D800ACD43E /* MGLImageSource_Private.h */,
07A019EB1ED662D800ACD43E /* MGLImageSource.h */,
07A019EC1ED662D800ACD43E /* MGLImageSource.mm */,
);
name = Sources;
sourceTree = "<group>";
@@ -774,6 +784,7 @@
DA87A9961DC9D88400810D09 /* MGLShapeSourceTests.mm */,
DA87A9971DC9D88400810D09 /* MGLTileSetTests.mm */,
920A3E581E6F859D00C16EFC /* MGLSourceQueryTests.m */,
07BA4CAB1EE21887004528F5 /* MGLImageSourceTests.m */,
);
name = Sources;
sourceTree = "<group>";
@@ -1166,6 +1177,7 @@
DAE6C3B41CC31EF300DB3429 /* MGLCompassCell.h in Headers */,
DA87A99C1DC9D8DD00810D09 /* MGLShapeSource_Private.h in Headers */,
3537CA741D3F93A600380318 /* MGLStyle_Private.h in Headers */,
0721493F1EE200E900085505 /* MGLImageSource.h in Headers */,
DA8F259A1D51CAD00010E6B5 /* MGLSource_Private.h in Headers */,
DA8F25931D51CA750010E6B5 /* MGLSymbolStyleLayer.h in Headers */,
DAE6C3B91CC31EF300DB3429 /* MGLOpenGLLayer.h in Headers */,
@@ -1386,6 +1398,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
07A019EF1ED665CD00ACD43E /* MGLImageSource.mm in Sources */,
40ABDB561DB0022100372083 /* NSImage+MGLAdditions.mm in Sources */,
DAE6C3901CC31E2A00DB3429 /* MGLPointAnnotation.mm in Sources */,
DAE6C3981CC31E2A00DB3429 /* NSBundle+MGLAdditions.m in Sources */,
@@ -1478,6 +1491,7 @@
DA87A9A71DCACC5000810D09 /* MGLBackgroundStyleLayerTests.mm in Sources */,
DAA999011E9F5EC5002E6EA6 /* MGLFillExtrusionStyleLayerTests.mm in Sources */,
DA29875A1E1A4290002299F5 /* MGLDocumentationExampleTests.swift in Sources */,
07BA4CAC1EE21887004528F5 /* MGLImageSourceTests.m in Sources */,
DAE6C3D31CC34C9900DB3429 /* MGLOfflinePackTests.m in Sources */,
DA87A9A51DCACC5000810D09 /* MGLLineStyleLayerTests.mm in Sources */,
DA87A9A31DCACC5000810D09 /* MGLRasterStyleLayerTests.mm in Sources */,

View File

@@ -50,6 +50,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLVectorSource.h"
#import "MGLShapeSource.h"
#import "MGLRasterSource.h"
#import "MGLImageSource.h"
#import "MGLTilePyramidOfflineRegion.h"
#import "MGLTypes.h"
#import "NSValue+MGLAdditions.h"

View File

@@ -12,6 +12,8 @@ NS_ASSUME_NONNULL_BEGIN
- (std::unique_ptr<mbgl::style::Image>)mgl_styleImageWithIdentifier:(NSString *)identifier;
- (mbgl::PremultipliedImage) mgl_PremultipliedImage;
@end
NS_ASSUME_NONNULL_END

View File

@@ -33,6 +33,15 @@
}
- (std::unique_ptr<mbgl::style::Image>)mgl_styleImageWithIdentifier:(NSString *)identifier {
mbgl::PremultipliedImage cPremultipliedImage = self.mgl_PremultipliedImage;
auto imageWidth = cPremultipliedImage.size.width;
return std::make_unique<mbgl::style::Image>([identifier UTF8String],
std::move(cPremultipliedImage),
(float)(imageWidth / self.size.width),
[self isTemplate]);
}
- (mbgl::PremultipliedImage)mgl_PremultipliedImage {
// Create a bitmap image representation from the image, respecting backing
// scale factor and any resizing done on the image at runtime.
// http://www.cocoabuilder.com/archive/cocoa/82430-nsimage-getting-raw-bitmap-data.html#82431
@@ -42,10 +51,6 @@
mbgl::PremultipliedImage cPremultipliedImage({ static_cast<uint32_t>(rep.pixelsWide), static_cast<uint32_t>(rep.pixelsHigh) });
std::copy(rep.bitmapData, rep.bitmapData + cPremultipliedImage.bytes(), cPremultipliedImage.data.get());
return std::make_unique<mbgl::style::Image>([identifier UTF8String],
std::move(cPremultipliedImage),
(float)(rep.pixelsWide / self.size.width),
[self isTemplate]);
return cPremultipliedImage;
}
@end

View File

@@ -13,7 +13,9 @@ RasterBucket::RasterBucket(UnassociatedImage&& image_) : image(std::move(image_)
}
void RasterBucket::upload(gl::Context& context) {
texture = context.createTexture(image);
if (!texture) {
texture = context.createTexture(image);
}
if (!vertices.empty()) {
vertexBuffer = context.createVertexBuffer(std::move(vertices));
indexBuffer = context.createIndexBuffer(std::move(indices));
@@ -27,7 +29,7 @@ void RasterBucket::clear() {
segments.clear();
vertices.clear();
indices.clear();
uploaded = false;
}
void RasterBucket::render(Painter& painter,

View File

@@ -135,12 +135,13 @@ void RenderImageSource::update(Immutable<style::Source::Impl> baseImpl_,
geomCoords.push_back(gc);
}
if (!bucket) {
UnassociatedImage img = impl().getImage().clone();
if (!img.valid()) {
return;
}
bucket = std::make_unique<RasterBucket>(std::move(img));
const UnassociatedImage& image = impl().getImage();
if (!image.valid()) {
return;
}
if (!bucket || image != bucket->image) {
bucket = std::make_unique<RasterBucket>(image.clone());
} else {
bucket->clear();
}