diff options
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions')
14 files changed, 1179 insertions, 0 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java new file mode 100644 index 0000000000..bb87fe8a39 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java @@ -0,0 +1,50 @@ +package com.mapbox.mapboxsdk.style.functions; + +import android.support.annotation.Keep; +import android.support.annotation.NonNull; + +import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops; +import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops; +import com.mapbox.mapboxsdk.style.functions.stops.Stop; +import com.mapbox.mapboxsdk.style.functions.stops.Stops; + +/** + * Camera function. Functions that take camera properties as input (zoom for now) + * <p> + * Zoom functions allow the appearance of a map feature to change with map’s zoom level. + * Zoom functions can be used to create the illusion of depth and control data density. + * Each stop is an array with two elements: the first is a zoom level and the second is + * a function output value. + * + * @param <I> the input type + * @param <O> the output type + * @see Function#zoom + */ +public class CameraFunction<I extends Number, O> extends Function<I, O> { + + /** + * Create an exponential camera function + * + * @param stops @see {@link com.mapbox.mapboxsdk.style.functions.stops.Stops#exponential(float, Stop[])} + */ + CameraFunction(@NonNull ExponentialStops<I, O> stops) { + super(stops); + } + + /** + * Create an interval camera function + * + * @param stops @see {@link com.mapbox.mapboxsdk.style.functions.stops.Stops#interval(Stop[])} + */ + CameraFunction(@NonNull IntervalStops<I, O> stops) { + super(stops); + } + + /** + * JNI constructor + */ + @Keep + private CameraFunction(Stops<I, O> stops) { + super(stops); + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java new file mode 100644 index 0000000000..1ed43580c4 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java @@ -0,0 +1,86 @@ +package com.mapbox.mapboxsdk.style.functions; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.mapbox.mapboxsdk.style.functions.stops.CompositeStops; +import com.mapbox.mapboxsdk.style.functions.stops.Stops; + +import java.util.Map; + +/** + * Composite functions combine {@link android.graphics.Camera} and {@link SourceFunction}s. + * <p> + * Composite functions allow the appearance of a map feature to change with both its + * properties and zoom. Each stop is an array with two elements, the first is an object + * with a property input value and a zoom, and the second is a function output value. Note + * that support for property functions is not yet complete. + * + * @param <Z> the zoom type (usually Float) + * @param <I> the input type (the feature property type) + * @param <O> the output type (the property type) + * @see Function#composite + */ +public class CompositeFunction<Z extends Number, I, O> extends Function<I, O> { + + private final String property; + private O defaultValue; + + CompositeFunction(@NonNull String property, + @NonNull CompositeStops<Z, I, O, ? extends Stops<I, O>> stops) { + this(null, property, stops); + } + + + /** + * JNI Constructor + */ + private CompositeFunction(@Nullable O defaultValue, @NonNull String property, + @NonNull CompositeStops<Z, I, O, ? extends Stops<I, O>> stops) { + super(stops); + this.defaultValue = defaultValue; + this.property = property; + } + + /** + * Set the default value + * + * @param defaultValue the default value to use when no other applies + * @return this (for chaining) + */ + public CompositeFunction<Z, I, O> withDefaultValue(O defaultValue) { + this.defaultValue = defaultValue; + return this; + } + + /** + * @return the defaultValue + */ + @Nullable + public O getDefaultValue() { + return defaultValue; + } + + /** + * INTERNAL USAGE ONLY + * + * @return the feature property name + */ + public String getProperty() { + return property; + } + + /** + * {@inheritDoc} + */ + @Override + public Map<String, Object> toValueObject() { + Map<String, Object> valueObject = super.toValueObject(); + valueObject.put(PROPERTY_KEY, property); + if (defaultValue != null) { + valueObject.put(DEFAULT_VALUE_KEY, defaultValue); + } + return valueObject; + } + +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java new file mode 100644 index 0000000000..8c5186b994 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java @@ -0,0 +1,301 @@ +package com.mapbox.mapboxsdk.style.functions; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.mapbox.mapboxsdk.style.functions.stops.CategoricalStops; +import com.mapbox.mapboxsdk.style.functions.stops.CompositeStops; +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 java.util.Map; + +import timber.log.Timber; + +/** + * Functions are used to change properties in relation to the state of the map. + * <p> + * The value for any layout or paint property may be specified as a function. Functions allow you to + * make the appearance of a map feature change with the current zoom level and/or the feature's properties. + * + * @param <I> the function's input type + * @param <O> the target property's value type. Make sure it matches. + * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a> + */ +public class Function<I, O> { + + static final String PROPERTY_KEY = "property"; + static final String DEFAULT_VALUE_KEY = "defaultValue"; + + /** + * Create an exponential {@link CameraFunction} + * <p> + * Zoom functions allow the appearance of a map feature to change with map’s zoom. + * Zoom functions can be used to create the illusion of depth and control data density. + * Each stop is an array with two elements, the first is a zoom and the second is a function output value. + * + * @param <Z> the zoom level type (Float, Integer) + * @param <O> the property type + * @param stops the stops implementation that define the function. @see {@link Stops#exponential(Stop[])} + * @return the {@link CameraFunction} + * @see CameraFunction + * @see ExponentialStops + * @see Stops#exponential(Stop[]) + * @see Stops#exponential(Stop[]) + * @see Stop#stop + */ + public static <Z extends Number, O> CameraFunction<Z, O> zoom(@NonNull ExponentialStops<Z, O> stops) { + return new CameraFunction<>(stops); + } + + /** + * Create an interval {@link CameraFunction} + * <p> + * Zoom functions allow the appearance of a map feature to change with map’s zoom. + * Zoom functions can be used to create the illusion of depth and control data density. + * Each stop is an array with two elements, the first is a zoom and the second is a function output value. + * + * @param <Z> the zoom level type (Float, Integer) + * @param <O> the property type + * @param stops the stops implementation that define the function. @see {@link Stops#interval(Stop[])} + * @return the {@link CameraFunction} + * @see CameraFunction + * @see IntervalStops + * @see Stops#interval(Stop[]) + * @see Stop#stop + */ + public static <Z extends Number, O> CameraFunction<Z, O> zoom(@NonNull IntervalStops<Z, O> stops) { + return new CameraFunction<>(stops); + } + + /** + * Create an exponential {@link SourceFunction} + * <p> + * Source functions allow the appearance of a map feature to change with + * its properties. Source functions can be used to visually differentiate + * types of features within the same layer or create data visualizations. + * Each stop is an array with two elements, the first is a property input + * value and the second is a function output value. Note that support for + * property functions is not available across all properties and platforms + * at this time. + * + * @param property the feature property name + * @param stops the stops + * @param <I> the function input type + * @param <O> the function output type + * @return the {@link SourceFunction} + * @see SourceFunction + * @see ExponentialStops + * @see Stops#exponential(Stop[]) + * @see Stop#stop + */ + public static <I, O> SourceFunction<I, O> property(@NonNull String property, @NonNull ExponentialStops<I, O> stops) { + return new SourceFunction<>(property, stops); + } + + /** + * Create an identity {@link SourceFunction} + * <p> + * Source functions allow the appearance of a map feature to change with + * its properties. Source functions can be used to visually differentiate + * types of features within the same layer or create data visualizations. + * Each stop is an array with two elements, the first is a property input + * value and the second is a function output value. Note that support for + * property functions is not available across all properties and platforms + * at this time. + * + * @param property the feature property name + * @param stops the stops + * @param <T> the function input/output type + * @return the {@link SourceFunction} + * @see SourceFunction + * @see IdentityStops + * @see Stops#identity() + * @see Stop#stop + */ + public static <T> SourceFunction<T, T> property(@NonNull String property, @NonNull IdentityStops<T> stops) { + return new SourceFunction<>(property, stops); + } + + /** + * Create an interval {@link SourceFunction} + * <p> + * Source functions allow the appearance of a map feature to change with + * its properties. Source functions can be used to visually differentiate + * types of features within the same layer or create data visualizations. + * Each stop is an array with two elements, the first is a property input + * value and the second is a function output value. Note that support for + * property functions is not available across all properties and platforms + * at this time. + * + * @param property the feature property name + * @param stops the stops + * @param <I> the function input type + * @param <O> the function output type + * @return the {@link SourceFunction} + * @see SourceFunction + * @see IntervalStops + * @see Stops#interval(Stop[]) + * @see Stop#stop + */ + public static <I, O> SourceFunction<I, O> property(@NonNull String property, @NonNull IntervalStops<I, O> stops) { + return new SourceFunction<>(property, stops); + } + + /** + * Create an categorical {@link SourceFunction} + * <p> + * Source functions allow the appearance of a map feature to change with + * its properties. Source functions can be used to visually differentiate + * types of features within the same layer or create data visualizations. + * Each stop is an array with two elements, the first is a property input + * value and the second is a function output value. Note that support for + * property functions is not available across all properties and platforms + * at this time. + * + * @param property the feature property name + * @param stops the stops + * @param <I> the function input type + * @param <O> the function output type + * @return the {@link SourceFunction} + * @see SourceFunction + * @see CategoricalStops + * @see Stops#categorical(Stop[]) + * @see Stop#stop + */ + public static <I, O> SourceFunction<I, O> property(@NonNull String property, @NonNull CategoricalStops<I, O> stops) { + return new SourceFunction<>(property, stops); + } + + /** + * Create a composite, categorical function. + * <p> + * Composite functions allow the appearance of a map feature to change with both its + * properties and zoom. Each stop is an array with two elements, the first is an object + * with a property input value and a zoom, and the second is a function output value. Note + * that support for property functions is not yet complete. + * + * @param property the feature property name for the source part of the function + * @param stops the stops + * @param <Z> the zoom function input type (Float usually) + * @param <I> the function input type for the source part of the function + * @param <O> the function output type + * @return the {@link CompositeFunction} + * @see CompositeFunction + * @see CategoricalStops + * @see Stops#categorical(Stop[]) + * @see Stop#stop + */ + public static <Z extends Number, I, O> CompositeFunction<Z, I, O> composite( + @NonNull String property, + @NonNull CategoricalStops<Stop.CompositeValue<Z, I>, O> stops) { + + return new CompositeFunction<>(property, new CompositeStops<>(stops)); + } + + /** + * Create a composite, exponential function. + * <p> + * Composite functions allow the appearance of a map feature to change with both its + * properties and zoom. Each stop is an array with two elements, the first is an object + * with a property input value and a zoom, and the second is a function output value. Note + * that support for property functions is not yet complete. + * + * @param property the feature property name for the source part of the function + * @param stops the stops + * @param <Z> the zoom function input type (Float usually) + * @param <I> the function input type for the source part of the function + * @param <O> the function output type + * @return the {@link CompositeFunction} + * @see CompositeFunction + * @see ExponentialStops + * @see Stops#exponential(Stop[]) + * @see Stop#stop + */ + public static <Z extends Number, I, O> CompositeFunction<Z, I, O> composite( + @NonNull String property, + @NonNull ExponentialStops<Stop.CompositeValue<Z, I>, O> stops) { + + return new CompositeFunction<>(property, new CompositeStops<>(stops)); + } + + /** + * Create a composite, interval function. + * <p> + * Composite functions allow the appearance of a map feature to change with both its + * properties and zoom. Each stop is an array with two elements, the first is an object + * with a property input value and a zoom, and the second is a function output value. Note + * that support for property functions is not yet complete. + * + * @param property the feature property name for the source part of the function + * @param stops the stops + * @param <Z> the zoom function input type (Float usually) + * @param <I> the function input type for the source part of the function + * @param <O> the function output type + * @return the {@link CompositeFunction} + * @see CompositeFunction + * @see IntervalStops + * @see Stops#interval(Stop[]) + * @see Stop#stop + */ + public static <Z extends Number, I, O> CompositeFunction<Z, I, O> composite( + @NonNull String property, + @NonNull IntervalStops<Stop.CompositeValue<Z, I>, O> stops) { + + return new CompositeFunction<>(property, new CompositeStops<>(stops)); + } + + // Class definition // + + private final Stops<I, O> stops; + + /** + * JNI Cosntructor for implementation classes + * + * @param stops the stops + */ + Function(@NonNull Stops stops) { + this.stops = stops; + } + + /** + * @return the stops in this function + */ + public Stops getStops() { + return stops; + } + + /** + * Convenience method + * + * @param <S> the Stops implementation type + * @return the Stops implementation or null when the wrong type is specified + */ + @Nullable + public <S extends Stops> S getStopsAs() { + try { + // noinspection unchecked + return (S) stops; + } catch (ClassCastException exception) { + Timber.e(String.format("Stops: %s is a different type: %s", stops.getClass(), exception)); + return null; + } + } + + /** + * INTERNAL USAGE ONLY + * + * @return a value object representation for core conversion + */ + public Map<String, Object> toValueObject() { + return stops.toValueObject(); + } + + @Override + public String toString() { + return String.format("%s: %s", getClass().getSimpleName(), stops); + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java new file mode 100644 index 0000000000..f0eed760a4 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java @@ -0,0 +1,84 @@ +package com.mapbox.mapboxsdk.style.functions; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.mapbox.mapboxsdk.style.functions.stops.Stops; + +import java.util.Map; + +/** + * Source functions take Feature property names as input. + * <p> + * Source functions allow the appearance of a map feature to change with + * its properties. Source functions can be used to visually differentiate + * types of features within the same layer or create data visualizations. + * Each stop is an array with two elements, the first is a property input + * value and the second is a function output value. Note that support for + * property functions is not available across all properties and platforms + * at this time. + * + * @param <I> the input type + * @param <O> the output type + * @see Function#property + */ +public class SourceFunction<I, O> extends Function<I, O> { + + private final String property; + private O defaultValue; + + SourceFunction(@NonNull String property, @NonNull Stops<I, O> stops) { + this(null, property, stops); + } + + /** + * JNI Constructor + */ + private SourceFunction(@Nullable O defaultValue, @NonNull String property, @NonNull Stops<I, O> stops) { + super(stops); + this.property = property; + this.defaultValue = defaultValue; + } + + + /** + * INTERNAL USAGE ONLY + * + * @return The feature property name + */ + public String getProperty() { + return property; + } + + /** + * Set the default value + * + * @param defaultValue the default value to use when no other applies + * @return this (for chaining) + */ + public SourceFunction<I, O> withDefaultValue(O defaultValue) { + this.defaultValue = defaultValue; + return this; + } + + /** + * @return the defaultValue + */ + @Nullable + public O getDefaultValue() { + return defaultValue; + } + + /** + * {@inheritDoc} + */ + @Override + public Map<String, Object> toValueObject() { + Map<String, Object> valueObject = super.toValueObject(); + valueObject.put(PROPERTY_KEY, property); + if (defaultValue != null) { + valueObject.put(DEFAULT_VALUE_KEY, defaultValue); + } + return valueObject; + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/package-info.java new file mode 100644 index 0000000000..6979676c9e --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/package-info.java @@ -0,0 +1,6 @@ +/** + * Contains the Mapbox Maps Android Style Function API classes. + * + * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a> + */ +package com.mapbox.mapboxsdk.style.functions; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CategoricalStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CategoricalStops.java new file mode 100644 index 0000000000..f9b2929350 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CategoricalStops.java @@ -0,0 +1,64 @@ +package com.mapbox.mapboxsdk.style.functions.stops; + +import android.support.annotation.NonNull; +import android.support.annotation.Size; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; + +/** + * {@link Stops} implementation for categorical functions + * + * @param <I> the {@link Stop} input type + * @param <O> the {@link Stop} output type + */ +public class CategoricalStops<I, O> extends IterableStops<I, O, Stop<I, O>> { + + private final Stop<I, O>[] stops; + + /** + * Create a categorical {@link Stops} implementation. Use through {@link Stops#categorical(Stop[])} + * + * @param stops the stops + */ + @SafeVarargs + public CategoricalStops(@NonNull @Size(min = 1) Stop<I, O>... stops) { + this.stops = stops; + } + + /** + * {@inheritDoc} + */ + @Override + public Map<String, Object> toValueObject() { + Map<String, Object> map = super.toValueObject(); + map.put("stops", toValueObjects(stops)); + return map; + } + + /** + * {@inheritDoc} + */ + @Override + public String getTypeName() { + return "categorical"; + } + + /** + * {@inheritDoc} + */ + @Override + public Iterator<Stop<I, O>> iterator() { + return Arrays.asList(stops).iterator(); + } + + /** + * {@inheritDoc} + */ + @Override + public int size() { + return stops.length; + } + +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CompositeStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CompositeStops.java new file mode 100644 index 0000000000..7e2ce94fe1 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CompositeStops.java @@ -0,0 +1,151 @@ +package com.mapbox.mapboxsdk.style.functions.stops; + +import android.support.annotation.Keep; +import android.support.annotation.NonNull; +import android.support.annotation.Size; + +import com.mapbox.mapboxsdk.style.functions.stops.Stop.CompositeValue; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * The {@link Stops} implementation for composite functions + * + * @param <Z> the zoom type (usually Float) + * @param <I> the input type (the feature property type) + * @param <O> the output type (the property type) + * @param <S> the {@link Stops} implementation (eg CategoricalStops, {@link ExponentialStops} or {@link IntervalStops}) + */ +public class CompositeStops<Z extends Number, I, O, S extends IterableStops<I, O, Stop<I, O>>> + extends IterableStops<CompositeValue<Z, I>, O, Map.Entry<Z, S>> { + + private final Map<Z, S> stops; + + /** + * JNI Constructor + * + * @param stops the stops {@link Map} + */ + @Keep + private CompositeStops(@NonNull @Size(min = 1) Map<Z, S> stops) { + this.stops = stops; + } + + /** + * Create composite stops for {@link ExponentialStops}. Use + * {@link com.mapbox.mapboxsdk.style.functions.Function#composite(String, ExponentialStops)} + * + * @param stops the stops + */ + public CompositeStops(@NonNull ExponentialStops<Stop.CompositeValue<Z, I>, O> stops) { + this.stops = new HashMap<>(); + + for (Map.Entry<Z, List<Stop<I, O>>> entry : collect(stops).entrySet()) { + // noinspection unchecked + this.stops.put(entry.getKey(), + (S) new ExponentialStops<>(stops.getBase(), entry.getValue().toArray(new Stop[0]))); + } + } + + /** + * Create composite stops for {@link IntervalStops}. + * Use {@link com.mapbox.mapboxsdk.style.functions.Function#composite(String, IntervalStops)} + * + * @param stops the stops + */ + public CompositeStops(@NonNull IntervalStops<Stop.CompositeValue<Z, I>, O> stops) { + this.stops = new HashMap<>(); + + for (Map.Entry<Z, List<Stop<I, O>>> entry : collect(stops).entrySet()) { + // noinspection unchecked + this.stops.put(entry.getKey(), (S) new IntervalStops<>(entry.getValue().toArray(new Stop[0]))); + } + } + + /** + * Create composite stops for {@link CategoricalStops}. + * Use {@link com.mapbox.mapboxsdk.style.functions.Function#composite(String, CategoricalStops)} + * + * @param stops the stops + */ + public CompositeStops(@NonNull CategoricalStops<CompositeValue<Z, I>, O> stops) { + this.stops = new HashMap<>(); + + for (Map.Entry<Z, List<Stop<I, O>>> entry : collect(stops).entrySet()) { + // noinspection unchecked + this.stops.put(entry.getKey(), (S) new CategoricalStops<>(entry.getValue().toArray(new Stop[0]))); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected String getTypeName() { + return stops.values().iterator().next().getTypeName(); + } + + /** + * {@inheritDoc} + */ + @Override + public Map<String, Object> toValueObject() { + Map<String, Object> map = super.toValueObject(); + + // Flatten and toValueObjects stops + // noinspection unchecked + map.put("stops", toValueObjects(flatten(this.stops).toArray(new Stop[0]))); + + return map; + } + + @NonNull + private List<Stop<CompositeValue<Z, I>, O>> flatten(Map<Z, S> stops) { + List<Stop<CompositeValue<Z, I>, O>> flattenedStops = new ArrayList<>(); + for (Map.Entry<Z, S> entry : stops.entrySet()) { + for (Stop<I, O> stop : entry.getValue()) { + flattenedStops.add(new Stop<>(new CompositeValue<>(entry.getKey(), stop.in), stop.out)); + } + } + return flattenedStops; + } + + @NonNull + private Map<Z, List<Stop<I, O>>> collect( + @NonNull IterableStops<CompositeValue<Z, I>, O, Stop<CompositeValue<Z, I>, O>> stops) { + Map<Z, List<Stop<I, O>>> converted = new HashMap<>(); + + for (Stop<CompositeValue<Z, I>, O> stop : stops) { + List<Stop<I, O>> stopsForZ = converted.get(stop.in.zoom); + if (stopsForZ == null) { + stopsForZ = new ArrayList<>(); + converted.put(stop.in.zoom, stopsForZ); + } + + stopsForZ.add(new Stop<>(stop.in.value, stop.out)); + } + + return converted; + } + + /** + * {@inheritDoc} + */ + @Override + public Iterator<Map.Entry<Z, S>> iterator() { + return stops.entrySet().iterator(); + } + + /** + * {@inheritDoc} + */ + @Override + public int size() { + return stops.size(); + } + +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/ExponentialStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/ExponentialStops.java new file mode 100644 index 0000000000..d47aa1fc91 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/ExponentialStops.java @@ -0,0 +1,97 @@ +package com.mapbox.mapboxsdk.style.functions.stops; + +import android.support.annotation.NonNull; +import android.support.annotation.Size; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; + +/** + * The {@link Stops} implementation for exponential functions + * + * @param <I> the input type + * @param <O> the output type + */ +public class ExponentialStops<I, O> extends IterableStops<I, O, Stop<I, O>> { + + private float base; + private final Stop<I, O>[] stops; + + /** + * Create exponential stops with an explicit base. Use through {@link Stops#exponential(Stop[])} + * + * @param base The exponential base of the interpolation curve. It controls the rate at which the function output + * increases. Higher values make the output increase more towards the high end of the range. + * With values close to 1 the output increases linearly. + * @param stops the stops + */ + @SafeVarargs + public ExponentialStops(Float base, @NonNull @Size(min = 1) Stop<I, O>... stops) { + this.base = base != null ? base : 1.0f; + this.stops = stops; + } + + /** + * Create exponential stops without an explicit base. Use through {@link Stops#exponential(Stop[])} + * + * @param stops the stops + */ + @SafeVarargs + public ExponentialStops(@NonNull @Size(min = 1) Stop<I, O>... stops) { + this(null, stops); + } + + /** + * Set the exponential base + * + * @param base the base to use in the exponential function + * @return this (for chaining) + */ + public ExponentialStops<I, O> withBase(float base) { + this.base = base; + return this; + } + + /** + * @return The exponential base + */ + public float getBase() { + return base; + } + + /** + * {@inheritDoc} + */ + @Override + public Map<String, Object> toValueObject() { + Map<String, Object> map = super.toValueObject(); + map.put("base", base); + map.put("stops", toValueObjects(stops)); + return map; + } + + /** + * {@inheritDoc} + */ + @Override + public String getTypeName() { + return "exponential"; + } + + /** + * {@inheritDoc} + */ + @Override + public Iterator<Stop<I, O>> iterator() { + return Arrays.asList(stops).iterator(); + } + + /** + * {@inheritDoc} + */ + @Override + public int size() { + return stops.length; + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IdentityStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IdentityStops.java new file mode 100644 index 0000000000..2c0b198dc2 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IdentityStops.java @@ -0,0 +1,18 @@ +package com.mapbox.mapboxsdk.style.functions.stops; + +/** + * The {@link Stops} implementation for identity functions + * + * @param <T> the input/output type + */ +public class IdentityStops<T> extends Stops<T, T> { + + /** + * {@inheritDoc} + */ + @Override + protected String getTypeName() { + return "identity"; + } + +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IntervalStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IntervalStops.java new file mode 100644 index 0000000000..9d95b3f8c1 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IntervalStops.java @@ -0,0 +1,58 @@ +package com.mapbox.mapboxsdk.style.functions.stops; + +import android.support.annotation.NonNull; +import android.support.annotation.Size; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; + +/** + * The {@link Stops} implementation for interval functions + * + * @param <I> the input type + * @param <O> the output type + */ +public class IntervalStops<I, O> extends IterableStops<I, O, Stop<I, O>> { + + private final Stop<I, O>[] stops; + + @SafeVarargs + public IntervalStops(@NonNull @Size(min = 1) Stop<I, O>... stops) { + this.stops = stops; + } + + /** + * {@inheritDoc} + */ + @Override + public String getTypeName() { + return "interval"; + } + + /** + * {@inheritDoc} + */ + @Override + public Map<String, Object> toValueObject() { + Map<String, Object> map = super.toValueObject(); + map.put("stops", toValueObjects(stops)); + return map; + } + + /** + * @return an {@link Iterator} for the contained stops + */ + @Override + public Iterator<Stop<I, O>> iterator() { + return Arrays.asList(stops).iterator(); + } + + /** + * @return The number of contained stops + */ + @Override + public int size() { + return stops.length; + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IterableStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IterableStops.java new file mode 100644 index 0000000000..8c5a6e8913 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IterableStops.java @@ -0,0 +1,52 @@ +package com.mapbox.mapboxsdk.style.functions.stops; + +import java.util.Iterator; + +/** + * Base class for {@link Stops} implementations with a collection of stops + * + * @param <I> the {@link Stops} input type + * @param <O> the {@link Stops} output type + * @param <S> the {@link Iterable} element type (usually {@link Stop}) + */ +public abstract class IterableStops<I, O, S> extends Stops<I, O> implements Iterable<S> { + + /** + * @return The size of the contained stops collection + */ + public abstract int size(); + + /** + * Convenience function to toValueObjects an array of stops to an array of value objects + * + * @param stops the stops to toValueObjects + * @return the stops as value objects + */ + Object[] toValueObjects(Stop<I, O>[] stops) { + if (stops != null) { + Object[] stopsValue = new Object[stops.length]; + + for (int i = 0; i < stopsValue.length; i++) { + Stop stop = stops[i]; + stopsValue[i] = stop.toValueObject(); + } + return stopsValue; + } + + return null; + } + + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(); + Iterator<S> iterator = iterator(); + while (iterator.hasNext()) { + S stop = iterator.next(); + buffer.append(stop); + if (iterator.hasNext()) { + buffer.append(","); + } + } + return String.format("%s: [%s]", super.toString(), buffer.toString()); + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stop.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stop.java new file mode 100644 index 0000000000..80825ccf6d --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stop.java @@ -0,0 +1,109 @@ +package com.mapbox.mapboxsdk.style.functions.stops; + +import com.mapbox.mapboxsdk.style.functions.Function; +import com.mapbox.mapboxsdk.style.layers.PropertyValue; + +import java.util.HashMap; +import java.util.Map; + +/** + * A stop represents a certain point in the range of this function + * + * @param <I> input the stop (function) input type + * @param <O> output the stop (function) output type + * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a> + */ +public class Stop<I, O> { + /** + * Creates a {@link Stop} to use in a {@link Function} + * + * @param in the input for the stop + * @param output the output for the stop + * @param <I> the input property type + * @param <O> the output property type + * @return the {@link Stop} + */ + public static <I, O> Stop<I, O> stop(I in, PropertyValue<O> output) { + return new Stop<>(in, output.value); + } + + /** + * Create a composite {@link Stop} for use in a {@link com.mapbox.mapboxsdk.style.functions.CompositeFunction} + * + * @param zoom the zoom input + * @param value the feature property input + * @param output the output for the stop + * @param <Z> the zoom type + * @param <I> the feature property input type + * @param <O> the output property type + * @return the {@link Stop} + * @see Function#composite(String, ExponentialStops) + */ + public static <Z extends Number, I, O> Stop<Stop.CompositeValue<Z, I>, O> stop(Z zoom, + I value, + PropertyValue<O> output) { + return new Stop<>(new Stop.CompositeValue<>(zoom, value), output.value); + } + + /** + * Represents a composite input value for composite functions (eg zoom and feature property value) + * + * @param <Z> the zoom input type (typically Float) + * @param <V> the feature property input type + */ + public static class CompositeValue<Z extends Number, V> { + Z zoom; + V value; + + CompositeValue(Z zoom, V value) { + this.zoom = zoom; + this.value = value; + } + + /** + * INTERNAL USAGE ONLY + * + * @return the value object representation for core conversion + */ + Map<String, Object> toValueObject() { + HashMap<String, Object> map = new HashMap<>(); + map.put("zoom", zoom); + map.put("value", value); + return map; + } + + @Override + public String toString() { + return String.format("[zoom: %s, value: %s]", zoom, value); + } + } + + /** + * The input type + */ + public final I in; + + /** + * The output type + */ + public final O out; + + Stop(I in, O out) { + this.in = in; + this.out = out; + } + + /** + * INTERNAL USAGE ONLY + * + * @return an array representation of the Stop + */ + Object[] toValueObject() { + return new Object[] {in instanceof CompositeValue ? ((CompositeValue) in).toValueObject() : in, out}; + } + + @Override + public String toString() { + return String.format("[%s, %s]", in, out); + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stops.java new file mode 100644 index 0000000000..a9d8055084 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stops.java @@ -0,0 +1,97 @@ +package com.mapbox.mapboxsdk.style.functions.stops; + +import android.support.annotation.NonNull; +import android.support.annotation.Size; + +import java.util.HashMap; +import java.util.Map; + +/** + * The base class for different stops implementations + * + * @param <I> the input type + * @param <O> the output type + * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a> + */ +public abstract class Stops<I, O> { + + /** + * Convenience method for use in function declarations + * + * @param stops the collections of discrete stops + * @param <I> the Stops input type + * @param <O> the Stops output type + * @return the {@link Stops} implementation + * @see Stop#stop + * @see CategoricalStops + */ + @SafeVarargs + public static <I, O> CategoricalStops<I, O> categorical(@NonNull @Size(min = 1) Stop<I, O>... stops) { + return new CategoricalStops<>(stops); + } + + /** + * Convenience method for use in function declarations + * + * @param stops the collections of discrete stops + * @param <I> the Stops input type + * @param <O> the Stops output type + * @return the {@link Stops} implementation + * @see Stop#stop + * @see ExponentialStops + */ + @SafeVarargs + public static <I, O> ExponentialStops<I, O> exponential(@NonNull @Size(min = 1) Stop<I, O>... stops) { + return new ExponentialStops<>(stops); + } + + /** + * Convenience method for use in function declarations + * + * @param <T> the Stops input/output type + * @return the {@link IdentityStops} implementation + * @see Stop#stop + * @see IdentityStops + */ + public static <T> IdentityStops<T> identity() { + return new IdentityStops<>(); + } + + /** + * Convenience method for use in function declarations + * + * @param stops the collections of discrete stops + * @param <I> the Stops input type + * @param <O> the Stops output type + * @return the {@link Stops} implementation + * @see Stop#stop + * @see IntervalStops + */ + @SafeVarargs + public static <I, O> IntervalStops<I, O> interval(@NonNull @Size(min = 1) Stop<I, O>... stops) { + return new IntervalStops<>(stops); + } + + /** + * INTERNAL USAGE ONLY + * + * @return the value object representation for conversion to core + */ + public Map<String, Object> toValueObject() { + HashMap<String, Object> map = new HashMap<>(); + map.put("type", getTypeName()); + return map; + } + + /** + * INTERNAL USAGE ONLY + * + * @return the unique type name as a string according to the style specification + */ + protected abstract String getTypeName(); + + @Override + public String toString() { + return getTypeName(); + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/package-info.java new file mode 100644 index 0000000000..fa388a9589 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/package-info.java @@ -0,0 +1,6 @@ +/** + * Contains the Mapbox Maps Android Style Function Stop implementation API classes. + * + * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a> + */ +package com.mapbox.mapboxsdk.style.functions.stops; |