Merge branch 'master' into release-boba

# Conflicts:
#	platform/android/CHANGELOG.md
#	platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
#	platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
#	platform/android/scripts/exclude-activity-gen.json
#	platform/ios/CHANGELOG.md
#	platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec
#	platform/ios/Mapbox-iOS-SDK-symbols.podspec
#	platform/ios/Mapbox-iOS-SDK.podspec
#	platform/macos/CHANGELOG.md
This commit is contained in:
Fabian Guerra
2018-02-15 11:54:51 -05:00
191 changed files with 6365 additions and 814 deletions

View File

@@ -7,50 +7,38 @@ that you can download instantly and get started with fast](https://www.mapbox.co
Still with us? These are the instructions you'll need to build Mapbox GL Native
from source on a variety of platforms and set up a development environment.
Your journey will start with getting the source code, then installing the
dependencies, and then setting up a development environment, which varies
depending on your operating system and what platform you want to develop for.
Your journey will start with installing dependencies, then getting the source code, and
then setting up a development environment, which varies depending on your
operating system and what platform you want to develop for.
## 1: Getting the source
## 1: Installing dependencies
Clone the git repository:
### macOS
git clone https://github.com/mapbox/mapbox-gl-native.git
cd mapbox-gl-native
1. Install [Xcode](https://developer.apple.com/xcode/)
2. Launch Xcode and install any updates
3. Install [Homebrew](http://brew.sh)
4. Install [Node.js](https://nodejs.org/), [CMake](https://cmake.org/), and [ccache](https://ccache.samba.org) with `brew install nodejs cmake ccache`
5. Install [xcpretty](https://github.com/supermarin/xcpretty) with `[sudo] gem install xcpretty` (optional, used for prettifying command line builds)
## 2: Installing dependencies
### Linux
These dependencies are required for all operating systems and all platform
targets.
- Modern C++ compiler that supports `-std=c++14`\*
- clang++ 3.5 or later _or_
- g++-4.9 or later
- [CMake](https://cmake.org/) 3.1 or later (for build only)
- [cURL](https://curl.haxx.se) (for build only)
- [Node.js](https://nodejs.org/) 4.2.1 or later (for build only)
- [`pkg-config`](https://wiki.freedesktop.org/www/Software/pkg-config/) (for build only)
**Note**: We partially support C++14 because GCC 4.9 does not fully implement the
final draft of the C++14 standard. More information in [DEVELOPING.md](DEVELOPING.md).
Depending on your operating system and target, you'll need additional
dependencies:
### Additional dependencies for Linux
Install the following:
- `clang++` 3.5 or later or `g++` 4.9 or later
- [git](https://git-scm.com/)
- [CMake](https://cmake.org/) 3.1 or later
- [cURL](https://curl.haxx.se)
- [Node.js](https://nodejs.org/) 4.2.1 or later
- [`libcurl`](http://curl.haxx.se/libcurl/) (depends on OpenSSL)
- [ccache](https://ccache.samba.org) (optional, improves recompilation performance)
### Additional dependencies for macOS
## 2: Getting the source
- Apple Command Line Tools (available at [Apple Developer](https://developer.apple.com/download/more/))
- [Homebrew](http://brew.sh)
- [Cask](http://caskroom.io/) (if building for Android)
- [xcpretty](https://github.com/supermarin/xcpretty) (`gem install xcpretty`)
Clone the git repository:
### Optional dependencies
- [ccache](https://ccache.samba.org) (for build only; improves recompilation performance)
git clone https://github.com/mapbox/mapbox-gl-native.git
cd mapbox-gl-native
## 3: Setting up a development environment & building
@@ -58,7 +46,7 @@ See the relevant SDK documentation for next steps:
* [Maps SDK for Android](platform/android/)
* [Maps SDK for iOS](platform/ios/)
* [Maps SDK for iOS](platform/macos/)
* [Maps SDK for macOS](platform/macos/)
* [Mapbox Qt SDK](platform/qt/)
* [Mapbox GL Native on Linux](platform/linux/)
* [node-mapbox-gl-native](platform/node/)

View File

@@ -146,6 +146,10 @@ set(MBGL_CORE_FILES
src/mbgl/programs/fill_extrusion_program.hpp
src/mbgl/programs/fill_program.cpp
src/mbgl/programs/fill_program.hpp
src/mbgl/programs/heatmap_program.cpp
src/mbgl/programs/heatmap_program.hpp
src/mbgl/programs/heatmap_texture_program.cpp
src/mbgl/programs/heatmap_texture_program.hpp
src/mbgl/programs/hillshade_prepare_program.cpp
src/mbgl/programs/hillshade_prepare_program.hpp
src/mbgl/programs/hillshade_program.cpp
@@ -170,6 +174,7 @@ set(MBGL_CORE_FILES
include/mbgl/renderer/renderer.hpp
include/mbgl/renderer/renderer_backend.hpp
include/mbgl/renderer/renderer_frontend.hpp
include/mbgl/renderer/renderer_observer.hpp
src/mbgl/renderer/backend_scope.cpp
src/mbgl/renderer/bucket.hpp
src/mbgl/renderer/bucket_parameters.cpp
@@ -206,7 +211,6 @@ set(MBGL_CORE_FILES
src/mbgl/renderer/renderer_backend.cpp
src/mbgl/renderer/renderer_impl.cpp
src/mbgl/renderer/renderer_impl.hpp
src/mbgl/renderer/renderer_observer.hpp
src/mbgl/renderer/style_diff.cpp
src/mbgl/renderer/style_diff.hpp
src/mbgl/renderer/tile_mask.hpp
@@ -225,6 +229,8 @@ set(MBGL_CORE_FILES
src/mbgl/renderer/buckets/fill_bucket.hpp
src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp
src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp
src/mbgl/renderer/buckets/heatmap_bucket.cpp
src/mbgl/renderer/buckets/heatmap_bucket.hpp
src/mbgl/renderer/buckets/hillshade_bucket.cpp
src/mbgl/renderer/buckets/hillshade_bucket.hpp
src/mbgl/renderer/buckets/line_bucket.cpp
@@ -245,6 +251,8 @@ set(MBGL_CORE_FILES
src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
src/mbgl/renderer/layers/render_fill_layer.cpp
src/mbgl/renderer/layers/render_fill_layer.hpp
src/mbgl/renderer/layers/render_heatmap_layer.cpp
src/mbgl/renderer/layers/render_heatmap_layer.hpp
src/mbgl/renderer/layers/render_hillshade_layer.cpp
src/mbgl/renderer/layers/render_hillshade_layer.hpp
src/mbgl/renderer/layers/render_line_layer.cpp
@@ -297,6 +305,10 @@ set(MBGL_CORE_FILES
src/mbgl/shaders/fill_outline_pattern.hpp
src/mbgl/shaders/fill_pattern.cpp
src/mbgl/shaders/fill_pattern.hpp
src/mbgl/shaders/heatmap.cpp
src/mbgl/shaders/heatmap.hpp
src/mbgl/shaders/heatmap_texture.cpp
src/mbgl/shaders/heatmap_texture.hpp
src/mbgl/shaders/hillshade.cpp
src/mbgl/shaders/hillshade.hpp
src/mbgl/shaders/hillshade_prepare.cpp
@@ -349,6 +361,7 @@ set(MBGL_CORE_FILES
include/mbgl/style/data_driven_property_value.hpp
include/mbgl/style/filter.hpp
include/mbgl/style/filter_evaluator.hpp
include/mbgl/style/heatmap_color_property_value.hpp
include/mbgl/style/image.hpp
include/mbgl/style/layer.hpp
include/mbgl/style/layer_type.hpp
@@ -401,6 +414,7 @@ set(MBGL_CORE_FILES
include/mbgl/style/conversion/geojson.hpp
include/mbgl/style/conversion/geojson_options.hpp
include/mbgl/style/conversion/get_json_type.hpp
include/mbgl/style/conversion/heatmap_color_property_value.hpp
include/mbgl/style/conversion/layer.hpp
include/mbgl/style/conversion/light.hpp
include/mbgl/style/conversion/position.hpp
@@ -495,6 +509,7 @@ set(MBGL_CORE_FILES
include/mbgl/style/layers/custom_layer.hpp
include/mbgl/style/layers/fill_extrusion_layer.hpp
include/mbgl/style/layers/fill_layer.hpp
include/mbgl/style/layers/heatmap_layer.hpp
include/mbgl/style/layers/hillshade_layer.hpp
include/mbgl/style/layers/line_layer.hpp
include/mbgl/style/layers/raster_layer.hpp
@@ -522,6 +537,11 @@ set(MBGL_CORE_FILES
src/mbgl/style/layers/fill_layer_impl.hpp
src/mbgl/style/layers/fill_layer_properties.cpp
src/mbgl/style/layers/fill_layer_properties.hpp
src/mbgl/style/layers/heatmap_layer.cpp
src/mbgl/style/layers/heatmap_layer_impl.cpp
src/mbgl/style/layers/heatmap_layer_impl.hpp
src/mbgl/style/layers/heatmap_layer_properties.cpp
src/mbgl/style/layers/heatmap_layer_properties.hpp
src/mbgl/style/layers/hillshade_layer.cpp
src/mbgl/style/layers/hillshade_layer_impl.cpp
src/mbgl/style/layers/hillshade_layer_impl.hpp

View File

@@ -48,7 +48,7 @@ public:
void dumpDebugLogs();
// Memory
void onLowMemory();
void reduceMemoryUse();
private:
class Impl;

View File

@@ -54,6 +54,26 @@ struct Converter<CustomGeometrySource::Options> {
}
}
const auto wrapValue = objectMember(value, "wrap");
if (wrapValue) {
if (toBool(*wrapValue)) {
options.tileOptions.wrap = static_cast<bool>(*toBool(*wrapValue));
} else {
error = { "CustomGeometrySource TileOptions wrap value must be a boolean" };
return {};
}
}
const auto clipValue = objectMember(value, "clip");
if (clipValue) {
if (toBool(*clipValue)) {
options.tileOptions.clip = static_cast<double>(*toBool(*clipValue));
} else {
error = { "CustomGeometrySource TileOptiosn clip value must be a boolean" };
return {};
}
}
return { options };
}

View File

@@ -0,0 +1,46 @@
#pragma once
#include <mbgl/style/heatmap_color_property_value.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/function.hpp>
#include <mbgl/style/conversion/expression.hpp>
#include <mbgl/style/expression/value.hpp>
#include <mbgl/style/expression/is_constant.hpp>
#include <mbgl/style/expression/is_expression.hpp>
#include <mbgl/style/expression/find_zoom_curve.hpp>
namespace mbgl {
namespace style {
namespace conversion {
template <>
struct Converter<HeatmapColorPropertyValue> {
optional<HeatmapColorPropertyValue> operator()(const Convertible& value, Error& error) const {
if (isUndefined(value)) {
return HeatmapColorPropertyValue();
} else if (isExpression(value)) {
optional<std::unique_ptr<Expression>> expression = convert<std::unique_ptr<Expression>>(value, error, expression::type::Color);
if (!expression) {
return {};
}
assert(*expression);
if (!isFeatureConstant(**expression)) {
error = { "property expressions not supported" };
return {};
}
if (!isZoomConstant(**expression)) {
error = { "zoom expressions not supported" };
return {};
}
return {HeatmapColorPropertyValue(std::move(*expression))};
} else {
error = { "heatmap-color must be an expression" };
return {};
}
}
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,49 @@
#pragma once
#include <mbgl/util/variant.hpp>
#include <mbgl/style/undefined.hpp>
#include <mbgl/style/function/camera_function.hpp>
namespace mbgl {
namespace style {
/*
* Special-case implementation of (a subset of) the PropertyValue<T> interface
* used for building the HeatmapColor paint property traits class.
*/
class HeatmapColorPropertyValue {
private:
std::shared_ptr<expression::Expression> value;
friend bool operator==(const HeatmapColorPropertyValue& lhs, const HeatmapColorPropertyValue& rhs) {
return (lhs.isUndefined() && rhs.isUndefined()) || (lhs.value && rhs.value && *(lhs.value) == *(rhs.value));
}
friend bool operator!=(const HeatmapColorPropertyValue& lhs, const HeatmapColorPropertyValue& rhs) {
return !(lhs == rhs);
}
public:
HeatmapColorPropertyValue() : value(nullptr) {}
HeatmapColorPropertyValue(std::shared_ptr<expression::Expression> value_) : value(std::move(value_)) {}
bool isUndefined() const { return value.get() == nullptr; }
// noop, needed for batch evaluation of paint property values to compile
template <typename Evaluator>
Color evaluate(const Evaluator&, TimePoint = {}) const { return {}; }
Color evaluate(double heatmapDensity) const {
const auto result = value->evaluate(expression::EvaluationContext({}, nullptr, {heatmapDensity}));
return *expression::fromExpressionValue<Color>(*result);
}
bool isDataDriven() const { return false; }
bool hasDataDrivenPropertyDifference(const HeatmapColorPropertyValue&) const { return false; }
const expression::Expression& getExpression() const { return *value; }
};
} // namespace style
} // namespace mbgl

View File

@@ -23,6 +23,7 @@ class HillshadeLayer;
class BackgroundLayer;
class CustomLayer;
class FillExtrusionLayer;
class HeatmapLayer;
class LayerObserver;
/**
@@ -93,6 +94,8 @@ public:
return std::forward<V>(visitor)(*as<CustomLayer>());
case LayerType::FillExtrusion:
return std::forward<V>(visitor)(*as<FillExtrusionLayer>());
case LayerType::Heatmap:
return std::forward<V>(visitor)(*as<HeatmapLayer>());
}

View File

@@ -13,6 +13,7 @@ enum class LayerType {
Background,
Custom,
FillExtrusion,
Heatmap,
};
} // namespace style

View File

@@ -0,0 +1,86 @@
// This file is generated. Do not edit.
#pragma once
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/style/heatmap_color_property_value.hpp>
#include <mbgl/util/color.hpp>
namespace mbgl {
namespace style {
class TransitionOptions;
class HeatmapLayer : public Layer {
public:
HeatmapLayer(const std::string& layerID, const std::string& sourceID);
~HeatmapLayer() final;
// Source
const std::string& getSourceID() const;
const std::string& getSourceLayer() const;
void setSourceLayer(const std::string& sourceLayer);
void setFilter(const Filter&);
const Filter& getFilter() const;
// Visibility
void setVisibility(VisibilityType) final;
// Zoom range
void setMinZoom(float) final;
void setMaxZoom(float) final;
// Paint properties
static DataDrivenPropertyValue<float> getDefaultHeatmapRadius();
DataDrivenPropertyValue<float> getHeatmapRadius() const;
void setHeatmapRadius(DataDrivenPropertyValue<float>);
void setHeatmapRadiusTransition(const TransitionOptions&);
TransitionOptions getHeatmapRadiusTransition() const;
static DataDrivenPropertyValue<float> getDefaultHeatmapWeight();
DataDrivenPropertyValue<float> getHeatmapWeight() const;
void setHeatmapWeight(DataDrivenPropertyValue<float>);
void setHeatmapWeightTransition(const TransitionOptions&);
TransitionOptions getHeatmapWeightTransition() const;
static PropertyValue<float> getDefaultHeatmapIntensity();
PropertyValue<float> getHeatmapIntensity() const;
void setHeatmapIntensity(PropertyValue<float>);
void setHeatmapIntensityTransition(const TransitionOptions&);
TransitionOptions getHeatmapIntensityTransition() const;
static HeatmapColorPropertyValue getDefaultHeatmapColor();
HeatmapColorPropertyValue getHeatmapColor() const;
void setHeatmapColor(HeatmapColorPropertyValue);
void setHeatmapColorTransition(const TransitionOptions&);
TransitionOptions getHeatmapColorTransition() const;
static PropertyValue<float> getDefaultHeatmapOpacity();
PropertyValue<float> getHeatmapOpacity() const;
void setHeatmapOpacity(PropertyValue<float>);
void setHeatmapOpacityTransition(const TransitionOptions&);
TransitionOptions getHeatmapOpacityTransition() const;
// Private implementation
class Impl;
const Impl& impl() const;
Mutable<Impl> mutableImpl() const;
HeatmapLayer(Immutable<Impl>);
std::unique_ptr<Layer> cloneRef(const std::string& id) const final;
};
template <>
inline bool Layer::is<HeatmapLayer>() const {
return getType() == LayerType::Heatmap;
}
} // namespace style
} // namespace mbgl

View File

@@ -11,6 +11,9 @@
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
#include <mbgl/style/data_driven_property_value.hpp>
<% if (type === 'heatmap') { -%>
#include <mbgl/style/heatmap_color_property_value.hpp>
<% } -%>
#include <mbgl/util/color.hpp>

View File

@@ -25,6 +25,8 @@ public:
double tolerance = 0.375;
uint16_t tileSize = util::tileSize;
uint16_t buffer = 128;
bool clip = false;
bool wrap = false;
};
struct Options {

View File

@@ -14,22 +14,28 @@ namespace mbgl {
class Tileset {
public:
enum class Scheme : bool { XYZ, TMS };
enum class DEMEncoding : bool { Mapbox, Terrarium };
std::vector<std::string> tiles;
Range<uint8_t> zoomRange;
std::string attribution;
Scheme scheme;
// DEMEncoding is not supported by the TileJSON spec
DEMEncoding encoding;
optional<LatLngBounds> bounds;
Tileset(std::vector<std::string> tiles_ = std::vector<std::string>(),
Range<uint8_t> zoomRange_ = { 0, util::DEFAULT_MAX_ZOOM },
std::string attribution_ = {},
Scheme scheme_ = Scheme::XYZ)
Scheme scheme_ = Scheme::XYZ,
DEMEncoding encoding_ = DEMEncoding::Mapbox)
: tiles(std::move(tiles_)),
zoomRange(std::move(zoomRange_)),
attribution(std::move(attribution_)),
scheme(scheme_),
bounds() {}
encoding(encoding_),
bounds() {};
// TileJSON also includes center and zoom but they are not used by mbgl.

View File

@@ -2,6 +2,10 @@
Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started.
## master
- HeatmapLayer [#11046](https://github.com/mapbox/mapbox-gl-native/pull/11046)
## 6.0.0-beta.2 - February 13, 2018
- Deprecate LocationEngine [#11185](https://github.com/mapbox/mapbox-gl-native/pull/11185)
- Remove LOST from SDK [11186](https://github.com/mapbox/mapbox-gl-native/pull/11186)
@@ -22,7 +26,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to
## 5.4.0 - January 30, 2018
- Blacklist Adreno 2xx GPU for VAO support [#11047](https://github.com/mapbox/mapbox-gl-native/pull/11047)
- Bearing tracking mode GPS_NORTH_FACING [#11095](https://github.com/mapbox/mapbox-gl-native/pull/11095)
- Disable logging missing location permissons [#11084](https://github.com/mapbox/mapbox-gl-native/pull/11084)
- Disable logging for missing location permissions when location is disabled [#11084](https://github.com/mapbox/mapbox-gl-native/pull/11084)
- Create offline handler using the main thread looper [#11021](https://github.com/mapbox/mapbox-gl-native/pull/11021)
## 6.0.0-beta.1 - January 26, 2018

View File

@@ -13,7 +13,7 @@ BUILDTYPE=Debug or BUILDTYPE=Release
##### Creating an Android Archive file that supports all ABIs
```sh
BUILDTYPE=RELEASE make apackage
BUILDTYPE=Release make apackage
```
This will build native libraries to support following ABIs:

View File

@@ -1,5 +1,5 @@
GROUP=com.mapbox.mapboxsdk
VERSION_NAME=6.0.0-SNAPSHOT
VERSION_NAME=7.0.0-SNAPSHOT
POM_DESCRIPTION=Mapbox GL Android SDK
POM_URL=https://github.com/mapbox/mapbox-gl-native

View File

@@ -12,4 +12,7 @@
# config for okhttp 3.8.0, https://github.com/square/okhttp/pull/3354
-dontwarn okio.**
-dontwarn javax.annotation.Nullable
-dontwarn javax.annotation.ParametersAreNonnullByDefault
-dontwarn javax.annotation.ParametersAreNonnullByDefault
# config for optional location provider https://github.com/mapbox/mapbox-gl-native/issues/10960
-dontwarn com.mapzen.android.lost.api**

View File

@@ -42,6 +42,8 @@ import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
import com.mapbox.mapboxsdk.storage.FileSource;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
@@ -50,9 +52,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import timber.log.Timber;
import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_MAP_NORTH_ANIMATION;

View File

@@ -7,10 +7,10 @@ import android.support.annotation.NonNull;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
@@ -24,7 +24,7 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
* </p>
*/
@SuppressLint("AppCompatCustomView")
public final class CompassView extends ImageView implements Runnable {
public final class CompassView extends AppCompatImageView implements Runnable {
public static final long TIME_WAIT_IDLE = 500;
public static final long TIME_MAP_NORTH_ANIMATION = 150;

View File

@@ -0,0 +1,221 @@
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
package com.mapbox.mapboxsdk.style.layers;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
/**
* A heatmap.
*
* @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layers-heatmap">The online documentation</a>
*/
@UiThread
public class HeatmapLayer extends Layer {
/**
* Creates a HeatmapLayer.
*
* @param nativePtr pointer used by core
*/
public HeatmapLayer(long nativePtr) {
super(nativePtr);
}
/**
* Creates a HeatmapLayer.
*
* @param layerId the id of the layer
* @param sourceId the id of the source
*/
public HeatmapLayer(String layerId, String sourceId) {
initialize(layerId, sourceId);
}
protected native void initialize(String layerId, String sourceId);
/**
* Set the source layer.
*
* @param sourceLayer the source layer to set
*/
public void setSourceLayer(String sourceLayer) {
nativeSetSourceLayer(sourceLayer);
}
/**
* Set the source Layer.
*
* @param sourceLayer the source layer to set
* @return This
*/
public HeatmapLayer withSourceLayer(String sourceLayer) {
setSourceLayer(sourceLayer);
return this;
}
/**
* Get the source layer.
*
* @return sourceLayer the source layer to get
*/
public String getSourceLayer() {
return nativeGetSourceLayer();
}
/**
* Set a single filter.
*
* @param filter the filter to set
*/
public void setFilter(Filter.Statement filter) {
nativeSetFilter(filter.toArray());
}
/**
* Set a single filter.
*
* @param filter the filter to set
* @return This
*/
public HeatmapLayer withFilter(Filter.Statement filter) {
setFilter(filter);
return this;
}
/**
* Set a property or properties.
*
* @param properties the var-args properties
* @return This
*/
public HeatmapLayer withProperties(@NonNull PropertyValue<?>... properties) {
setProperties(properties);
return this;
}
// Property getters
/**
* Get the HeatmapRadius property
*
* @return property wrapper value around Float
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getHeatmapRadius() {
return (PropertyValue<Float>) new PropertyValue("heatmap-radius", nativeGetHeatmapRadius());
}
/**
* Get the HeatmapRadius property transition options
*
* @return transition options for Float
*/
public TransitionOptions getHeatmapRadiusTransition() {
return nativeGetHeatmapRadiusTransition();
}
/**
* Set the HeatmapRadius property transition options
*
* @param options transition options for Float
*/
public void setHeatmapRadiusTransition(TransitionOptions options) {
nativeSetHeatmapRadiusTransition(options.getDuration(), options.getDelay());
}
/**
* Get the HeatmapWeight property
*
* @return property wrapper value around Float
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getHeatmapWeight() {
return (PropertyValue<Float>) new PropertyValue("heatmap-weight", nativeGetHeatmapWeight());
}
/**
* Get the HeatmapIntensity property
*
* @return property wrapper value around Float
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getHeatmapIntensity() {
return (PropertyValue<Float>) new PropertyValue("heatmap-intensity", nativeGetHeatmapIntensity());
}
/**
* Get the HeatmapIntensity property transition options
*
* @return transition options for Float
*/
public TransitionOptions getHeatmapIntensityTransition() {
return nativeGetHeatmapIntensityTransition();
}
/**
* Set the HeatmapIntensity property transition options
*
* @param options transition options for Float
*/
public void setHeatmapIntensityTransition(TransitionOptions options) {
nativeSetHeatmapIntensityTransition(options.getDuration(), options.getDelay());
}
/**
* Get the HeatmapOpacity property
*
* @return property wrapper value around Float
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getHeatmapOpacity() {
return (PropertyValue<Float>) new PropertyValue("heatmap-opacity", nativeGetHeatmapOpacity());
}
/**
* Get the HeatmapOpacity property transition options
*
* @return transition options for Float
*/
public TransitionOptions getHeatmapOpacityTransition() {
return nativeGetHeatmapOpacityTransition();
}
/**
* Set the HeatmapOpacity property transition options
*
* @param options transition options for Float
*/
public void setHeatmapOpacityTransition(TransitionOptions options) {
nativeSetHeatmapOpacityTransition(options.getDuration(), options.getDelay());
}
private native Object nativeGetHeatmapRadius();
private native TransitionOptions nativeGetHeatmapRadiusTransition();
private native void nativeSetHeatmapRadiusTransition(long duration, long delay);
private native Object nativeGetHeatmapWeight();
private native Object nativeGetHeatmapIntensity();
private native TransitionOptions nativeGetHeatmapIntensityTransition();
private native void nativeSetHeatmapIntensityTransition(long duration, long delay);
private native Object nativeGetHeatmapOpacity();
private native TransitionOptions nativeGetHeatmapOpacityTransition();
private native void nativeSetHeatmapOpacityTransition(long duration, long delay);
@Override
protected native void finalize() throws Throwable;
}

View File

@@ -11,7 +11,7 @@ import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
/**
* Client-side hillshading visualization based on DEM data. Currently, the implementation only supports Mapbox Terrain RGB tiles
* Client-side hillshading visualization based on DEM data. Currently, the implementation only supports Mapbox Terrain RGB and Mapzen Terrarium tiles.
*
* @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layers-hillshade">The online documentation</a>
*/

View File

@@ -1515,6 +1515,138 @@ public class PropertyFactory {
return new PaintPropertyValue<>("circle-stroke-opacity", function);
}
/**
* Radius of influence of one heatmap point in density-independent pixels. Increasing the value makes the heatmap smoother, but less detailed.
*
* @param value a Float value
* @return property wrapper around Float
*/
public static PropertyValue<Float> heatmapRadius(Float value) {
return new PaintPropertyValue<>("heatmap-radius", value);
}
/**
* Radius of influence of one heatmap point in density-independent pixels. Increasing the value makes the heatmap smoother, but less detailed.
*
* @param expression an expression statement
* @return property wrapper around an expression statement
*/
public static PropertyValue<Expression> heatmapRadius(Expression expression) {
return new PaintPropertyValue<>("heatmap-radius", expression);
}
/**
* Radius of influence of one heatmap point in density-independent pixels. Increasing the value makes the heatmap smoother, but less detailed.
*
* @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
@Deprecated
public static <T> PropertyValue<Function<T, Float>> heatmapRadius(Function<T, Float> function) {
return new PaintPropertyValue<>("heatmap-radius", function);
}
/**
* A measure of how much an individual point contributes to the heatmap. A value of 10 would be equivalent to having 10 points of weight 1 in the same spot. Especially useful when combined with clustering.
*
* @param value a Float value
* @return property wrapper around Float
*/
public static PropertyValue<Float> heatmapWeight(Float value) {
return new PaintPropertyValue<>("heatmap-weight", value);
}
/**
* A measure of how much an individual point contributes to the heatmap. A value of 10 would be equivalent to having 10 points of weight 1 in the same spot. Especially useful when combined with clustering.
*
* @param expression an expression statement
* @return property wrapper around an expression statement
*/
public static PropertyValue<Expression> heatmapWeight(Expression expression) {
return new PaintPropertyValue<>("heatmap-weight", expression);
}
/**
* A measure of how much an individual point contributes to the heatmap. A value of 10 would be equivalent to having 10 points of weight 1 in the same spot. Especially useful when combined with clustering.
*
* @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
@Deprecated
public static <T> PropertyValue<Function<T, Float>> heatmapWeight(Function<T, Float> function) {
return new PaintPropertyValue<>("heatmap-weight", function);
}
/**
* Similar to {@link PropertyFactory#heatmapWeight} but controls the intensity of the heatmap globally. Primarily used for adjusting the heatmap based on zoom level.
*
* @param value a Float value
* @return property wrapper around Float
*/
public static PropertyValue<Float> heatmapIntensity(Float value) {
return new PaintPropertyValue<>("heatmap-intensity", value);
}
/**
* Similar to {@link PropertyFactory#heatmapWeight} but controls the intensity of the heatmap globally. Primarily used for adjusting the heatmap based on zoom level.
*
* @param expression an expression statement
* @return property wrapper around an expression statement
*/
public static PropertyValue<Expression> heatmapIntensity(Expression expression) {
return new PaintPropertyValue<>("heatmap-intensity", expression);
}
/**
* Similar to {@link PropertyFactory#heatmapWeight} but controls the intensity of the heatmap globally. Primarily used for adjusting the heatmap based on zoom level.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
@Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> heatmapIntensity(CameraFunction<Z, Float> function) {
return new PaintPropertyValue<>("heatmap-intensity", function);
}
/**
* The global opacity at which the heatmap layer will be drawn.
*
* @param value a Float value
* @return property wrapper around Float
*/
public static PropertyValue<Float> heatmapOpacity(Float value) {
return new PaintPropertyValue<>("heatmap-opacity", value);
}
/**
* The global opacity at which the heatmap layer will be drawn.
*
* @param expression an expression statement
* @return property wrapper around an expression statement
*/
public static PropertyValue<Expression> heatmapOpacity(Expression expression) {
return new PaintPropertyValue<>("heatmap-opacity", expression);
}
/**
* The global opacity at which the heatmap layer will be drawn.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
@Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> heatmapOpacity(CameraFunction<Z, Float> function) {
return new PaintPropertyValue<>("heatmap-opacity", function);
}
/**
* The opacity of the entire fill extrusion layer. This is rendered on a per-layer, not per-feature, basis, and data-driven styling is not available.
*

View File

@@ -37,18 +37,18 @@ public class CustomGeometrySource extends Source {
* @param provider The tile provider that returns geometry data for this source.
*/
public CustomGeometrySource(String id, GeometryTileProvider provider) {
this(id, provider, new GeoJsonOptions());
this(id, provider, new CustomGeometrySourceOptions());
}
/**
* Create a CustomGeometrySource with non-default GeoJsonOptions.
* Create a CustomGeometrySource with non-default CustomGeometrySourceOptions.
* <p>Supported options are minZoom, maxZoom, buffer, and tolerance.</p>
*
* @param id The source id.
* @param provider The tile provider that returns geometry data for this source.
* @param options GeoJsonOptions.
* @param options CustomGeometrySourceOptions.
*/
public CustomGeometrySource(String id, GeometryTileProvider provider, GeoJsonOptions options) {
public CustomGeometrySource(String id, GeometryTileProvider provider, CustomGeometrySourceOptions options) {
this.provider = provider;
executor = Executors.newFixedThreadPool(4);
initialize(id, options);

View File

@@ -0,0 +1,31 @@
package com.mapbox.mapboxsdk.style.sources;
/**
* Builder class for composing CustomGeometrySource objects.
*/
public class CustomGeometrySourceOptions extends GeoJsonOptions {
/**
* If the data includes wrapped coordinates, setting this to true unwraps the coordinates.
*
* @param wrap defaults to false
* @return the current instance for chaining
*/
public CustomGeometrySourceOptions withWrap(boolean wrap) {
this.put("wrap", wrap);
return this;
}
/**
* If the data includes geometry outside the tile boundaries, setting this to true clips the geometry
* to the tile boundaries.
*
* @param clip defaults to false
* @return the current instance for chaining
*/
public CustomGeometrySourceOptions withClip(boolean clip) {
this.put("clip", clip);
return this;
}
}

View File

@@ -0,0 +1,626 @@
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
package com.mapbox.mapboxsdk.testapp.style;
import android.graphics.Color;
import android.support.test.espresso.UiController;
import android.support.test.runner.AndroidJUnit4;
import timber.log.Timber;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.style.functions.CompositeFunction;
import com.mapbox.mapboxsdk.style.functions.CameraFunction;
import com.mapbox.mapboxsdk.style.functions.SourceFunction;
import com.mapbox.mapboxsdk.style.functions.stops.CategoricalStops;
import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops;
import com.mapbox.mapboxsdk.style.functions.stops.Stop;
import com.mapbox.mapboxsdk.style.functions.stops.Stops;
import com.mapbox.mapboxsdk.style.layers.HeatmapLayer;
import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction;
import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import static com.mapbox.mapboxsdk.style.functions.Function.*;
import static com.mapbox.mapboxsdk.style.functions.stops.Stop.stop;
import static com.mapbox.mapboxsdk.style.functions.stops.Stops.*;
import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke;
import static org.junit.Assert.*;
import static com.mapbox.mapboxsdk.style.layers.Property.*;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
/**
* Basic smoke tests for HeatmapLayer
*/
@RunWith(AndroidJUnit4.class)
public class HeatmapLayerTest extends BaseActivityTest {
private HeatmapLayer layer;
@Override
protected Class getActivityClass() {
return EspressoTestActivity.class;
}
private void setupLayer() {
Timber.i("Retrieving layer");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
Timber.i("Adding layer");
layer = new HeatmapLayer("my-layer", "composite");
layer.setSourceLayer("composite");
mapboxMap.addLayer(layer);
// Layer reference is now stale, get new reference
layer = mapboxMap.getLayerAs("my-layer");
}
}
});
}
@Test
public void testSetVisibility() {
validateTestSetup();
setupLayer();
Timber.i("Visibility");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Get initial
assertEquals(layer.getVisibility().getValue(), VISIBLE);
// Set
layer.setProperties(visibility(NONE));
assertEquals(layer.getVisibility().getValue(), NONE);
}
});
}
@Test
public void testSourceLayer() {
validateTestSetup();
setupLayer();
Timber.i("SourceLayer");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Get initial
assertEquals(layer.getSourceLayer(), "composite");
// Set
final String sourceLayer = "test";
layer.setSourceLayer(sourceLayer);
assertEquals(layer.getSourceLayer(), sourceLayer);
}
});
}
@Test
public void testHeatmapRadiusTransition() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-radiusTransitionOptions");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set and Get
TransitionOptions options = new TransitionOptions(300, 100);
layer.setHeatmapRadiusTransition(options);
assertEquals(layer.getHeatmapRadiusTransition(), options);
}
});
}
@Test
public void testHeatmapRadiusAsConstant() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-radius");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set and Get
layer.setProperties(heatmapRadius(0.3f));
assertEquals((Float) layer.getHeatmapRadius().getValue(), (Float) 0.3f);
}
});
}
@Test
public void testHeatmapRadiusAsCameraFunction() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-radius");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set
layer.setProperties(
heatmapRadius(
zoom(
exponential(
stop(2, heatmapRadius(0.3f))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getHeatmapRadius());
assertNotNull(layer.getHeatmapRadius().getFunction());
assertEquals(CameraFunction.class, layer.getHeatmapRadius().getFunction().getClass());
assertEquals(ExponentialStops.class, layer.getHeatmapRadius().getFunction().getStops().getClass());
assertEquals(0.5f, ((ExponentialStops) layer.getHeatmapRadius().getFunction().getStops()).getBase(), 0.001);
assertEquals(1, ((ExponentialStops) layer.getHeatmapRadius().getFunction().getStops()).size());
}
});
}
@Test
public void testHeatmapRadiusAsIdentitySourceFunction() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-radius");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set
layer.setProperties(
heatmapRadius(property("FeaturePropertyA", Stops.<Float>identity()))
);
// Verify
assertNotNull(layer.getHeatmapRadius());
assertNotNull(layer.getHeatmapRadius().getFunction());
assertEquals(SourceFunction.class, layer.getHeatmapRadius().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getHeatmapRadius().getFunction()).getProperty());
assertEquals(IdentityStops.class, layer.getHeatmapRadius().getFunction().getStops().getClass());
}
});
}
@Test
public void testHeatmapRadiusAsExponentialSourceFunction() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-radius");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set
layer.setProperties(
heatmapRadius(
property(
"FeaturePropertyA",
exponential(
stop(0.3f, heatmapRadius(0.3f))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getHeatmapRadius());
assertNotNull(layer.getHeatmapRadius().getFunction());
assertEquals(SourceFunction.class, layer.getHeatmapRadius().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getHeatmapRadius().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getHeatmapRadius().getFunction().getStops().getClass());
}
});
}
@Test
public void testHeatmapRadiusAsCategoricalSourceFunction() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-radius");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set
layer.setProperties(
heatmapRadius(
property(
"FeaturePropertyA",
categorical(
stop(1.0f, heatmapRadius(0.3f))
)
).withDefaultValue(heatmapRadius(0.3f))
)
);
// Verify
assertNotNull(layer.getHeatmapRadius());
assertNotNull(layer.getHeatmapRadius().getFunction());
assertEquals(SourceFunction.class, layer.getHeatmapRadius().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getHeatmapRadius().getFunction()).getProperty());
assertEquals(CategoricalStops.class, layer.getHeatmapRadius().getFunction().getStops().getClass());
assertNotNull(((SourceFunction) layer.getHeatmapRadius().getFunction()).getDefaultValue());
assertNotNull(((SourceFunction) layer.getHeatmapRadius().getFunction()).getDefaultValue().getValue());
assertEquals(0.3f, ((SourceFunction) layer.getHeatmapRadius().getFunction()).getDefaultValue().getValue());
}
});
}
@Test
public void testHeatmapRadiusAsCompositeFunction() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-radius");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set
layer.setProperties(
heatmapRadius(
composite(
"FeaturePropertyA",
exponential(
stop(0, 0.3f, heatmapRadius(0.9f))
).withBase(0.5f)
).withDefaultValue(heatmapRadius(0.3f))
)
);
// Verify
assertNotNull(layer.getHeatmapRadius());
assertNotNull(layer.getHeatmapRadius().getFunction());
assertEquals(CompositeFunction.class, layer.getHeatmapRadius().getFunction().getClass());
assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getHeatmapRadius().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getHeatmapRadius().getFunction().getStops().getClass());
assertEquals(1, ((ExponentialStops) layer.getHeatmapRadius().getFunction().getStops()).size());
ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
(ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getHeatmapRadius().getFunction().getStops();
Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
assertEquals(0f, stop.in.zoom, 0.001);
assertEquals(0.3f, stop.in.value, 0.001f);
assertEquals(0.9f, stop.out, 0.001f);
}
});
}
@Test
public void testHeatmapWeightAsConstant() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-weight");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set and Get
layer.setProperties(heatmapWeight(0.3f));
assertEquals((Float) layer.getHeatmapWeight().getValue(), (Float) 0.3f);
}
});
}
@Test
public void testHeatmapWeightAsCameraFunction() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-weight");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set
layer.setProperties(
heatmapWeight(
zoom(
exponential(
stop(2, heatmapWeight(0.3f))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getHeatmapWeight());
assertNotNull(layer.getHeatmapWeight().getFunction());
assertEquals(CameraFunction.class, layer.getHeatmapWeight().getFunction().getClass());
assertEquals(ExponentialStops.class, layer.getHeatmapWeight().getFunction().getStops().getClass());
assertEquals(0.5f, ((ExponentialStops) layer.getHeatmapWeight().getFunction().getStops()).getBase(), 0.001);
assertEquals(1, ((ExponentialStops) layer.getHeatmapWeight().getFunction().getStops()).size());
}
});
}
@Test
public void testHeatmapWeightAsIdentitySourceFunction() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-weight");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set
layer.setProperties(
heatmapWeight(property("FeaturePropertyA", Stops.<Float>identity()))
);
// Verify
assertNotNull(layer.getHeatmapWeight());
assertNotNull(layer.getHeatmapWeight().getFunction());
assertEquals(SourceFunction.class, layer.getHeatmapWeight().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getHeatmapWeight().getFunction()).getProperty());
assertEquals(IdentityStops.class, layer.getHeatmapWeight().getFunction().getStops().getClass());
}
});
}
@Test
public void testHeatmapWeightAsExponentialSourceFunction() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-weight");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set
layer.setProperties(
heatmapWeight(
property(
"FeaturePropertyA",
exponential(
stop(0.3f, heatmapWeight(0.3f))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getHeatmapWeight());
assertNotNull(layer.getHeatmapWeight().getFunction());
assertEquals(SourceFunction.class, layer.getHeatmapWeight().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getHeatmapWeight().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getHeatmapWeight().getFunction().getStops().getClass());
}
});
}
@Test
public void testHeatmapWeightAsCategoricalSourceFunction() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-weight");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set
layer.setProperties(
heatmapWeight(
property(
"FeaturePropertyA",
categorical(
stop(1.0f, heatmapWeight(0.3f))
)
).withDefaultValue(heatmapWeight(0.3f))
)
);
// Verify
assertNotNull(layer.getHeatmapWeight());
assertNotNull(layer.getHeatmapWeight().getFunction());
assertEquals(SourceFunction.class, layer.getHeatmapWeight().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getHeatmapWeight().getFunction()).getProperty());
assertEquals(CategoricalStops.class, layer.getHeatmapWeight().getFunction().getStops().getClass());
assertNotNull(((SourceFunction) layer.getHeatmapWeight().getFunction()).getDefaultValue());
assertNotNull(((SourceFunction) layer.getHeatmapWeight().getFunction()).getDefaultValue().getValue());
assertEquals(0.3f, ((SourceFunction) layer.getHeatmapWeight().getFunction()).getDefaultValue().getValue());
}
});
}
@Test
public void testHeatmapWeightAsCompositeFunction() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-weight");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set
layer.setProperties(
heatmapWeight(
composite(
"FeaturePropertyA",
exponential(
stop(0, 0.3f, heatmapWeight(0.9f))
).withBase(0.5f)
).withDefaultValue(heatmapWeight(0.3f))
)
);
// Verify
assertNotNull(layer.getHeatmapWeight());
assertNotNull(layer.getHeatmapWeight().getFunction());
assertEquals(CompositeFunction.class, layer.getHeatmapWeight().getFunction().getClass());
assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getHeatmapWeight().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getHeatmapWeight().getFunction().getStops().getClass());
assertEquals(1, ((ExponentialStops) layer.getHeatmapWeight().getFunction().getStops()).size());
ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
(ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getHeatmapWeight().getFunction().getStops();
Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
assertEquals(0f, stop.in.zoom, 0.001);
assertEquals(0.3f, stop.in.value, 0.001f);
assertEquals(0.9f, stop.out, 0.001f);
}
});
}
@Test
public void testHeatmapIntensityTransition() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-intensityTransitionOptions");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set and Get
TransitionOptions options = new TransitionOptions(300, 100);
layer.setHeatmapIntensityTransition(options);
assertEquals(layer.getHeatmapIntensityTransition(), options);
}
});
}
@Test
public void testHeatmapIntensityAsConstant() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-intensity");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set and Get
layer.setProperties(heatmapIntensity(0.3f));
assertEquals((Float) layer.getHeatmapIntensity().getValue(), (Float) 0.3f);
}
});
}
@Test
public void testHeatmapIntensityAsCameraFunction() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-intensity");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set
layer.setProperties(
heatmapIntensity(
zoom(
exponential(
stop(2, heatmapIntensity(0.3f))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getHeatmapIntensity());
assertNotNull(layer.getHeatmapIntensity().getFunction());
assertEquals(CameraFunction.class, layer.getHeatmapIntensity().getFunction().getClass());
assertEquals(ExponentialStops.class, layer.getHeatmapIntensity().getFunction().getStops().getClass());
assertEquals(0.5f, ((ExponentialStops) layer.getHeatmapIntensity().getFunction().getStops()).getBase(), 0.001);
assertEquals(1, ((ExponentialStops) layer.getHeatmapIntensity().getFunction().getStops()).size());
}
});
}
@Test
public void testHeatmapOpacityTransition() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-opacityTransitionOptions");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set and Get
TransitionOptions options = new TransitionOptions(300, 100);
layer.setHeatmapOpacityTransition(options);
assertEquals(layer.getHeatmapOpacityTransition(), options);
}
});
}
@Test
public void testHeatmapOpacityAsConstant() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-opacity");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set and Get
layer.setProperties(heatmapOpacity(0.3f));
assertEquals((Float) layer.getHeatmapOpacity().getValue(), (Float) 0.3f);
}
});
}
@Test
public void testHeatmapOpacityAsCameraFunction() {
validateTestSetup();
setupLayer();
Timber.i("heatmap-opacity");
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
@Override
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
assertNotNull(layer);
// Set
layer.setProperties(
heatmapOpacity(
zoom(
exponential(
stop(2, heatmapOpacity(0.3f))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getHeatmapOpacity());
assertNotNull(layer.getHeatmapOpacity().getFunction());
assertEquals(CameraFunction.class, layer.getHeatmapOpacity().getFunction().getClass());
assertEquals(ExponentialStops.class, layer.getHeatmapOpacity().getFunction().getStops().getClass());
assertEquals(0.5f, ((ExponentialStops) layer.getHeatmapOpacity().getFunction().getStops()).getBase(), 0.001);
assertEquals(1, ((ExponentialStops) layer.getHeatmapOpacity().getFunction().getStops()).size());
}
});
}
}

View File

@@ -800,6 +800,17 @@
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.style.HeatmapLayerActivity"
android:description="@string/description_heatmaplayer"
android:label="@string/activity_heatmaplayer">
<meta-data
android:name="@string/category"
android:value="@string/category_style"/>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.FeatureOverviewActivity"/>
</activity>
<!-- For Instrumentation tests -->
<activity

View File

@@ -0,0 +1,216 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.style.layers.HeatmapLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.testapp.R;
import java.net.MalformedURLException;
import java.net.URL;
import timber.log.Timber;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate;
import static com.mapbox.mapboxsdk.style.expressions.Expression.linear;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgba;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleOpacity;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleStrokeColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleStrokeWidth;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapIntensity;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapOpacity;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapRadius;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapWeight;
/**
* Test activity showcasing the heatmap layer api.
*/
public class HeatmapLayerActivity extends AppCompatActivity {
private static final String EARTHQUAKE_SOURCE_URL = "https://www.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson";
private static final String EARTHQUAKE_SOURCE_ID = "earthquakes";
private static final String HEATMAP_LAYER_ID = "earthquakes-heat";
private static final String HEATMAP_LAYER_SOURCE = "earthquakes";
private static final String CIRCLE_LAYER_ID = "earthquakes-circle";
private MapView mapView;
private MapboxMap mapboxMap;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_heatmaplayer);
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
mapboxMap = map;
addEarthquakeSource();
addHeatmapLayer();
addCircleLayer();
});
}
private void addEarthquakeSource() {
try {
mapboxMap.addSource(new GeoJsonSource(EARTHQUAKE_SOURCE_ID, new URL(EARTHQUAKE_SOURCE_URL)));
} catch (MalformedURLException malformedUrlException) {
Timber.e(malformedUrlException, "That's not an url... ");
}
}
private void addHeatmapLayer() {
HeatmapLayer layer = new HeatmapLayer(HEATMAP_LAYER_ID, EARTHQUAKE_SOURCE_ID);
layer.setMaxZoom(9);
layer.setSourceLayer(HEATMAP_LAYER_SOURCE);
layer.setProperties(
// TODO add heatmap color https://github.com/mapbox/mapbox-gl-native/issues/11172
// Color ramp for heatmap. Domain is 0 (low) to 1 (high).
// Begin color ramp at 0-stop with a 0-transparancy color
// to create a blur-like effect.
//heatmapColor(),
// Increase the heatmap weight based on frequency and property magnitude
heatmapWeight(
interpolate(
linear(), get("mag"),
stop(0, 0),
stop(6, 1)
)
),
// Increase the heatmap color weight weight by zoom level
// heatmap-intensity is a multiplier on top of heatmap-weight
heatmapIntensity(
interpolate(
linear(), zoom(),
stop(0, 1),
stop(9, 3)
)
),
// Adjust the heatmap radius by zoom level
heatmapRadius(
interpolate(
linear(), zoom(),
stop(0, 2),
stop(9, 20)
)
),
// Transition from heatmap to circle layer by zoom level
heatmapOpacity(
interpolate(
linear(), zoom(),
stop(7, 1),
stop(9, 0)
)
)
);
mapboxMap.addLayerAbove(layer, "waterway-label");
}
private void addCircleLayer() {
CircleLayer circleLayer = new CircleLayer(CIRCLE_LAYER_ID, EARTHQUAKE_SOURCE_ID);
circleLayer.setProperties(
// Size circle radius by earthquake magnitude and zoom level
circleRadius(
interpolate(
linear(), zoom(),
literal(7), interpolate(
linear(), get("mag"),
stop(1, 1),
stop(6, 4)
),
literal(16), interpolate(
linear(), get("mag"),
stop(1, 5),
stop(6, 50)
)
)
),
// Color circle by earthquake magnitude
circleColor(
interpolate(
linear(), get("mag"),
literal(1), rgba(33, 102, 172, 0),
literal(2), rgb(103, 169, 207),
literal(3), rgb(209, 229, 240),
literal(4), rgb(253, 219, 199),
literal(5), rgb(239, 138, 98),
literal(6), rgb(178, 24, 43)
)
),
// Transition from heatmap to circle layer by zoom level
circleOpacity(
interpolate(
linear(), zoom(),
stop(7, 0),
stop(8, 1)
)
),
circleStrokeColor("white"),
circleStrokeWidth(1.0f)
);
mapboxMap.addLayerBelow(circleLayer, HEATMAP_LAYER_ID);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:mapbox_styleUrl="@string/mapbox_style_dark"/>
</RelativeLayout>

View File

@@ -71,4 +71,5 @@
<string name="description_grid_source">Example Custom Geometry Source</string>
<string name="description_local_glyph">Suzhou using Droid Sans for Chinese glyphs</string>
<string name="description_hillshade">Example raster-dem source and hillshade layer</string>
<string name="description_heatmaplayer">Use HeatmapLayer to visualise earthquakes</string>
</resources>

View File

@@ -71,4 +71,5 @@
<string name="activity_grid_source">Grid Source</string>
<string name="activity_local_glyph">Local CJK glyph generation</string>
<string name="activity_hillshade">Hillshade</string>
<string name="activity_heatmaplayer">Heatmap layer</string>
</resources>

View File

@@ -158,6 +158,8 @@ add_library(mbgl-android STATIC
platform/android/src/style/layers/fill_extrusion_layer.hpp
platform/android/src/style/layers/fill_layer.cpp
platform/android/src/style/layers/fill_layer.hpp
platform/android/src/style/layers/heatmap_layer.cpp
platform/android/src/style/layers/heatmap_layer.hpp
platform/android/src/style/layers/hillshade_layer.cpp
platform/android/src/style/layers/hillshade_layer.hpp
platform/android/src/style/layers/layer.cpp

View File

@@ -27,6 +27,7 @@
"QueryRenderedFeaturesBoxHighlightActivity",
"MultiMapActivity",
"MapInDialogActivity",
"SimpleMapActivity",
"ManualZoomActivity",
"MaxMinZoomActivity",
"ScrollByActivity",
@@ -34,4 +35,4 @@
"SymbolGeneratorActivity",
"TextureViewTransparentBackgroundActivity",
"SimpleMapActivity"
]
]

View File

@@ -28,6 +28,9 @@ var layers = Object.keys(spec.layer.type.values).map((type) => {
}, []);
const paintProperties = Object.keys(spec[`paint_${type}`]).reduce((memo, name) => {
// disabled for now, see https://github.com/mapbox/mapbox-gl-native/issues/11172
if (name === 'heatmap-color') return memo;
spec[`paint_${type}`][name].name = name;
memo.push(spec[`paint_${type}`][name]);
return memo;

View File

@@ -77,8 +77,8 @@ void AndroidRendererFrontend::update(std::shared_ptr<UpdateParameters> params) {
mapRenderer.requestRender();
}
void AndroidRendererFrontend::onLowMemory() {
mapRenderer.actor().invoke(&Renderer::onLowMemory);
void AndroidRendererFrontend::reduceMemoryUse() {
mapRenderer.actor().invoke(&Renderer::reduceMemoryUse);
}
std::vector<Feature> AndroidRendererFrontend::querySourceFeatures(const std::string& sourceID,

View File

@@ -39,7 +39,7 @@ public:
AnnotationIDs queryShapeAnnotations(const ScreenBox& box) const;
// Memory
void onLowMemory();
void reduceMemoryUse();
private:
MapRenderer& mapRenderer;

View File

@@ -96,7 +96,7 @@ void nativeContextLost(void */*context*/) {
mbgl::Log::Info(mbgl::Event::General, "nativeContextLost");
}
void nativeDenitialize(void *context) {
void nativeDeinitialize(void *context) {
mbgl::Log::Info(mbgl::Event::General, "nativeDeinitialize");
delete reinterpret_cast<ExampleCustomLayer*>(context);
}
@@ -132,7 +132,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
env->SetStaticLongField(customLayerClass,
env->GetStaticFieldID(customLayerClass, "DeinitializeFunction", "J"),
reinterpret_cast<jlong>(nativeDenitialize));
reinterpret_cast<jlong>(nativeDeinitialize));
return JNI_VERSION_1_6;
}

View File

@@ -450,7 +450,7 @@ jni::Array<jni::jlong> NativeMapView::addMarkers(jni::JNIEnv& env, jni::Array<jn
}
void NativeMapView::onLowMemory(JNIEnv&) {
rendererFrontend->onLowMemory();
rendererFrontend->reduceMemoryUse();
}
using DebugOptions = mbgl::MapDebugOptions;

View File

@@ -0,0 +1,134 @@
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
#include "heatmap_layer.hpp"
#include <string>
#include "../conversion/property_value.hpp"
#include "../conversion/transition_options.hpp"
namespace mbgl {
namespace android {
/**
* Creates an owning peer object (for layers not attached to the map) from the JVM side
*/
HeatmapLayer::HeatmapLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
: Layer(env, std::make_unique<mbgl::style::HeatmapLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
}
/**
* Creates a non-owning peer object (for layers currently attached to the map)
*/
HeatmapLayer::HeatmapLayer(mbgl::Map& map, mbgl::style::HeatmapLayer& coreLayer)
: Layer(map, coreLayer) {
}
/**
* Creates an owning peer object (for layers not attached to the map)
*/
HeatmapLayer::HeatmapLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::HeatmapLayer> coreLayer)
: Layer(map, std::move(coreLayer)) {
}
HeatmapLayer::~HeatmapLayer() = default;
// Property getters
jni::Object<jni::ObjectTag> HeatmapLayer::getHeatmapRadius(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapRadius());
return jni::Object<jni::ObjectTag>(*converted);
}
jni::Object<TransitionOptions> HeatmapLayer::getHeatmapRadiusTransition(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
mbgl::style::TransitionOptions options = layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapRadiusTransition();
return *convert<jni::Object<TransitionOptions>>(env, options);
}
void HeatmapLayer::setHeatmapRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay) {
mbgl::style::TransitionOptions options;
options.duration.emplace(mbgl::Milliseconds(duration));
options.delay.emplace(mbgl::Milliseconds(delay));
layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::setHeatmapRadiusTransition(options);
}
jni::Object<jni::ObjectTag> HeatmapLayer::getHeatmapWeight(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapWeight());
return jni::Object<jni::ObjectTag>(*converted);
}
jni::Object<jni::ObjectTag> HeatmapLayer::getHeatmapIntensity(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapIntensity());
return jni::Object<jni::ObjectTag>(*converted);
}
jni::Object<TransitionOptions> HeatmapLayer::getHeatmapIntensityTransition(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
mbgl::style::TransitionOptions options = layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapIntensityTransition();
return *convert<jni::Object<TransitionOptions>>(env, options);
}
void HeatmapLayer::setHeatmapIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay) {
mbgl::style::TransitionOptions options;
options.duration.emplace(mbgl::Milliseconds(duration));
options.delay.emplace(mbgl::Milliseconds(delay));
layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::setHeatmapIntensityTransition(options);
}
jni::Object<jni::ObjectTag> HeatmapLayer::getHeatmapOpacity(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapOpacity());
return jni::Object<jni::ObjectTag>(*converted);
}
jni::Object<TransitionOptions> HeatmapLayer::getHeatmapOpacityTransition(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
mbgl::style::TransitionOptions options = layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapOpacityTransition();
return *convert<jni::Object<TransitionOptions>>(env, options);
}
void HeatmapLayer::setHeatmapOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) {
mbgl::style::TransitionOptions options;
options.duration.emplace(mbgl::Milliseconds(duration));
options.delay.emplace(mbgl::Milliseconds(delay));
layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::setHeatmapOpacityTransition(options);
}
jni::Class<HeatmapLayer> HeatmapLayer::javaClass;
jni::jobject* HeatmapLayer::createJavaPeer(jni::JNIEnv& env) {
static auto constructor = HeatmapLayer::javaClass.template GetConstructor<jni::jlong>(env);
return HeatmapLayer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
}
void HeatmapLayer::registerNative(jni::JNIEnv& env) {
// Lookup the class
HeatmapLayer::javaClass = *jni::Class<HeatmapLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
// Register the peer
jni::RegisterNativePeer<HeatmapLayer>(
env, HeatmapLayer::javaClass, "nativePtr",
std::make_unique<HeatmapLayer, JNIEnv&, jni::String, jni::String>,
"initialize",
"finalize",
METHOD(&HeatmapLayer::getHeatmapRadiusTransition, "nativeGetHeatmapRadiusTransition"),
METHOD(&HeatmapLayer::setHeatmapRadiusTransition, "nativeSetHeatmapRadiusTransition"),
METHOD(&HeatmapLayer::getHeatmapRadius, "nativeGetHeatmapRadius"),
METHOD(&HeatmapLayer::getHeatmapWeight, "nativeGetHeatmapWeight"),
METHOD(&HeatmapLayer::getHeatmapIntensityTransition, "nativeGetHeatmapIntensityTransition"),
METHOD(&HeatmapLayer::setHeatmapIntensityTransition, "nativeSetHeatmapIntensityTransition"),
METHOD(&HeatmapLayer::getHeatmapIntensity, "nativeGetHeatmapIntensity"),
METHOD(&HeatmapLayer::getHeatmapOpacityTransition, "nativeGetHeatmapOpacityTransition"),
METHOD(&HeatmapLayer::setHeatmapOpacityTransition, "nativeSetHeatmapOpacityTransition"),
METHOD(&HeatmapLayer::getHeatmapOpacity, "nativeGetHeatmapOpacity"));
}
} // namespace android
} // namespace mbgl

View File

@@ -0,0 +1,50 @@
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
#pragma once
#include "layer.hpp"
#include "../transition_options.hpp"
#include <mbgl/style/layers/heatmap_layer.hpp>
#include <jni/jni.hpp>
namespace mbgl {
namespace android {
class HeatmapLayer : public Layer {
public:
static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/HeatmapLayer"; };
static jni::Class<HeatmapLayer> javaClass;
static void registerNative(jni::JNIEnv&);
HeatmapLayer(jni::JNIEnv&, jni::String, jni::String);
HeatmapLayer(mbgl::Map&, mbgl::style::HeatmapLayer&);
HeatmapLayer(mbgl::Map&, std::unique_ptr<mbgl::style::HeatmapLayer>);
~HeatmapLayer();
// Properties
jni::Object<jni::ObjectTag> getHeatmapRadius(jni::JNIEnv&);
void setHeatmapRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay);
jni::Object<TransitionOptions> getHeatmapRadiusTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getHeatmapWeight(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getHeatmapIntensity(jni::JNIEnv&);
void setHeatmapIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay);
jni::Object<TransitionOptions> getHeatmapIntensityTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getHeatmapOpacity(jni::JNIEnv&);
void setHeatmapOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay);
jni::Object<TransitionOptions> getHeatmapOpacityTransition(jni::JNIEnv&);
jni::jobject* createJavaPeer(jni::JNIEnv&);
}; // class HeatmapLayer
} // namespace android
} // namespace mbgl

View File

@@ -10,6 +10,7 @@
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/fill_extrusion_layer.hpp>
#include <mbgl/style/layers/heatmap_layer.hpp>
#include <mbgl/style/layers/hillshade_layer.hpp>
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/style/layers/raster_layer.hpp>

View File

@@ -5,6 +5,7 @@
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/fill_extrusion_layer.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/heatmap_layer.hpp>
#include <mbgl/style/layers/hillshade_layer.hpp>
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
@@ -16,6 +17,7 @@
#include "custom_layer.hpp"
#include "fill_extrusion_layer.hpp"
#include "fill_layer.hpp"
#include "heatmap_layer.hpp"
#include "hillshade_layer.hpp"
#include "line_layer.hpp"
#include "raster_layer.hpp"
@@ -32,6 +34,7 @@ template <> struct PeerType<style::BackgroundLayer> { using Type = android::Back
template <> struct PeerType<style::CircleLayer> { using Type = android::CircleLayer; };
template <> struct PeerType<style::FillExtrusionLayer> { using Type = android::FillExtrusionLayer; };
template <> struct PeerType<style::FillLayer> { using Type = android::FillLayer; };
template <> struct PeerType<style::HeatmapLayer> { using Type = android::HeatmapLayer; };
template <> struct PeerType<style::HillshadeLayer> { using Type = android::HillshadeLayer; };
template <> struct PeerType<style::LineLayer> { using Type = android::LineLayer; };
template <> struct PeerType<style::RasterLayer> { using Type = android::RasterLayer; };
@@ -95,6 +98,7 @@ void registerNativeLayers(jni::JNIEnv& env) {
CustomLayer::registerNative(env);
FillExtrusionLayer::registerNative(env);
FillLayer::registerNative(env);
HeatmapLayer::registerNative(env);
HillshadeLayer::registerNative(env);
LineLayer::registerNative(env);
RasterLayer::registerNative(env);

View File

@@ -18,7 +18,7 @@ namespace mbgl {
namespace android {
// This conversion is expected not to fail because it's used only in contexts where
// the value was originally a GeoJsonOptions object on the Java side. If it fails
// the value was originally a CustomGeometrySourceOptions object on the Java side. If it fails
// to convert, it's a bug in our serialization or Java-side static typing.
static style::CustomGeometrySource::Options convertCustomGeometrySourceOptions(jni::JNIEnv& env,
jni::Object<> options,

View File

@@ -160,6 +160,7 @@ the following terms for concepts defined in the style specification:
In the style specification | In the SDK
---------------------------|---------
bounds | coordinate bounds
filter | predicate
function type | interpolation mode
id | identifier
@@ -200,6 +201,7 @@ In style JSON | In TileJSON | In the SDK
`tiles` | `tiles` | `tileURLTemplates` parameter in `-[MGLTileSource initWithIdentifier:tileURLTemplates:options:]`
`minzoom` | `minzoom` | `MGLTileSourceOptionMinimumZoomLevel`
`maxzoom` | `maxzoom` | `MGLTileSourceOptionMaximumZoomLevel`
`bounds` | `bounds` | `MGLTileSourceOptionCoordinateBounds`
`tileSize` | — | `MGLTileSourceOptionTileSize`
`attribution` | `attribution` | `MGLTileSourceOptionAttributionHTMLString` (but consider specifying `MGLTileSourceOptionAttributionInfos` instead for improved security)
`scheme` | `scheme` | `MGLTileSourceOptionTileCoordinateSystem`

View File

@@ -318,14 +318,15 @@ global.propertyDoc = function (propertyName, property, layerType, kind) {
doc += '* Predefined functions, including mathematical and string operators\n' +
'* Conditional expressions\n' +
'* Variable assignments and references to assigned variables\n';
const inputVariable = property.name === 'heatmap-color' ? '$heatmapDensity' : '$zoomLevel';
if (property["property-function"]) {
doc += '* Interpolation and step functions applied to the `$zoomLevel` variable and/or feature attributes\n';
doc += `* Interpolation and step functions applied to the \`${inputVariable}\` variable and/or feature attributes\n`;
} else if (property.function === "interpolated") {
doc += '* Interpolation and step functions applied to the `$zoomLevel` variable\n\n' +
doc += `* Interpolation and step functions applied to the \`${inputVariable}\` variable\n\n` +
'This property does not support applying interpolation or step functions to feature attributes.';
} else {
doc += '* Step functions applied to the `$zoomLevel` variable\n\n' +
'This property does not support applying interpolation functions to the `$zoomLevel` variable or applying interpolation or step functions to feature attributes.';
doc += `* Step functions applied to the \`${inputVariable}\` variable\n\n` +
`This property does not support applying interpolation functions to the \`${inputVariable}\` variable or applying interpolation or step functions to feature attributes.`;
}
}
return doc;
@@ -397,7 +398,7 @@ global.describeValue = function (value, property, layerType) {
throw new Error(`No description available for ${value[0]} expression in ${property.name} of ${layerType}.`);
}
}
switch (property.type) {
case 'boolean':
return value ? '`YES`' : '`NO`';

View File

@@ -23,6 +23,9 @@
"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."
},
"heatmap": {
"doc": "An `MGLHeatmapStyleLayer` is a style layer that renders a <a href=\"https://en.wikipedia.org/wiki/Heat_map\">heatmap</a>.\n\nA heatmap visualizes the spatial distribution of a large, dense set of point data, using color to avoid cluttering the map with individual points at low zoom levels. The points are weighted by an attribute you specify. Use a heatmap style layer in conjunction with 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\nConsider accompanying a heatmap style layer with an `MGLCircleStyleLayer` or `MGLSymbolStyleLayer` at high zoom levels. If you are unsure whether the point data in an `MGLShapeSource` is dense enough to warrant a heatmap, you can alternatively cluster the source using the `MGLShapeSourceOptionClustered` option and render the data using an `MGLCircleStyleLayer` or `MGLSymbolStyleLayer`."
},
"raster": {
"doc": "An `MGLRasterStyleLayer` is a style layer that renders georeferenced raster imagery on the map, especially raster tiles.\n\nUse a raster style layer to configure the color parameters of raster tiles loaded by an `MGLRasterSource` object or raster images loaded by an `MGLImageSource` 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.\n\nRaster images may also be used as icons or patterns in a style layer. To register an image for use as an icon or pattern, use the `-[MGLStyle setImage:forName:]` method. To configure a point annotation’s image, use the `MGLAnnotationImage` class."
},
@@ -79,6 +82,11 @@
"doc": "The base color of this layer. The extrusion's surfaces will be shaded differently based on this color in combination with the `light` settings. If this color is specified with an alpha component, the alpha component will be ignored; use `fill-extrusion-opacity` to set layer opacityco."
}
},
"paint_heatmap": {
"heatmap-color": {
"doc": "Defines the color of each pixel based on its density value in a heatmap. Should be an expression that uses `$heatmapDensity` as input."
}
},
"paint_line": {
"line-pattern": {
"doc": "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)."
@@ -114,4 +122,4 @@
"doc": "Distance that the text's anchor is moved from its original placement."
}
}
}
}

View File

@@ -81,6 +81,31 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionBuffer;
*/
extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance;
/**
An `NSNumber` object containing a Boolean value; specifies whether the shape of
an `MGLComputedShapeSource` should be wrapped to accomodate coordinates with
longitudes beyond −180 and 180. The default value is `NO`.
Setting this option to `YES` affects rendering performance.
This option is ignored when creating an instance of a class besides
`MGLComputedShapeSource`.
*/
extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionWrapsCoordinates;
/**
An `NSNumber` object containing a Boolean value; specifies whether the shape of
an `MGLComputedShapeSource` should be clipped at the edge of each tile. The
default value is `NO`.
Setting this option to `YES` affects rendering performance. Use this option to
clip `MGLPolyline`s and `MGLPolygon`s at tile boundaries without artifacts.
This option is ignored when creating an instance of a class besides
`MGLComputedShapeSource`.
*/
extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClipsCoordinates;
/**
`MGLAbstractShapeSource` is an abstract base class for map content sources that
supply vector shapes to be shown on the map. A shape source is added to an

View File

@@ -8,6 +8,8 @@ const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel = @"MGLShapeSour
const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @"MGLShapeSourceOptionMaximumZoomLevelForClustering";
const MGLShapeSourceOption MGLShapeSourceOptionMinimumZoomLevel = @"MGLShapeSourceOptionMinimumZoomLevel";
const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLShapeSourceOptionSimplificationTolerance";
const MGLShapeSourceOption MGLShapeSourceOptionWrapsCoordinates = @"MGLShapeSourceOptionWrapsCoordinates";
const MGLShapeSourceOption MGLShapeSourceOptionClipsCoordinates = @"MGLShapeSourceOptionClipsCoordinates";
@interface MGLAbstractShapeSource ()
@@ -113,5 +115,22 @@ mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDi
}
sourceOptions.tileOptions.tolerance = value.doubleValue;
}
if (NSNumber *value = options[MGLShapeSourceOptionWrapsCoordinates]) {
if (![value isKindOfClass:[NSNumber class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLShapeSourceOptionWrapsCoordinates must be an NSNumber."];
}
sourceOptions.tileOptions.wrap = value.boolValue;
}
if (NSNumber *value = options[MGLShapeSourceOptionClipsCoordinates]) {
if (![value isKindOfClass:[NSNumber class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLShapeSourceOptionClipsCoordinates must be an NSNumber."];
}
sourceOptions.tileOptions.clip = value.boolValue;
}
return sourceOptions;
}

View File

@@ -0,0 +1,189 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLFoundation.h"
#import "MGLVectorStyleLayer.h"
NS_ASSUME_NONNULL_BEGIN
/**
An `MGLHeatmapStyleLayer` is a style layer that renders a <a
href="https://en.wikipedia.org/wiki/Heat_map">heatmap</a>.
A heatmap visualizes the spatial distribution of a large, dense set of point
data, using color to avoid cluttering the map with individual points at low
zoom levels. The points are weighted by an attribute you specify. Use a heatmap
style layer in conjunction with point or point collection features in vector
tiles loaded by an `MGLVectorSource` object or `MGLPointAnnotation`,
`MGLPointFeature`, `MGLPointCollection`, or `MGLPointCollectionFeature`
instances in an `MGLShapeSource` object.
Consider accompanying a heatmap style layer with an `MGLCircleStyleLayer` or
`MGLSymbolStyleLayer` at high zoom levels. If you are unsure whether the point
data in an `MGLShapeSource` is dense enough to warrant a heatmap, you can
alternatively cluster the source using the `MGLShapeSourceOptionClustered`
option and render the data using an `MGLCircleStyleLayer` or
`MGLSymbolStyleLayer`.
You can access an existing heatmap 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 heatmap style layer and add it to the style using a method such as
`-[MGLStyle addLayer:]`.
### Example
```swift
let layer = MGLHeatmapStyleLayer(identifier: "earthquake-heat", source: earthquakes)
layer.heatmapWeight = NSExpression(format: "FUNCTION(magnitude, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', nil, %@)",
[0: 0,
6: 1])
layer.heatmapIntensity = NSExpression(format: "FUNCTION($zoomLevel, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', nil, %@)",
[0: 1,
9: 3])
mapView.style?.addLayer(layer)
```
*/
MGL_EXPORT
@interface MGLHeatmapStyleLayer : MGLVectorStyleLayer
/**
Returns a heatmap style layer initialized with an identifier and source.
After initializing and configuring the style layer, add it to a map view’s
style using the `-[MGLStyle addLayer:]` or
`-[MGLStyle insertLayer:belowLayer:]` method.
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param source The source from which to obtain the data to style. If the source
has not yet been added to the current style, the behavior is undefined.
@return An initialized foreground style layer.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source;
#pragma mark - Accessing the Paint Attributes
/**
Defines the color of each point based on its density value in a heatmap. Should
be an expression that uses `$heatmapDensity` as input.
The default value of this property is an expression that evaluates to a rainbow
color scale from blue to red. Set this property to `nil` to reset it to the
default value.
You can set this property to an expression containing any of the following:
* Constant `UIColor` values
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
* Interpolation and step functions applied to the `$heatmapDensity` variable
This property does not support applying interpolation or step functions to
feature attributes.
*/
@property (nonatomic, null_resettable) NSExpression *heatmapColor;
/**
Similar to `heatmapWeight` but controls the intensity of the heatmap globally.
Primarily used for adjusting the heatmap based on zoom level.
The default value of this property is an expression that evaluates to the float
`1`. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
* Constant numeric values
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
* Interpolation and step functions applied to the `$zoomLevel` variable
This property does not support applying interpolation or step functions to
feature attributes.
*/
@property (nonatomic, null_resettable) NSExpression *heatmapIntensity;
/**
The transition affecting any changes to this layer’s `heatmapIntensity` property.
This property corresponds to the `heatmap-intensity-transition` property in the style JSON file format.
*/
@property (nonatomic) MGLTransition heatmapIntensityTransition;
/**
The global opacity at which the heatmap layer will be drawn.
The default value of this property is an expression that evaluates to the float
`1`. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
* Constant numeric values
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
* Interpolation and step functions applied to the `$zoomLevel` variable
This property does not support applying interpolation or step functions to
feature attributes.
*/
@property (nonatomic, null_resettable) NSExpression *heatmapOpacity;
/**
The transition affecting any changes to this layer’s `heatmapOpacity` property.
This property corresponds to the `heatmap-opacity-transition` property in the style JSON file format.
*/
@property (nonatomic) MGLTransition heatmapOpacityTransition;
/**
Radius of influence of one heatmap point in points. Increasing the value makes
the heatmap smoother, but less detailed.
This property is measured in points.
The default value of this property is an expression that evaluates to the float
`30`. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
* Constant numeric values
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
* Interpolation and step functions applied to the `$zoomLevel` variable and/or
feature attributes
*/
@property (nonatomic, null_resettable) NSExpression *heatmapRadius;
/**
The transition affecting any changes to this layer’s `heatmapRadius` property.
This property corresponds to the `heatmap-radius-transition` property in the style JSON file format.
*/
@property (nonatomic) MGLTransition heatmapRadiusTransition;
/**
A measure of how much an individual point contributes to the heatmap. A value
of 10 would be equivalent to having 10 points of weight 1 in the same spot.
Especially useful when combined with clustering.
The default value of this property is an expression that evaluates to the float
`1`. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
* Constant numeric values
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
* Interpolation and step functions applied to the `$zoomLevel` variable and/or
feature attributes
*/
@property (nonatomic, null_resettable) NSExpression *heatmapWeight;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,210 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "NSPredicate+MGLAdditions.h"
#import "NSDate+MGLAdditions.h"
#import "MGLStyleLayer_Private.h"
#import "MGLStyleValue_Private.h"
#import "MGLHeatmapStyleLayer.h"
#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/layers/heatmap_layer.hpp>
@interface MGLHeatmapStyleLayer ()
@property (nonatomic, readonly) mbgl::style::HeatmapLayer *rawLayer;
@end
@implementation MGLHeatmapStyleLayer
- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source
{
auto layer = std::make_unique<mbgl::style::HeatmapLayer>(identifier.UTF8String, source.identifier.UTF8String);
return self = [super initWithPendingLayer:std::move(layer)];
}
- (mbgl::style::HeatmapLayer *)rawLayer
{
return (mbgl::style::HeatmapLayer *)super.rawLayer;
}
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
return @(self.rawLayer->getSourceID().c_str());
}
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
auto layerID = self.rawLayer->getSourceLayer();
return layerID.empty() ? nil : @(layerID.c_str());
}
- (void)setSourceLayerIdentifier:(NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
self.rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: "");
}
- (void)setPredicate:(NSPredicate *)predicate
{
MGLAssertStyleLayerIsValid();
self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter());
}
- (NSPredicate *)predicate
{
MGLAssertStyleLayerIsValid();
return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()];
}
#pragma mark - Accessing the Paint Attributes
- (void)setHeatmapColor:(NSExpression *)heatmapColor {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::HeatmapColorPropertyValue>(heatmapColor);
self.rawLayer->setHeatmapColor(mbglValue);
}
- (NSExpression *)heatmapColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getHeatmapColor();
if (propertyValue.isUndefined()) {
propertyValue = self.rawLayer->getDefaultHeatmapColor();
}
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
}
- (void)setHeatmapIntensity:(NSExpression *)heatmapIntensity {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(heatmapIntensity);
self.rawLayer->setHeatmapIntensity(mbglValue);
}
- (NSExpression *)heatmapIntensity {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getHeatmapIntensity();
if (propertyValue.isUndefined()) {
propertyValue = self.rawLayer->getDefaultHeatmapIntensity();
}
return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setHeatmapIntensityTransition:(MGLTransition )transition {
MGLAssertStyleLayerIsValid();
mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
self.rawLayer->setHeatmapIntensityTransition(options);
}
- (MGLTransition)heatmapIntensityTransition {
MGLAssertStyleLayerIsValid();
mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getHeatmapIntensityTransition();
MGLTransition transition;
transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
return transition;
}
- (void)setHeatmapOpacity:(NSExpression *)heatmapOpacity {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(heatmapOpacity);
self.rawLayer->setHeatmapOpacity(mbglValue);
}
- (NSExpression *)heatmapOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getHeatmapOpacity();
if (propertyValue.isUndefined()) {
propertyValue = self.rawLayer->getDefaultHeatmapOpacity();
}
return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setHeatmapOpacityTransition:(MGLTransition )transition {
MGLAssertStyleLayerIsValid();
mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
self.rawLayer->setHeatmapOpacityTransition(options);
}
- (MGLTransition)heatmapOpacityTransition {
MGLAssertStyleLayerIsValid();
mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getHeatmapOpacityTransition();
MGLTransition transition;
transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
return transition;
}
- (void)setHeatmapRadius:(NSExpression *)heatmapRadius {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(heatmapRadius);
self.rawLayer->setHeatmapRadius(mbglValue);
}
- (NSExpression *)heatmapRadius {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getHeatmapRadius();
if (propertyValue.isUndefined()) {
propertyValue = self.rawLayer->getDefaultHeatmapRadius();
}
return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setHeatmapRadiusTransition:(MGLTransition )transition {
MGLAssertStyleLayerIsValid();
mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
self.rawLayer->setHeatmapRadiusTransition(options);
}
- (MGLTransition)heatmapRadiusTransition {
MGLAssertStyleLayerIsValid();
mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getHeatmapRadiusTransition();
MGLTransition transition;
transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
return transition;
}
- (void)setHeatmapWeight:(NSExpression *)heatmapWeight {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(heatmapWeight);
self.rawLayer->setHeatmapWeight(mbglValue);
}
- (NSExpression *)heatmapWeight {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getHeatmapWeight();
if (propertyValue.isUndefined()) {
propertyValue = self.rawLayer->getDefaultHeatmapWeight();
}
return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
@end

View File

@@ -81,7 +81,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
@end
@interface MGLMapSnapshotter()
@property (nonatomic) BOOL loading;
@end
@implementation MGLMapSnapshotter {
@@ -90,6 +90,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
std::unique_ptr<mbgl::MapSnapshotter> _mbglMapSnapshotter;
std::unique_ptr<mbgl::Actor<mbgl::MapSnapshotter::Callback>> _snapshotCallback;
NS_ARRAY_OF(MGLAttributionInfo *) *_attributionInfo;
}
- (instancetype)initWithOptions:(MGLMapSnapshotOptions *)options
@@ -115,182 +116,192 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
format:@"Already started this snapshotter."];
}
_loading = true;
self.loading = true;
dispatch_async(queue, ^{
_snapshotCallback = std::make_unique<mbgl::Actor<mbgl::MapSnapshotter::Callback>>(*mbgl::Scheduler::GetCurrent(), [=](std::exception_ptr mbglError, mbgl::PremultipliedImage image, mbgl::MapSnapshotter::Attributions attributions, mbgl::MapSnapshotter::PointForFn pointForFn) {
_loading = false;
__weak __typeof__(self) weakSelf = self;
_snapshotCallback = std::make_unique<mbgl::Actor<mbgl::MapSnapshotter::Callback>>(*mbgl::Scheduler::GetCurrent(), [=](std::exception_ptr mbglError, mbgl::PremultipliedImage image, mbgl::MapSnapshotter::Attributions attributions, mbgl::MapSnapshotter::PointForFn pointForFn) {
__typeof__(self) strongSelf = weakSelf;
strongSelf.loading = false;
if (mbglError) {
NSString *description = @(mbgl::util::toString(mbglError).c_str());
NSDictionary *userInfo = @{NSLocalizedDescriptionKey: description};
NSError *error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeSnapshotFailed userInfo:userInfo];
NSMutableArray *infos = [NSMutableArray array];
// Dispatch result to origin queue
dispatch_async(queue, ^{
completion(nil, error);
});
} else {
#if TARGET_OS_IPHONE
CGFloat fontSize = [UIFont smallSystemFontSize];
UIColor *attributeFontColor = [UIColor blackColor];
MGLImage *mglImage = [[MGLImage alloc] initWithMGLPremultipliedImage:std::move(image) scale:strongSelf.options.scale];
#else
CGFloat fontSize = [NSFont systemFontSizeForControlSize:NSMiniControlSize];
NSColor *attributeFontColor = [NSColor blackColor];
MGLImage *mglImage = [[MGLImage alloc] initWithMGLPremultipliedImage:std::move(image)];
mglImage.size = NSMakeSize(mglImage.size.width / strongSelf.options.scale,
mglImage.size.height / strongSelf.options.scale);
#endif
for (auto attribution = attributions.begin(); attribution != attributions.end(); ++attribution) {
NSString *attributionHTMLString = @(attribution->c_str());
NSArray *tileSetInfos = [MGLAttributionInfo attributionInfosFromHTMLString:attributionHTMLString
fontSize:fontSize
linkColor:attributeFontColor];
[infos growArrayByAddingAttributionInfosFromArray:tileSetInfos];
}
_attributionInfo = infos;
if (mbglError) {
NSString *description = @(mbgl::util::toString(mbglError).c_str());
NSDictionary *userInfo = @{NSLocalizedDescriptionKey: description};
NSError *error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeSnapshotFailed userInfo:userInfo];
// Dispatch result to origin queue
dispatch_async(queue, ^{
completion(nil, error);
});
} else {
#if TARGET_OS_IPHONE
MGLImage *mglImage = [[MGLImage alloc] initWithMGLPremultipliedImage:std::move(image) scale:self.options.scale];
#else
MGLImage *mglImage = [[MGLImage alloc] initWithMGLPremultipliedImage:std::move(image)];
mglImage.size = NSMakeSize(mglImage.size.width / self.options.scale,
mglImage.size.height / self.options.scale);
#endif
// Process image watermark in a work queue
dispatch_queue_t workQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(workQueue, ^{
#if TARGET_OS_IPHONE
MGLAttributionInfoStyle attributionInfoStyle = MGLAttributionInfoStyleLong;
for (NSUInteger styleValue = MGLAttributionInfoStyleLong; styleValue >= MGLAttributionInfoStyleShort; styleValue--) {
attributionInfoStyle = (MGLAttributionInfoStyle)styleValue;
CGSize attributionSize = [self attributionSizeWithLogoStyle:attributionInfoStyle sourceAttributionStyle:attributionInfoStyle];
if (attributionSize.width <= mglImage.size.width) {
break;
}
}
UIImage *logoImage = [self logoImageWithStyle:attributionInfoStyle];
CGSize attributionBackgroundSize = [self attributionTextSizeWithStyle:attributionInfoStyle];
CGRect logoImageRect = CGRectMake(MGLLogoImagePosition.x, mglImage.size.height - (MGLLogoImagePosition.y + logoImage.size.height), logoImage.size.width, logoImage.size.height);
CGPoint attributionOrigin = CGPointMake(mglImage.size.width - 10 - attributionBackgroundSize.width,
logoImageRect.origin.y + (logoImageRect.size.height / 2) - (attributionBackgroundSize.height / 2) + 1);
if (!logoImage) {
CGSize defaultLogoSize = [self mapboxLongStyleLogo].size;
logoImageRect = CGRectMake(0, mglImage.size.height - (MGLLogoImagePosition.y + defaultLogoSize.height), 0, defaultLogoSize.height);
attributionOrigin = CGPointMake(10, logoImageRect.origin.y + (logoImageRect.size.height / 2) - (attributionBackgroundSize.height / 2) + 1);
}
CGRect attributionBackgroundFrame = CGRectMake(attributionOrigin.x,
attributionOrigin.y,
attributionBackgroundSize.width,
attributionBackgroundSize.height);
CGPoint attributionTextPosition = CGPointMake(attributionBackgroundFrame.origin.x + 10,
attributionBackgroundFrame.origin.y - 1);
CGRect cropRect = CGRectMake(attributionBackgroundFrame.origin.x * mglImage.scale,
attributionBackgroundFrame.origin.y * mglImage.scale,
attributionBackgroundSize.width * mglImage.scale,
attributionBackgroundSize.height * mglImage.scale);
UIGraphicsBeginImageContextWithOptions(mglImage.size, NO, self.options.scale);
[mglImage drawInRect:CGRectMake(0, 0, mglImage.size.width, mglImage.size.height)];
[logoImage drawInRect:logoImageRect];
UIImage *currentImage = UIGraphicsGetImageFromCurrentImageContext();
CGImageRef attributionImageRef = CGImageCreateWithImageInRect([currentImage CGImage], cropRect);
UIImage *attributionImage = [UIImage imageWithCGImage:attributionImageRef];
CGImageRelease(attributionImageRef);
CIImage *ciAttributionImage = [[CIImage alloc] initWithCGImage:attributionImage.CGImage];
UIImage *blurredAttributionBackground = [self blurredAttributionBackground:ciAttributionImage];
[blurredAttributionBackground drawInRect:attributionBackgroundFrame];
[self drawAttributionTextWithStyle:attributionInfoStyle origin:attributionTextPosition];
UIImage *compositedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
#else
NSSize targetSize = NSMakeSize(self.options.size.width, self.options.size.height);
NSRect targetFrame = NSMakeRect(0, 0, targetSize.width, targetSize.height);
MGLAttributionInfoStyle attributionInfoStyle = MGLAttributionInfoStyleLong;
for (NSUInteger styleValue = MGLAttributionInfoStyleLong; styleValue >= MGLAttributionInfoStyleShort; styleValue--) {
attributionInfoStyle = (MGLAttributionInfoStyle)styleValue;
CGSize attributionSize = [self attributionSizeWithLogoStyle:attributionInfoStyle sourceAttributionStyle:attributionInfoStyle];
if (attributionSize.width <= mglImage.size.width) {
break;
}
}
NSImage *logoImage = [self logoImageWithStyle:attributionInfoStyle];
CGSize attributionBackgroundSize = [self attributionTextSizeWithStyle:attributionInfoStyle];
NSImage *sourceImage = mglImage;
CGRect logoImageRect = CGRectMake(MGLLogoImagePosition.x, MGLLogoImagePosition.y, logoImage.size.width, logoImage.size.height);
CGPoint attributionOrigin = CGPointMake(targetFrame.size.width - 10 - attributionBackgroundSize.width,
MGLLogoImagePosition.y + 1);
if (!logoImage) {
CGSize defaultLogoSize = [self mapboxLongStyleLogo].size;
logoImageRect = CGRectMake(0, MGLLogoImagePosition.y, 0, defaultLogoSize.height);
attributionOrigin = CGPointMake(10, attributionOrigin.y);
}
CGRect attributionBackgroundFrame = CGRectMake(attributionOrigin.x,
attributionOrigin.y,
attributionBackgroundSize.width,
attributionBackgroundSize.height);
CGPoint attributionTextPosition = CGPointMake(attributionBackgroundFrame.origin.x + 10,
logoImageRect.origin.y + (logoImageRect.size.height / 2) - (attributionBackgroundSize.height / 2));
NSImage *compositedImage = nil;
NSImageRep *sourceImageRep = [sourceImage bestRepresentationForRect:targetFrame
context:nil
hints:nil];
compositedImage = [[NSImage alloc] initWithSize:targetSize];
[compositedImage lockFocus];
[sourceImageRep drawInRect: targetFrame];
if (logoImage) {
[logoImage drawInRect:logoImageRect];
}
NSBitmapImageRep *attributionBackground = [[NSBitmapImageRep alloc] initWithFocusedViewRect:attributionBackgroundFrame];
CIImage *attributionBackgroundImage = [[CIImage alloc] initWithCGImage:[attributionBackground CGImage]];
NSImage *blurredAttributionBackground = [self blurredAttributionBackground:attributionBackgroundImage];
[blurredAttributionBackground drawInRect:attributionBackgroundFrame];
[self drawAttributionTextWithStyle:attributionInfoStyle origin:attributionTextPosition];
[compositedImage unlockFocus];
#endif
// Dispatch result to origin queue
dispatch_async(queue, ^{
MGLMapSnapshot* snapshot = [[MGLMapSnapshot alloc] initWithImage:compositedImage scale:self.options.scale pointForFn:pointForFn];
completion(snapshot, nil);
});
});
}
});
_mbglMapSnapshotter->snapshot(_snapshotCallback->self());
[strongSelf drawAttributedSnapshot:attributions snapshotImage:mglImage pointForFn:pointForFn queue:queue completionHandler:completion];
}
_snapshotCallback = NULL;
});
dispatch_async(queue, ^{
_mbglMapSnapshotter->snapshot(_snapshotCallback->self());
});
}
- (MGLImage *)drawAttributedSnapshot:(mbgl::MapSnapshotter::Attributions)attributions snapshotImage:(MGLImage *)mglImage pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn queue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshotCompletionHandler)completion {
NSMutableArray *infos = [NSMutableArray array];
#if TARGET_OS_IPHONE
CGFloat fontSize = [UIFont smallSystemFontSize];
UIColor *attributeFontColor = [UIColor blackColor];
#else
CGFloat fontSize = [NSFont systemFontSizeForControlSize:NSMiniControlSize];
NSColor *attributeFontColor = [NSColor blackColor];
#endif
for (auto attribution = attributions.begin(); attribution != attributions.end(); ++attribution) {
NSString *attributionHTMLString = @(attribution->c_str());
NSArray *tileSetInfos = [MGLAttributionInfo attributionInfosFromHTMLString:attributionHTMLString
fontSize:fontSize
linkColor:attributeFontColor];
[infos growArrayByAddingAttributionInfosFromArray:tileSetInfos];
}
_attributionInfo = infos;
// Process image watermark in a work queue
dispatch_queue_t workQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(workQueue, ^{
#if TARGET_OS_IPHONE
MGLAttributionInfoStyle attributionInfoStyle = MGLAttributionInfoStyleLong;
for (NSUInteger styleValue = MGLAttributionInfoStyleLong; styleValue >= MGLAttributionInfoStyleShort; styleValue--) {
attributionInfoStyle = (MGLAttributionInfoStyle)styleValue;
CGSize attributionSize = [self attributionSizeWithLogoStyle:attributionInfoStyle sourceAttributionStyle:attributionInfoStyle];
if (attributionSize.width <= mglImage.size.width) {
break;
}
}
UIImage *logoImage = [self logoImageWithStyle:attributionInfoStyle];
CGSize attributionBackgroundSize = [self attributionTextSizeWithStyle:attributionInfoStyle];
CGRect logoImageRect = CGRectMake(MGLLogoImagePosition.x, mglImage.size.height - (MGLLogoImagePosition.y + logoImage.size.height), logoImage.size.width, logoImage.size.height);
CGPoint attributionOrigin = CGPointMake(mglImage.size.width - 10 - attributionBackgroundSize.width,
logoImageRect.origin.y + (logoImageRect.size.height / 2) - (attributionBackgroundSize.height / 2) + 1);
if (!logoImage) {
CGSize defaultLogoSize = [self mapboxLongStyleLogo].size;
logoImageRect = CGRectMake(0, mglImage.size.height - (MGLLogoImagePosition.y + defaultLogoSize.height), 0, defaultLogoSize.height);
attributionOrigin = CGPointMake(10, logoImageRect.origin.y + (logoImageRect.size.height / 2) - (attributionBackgroundSize.height / 2) + 1);
}
CGRect attributionBackgroundFrame = CGRectMake(attributionOrigin.x,
attributionOrigin.y,
attributionBackgroundSize.width,
attributionBackgroundSize.height);
CGPoint attributionTextPosition = CGPointMake(attributionBackgroundFrame.origin.x + 10,
attributionBackgroundFrame.origin.y - 1);
CGRect cropRect = CGRectMake(attributionBackgroundFrame.origin.x * mglImage.scale,
attributionBackgroundFrame.origin.y * mglImage.scale,
attributionBackgroundSize.width * mglImage.scale,
attributionBackgroundSize.height * mglImage.scale);
UIGraphicsBeginImageContextWithOptions(mglImage.size, NO, self.options.scale);
[mglImage drawInRect:CGRectMake(0, 0, mglImage.size.width, mglImage.size.height)];
[logoImage drawInRect:logoImageRect];
UIImage *currentImage = UIGraphicsGetImageFromCurrentImageContext();
CGImageRef attributionImageRef = CGImageCreateWithImageInRect([currentImage CGImage], cropRect);
UIImage *attributionImage = [UIImage imageWithCGImage:attributionImageRef];
CGImageRelease(attributionImageRef);
CIImage *ciAttributionImage = [[CIImage alloc] initWithCGImage:attributionImage.CGImage];
UIImage *blurredAttributionBackground = [self blurredAttributionBackground:ciAttributionImage];
[blurredAttributionBackground drawInRect:attributionBackgroundFrame];
[self drawAttributionTextWithStyle:attributionInfoStyle origin:attributionTextPosition];
UIImage *compositedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
#else
NSSize targetSize = NSMakeSize(self.options.size.width, self.options.size.height);
NSRect targetFrame = NSMakeRect(0, 0, targetSize.width, targetSize.height);
MGLAttributionInfoStyle attributionInfoStyle = MGLAttributionInfoStyleLong;
for (NSUInteger styleValue = MGLAttributionInfoStyleLong; styleValue >= MGLAttributionInfoStyleShort; styleValue--) {
attributionInfoStyle = (MGLAttributionInfoStyle)styleValue;
CGSize attributionSize = [self attributionSizeWithLogoStyle:attributionInfoStyle sourceAttributionStyle:attributionInfoStyle];
if (attributionSize.width <= mglImage.size.width) {
break;
}
}
NSImage *logoImage = [self logoImageWithStyle:attributionInfoStyle];
CGSize attributionBackgroundSize = [self attributionTextSizeWithStyle:attributionInfoStyle];
NSImage *sourceImage = mglImage;
CGRect logoImageRect = CGRectMake(MGLLogoImagePosition.x, MGLLogoImagePosition.y, logoImage.size.width, logoImage.size.height);
CGPoint attributionOrigin = CGPointMake(targetFrame.size.width - 10 - attributionBackgroundSize.width,
MGLLogoImagePosition.y + 1);
if (!logoImage) {
CGSize defaultLogoSize = [self mapboxLongStyleLogo].size;
logoImageRect = CGRectMake(0, MGLLogoImagePosition.y, 0, defaultLogoSize.height);
attributionOrigin = CGPointMake(10, attributionOrigin.y);
}
CGRect attributionBackgroundFrame = CGRectMake(attributionOrigin.x,
attributionOrigin.y,
attributionBackgroundSize.width,
attributionBackgroundSize.height);
CGPoint attributionTextPosition = CGPointMake(attributionBackgroundFrame.origin.x + 10,
logoImageRect.origin.y + (logoImageRect.size.height / 2) - (attributionBackgroundSize.height / 2));
NSImage *compositedImage = nil;
NSImageRep *sourceImageRep = [sourceImage bestRepresentationForRect:targetFrame
context:nil
hints:nil];
compositedImage = [[NSImage alloc] initWithSize:targetSize];
[compositedImage lockFocus];
[sourceImageRep drawInRect: targetFrame];
if (logoImage) {
[logoImage drawInRect:logoImageRect];
}
NSBitmapImageRep *attributionBackground = [[NSBitmapImageRep alloc] initWithFocusedViewRect:attributionBackgroundFrame];
CIImage *attributionBackgroundImage = [[CIImage alloc] initWithCGImage:[attributionBackground CGImage]];
NSImage *blurredAttributionBackground = [self blurredAttributionBackground:attributionBackgroundImage];
[blurredAttributionBackground drawInRect:attributionBackgroundFrame];
[self drawAttributionTextWithStyle:attributionInfoStyle origin:attributionTextPosition];
[compositedImage unlockFocus];
#endif
// Dispatch result to origin queue
dispatch_async(queue, ^{
MGLMapSnapshot* snapshot = [[MGLMapSnapshot alloc] initWithImage:compositedImage scale:self.options.scale pointForFn:pointForFn];
completion(snapshot, nil);
});
});
return nil;
}
- (void)drawAttributionTextWithStyle:(MGLAttributionInfoStyle)attributionInfoStyle origin:(CGPoint)origin

View File

@@ -56,9 +56,9 @@ public:
return renderer.get();
}
void onLowMemory() {
void reduceMemoryUse() {
if (!renderer) return;
renderer->onLowMemory();
renderer->reduceMemoryUse();
}
private:

View File

@@ -8,6 +8,7 @@
#import "MGLLineStyleLayer.h"
#import "MGLCircleStyleLayer.h"
#import "MGLSymbolStyleLayer.h"
#import "MGLHeatmapStyleLayer.h"
#import "MGLHillshadeStyleLayer.h"
#import "MGLRasterStyleLayer.h"
#import "MGLBackgroundStyleLayer.h"
@@ -36,6 +37,7 @@
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
#include <mbgl/style/layers/heatmap_layer.hpp>
#include <mbgl/style/layers/hillshade_layer.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/background_layer.hpp>
@@ -401,6 +403,8 @@ static NSURL *MGLStyleURL_trafficNight;
return [[MGLSymbolStyleLayer alloc] initWithRawLayer:symbolLayer];
} else if (auto rasterLayer = rawLayer->as<mbgl::style::RasterLayer>()) {
return [[MGLRasterStyleLayer alloc] initWithRawLayer:rasterLayer];
} else if (auto heatmapLayer = rawLayer->as<mbgl::style::HeatmapLayer>()) {
return [[MGLHeatmapStyleLayer alloc] initWithRawLayer:heatmapLayer];
} else if (auto hillshadeLayer = rawLayer->as<mbgl::style::HillshadeLayer>()) {
return [[MGLHillshadeStyleLayer alloc] initWithRawLayer:hillshadeLayer];
} else if (auto circleLayer = rawLayer->as<mbgl::style::CircleLayer>()) {

View File

@@ -157,7 +157,9 @@ namespace mbgl {
- (void)set<%- camelize(property.name) %>:(NSExpression *)<%- objCName(property) %> {
MGLAssertStyleLayerIsValid();
<% if (property["property-function"]) { -%>
<% if (property.name === 'heatmap-color') { -%>
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::HeatmapColorPropertyValue>(heatmapColor);
<% } else if (property["property-function"]) { -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<<%- valueTransformerArguments(property)[0] %>>>(<%- objCName(property) %>);
<% } else { -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::PropertyValue<<%- valueTransformerArguments(property)[0] %>>>(<%- objCName(property) %>);

View File

@@ -10,6 +10,7 @@
#import "MGLConversion.h"
#include <mbgl/style/conversion/property_value.hpp>
#include <mbgl/style/conversion/data_driven_property_value.hpp>
#include <mbgl/style/conversion/heatmap_color_property_value.hpp>
#include <mbgl/style/conversion/position.hpp>
#import <mbgl/style/types.hpp>
@@ -52,11 +53,20 @@ public:
return mbglValue.evaluate(evaluator);
}
// Convert an mbgl heatmap color property value into an mgl style value
NSExpression *toExpression(const mbgl::style::HeatmapColorPropertyValue &mbglValue) {
if (mbglValue.isUndefined()) {
return nil;
}
return [NSExpression mgl_expressionWithJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())];
}
/**
Converts an NSExpression to an mbgl property value.
*/
template <typename MBGLValue>
MBGLValue toPropertyValue(NSExpression *expression) {
typename std::enable_if_t<!std::is_same<MBGLValue, mbgl::style::HeatmapColorPropertyValue>::value,
MBGLValue> toPropertyValue(NSExpression *expression) {
if (!expression) {
return {};
}
@@ -85,6 +95,30 @@ public:
return *value;
}
/**
Converts an NSExpression to an mbgl property value.
*/
template <typename MBGLValue>
typename std::enable_if_t<std::is_same<MBGLValue, mbgl::style::HeatmapColorPropertyValue>::value,
MBGLValue> toPropertyValue(NSExpression *expression) {
if (!expression) {
return {};
}
NSArray *jsonExpression = expression.mgl_jsonExpressionObject;
mbgl::style::conversion::Error valueError;
auto value = mbgl::style::conversion::convert<mbgl::style::HeatmapColorPropertyValue>(
mbgl::style::conversion::makeConvertible(jsonExpression), valueError);
if (!value) {
[NSException raise:NSInvalidArgumentException
format:@"Invalid property value: %@", @(valueError.message.c_str())];
return {};
}
return *value;
}
private: // Private utilities for converting from mgl to mbgl values

View File

@@ -41,6 +41,20 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionMinimumZoomLevel;
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionMaximumZoomLevel;
/**
An `NSValue` object containing an `MGLCoordinateBounds` struct that specifies
the geographic extent of the source.
If this option is specified, the SDK avoids requesting any tile that falls
outside of the coordinate bounds. Otherwise, the SDK requests any tile needed
to cover the viewport, as it does by default.
This option corresponds to the `bounds` key in the
<a href="https://github.com/mapbox/tilejson-spec/tree/master/2.1.0">TileJSON</a>
specification.
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionCoordinateBounds;
#if TARGET_OS_IPHONE
/**
An HTML string defining the buttons to be displayed in an action sheet when the

View File

@@ -1,7 +1,9 @@
#import "MGLTileSource_Private.h"
#import "MGLAttributionInfo_Private.h"
#import "MGLGeometry_Private.h"
#import "NSString+MGLAdditions.h"
#import "NSValue+MGLAdditions.h"
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
@@ -13,6 +15,7 @@
const MGLTileSourceOption MGLTileSourceOptionMinimumZoomLevel = @"MGLTileSourceOptionMinimumZoomLevel";
const MGLTileSourceOption MGLTileSourceOptionMaximumZoomLevel = @"MGLTileSourceOptionMaximumZoomLevel";
const MGLTileSourceOption MGLTileSourceOptionCoordinateBounds = @"MGLTileSourceOptionCoordinateBounds";
const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLString = @"MGLTileSourceOptionAttributionHTMLString";
const MGLTileSourceOption MGLTileSourceOptionAttributionInfos = @"MGLTileSourceOptionAttributionInfos";
const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem = @"MGLTileSourceOptionTileCoordinateSystem";
@@ -70,6 +73,15 @@ mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTem
[NSException raise:NSInvalidArgumentException
format:@"MGLTileSourceOptionMinimumZoomLevel must be less than MGLTileSourceOptionMaximumZoomLevel."];
}
if (NSValue *coordinateBounds = options[MGLTileSourceOptionCoordinateBounds]) {
if (![coordinateBounds isKindOfClass:[NSValue class]]
&& strcmp(coordinateBounds.objCType, @encode(MGLCoordinateBounds)) == 0) {
[NSException raise:NSInvalidArgumentException
format:@"MGLTileSourceOptionCoordinateBounds must be set to an NSValue containing an MGLCoordinateBounds."];
}
tileSet.bounds = MGLLatLngBoundsFromCoordinateBounds(coordinateBounds.MGLCoordinateBoundsValue);
}
if (NSString *attribution = options[MGLTileSourceOptionAttributionHTMLString]) {
if (![attribution isKindOfClass:[NSString class]]) {

View File

@@ -10,10 +10,10 @@ NS_ASSUME_NONNULL_BEGIN
is defined by an `MGLShapeSource` or `MGLVectorSource` object.
Create instances of `MGLCircleStyleLayer`, `MGLFillStyleLayer`,
`MGLFillExtrusionStyleLayer`, `MGLLineStyleLayer`, and `MGLSymbolStyleLayer` in
order to use `MGLVectorStyleLayer`'s properties and methods. Do not create
instances of `MGLVectorStyleLayer` directly, and do not create your own
subclasses of this class.
`MGLFillExtrusionStyleLayer`, `MGLHeatmapStyleLayer`, `MGLLineStyleLayer`, and
`MGLSymbolStyleLayer` in order to use `MGLVectorStyleLayer`'s properties and
methods. Do not create instances of `MGLVectorStyleLayer` directly, and do not
create your own subclasses of this class.
*/
MGL_EXPORT
@interface MGLVectorStyleLayer : MGLForegroundStyleLayer

View File

@@ -230,6 +230,24 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "buildings"))
}
func testMGLHeatmapStyleLayer() {
let earthquakes = MGLShapeSource(identifier: "earthquakes", url: URL(string: "https://example.com/earthquakes.json")!, options: [:])
mapView.style?.addSource(earthquakes)
//#-example-code
let layer = MGLHeatmapStyleLayer(identifier: "earthquake-heat", source: earthquakes)
layer.heatmapWeight = NSExpression(format: "FUNCTION(magnitude, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', nil, %@)",
[0: 0,
6: 1])
layer.heatmapIntensity = NSExpression(format: "FUNCTION($zoomLevel, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', nil, %@)",
[0: 1,
9: 3])
mapView.style?.addLayer(layer)
//#-end-example-code
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "earthquake-heat"))
}
func testMGLSymbolStyleLayer() {
let pois = MGLVectorSource(identifier: "pois", configurationURL: URL(string: "https://example.com/style.json")!)

View File

@@ -0,0 +1,61 @@
#import <Mapbox/Mapbox.h>
#import <XCTest/XCTest.h>
#import "MGLStyleLayer_Private.h"
#include <mbgl/style/layers/heatmap_layer.hpp>
@interface MGLHeatmapColorTests : XCTestCase <MGLMapViewDelegate>
@end
@implementation MGLHeatmapColorTests
- (void)testProperties {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
MGLHeatmapStyleLayer *layer = [[MGLHeatmapStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
auto rawLayer = layer.rawLayer->as<mbgl::style::HeatmapLayer>();
XCTAssertTrue(rawLayer->getHeatmapColor().isUndefined(),
@"heatmap-color should be unset initially.");
NSExpression *defaultExpression = layer.heatmapColor;
NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
layer.heatmapColor = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getHeatmapColor().evaluate(0.0), mbgl::Color::red(),
@"Setting heatmapColor to a constant value expression should update heatmap-color.");
XCTAssertEqualObjects(layer.heatmapColor, constantExpression,
@"heatmapColor should round-trip constant value expressions.");
constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
NSExpression *constantExpression2 = [NSExpression expressionWithFormat:@"%@", [MGLColor blueColor]];
NSExpression *functionExpression = [NSExpression expressionWithFormat:@"FUNCTION($heatmapDensity, 'mgl_stepWithMinimum:stops:', %@, %@)", constantExpression, @{@12: constantExpression2}];
layer.heatmapColor = functionExpression;
XCTAssertEqual(rawLayer->getHeatmapColor().evaluate(11.0), mbgl::Color::red(),
@"Setting heatmapColor to an expression depending on $heatmapDensity should update heatmap-color.");
XCTAssertEqual(rawLayer->getHeatmapColor().evaluate(12.0), mbgl::Color::blue(),
@"Setting heatmapColor to an expression depending on $heatmapDensity should update heatmap-color.");
XCTAssertEqualObjects(layer.heatmapColor, functionExpression,
@"heatmapColor should round-trip expressions depending on $heatmapDensity.");
layer.heatmapColor = nil;
XCTAssertTrue(rawLayer->getHeatmapColor().isUndefined(),
@"Unsetting heatmapColor should return heatmap-color to the default value.");
XCTAssertEqualObjects(layer.heatmapColor, defaultExpression,
@"heatmapColor should return the default value after being unset.");
functionExpression = [NSExpression expressionWithFormat:@"FUNCTION($zoomLevel, 'mgl_stepWithMinimum:stops:', %@, %@)", constantExpression, @{@18: constantExpression}];
XCTAssertThrowsSpecificNamed(layer.heatmapColor = functionExpression, NSException, NSInvalidArgumentException, @"MGLHeatmapLayer should raise an exception if a camera expression is applied to heatmapColor.");
functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
XCTAssertThrowsSpecificNamed(layer.heatmapColor = functionExpression, NSException, NSInvalidArgumentException, @"MGLHeatmapLayer should raise an exception if a data expression is applied to heatmapColor.");
functionExpression = [NSExpression expressionWithFormat:@"FUNCTION(bogus, 'mgl_stepWithMinimum:stops:', %@, %@)", constantExpression, @{@18: constantExpression}];
functionExpression = [NSExpression expressionWithFormat:@"FUNCTION($zoomLevel, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', nil, %@)", @{@10: functionExpression}];
XCTAssertThrowsSpecificNamed(layer.heatmapColor = functionExpression, NSException, NSInvalidArgumentException, @"MGLHeatmapLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
@end

View File

@@ -0,0 +1,296 @@
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLStyleLayerTests.h"
#import "../../darwin/src/NSDate+MGLAdditions.h"
#import "MGLStyleLayer_Private.h"
#include <mbgl/style/layers/heatmap_layer.hpp>
#include <mbgl/style/transition_options.hpp>
@interface MGLHeatmapLayerTests : MGLStyleLayerTests
@end
@implementation MGLHeatmapLayerTests
+ (NSString *)layerType {
return @"heatmap";
}
- (void)testPredicates {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
MGLHeatmapStyleLayer *layer = [[MGLHeatmapStyleLayer 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];
MGLHeatmapStyleLayer *layer = [[MGLHeatmapStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
XCTAssertNotEqual(layer.rawLayer, nullptr);
XCTAssertTrue(layer.rawLayer->is<mbgl::style::HeatmapLayer>());
auto rawLayer = layer.rawLayer->as<mbgl::style::HeatmapLayer>();
MGLTransition transitionTest = MGLTransitionMake(5, 4);
// heatmap-intensity
{
XCTAssertTrue(rawLayer->getHeatmapIntensity().isUndefined(),
@"heatmap-intensity should be unset initially.");
NSExpression *defaultExpression = layer.heatmapIntensity;
NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
layer.heatmapIntensity = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getHeatmapIntensity(), propertyValue,
@"Setting heatmapIntensity to a constant value expression should update heatmap-intensity.");
XCTAssertEqualObjects(layer.heatmapIntensity, constantExpression,
@"heatmapIntensity should round-trip constant value expressions.");
constantExpression = [NSExpression expressionWithFormat:@"0xff"];
NSExpression *functionExpression = [NSExpression expressionWithFormat:@"FUNCTION($zoomLevel, 'mgl_stepWithMinimum:stops:', %@, %@)", constantExpression, @{@18: constantExpression}];
layer.heatmapIntensity = functionExpression;
mbgl::style::IntervalStops<float> intervalStops = {{
{ -INFINITY, 0xff },
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getHeatmapIntensity(), propertyValue,
@"Setting heatmapIntensity to a camera expression should update heatmap-intensity.");
XCTAssertEqualObjects(layer.heatmapIntensity, functionExpression,
@"heatmapIntensity should round-trip camera expressions.");
layer.heatmapIntensity = nil;
XCTAssertTrue(rawLayer->getHeatmapIntensity().isUndefined(),
@"Unsetting heatmapIntensity should return heatmap-intensity to the default value.");
XCTAssertEqualObjects(layer.heatmapIntensity, defaultExpression,
@"heatmapIntensity should return the default value after being unset.");
functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
XCTAssertThrowsSpecificNamed(layer.heatmapIntensity = functionExpression, NSException, NSInvalidArgumentException, @"MGLHeatmapLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
functionExpression = [NSExpression expressionWithFormat:@"FUNCTION(bogus, 'mgl_stepWithMinimum:stops:', %@, %@)", constantExpression, @{@18: constantExpression}];
functionExpression = [NSExpression expressionWithFormat:@"FUNCTION($zoomLevel, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', nil, %@)", @{@10: functionExpression}];
XCTAssertThrowsSpecificNamed(layer.heatmapIntensity = functionExpression, NSException, NSInvalidArgumentException, @"MGLHeatmapLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
// Transition property test
layer.heatmapIntensityTransition = transitionTest;
auto toptions = rawLayer->getHeatmapIntensityTransition();
XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
MGLTransition heatmapIntensityTransition = layer.heatmapIntensityTransition;
XCTAssertEqual(heatmapIntensityTransition.delay, transitionTest.delay);
XCTAssertEqual(heatmapIntensityTransition.duration, transitionTest.duration);
}
// heatmap-opacity
{
XCTAssertTrue(rawLayer->getHeatmapOpacity().isUndefined(),
@"heatmap-opacity should be unset initially.");
NSExpression *defaultExpression = layer.heatmapOpacity;
NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
layer.heatmapOpacity = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getHeatmapOpacity(), propertyValue,
@"Setting heatmapOpacity to a constant value expression should update heatmap-opacity.");
XCTAssertEqualObjects(layer.heatmapOpacity, constantExpression,
@"heatmapOpacity should round-trip constant value expressions.");
constantExpression = [NSExpression expressionWithFormat:@"0xff"];
NSExpression *functionExpression = [NSExpression expressionWithFormat:@"FUNCTION($zoomLevel, 'mgl_stepWithMinimum:stops:', %@, %@)", constantExpression, @{@18: constantExpression}];
layer.heatmapOpacity = functionExpression;
mbgl::style::IntervalStops<float> intervalStops = {{
{ -INFINITY, 0xff },
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getHeatmapOpacity(), propertyValue,
@"Setting heatmapOpacity to a camera expression should update heatmap-opacity.");
XCTAssertEqualObjects(layer.heatmapOpacity, functionExpression,
@"heatmapOpacity should round-trip camera expressions.");
layer.heatmapOpacity = nil;
XCTAssertTrue(rawLayer->getHeatmapOpacity().isUndefined(),
@"Unsetting heatmapOpacity should return heatmap-opacity to the default value.");
XCTAssertEqualObjects(layer.heatmapOpacity, defaultExpression,
@"heatmapOpacity should return the default value after being unset.");
functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
XCTAssertThrowsSpecificNamed(layer.heatmapOpacity = functionExpression, NSException, NSInvalidArgumentException, @"MGLHeatmapLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
functionExpression = [NSExpression expressionWithFormat:@"FUNCTION(bogus, 'mgl_stepWithMinimum:stops:', %@, %@)", constantExpression, @{@18: constantExpression}];
functionExpression = [NSExpression expressionWithFormat:@"FUNCTION($zoomLevel, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', nil, %@)", @{@10: functionExpression}];
XCTAssertThrowsSpecificNamed(layer.heatmapOpacity = functionExpression, NSException, NSInvalidArgumentException, @"MGLHeatmapLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
// Transition property test
layer.heatmapOpacityTransition = transitionTest;
auto toptions = rawLayer->getHeatmapOpacityTransition();
XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
MGLTransition heatmapOpacityTransition = layer.heatmapOpacityTransition;
XCTAssertEqual(heatmapOpacityTransition.delay, transitionTest.delay);
XCTAssertEqual(heatmapOpacityTransition.duration, transitionTest.duration);
}
// heatmap-radius
{
XCTAssertTrue(rawLayer->getHeatmapRadius().isUndefined(),
@"heatmap-radius should be unset initially.");
NSExpression *defaultExpression = layer.heatmapRadius;
NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
layer.heatmapRadius = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getHeatmapRadius(), propertyValue,
@"Setting heatmapRadius to a constant value expression should update heatmap-radius.");
XCTAssertEqualObjects(layer.heatmapRadius, constantExpression,
@"heatmapRadius should round-trip constant value expressions.");
constantExpression = [NSExpression expressionWithFormat:@"0xff"];
NSExpression *functionExpression = [NSExpression expressionWithFormat:@"FUNCTION($zoomLevel, 'mgl_stepWithMinimum:stops:', %@, %@)", constantExpression, @{@18: constantExpression}];
layer.heatmapRadius = functionExpression;
mbgl::style::IntervalStops<float> intervalStops = {{
{ -INFINITY, 0xff },
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getHeatmapRadius(), propertyValue,
@"Setting heatmapRadius to a camera expression should update heatmap-radius.");
XCTAssertEqualObjects(layer.heatmapRadius, functionExpression,
@"heatmapRadius should round-trip camera expressions.");
functionExpression = [NSExpression expressionWithFormat:@"FUNCTION(keyName, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', nil, %@)", @{@18: constantExpression}];
layer.heatmapRadius = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getHeatmapRadius(), propertyValue,
@"Setting heatmapRadius to a data expression should update heatmap-radius.");
XCTAssertEqualObjects(layer.heatmapRadius, functionExpression,
@"heatmapRadius should round-trip data expressions.");
functionExpression = [NSExpression expressionWithFormat:@"FUNCTION($zoomLevel, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', nil, %@)", @{@10: functionExpression}];
layer.heatmapRadius = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getHeatmapRadius(), propertyValue,
@"Setting heatmapRadius to a camera-data expression should update heatmap-radius.");
XCTAssertEqualObjects(layer.heatmapRadius, functionExpression,
@"heatmapRadius should round-trip camera-data expressions.");
layer.heatmapRadius = nil;
XCTAssertTrue(rawLayer->getHeatmapRadius().isUndefined(),
@"Unsetting heatmapRadius should return heatmap-radius to the default value.");
XCTAssertEqualObjects(layer.heatmapRadius, defaultExpression,
@"heatmapRadius should return the default value after being unset.");
// Transition property test
layer.heatmapRadiusTransition = transitionTest;
auto toptions = rawLayer->getHeatmapRadiusTransition();
XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
MGLTransition heatmapRadiusTransition = layer.heatmapRadiusTransition;
XCTAssertEqual(heatmapRadiusTransition.delay, transitionTest.delay);
XCTAssertEqual(heatmapRadiusTransition.duration, transitionTest.duration);
}
// heatmap-weight
{
XCTAssertTrue(rawLayer->getHeatmapWeight().isUndefined(),
@"heatmap-weight should be unset initially.");
NSExpression *defaultExpression = layer.heatmapWeight;
NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
layer.heatmapWeight = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getHeatmapWeight(), propertyValue,
@"Setting heatmapWeight to a constant value expression should update heatmap-weight.");
XCTAssertEqualObjects(layer.heatmapWeight, constantExpression,
@"heatmapWeight should round-trip constant value expressions.");
constantExpression = [NSExpression expressionWithFormat:@"0xff"];
NSExpression *functionExpression = [NSExpression expressionWithFormat:@"FUNCTION($zoomLevel, 'mgl_stepWithMinimum:stops:', %@, %@)", constantExpression, @{@18: constantExpression}];
layer.heatmapWeight = functionExpression;
mbgl::style::IntervalStops<float> intervalStops = {{
{ -INFINITY, 0xff },
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getHeatmapWeight(), propertyValue,
@"Setting heatmapWeight to a camera expression should update heatmap-weight.");
XCTAssertEqualObjects(layer.heatmapWeight, functionExpression,
@"heatmapWeight should round-trip camera expressions.");
functionExpression = [NSExpression expressionWithFormat:@"FUNCTION(keyName, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', nil, %@)", @{@18: constantExpression}];
layer.heatmapWeight = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getHeatmapWeight(), propertyValue,
@"Setting heatmapWeight to a data expression should update heatmap-weight.");
XCTAssertEqualObjects(layer.heatmapWeight, functionExpression,
@"heatmapWeight should round-trip data expressions.");
functionExpression = [NSExpression expressionWithFormat:@"FUNCTION($zoomLevel, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', nil, %@)", @{@10: functionExpression}];
layer.heatmapWeight = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getHeatmapWeight(), propertyValue,
@"Setting heatmapWeight to a camera-data expression should update heatmap-weight.");
XCTAssertEqualObjects(layer.heatmapWeight, functionExpression,
@"heatmapWeight should round-trip camera-data expressions.");
layer.heatmapWeight = nil;
XCTAssertTrue(rawLayer->getHeatmapWeight().isUndefined(),
@"Unsetting heatmapWeight should return heatmap-weight to the default value.");
XCTAssertEqualObjects(layer.heatmapWeight, defaultExpression,
@"heatmapWeight should return the default value after being unset.");
}
}
- (void)testPropertyNames {
[self testPropertyName:@"heatmap-intensity" isBoolean:NO];
[self testPropertyName:@"heatmap-opacity" isBoolean:NO];
[self testPropertyName:@"heatmap-radius" isBoolean:NO];
[self testPropertyName:@"heatmap-weight" isBoolean:NO];
}
@end

View File

@@ -59,6 +59,7 @@
MGLTransition transitionTest = MGLTransitionMake(5, 4);
<% for (const property of properties) { -%>
<% if (property.name === 'heatmap-color') continue; -%>
// <%- originalPropertyName(property) %>
{
@@ -151,6 +152,7 @@
- (void)testPropertyNames {
<% for (const property of properties) { -%>
<% if (property.name === 'heatmap-color') continue; -%>
[self testPropertyName:@"<%- property.getter || property.name %>" isBoolean:<%- property.type === 'boolean' ? 'YES' : 'NO' %>];
<% } -%>
}

View File

@@ -2,6 +2,7 @@
#import <Mapbox/Mapbox.h>
#import "MGLTileSource_Private.h"
#import "MGLGeometry_Private.h"
#include <mbgl/util/tileset.hpp>
@@ -40,6 +41,19 @@
XCTAssertEqual(tileSet.zoomRange.min, 1);
XCTAssertEqual(tileSet.zoomRange.max, 2);
// when the tile set has a bounds set
MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(12, 34), CLLocationCoordinate2DMake(56, 78));
tileSet = MGLTileSetFromTileURLTemplates(@[@"tile.1"], @{
MGLTileSourceOptionCoordinateBounds: @(bounds),
});
// the mbgl object reflects the set values for the bounds
XCTAssert(!!tileSet.bounds, @"The bounds are set after setting the bounds");
if (tileSet.bounds) {
MGLCoordinateBounds actual = MGLCoordinateBoundsFromLatLngBounds(*tileSet.bounds);
XCTAssert(MGLCoordinateBoundsEqualToCoordinateBounds(bounds, actual), @"The bounds round-trip");
}
// when the tile set has an attribution
NSString *attribution = @"my tileset © ©️🎈";
tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, @{

View File

@@ -10,6 +10,12 @@
#include <sys/types.h>
#include <sys/stat.h>
namespace {
const std::string assetProtocol = "asset://";
} // namespace
namespace mbgl {
class AssetFileSource::Impl {
@@ -19,18 +25,17 @@ public:
}
void request(const std::string& url, ActorRef<FileSourceRequest> req) {
std::string path;
if (url.size() <= 8 || url[8] == '/') {
// This is an empty or absolute path.
path = mbgl::util::percentDecode(url.substr(8));
} else {
// This is a relative path. Prefix with the application root.
path = root + "/" + mbgl::util::percentDecode(url.substr(8));
}
Response response;
if (!acceptsURL(url)) {
response.error = std::make_unique<Response::Error>(Response::Error::Reason::Other,
"Invalid asset URL");
req.invoke(&FileSourceRequest::setResponse, response);
return;
}
// Cut off the protocol and prefix with path.
const auto path = root + "/" + mbgl::util::percentDecode(url.substr(assetProtocol.size()));
struct stat buf;
int result = stat(path.c_str(), &buf);
@@ -69,4 +74,8 @@ std::unique_ptr<AsyncRequest> AssetFileSource::request(const Resource& resource,
return std::move(req);
}
bool AssetFileSource::acceptsURL(const std::string& url) {
return std::equal(assetProtocol.begin(), assetProtocol.end(), url.begin());
}
} // namespace mbgl

View File

@@ -14,16 +14,6 @@
#include <cassert>
namespace {
const std::string assetProtocol = "asset://";
bool isAssetURL(const std::string& url) {
return std::equal(assetProtocol.begin(), assetProtocol.end(), url.begin());
}
} // namespace
namespace mbgl {
class DefaultFileSource::Impl {
@@ -118,7 +108,7 @@ public:
ref.invoke(&FileSourceRequest::setResponse, res);
};
if (isAssetURL(resource.url)) {
if (AssetFileSource::acceptsURL(resource.url)) {
//Asset request
tasks[req] = assetFileSource->request(resource, callback);
} else if (LocalFileSource::acceptsURL(resource.url)) {

View File

@@ -16,8 +16,7 @@
namespace {
const char* protocol = "file://";
const std::size_t protocolLength = 7;
const std::string fileProtocol = "file://";
} // namespace
@@ -28,11 +27,17 @@ public:
Impl(ActorRef<Impl>) {}
void request(const std::string& url, ActorRef<FileSourceRequest> req) {
// Cut off the protocol
std::string path = mbgl::util::percentDecode(url.substr(protocolLength));
Response response;
if (!acceptsURL(url)) {
response.error = std::make_unique<Response::Error>(Response::Error::Reason::Other,
"Invalid file URL");
req.invoke(&FileSourceRequest::setResponse, response);
return;
}
// Cut off the protocol and prefix with path.
const auto path = mbgl::util::percentDecode(url.substr(fileProtocol.size()));
struct stat buf;
int result = stat(path.c_str(), &buf);
@@ -70,7 +75,7 @@ std::unique_ptr<AsyncRequest> LocalFileSource::request(const Resource& resource,
}
bool LocalFileSource::acceptsURL(const std::string& url) {
return url.compare(0, protocolLength, protocol) == 0;
return std::equal(fileProtocol.begin(), fileProtocol.end(), url.begin());
}
} // namespace mbgl

View File

@@ -11,6 +11,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
### Styles and rendering
* Added support for a new layer type: `MGLHeatmapStyleLayer`, a powerful way to visualize point data distributions using heatmaps, fully customizable through runtime styling. [#11046](https://github.com/mapbox/mapbox-gl-native/pull/11046)
* The layout and paint properties on subclasses of `MGLStyleLayer` are now of type `NSExpression` instead of `MGLStyleValue`. A new “Predicates and Expressions” guide provides an overview of the supported operators. ([#10726](https://github.com/mapbox/mapbox-gl-native/pull/10726))
* Added an `MGLComputedShapeSource` class that allows applications to supply vector data to a style layer on a per-tile basis. ([#9983](https://github.com/mapbox/mapbox-gl-native/pull/9983))
* A style can now display smooth hillshading and customize its appearance at runtime using the `MGLHillshadeStyleLayer` class. Hillshading is based on a rasterized digital elevation model supplied by the `MGLRasterDEMSource` class. ([#10642](https://github.com/mapbox/mapbox-gl-native/pull/10642))
@@ -34,15 +35,19 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
### Map snapshots
* Fixed a memory leak that occurred when creating a map snapshot. ([#10585](https://github.com/mapbox/mapbox-gl-native/pull/10585))
* Fixed an issue that caused `MGLMapSnapshotter.pointForCoordinate` to return an incorrect value. ([#11035](https://github.com/mapbox/mapbox-gl-native/pull/11035))
### Other changes
## Other changes
* Feature querying results now account for the `MGLSymbolStyleLayer.circleStrokeWidth` property. ([#10897](https://github.com/mapbox/mapbox-gl-native/pull/10897))
* Fixed an issue preventing labels from being transliterated when VoiceOver was enabled on iOS 10._x_ and below. ([#10881](https://github.com/mapbox/mapbox-gl-native/pull/10881))
* Labels are now transliterated from more languages when VoiceOver is enabled. ([#10881](https://github.com/mapbox/mapbox-gl-native/pull/10881))
* Long-pressing the attribution button causes the SDK’s version number to be displayed in the action sheet that appears. ([#10650](https://github.com/mapbox/mapbox-gl-native/pull/10650))
## 3.7.4 - February 12, 2018
* Added the `MGLTileSourceOptionTileCoordinateBounds` option to create an `MGLTileSource` that only supplies tiles within a specific geographic bounding box. ([#11141](https://github.com/mapbox/mapbox-gl-native/pull/11141))
* Fixed an issue that caused `-[MGLMapSnapshotter pointForCoordinate:]` to return the wrong point. ([#11035](https://github.com/mapbox/mapbox-gl-native/pull/11035))
## 3.7.3 - January 10, 2018
* Fixed a crash while zooming while annotations are present on the map. ([#10791](https://github.com/mapbox/mapbox-gl-native/pull/10791))

View File

@@ -50,12 +50,13 @@
options.zoomLevel = 10;
// Create and start the snapshotter
__weak UIImageView *weakImageView = imageView;
MGLMapSnapshotter* snapshotter = [[MGLMapSnapshotter alloc] initWithOptions:options];
[snapshotter startWithCompletionHandler: ^(MGLMapSnapshot* snapshot, NSError *error) {
if (error) {
NSLog(@"Could not load snapshot: %@", [error localizedDescription]);
} else {
imageView.image = snapshot.image;
weakImageView.image = snapshot.image;
}
}];

View File

@@ -1280,6 +1280,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
- (void)styleDynamicPointCollection
{
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(36.9979, -109.0441) zoomLevel:14 animated:NO];
CLLocationCoordinate2D coordinates[] = {
{37.00145594210082, -109.04960632324219},
{37.00173012609867, -109.0404224395752},
@@ -1889,7 +1890,8 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[self updateHUD];
}
- (void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
- (void)mapView:(MGLMapView *)mapView regionDidChangeWithReason:(MGLCameraChangeReason)reason animated:(BOOL)animated
{
[self updateHUD];
}

View File

@@ -109,6 +109,7 @@ the following terms for concepts defined in the style specification:
In the style specification | In the SDK
---------------------------|---------
bounds | coordinate bounds
filter | predicate
function type | interpolation mode
id | identifier
@@ -149,6 +150,7 @@ In style JSON | In TileJSON | In the SDK
`tiles` | `tiles` | `tileURLTemplates` parameter in `-[MGLTileSource initWithIdentifier:tileURLTemplates:options:]`
`minzoom` | `minzoom` | `MGLTileSourceOptionMinimumZoomLevel`
`maxzoom` | `maxzoom` | `MGLTileSourceOptionMaximumZoomLevel`
`bounds` | `bounds` | `MGLTileSourceOptionCoordinateBounds`
`tileSize` | — | `MGLTileSourceOptionTileSize`
`attribution` | `attribution` | `MGLTileSourceOptionAttributionHTMLString` (but consider specifying `MGLTileSourceOptionAttributionInfos` instead for improved security)
`scheme` | `scheme` | `MGLTileSourceOptionTileCoordinateSystem`
@@ -190,6 +192,7 @@ In style JSON | In the SDK
`circle` | `MGLCircleStyleLayer`
`fill` | `MGLFillStyleLayer`
`fill-extrusion` | `MGLFillExtrusionStyleLayer`
`heatmap` | `MGLHeatmapStyleLayer`
`hillshade` | `MGLHillshadeStyleLayer`
`line` | `MGLLineStyleLayer`
`raster` | `MGLRasterStyleLayer`

View File

@@ -28,6 +28,8 @@
16376B471FFDB92B0000563E /* one-liner.json in Resources */ = {isa = PBXBuildFile; fileRef = DA35D0871E1A6309007DED41 /* one-liner.json */; };
16376B491FFEED010000563E /* MGLMapViewLayoutTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 16376B481FFEED010000563E /* MGLMapViewLayoutTests.m */; };
165D0CE720005419009A3C66 /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA8847D21CBAF91600AB86E3 /* Mapbox.framework */; };
170C437C2029D96F00863DF0 /* MGLHeatmapColorTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 170C43782028D49800863DF0 /* MGLHeatmapColorTests.mm */; };
170C437D2029D97900863DF0 /* MGLHeatmapStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 170C43792028D49800863DF0 /* MGLHeatmapStyleLayerTests.mm */; };
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, ); }; };
@@ -226,6 +228,10 @@
55E2AD131E5B125400E8C587 /* MGLOfflineStorageTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 55E2AD121E5B125400E8C587 /* MGLOfflineStorageTests.mm */; };
632281DF1E6F855900D75A5D /* MBXEmbeddedMapViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 632281DE1E6F855900D75A5D /* MBXEmbeddedMapViewController.m */; };
6407D6701E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6407D66F1E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift */; };
8989B17C201A48EB0081CF59 /* MGLHeatmapStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 8989B17A201A48EA0081CF59 /* MGLHeatmapStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
8989B17D201A48EB0081CF59 /* MGLHeatmapStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 8989B17A201A48EA0081CF59 /* MGLHeatmapStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
8989B17E201A48EB0081CF59 /* MGLHeatmapStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8989B17B201A48EA0081CF59 /* MGLHeatmapStyleLayer.mm */; };
8989B17F201A48EB0081CF59 /* MGLHeatmapStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8989B17B201A48EA0081CF59 /* MGLHeatmapStyleLayer.mm */; };
920A3E5D1E6F995200C16EFC /* MGLSourceQueryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 920A3E5C1E6F995200C16EFC /* MGLSourceQueryTests.m */; };
927FBCFC1F4DAA8300F8BF1F /* MBXSnapshotsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 927FBCFB1F4DAA8300F8BF1F /* MBXSnapshotsViewController.m */; };
927FBCFF1F4DB05500F8BF1F /* MGLMapSnapshotter.h in Headers */ = {isa = PBXBuildFile; fileRef = 927FBCFD1F4DB05500F8BF1F /* MGLMapSnapshotter.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -297,6 +303,12 @@
96E5170320005A6800A02306 /* FABKitProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848811CBB033F00AB86E3 /* FABKitProtocol.h */; };
96E5170420005A6B00A02306 /* SMCalloutView.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848891CBB037E00AB86E3 /* SMCalloutView.h */; };
96F3F73C1F57124B003E2D2C /* MGLUserLocationHeadingIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 96F3F73B1F5711F1003E2D2C /* MGLUserLocationHeadingIndicator.h */; };
AC518DFF201BB55A00EBC820 /* MGLTelemetryConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = AC518DFD201BB55A00EBC820 /* MGLTelemetryConfig.h */; };
AC518E00201BB55A00EBC820 /* MGLTelemetryConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = AC518DFD201BB55A00EBC820 /* MGLTelemetryConfig.h */; };
AC518E03201BB56000EBC820 /* MGLTelemetryConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = AC518DFE201BB55A00EBC820 /* MGLTelemetryConfig.m */; };
AC518E04201BB56100EBC820 /* MGLTelemetryConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = AC518DFE201BB55A00EBC820 /* MGLTelemetryConfig.m */; };
CA55CD41202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */ = {isa = PBXBuildFile; fileRef = CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */; settings = {ATTRIBUTES = (Public, ); }; };
CA55CD42202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */ = {isa = PBXBuildFile; fileRef = CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA00FC8E1D5EEB0D009AABC8 /* MGLAttributionInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA00FC8F1D5EEB0D009AABC8 /* MGLAttributionInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA00FC901D5EEB0D009AABC8 /* MGLAttributionInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA00FC8D1D5EEB0D009AABC8 /* MGLAttributionInfo.mm */; };
@@ -666,6 +678,8 @@
16376B3F1FFDB4B40000563E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
16376B401FFDB4B40000563E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
16376B481FFEED010000563E /* MGLMapViewLayoutTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLMapViewLayoutTests.m; sourceTree = "<group>"; };
170C43782028D49800863DF0 /* MGLHeatmapColorTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLHeatmapColorTests.mm; path = ../../darwin/test/MGLHeatmapColorTests.mm; sourceTree = "<group>"; };
170C43792028D49800863DF0 /* MGLHeatmapStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLHeatmapStyleLayerTests.mm; path = ../../darwin/test/MGLHeatmapStyleLayerTests.mm; 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>"; };
@@ -797,6 +811,8 @@
632281DD1E6F855900D75A5D /* MBXEmbeddedMapViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBXEmbeddedMapViewController.h; sourceTree = "<group>"; };
632281DE1E6F855900D75A5D /* MBXEmbeddedMapViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBXEmbeddedMapViewController.m; sourceTree = "<group>"; };
6407D66F1E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MGLDocumentationExampleTests.swift; path = ../../darwin/test/MGLDocumentationExampleTests.swift; sourceTree = "<group>"; };
8989B17A201A48EA0081CF59 /* MGLHeatmapStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLHeatmapStyleLayer.h; sourceTree = "<group>"; };
8989B17B201A48EA0081CF59 /* MGLHeatmapStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLHeatmapStyleLayer.mm; sourceTree = "<group>"; };
920A3E5C1E6F995200C16EFC /* MGLSourceQueryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLSourceQueryTests.m; path = ../../darwin/test/MGLSourceQueryTests.m; sourceTree = "<group>"; };
927FBCFA1F4DAA8300F8BF1F /* MBXSnapshotsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBXSnapshotsViewController.h; sourceTree = "<group>"; };
927FBCFB1F4DAA8300F8BF1F /* MBXSnapshotsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBXSnapshotsViewController.m; sourceTree = "<group>"; };
@@ -831,6 +847,9 @@
96E0272D1E57C7E6004B8E66 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
96E0272E1E57C7E7004B8E66 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = "<group>"; };
96F3F73B1F5711F1003E2D2C /* MGLUserLocationHeadingIndicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLUserLocationHeadingIndicator.h; sourceTree = "<group>"; };
AC518DFD201BB55A00EBC820 /* MGLTelemetryConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLTelemetryConfig.h; sourceTree = "<group>"; };
AC518DFE201BB55A00EBC820 /* MGLTelemetryConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLTelemetryConfig.m; sourceTree = "<group>"; };
CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCameraChangeReason.h; sourceTree = "<group>"; };
DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo.h; sourceTree = "<group>"; };
DA00FC8D1D5EEB0D009AABC8 /* MGLAttributionInfo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAttributionInfo.mm; sourceTree = "<group>"; };
DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFeatureTests.mm; path = ../../darwin/test/MGLFeatureTests.mm; sourceTree = "<group>"; };
@@ -1236,6 +1255,8 @@
FA68F1481E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.h */,
FA68F1491E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.mm */,
35D13AC11D3D19DD00AFB4E0 /* MGLFillStyleLayer.h */,
8989B17A201A48EA0081CF59 /* MGLHeatmapStyleLayer.h */,
8989B17B201A48EA0081CF59 /* MGLHeatmapStyleLayer.mm */,
35D13AC21D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm */,
3538AA1B1D542239008EC33D /* MGLForegroundStyleLayer.h */,
3538AA1C1D542239008EC33D /* MGLForegroundStyleLayer.mm */,
@@ -1306,6 +1327,8 @@
3575798F1D513EF1000B822E /* Layers */ = {
isa = PBXGroup;
children = (
170C43782028D49800863DF0 /* MGLHeatmapColorTests.mm */,
170C43792028D49800863DF0 /* MGLHeatmapStyleLayerTests.mm */,
DA2DBBCC1D51E80400D38FF9 /* MGLStyleLayerTests.h */,
DA2DBBCD1D51E80400D38FF9 /* MGLStyleLayerTests.m */,
DA3C6FF21E2859E700F962BE /* test-Bridging-Header.h */,
@@ -1587,19 +1610,20 @@
DA8848331CBAFB2A00AB86E3 /* Kit */ = {
isa = PBXGroup;
children = (
355ADFF91E9281C300F3939D /* Views */,
35CE617F1D4165C2004F2359 /* Categories */,
DAD165841CF4D06B001FF4B9 /* Annotations */,
DAD165851CF4D08B001FF4B9 /* Telemetry */,
DA704CC01F65A475004B3F28 /* MGLMapAccessibilityElement.h */,
DA704CC11F65A475004B3F28 /* MGLMapAccessibilityElement.mm */,
DA8848361CBAFB8500AB86E3 /* MGLMapView.h */,
DA17BE2F1CC4BAC300402C41 /* MGLMapView_Private.h */,
DA8848371CBAFB8500AB86E3 /* MGLMapView+IBAdditions.h */,
DA737EE01D056A4E005BDA16 /* MGLMapViewDelegate.h */,
DA88484A1CBAFB9800AB86E3 /* MGLMapView.mm */,
35CE617F1D4165C2004F2359 /* Categories */,
DA88487F1CBB033F00AB86E3 /* Fabric */,
DA8848881CBB036000AB86E3 /* SMCalloutView */,
DAD165851CF4D08B001FF4B9 /* Telemetry */,
355ADFF91E9281C300F3939D /* Views */,
CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */,
DA704CC01F65A475004B3F28 /* MGLMapAccessibilityElement.h */,
DA704CC11F65A475004B3F28 /* MGLMapAccessibilityElement.mm */,
DA17BE2F1CC4BAC300402C41 /* MGLMapView_Private.h */,
DA8848361CBAFB8500AB86E3 /* MGLMapView.h */,
DA88484A1CBAFB9800AB86E3 /* MGLMapView.mm */,
DA8848371CBAFB8500AB86E3 /* MGLMapView+IBAdditions.h */,
DA737EE01D056A4E005BDA16 /* MGLMapViewDelegate.h */,
);
name = Kit;
path = src;
@@ -1858,6 +1882,8 @@
DA8848491CBAFB9800AB86E3 /* MGLMapboxEvents.m */,
9620BB361E69FE1700705A1D /* MGLSDKUpdateChecker.h */,
9620BB371E69FE1700705A1D /* MGLSDKUpdateChecker.mm */,
AC518DFD201BB55A00EBC820 /* MGLTelemetryConfig.h */,
AC518DFE201BB55A00EBC820 /* MGLTelemetryConfig.m */,
);
name = Telemetry;
sourceTree = "<group>";
@@ -1891,6 +1917,8 @@
350098DC1D484E60004B2AF0 /* NSValue+MGLStyleAttributeAdditions.h in Headers */,
DA8848231CBAFA6200AB86E3 /* MGLOfflineStorage_Private.h in Headers */,
404326891D5B9B27007111BD /* MGLAnnotationContainerView_Private.h in Headers */,
CA55CD41202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */,
1FB7DAAF1F2A4DBD00410606 /* MGLVectorSource+MGLAdditions.h in Headers */,
DA88483B1CBAFB8500AB86E3 /* MGLCalloutView.h in Headers */,
35E0CFE61D3E501500188327 /* MGLStyle_Private.h in Headers */,
3510FFF01D6D9D8C00F413B2 /* NSExpression+MGLAdditions.h in Headers */,
@@ -1963,6 +1991,7 @@
DA8847F91CBAFA5100AB86E3 /* MGLPolygon.h in Headers */,
4049C2AC1DB6E05500B3F799 /* MGLPointCollection_Private.h in Headers */,
DA8847F81CBAFA5100AB86E3 /* MGLPointAnnotation.h in Headers */,
8989B17C201A48EB0081CF59 /* MGLHeatmapStyleLayer.h in Headers */,
353933F21D3FB753003F57D7 /* MGLCircleStyleLayer.h in Headers */,
DA8847F31CBAFA5100AB86E3 /* MGLMultiPoint.h in Headers */,
30E578171DAA85520050F07E /* UIImage+MGLAdditions.h in Headers */,
@@ -1978,6 +2007,7 @@
DA8847F51CBAFA5100AB86E3 /* MGLOfflineRegion.h in Headers */,
DA737EE11D056A4E005BDA16 /* MGLMapViewDelegate.h in Headers */,
DA8848851CBB033F00AB86E3 /* FABKitProtocol.h in Headers */,
AC518DFF201BB55A00EBC820 /* MGLTelemetryConfig.h in Headers */,
DA88481B1CBAFA6200AB86E3 /* MGLGeometry_Private.h in Headers */,
3510FFF91D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.h in Headers */,
3557F7B01E1D27D300CCA5E6 /* MGLDistanceFormatter.h in Headers */,
@@ -2038,6 +2068,7 @@
96E516EF2000594F00A02306 /* NSArray+MGLAdditions.h in Headers */,
96E516F12000596800A02306 /* NSString+MGLAdditions.h in Headers */,
35E0CFE71D3E501500188327 /* MGLStyle_Private.h in Headers */,
CA55CD42202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */,
DABFB86D1CBE9A0F00D62B32 /* MGLAnnotationImage.h in Headers */,
DABFB8721CBE9A0F00D62B32 /* MGLUserLocation.h in Headers */,
927FBD001F4DB05500F8BF1F /* MGLMapSnapshotter.h in Headers */,
@@ -2068,6 +2099,7 @@
96E516FB20005A4000A02306 /* MGLUserLocationHeadingBeamLayer.h in Headers */,
96E516DC2000547000A02306 /* MGLPolyline_Private.h in Headers */,
353AFA151D65AB17005A69F4 /* NSDate+MGLAdditions.h in Headers */,
AC518E00201BB55A00EBC820 /* MGLTelemetryConfig.h in Headers */,
3510FFFA1D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.h in Headers */,
DA72620C1DEEE3480043BB89 /* MGLOpenGLStyleLayer.h in Headers */,
35CE61831D4165D9004F2359 /* UIColor+MGLAdditions.h in Headers */,
@@ -2099,6 +2131,7 @@
DABFB8631CBE99E500D62B32 /* MGLOfflineRegion.h in Headers */,
DA35A2B21CCA141D00E826B2 /* MGLCompassDirectionFormatter.h in Headers */,
DAF0D8141DFE0EC500B28378 /* MGLVectorSource_Private.h in Headers */,
8989B17D201A48EB0081CF59 /* MGLHeatmapStyleLayer.h in Headers */,
DABFB8731CBE9A9900D62B32 /* Mapbox.h in Headers */,
357FE2DE1E02D2B20068B753 /* NSCoder+MGLAdditions.h in Headers */,
1753ED431E53CE6F00A9FD90 /* MGLConversion.h in Headers */,
@@ -2544,6 +2577,8 @@
409F43FD1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift in Sources */,
DA2E88651CC0382C00F24E7B /* MGLStyleTests.mm in Sources */,
DA2E88611CC0382C00F24E7B /* MGLGeometryTests.mm in Sources */,
170C437D2029D97900863DF0 /* MGLHeatmapStyleLayerTests.mm in Sources */,
170C437C2029D96F00863DF0 /* MGLHeatmapColorTests.mm in Sources */,
357579801D501E09000B822E /* MGLFillStyleLayerTests.mm in Sources */,
35D9DDE21DA25EEC00DAAD69 /* MGLCodingTests.m in Sources */,
DA1F8F3D1EBD287B00367E42 /* MGLDocumentationGuideTests.swift in Sources */,
@@ -2656,6 +2691,7 @@
35B82BFA1D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm in Sources */,
DA8848521CBAFB9800AB86E3 /* MGLAPIClient.m in Sources */,
966FCF4E1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */,
8989B17E201A48EB0081CF59 /* MGLHeatmapStyleLayer.mm in Sources */,
DA8848301CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.m in Sources */,
353AFA161D65AB17005A69F4 /* NSDate+MGLAdditions.mm in Sources */,
35D13AC51D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */,
@@ -2667,6 +2703,7 @@
DA72620D1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm in Sources */,
DA88481A1CBAFA6200AB86E3 /* MGLAccountManager.m in Sources */,
3510FFFB1D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.mm in Sources */,
AC518E03201BB56000EBC820 /* MGLTelemetryConfig.m in Sources */,
DA8848271CBAFA6200AB86E3 /* MGLPolyline.mm in Sources */,
DA8848581CBAFB9800AB86E3 /* MGLMapboxEvents.m in Sources */,
35CE61841D4165D9004F2359 /* UIColor+MGLAdditions.mm in Sources */,
@@ -2747,6 +2784,7 @@
DAA4E4311CBB730400178DFB /* MGLMapboxEvents.m in Sources */,
966FCF4F1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */,
DAA4E4231CBB730400178DFB /* MGLPolygon.mm in Sources */,
8989B17F201A48EB0081CF59 /* MGLHeatmapStyleLayer.mm in Sources */,
353AFA171D65AB17005A69F4 /* NSDate+MGLAdditions.mm in Sources */,
35D13AC61D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */,
DAA4E42A1CBB730400178DFB /* NSProcessInfo+MGLAdditions.m in Sources */,
@@ -2758,6 +2796,7 @@
DA72620E1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm in Sources */,
DAA4E42F1CBB730400178DFB /* MGLCompactCalloutView.m in Sources */,
3510FFFC1D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.mm in Sources */,
AC518E04201BB56100EBC820 /* MGLTelemetryConfig.m in Sources */,
DAA4E4271CBB730400178DFB /* MGLTilePyramidOfflineRegion.mm in Sources */,
DAA4E41C1CBB730400178DFB /* MGLAccountManager.m in Sources */,
35CE61851D4165D9004F2359 /* UIColor+MGLAdditions.mm in Sources */,

View File

@@ -95,6 +95,7 @@ custom_categories:
- MGLCircleStyleLayer
- MGLFillStyleLayer
- MGLFillExtrusionStyleLayer
- MGLHeatmapStyleLayer
- MGLHillshadeStyleLayer
- MGLLineStyleLayer
- MGLSymbolStyleLayer

View File

@@ -0,0 +1,61 @@
#import "MGLFoundation.h"
/**
:nodoc:
Bitmask values that describe why a camera move occurred.
Values of this type are passed to the `MGLMapView`'s delegate in the following methods:
- `-mapView:shouldChangeFromCamera:toCamera:reason:`
- `-mapView:regionWillChangeWithReason:animated:`
- `-mapView:regionIsChangingWithReason:`
- `-mapView:regionDidChangeWithReason:animated:`
It's important to note that it's almost impossible to perform a rotate without zooming (in or out),
so if you'll often find `MGLCameraChangeReasonGesturePinch` set alongside `MGLCameraChangeReasonGestureRotate`.
Since there are several reasons why a zoom or rotation has occurred, it is worth considering
creating a combined constant, for example:
```
static const MGLCameraChangeReason anyZoom = MGLCameraChangeReasonGesturePinch |
MGLCameraChangeReasonGestureZoomIn |
MGLCameraChangeReasonGestureZoomOut |
MGLCameraChangeReasonGestureOneFingerZoom;
static const MGLCameraChangeReason anyRotation = MGLCameraChangeReasonResetNorth | MGLCameraChangeReasonGestureRotate;
```
*/
typedef NS_OPTIONS(NSUInteger, MGLCameraChangeReason)
{
/// :nodoc: The reason for the camera change has not be specified.
MGLCameraChangeReasonNone = 0,
/// :nodoc: Set when a public API that moves the camera is called. This may be set for some gestures,
/// for example MGLCameraChangeReasonResetNorth.
MGLCameraChangeReasonProgrammatic = 1 << 0,
/// :nodoc: The user tapped the compass to reset the map orientation so North is up.
MGLCameraChangeReasonResetNorth = 1 << 1,
/// :nodoc: The user panned the map.
MGLCameraChangeReasonGesturePan = 1 << 2,
/// :nodoc: The user pinched to zoom in/out.
MGLCameraChangeReasonGesturePinch = 1 << 3,
// :nodoc: The user rotated the map.
MGLCameraChangeReasonGestureRotate = 1 << 4,
/// :nodoc: The user zoomed the map in (one finger double tap).
MGLCameraChangeReasonGestureZoomIn = 1 << 5,
/// :nodoc: The user zoomed the map out (two finger single tap).
MGLCameraChangeReasonGestureZoomOut = 1 << 6,
/// :nodoc: The user long pressed on the map for a quick zoom (single tap, then long press and drag up/down).
MGLCameraChangeReasonGestureOneFingerZoom = 1 << 7,
// :nodoc: The user panned with two fingers to tilt the map (two finger drag).
MGLCameraChangeReasonGestureTilt = 1 << 8
};

View File

@@ -1,9 +1,9 @@
#import "MGLLocationManager.h"
#import "MGLTelemetryConfig.h"
#import <UIKit/UIKit.h>
static const NSTimeInterval MGLLocationManagerHibernationTimeout = 300.0;
static const NSTimeInterval MGLLocationManagerHibernationPollInterval = 5.0;
static const CLLocationDistance MGLLocationManagerHibernationRadius = 300.0;
static const CLLocationDistance MGLLocationManagerDistanceFilter = 5.0;
static NSString * const MGLLocationManagerRegionIdentifier = @"MGLLocationManagerRegionIdentifier.fence.center";
@@ -122,7 +122,7 @@ static NSString * const MGLLocationManagerRegionIdentifier = @"MGLLocationManage
}
- (void)establishRegionMonitoringForLocation:(CLLocation *)location {
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:location.coordinate radius:MGLLocationManagerHibernationRadius identifier:MGLLocationManagerRegionIdentifier];
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:location.coordinate radius:MGLTelemetryConfig.sharedConfig.MGLLocationManagerHibernationRadius identifier:MGLLocationManagerRegionIdentifier];
region.notifyOnEntry = NO;
region.notifyOnExit = YES;
[self.standardLocationManager startMonitoringForRegion:region];
@@ -151,7 +151,7 @@ static NSString * const MGLLocationManagerRegionIdentifier = @"MGLLocationManage
if (location.speed > 0.0) {
[self startBackgroundTimeoutTimer];
}
if (self.standardLocationManager.monitoredRegions.count == 0 || location.horizontalAccuracy < MGLLocationManagerHibernationRadius) {
if (self.standardLocationManager.monitoredRegions.count == 0 || location.horizontalAccuracy < MGLTelemetryConfig.sharedConfig.MGLLocationManagerHibernationRadius) {
[self establishRegionMonitoringForLocation:location];
}
if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateLocations:)]) {

View File

@@ -210,6 +210,8 @@ public:
@property (nonatomic) UILongPressGestureRecognizer *quickZoom;
@property (nonatomic) UIPanGestureRecognizer *twoFingerDrag;
@property (nonatomic) MGLCameraChangeReason cameraChangeReasonBitmask;
/// Mapping from reusable identifiers to annotation images.
@property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLAnnotationImage *) *annotationImagesByIdentifier;
@@ -506,10 +508,6 @@ public:
_doubleTap.numberOfTapsRequired = 2;
[self addGestureRecognizer:_doubleTap];
_singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTapGesture:)];
[_singleTapGestureRecognizer requireGestureRecognizerToFail:_doubleTap];
_singleTapGestureRecognizer.delegate = self;
[self addGestureRecognizer:_singleTapGestureRecognizer];
_twoFingerDrag = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerDragGesture:)];
_twoFingerDrag.minimumNumberOfTouches = 2;
@@ -534,16 +532,25 @@ public:
[_quickZoom requireGestureRecognizerToFail:_doubleTap];
[self addGestureRecognizer:_quickZoom];
_singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTapGesture:)];
[_singleTapGestureRecognizer requireGestureRecognizerToFail:_doubleTap];
_singleTapGestureRecognizer.delegate = self;
[_singleTapGestureRecognizer requireGestureRecognizerToFail:_quickZoom];
[self addGestureRecognizer:_singleTapGestureRecognizer];
// observe app activity
//
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willTerminate) name:UIApplicationWillTerminateNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sleepGL:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(wakeGL:) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sleepGL:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(wakeGL:) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
// set initial position
//
mbgl::CameraOptions options;
@@ -551,6 +558,9 @@ public:
mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
options.padding = padding;
options.zoom = 0;
_cameraChangeReasonBitmask = MGLCameraChangeReasonNone;
_mbglMap->jumpTo(options);
_pendingLatitude = NAN;
_pendingLongitude = NAN;
@@ -706,7 +716,7 @@ public:
{
MGLAssertIsMainThread();
_rendererFrontend->onLowMemory();
_rendererFrontend->reduceMemoryUse();
}
#pragma mark - Layout -
@@ -1148,6 +1158,13 @@ public:
- (void)sleepGL:(__unused NSNotification *)notification
{
MGLAssertIsMainThread();
// Ideally we would wait until we actually received a memory warning but the bulk of the memory
// we have to release is tied up in GL buffers that we can't touch once we're in the background.
// Compromise position: release everything but currently rendering tiles
// A possible improvement would be to store a copy of the GL buffers that we could use to rapidly
// restart, but that we could also discard in response to a memory warning.
_rendererFrontend->reduceMemoryUse();
if ( ! self.dormant)
{
@@ -1237,6 +1254,8 @@ public:
- (void)handleCompassTapGesture:(__unused id)sender
{
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonResetNorth;
[self resetNorthAnimated:YES];
if (self.userTrackingMode == MGLUserTrackingModeFollowWithHeading ||
@@ -1259,6 +1278,7 @@ public:
- (void)notifyGestureDidBegin {
BOOL animated = NO;
[self cameraWillChangeAnimated:animated];
_mbglMap->setGestureInProgress(true);
_changeDelimiterSuppressionDepth++;
@@ -1282,6 +1302,23 @@ public:
return _changeDelimiterSuppressionDepth > 0;
}
- (BOOL)_shouldChangeFromCamera:(nonnull MGLMapCamera *)oldCamera toCamera:(nonnull MGLMapCamera *)newCamera
{
// Check delegates first
if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:reason:)])
{
return [self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:newCamera reason:self.cameraChangeReasonBitmask];
}
else if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)])
{
return [self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:newCamera];
}
else
{
return YES;
}
}
- (void)handlePanGesture:(UIPanGestureRecognizer *)pan
{
if ( ! self.isScrollEnabled) return;
@@ -1289,7 +1326,9 @@ public:
_mbglMap->cancelTransitions();
MGLMapCamera *oldCamera = self.camera;
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonGesturePan;
if (pan.state == UIGestureRecognizerStateBegan)
{
[self trackGestureEvent:MGLEventGesturePanStart forRecognizer:pan];
@@ -1303,9 +1342,8 @@ public:
CGPoint delta = [pan translationInView:pan.view];
MGLMapCamera *toCamera = [self cameraByPanningWithTranslation:delta panGesture:pan];
if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
[self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
_mbglMap->moveBy({ delta.x, delta.y });
[pan setTranslation:CGPointZero inView:pan.view];
@@ -1327,9 +1365,8 @@ public:
{
CGPoint offset = CGPointMake(velocity.x * self.decelerationRate / 4, velocity.y * self.decelerationRate / 4);
MGLMapCamera *toCamera = [self cameraByPanningWithTranslation:offset panGesture:pan];
if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
[self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
_mbglMap->moveBy({ offset.x, offset.y }, MGLDurationFromTimeInterval(self.decelerationRate));
}
@@ -1360,6 +1397,8 @@ public:
CGPoint centerPoint = [self anchorPointForGesture:pinch];
MGLMapCamera *oldCamera = self.camera;
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonGesturePinch;
if (pinch.state == UIGestureRecognizerStateBegan)
{
[self trackGestureEvent:MGLEventGesturePinchStart forRecognizer:pinch];
@@ -1376,9 +1415,8 @@ public:
// Calculates the final camera zoom, has no effect within current map camera.
MGLMapCamera *toCamera = [self cameraByZoomingToZoomLevel:newZoom aroundAnchorPoint:centerPoint];
if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
[self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
_mbglMap->setZoom(newZoom, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
// The gesture recognizer only reports the gesture’s current center
@@ -1430,9 +1468,8 @@ public:
// Calculates the final camera zoom, this has no effect within current map camera.
double zoom = log2(newScale);
MGLMapCamera *toCamera = [self cameraByZoomingToZoomLevel:zoom aroundAnchorPoint:centerPoint];
if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
&& ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
drift = NO;
} else {
@@ -1458,7 +1495,9 @@ public:
CGPoint centerPoint = [self anchorPointForGesture:rotate];
MGLMapCamera *oldCamera = self.camera;
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonGestureRotate;
if (rotate.state == UIGestureRecognizerStateBegan)
{
[self trackGestureEvent:MGLEventGestureRotateStart forRecognizer:rotate];
@@ -1485,9 +1524,8 @@ public:
}
MGLMapCamera *toCamera = [self cameraByRotatingToDirection:newDegrees aroundAnchorPoint:centerPoint];
if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
[self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
_mbglMap->setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
}
@@ -1505,9 +1543,8 @@ public:
CGFloat newDegrees = MGLDegreesFromRadians(newRadians) * -1;
MGLMapCamera *toCamera = [self cameraByRotatingToDirection:newDegrees aroundAnchorPoint:centerPoint];
if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
[self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
_mbglMap->setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationFromTimeInterval(decelerationRate));
@@ -1552,6 +1589,7 @@ public:
}
[self deselectAnnotation:self.selectedAnnotation animated:YES];
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nextElement);
return;
}
@@ -1562,7 +1600,7 @@ public:
CGRect positionRect = [self positioningRectForAnnotation:annotation defaultCalloutPoint:calloutPoint];
[self selectAnnotation:annotation animated:YES calloutPositioningRect:positionRect];
}
else
else if (self.selectedAnnotation)
{
[self deselectAnnotation:self.selectedAnnotation animated:YES];
}
@@ -1644,6 +1682,8 @@ public:
if (doubleTap.state == UIGestureRecognizerStateEnded)
{
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonGestureZoomIn;
MGLMapCamera *oldCamera = self.camera;
double newZoom = round(self.zoomLevel) + 1.0;
@@ -1651,9 +1691,8 @@ public:
CGPoint gesturePoint = [self anchorPointForGesture:doubleTap];
MGLMapCamera *toCamera = [self cameraByZoomingToZoomLevel:newZoom aroundAnchorPoint:gesturePoint];
if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
[self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
[self trackGestureEvent:MGLEventGestureDoubleTap forRecognizer:doubleTap];
@@ -1680,9 +1719,13 @@ public:
_mbglMap->cancelTransitions();
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonGestureZoomOut;
if (twoFingerTap.state == UIGestureRecognizerStateBegan)
{
[self trackGestureEvent:MGLEventGestureTwoFingerSingleTap forRecognizer:twoFingerTap];
[self notifyGestureDidBegin];
}
else if (twoFingerTap.state == UIGestureRecognizerStateEnded)
{
@@ -1693,9 +1736,8 @@ public:
CGPoint gesturePoint = [self anchorPointForGesture:twoFingerTap];
MGLMapCamera *toCamera = [self cameraByZoomingToZoomLevel:newZoom aroundAnchorPoint:gesturePoint];
if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
[self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y);
_mbglMap->setZoom(newZoom, center, MGLDurationFromTimeInterval(MGLAnimationDuration));
@@ -1715,7 +1757,9 @@ public:
if ( ! self.isZoomEnabled) return;
_mbglMap->cancelTransitions();
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonGestureOneFingerZoom;
if (quickZoom.state == UIGestureRecognizerStateBegan)
{
[self trackGestureEvent:MGLEventGestureQuickZoom forRecognizer:quickZoom];
@@ -1738,9 +1782,8 @@ public:
MGLMapCamera *oldCamera = self.camera;
MGLMapCamera *toCamera = [self cameraByZoomingToZoomLevel:newZoom aroundAnchorPoint:centerPoint];
if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
[self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
_mbglMap->setZoom(newZoom, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
}
@@ -1760,6 +1803,8 @@ public:
_mbglMap->cancelTransitions();
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonGestureTilt;
if (twoFingerDrag.state == UIGestureRecognizerStateBegan)
{
[self trackGestureEvent:MGLEventGesturePitchStart forRecognizer:twoFingerDrag];
@@ -1779,8 +1824,7 @@ public:
MGLMapCamera *oldCamera = self.camera;
MGLMapCamera *toCamera = [self cameraByTiltingToPitch:pitchNew];
if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
[self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
_mbglMap->setPitch(pitchNew, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
}
@@ -2278,7 +2322,7 @@ public:
- (void)emptyMemoryCache
{
_rendererFrontend->onLowMemory();
_rendererFrontend->reduceMemoryUse();
}
- (void)setZoomEnabled:(BOOL)zoomEnabled
@@ -2871,6 +2915,8 @@ public:
{
self.userTrackingMode = MGLUserTrackingModeNone;
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
[self _setCenterCoordinate:centerCoordinate edgePadding:self.contentInset zoomLevel:zoomLevel direction:direction duration:animated ? MGLAnimationDuration : 0 animationTimingFunction:nil completionHandler:completion];
}
@@ -2920,6 +2966,9 @@ public:
}
_mbglMap->cancelTransitions();
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
_mbglMap->easeTo(cameraOptions, animationOptions);
}
@@ -2943,6 +2992,8 @@ public:
if (zoomLevel == self.zoomLevel) return;
_mbglMap->cancelTransitions();
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
CGFloat duration = animated ? MGLAnimationDuration : 0;
_mbglMap->setZoom(zoomLevel,
@@ -3031,6 +3082,9 @@ public:
- (void)setVisibleCoordinates:(const CLLocationCoordinate2D *)coordinates count:(NSUInteger)count edgePadding:(UIEdgeInsets)insets direction:(CLLocationDirection)direction duration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion
{
self.userTrackingMode = MGLUserTrackingModeNone;
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
[self _setVisibleCoordinates:coordinates count:count edgePadding:insets direction:direction duration:duration animationTimingFunction:function completionHandler:completion];
}
@@ -3080,6 +3134,9 @@ public:
[self willChangeValueForKey:@"visibleCoordinateBounds"];
_mbglMap->cancelTransitions();
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
_mbglMap->easeTo(cameraOptions, animationOptions);
[self didChangeValueForKey:@"visibleCoordinateBounds"];
}
@@ -3113,6 +3170,8 @@ public:
CGFloat duration = animated ? MGLAnimationDuration : 0;
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
if (self.userTrackingMode == MGLUserTrackingModeNone)
{
_mbglMap->setBearing(direction,
@@ -3197,6 +3256,9 @@ public:
[self willChangeValueForKey:@"camera"];
_mbglMap->cancelTransitions();
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera edgePadding:edgePadding];
_mbglMap->easeTo(cameraOptions, animationOptions);
[self didChangeValueForKey:@"camera"];
@@ -3253,6 +3315,9 @@ public:
[self willChangeValueForKey:@"camera"];
_mbglMap->cancelTransitions();
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera edgePadding:insets];
_mbglMap->flyTo(cameraOptions, animationOptions);
[self didChangeValueForKey:@"camera"];
@@ -3413,6 +3478,13 @@ public:
return [self metersPerPointAtLatitude:latitude];
}
#pragma mark - Camera Change Reason -
- (void)resetCameraChangeReason
{
self.cameraChangeReasonBitmask = MGLCameraChangeReasonNone;
}
#pragma mark - Styling -
- (NS_ARRAY_OF(NSURL *) *)bundledStyleURLs
@@ -5354,9 +5426,16 @@ public:
}
}
if ( ! [self isSuppressingChangeDelimiters] && [self.delegate respondsToSelector:@selector(mapView:regionWillChangeAnimated:)])
if ( ! [self isSuppressingChangeDelimiters] )
{
[self.delegate mapView:self regionWillChangeAnimated:animated];
if ([self.delegate respondsToSelector:@selector(mapView:regionWillChangeWithReason:animated:)])
{
[self.delegate mapView:self regionWillChangeWithReason:self.cameraChangeReasonBitmask animated:animated];
}
else if ([self.delegate respondsToSelector:@selector(mapView:regionWillChangeAnimated:)])
{
[self.delegate mapView:self regionWillChangeAnimated:animated];
}
}
}
@@ -5370,8 +5449,12 @@ public:
if (!self.scaleBar.hidden) {
[(MGLScaleBar *)self.scaleBar setMetersPerPoint:[self metersPerPointAtLatitude:self.centerCoordinate.latitude]];
}
if ([self.delegate respondsToSelector:@selector(mapViewRegionIsChanging:)])
if ([self.delegate respondsToSelector:@selector(mapView:regionIsChangingWithReason:)])
{
[self.delegate mapView:self regionIsChangingWithReason:self.cameraChangeReasonBitmask];
}
else if ([self.delegate respondsToSelector:@selector(mapViewRegionIsChanging:)])
{
[self.delegate mapViewRegionIsChanging:self];
}
@@ -5384,9 +5467,13 @@ public:
[self updateCompass];
if ( ! [self isSuppressingChangeDelimiters] && [self.delegate respondsToSelector:@selector(mapView:regionDidChangeAnimated:)])
if ( ! [self isSuppressingChangeDelimiters])
{
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive)
BOOL respondsToSelector = [self.delegate respondsToSelector:@selector(mapView:regionDidChangeAnimated:)];
BOOL respondsToSelectorWithReason = [self.delegate respondsToSelector:@selector(mapView:regionDidChangeWithReason:animated:)];
if ((respondsToSelector || respondsToSelectorWithReason) &&
([UIApplication sharedApplication].applicationState == UIApplicationStateActive))
{
_featureAccessibilityElements = nil;
_visiblePlaceFeatures = nil;
@@ -5398,7 +5485,17 @@ public:
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
}
}
[self.delegate mapView:self regionDidChangeAnimated:animated];
if (respondsToSelectorWithReason)
{
[self.delegate mapView:self regionDidChangeWithReason:self.cameraChangeReasonBitmask animated:animated];
}
else if (respondsToSelector)
{
[self.delegate mapView:self regionDidChangeAnimated:animated];
}
[self resetCameraChangeReason];
}
}

View File

@@ -1,6 +1,7 @@
#import <UIKit/UIKit.h>
#import "MGLTypes.h"
#import "MGLCameraChangeReason.h"
NS_ASSUME_NONNULL_BEGIN
@@ -21,17 +22,80 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark Responding to Map Position Changes
/**
Asks the delegate whether the map view should be allowed to change from the
existing camera to the new camera in response to a user gesture.
This method is called as soon as the user gesture is recognized. It is not
called in response to a programmatic camera change, such as by setting the
`centerCoordinate` property or calling `-flyToCamera:completionHandler:`.
This method is called many times during gesturing, so you should avoid performing
complex or performance-intensive tasks in your implementation.
@param mapView The map view that the user is manipulating.
@param oldCamera The camera representing the viewpoint at the moment the
gesture is recognized. If this method returns `NO`, the map view’s camera
continues to be this camera.
@param newCamera The expected camera after the gesture completes. If this
method returns `YES`, this camera becomes the map view’s camera.
@return A Boolean value indicating whether the map view should stay at
`oldCamera` or change to `newCamera`.
*/
- (BOOL)mapView:(MGLMapView *)mapView shouldChangeFromCamera:(MGLMapCamera *)oldCamera toCamera:(MGLMapCamera *)newCamera;
/**
:nodoc:
Asks the delegate whether the map view should be allowed to change from the
existing camera to the new camera in response to a user gesture.
This method is called as soon as the user gesture is recognized. It is not
called in response to a programmatic camera change, such as by setting the
`centerCoordinate` property or calling `-flyToCamera:completionHandler:`.
This method is called many times during gesturing, so you should avoid performing
complex or performance-intensive tasks in your implementation.
@param mapView The map view that the user is manipulating.
@param oldCamera The camera representing the viewpoint at the moment the
gesture is recognized. If this method returns `NO`, the map view’s camera
continues to be this camera.
@param newCamera The expected camera after the gesture completes. If this
method returns `YES`, this camera becomes the map view’s camera.
@param reason The reason for the camera change.
@return A Boolean value indicating whether the map view should stay at
`oldCamera` or change to `newCamera`.
@note If this method is implemented `-mapView:shouldChangeFromCamera:toCamera:` will not be called.
*/
- (BOOL)mapView:(MGLMapView *)mapView shouldChangeFromCamera:(MGLMapCamera *)oldCamera toCamera:(MGLMapCamera *)newCamera reason:(MGLCameraChangeReason)reason;
/**
Tells the delegate that the viewpoint depicted by the map view is about to change.
This method is called whenever the currently displayed map camera will start
changing for any reason.
@param mapView The map view whose viewpoint will change.
@param animated Whether the change will cause an animated effect on the map.
*/
- (void)mapView:(MGLMapView *)mapView regionWillChangeAnimated:(BOOL)animated;
/**
:nodoc:
Tells the delegate that the viewpoint depicted by the map view is about to change.
This method is called whenever the currently displayed map camera will start
changing for any reason.
@param mapView The map view whose viewpoint will change.
@param animated Whether the change will cause an animated effect on the map.
@param reason The reason for the camera change.
@note If this method is implemented `-mapView:regionWillChangeAnimated:` will not be called.
*/
- (void)mapView:(MGLMapView *)mapView regionWillChangeWithReason:(MGLCameraChangeReason)reason animated:(BOOL)animated;
/**
Tells the delegate that the viewpoint depicted by the map view is changing.
@@ -48,6 +112,26 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)mapViewRegionIsChanging:(MGLMapView *)mapView;
/**
:nodoc:
Tells the delegate that the viewpoint depicted by the map view is changing.
This method is called as the currently displayed map camera changes as part of
an animation, whether due to a user gesture or due to a call to a method such
as `-[MGLMapView setCamera:animated:]`. This method can be called before
`-mapViewDidFinishLoadingMap:` is called.
During the animation, this method may be called many times to report updates to
the viewpoint. Therefore, your implementation of this method should be as lightweight
as possible to avoid affecting performance.
@param mapView The map view whose viewpoint is changing.
@param reason The reason for the camera change.
@note If this method is implemented `-mapViewRegionIsChanging:` will not be called.
*/
- (void)mapView:(MGLMapView *)mapView regionIsChangingWithReason:(MGLCameraChangeReason)reason;
/**
Tells the delegate that the viewpoint depicted by the map view has finished
changing.
@@ -62,26 +146,21 @@ NS_ASSUME_NONNULL_BEGIN
- (void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
/**
Asks the delegate whether the map view should be allowed to change from the
existing camera to the new camera in response to a user gesture.
This method is called as soon as the user gesture is recognized. It is not
called in response to a programmatic camera change, such as by setting the
`centerCoordinate` property or calling `-flyToCamera:completionHandler:`.
This method is called many times during gesturing, so you should avoid performing
complex or performance-intensive tasks in your implementation.
@param mapView The map view that the user is manipulating.
@param oldCamera The camera representing the viewpoint at the moment the
gesture is recognized. If this method returns `NO`, the map view’s camera
continues to be this camera.
@param newCamera The expected camera after the gesture completes. If this
method returns `YES`, this camera becomes the map view’s camera.
@return A Boolean value indicating whether the map view should stay at
`oldCamera` or change to `newCamera`.
:nodoc:
Tells the delegate that the viewpoint depicted by the map view has finished
changing.
This method is called whenever the currently displayed map camera has finished
changing, after any calls to `-mapViewRegionIsChanging:` due to animation. Therefore,
this method can be called before `-mapViewDidFinishLoadingMap:` is called.
@param mapView The map view whose viewpoint has changed.
@param animated Whether the change caused an animated effect on the map.
@param reason The reason for the camera change.
@note If this method is implemented `-mapView:regionDidChangeAnimated:` will not be called.
*/
- (BOOL)mapView:(MGLMapView *)mapView shouldChangeFromCamera:(MGLMapCamera *)oldCamera toCamera:(MGLMapCamera *)newCamera;
- (void)mapView:(MGLMapView *)mapView regionDidChangeWithReason:(MGLCameraChangeReason)reason animated:(BOOL)animated;
#pragma mark Loading the Map

View File

@@ -6,6 +6,7 @@
#import "NSException+MGLAdditions.h"
#import "MGLAPIClient.h"
#import "MGLLocationManager.h"
#import "MGLTelemetryConfig.h"
#include <mbgl/storage/reachability.h>
#include <sys/sysctl.h>
@@ -172,6 +173,8 @@ const NSTimeInterval MGLFlushInterval = 180;
- (instancetype) init {
self = [super init];
if (self) {
[MGLTelemetryConfig.sharedConfig configurationFromKey:[[NSUserDefaults standardUserDefaults] objectForKey:MGLMapboxMetricsProfile]];
_currentAccountTypeValue = @0;
_currentMetricsEnabledValue = YES;

View File

@@ -0,0 +1,18 @@
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
NS_ASSUME_NONNULL_BEGIN
@interface MGLTelemetryConfig : NSObject
@property (nonatomic) CLLocationDistance MGLLocationManagerHibernationRadius;
extern NSString *const MGLMapboxMetricsProfile;
+ (nullable instancetype)sharedConfig;
- (void)configurationFromKey:(NSString *)key;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,35 @@
#import "MGLTelemetryConfig.h"
static const CLLocationDistance MGLConfigHibernationRadiusDefault = 300.0;
static const CLLocationDistance MGLConfigHibernationRadiusWide = 600.0;
NSString *const MGLMapboxMetricsProfile = @"MGLMapboxMetricsProfile";
static NSString *const MGLConfigHibernationRadiusWideKey = @"WideGeoFence";
@implementation MGLTelemetryConfig
- (instancetype) init {
self = [super init];
if (self) {
_MGLLocationManagerHibernationRadius = MGLConfigHibernationRadiusDefault;
}
return self;
}
+ (nullable instancetype)sharedConfig {
static dispatch_once_t onceToken;
static MGLTelemetryConfig *_sharedConfig;
dispatch_once(&onceToken, ^{
_sharedConfig = [[self alloc] init];
});
return _sharedConfig;
}
- (void)configurationFromKey:(NSString *)key {
if ([key isEqualToString:MGLConfigHibernationRadiusWideKey]) {
_MGLLocationManagerHibernationRadius = MGLConfigHibernationRadiusWide;
}
}
@end

View File

@@ -45,6 +45,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLSymbolStyleLayer.h"
#import "MGLRasterStyleLayer.h"
#import "MGLCircleStyleLayer.h"
#import "MGLHeatmapStyleLayer.h"
#import "MGLHillshadeStyleLayer.h"
#import "MGLBackgroundStyleLayer.h"
#import "MGLOpenGLStyleLayer.h"

View File

@@ -13,6 +13,10 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate {
func mapViewRegionIsChanging(_ mapView: MGLMapView) {}
func mapViewRegionIsChanging(_ mapView: MGLMapView, reason: MGLCameraChangeReason) {}
func mapView(_ mapView: MGLMapView, regionIsChangingWith reason: MGLCameraChangeReason) {}
func mapView(_ mapView: MGLMapView, didChange mode: MGLUserTrackingMode, animated: Bool) {}
func mapViewDidFinishLoadingMap(_ mapView: MGLMapView) {}
@@ -33,10 +37,16 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate {
func mapView(_ mapView: MGLMapView, didDeselect annotation: MGLAnnotation) {}
func mapView(_ mapView: MGLMapView, didSingleTapAt coordinate: CLLocationCoordinate2D) {}
func mapView(_ mapView: MGLMapView, regionDidChangeAnimated animated: Bool) {}
func mapView(_ mapView: MGLMapView, regionDidChangeWith reason: MGLCameraChangeReason, animated: Bool) {}
func mapView(_ mapView: MGLMapView, regionWillChangeAnimated animated: Bool) {}
func mapView(_ mapView: MGLMapView, regionWillChangeWith reason: MGLCameraChangeReason, animated: Bool) {}
func mapViewDidFailLoadingMap(_ mapView: MGLMapView, withError error: Error) {}
func mapView(_ mapView: MGLMapView, didUpdate userLocation: MGLUserLocation?) {}
@@ -79,4 +89,5 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate {
func mapView(_ mapView: MGLMapView, shouldChangeFrom oldCamera: MGLMapCamera, to newCamera: MGLMapCamera) -> Bool { return false }
func mapView(_ mapView: MGLMapView, shouldChangeFrom oldCamera: MGLMapCamera, to newCamera: MGLMapCamera, reason: MGLCameraChangeReason) -> Bool { return false }
}

View File

@@ -538,10 +538,13 @@
userInfo:@{ @"animated" : @(animated) }];
}
- (void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
- (void)mapView:(MGLMapView *)mapView regionDidChangeWithReason:(MGLCameraChangeReason)reason animated:(BOOL)animated {
[[NSNotificationCenter defaultCenter] postNotificationName:@"regionDidChangeAnimated"
object:mapView
userInfo:@{ @"animated" : @(animated) }];
userInfo:@{ @"animated" : @(animated),
@"reason" : @(reason)
}];
}
- (void)testDelegatesStartStopLocatingUser {

View File

@@ -4,20 +4,24 @@
### Styles and rendering
* Added support for a new layer type: `MGLHeatmapStyleLayer`, a powerful way to visualize point data distributions using heatmaps, fully customizable through runtime styling. [#11046](https://github.com/mapbox/mapbox-gl-native/pull/11046)
* The layout and paint properties on subclasses of `MGLStyleLayer` are now of type `NSExpression` instead of `MGLStyleValue`. A new “Predicates and Expressions” guide provides an overview of the supported operators. ([#10726](https://github.com/mapbox/mapbox-gl-native/pull/10726))
* Added an `MGLComputedShapeSource` class that allows applications to supply vector data to a style layer on a per-tile basis. ([#9983](https://github.com/mapbox/mapbox-gl-native/pull/9983))
* A style can now display smooth hillshading and customize its appearance at runtime using the `MGLHillshadeStyleLayer` class. Hillshading is based on a rasterized digital elevation model supplied by the `MGLRasterDEMSource` class. ([#10642](https://github.com/mapbox/mapbox-gl-native/pull/10642))
* The `MGLSymbolStyleLayer.textFontNames` property can now depend on a feature’s attributes. ([#10850](https://github.com/mapbox/mapbox-gl-native/pull/10850))
* Properties such as `MGLSymbolStyleLayer.iconAllowsOverlap` and `MGLSymbolStyleLayer.iconIgnoresPlacement` now account for symbols in other sources. ([#10436](https://github.com/mapbox/mapbox-gl-native/pull/10436))
### Map rendering
* Improved the reliability of collision detection between symbols near the edges of tiles, as well as between symbols when the map is tilted. It is no longer necessary to enable `MGLSymbolStyleLayer.symbolAvoidsEdges` to prevent symbols in adjacent tiles from overlapping with each other. ([#10436](https://github.com/mapbox/mapbox-gl-native/pull/10436))
* Symbols can fade in and out as the map pans, rotates, or tilts. ([#10436](https://github.com/mapbox/mapbox-gl-native/pull/10436))
* Properties such as `MGLSymbolStyleLayer.iconAllowsOverlap` and `MGLSymbolStyleLayer.iconIgnoresPlacement` now account for symbols in other sources. ([#10436](https://github.com/mapbox/mapbox-gl-native/pull/10436))
* Added the `MGLTileSourceOptionTileCoordinateBounds` option to create an `MGLTileSource` that only supplies tiles within a specific geographic bounding box. ([#11141](https://github.com/mapbox/mapbox-gl-native/pull/11141))
* Fixed an issue preventing a dynamically-added `MGLRasterStyleLayer` from drawing until the map pans. ([#10270](https://github.com/mapbox/mapbox-gl-native/pull/10270))
* Fixed an issue preventing `MGLImageSource`s from drawing on the map when the map is zoomed in and tilted. ([#10677](https://github.com/mapbox/mapbox-gl-native/pull/10677))
* Improved the sharpness of raster tiles on Retina displays. ([#10984](https://github.com/mapbox/mapbox-gl-native/pull/10984))
* Fixed a crash parsing a malformed style. ([#11001](https://github.com/mapbox/mapbox-gl-native/pull/11001))
* Added the `MGLTileSourceOptionTileCoordinateBounds` option to create an `MGLTileSource` that only supplies tiles within a specific geographic bounding box. ([#11141](https://github.com/mapbox/mapbox-gl-native/pull/11141))
### Map snapshots
@@ -28,6 +32,7 @@
* Added Danish and Hebrew localizations. ([#10967](https://github.com/mapbox/mapbox-gl-native/pull/10967), [#11136](https://github.com/mapbox/mapbox-gl-native/pull/11134))
* Feature querying results now account for the `MGLSymbolStyleLayer.circleStrokeWidth` property. ([#10897](https://github.com/mapbox/mapbox-gl-native/pull/10897))
* Added a Hebrew localization. ([#10967](https://github.com/mapbox/mapbox-gl-native/pull/10967))
## v0.6.1 - January 16, 2018

View File

@@ -0,0 +1,16 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "heatmap.pdf",
"language-direction" : "left-to-right"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

View File

@@ -726,8 +726,14 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[self.undoManager setActionName:@"Add Graticule"];
}
NSDictionary *sourceOptions = @{
MGLShapeSourceOptionMaximumZoomLevel:@14,
MGLShapeSourceOptionWrapsCoordinates: @YES,
MGLShapeSourceOptionClipsCoordinates: @YES,
};
MGLComputedShapeSource *source = [[MGLComputedShapeSource alloc] initWithIdentifier:@"graticule"
options:@{MGLShapeSourceOptionMaximumZoomLevel:@14}];
options:sourceOptions];
source.dataSource = self;
[self.mapView.style addSource:source];
MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"graticule.lines"

View File

@@ -31,6 +31,9 @@
if ([layer isKindOfClass:[MGLSymbolStyleLayer class]]) {
return [NSImage imageNamed:@"symbol"];
}
if ([layer isKindOfClass:[MGLHeatmapStyleLayer class]]) {
return [NSImage imageNamed:@"heatmap"];
}
if ([layer isKindOfClass:[MGLHillshadeStyleLayer class]]) {
return [NSImage imageNamed:@"hillshade"];
}

View File

@@ -0,0 +1,809 @@
{
"version": 8,
"name": "Basic Heatmap",
"center": [
30.49860107152665,
50.459868549177486
],
"zoom": 14.033276876197775,
"bearing": 0,
"pitch": 0,
"sources": {
"mapbox": {
"url": "mapbox://mapbox.mapbox-streets-v7",
"type": "vector"
}
},
"sprite": "mapbox://sprites/mourner/cjcgg2bl16cf42snvcbbaf09z",
"glyphs": "mapbox://fonts/mourner/{fontstack}/{range}.pbf",
"layers": [
{
"id": "background",
"type": "background",
"paint": {
"background-color": "#dedede"
}
},
{
"id": "landuse_overlay_national_park",
"type": "fill",
"source": "mapbox",
"source-layer": "landuse_overlay",
"filter": [
"==",
"class",
"national_park"
],
"paint": {
"fill-color": "#d2edae",
"fill-opacity": 0.75
}
},
{
"id": "landuse_park",
"type": "fill",
"source": "mapbox",
"source-layer": "landuse",
"filter": [
"==",
"class",
"park"
],
"paint": {
"fill-color": "#d2edae"
}
},
{
"id": "waterway",
"type": "line",
"source": "mapbox",
"source-layer": "waterway",
"filter": [
"all",
[
"==",
"$type",
"LineString"
],
[
"in",
"class",
"canal",
"river"
]
],
"paint": {
"line-color": "#a0cfdf",
"line-width": {
"base": 1.4,
"stops": [
[
8,
0.5
],
[
20,
15
]
]
}
}
},
{
"id": "water",
"type": "fill",
"source": "mapbox",
"source-layer": "water",
"paint": {
"fill-color": "#a0cfdf"
}
},
{
"id": "building",
"type": "fill",
"source": "mapbox",
"source-layer": "building",
"paint": {
"fill-color": "#d6d6d6"
}
},
{
"id": "tunnel_minor",
"type": "line",
"source": "mapbox",
"source-layer": "road",
"filter": [
"all",
[
"==",
"$type",
"LineString"
],
[
"all",
[
"==",
"structure",
"tunnel"
],
[
"in",
"class",
"link",
"motorway_link",
"path",
"pedestrian",
"service",
"street",
"street_limited",
"track"
]
]
],
"layout": {
"line-cap": "butt",
"line-join": "miter"
},
"paint": {
"line-color": "#efefef",
"line-width": {
"base": 1.55,
"stops": [
[
4,
0.25
],
[
20,
30
]
]
},
"line-dasharray": [
0.36,
0.18
]
}
},
{
"id": "tunnel_major",
"type": "line",
"source": "mapbox",
"source-layer": "road",
"filter": [
"all",
[
"==",
"$type",
"LineString"
],
[
"all",
[
"==",
"structure",
"tunnel"
],
[
"in",
"class",
"motorway",
"primary",
"secondary",
"tertiary",
"trunk"
]
]
],
"layout": {
"line-cap": "butt",
"line-join": "miter"
},
"paint": {
"line-color": "#fff",
"line-width": {
"base": 1.4,
"stops": [
[
6,
0.5
],
[
20,
30
]
]
},
"line-dasharray": [
0.28,
0.14
]
}
},
{
"id": "road_minor",
"type": "line",
"source": "mapbox",
"source-layer": "road",
"filter": [
"all",
[
"==",
"$type",
"LineString"
],
[
"all",
[
"in",
"class",
"link",
"motorway_link",
"path",
"pedestrian",
"service",
"street",
"street_limited",
"track"
],
[
"in",
"structure",
"ford",
"none"
]
]
],
"layout": {
"line-cap": "round",
"line-join": "round"
},
"paint": {
"line-color": "#efefef",
"line-width": {
"base": 1.55,
"stops": [
[
4,
0.25
],
[
20,
30
]
]
}
}
},
{
"id": "road_major",
"type": "line",
"source": "mapbox",
"source-layer": "road",
"filter": [
"all",
[
"==",
"$type",
"LineString"
],
[
"all",
[
"in",
"class",
"motorway",
"primary",
"secondary",
"tertiary",
"trunk"
],
[
"in",
"structure",
"ford",
"none"
]
]
],
"layout": {
"line-cap": "round",
"line-join": "round"
},
"paint": {
"line-color": "#fff",
"line-width": {
"base": 1.4,
"stops": [
[
6,
0.5
],
[
20,
30
]
]
}
}
},
{
"id": "bridge_minor case",
"type": "line",
"source": "mapbox",
"source-layer": "road",
"filter": [
"all",
[
"==",
"$type",
"LineString"
],
[
"all",
[
"==",
"structure",
"bridge"
],
[
"in",
"class",
"link",
"motorway_link",
"path",
"pedestrian",
"service",
"street",
"street_limited",
"track"
]
]
],
"layout": {
"line-cap": "butt",
"line-join": "miter"
},
"paint": {
"line-color": "#dedede",
"line-width": {
"base": 1.6,
"stops": [
[
12,
0.5
],
[
20,
10
]
]
},
"line-gap-width": {
"base": 1.55,
"stops": [
[
4,
0.25
],
[
20,
30
]
]
}
}
},
{
"id": "bridge_major case",
"type": "line",
"source": "mapbox",
"source-layer": "road",
"filter": [
"all",
[
"==",
"$type",
"LineString"
],
[
"all",
[
"==",
"structure",
"bridge"
],
[
"in",
"class",
"motorway",
"primary",
"secondary",
"tertiary",
"trunk"
]
]
],
"layout": {
"line-cap": "butt",
"line-join": "miter"
},
"paint": {
"line-color": "#dedede",
"line-width": {
"base": 1.6,
"stops": [
[
12,
0.5
],
[
20,
10
]
]
},
"line-gap-width": {
"base": 1.55,
"stops": [
[
4,
0.25
],
[
20,
30
]
]
}
}
},
{
"id": "bridge_minor",
"type": "line",
"source": "mapbox",
"source-layer": "road",
"filter": [
"all",
[
"==",
"$type",
"LineString"
],
[
"all",
[
"==",
"structure",
"bridge"
],
[
"in",
"class",
"link",
"motorway_link",
"path",
"pedestrian",
"service",
"street",
"street_limited",
"track"
]
]
],
"layout": {
"line-cap": "round",
"line-join": "round"
},
"paint": {
"line-color": "#efefef",
"line-width": {
"base": 1.55,
"stops": [
[
4,
0.25
],
[
20,
30
]
]
}
}
},
{
"id": "bridge_major",
"type": "line",
"source": "mapbox",
"source-layer": "road",
"filter": [
"all",
[
"==",
"$type",
"LineString"
],
[
"all",
[
"==",
"structure",
"bridge"
],
[
"in",
"class",
"motorway",
"primary",
"secondary",
"tertiary",
"trunk"
]
]
],
"layout": {
"line-cap": "round",
"line-join": "round"
},
"paint": {
"line-color": "#fff",
"line-width": {
"base": 1.4,
"stops": [
[
6,
0.5
],
[
20,
30
]
]
}
}
},
{
"id": "admin_country",
"type": "line",
"source": "mapbox",
"source-layer": "admin",
"filter": [
"all",
[
"==",
"$type",
"LineString"
],
[
"all",
[
"<=",
"admin_level",
2
],
[
"==",
"maritime",
0
]
]
],
"layout": {
"line-cap": "round",
"line-join": "round"
},
"paint": {
"line-color": "#8b8a8a",
"line-width": {
"base": 1.3,
"stops": [
[
3,
0.5
],
[
22,
15
]
]
}
}
},
{
"id": "road_major_label",
"type": "symbol",
"source": "mapbox",
"source-layer": "road_label",
"filter": [
"all",
[
"==",
"$type",
"LineString"
],
[
"in",
"class",
"motorway",
"primary",
"secondary",
"tertiary",
"trunk"
]
],
"layout": {
"symbol-placement": "line",
"text-field": "{name_en}",
"text-font": [
"Open Sans Semibold",
"Arial Unicode MS Bold"
],
"text-transform": "uppercase",
"text-letter-spacing": 0.1,
"text-size": {
"base": 1.4,
"stops": [
[
10,
8
],
[
20,
14
]
]
}
},
"paint": {
"text-color": "#666",
"text-halo-color": "rgba(255,255,255,0.75)",
"text-halo-width": 2
}
},
{
"id": "place_label_other",
"type": "symbol",
"source": "mapbox",
"source-layer": "place_label",
"minzoom": 8,
"filter": [
"all",
[
"==",
"$type",
"Point"
],
[
"in",
"type",
"hamlet",
"island",
"neighbourhood",
"suburb",
"town",
"village"
]
],
"layout": {
"text-field": "{name_en}",
"text-font": [
"Open Sans Semibold",
"Arial Unicode MS Bold"
],
"text-max-width": 6,
"text-size": {
"stops": [
[
6,
12
],
[
12,
16
]
]
}
},
"paint": {
"text-color": "#666",
"text-halo-color": "rgba(255,255,255,0.75)",
"text-halo-width": 1,
"text-halo-blur": 1
}
},
{
"id": "place_label_city",
"type": "symbol",
"source": "mapbox",
"source-layer": "place_label",
"maxzoom": 16,
"filter": [
"all",
[
"==",
"$type",
"Point"
],
[
"==",
"type",
"city"
]
],
"layout": {
"text-field": "{name_en}",
"text-font": [
"Open Sans Bold",
"Arial Unicode MS Bold"
],
"text-max-width": 10,
"text-size": {
"stops": [
[
3,
12
],
[
8,
16
]
]
}
},
"paint": {
"text-color": "#666",
"text-halo-color": "rgba(255,255,255,0.75)",
"text-halo-width": 1,
"text-halo-blur": 1
}
},
{
"id": "country_label",
"type": "symbol",
"source": "mapbox",
"source-layer": "country_label",
"maxzoom": 12,
"filter": [
"==",
"$type",
"Point"
],
"layout": {
"text-field": "{name_en}",
"text-font": [
"Open Sans Regular",
"Arial Unicode MS Regular"
],
"text-max-width": 10,
"text-size": {
"stops": [
[
3,
14
],
[
8,
22
]
]
}
},
"paint": {
"text-color": "#666",
"text-halo-color": "rgba(255,255,255,0.75)",
"text-halo-width": 1,
"text-halo-blur": 1
}
},
{
"id": "road-heatmap",
"type": "heatmap",
"source": "mapbox",
"source-layer": "road",
"paint": {
"heatmap-intensity": 1
}
}
]
}

View File

@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
id="svg4148"
version="1.1"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
sodipodi:docname="heatmap.svg"
inkscape:export-filename="/Users/mxn/Desktop/symbol.png"
inkscape:export-xdpi="90.000244"
inkscape:export-ydpi="90.000244">
<defs
id="defs4150" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="23.25"
inkscape:cx="4.7741936"
inkscape:cy="7.6812068"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="1280"
inkscape:window-height="755"
inkscape:window-x="0"
inkscape:window-y="1"
inkscape:window-maximized="1"
inkscape:snap-bbox="true" />
<metadata
id="metadata4153">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1036.3622)">
<path
style="opacity:1;fill:#ffffff;fill-opacity:0;fill-rule:evenodd;stroke:#000000;stroke-width:0.99369001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 11.237265,1036.8591 a 4.2655011,4.1972104 0 0 0 -4.2658922,4.1979 4.2655011,4.1972104 0 0 0 0.025231,0.427 5.3408028,5.2552965 0 0 0 -1.1586611,-0.1299 5.3408028,5.2552965 0 0 0 -5.34109749,5.2556 5.3408028,5.2552965 0 0 0 5.34109749,5.2557 5.3408028,5.2552965 0 0 0 5.3410983,-5.2557 5.3408028,5.2552965 0 0 0 -0.186318,-1.3664 4.2655011,4.1972104 0 0 0 0.244542,0.012 4.2655011,4.1972104 0 0 0 4.26589,-4.198 4.2655011,4.1972104 0 0 0 -4.26589,-4.1979 z"
id="path818"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:#000000;fill-opacity:0.15686275;fill-rule:evenodd;stroke:none;stroke-width:0.99369001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 11.005859,1038.875 c -4.8895767,1.3679 0.321278,7.2823 2.416016,2.7578 0.450567,-1.4666 -0.923376,-2.9624 -2.416016,-2.7578 z m -5.5078121,4.5 c -5.49629855,0.4756 -2.1892763,9.0394 2.2363281,5.9121 2.667642,-1.8963 1.5392118,-6.8607 -2.2363281,-5.9121 z"
id="path836"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -96,6 +96,7 @@ the following terms for concepts defined in the style specification:
In the style specification | In the SDK
---------------------------|---------
bounds | coordinate bounds
filter | predicate
function type | interpolation mode
id | identifier
@@ -136,6 +137,7 @@ In style JSON | In TileJSON | In the SDK
`tiles` | `tiles` | `tileURLTemplates` parameter in `-[MGLTileSource initWithIdentifier:tileURLTemplates:options:]`
`minzoom` | `minzoom` | `MGLTileSourceOptionMinimumZoomLevel`
`maxzoom` | `maxzoom` | `MGLTileSourceOptionMaximumZoomLevel`
`bounds` | `bounds` | `MGLTileSourceOptionCoordinateBounds`
`tileSize` | — | `MGLTileSourceOptionTileSize`
`attribution` | `attribution` | `MGLTileSourceOptionAttributionHTMLString` (but consider specifying `MGLTileSourceOptionAttributionInfos` instead for improved security)
`scheme` | `scheme` | `MGLTileSourceOptionTileCoordinateSystem`
@@ -177,6 +179,7 @@ In style JSON | In the SDK
`circle` | `MGLCircleStyleLayer`
`fill` | `MGLFillStyleLayer`
`fill-extrusion` | `MGLFillExtrusionStyleLayer`
`heatmap` | `MGLHeatmapStyleLayer`
`hillshade` | `MGLHillshadeStyleLayer`
`line` | `MGLLineStyleLayer`
`raster` | `MGLRasterStyleLayer`

View File

@@ -80,6 +80,7 @@ custom_categories:
- MGLCircleStyleLayer
- MGLFillStyleLayer
- MGLFillExtrusionStyleLayer
- MGLHeatmapStyleLayer
- MGLHillshadeStyleLayer
- MGLLineStyleLayer
- MGLSymbolStyleLayer

View File

@@ -16,6 +16,8 @@
07D9474D1F67441B00E37934 /* MGLAbstractShapeSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 07D947471F6741F500E37934 /* MGLAbstractShapeSource_Private.h */; };
07F8E2F71F674C8800F794BB /* MGLComputedShapeSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 07F8E2F41F674C8000F794BB /* MGLComputedShapeSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
07F8E2F81F674C9000F794BB /* MGLComputedShapeSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 07F8E2F51F674C8000F794BB /* MGLComputedShapeSource.mm */; };
170A82BF201BDD1B00943087 /* MGLHeatmapStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 170A82BE201BDD1B00943087 /* MGLHeatmapStyleLayerTests.mm */; };
170A82C4201FB6EC00943087 /* MGLHeatmapColorTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 170A82C2201FAFF800943087 /* MGLHeatmapColorTests.mm */; };
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, ); }; };
@@ -85,6 +87,9 @@
55D120A31F7906E6004B6D81 /* libmbgl-filesource.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D120A41F7906E6004B6D81 /* libmbgl-filesource.a */; };
55D120A51F790A0C004B6D81 /* libmbgl-filesource.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D120A41F7906E6004B6D81 /* libmbgl-filesource.a */; };
55E2AD111E5B0A6900E8C587 /* MGLOfflineStorageTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 55E2AD101E5B0A6900E8C587 /* MGLOfflineStorageTests.mm */; };
89462399200D199100DA8EF2 /* heatmap.json in Resources */ = {isa = PBXBuildFile; fileRef = 89462398200D199100DA8EF2 /* heatmap.json */; };
8946239D200E744800DA8EF2 /* MGLHeatmapStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 8946239A200E73CA00DA8EF2 /* MGLHeatmapStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
894623A0200E748000DA8EF2 /* MGLHeatmapStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8946239B200E73CA00DA8EF2 /* MGLHeatmapStyleLayer.mm */; };
92092EF01F5EB10E00AF5130 /* MGLMapSnapshotter.h in Headers */ = {isa = PBXBuildFile; fileRef = 92092EEE1F5EB10E00AF5130 /* MGLMapSnapshotter.h */; settings = {ATTRIBUTES = (Public, ); }; };
92092EF11F5EB10E00AF5130 /* MGLMapSnapshotter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92092EEF1F5EB10E00AF5130 /* MGLMapSnapshotter.mm */; };
920A3E591E6F859D00C16EFC /* MGLSourceQueryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 920A3E581E6F859D00C16EFC /* MGLSourceQueryTests.m */; };
@@ -298,6 +303,8 @@
07D947491F6741F500E37934 /* MGLAbstractShapeSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAbstractShapeSource.mm; sourceTree = "<group>"; };
07F8E2F41F674C8000F794BB /* MGLComputedShapeSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLComputedShapeSource.h; sourceTree = "<group>"; };
07F8E2F51F674C8000F794BB /* MGLComputedShapeSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLComputedShapeSource.mm; sourceTree = "<group>"; };
170A82BE201BDD1B00943087 /* MGLHeatmapStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLHeatmapStyleLayerTests.mm; sourceTree = "<group>"; };
170A82C2201FAFF800943087 /* MGLHeatmapColorTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLHeatmapColorTests.mm; 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>"; };
@@ -369,6 +376,9 @@
55D9B4B01D005D3900C1CCE2 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
55E2AD101E5B0A6900E8C587 /* MGLOfflineStorageTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLOfflineStorageTests.mm; path = ../../darwin/test/MGLOfflineStorageTests.mm; sourceTree = "<group>"; };
55FE0E8D1D100A0900FD240B /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = config.xcconfig; path = ../../build/macos/config.xcconfig; sourceTree = "<group>"; };
89462398200D199100DA8EF2 /* heatmap.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = heatmap.json; sourceTree = "<group>"; };
8946239A200E73CA00DA8EF2 /* MGLHeatmapStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLHeatmapStyleLayer.h; sourceTree = "<group>"; };
8946239B200E73CA00DA8EF2 /* MGLHeatmapStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLHeatmapStyleLayer.mm; sourceTree = "<group>"; };
92092EEE1F5EB10E00AF5130 /* MGLMapSnapshotter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapSnapshotter.h; sourceTree = "<group>"; };
92092EEF1F5EB10E00AF5130 /* MGLMapSnapshotter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapSnapshotter.mm; sourceTree = "<group>"; };
920A3E581E6F859D00C16EFC /* MGLSourceQueryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLSourceQueryTests.m; sourceTree = "<group>"; };
@@ -676,6 +686,8 @@
35602BF91D3EA99F0050646F /* MGLFillStyleLayer.mm */,
35602BFD1D3EA9B40050646F /* MGLForegroundStyleLayer.h */,
35602BFE1D3EA9B40050646F /* MGLForegroundStyleLayer.mm */,
8946239A200E73CA00DA8EF2 /* MGLHeatmapStyleLayer.h */,
8946239B200E73CA00DA8EF2 /* MGLHeatmapStyleLayer.mm */,
DAF25714201901C200367EF5 /* MGLHillshadeStyleLayer.h */,
DAF25713201901C100367EF5 /* MGLHillshadeStyleLayer.mm */,
DA8F25891D51CA540010E6B5 /* MGLLineStyleLayer.h */,
@@ -829,6 +841,7 @@
DA839EA61CC2E3400062CAFB /* Info.plist */,
96E027331E57C9A7004B8E66 /* Localizable.strings */,
DA839E981CC2E3400062CAFB /* Supporting Files */,
89462398200D199100DA8EF2 /* heatmap.json */,
);
name = "Demo App";
path = app;
@@ -879,6 +892,8 @@
DA8F257C1D51C5F40010E6B5 /* Layers */ = {
isa = PBXGroup;
children = (
170A82C2201FAFF800943087 /* MGLHeatmapColorTests.mm */,
170A82BE201BDD1B00943087 /* MGLHeatmapStyleLayerTests.mm */,
40E1601A1DF216E6005EA6D9 /* MGLStyleLayerTests.h */,
40E1601B1DF216E6005EA6D9 /* MGLStyleLayerTests.m */,
DA2207BA1DC076930002F84D /* test-Bridging-Header.h */,
@@ -1236,6 +1251,7 @@
359819591E02F611008FC139 /* NSCoder+MGLAdditions.h in Headers */,
DAE6C38E1CC31E2A00DB3429 /* MGLOfflineStorage_Private.h in Headers */,
DA87A9A01DC9DC6200810D09 /* MGLValueEvaluator.h in Headers */,
8946239D200E744800DA8EF2 /* MGLHeatmapStyleLayer.h in Headers */,
DAE6C3601CC31E0400DB3429 /* MGLOfflineRegion.h in Headers */,
DAE6C3681CC31E0400DB3429 /* MGLTilePyramidOfflineRegion.h in Headers */,
DA35A2CF1CCAAED300E826B2 /* NSValue+MGLAdditions.h in Headers */,
@@ -1427,6 +1443,7 @@
DA839EA01CC2E3400062CAFB /* MapDocument.xib in Resources */,
353BAEF81D6463B8009A8DA9 /* amsterdam.geojson in Resources */,
96E027311E57C9A7004B8E66 /* Localizable.strings in Resources */,
89462399200D199100DA8EF2 /* heatmap.json in Resources */,
DA839EA51CC2E3400062CAFB /* MainMenu.xib in Resources */,
DA5589771D320C41006B7F64 /* wms.json in Resources */,
DAE6C2E21CC304F900DB3429 /* Credits.rtf in Resources */,
@@ -1508,6 +1525,7 @@
07D9474B1F6743F000E37934 /* MGLAbstractShapeSource.mm in Sources */,
DAE6C3941CC31E2A00DB3429 /* MGLStyle.mm in Sources */,
DAE6C3871CC31E2A00DB3429 /* MGLGeometry.mm in Sources */,
894623A0200E748000DA8EF2 /* MGLHeatmapStyleLayer.mm in Sources */,
3527428E1D4C24AB00A1ECE6 /* MGLCircleStyleLayer.mm in Sources */,
35602C011D3EA9B40050646F /* MGLForegroundStyleLayer.mm in Sources */,
408AA86A1DAEEE5D00022900 /* NSDictionary+MGLAdditions.mm in Sources */,
@@ -1570,11 +1588,13 @@
DAE6C3D21CC34C9900DB3429 /* MGLGeometryTests.mm in Sources */,
DA87A9A41DCACC5000810D09 /* MGLSymbolStyleLayerTests.mm in Sources */,
40E1601D1DF217D6005EA6D9 /* MGLStyleLayerTests.m in Sources */,
170A82BF201BDD1B00943087 /* MGLHeatmapStyleLayerTests.mm in Sources */,
1F95931B1E6DE2B600D5B294 /* MGLNSDateAdditionsTests.mm in Sources */,
DAF25721201902C100367EF5 /* MGLHillshadeStyleLayerTests.mm in Sources */,
DA87A9A61DCACC5000810D09 /* MGLCircleStyleLayerTests.mm in Sources */,
DA87A99E1DC9DC2100810D09 /* MGLPredicateTests.mm in Sources */,
DD58A4C91D822C6700E1F038 /* MGLExpressionTests.mm in Sources */,
170A82C4201FB6EC00943087 /* MGLHeatmapColorTests.mm in Sources */,
4031ACFC1E9EB3C100A3EA26 /* MGLMapViewDelegateIntegrationTests.swift in Sources */,
4031AD031E9FD6AA00A3EA26 /* MGLSDKTestHelpers.swift in Sources */,
DA87A9A71DCACC5000810D09 /* MGLBackgroundStyleLayerTests.mm in Sources */,

View File

@@ -44,6 +44,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLRasterStyleLayer.h"
#import "MGLCircleStyleLayer.h"
#import "MGLBackgroundStyleLayer.h"
#import "MGLHeatmapStyleLayer.h"
#import "MGLHillshadeStyleLayer.h"
#import "MGLOpenGLStyleLayer.h"
#import "MGLSource.h"

View File

@@ -15,6 +15,7 @@
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/fill_extrusion_layer.hpp>
#include <mbgl/style/layers/heatmap_layer.hpp>
#include <mbgl/style/layers/hillshade_layer.hpp>
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/style/layers/raster_layer.hpp>

View File

@@ -9,6 +9,7 @@
"render-tests/background-color/transition": "https://github.com/mapbox/mapbox-gl-native/issues/10619",
"render-tests/debug/collision": "https://github.com/mapbox/mapbox-gl-native/issues/3841",
"render-tests/debug/collision-lines": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
"render-tests/debug/collision-lines-overscaled": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
"render-tests/debug/collision-lines-pitched": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
"render-tests/debug/collision-pitched-wrapped": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
"render-tests/debug/tile": "https://github.com/mapbox/mapbox-gl-native/issues/3841",
@@ -22,24 +23,6 @@
"render-tests/fill-extrusion-pattern/opacity": "https://github.com/mapbox/mapbox-gl-js/issues/3327",
"render-tests/geojson/inline-linestring-fill": "current behavior is arbitrary",
"render-tests/geojson/inline-polygon-symbol": "behavior needs reconciliation with gl-js",
"render-tests/heatmap-color/default": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-color/expression": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-color/function": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-intensity/default": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-intensity/function": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-intensity/literal": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-opacity/default": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-opacity/function": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-opacity/literal": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-radius/antimeridian": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-radius/data-expression": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-radius/default": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-radius/function": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-radius/literal": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-radius/pitch30": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-weight/default": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-weight/identity-property-function": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/heatmap-weight/literal": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/mixed-zoom/z10-z11": "https://github.com/mapbox/mapbox-gl-native/issues/10397",
"render-tests/raster-masking/overlapping-zoom": "https://github.com/mapbox/mapbox-gl-native/issues/10195",
"render-tests/regressions/mapbox-gl-js#2305": "https://github.com/mapbox/mapbox-gl-native/issues/6927",
@@ -84,6 +67,10 @@
"render-tests/combinations/line-translucent--heatmap-translucent": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/combinations/raster-translucent--heatmap-translucent": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/combinations/symbol-translucent--heatmap-translucent": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
"render-tests/combinations/background-opaque--hillshade-translucent": "https://github.com/mapbox/mapbox-gl-native/pull/10642",
"render-tests/combinations/background-translucent--hillshade-translucent": "https://github.com/mapbox/mapbox-gl-native/pull/10642",
"render-tests/combinations/circle-translucent--hillshade-translucent": "https://github.com/mapbox/mapbox-gl-native/pull/10642",
"render-tests/combinations/fill-extrusion-translucent--hillshade-translucent": "https://github.com/mapbox/mapbox-gl-native/pull/10642",
"render-tests/combinations/background-opaque--fill-extrusion-translucent": "needs investigation",
"render-tests/combinations/background-translucent--fill-extrusion-translucent": "needs investigation",
"render-tests/combinations/circle-translucent--fill-extrusion-translucent": "needs investigation",

View File

@@ -442,10 +442,9 @@ void MapWindow::initializeGL()
void MapWindow::paintGL()
{
m_frameDraws++;
m_map->resize(size(), size() * pixelRatio());
m_map->resize(size());
#if QT_VERSION >= 0x050400
// When we're using QOpenGLWidget, we need to tell Mapbox GL about the framebuffer we're using.
m_map->setFramebufferObject(defaultFramebufferObject());
m_map->setFramebufferObject(defaultFramebufferObject(), size() * pixelRatio());
#endif
m_map->render();
}

View File

@@ -26,6 +26,11 @@ public:
SharedGLContext
};
enum MapMode {
Continuous = 0,
Static
};
enum ConstrainMode {
NoConstrain = 0,
ConstrainHeightOnly,
@@ -40,6 +45,9 @@ public:
GLContextMode contextMode() const;
void setContextMode(GLContextMode);
MapMode mapMode() const;
void setMapMode(MapMode);
ConstrainMode constrainMode() const;
void setConstrainMode(ConstrainMode);
@@ -66,6 +74,7 @@ public:
private:
GLContextMode m_contextMode;
MapMode m_mapMode;
ConstrainMode m_constrainMode;
ViewportMode m_viewportMode;
@@ -191,8 +200,7 @@ public:
void scaleBy(double scale, const QPointF &center = QPointF());
void rotateBy(const QPointF &first, const QPointF &second);
void resize(const QSize &size, const QSize &framebufferSize);
void setFramebufferObject(quint32 fbo);
void resize(const QSize &size);
double metersPerPixelAtLatitude(double latitude, double zoom) const;
QMapbox::ProjectedMeters projectedMetersForCoordinate(const QMapbox::Coordinate &) const;
@@ -226,15 +234,27 @@ public:
void setFilter(const QString &layer, const QVariant &filter);
// When rendering on a different thread,
// should be called on the render thread.
void createRenderer();
void destroyRenderer();
void setFramebufferObject(quint32 fbo, const QSize &size);
public slots:
void render();
void connectionEstablished();
// Commit changes, load all the resources
// and renders the map when completed.
void startStaticRender();
signals:
void needsRendering();
void mapChanged(QMapboxGL::MapChange);
void copyrightsChanged(const QString &copyrightsHtml);
void staticRenderFinished(const QString &error);
private:
Q_DISABLE_COPY(QMapboxGL)

View File

@@ -61,8 +61,12 @@ add_library(qmapboxgl SHARED
platform/qt/src/qmapbox.cpp
platform/qt/src/qmapboxgl.cpp
platform/qt/src/qmapboxgl_p.hpp
platform/qt/src/qmapboxgl_renderer_frontend_p.hpp
platform/qt/src/qmapboxgl_renderer_frontend_p.cpp
platform/qt/src/qmapboxgl_map_observer.cpp
platform/qt/src/qmapboxgl_map_observer.hpp
platform/qt/src/qmapboxgl_map_renderer.cpp
platform/qt/src/qmapboxgl_map_renderer.hpp
platform/qt/src/qmapboxgl_renderer_backend.hpp
platform/qt/src/qmapboxgl_renderer_backend.cpp
platform/default/mbgl/util/default_styles.hpp
)

View File

@@ -1,6 +1,8 @@
#include "qmapboxgl.hpp"
#include "qmapboxgl_p.hpp"
#include "qmapboxgl_renderer_frontend_p.hpp"
#include "qmapboxgl_map_observer.hpp"
#include "qmapboxgl_renderer_observer.hpp"
#include "qt_conversion.hpp"
#include "qt_geojson.hpp"
@@ -43,11 +45,8 @@
#if QT_VERSION >= 0x050000
#include <QGuiApplication>
#include <QWindow>
#include <QOpenGLContext>
#else
#include <QCoreApplication>
#include <QGLContext>
#endif
#include <QDebug>
@@ -65,6 +64,10 @@ using namespace QMapbox;
static_assert(mbgl::underlying_type(QMapboxGLSettings::UniqueGLContext) == mbgl::underlying_type(mbgl::GLContextMode::Unique), "error");
static_assert(mbgl::underlying_type(QMapboxGLSettings::SharedGLContext) == mbgl::underlying_type(mbgl::GLContextMode::Shared), "error");
// mbgl::MapMode
static_assert(mbgl::underlying_type(QMapboxGLSettings::Continuous) == mbgl::underlying_type(mbgl::MapMode::Continuous), "error");
static_assert(mbgl::underlying_type(QMapboxGLSettings::Static) == mbgl::underlying_type(mbgl::MapMode::Static), "error");
// mbgl::ConstrainMode
static_assert(mbgl::underlying_type(QMapboxGLSettings::NoConstrain) == mbgl::underlying_type(mbgl::ConstrainMode::None), "error");
static_assert(mbgl::underlying_type(QMapboxGLSettings::ConstrainHeightOnly) == mbgl::underlying_type(mbgl::ConstrainMode::HeightOnly), "error");
@@ -164,6 +167,27 @@ std::unique_ptr<mbgl::style::Image> toStyleImage(const QString &id, const QImage
\sa contextMode()
*/
/*!
\enum QMapboxGLSettings::MapMode
This enum sets the map rendering mode
\value Continuous The map will render as data arrives from the network and
react immediately to state changes.
This is the default mode and the preferred when the map is intended to be
interactive.
\value Static The map will no longer react to state changes and will only
be rendered when QMapboxGL::startStaticRender is called. After all the
resources are loaded, the QMapboxGL::staticRenderFinished signal is emitted.
This mode is useful for taking a snapshot of the finished rendering result
of the map into a QImage.
\sa mapMode()
*/
/*!
\enum QMapboxGLSettings::ConstrainMode
@@ -200,6 +224,7 @@ std::unique_ptr<mbgl::style::Image> toStyleImage(const QString &id, const QImage
*/
QMapboxGLSettings::QMapboxGLSettings()
: m_contextMode(QMapboxGLSettings::SharedGLContext)
, m_mapMode(QMapboxGLSettings::Continuous)
, m_constrainMode(QMapboxGLSettings::ConstrainHeightOnly)
, m_viewportMode(QMapboxGLSettings::DefaultViewport)
, m_cacheMaximumSize(mbgl::util::DEFAULT_MAX_CACHE_SIZE)
@@ -229,6 +254,31 @@ void QMapboxGLSettings::setContextMode(GLContextMode mode)
m_contextMode = mode;
}
/*!
Returns the map mode. Static mode will emit a signal for
rendering a map only when the map is fully loaded.
Animations like style transitions and labels fading won't
be seen.
The Continuous mode will emit the signal for every new
change on the map and it is usually what you expect for
a interactive map.
By default, it is set to QMapboxGLSettings::Continuous.
*/
QMapboxGLSettings::MapMode QMapboxGLSettings::mapMode() const
{
return m_mapMode;
}
/*!
Sets the map \a mode.
*/
void QMapboxGLSettings::setMapMode(MapMode mode)
{
m_mapMode = mode;
}
/*!
Returns the constrain mode. This is used to limit the map to wrap
around the globe horizontally.
@@ -1048,32 +1098,17 @@ void QMapboxGL::rotateBy(const QPointF &first, const QPointF &second)
}
/*!
Resize the map to \a size and scale to fit at \a framebufferSize. For
high DPI screens, the size will be smaller than the \a framebufferSize.
This fallowing example will double the pixel density of the map for
a given \c size:
\code
map->resize(size / 2, size);
\endcode
Resize the map to \a size_ and scale to fit at the framebuffer. For
high DPI screens, the size will be smaller than the framebuffer.
*/
void QMapboxGL::resize(const QSize& size, const QSize& framebufferSize)
void QMapboxGL::resize(const QSize& size_)
{
if (d_ptr->size == size && d_ptr->fbSize == framebufferSize) return;
auto size = sanitizedSize(size_);
d_ptr->size = size;
d_ptr->fbSize = framebufferSize;
if (d_ptr->mapObj->getSize() == size)
return;
d_ptr->mapObj->setSize(sanitizedSize(size));
}
/*!
If Mapbox GL needs to rebind the default \a fbo, it will use the
ID supplied here.
*/
void QMapboxGL::setFramebufferObject(quint32 fbo) {
d_ptr->fbObject = fbo;
d_ptr->mapObj->setSize(size);
}
/*!
@@ -1467,6 +1502,51 @@ void QMapboxGL::setFilter(const QString& layer, const QVariant& filter)
qWarning() << "Layer doesn't support filters";
}
/*!
Creates the infrastructure needed for rendering the map. It
should be called before any call to render().
Must be called on the render thread.
*/
void QMapboxGL::createRenderer()
{
d_ptr->createRenderer();
}
/*!
Destroys the infrastructure needed for rendering the map,
releasing resources.
Must be called on the render thread.
*/
void QMapboxGL::destroyRenderer()
{
d_ptr->destroyRenderer();
}
/*!
Start a static rendering of the current state of the map. This
should only be called when the map is initialized in static mode.
\sa QMapboxGLSettings::MapMode
*/
void QMapboxGL::startStaticRender()
{
d_ptr->mapObj->renderStill([this](std::exception_ptr err) {
QString what;
try {
if (err) {
std::rethrow_exception(err);
}
} catch(const std::exception& e) {
what = e.what();
}
emit staticRenderFinished(what);
});
}
/*!
Renders the map using OpenGL draw calls. It will make sure to bind the
framebuffer object before drawing; otherwise a valid OpenGL context is
@@ -1475,28 +1555,33 @@ void QMapboxGL::setFilter(const QString& layer, const QVariant& filter)
This function should be called only after the signal needsRendering() is
emitted at least once.
Must be called on the render thread.
*/
void QMapboxGL::render()
{
#if defined(__APPLE__) && QT_VERSION < 0x050000
// FIXME Qt 4.x provides an incomplete FBO at start.
// See https://bugreports.qt.io/browse/QTBUG-36802 for details.
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
return;
}
#endif
d_ptr->dirty = false;
d_ptr->render();
}
/*!
If Mapbox GL needs to rebind the default \a fbo, it will use the
ID supplied here. \a size is the size of the framebuffer, which
on high DPI screens is usually bigger than the map size.
Must be called on the render thread.
*/
void QMapboxGL::setFramebufferObject(quint32 fbo, const QSize& size)
{
d_ptr->setFramebufferObject(fbo, size);
}
/*!
Informs the map that the network connection has been established, causing
all network requests that previously timed out to be retried immediately.
*/
void QMapboxGL::connectionEstablished()
{
d_ptr->connectionEstablished();
mbgl::NetworkStatus::Reachable();
}
/*!
@@ -1509,6 +1594,16 @@ void QMapboxGL::connectionEstablished()
\sa render()
*/
/*!
\fn void QMapboxGL::staticRenderFinished(const QString &error)
This signal is emitted when a static map is fully drawn. Usually the next
step is to extract the map from a framebuffer into a container like a
QImage. \a error is set to a message when an error occurs.
\sa startStaticRender()
*/
/*!
\fn void QMapboxGL::mapChanged(QMapboxGL::MapChange change)
@@ -1526,186 +1621,140 @@ void QMapboxGL::connectionEstablished()
\a copyrightsHtml is a string with a HTML snippet.
*/
class QMapboxGLRendererFrontend;
QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settings, const QSize &size_, qreal pixelRatio)
QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settings, const QSize &size, qreal pixelRatio_)
: QObject(q)
, size(size_)
, q_ptr(q)
, fileSourceObj(sharedDefaultFileSource(
, m_fileSourceObj(sharedDefaultFileSource(
settings.cacheDatabasePath().toStdString(),
settings.assetPath().toStdString(),
settings.cacheDatabaseMaximumSize()))
, threadPool(mbgl::sharedThreadPool())
, m_threadPool(mbgl::sharedThreadPool())
, m_mode(settings.contextMode())
, m_pixelRatio(pixelRatio_)
{
// Setup resource transform if needed
// Setup the FileSource
m_fileSourceObj->setAccessToken(settings.accessToken().toStdString());
m_fileSourceObj->setAPIBaseURL(settings.apiBaseUrl().toStdString());
if (settings.resourceTransform()) {
m_resourceTransform =
std::make_unique< mbgl::Actor<mbgl::ResourceTransform> >( *mbgl::Scheduler::GetCurrent(),
[callback = settings.resourceTransform()]
(mbgl::Resource::Kind , const std::string&& url_) -> std::string {
return callback(std::move(url_));
}
);
fileSourceObj->setResourceTransform(m_resourceTransform->self());
m_resourceTransform = std::make_unique<mbgl::Actor<mbgl::ResourceTransform>>(*mbgl::Scheduler::GetCurrent(),
[callback = settings.resourceTransform()] (mbgl::Resource::Kind, const std::string &&url_) -> std::string {
return callback(std::move(url_));
});
m_fileSourceObj->setResourceTransform(m_resourceTransform->self());
}
// Setup and connect the renderer frontend
frontend = std::make_unique<QMapboxGLRendererFrontend>(
std::make_unique<mbgl::Renderer>(*this, pixelRatio, *fileSourceObj, *threadPool,
static_cast<mbgl::GLContextMode>(settings.contextMode())),
*this);
connect(frontend.get(), SIGNAL(updated()), this, SLOT(invalidate()));
mapObj = std::make_unique<mbgl::Map>(
*frontend,
*this, sanitizedSize(size),
pixelRatio, *fileSourceObj, *threadPool,
mbgl::MapMode::Continuous,
static_cast<mbgl::ConstrainMode>(settings.constrainMode()),
static_cast<mbgl::ViewportMode>(settings.viewportMode()));
// Setup MapObserver
m_mapObserver = std::make_unique<QMapboxGLMapObserver>(this);
qRegisterMetaType<QMapboxGL::MapChange>("QMapboxGL::MapChange");
fileSourceObj->setAccessToken(settings.accessToken().toStdString());
fileSourceObj->setAPIBaseURL(settings.apiBaseUrl().toStdString());
connect(m_mapObserver.get(), SIGNAL(mapChanged(QMapboxGL::MapChange)), q, SIGNAL(mapChanged(QMapboxGL::MapChange)));
connect(m_mapObserver.get(), SIGNAL(copyrightsChanged(QString)), q, SIGNAL(copyrightsChanged(QString)));
connect(this, SIGNAL(needsRendering()), q_ptr, SIGNAL(needsRendering()), Qt::QueuedConnection);
connect(this, SIGNAL(mapChanged(QMapboxGL::MapChange)), q_ptr, SIGNAL(mapChanged(QMapboxGL::MapChange)), Qt::QueuedConnection);
connect(this, SIGNAL(copyrightsChanged(QString)), q_ptr, SIGNAL(copyrightsChanged(QString)), Qt::QueuedConnection);
// Setup the Map object
mapObj = std::make_unique<mbgl::Map>(
*this, // RendererFrontend
*m_mapObserver,
sanitizedSize(size),
m_pixelRatio, *m_fileSourceObj, *m_threadPool,
static_cast<mbgl::MapMode>(settings.mapMode()),
static_cast<mbgl::ConstrainMode>(settings.constrainMode()),
static_cast<mbgl::ViewportMode>(settings.viewportMode()));
// Needs to be Queued to give time to discard redundant draw calls via the `renderQueued` flag.
connect(this, SIGNAL(needsRendering()), q, SIGNAL(needsRendering()), Qt::QueuedConnection);
}
QMapboxGLPrivate::~QMapboxGLPrivate()
{
}
mbgl::Size QMapboxGLPrivate::getFramebufferSize() const {
return sanitizedSize(fbSize);
}
void QMapboxGLPrivate::updateAssumedState() {
assumeFramebufferBinding(fbObject);
#if QT_VERSION >= 0x050600
assumeViewport(0, 0, getFramebufferSize());
#endif
}
void QMapboxGLPrivate::bind() {
setFramebufferBinding(fbObject);
setViewport(0, 0, getFramebufferSize());
}
void QMapboxGLPrivate::invalidate()
void QMapboxGLPrivate::update(std::shared_ptr<mbgl::UpdateParameters> parameters)
{
if (!dirty) {
emit needsRendering();
dirty = true;
std::lock_guard<std::recursive_mutex> lock(m_mapRendererMutex);
if (!m_mapRenderer) {
return;
}
m_mapRenderer->updateParameters(std::move(parameters));
requestRendering();
}
void QMapboxGLPrivate::setObserver(mbgl::RendererObserver &observer)
{
m_rendererObserver = std::make_shared<QMapboxGLRendererObserver>(
*mbgl::util::RunLoop::Get(), observer);
std::lock_guard<std::recursive_mutex> lock(m_mapRendererMutex);
if (m_mapRenderer) {
m_mapRenderer->setObserver(m_rendererObserver);
}
}
void QMapboxGLPrivate::createRenderer()
{
std::lock_guard<std::recursive_mutex> lock(m_mapRendererMutex);
if (m_mapRenderer) {
return;
}
m_mapRenderer = std::make_unique<QMapboxGLMapRenderer>(
m_pixelRatio,
*m_fileSourceObj,
*m_threadPool,
m_mode
);
connect(m_mapRenderer.get(), SIGNAL(needsRendering()), this, SLOT(requestRendering()));
m_mapRenderer->setObserver(m_rendererObserver);
}
void QMapboxGLPrivate::destroyRenderer()
{
std::lock_guard<std::recursive_mutex> lock(m_mapRendererMutex);
m_mapRenderer.reset();
}
void QMapboxGLPrivate::render()
{
frontend->render();
}
std::lock_guard<std::recursive_mutex> lock(m_mapRendererMutex);
void QMapboxGLPrivate::onCameraWillChange(mbgl::MapObserver::CameraChangeMode mode)
{
if (mode == mbgl::MapObserver::CameraChangeMode::Immediate) {
emit mapChanged(QMapboxGL::MapChangeRegionWillChange);
} else {
emit mapChanged(QMapboxGL::MapChangeRegionWillChangeAnimated);
if (!m_mapRenderer) {
createRenderer();
}
}
void QMapboxGLPrivate::onCameraIsChanging()
{
emit mapChanged(QMapboxGL::MapChangeRegionIsChanging);
}
void QMapboxGLPrivate::onCameraDidChange(mbgl::MapObserver::CameraChangeMode mode)
{
if (mode == mbgl::MapObserver::CameraChangeMode::Immediate) {
emit mapChanged(QMapboxGL::MapChangeRegionDidChange);
} else {
emit mapChanged(QMapboxGL::MapChangeRegionDidChangeAnimated);
#if defined(__APPLE__) && QT_VERSION < 0x050000
// FIXME Qt 4.x provides an incomplete FBO at start.
// See https://bugreports.qt.io/browse/QTBUG-36802 for details.
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
return;
}
}
void QMapboxGLPrivate::onWillStartLoadingMap()
{
emit mapChanged(QMapboxGL::MapChangeWillStartLoadingMap);
}
void QMapboxGLPrivate::onDidFinishLoadingMap()
{
emit mapChanged(QMapboxGL::MapChangeDidFinishLoadingMap);
}
void QMapboxGLPrivate::onDidFailLoadingMap(std::exception_ptr)
{
emit mapChanged(QMapboxGL::MapChangeDidFailLoadingMap);
}
void QMapboxGLPrivate::onWillStartRenderingFrame()
{
emit mapChanged(QMapboxGL::MapChangeWillStartRenderingFrame);
}
void QMapboxGLPrivate::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode)
{
if (mode == mbgl::MapObserver::RenderMode::Partial) {
emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingFrame);
} else {
emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingFrameFullyRendered);
}
}
void QMapboxGLPrivate::onWillStartRenderingMap()
{
emit mapChanged(QMapboxGL::MapChangeWillStartLoadingMap);
}
void QMapboxGLPrivate::onDidFinishRenderingMap(mbgl::MapObserver::RenderMode mode)
{
if (mode == mbgl::MapObserver::RenderMode::Partial) {
emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingMap);
} else {
emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingMapFullyRendered);
}
}
void QMapboxGLPrivate::onDidFinishLoadingStyle()
{
emit mapChanged(QMapboxGL::MapChangeDidFinishLoadingStyle);
}
void QMapboxGLPrivate::onSourceChanged(mbgl::style::Source&)
{
std::string attribution;
for (const auto& source : mapObj->getStyle().getSources()) {
// Avoid duplicates by using the most complete attribution HTML snippet.
if (source->getAttribution() && (attribution.size() < source->getAttribution()->size()))
attribution = *source->getAttribution();
}
emit copyrightsChanged(QString::fromStdString(attribution));
emit mapChanged(QMapboxGL::MapChangeSourceDidChange);
}
/*!
Initializes an OpenGL extension function such as Vertex Array Objects (VAOs),
required by Mapbox GL Native engine.
*/
mbgl::gl::ProcAddress QMapboxGLPrivate::getExtensionFunctionPointer(const char* name) {
#if QT_VERSION >= 0x050000
QOpenGLContext* thisContext = QOpenGLContext::currentContext();
return thisContext->getProcAddress(name);
#else
const QGLContext* thisContext = QGLContext::currentContext();
return reinterpret_cast<mbgl::gl::ProcAddress>(thisContext->getProcAddress(name));
#endif
m_renderQueued.clear();
m_mapRenderer->render();
}
void QMapboxGLPrivate::connectionEstablished()
void QMapboxGLPrivate::setFramebufferObject(quint32 fbo, const QSize& size)
{
mbgl::NetworkStatus::Reachable();
std::lock_guard<std::recursive_mutex> lock(m_mapRendererMutex);
if (!m_mapRenderer) {
createRenderer();
}
m_mapRenderer->updateFramebuffer(fbo, sanitizedSize(size));
}
void QMapboxGLPrivate::requestRendering()
{
if (!m_renderQueued.test_and_set()) {
emit needsRendering();
}
}

View File

@@ -0,0 +1,95 @@
#include "qmapboxgl_map_observer.hpp"
#include "qmapboxgl_p.hpp"
QMapboxGLMapObserver::QMapboxGLMapObserver(QMapboxGLPrivate *d)
: d_ptr(d)
{
}
QMapboxGLMapObserver::~QMapboxGLMapObserver()
{
}
void QMapboxGLMapObserver::onCameraWillChange(mbgl::MapObserver::CameraChangeMode mode)
{
if (mode == mbgl::MapObserver::CameraChangeMode::Immediate) {
emit mapChanged(QMapboxGL::MapChangeRegionWillChange);
} else {
emit mapChanged(QMapboxGL::MapChangeRegionWillChangeAnimated);
}
}
void QMapboxGLMapObserver::onCameraIsChanging()
{
emit mapChanged(QMapboxGL::MapChangeRegionIsChanging);
}
void QMapboxGLMapObserver::onCameraDidChange(mbgl::MapObserver::CameraChangeMode mode)
{
if (mode == mbgl::MapObserver::CameraChangeMode::Immediate) {
emit mapChanged(QMapboxGL::MapChangeRegionDidChange);
} else {
emit mapChanged(QMapboxGL::MapChangeRegionDidChangeAnimated);
}
}
void QMapboxGLMapObserver::onWillStartLoadingMap()
{
emit mapChanged(QMapboxGL::MapChangeWillStartLoadingMap);
}
void QMapboxGLMapObserver::onDidFinishLoadingMap()
{
emit mapChanged(QMapboxGL::MapChangeDidFinishLoadingMap);
}
void QMapboxGLMapObserver::onDidFailLoadingMap(std::exception_ptr)
{
emit mapChanged(QMapboxGL::MapChangeDidFailLoadingMap);
}
void QMapboxGLMapObserver::onWillStartRenderingFrame()
{
emit mapChanged(QMapboxGL::MapChangeWillStartRenderingFrame);
}
void QMapboxGLMapObserver::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode)
{
if (mode == mbgl::MapObserver::RenderMode::Partial) {
emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingFrame);
} else {
emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingFrameFullyRendered);
}
}
void QMapboxGLMapObserver::onWillStartRenderingMap()
{
emit mapChanged(QMapboxGL::MapChangeWillStartLoadingMap);
}
void QMapboxGLMapObserver::onDidFinishRenderingMap(mbgl::MapObserver::RenderMode mode)
{
if (mode == mbgl::MapObserver::RenderMode::Partial) {
emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingMap);
} else {
emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingMapFullyRendered);
}
}
void QMapboxGLMapObserver::onDidFinishLoadingStyle()
{
emit mapChanged(QMapboxGL::MapChangeDidFinishLoadingStyle);
}
void QMapboxGLMapObserver::onSourceChanged(mbgl::style::Source&)
{
std::string attribution;
for (const auto& source : d_ptr->mapObj->getStyle().getSources()) {
// Avoid duplicates by using the most complete attribution HTML snippet.
if (source->getAttribution() && (attribution.size() < source->getAttribution()->size()))
attribution = *source->getAttribution();
}
emit copyrightsChanged(QString::fromStdString(attribution));
emit mapChanged(QMapboxGL::MapChangeSourceDidChange);
}

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