[core] Implement data-driven styling for {text,icon}-{color,opacity,halo-color,halo-blur,halo-width} (#7939)

* Add symbol dds attributes and adapt style code generation

* Update to mapbox-gl-js/master

* Refactor SymbolFeature as a subclass of GeometryTileFeature

Prepares for enabling DDS on symbol paint properties by allowing the
SymbolFeatures, which we keep around after constructing SymbolLayout,
to be used in evaluating data-driven paint properties later in the
layout process.

* Draft approach for splitting icon/text paint properties

The `Program` types are set up to bind GL attributes to each of the
data-driven paint properties specified in the `PaintProperties` type
provided.  Since `SymbolPaintProperties` specifies both `Text*` and
`Icon*` properties, the symbolIcon, symbolIconSDF, and symbolGlyph
programs each attempt to bind roughly double the number of attributes
that they actually need.

This change addresses this by:
- Adding the more specific `IconPaintProperties` and `TextPaintProperties` types, which are subsets of the full `SymbolPaintProperties`.
- The symbol layer continues to use its `SymbolPaintProperties paint` member to track layer property state, but it provides helpers that construct objects of each the specific `{Icon,Text}PaintProperties::Evaluated` type, for use by the painter.
- The three symbol programs instantiate `Program<>` using the appropriate `{Icon,Text}PaintProperties` type.

* check in generated style code

* Populate paint buffers for symbol DDS properties

* Address first round of review comments

* Refactor VectorTile{Layer,Feature} to explicitly share data

* Update submodule
This commit is contained in:
Anand Thakker
2017-02-28 19:54:24 -08:00
committed by GitHub
parent c3ed1f51ca
commit f901e776b3
31 changed files with 1982 additions and 475 deletions

View File

@@ -169,29 +169,29 @@ public:
// Paint properties
static PropertyValue<float> getDefaultIconOpacity();
PropertyValue<float> getIconOpacity(const optional<std::string>& klass = {}) const;
void setIconOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
static DataDrivenPropertyValue<float> getDefaultIconOpacity();
DataDrivenPropertyValue<float> getIconOpacity(const optional<std::string>& klass = {}) const;
void setIconOpacity(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
void setIconOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<Color> getDefaultIconColor();
PropertyValue<Color> getIconColor(const optional<std::string>& klass = {}) const;
void setIconColor(PropertyValue<Color>, const optional<std::string>& klass = {});
static DataDrivenPropertyValue<Color> getDefaultIconColor();
DataDrivenPropertyValue<Color> getIconColor(const optional<std::string>& klass = {}) const;
void setIconColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
void setIconColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<Color> getDefaultIconHaloColor();
PropertyValue<Color> getIconHaloColor(const optional<std::string>& klass = {}) const;
void setIconHaloColor(PropertyValue<Color>, const optional<std::string>& klass = {});
static DataDrivenPropertyValue<Color> getDefaultIconHaloColor();
DataDrivenPropertyValue<Color> getIconHaloColor(const optional<std::string>& klass = {}) const;
void setIconHaloColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
void setIconHaloColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultIconHaloWidth();
PropertyValue<float> getIconHaloWidth(const optional<std::string>& klass = {}) const;
void setIconHaloWidth(PropertyValue<float>, const optional<std::string>& klass = {});
static DataDrivenPropertyValue<float> getDefaultIconHaloWidth();
DataDrivenPropertyValue<float> getIconHaloWidth(const optional<std::string>& klass = {}) const;
void setIconHaloWidth(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
void setIconHaloWidthTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultIconHaloBlur();
PropertyValue<float> getIconHaloBlur(const optional<std::string>& klass = {}) const;
void setIconHaloBlur(PropertyValue<float>, const optional<std::string>& klass = {});
static DataDrivenPropertyValue<float> getDefaultIconHaloBlur();
DataDrivenPropertyValue<float> getIconHaloBlur(const optional<std::string>& klass = {}) const;
void setIconHaloBlur(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
void setIconHaloBlurTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::array<float, 2>> getDefaultIconTranslate();
@@ -204,29 +204,29 @@ public:
void setIconTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
void setIconTranslateAnchorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultTextOpacity();
PropertyValue<float> getTextOpacity(const optional<std::string>& klass = {}) const;
void setTextOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
static DataDrivenPropertyValue<float> getDefaultTextOpacity();
DataDrivenPropertyValue<float> getTextOpacity(const optional<std::string>& klass = {}) const;
void setTextOpacity(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
void setTextOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<Color> getDefaultTextColor();
PropertyValue<Color> getTextColor(const optional<std::string>& klass = {}) const;
void setTextColor(PropertyValue<Color>, const optional<std::string>& klass = {});
static DataDrivenPropertyValue<Color> getDefaultTextColor();
DataDrivenPropertyValue<Color> getTextColor(const optional<std::string>& klass = {}) const;
void setTextColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
void setTextColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<Color> getDefaultTextHaloColor();
PropertyValue<Color> getTextHaloColor(const optional<std::string>& klass = {}) const;
void setTextHaloColor(PropertyValue<Color>, const optional<std::string>& klass = {});
static DataDrivenPropertyValue<Color> getDefaultTextHaloColor();
DataDrivenPropertyValue<Color> getTextHaloColor(const optional<std::string>& klass = {}) const;
void setTextHaloColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
void setTextHaloColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultTextHaloWidth();
PropertyValue<float> getTextHaloWidth(const optional<std::string>& klass = {}) const;
void setTextHaloWidth(PropertyValue<float>, const optional<std::string>& klass = {});
static DataDrivenPropertyValue<float> getDefaultTextHaloWidth();
DataDrivenPropertyValue<float> getTextHaloWidth(const optional<std::string>& klass = {}) const;
void setTextHaloWidth(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
void setTextHaloWidthTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultTextHaloBlur();
PropertyValue<float> getTextHaloBlur(const optional<std::string>& klass = {}) const;
void setTextHaloBlur(PropertyValue<float>, const optional<std::string>& klass = {});
static DataDrivenPropertyValue<float> getDefaultTextHaloBlur();
DataDrivenPropertyValue<float> getTextHaloBlur(const optional<std::string>& klass = {}) const;
void setTextHaloBlur(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
void setTextHaloBlurTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::array<float, 2>> getDefaultTextTranslate();

View File

@@ -454,11 +454,11 @@ public class PropertyFactory {
/**
* The opacity at which the icon will be drawn.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for Float
* @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> iconOpacity(CameraFunction<Z, Float> function) {
public static <T> PropertyValue<Function<T, Float>> iconOpacity(Function<T, Float> function) {
return new PaintPropertyValue<>("icon-opacity", function);
}
@@ -486,11 +486,11 @@ public class PropertyFactory {
/**
* The color of the icon. This can only be used with sdf icons.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for String
* @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> iconColor(CameraFunction<Z, String> function) {
public static <T> PropertyValue<Function<T, String>> iconColor(Function<T, String> function) {
return new PaintPropertyValue<>("icon-color", function);
}
@@ -518,11 +518,11 @@ public class PropertyFactory {
/**
* The color of the icon's halo. Icon halos can only be used with SDF icons.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for String
* @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> iconHaloColor(CameraFunction<Z, String> function) {
public static <T> PropertyValue<Function<T, String>> iconHaloColor(Function<T, String> function) {
return new PaintPropertyValue<>("icon-halo-color", function);
}
@@ -540,11 +540,11 @@ public class PropertyFactory {
/**
* Distance of halo to the icon outline.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for Float
* @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> iconHaloWidth(CameraFunction<Z, Float> function) {
public static <T> PropertyValue<Function<T, Float>> iconHaloWidth(Function<T, Float> function) {
return new PaintPropertyValue<>("icon-halo-width", function);
}
@@ -562,11 +562,11 @@ public class PropertyFactory {
/**
* Fade out the halo towards the outside.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for Float
* @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> iconHaloBlur(CameraFunction<Z, Float> function) {
public static <T> PropertyValue<Function<T, Float>> iconHaloBlur(Function<T, Float> function) {
return new PaintPropertyValue<>("icon-halo-blur", function);
}
@@ -628,11 +628,11 @@ public class PropertyFactory {
/**
* The opacity at which the text will be drawn.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for Float
* @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textOpacity(CameraFunction<Z, Float> function) {
public static <T> PropertyValue<Function<T, Float>> textOpacity(Function<T, Float> function) {
return new PaintPropertyValue<>("text-opacity", function);
}
@@ -660,11 +660,11 @@ public class PropertyFactory {
/**
* The color with which the text will be drawn.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for String
* @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> textColor(CameraFunction<Z, String> function) {
public static <T> PropertyValue<Function<T, String>> textColor(Function<T, String> function) {
return new PaintPropertyValue<>("text-color", function);
}
@@ -692,11 +692,11 @@ public class PropertyFactory {
/**
* The color of the text's halo, which helps it stand out from backgrounds.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for String
* @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> textHaloColor(CameraFunction<Z, String> function) {
public static <T> PropertyValue<Function<T, String>> textHaloColor(Function<T, String> function) {
return new PaintPropertyValue<>("text-halo-color", function);
}
@@ -714,11 +714,11 @@ public class PropertyFactory {
/**
* Distance of halo to the font outline. Max text halo width is 1/4 of the font-size.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for Float
* @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textHaloWidth(CameraFunction<Z, Float> function) {
public static <T> PropertyValue<Function<T, Float>> textHaloWidth(Function<T, Float> function) {
return new PaintPropertyValue<>("text-halo-width", function);
}
@@ -736,11 +736,11 @@ public class PropertyFactory {
/**
* The halo's fadeout distance towards the outside.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for Float
* @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textHaloBlur(CameraFunction<Z, Float> function) {
public static <T> PropertyValue<Function<T, Float>> textHaloBlur(Function<T, Float> function) {
return new PaintPropertyValue<>("text-halo-blur", function);
}
@@ -1742,7 +1742,7 @@ public class PropertyFactory {
}
/**
* Value to use for a text label. Feature properties are specified using tokens like {field_name}. (Token replacement is only supported for literal `textField` values--not for property functions.)
* Value to use for a text label. Feature properties are specified using tokens like {field_name}. (Token replacement is only supported for literal {@link PropertyFactory#textField} values--not for property functions.)
*
* @param value a String value
* @return property wrapper around String
@@ -1754,7 +1754,7 @@ public class PropertyFactory {
/**
* Value to use for a text label. Feature properties are specified using tokens like {field_name}. (Token replacement is only supported for literal `textField` values--not for property functions.)
* Value to use for a text label. Feature properties are specified using tokens like {field_name}. (Token replacement is only supported for literal {@link PropertyFactory#textField} values--not for property functions.)
*
* @param <T> the function input type
* @param function a wrapper function for String

View File

@@ -1597,6 +1597,112 @@ public class SymbolLayerTest extends BaseStyleTest {
assertEquals(1, ((ExponentialStops) layer.getIconOpacity().getFunction().getStops()).size());
}
@Test
public void testIconOpacityAsIdentitySourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-opacity");
assertNotNull(layer);
// Set
layer.setProperties(
iconOpacity(property("FeaturePropertyA", Stops.<Float>identity()))
);
// Verify
assertNotNull(layer.getIconOpacity());
assertNotNull(layer.getIconOpacity().getFunction());
assertEquals(SourceFunction.class, layer.getIconOpacity().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconOpacity().getFunction()).getProperty());
assertEquals(IdentityStops.class, layer.getIconOpacity().getFunction().getStops().getClass());
}
@Test
public void testIconOpacityAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-opacity");
assertNotNull(layer);
// Set
layer.setProperties(
iconOpacity(
property(
"FeaturePropertyA",
exponential(
stop(0.3f, iconOpacity(0.3f))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getIconOpacity());
assertNotNull(layer.getIconOpacity().getFunction());
assertEquals(SourceFunction.class, layer.getIconOpacity().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconOpacity().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getIconOpacity().getFunction().getStops().getClass());
}
@Test
public void testIconOpacityAsCategoricalSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-opacity");
assertNotNull(layer);
// Set
layer.setProperties(
iconOpacity(
property(
"FeaturePropertyA",
categorical(
stop(1.0f, iconOpacity(0.3f))
)
).withDefaultValue(0.3f)
)
);
// Verify
assertNotNull(layer.getIconOpacity());
assertNotNull(layer.getIconOpacity().getFunction());
assertEquals(SourceFunction.class, layer.getIconOpacity().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconOpacity().getFunction()).getProperty());
assertEquals(CategoricalStops.class, layer.getIconOpacity().getFunction().getStops().getClass());
assertEquals(0.3f, ((SourceFunction) layer.getIconOpacity().getFunction()).getDefaultValue());
}
@Test
public void testIconOpacityAsCompositeFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-opacity");
assertNotNull(layer);
// Set
layer.setProperties(
iconOpacity(
composite(
"FeaturePropertyA",
exponential(
stop(0, 0.3f, iconOpacity(0.9f))
).withBase(0.5f)
).withDefaultValue(0.3f)
)
);
// Verify
assertNotNull(layer.getIconOpacity());
assertNotNull(layer.getIconOpacity().getFunction());
assertEquals(CompositeFunction.class, layer.getIconOpacity().getFunction().getClass());
assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getIconOpacity().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getIconOpacity().getFunction().getStops().getClass());
assertEquals(1, ((ExponentialStops) layer.getIconOpacity().getFunction().getStops()).size());
ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
(ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getIconOpacity().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 testIconColorAsConstant() {
checkViewIsDisplayed(R.id.mapView);
@@ -1634,6 +1740,77 @@ public class SymbolLayerTest extends BaseStyleTest {
assertEquals(1, ((ExponentialStops) layer.getIconColor().getFunction().getStops()).size());
}
@Test
public void testIconColorAsIdentitySourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-color");
assertNotNull(layer);
// Set
layer.setProperties(
iconColor(property("FeaturePropertyA", Stops.<String>identity()))
);
// Verify
assertNotNull(layer.getIconColor());
assertNotNull(layer.getIconColor().getFunction());
assertEquals(SourceFunction.class, layer.getIconColor().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconColor().getFunction()).getProperty());
assertEquals(IdentityStops.class, layer.getIconColor().getFunction().getStops().getClass());
}
@Test
public void testIconColorAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-color");
assertNotNull(layer);
// Set
layer.setProperties(
iconColor(
property(
"FeaturePropertyA",
exponential(
stop(Color.RED, iconColor(Color.RED))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getIconColor());
assertNotNull(layer.getIconColor().getFunction());
assertEquals(SourceFunction.class, layer.getIconColor().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconColor().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getIconColor().getFunction().getStops().getClass());
}
@Test
public void testIconColorAsCategoricalSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-color");
assertNotNull(layer);
// Set
layer.setProperties(
iconColor(
property(
"FeaturePropertyA",
categorical(
stop("valueA", iconColor(Color.RED))
)
)
)
);
// Verify
assertNotNull(layer.getIconColor());
assertNotNull(layer.getIconColor().getFunction());
assertEquals(SourceFunction.class, layer.getIconColor().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconColor().getFunction()).getProperty());
assertEquals(CategoricalStops.class, layer.getIconColor().getFunction().getStops().getClass());
}
@Test
public void testIconColorAsIntConstant() {
checkViewIsDisplayed(R.id.mapView);
@@ -1682,6 +1859,77 @@ public class SymbolLayerTest extends BaseStyleTest {
assertEquals(1, ((ExponentialStops) layer.getIconHaloColor().getFunction().getStops()).size());
}
@Test
public void testIconHaloColorAsIdentitySourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-color");
assertNotNull(layer);
// Set
layer.setProperties(
iconHaloColor(property("FeaturePropertyA", Stops.<String>identity()))
);
// Verify
assertNotNull(layer.getIconHaloColor());
assertNotNull(layer.getIconHaloColor().getFunction());
assertEquals(SourceFunction.class, layer.getIconHaloColor().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloColor().getFunction()).getProperty());
assertEquals(IdentityStops.class, layer.getIconHaloColor().getFunction().getStops().getClass());
}
@Test
public void testIconHaloColorAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-color");
assertNotNull(layer);
// Set
layer.setProperties(
iconHaloColor(
property(
"FeaturePropertyA",
exponential(
stop(Color.RED, iconHaloColor(Color.RED))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getIconHaloColor());
assertNotNull(layer.getIconHaloColor().getFunction());
assertEquals(SourceFunction.class, layer.getIconHaloColor().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloColor().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getIconHaloColor().getFunction().getStops().getClass());
}
@Test
public void testIconHaloColorAsCategoricalSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-color");
assertNotNull(layer);
// Set
layer.setProperties(
iconHaloColor(
property(
"FeaturePropertyA",
categorical(
stop("valueA", iconHaloColor(Color.RED))
)
)
)
);
// Verify
assertNotNull(layer.getIconHaloColor());
assertNotNull(layer.getIconHaloColor().getFunction());
assertEquals(SourceFunction.class, layer.getIconHaloColor().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloColor().getFunction()).getProperty());
assertEquals(CategoricalStops.class, layer.getIconHaloColor().getFunction().getStops().getClass());
}
@Test
public void testIconHaloColorAsIntConstant() {
checkViewIsDisplayed(R.id.mapView);
@@ -1730,6 +1978,112 @@ public class SymbolLayerTest extends BaseStyleTest {
assertEquals(1, ((ExponentialStops) layer.getIconHaloWidth().getFunction().getStops()).size());
}
@Test
public void testIconHaloWidthAsIdentitySourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-width");
assertNotNull(layer);
// Set
layer.setProperties(
iconHaloWidth(property("FeaturePropertyA", Stops.<Float>identity()))
);
// Verify
assertNotNull(layer.getIconHaloWidth());
assertNotNull(layer.getIconHaloWidth().getFunction());
assertEquals(SourceFunction.class, layer.getIconHaloWidth().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloWidth().getFunction()).getProperty());
assertEquals(IdentityStops.class, layer.getIconHaloWidth().getFunction().getStops().getClass());
}
@Test
public void testIconHaloWidthAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-width");
assertNotNull(layer);
// Set
layer.setProperties(
iconHaloWidth(
property(
"FeaturePropertyA",
exponential(
stop(0.3f, iconHaloWidth(0.3f))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getIconHaloWidth());
assertNotNull(layer.getIconHaloWidth().getFunction());
assertEquals(SourceFunction.class, layer.getIconHaloWidth().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloWidth().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getIconHaloWidth().getFunction().getStops().getClass());
}
@Test
public void testIconHaloWidthAsCategoricalSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-width");
assertNotNull(layer);
// Set
layer.setProperties(
iconHaloWidth(
property(
"FeaturePropertyA",
categorical(
stop(1.0f, iconHaloWidth(0.3f))
)
).withDefaultValue(0.3f)
)
);
// Verify
assertNotNull(layer.getIconHaloWidth());
assertNotNull(layer.getIconHaloWidth().getFunction());
assertEquals(SourceFunction.class, layer.getIconHaloWidth().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloWidth().getFunction()).getProperty());
assertEquals(CategoricalStops.class, layer.getIconHaloWidth().getFunction().getStops().getClass());
assertEquals(0.3f, ((SourceFunction) layer.getIconHaloWidth().getFunction()).getDefaultValue());
}
@Test
public void testIconHaloWidthAsCompositeFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-width");
assertNotNull(layer);
// Set
layer.setProperties(
iconHaloWidth(
composite(
"FeaturePropertyA",
exponential(
stop(0, 0.3f, iconHaloWidth(0.9f))
).withBase(0.5f)
).withDefaultValue(0.3f)
)
);
// Verify
assertNotNull(layer.getIconHaloWidth());
assertNotNull(layer.getIconHaloWidth().getFunction());
assertEquals(CompositeFunction.class, layer.getIconHaloWidth().getFunction().getClass());
assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getIconHaloWidth().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getIconHaloWidth().getFunction().getStops().getClass());
assertEquals(1, ((ExponentialStops) layer.getIconHaloWidth().getFunction().getStops()).size());
ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
(ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getIconHaloWidth().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 testIconHaloBlurAsConstant() {
checkViewIsDisplayed(R.id.mapView);
@@ -1767,6 +2121,112 @@ public class SymbolLayerTest extends BaseStyleTest {
assertEquals(1, ((ExponentialStops) layer.getIconHaloBlur().getFunction().getStops()).size());
}
@Test
public void testIconHaloBlurAsIdentitySourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-blur");
assertNotNull(layer);
// Set
layer.setProperties(
iconHaloBlur(property("FeaturePropertyA", Stops.<Float>identity()))
);
// Verify
assertNotNull(layer.getIconHaloBlur());
assertNotNull(layer.getIconHaloBlur().getFunction());
assertEquals(SourceFunction.class, layer.getIconHaloBlur().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloBlur().getFunction()).getProperty());
assertEquals(IdentityStops.class, layer.getIconHaloBlur().getFunction().getStops().getClass());
}
@Test
public void testIconHaloBlurAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-blur");
assertNotNull(layer);
// Set
layer.setProperties(
iconHaloBlur(
property(
"FeaturePropertyA",
exponential(
stop(0.3f, iconHaloBlur(0.3f))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getIconHaloBlur());
assertNotNull(layer.getIconHaloBlur().getFunction());
assertEquals(SourceFunction.class, layer.getIconHaloBlur().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloBlur().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getIconHaloBlur().getFunction().getStops().getClass());
}
@Test
public void testIconHaloBlurAsCategoricalSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-blur");
assertNotNull(layer);
// Set
layer.setProperties(
iconHaloBlur(
property(
"FeaturePropertyA",
categorical(
stop(1.0f, iconHaloBlur(0.3f))
)
).withDefaultValue(0.3f)
)
);
// Verify
assertNotNull(layer.getIconHaloBlur());
assertNotNull(layer.getIconHaloBlur().getFunction());
assertEquals(SourceFunction.class, layer.getIconHaloBlur().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloBlur().getFunction()).getProperty());
assertEquals(CategoricalStops.class, layer.getIconHaloBlur().getFunction().getStops().getClass());
assertEquals(0.3f, ((SourceFunction) layer.getIconHaloBlur().getFunction()).getDefaultValue());
}
@Test
public void testIconHaloBlurAsCompositeFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-blur");
assertNotNull(layer);
// Set
layer.setProperties(
iconHaloBlur(
composite(
"FeaturePropertyA",
exponential(
stop(0, 0.3f, iconHaloBlur(0.9f))
).withBase(0.5f)
).withDefaultValue(0.3f)
)
);
// Verify
assertNotNull(layer.getIconHaloBlur());
assertNotNull(layer.getIconHaloBlur().getFunction());
assertEquals(CompositeFunction.class, layer.getIconHaloBlur().getFunction().getClass());
assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getIconHaloBlur().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getIconHaloBlur().getFunction().getStops().getClass());
assertEquals(1, ((ExponentialStops) layer.getIconHaloBlur().getFunction().getStops()).size());
ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
(ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getIconHaloBlur().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 testIconTranslateAsConstant() {
checkViewIsDisplayed(R.id.mapView);
@@ -1877,6 +2337,112 @@ public class SymbolLayerTest extends BaseStyleTest {
assertEquals(1, ((ExponentialStops) layer.getTextOpacity().getFunction().getStops()).size());
}
@Test
public void testTextOpacityAsIdentitySourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-opacity");
assertNotNull(layer);
// Set
layer.setProperties(
textOpacity(property("FeaturePropertyA", Stops.<Float>identity()))
);
// Verify
assertNotNull(layer.getTextOpacity());
assertNotNull(layer.getTextOpacity().getFunction());
assertEquals(SourceFunction.class, layer.getTextOpacity().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextOpacity().getFunction()).getProperty());
assertEquals(IdentityStops.class, layer.getTextOpacity().getFunction().getStops().getClass());
}
@Test
public void testTextOpacityAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-opacity");
assertNotNull(layer);
// Set
layer.setProperties(
textOpacity(
property(
"FeaturePropertyA",
exponential(
stop(0.3f, textOpacity(0.3f))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getTextOpacity());
assertNotNull(layer.getTextOpacity().getFunction());
assertEquals(SourceFunction.class, layer.getTextOpacity().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextOpacity().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getTextOpacity().getFunction().getStops().getClass());
}
@Test
public void testTextOpacityAsCategoricalSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-opacity");
assertNotNull(layer);
// Set
layer.setProperties(
textOpacity(
property(
"FeaturePropertyA",
categorical(
stop(1.0f, textOpacity(0.3f))
)
).withDefaultValue(0.3f)
)
);
// Verify
assertNotNull(layer.getTextOpacity());
assertNotNull(layer.getTextOpacity().getFunction());
assertEquals(SourceFunction.class, layer.getTextOpacity().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextOpacity().getFunction()).getProperty());
assertEquals(CategoricalStops.class, layer.getTextOpacity().getFunction().getStops().getClass());
assertEquals(0.3f, ((SourceFunction) layer.getTextOpacity().getFunction()).getDefaultValue());
}
@Test
public void testTextOpacityAsCompositeFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-opacity");
assertNotNull(layer);
// Set
layer.setProperties(
textOpacity(
composite(
"FeaturePropertyA",
exponential(
stop(0, 0.3f, textOpacity(0.9f))
).withBase(0.5f)
).withDefaultValue(0.3f)
)
);
// Verify
assertNotNull(layer.getTextOpacity());
assertNotNull(layer.getTextOpacity().getFunction());
assertEquals(CompositeFunction.class, layer.getTextOpacity().getFunction().getClass());
assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getTextOpacity().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getTextOpacity().getFunction().getStops().getClass());
assertEquals(1, ((ExponentialStops) layer.getTextOpacity().getFunction().getStops()).size());
ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
(ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getTextOpacity().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 testTextColorAsConstant() {
checkViewIsDisplayed(R.id.mapView);
@@ -1914,6 +2480,77 @@ public class SymbolLayerTest extends BaseStyleTest {
assertEquals(1, ((ExponentialStops) layer.getTextColor().getFunction().getStops()).size());
}
@Test
public void testTextColorAsIdentitySourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-color");
assertNotNull(layer);
// Set
layer.setProperties(
textColor(property("FeaturePropertyA", Stops.<String>identity()))
);
// Verify
assertNotNull(layer.getTextColor());
assertNotNull(layer.getTextColor().getFunction());
assertEquals(SourceFunction.class, layer.getTextColor().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextColor().getFunction()).getProperty());
assertEquals(IdentityStops.class, layer.getTextColor().getFunction().getStops().getClass());
}
@Test
public void testTextColorAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-color");
assertNotNull(layer);
// Set
layer.setProperties(
textColor(
property(
"FeaturePropertyA",
exponential(
stop(Color.RED, textColor(Color.RED))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getTextColor());
assertNotNull(layer.getTextColor().getFunction());
assertEquals(SourceFunction.class, layer.getTextColor().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextColor().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getTextColor().getFunction().getStops().getClass());
}
@Test
public void testTextColorAsCategoricalSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-color");
assertNotNull(layer);
// Set
layer.setProperties(
textColor(
property(
"FeaturePropertyA",
categorical(
stop("valueA", textColor(Color.RED))
)
)
)
);
// Verify
assertNotNull(layer.getTextColor());
assertNotNull(layer.getTextColor().getFunction());
assertEquals(SourceFunction.class, layer.getTextColor().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextColor().getFunction()).getProperty());
assertEquals(CategoricalStops.class, layer.getTextColor().getFunction().getStops().getClass());
}
@Test
public void testTextColorAsIntConstant() {
checkViewIsDisplayed(R.id.mapView);
@@ -1962,6 +2599,77 @@ public class SymbolLayerTest extends BaseStyleTest {
assertEquals(1, ((ExponentialStops) layer.getTextHaloColor().getFunction().getStops()).size());
}
@Test
public void testTextHaloColorAsIdentitySourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-color");
assertNotNull(layer);
// Set
layer.setProperties(
textHaloColor(property("FeaturePropertyA", Stops.<String>identity()))
);
// Verify
assertNotNull(layer.getTextHaloColor());
assertNotNull(layer.getTextHaloColor().getFunction());
assertEquals(SourceFunction.class, layer.getTextHaloColor().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloColor().getFunction()).getProperty());
assertEquals(IdentityStops.class, layer.getTextHaloColor().getFunction().getStops().getClass());
}
@Test
public void testTextHaloColorAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-color");
assertNotNull(layer);
// Set
layer.setProperties(
textHaloColor(
property(
"FeaturePropertyA",
exponential(
stop(Color.RED, textHaloColor(Color.RED))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getTextHaloColor());
assertNotNull(layer.getTextHaloColor().getFunction());
assertEquals(SourceFunction.class, layer.getTextHaloColor().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloColor().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getTextHaloColor().getFunction().getStops().getClass());
}
@Test
public void testTextHaloColorAsCategoricalSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-color");
assertNotNull(layer);
// Set
layer.setProperties(
textHaloColor(
property(
"FeaturePropertyA",
categorical(
stop("valueA", textHaloColor(Color.RED))
)
)
)
);
// Verify
assertNotNull(layer.getTextHaloColor());
assertNotNull(layer.getTextHaloColor().getFunction());
assertEquals(SourceFunction.class, layer.getTextHaloColor().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloColor().getFunction()).getProperty());
assertEquals(CategoricalStops.class, layer.getTextHaloColor().getFunction().getStops().getClass());
}
@Test
public void testTextHaloColorAsIntConstant() {
checkViewIsDisplayed(R.id.mapView);
@@ -2010,6 +2718,112 @@ public class SymbolLayerTest extends BaseStyleTest {
assertEquals(1, ((ExponentialStops) layer.getTextHaloWidth().getFunction().getStops()).size());
}
@Test
public void testTextHaloWidthAsIdentitySourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-width");
assertNotNull(layer);
// Set
layer.setProperties(
textHaloWidth(property("FeaturePropertyA", Stops.<Float>identity()))
);
// Verify
assertNotNull(layer.getTextHaloWidth());
assertNotNull(layer.getTextHaloWidth().getFunction());
assertEquals(SourceFunction.class, layer.getTextHaloWidth().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloWidth().getFunction()).getProperty());
assertEquals(IdentityStops.class, layer.getTextHaloWidth().getFunction().getStops().getClass());
}
@Test
public void testTextHaloWidthAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-width");
assertNotNull(layer);
// Set
layer.setProperties(
textHaloWidth(
property(
"FeaturePropertyA",
exponential(
stop(0.3f, textHaloWidth(0.3f))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getTextHaloWidth());
assertNotNull(layer.getTextHaloWidth().getFunction());
assertEquals(SourceFunction.class, layer.getTextHaloWidth().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloWidth().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getTextHaloWidth().getFunction().getStops().getClass());
}
@Test
public void testTextHaloWidthAsCategoricalSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-width");
assertNotNull(layer);
// Set
layer.setProperties(
textHaloWidth(
property(
"FeaturePropertyA",
categorical(
stop(1.0f, textHaloWidth(0.3f))
)
).withDefaultValue(0.3f)
)
);
// Verify
assertNotNull(layer.getTextHaloWidth());
assertNotNull(layer.getTextHaloWidth().getFunction());
assertEquals(SourceFunction.class, layer.getTextHaloWidth().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloWidth().getFunction()).getProperty());
assertEquals(CategoricalStops.class, layer.getTextHaloWidth().getFunction().getStops().getClass());
assertEquals(0.3f, ((SourceFunction) layer.getTextHaloWidth().getFunction()).getDefaultValue());
}
@Test
public void testTextHaloWidthAsCompositeFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-width");
assertNotNull(layer);
// Set
layer.setProperties(
textHaloWidth(
composite(
"FeaturePropertyA",
exponential(
stop(0, 0.3f, textHaloWidth(0.9f))
).withBase(0.5f)
).withDefaultValue(0.3f)
)
);
// Verify
assertNotNull(layer.getTextHaloWidth());
assertNotNull(layer.getTextHaloWidth().getFunction());
assertEquals(CompositeFunction.class, layer.getTextHaloWidth().getFunction().getClass());
assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getTextHaloWidth().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getTextHaloWidth().getFunction().getStops().getClass());
assertEquals(1, ((ExponentialStops) layer.getTextHaloWidth().getFunction().getStops()).size());
ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
(ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getTextHaloWidth().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 testTextHaloBlurAsConstant() {
checkViewIsDisplayed(R.id.mapView);
@@ -2047,6 +2861,112 @@ public class SymbolLayerTest extends BaseStyleTest {
assertEquals(1, ((ExponentialStops) layer.getTextHaloBlur().getFunction().getStops()).size());
}
@Test
public void testTextHaloBlurAsIdentitySourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-blur");
assertNotNull(layer);
// Set
layer.setProperties(
textHaloBlur(property("FeaturePropertyA", Stops.<Float>identity()))
);
// Verify
assertNotNull(layer.getTextHaloBlur());
assertNotNull(layer.getTextHaloBlur().getFunction());
assertEquals(SourceFunction.class, layer.getTextHaloBlur().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloBlur().getFunction()).getProperty());
assertEquals(IdentityStops.class, layer.getTextHaloBlur().getFunction().getStops().getClass());
}
@Test
public void testTextHaloBlurAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-blur");
assertNotNull(layer);
// Set
layer.setProperties(
textHaloBlur(
property(
"FeaturePropertyA",
exponential(
stop(0.3f, textHaloBlur(0.3f))
).withBase(0.5f)
)
)
);
// Verify
assertNotNull(layer.getTextHaloBlur());
assertNotNull(layer.getTextHaloBlur().getFunction());
assertEquals(SourceFunction.class, layer.getTextHaloBlur().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloBlur().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getTextHaloBlur().getFunction().getStops().getClass());
}
@Test
public void testTextHaloBlurAsCategoricalSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-blur");
assertNotNull(layer);
// Set
layer.setProperties(
textHaloBlur(
property(
"FeaturePropertyA",
categorical(
stop(1.0f, textHaloBlur(0.3f))
)
).withDefaultValue(0.3f)
)
);
// Verify
assertNotNull(layer.getTextHaloBlur());
assertNotNull(layer.getTextHaloBlur().getFunction());
assertEquals(SourceFunction.class, layer.getTextHaloBlur().getFunction().getClass());
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloBlur().getFunction()).getProperty());
assertEquals(CategoricalStops.class, layer.getTextHaloBlur().getFunction().getStops().getClass());
assertEquals(0.3f, ((SourceFunction) layer.getTextHaloBlur().getFunction()).getDefaultValue());
}
@Test
public void testTextHaloBlurAsCompositeFunction() {
checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-blur");
assertNotNull(layer);
// Set
layer.setProperties(
textHaloBlur(
composite(
"FeaturePropertyA",
exponential(
stop(0, 0.3f, textHaloBlur(0.9f))
).withBase(0.5f)
).withDefaultValue(0.3f)
)
);
// Verify
assertNotNull(layer.getTextHaloBlur());
assertNotNull(layer.getTextHaloBlur().getFunction());
assertEquals(CompositeFunction.class, layer.getTextHaloBlur().getFunction().getClass());
assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getTextHaloBlur().getFunction()).getProperty());
assertEquals(ExponentialStops.class, layer.getTextHaloBlur().getFunction().getStops().getClass());
assertEquals(1, ((ExponentialStops) layer.getTextHaloBlur().getFunction().getStops()).size());
ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
(ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getTextHaloBlur().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 testTextTranslateAsConstant() {
checkViewIsDisplayed(R.id.mapView);

View File

@@ -1204,6 +1204,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLSourceStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
* `MGLInterpolationModeIdentity`
* `MGLCompositeStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *iconColor;
#else
@@ -1224,6 +1233,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLSourceStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
* `MGLInterpolationModeIdentity`
* `MGLCompositeStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *iconColor;
#endif
@@ -1246,6 +1264,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLSourceStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
* `MGLInterpolationModeIdentity`
* `MGLCompositeStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconHaloBlur;
@@ -1267,6 +1294,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLSourceStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
* `MGLInterpolationModeIdentity`
* `MGLCompositeStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *iconHaloColor;
#else
@@ -1287,6 +1323,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLSourceStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
* `MGLInterpolationModeIdentity`
* `MGLCompositeStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *iconHaloColor;
#endif
@@ -1309,6 +1354,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLSourceStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
* `MGLInterpolationModeIdentity`
* `MGLCompositeStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconHaloWidth;
@@ -1328,6 +1382,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLSourceStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
* `MGLInterpolationModeIdentity`
* `MGLCompositeStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconOpacity;
@@ -1426,6 +1489,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLSourceStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
* `MGLInterpolationModeIdentity`
* `MGLCompositeStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *textColor;
#else
@@ -1445,6 +1517,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLSourceStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
* `MGLInterpolationModeIdentity`
* `MGLCompositeStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *textColor;
#endif
@@ -1467,6 +1548,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLSourceStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
* `MGLInterpolationModeIdentity`
* `MGLCompositeStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textHaloBlur;
@@ -1487,6 +1577,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLSourceStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
* `MGLInterpolationModeIdentity`
* `MGLCompositeStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *textHaloColor;
#else
@@ -1506,6 +1605,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLSourceStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
* `MGLInterpolationModeIdentity`
* `MGLCompositeStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *textHaloColor;
#endif
@@ -1529,6 +1637,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLSourceStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
* `MGLInterpolationModeIdentity`
* `MGLCompositeStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textHaloWidth;
@@ -1548,6 +1665,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLSourceStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
* `MGLInterpolationModeIdentity`
* `MGLCompositeStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
* `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textOpacity;

View File

@@ -890,7 +890,7 @@ namespace mbgl {
- (void)setIconColor:(MGLStyleValue<MGLColor *> *)iconColor {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toInterpolatablePropertyValue(iconColor);
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(iconColor);
self.rawLayer->setIconColor(mbglValue);
}
@@ -899,15 +899,15 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getIconColor();
if (propertyValue.isUndefined()) {
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(self.rawLayer->getDefaultIconColor());
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconColor());
}
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconHaloBlur:(MGLStyleValue<NSNumber *> *)iconHaloBlur {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(iconHaloBlur);
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(iconHaloBlur);
self.rawLayer->setIconHaloBlur(mbglValue);
}
@@ -916,15 +916,15 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getIconHaloBlur();
if (propertyValue.isUndefined()) {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconHaloBlur());
return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconHaloBlur());
}
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconHaloColor:(MGLStyleValue<MGLColor *> *)iconHaloColor {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toInterpolatablePropertyValue(iconHaloColor);
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(iconHaloColor);
self.rawLayer->setIconHaloColor(mbglValue);
}
@@ -933,15 +933,15 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getIconHaloColor();
if (propertyValue.isUndefined()) {
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(self.rawLayer->getDefaultIconHaloColor());
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconHaloColor());
}
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconHaloWidth:(MGLStyleValue<NSNumber *> *)iconHaloWidth {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(iconHaloWidth);
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(iconHaloWidth);
self.rawLayer->setIconHaloWidth(mbglValue);
}
@@ -950,15 +950,15 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getIconHaloWidth();
if (propertyValue.isUndefined()) {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconHaloWidth());
return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconHaloWidth());
}
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconOpacity:(MGLStyleValue<NSNumber *> *)iconOpacity {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(iconOpacity);
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(iconOpacity);
self.rawLayer->setIconOpacity(mbglValue);
}
@@ -967,9 +967,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getIconOpacity();
if (propertyValue.isUndefined()) {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconOpacity());
return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconOpacity());
}
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconTranslation:(MGLStyleValue<NSValue *> *)iconTranslation {
@@ -1023,7 +1023,7 @@ namespace mbgl {
- (void)setTextColor:(MGLStyleValue<MGLColor *> *)textColor {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toInterpolatablePropertyValue(textColor);
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(textColor);
self.rawLayer->setTextColor(mbglValue);
}
@@ -1032,15 +1032,15 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getTextColor();
if (propertyValue.isUndefined()) {
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(self.rawLayer->getDefaultTextColor());
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextColor());
}
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextHaloBlur:(MGLStyleValue<NSNumber *> *)textHaloBlur {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(textHaloBlur);
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textHaloBlur);
self.rawLayer->setTextHaloBlur(mbglValue);
}
@@ -1049,15 +1049,15 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getTextHaloBlur();
if (propertyValue.isUndefined()) {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextHaloBlur());
return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextHaloBlur());
}
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextHaloColor:(MGLStyleValue<MGLColor *> *)textHaloColor {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toInterpolatablePropertyValue(textHaloColor);
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(textHaloColor);
self.rawLayer->setTextHaloColor(mbglValue);
}
@@ -1066,15 +1066,15 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getTextHaloColor();
if (propertyValue.isUndefined()) {
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(self.rawLayer->getDefaultTextHaloColor());
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextHaloColor());
}
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextHaloWidth:(MGLStyleValue<NSNumber *> *)textHaloWidth {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(textHaloWidth);
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textHaloWidth);
self.rawLayer->setTextHaloWidth(mbglValue);
}
@@ -1083,15 +1083,15 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getTextHaloWidth();
if (propertyValue.isUndefined()) {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextHaloWidth());
return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextHaloWidth());
}
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextOpacity:(MGLStyleValue<NSNumber *> *)textOpacity {
MGLAssertStyleLayerIsValid();
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(textOpacity);
auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textOpacity);
self.rawLayer->setTextOpacity(mbglValue);
}
@@ -1100,9 +1100,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getTextOpacity();
if (propertyValue.isUndefined()) {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextOpacity());
return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextOpacity());
}
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextTranslation:(MGLStyleValue<NSValue *> *)textTranslation {

View File

@@ -1421,7 +1421,7 @@
MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
layer.iconColor = constantStyleValue;
mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
@"Setting iconColor to a constant value should update icon-color.");
XCTAssertEqualObjects(layer.iconColor, constantStyleValue,
@@ -1438,6 +1438,29 @@
XCTAssertEqualObjects(layer.iconColor, functionStyleValue,
@"iconColor should round-trip camera functions.");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
layer.iconColor = functionStyleValue;
mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
@"Setting iconColor to a source function should update icon-color.");
XCTAssertEqualObjects(layer.iconColor, functionStyleValue,
@"iconColor should round-trip source functions.");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
layer.iconColor = functionStyleValue;
std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
@"Setting iconColor to a composite function should update icon-color.");
XCTAssertEqualObjects(layer.iconColor, functionStyleValue,
@"iconColor should round-trip composite functions.");
layer.iconColor = nil;
@@ -1445,11 +1468,6 @@
@"Unsetting iconColor should return icon-color to the default value.");
XCTAssertEqualObjects(layer.iconColor, defaultStyleValue,
@"iconColor should return the default value after being unset.");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.iconColor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.iconColor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// icon-halo-blur
@@ -1460,7 +1478,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.iconHaloBlur = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue,
@"Setting iconHaloBlur to a constant value should update icon-halo-blur.");
XCTAssertEqualObjects(layer.iconHaloBlur, constantStyleValue,
@@ -1477,6 +1495,29 @@
XCTAssertEqualObjects(layer.iconHaloBlur, functionStyleValue,
@"iconHaloBlur should round-trip camera functions.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
layer.iconHaloBlur = functionStyleValue;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue,
@"Setting iconHaloBlur to a source function should update icon-halo-blur.");
XCTAssertEqualObjects(layer.iconHaloBlur, functionStyleValue,
@"iconHaloBlur should round-trip source functions.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
layer.iconHaloBlur = functionStyleValue;
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->getIconHaloBlur(), propertyValue,
@"Setting iconHaloBlur to a composite function should update icon-halo-blur.");
XCTAssertEqualObjects(layer.iconHaloBlur, functionStyleValue,
@"iconHaloBlur should round-trip composite functions.");
layer.iconHaloBlur = nil;
@@ -1484,11 +1525,6 @@
@"Unsetting iconHaloBlur should return icon-halo-blur to the default value.");
XCTAssertEqualObjects(layer.iconHaloBlur, defaultStyleValue,
@"iconHaloBlur should return the default value after being unset.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.iconHaloBlur = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.iconHaloBlur = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// icon-halo-color
@@ -1499,7 +1535,7 @@
MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
layer.iconHaloColor = constantStyleValue;
mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
@"Setting iconHaloColor to a constant value should update icon-halo-color.");
XCTAssertEqualObjects(layer.iconHaloColor, constantStyleValue,
@@ -1516,6 +1552,29 @@
XCTAssertEqualObjects(layer.iconHaloColor, functionStyleValue,
@"iconHaloColor should round-trip camera functions.");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
layer.iconHaloColor = functionStyleValue;
mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
@"Setting iconHaloColor to a source function should update icon-halo-color.");
XCTAssertEqualObjects(layer.iconHaloColor, functionStyleValue,
@"iconHaloColor should round-trip source functions.");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
layer.iconHaloColor = functionStyleValue;
std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
@"Setting iconHaloColor to a composite function should update icon-halo-color.");
XCTAssertEqualObjects(layer.iconHaloColor, functionStyleValue,
@"iconHaloColor should round-trip composite functions.");
layer.iconHaloColor = nil;
@@ -1523,11 +1582,6 @@
@"Unsetting iconHaloColor should return icon-halo-color to the default value.");
XCTAssertEqualObjects(layer.iconHaloColor, defaultStyleValue,
@"iconHaloColor should return the default value after being unset.");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.iconHaloColor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.iconHaloColor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// icon-halo-width
@@ -1538,7 +1592,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.iconHaloWidth = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue,
@"Setting iconHaloWidth to a constant value should update icon-halo-width.");
XCTAssertEqualObjects(layer.iconHaloWidth, constantStyleValue,
@@ -1555,6 +1609,29 @@
XCTAssertEqualObjects(layer.iconHaloWidth, functionStyleValue,
@"iconHaloWidth should round-trip camera functions.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
layer.iconHaloWidth = functionStyleValue;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue,
@"Setting iconHaloWidth to a source function should update icon-halo-width.");
XCTAssertEqualObjects(layer.iconHaloWidth, functionStyleValue,
@"iconHaloWidth should round-trip source functions.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
layer.iconHaloWidth = functionStyleValue;
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->getIconHaloWidth(), propertyValue,
@"Setting iconHaloWidth to a composite function should update icon-halo-width.");
XCTAssertEqualObjects(layer.iconHaloWidth, functionStyleValue,
@"iconHaloWidth should round-trip composite functions.");
layer.iconHaloWidth = nil;
@@ -1562,11 +1639,6 @@
@"Unsetting iconHaloWidth should return icon-halo-width to the default value.");
XCTAssertEqualObjects(layer.iconHaloWidth, defaultStyleValue,
@"iconHaloWidth should return the default value after being unset.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.iconHaloWidth = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.iconHaloWidth = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// icon-opacity
@@ -1577,7 +1649,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.iconOpacity = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue,
@"Setting iconOpacity to a constant value should update icon-opacity.");
XCTAssertEqualObjects(layer.iconOpacity, constantStyleValue,
@@ -1594,6 +1666,29 @@
XCTAssertEqualObjects(layer.iconOpacity, functionStyleValue,
@"iconOpacity should round-trip camera functions.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
layer.iconOpacity = functionStyleValue;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue,
@"Setting iconOpacity to a source function should update icon-opacity.");
XCTAssertEqualObjects(layer.iconOpacity, functionStyleValue,
@"iconOpacity should round-trip source functions.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
layer.iconOpacity = functionStyleValue;
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->getIconOpacity(), propertyValue,
@"Setting iconOpacity to a composite function should update icon-opacity.");
XCTAssertEqualObjects(layer.iconOpacity, functionStyleValue,
@"iconOpacity should round-trip composite functions.");
layer.iconOpacity = nil;
@@ -1601,11 +1696,6 @@
@"Unsetting iconOpacity should return icon-opacity to the default value.");
XCTAssertEqualObjects(layer.iconOpacity, defaultStyleValue,
@"iconOpacity should return the default value after being unset.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.iconOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.iconOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// icon-translate
@@ -1700,7 +1790,7 @@
MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
layer.textColor = constantStyleValue;
mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
@"Setting textColor to a constant value should update text-color.");
XCTAssertEqualObjects(layer.textColor, constantStyleValue,
@@ -1717,6 +1807,29 @@
XCTAssertEqualObjects(layer.textColor, functionStyleValue,
@"textColor should round-trip camera functions.");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
layer.textColor = functionStyleValue;
mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
@"Setting textColor to a source function should update text-color.");
XCTAssertEqualObjects(layer.textColor, functionStyleValue,
@"textColor should round-trip source functions.");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
layer.textColor = functionStyleValue;
std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
@"Setting textColor to a composite function should update text-color.");
XCTAssertEqualObjects(layer.textColor, functionStyleValue,
@"textColor should round-trip composite functions.");
layer.textColor = nil;
@@ -1724,11 +1837,6 @@
@"Unsetting textColor should return text-color to the default value.");
XCTAssertEqualObjects(layer.textColor, defaultStyleValue,
@"textColor should return the default value after being unset.");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.textColor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.textColor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// text-halo-blur
@@ -1739,7 +1847,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.textHaloBlur = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue,
@"Setting textHaloBlur to a constant value should update text-halo-blur.");
XCTAssertEqualObjects(layer.textHaloBlur, constantStyleValue,
@@ -1756,6 +1864,29 @@
XCTAssertEqualObjects(layer.textHaloBlur, functionStyleValue,
@"textHaloBlur should round-trip camera functions.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
layer.textHaloBlur = functionStyleValue;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue,
@"Setting textHaloBlur to a source function should update text-halo-blur.");
XCTAssertEqualObjects(layer.textHaloBlur, functionStyleValue,
@"textHaloBlur should round-trip source functions.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
layer.textHaloBlur = functionStyleValue;
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->getTextHaloBlur(), propertyValue,
@"Setting textHaloBlur to a composite function should update text-halo-blur.");
XCTAssertEqualObjects(layer.textHaloBlur, functionStyleValue,
@"textHaloBlur should round-trip composite functions.");
layer.textHaloBlur = nil;
@@ -1763,11 +1894,6 @@
@"Unsetting textHaloBlur should return text-halo-blur to the default value.");
XCTAssertEqualObjects(layer.textHaloBlur, defaultStyleValue,
@"textHaloBlur should return the default value after being unset.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.textHaloBlur = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.textHaloBlur = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// text-halo-color
@@ -1778,7 +1904,7 @@
MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
layer.textHaloColor = constantStyleValue;
mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
@"Setting textHaloColor to a constant value should update text-halo-color.");
XCTAssertEqualObjects(layer.textHaloColor, constantStyleValue,
@@ -1795,6 +1921,29 @@
XCTAssertEqualObjects(layer.textHaloColor, functionStyleValue,
@"textHaloColor should round-trip camera functions.");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
layer.textHaloColor = functionStyleValue;
mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
@"Setting textHaloColor to a source function should update text-halo-color.");
XCTAssertEqualObjects(layer.textHaloColor, functionStyleValue,
@"textHaloColor should round-trip source functions.");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
layer.textHaloColor = functionStyleValue;
std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
@"Setting textHaloColor to a composite function should update text-halo-color.");
XCTAssertEqualObjects(layer.textHaloColor, functionStyleValue,
@"textHaloColor should round-trip composite functions.");
layer.textHaloColor = nil;
@@ -1802,11 +1951,6 @@
@"Unsetting textHaloColor should return text-halo-color to the default value.");
XCTAssertEqualObjects(layer.textHaloColor, defaultStyleValue,
@"textHaloColor should return the default value after being unset.");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.textHaloColor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.textHaloColor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// text-halo-width
@@ -1817,7 +1961,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.textHaloWidth = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue,
@"Setting textHaloWidth to a constant value should update text-halo-width.");
XCTAssertEqualObjects(layer.textHaloWidth, constantStyleValue,
@@ -1834,6 +1978,29 @@
XCTAssertEqualObjects(layer.textHaloWidth, functionStyleValue,
@"textHaloWidth should round-trip camera functions.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
layer.textHaloWidth = functionStyleValue;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue,
@"Setting textHaloWidth to a source function should update text-halo-width.");
XCTAssertEqualObjects(layer.textHaloWidth, functionStyleValue,
@"textHaloWidth should round-trip source functions.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
layer.textHaloWidth = functionStyleValue;
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->getTextHaloWidth(), propertyValue,
@"Setting textHaloWidth to a composite function should update text-halo-width.");
XCTAssertEqualObjects(layer.textHaloWidth, functionStyleValue,
@"textHaloWidth should round-trip composite functions.");
layer.textHaloWidth = nil;
@@ -1841,11 +2008,6 @@
@"Unsetting textHaloWidth should return text-halo-width to the default value.");
XCTAssertEqualObjects(layer.textHaloWidth, defaultStyleValue,
@"textHaloWidth should return the default value after being unset.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.textHaloWidth = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.textHaloWidth = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// text-opacity
@@ -1856,7 +2018,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.textOpacity = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue,
@"Setting textOpacity to a constant value should update text-opacity.");
XCTAssertEqualObjects(layer.textOpacity, constantStyleValue,
@@ -1873,6 +2035,29 @@
XCTAssertEqualObjects(layer.textOpacity, functionStyleValue,
@"textOpacity should round-trip camera functions.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
layer.textOpacity = functionStyleValue;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue,
@"Setting textOpacity to a source function should update text-opacity.");
XCTAssertEqualObjects(layer.textOpacity, functionStyleValue,
@"textOpacity should round-trip source functions.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
layer.textOpacity = functionStyleValue;
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->getTextOpacity(), propertyValue,
@"Setting textOpacity to a composite function should update text-opacity.");
XCTAssertEqualObjects(layer.textOpacity, functionStyleValue,
@"textOpacity should round-trip composite functions.");
layer.textOpacity = nil;
@@ -1880,11 +2065,6 @@
@"Unsetting textOpacity should return text-opacity to the default value.");
XCTAssertEqualObjects(layer.textOpacity, defaultStyleValue,
@"textOpacity should return the default value after being unset.");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.textOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
XCTAssertThrowsSpecificNamed(layer.textOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// text-translate

View File

@@ -47,7 +47,20 @@ global.evaluatedType = function (property) {
};
function attributeType(property, type) {
const name = property.name.replace(type + '-', '').replace('-', '_');
const attributeNameExceptions = {
'text-opacity': 'opacity',
'icon-opacity': 'opacity',
'text-color': 'fill_color',
'icon-color': 'fill_color',
'text-halo-color': 'halo_color',
'icon-halo-color': 'halo_color',
'text-halo-blur': 'halo_blur',
'icon-halo-blur': 'halo_blur',
'text-halo-width': 'halo_width',
'icon-halo-width': 'halo_width'
}
const name = attributeNameExceptions[property.name] ||
property.name.replace(type + '-', '').replace(/-/g, '_');
return `attributes::a_${name}${name === 'offset' ? '<1>' : ''}`;
}

View File

@@ -8,14 +8,23 @@
namespace mbgl {
class SymbolFeature {
class SymbolFeature : public GeometryTileFeature {
public:
FeatureType type;
SymbolFeature(std::unique_ptr<GeometryTileFeature> feature_) :
feature(std::move(feature_)),
geometry(feature->getGeometries()) // we need a mutable copy of the geometry for mergeLines()
{}
FeatureType getType() const override { return feature->getType(); }
optional<Value> getValue(const std::string& key) const override { return feature->getValue(key); };
std::unordered_map<std::string,Value> getProperties() const override { return feature->getProperties(); };
optional<FeatureIdentifier> getID() const override { return feature->getID(); };
GeometryCollection getGeometries() const override { return geometry; };
std::unique_ptr<GeometryTileFeature> feature;
GeometryCollection geometry;
optional<std::u16string> text;
optional<std::string> icon;
std::array<float, 2> iconOffset;
float iconRotation;
std::size_t index;
};

View File

@@ -10,7 +10,7 @@ SymbolInstance::SymbolInstance(Anchor& anchor, const GeometryCoordinates& line,
const SymbolLayoutProperties::Evaluated& layout, const bool addToBuffers, const uint32_t index_,
const float textBoxScale, const float textPadding, const SymbolPlacementType textPlacement,
const float iconBoxScale, const float iconPadding, const SymbolPlacementType iconPlacement,
const GlyphPositions& face, const IndexedSubfeature& indexedFeature) :
const GlyphPositions& face, const IndexedSubfeature& indexedFeature, const std::size_t featureIndex_) :
point(anchor.point),
index(index_),
hasText(shapedTextOrientations.first || shapedTextOrientations.second),
@@ -18,7 +18,8 @@ SymbolInstance::SymbolInstance(Anchor& anchor, const GeometryCoordinates& line,
// Create the collision features that will be used to check whether this symbol instance can be placed
textCollisionFeature(line, anchor, shapedTextOrientations.second ?: shapedTextOrientations.first, textBoxScale, textPadding, textPlacement, indexedFeature),
iconCollisionFeature(line, anchor, shapedIcon, iconBoxScale, iconPadding, iconPlacement, indexedFeature) {
iconCollisionFeature(line, anchor, shapedIcon, iconBoxScale, iconPadding, iconPlacement, indexedFeature),
featureIndex(featureIndex_) {
// Create the quads used for rendering the icon and glyphs.
if (addToBuffers) {

View File

@@ -17,7 +17,7 @@ public:
const style::SymbolLayoutProperties::Evaluated&, const bool inside, const uint32_t index,
const float textBoxScale, const float textPadding, style::SymbolPlacementType textPlacement,
const float iconBoxScale, const float iconPadding, style::SymbolPlacementType iconPlacement,
const GlyphPositions& face, const IndexedSubfeature& indexedfeature);
const GlyphPositions& face, const IndexedSubfeature& indexedfeature, const std::size_t featureIndex);
Point<float> point;
uint32_t index;
@@ -28,6 +28,7 @@ public:
CollisionFeature textCollisionFeature;
CollisionFeature iconCollisionFeature;
WritingModeType writingModes;
std::size_t featureIndex;
};
} // namespace mbgl

View File

@@ -87,7 +87,10 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
}
for (const auto& layer : layers) {
layerPaintProperties.emplace(layer->getID(), layer->as<SymbolLayer>()->impl->paint.evaluated);
layerPaintProperties.emplace(layer->getID(), std::make_pair(
layer->as<SymbolLayer>()->impl->iconPaintProperties(),
layer->as<SymbolLayer>()->impl->textPaintProperties()
));
}
// Determine and load glyph ranges
@@ -96,12 +99,13 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
auto feature = sourceLayer.getFeature(i);
if (!leader.filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
continue;
SymbolFeature ft(std::move(feature));
SymbolFeature ft;
ft.index = i;
auto getValue = [&feature](const std::string& key) -> std::string {
auto value = feature->getValue(key);
auto getValue = [&ft](const std::string& key) -> std::string {
auto value = ft.getValue(key);
if (!value)
return std::string();
if (value->is<std::string>())
@@ -118,12 +122,12 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
};
if (hasText) {
std::string u8string = layout.evaluate<TextField>(zoom, *feature);
std::string u8string = layout.evaluate<TextField>(zoom, ft);
if (layout.get<TextField>().isConstant()) {
u8string = util::replaceTokens(u8string, getValue);
}
auto textTransform = layout.evaluate<TextTransform>(zoom, *feature);
auto textTransform = layout.evaluate<TextTransform>(zoom, ft);
if (textTransform == TextTransformType::Uppercase) {
u8string = platform::uppercase(u8string);
@@ -144,13 +148,9 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
if (hasIcon) {
ft.icon = util::replaceTokens(layout.get<IconImage>(), getValue);
ft.iconOffset = layout.evaluate<IconOffset>(zoom, *feature);
ft.iconRotation = layout.evaluate<IconRotate>(zoom, *feature) * util::DEG2RAD;
}
if (ft.text || ft.icon) {
ft.type = feature->getType();
ft.geometry = feature->getGeometries();
features.push_back(std::move(ft));
}
}
@@ -229,7 +229,8 @@ void SymbolLayout::prepare(uintptr_t tileUID,
const bool textAlongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map &&
layout.get<SymbolPlacement>() == SymbolPlacementType::Line;
for (const auto& feature : features) {
for (auto it = features.begin(); it != features.end(); ++it) {
auto& feature = *it;
if (feature.geometry.empty()) continue;
std::pair<Shaping, Shaping> shapedTextOrientations;
@@ -273,7 +274,9 @@ void SymbolLayout::prepare(uintptr_t tileUID,
if (feature.icon) {
auto image = spriteAtlas.getIcon(*feature.icon);
if (image) {
shapedIcon = shapeIcon(*image, feature);
shapedIcon = shapeIcon(*image,
layout.evaluate<IconOffset>(zoom, feature),
layout.evaluate<IconRotate>(zoom, feature) * util::DEG2RAD);
assert((*image).spriteImage);
if ((*image).spriteImage->sdf) {
sdfIcons = true;
@@ -288,15 +291,17 @@ void SymbolLayout::prepare(uintptr_t tileUID,
// if either shapedText or icon position is present, add the feature
if (shapedTextOrientations.first || shapedIcon) {
addFeature(feature, shapedTextOrientations, shapedIcon, face);
addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, face);
}
feature.geometry.clear();
}
features.clear();
compareText.clear();
}
void SymbolLayout::addFeature(const SymbolFeature& feature,
void SymbolLayout::addFeature(const std::size_t index,
const SymbolFeature& feature,
const std::pair<Shaping, Shaping>& shapedTextOrientations,
const PositionedIcon& shapedIcon,
const GlyphPositions& face) {
@@ -345,8 +350,10 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, layout, addToBuffers, symbolInstances.size(),
textBoxScale, textPadding, textPlacement,
iconBoxScale, iconPadding, iconPlacement,
face, indexedFeature);
face, indexedFeature, index);
};
const auto& type = feature.getType();
if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
auto clippedLines = util::clipLines(feature.geometry, 0, 0, util::EXTENT, util::EXTENT);
@@ -368,7 +375,7 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
}
}
}
} else if (feature.type == FeatureType::Polygon) {
} else if (type == FeatureType::Polygon) {
for (const auto& polygon : classifyRings(feature.geometry)) {
Polygon<double> poly;
for (const auto& ring : polygon) {
@@ -384,12 +391,12 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
Anchor anchor(poi.x, poi.y, 0, minScale);
addSymbolInstance(polygon[0], anchor);
}
} else if (feature.type == FeatureType::LineString) {
} else if (type == FeatureType::LineString) {
for (const auto& line : feature.geometry) {
Anchor anchor(line[0].x, line[0].y, 0, minScale);
addSymbolInstance(line, anchor);
}
} else if (feature.type == FeatureType::Point) {
} else if (type == FeatureType::Point) {
for (const auto& points : feature.geometry) {
for (const auto& point : points) {
Anchor anchor(point.x, point.y, 0, minScale);
@@ -503,6 +510,12 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
keepUpright, iconPlacement, collisionTile.config.angle, symbolInstance.writingModes);
}
}
const auto& feature = features.at(symbolInstance.featureIndex);
for (auto& pair : bucket->paintPropertyBinders) {
pair.second.first.populateVertexVectors(feature, bucket->icon.vertices.vertexSize());
pair.second.second.populateVertexVectors(feature, bucket->text.vertices.vertexSize());
}
}
if (collisionTile.config.debug) {

View File

@@ -5,6 +5,7 @@
#include <mbgl/layout/symbol_feature.hpp>
#include <mbgl/layout/symbol_instance.hpp>
#include <mbgl/text/bidi.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <memory>
#include <map>
@@ -51,10 +52,12 @@ public:
State state = Pending;
std::unordered_map<std::string, style::SymbolPaintProperties::Evaluated> layerPaintProperties;
std::unordered_map<std::string,
std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>> layerPaintProperties;
private:
void addFeature(const SymbolFeature&,
void addFeature(const size_t,
const SymbolFeature&,
const std::pair<Shaping, Shaping>& shapedTextOrientations,
const PositionedIcon& shapedIcon,
const GlyphPositions& face);

View File

@@ -64,6 +64,34 @@ struct a_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
}
};
// used in the symbol sdf shader
struct a_fill_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
static auto name() { return "a_fill_color"; }
static Value value(const Color& color) {
return {{
gl::Normalized<uint8_t>(color.r),
gl::Normalized<uint8_t>(color.g),
gl::Normalized<uint8_t>(color.b),
gl::Normalized<uint8_t>(color.a)
}};
}
};
// used in the symbol sdf shader
struct a_halo_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
static auto name() { return "a_halo_color"; }
static Value value(const Color& color) {
return {{
gl::Normalized<uint8_t>(color.r),
gl::Normalized<uint8_t>(color.g),
gl::Normalized<uint8_t>(color.b),
gl::Normalized<uint8_t>(color.a)
}};
}
};
struct a_stroke_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
static auto name() { return "a_stroke_color"; }
@@ -171,5 +199,23 @@ struct a_offset<1> : gl::Attribute<float, 1> {
}
};
struct a_halo_width : gl::Attribute<float, 1> {
static auto name() { return "a_halo_width"; }
static Value value(float width) {
return {{ width }};
}
};
struct a_halo_blur : gl::Attribute<float, 1> {
static auto name() { return "a_halo_blur"; }
static Value value(float blur) {
return {{ blur }};
}
};
} // namespace attributes
} // namespace mbgl

View File

@@ -40,8 +40,8 @@ public:
LinePatternProgram linePattern;
RasterProgram raster;
SymbolIconProgram symbolIcon;
SymbolSDFProgram symbolIconSDF;
SymbolSDFProgram symbolGlyph;
SymbolSDFIconProgram symbolIconSDF;
SymbolSDFTextProgram symbolGlyph;
DebugProgram debug;
CollisionBoxProgram collisionBox;

View File

@@ -2,6 +2,7 @@
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/util/enum.hpp>
namespace mbgl {
@@ -19,6 +20,7 @@ Values makeValues(const style::SymbolPropertyValues& values,
std::array<float, 2> extrudeScale;
const float scale = values.paintSize / values.sdfScale;
if (values.pitchAlignment == AlignmentType::Map) {
extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom()) * scale);
} else {
@@ -27,7 +29,7 @@ Values makeValues(const style::SymbolPropertyValues& values,
pixelsToGLUnits[1] * scale * state.getCameraToCenterDistance()
}};
}
// adjust min/max zooms for variable font sies
float zoomAdjust = std::log(values.paintSize / values.layoutSize) / std::log(2);
@@ -35,7 +37,6 @@ Values makeValues(const style::SymbolPropertyValues& values,
uniforms::u_matrix::Value{ tile.translatedMatrix(values.translate,
values.translateAnchor,
state) },
uniforms::u_opacity::Value{ values.opacity },
uniforms::u_extrude_scale::Value{ extrudeScale },
uniforms::u_texsize::Value{ std::array<float, 2> {{ float(texsize.width) / 4, float(texsize.height) / 4 }} },
uniforms::u_zoom::Value{ float((state.getZoom() - zoomAdjust) * 10) },
@@ -62,84 +63,37 @@ SymbolIconProgram::uniformValues(const style::SymbolPropertyValues& values,
);
}
static SymbolSDFProgram::UniformValues makeSDFValues(const style::SymbolPropertyValues& values,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
const RenderTile& tile,
const TransformState& state,
float pixelRatio,
Color color,
float buffer,
float gammaAdjust)
{
// The default gamma value has to be adjust for the current pixelratio so that we're not
// drawing blurry font on retina screens.
const float gammaBase = 0.105 * values.sdfScale / values.paintSize / pixelRatio;
const float gammaScale = (values.pitchAlignment == AlignmentType::Map
? 1.0 / std::cos(state.getPitch())
: 1.0) / state.getCameraToCenterDistance();
return makeValues<SymbolSDFProgram::UniformValues>(
values,
texsize,
pixelsToGLUnits,
tile,
state,
uniforms::u_color::Value{ color },
uniforms::u_buffer::Value{ buffer },
uniforms::u_gamma::Value{ (gammaBase + gammaAdjust) * gammaScale },
uniforms::u_pitch::Value{ state.getPitch() },
uniforms::u_bearing::Value{ -1.0f * state.getAngle() },
uniforms::u_aspect_ratio::Value{ (state.getSize().width * 1.0f) / (state.getSize().height * 1.0f) },
uniforms::u_pitch_with_map::Value{ values.pitchAlignment == AlignmentType::Map }
);
}
SymbolSDFProgram::UniformValues
SymbolSDFProgram::haloUniformValues(const style::SymbolPropertyValues& values,
template <class PaintProperties>
typename SymbolSDFProgram<PaintProperties>::UniformValues SymbolSDFProgram<PaintProperties>::uniformValues(const style::SymbolPropertyValues& values,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
const RenderTile& tile,
const TransformState& state,
float pixelRatio)
const SymbolSDFPart part)
{
const float scale = values.paintSize / values.sdfScale;
const float sdfPx = 8.0f;
const float blurOffset = 1.19f;
const float haloOffset = 6.0f;
return makeSDFValues(
const float gammaScale = scale * (values.pitchAlignment == AlignmentType::Map
? std::cos(state.getPitch())
: 1.0) * state.getCameraToCenterDistance();
return makeValues<SymbolSDFProgram<PaintProperties>::UniformValues>(
values,
texsize,
pixelsToGLUnits,
tile,
state,
pixelRatio,
values.haloColor,
(haloOffset - values.haloWidth / scale) / sdfPx,
values.haloBlur * blurOffset / scale / sdfPx
uniforms::u_font_scale::Value{ scale },
uniforms::u_gamma_scale::Value{ gammaScale },
uniforms::u_pitch::Value{ state.getPitch() },
uniforms::u_bearing::Value{ -1.0f * state.getAngle() },
uniforms::u_aspect_ratio::Value{ (state.getSize().width * 1.0f) / (state.getSize().height * 1.0f) },
uniforms::u_pitch_with_map::Value{ values.pitchAlignment == AlignmentType::Map },
uniforms::u_is_halo::Value{ part == SymbolSDFPart::Halo }
);
}
SymbolSDFProgram::UniformValues
SymbolSDFProgram::foregroundUniformValues(const style::SymbolPropertyValues& values,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
const RenderTile& tile,
const TransformState& state,
float pixelRatio)
{
return makeSDFValues(
values,
texsize,
pixelsToGLUnits,
tile,
state,
pixelRatio,
values.color,
(256.0f - 64.0f) / 256.0f,
0
);
}
template class SymbolSDFProgram<style::IconPaintProperties>;
template class SymbolSDFProgram<style::TextPaintProperties>;
} // namespace mbgl

View File

@@ -8,6 +8,7 @@
#include <mbgl/util/geometry.hpp>
#include <mbgl/util/size.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <cmath>
#include <array>
@@ -27,9 +28,10 @@ MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_with_map);
MBGL_DEFINE_UNIFORM_SCALAR(bool, u_pitch_with_map);
MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_texture);
MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_fadetexture);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_buffer);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio);
MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_halo);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_font_scale);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma_scale);
} // namespace uniforms
struct SymbolLayoutAttributes : gl::Attributes<
@@ -75,14 +77,13 @@ class SymbolIconProgram : public Program<
SymbolLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
uniforms::u_opacity,
uniforms::u_extrude_scale,
uniforms::u_texsize,
uniforms::u_zoom,
uniforms::u_rotate_with_map,
uniforms::u_texture,
uniforms::u_fadetexture>,
style::SymbolPaintProperties>
style::IconPaintProperties>
{
public:
using Program::Program;
@@ -94,47 +95,73 @@ public:
const TransformState&);
};
enum class SymbolSDFPart {
Fill = 1,
Halo = 0
};
template <class PaintProperties>
class SymbolSDFProgram : public Program<
shaders::symbol_sdf,
gl::Triangle,
SymbolLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
uniforms::u_opacity,
uniforms::u_extrude_scale,
uniforms::u_texsize,
uniforms::u_zoom,
uniforms::u_rotate_with_map,
uniforms::u_texture,
uniforms::u_fadetexture,
uniforms::u_color,
uniforms::u_buffer,
uniforms::u_gamma,
uniforms::u_font_scale,
uniforms::u_gamma_scale,
uniforms::u_pitch,
uniforms::u_bearing,
uniforms::u_aspect_ratio,
uniforms::u_pitch_with_map>,
style::SymbolPaintProperties>
uniforms::u_pitch_with_map,
uniforms::u_is_halo>,
PaintProperties>
{
public:
using Program::Program;
using BaseProgram = Program<shaders::symbol_sdf,
gl::Triangle,
SymbolLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
uniforms::u_extrude_scale,
uniforms::u_texsize,
uniforms::u_zoom,
uniforms::u_rotate_with_map,
uniforms::u_texture,
uniforms::u_fadetexture,
uniforms::u_font_scale,
uniforms::u_gamma_scale,
uniforms::u_pitch,
uniforms::u_bearing,
uniforms::u_aspect_ratio,
uniforms::u_pitch_with_map,
uniforms::u_is_halo>,
PaintProperties>;
using UniformValues = typename BaseProgram::UniformValues;
static UniformValues haloUniformValues(const style::SymbolPropertyValues&,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
const RenderTile&,
const TransformState&,
float pixelRatio);
using BaseProgram::BaseProgram;
static UniformValues foregroundUniformValues(const style::SymbolPropertyValues&,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
const RenderTile&,
const TransformState&,
float pixelRatio);
static UniformValues uniformValues(const style::SymbolPropertyValues&,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
const RenderTile&,
const TransformState&,
const SymbolSDFPart);
};
using SymbolSDFIconProgram = SymbolSDFProgram<style::IconPaintProperties>;
using SymbolSDFTextProgram = SymbolSDFProgram<style::TextPaintProperties>;
using SymbolLayoutVertex = SymbolLayoutAttributes::Vertex;
using SymbolAttributes = SymbolIconProgram::Attributes;
using SymbolIconAttributes = SymbolIconProgram::Attributes;
using SymbolTextAttributes = SymbolSDFTextProgram::Attributes;
} // namespace mbgl

View File

@@ -33,7 +33,9 @@ void Painter::renderSymbol(PaintParameters& parameters,
auto draw = [&] (auto& program,
auto&& uniformValues,
const auto& buffers,
const SymbolPropertyValues& values_)
const SymbolPropertyValues& values_,
const auto& binders,
const auto& paintProperties)
{
// We clip symbols to their tile extent in still mode.
const bool needsClipping = frame.mapMode == MapMode::Still;
@@ -52,14 +54,15 @@ void Painter::renderSymbol(PaintParameters& parameters,
*buffers.vertexBuffer,
*buffers.indexBuffer,
buffers.segments,
bucket.paintPropertyBinders.at(layer.getID()),
layer.impl->paint.evaluated,
binders,
paintProperties,
state.getZoom()
);
};
if (bucket.hasIconData()) {
auto values = layer.impl->iconPropertyValues(layout);
auto paintPropertyValues = layer.impl->iconPaintProperties();
SpriteAtlas& atlas = *layer.impl->spriteAtlas;
const bool iconScaled = values.paintSize != 1.0f || frame.pixelRatio != atlas.getPixelRatio() || bucket.iconsNeedLinear;
@@ -69,24 +72,30 @@ void Painter::renderSymbol(PaintParameters& parameters,
const Size texsize = atlas.getSize();
if (bucket.sdfIcons) {
if (values.hasHalo()) {
if (values.hasHalo) {
draw(parameters.programs.symbolIconSDF,
SymbolSDFProgram::haloUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
SymbolSDFIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo),
bucket.icon,
values);
values,
bucket.paintPropertyBinders.at(layer.getID()).first,
paintPropertyValues);
}
if (values.hasForeground()) {
if (values.hasFill) {
draw(parameters.programs.symbolIconSDF,
SymbolSDFProgram::foregroundUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
SymbolSDFIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill),
bucket.icon,
values);
values,
bucket.paintPropertyBinders.at(layer.getID()).first,
paintPropertyValues);
}
} else {
draw(parameters.programs.symbolIcon,
SymbolIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state),
bucket.icon,
values);
values,
bucket.paintPropertyBinders.at(layer.getID()).first,
paintPropertyValues);
}
}
@@ -94,21 +103,26 @@ void Painter::renderSymbol(PaintParameters& parameters,
glyphAtlas->bind(context, 0);
auto values = layer.impl->textPropertyValues(layout);
auto paintPropertyValues = layer.impl->textPaintProperties();
const Size texsize = glyphAtlas->getSize();
if (values.hasHalo()) {
if (values.hasHalo) {
draw(parameters.programs.symbolGlyph,
SymbolSDFProgram::haloUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
SymbolSDFTextProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo),
bucket.text,
values);
values,
bucket.paintPropertyBinders.at(layer.getID()).second,
paintPropertyValues);
}
if (values.hasForeground()) {
if (values.hasFill) {
draw(parameters.programs.symbolGlyph,
SymbolSDFProgram::foregroundUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
SymbolSDFTextProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill),
bucket.text,
values);
values,
bucket.paintPropertyBinders.at(layer.getID()).second,
paintPropertyValues);
}
}

View File

@@ -9,7 +9,8 @@ namespace mbgl {
using namespace style;
SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::Evaluated layout_,
const std::unordered_map<std::string, style::SymbolPaintProperties::Evaluated>& layerPaintProperties,
const std::unordered_map<std::string, std::pair<
style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>& layerPaintProperties,
float zoom,
bool sdfIcons_,
bool iconsNeedLinear_)
@@ -17,8 +18,10 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::Evaluated layout_,
sdfIcons(sdfIcons_),
iconsNeedLinear(iconsNeedLinear_) {
for (const auto& pair : layerPaintProperties) {
paintPropertyBinders.emplace(pair.first,
SymbolIconProgram::PaintPropertyBinders(pair.second, zoom));
paintPropertyBinders.emplace(pair.first, std::make_pair(
SymbolIconProgram::PaintPropertyBinders(pair.second.first, zoom),
SymbolSDFTextProgram::PaintPropertyBinders(pair.second.second, zoom)
));
}
}
@@ -39,7 +42,8 @@ void SymbolBucket::upload(gl::Context& context) {
}
for (auto& pair : paintPropertyBinders) {
pair.second.upload(context);
pair.second.first.upload(context);
pair.second.second.upload(context);
}
uploaded = true;

View File

@@ -17,7 +17,7 @@ namespace mbgl {
class SymbolBucket : public Bucket {
public:
SymbolBucket(style::SymbolLayoutProperties::Evaluated,
const std::unordered_map<std::string, style::SymbolPaintProperties::Evaluated>&,
const std::unordered_map<std::string, std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>&,
float zoom,
bool sdfIcons,
bool iconsNeedLinear);
@@ -33,12 +33,14 @@ public:
const bool sdfIcons;
const bool iconsNeedLinear;
std::unordered_map<std::string, SymbolIconProgram::PaintPropertyBinders> paintPropertyBinders;
std::unordered_map<std::string, std::pair<
SymbolIconProgram::PaintPropertyBinders,
SymbolSDFTextProgram::PaintPropertyBinders>> paintPropertyBinders;
struct TextBuffer {
gl::VertexVector<SymbolLayoutVertex> vertices;
gl::IndexVector<gl::Triangles> triangles;
gl::SegmentVector<SymbolAttributes> segments;
gl::SegmentVector<SymbolTextAttributes> segments;
optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
@@ -47,7 +49,7 @@ public:
struct IconBuffer {
gl::VertexVector<SymbolLayoutVertex> vertices;
gl::IndexVector<gl::Triangles> triangles;
gl::SegmentVector<SymbolAttributes> segments;
gl::SegmentVector<SymbolIconAttributes> segments;
optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;

View File

@@ -66,6 +66,10 @@ attribute vec2 a_offset;
attribute vec2 a_texture_pos;
attribute vec4 a_data;
uniform lowp float a_opacity_t;
attribute lowp float a_opacity_min;
attribute lowp float a_opacity_max;
varying lowp float opacity;
// matrix is for the vertex position.
uniform mat4 u_matrix;
@@ -80,6 +84,8 @@ varying vec2 v_tex;
varying vec2 v_fade_tex;
void main() {
opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
vec2 a_tex = a_texture_pos.xy;
mediump float a_labelminzoom = a_data[0];
mediump vec2 a_zoom = a_data.pq;
@@ -122,13 +128,16 @@ precision mediump float;
#endif
uniform sampler2D u_texture;
uniform sampler2D u_fadetexture;
uniform lowp float u_opacity;
varying lowp float opacity;
varying vec2 v_tex;
varying vec2 v_fade_tex;
void main() {
lowp float alpha = texture2D(u_fadetexture, v_fade_tex).a * u_opacity;
lowp float alpha = texture2D(u_fadetexture, v_fade_tex).a * opacity;
gl_FragColor = texture2D(u_texture, v_tex) * alpha;
#ifdef OVERDRAW_INSPECTOR

View File

@@ -68,6 +68,26 @@ attribute vec2 a_offset;
attribute vec2 a_texture_pos;
attribute vec4 a_data;
uniform lowp float a_fill_color_t;
attribute lowp vec4 a_fill_color_min;
attribute lowp vec4 a_fill_color_max;
varying lowp vec4 fill_color;
uniform lowp float a_halo_color_t;
attribute lowp vec4 a_halo_color_min;
attribute lowp vec4 a_halo_color_max;
varying lowp vec4 halo_color;
uniform lowp float a_opacity_t;
attribute lowp float a_opacity_min;
attribute lowp float a_opacity_max;
varying lowp float opacity;
uniform lowp float a_halo_width_t;
attribute lowp float a_halo_width_min;
attribute lowp float a_halo_width_max;
varying lowp float halo_width;
uniform lowp float a_halo_blur_t;
attribute lowp float a_halo_blur_min;
attribute lowp float a_halo_blur_max;
varying lowp float halo_blur;
// matrix is for the vertex position.
uniform mat4 u_matrix;
@@ -87,6 +107,12 @@ varying vec2 v_fade_tex;
varying float v_gamma_scale;
void main() {
fill_color = mix(a_fill_color_min, a_fill_color_max, a_fill_color_t);
halo_color = mix(a_halo_color_min, a_halo_color_max, a_halo_color_t);
opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
halo_width = mix(a_halo_width_min, a_halo_width_max, a_halo_width_t);
halo_blur = mix(a_halo_blur_min, a_halo_blur_max, a_halo_blur_t);
vec2 a_tex = a_texture_pos.xy;
mediump float a_labelminzoom = a_data[0];
mediump vec2 a_zoom = a_data.pq;
@@ -163,24 +189,47 @@ precision mediump float;
#endif
#endif
#define SDF_PX 8.0
#define EDGE_GAMMA 0.105/DEVICE_PIXEL_RATIO
uniform bool u_is_halo;
varying lowp vec4 fill_color;
varying lowp vec4 halo_color;
varying lowp float opacity;
varying lowp float halo_width;
varying lowp float halo_blur;
uniform sampler2D u_texture;
uniform sampler2D u_fadetexture;
uniform lowp vec4 u_color;
uniform lowp float u_opacity;
uniform lowp float u_buffer;
uniform highp float u_gamma;
uniform lowp float u_font_scale;
uniform highp float u_gamma_scale;
varying vec2 v_tex;
varying vec2 v_fade_tex;
varying float v_gamma_scale;
void main() {
lowp vec4 color = fill_color;
lowp float gamma = EDGE_GAMMA / u_gamma_scale;
lowp float buff = (256.0 - 64.0) / 256.0;
if (u_is_halo) {
color = halo_color;
gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / u_gamma_scale;
buff = (6.0 - halo_width / u_font_scale) / SDF_PX;
}
lowp float dist = texture2D(u_texture, v_tex).a;
lowp float fade_alpha = texture2D(u_fadetexture, v_fade_tex).a;
highp float gamma = u_gamma * v_gamma_scale;
highp float alpha = smoothstep(u_buffer - gamma, u_buffer + gamma, dist) * fade_alpha;
highp float gamma_scaled = gamma * v_gamma_scale;
highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist) * fade_alpha;
gl_FragColor = u_color * (alpha * u_opacity);
gl_FragColor = color * (alpha * opacity);
#ifdef OVERDRAW_INSPECTOR
gl_FragColor = vec4(1.0);

View File

@@ -542,95 +542,115 @@ void SymbolLayer::setTextOptional(PropertyValue<bool> value) {
// Paint properties
PropertyValue<float> SymbolLayer::getDefaultIconOpacity() {
DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconOpacity() {
return { 1 };
}
PropertyValue<float> SymbolLayer::getIconOpacity(const optional<std::string>& klass) const {
DataDrivenPropertyValue<float> SymbolLayer::getIconOpacity(const optional<std::string>& klass) const {
return impl->paint.get<IconOpacity>(klass);
}
void SymbolLayer::setIconOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
void SymbolLayer::setIconOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getIconOpacity(klass))
return;
impl->paint.set<IconOpacity>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
if (value.isDataDriven()) {
impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
} else {
impl->observer->onLayerPaintPropertyChanged(*this);
}
}
void SymbolLayer::setIconOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
impl->paint.setTransition<IconOpacity>(value, klass);
}
PropertyValue<Color> SymbolLayer::getDefaultIconColor() {
DataDrivenPropertyValue<Color> SymbolLayer::getDefaultIconColor() {
return { Color::black() };
}
PropertyValue<Color> SymbolLayer::getIconColor(const optional<std::string>& klass) const {
DataDrivenPropertyValue<Color> SymbolLayer::getIconColor(const optional<std::string>& klass) const {
return impl->paint.get<IconColor>(klass);
}
void SymbolLayer::setIconColor(PropertyValue<Color> value, const optional<std::string>& klass) {
void SymbolLayer::setIconColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getIconColor(klass))
return;
impl->paint.set<IconColor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
if (value.isDataDriven()) {
impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
} else {
impl->observer->onLayerPaintPropertyChanged(*this);
}
}
void SymbolLayer::setIconColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
impl->paint.setTransition<IconColor>(value, klass);
}
PropertyValue<Color> SymbolLayer::getDefaultIconHaloColor() {
DataDrivenPropertyValue<Color> SymbolLayer::getDefaultIconHaloColor() {
return { {} };
}
PropertyValue<Color> SymbolLayer::getIconHaloColor(const optional<std::string>& klass) const {
DataDrivenPropertyValue<Color> SymbolLayer::getIconHaloColor(const optional<std::string>& klass) const {
return impl->paint.get<IconHaloColor>(klass);
}
void SymbolLayer::setIconHaloColor(PropertyValue<Color> value, const optional<std::string>& klass) {
void SymbolLayer::setIconHaloColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getIconHaloColor(klass))
return;
impl->paint.set<IconHaloColor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
if (value.isDataDriven()) {
impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
} else {
impl->observer->onLayerPaintPropertyChanged(*this);
}
}
void SymbolLayer::setIconHaloColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
impl->paint.setTransition<IconHaloColor>(value, klass);
}
PropertyValue<float> SymbolLayer::getDefaultIconHaloWidth() {
DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconHaloWidth() {
return { 0 };
}
PropertyValue<float> SymbolLayer::getIconHaloWidth(const optional<std::string>& klass) const {
DataDrivenPropertyValue<float> SymbolLayer::getIconHaloWidth(const optional<std::string>& klass) const {
return impl->paint.get<IconHaloWidth>(klass);
}
void SymbolLayer::setIconHaloWidth(PropertyValue<float> value, const optional<std::string>& klass) {
void SymbolLayer::setIconHaloWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getIconHaloWidth(klass))
return;
impl->paint.set<IconHaloWidth>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
if (value.isDataDriven()) {
impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
} else {
impl->observer->onLayerPaintPropertyChanged(*this);
}
}
void SymbolLayer::setIconHaloWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
impl->paint.setTransition<IconHaloWidth>(value, klass);
}
PropertyValue<float> SymbolLayer::getDefaultIconHaloBlur() {
DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconHaloBlur() {
return { 0 };
}
PropertyValue<float> SymbolLayer::getIconHaloBlur(const optional<std::string>& klass) const {
DataDrivenPropertyValue<float> SymbolLayer::getIconHaloBlur(const optional<std::string>& klass) const {
return impl->paint.get<IconHaloBlur>(klass);
}
void SymbolLayer::setIconHaloBlur(PropertyValue<float> value, const optional<std::string>& klass) {
void SymbolLayer::setIconHaloBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getIconHaloBlur(klass))
return;
impl->paint.set<IconHaloBlur>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
if (value.isDataDriven()) {
impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
} else {
impl->observer->onLayerPaintPropertyChanged(*this);
}
}
void SymbolLayer::setIconHaloBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) {
@@ -671,99 +691,119 @@ void SymbolLayer::setIconTranslateAnchor(PropertyValue<TranslateAnchorType> valu
impl->observer->onLayerPaintPropertyChanged(*this);
}
PropertyValue<float> SymbolLayer::getDefaultTextOpacity() {
return { 1 };
}
void SymbolLayer::setIconTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
impl->paint.setTransition<IconTranslateAnchor>(value, klass);
}
PropertyValue<float> SymbolLayer::getTextOpacity(const optional<std::string>& klass) const {
DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextOpacity() {
return { 1 };
}
DataDrivenPropertyValue<float> SymbolLayer::getTextOpacity(const optional<std::string>& klass) const {
return impl->paint.get<TextOpacity>(klass);
}
void SymbolLayer::setTextOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
void SymbolLayer::setTextOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getTextOpacity(klass))
return;
impl->paint.set<TextOpacity>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
}
PropertyValue<Color> SymbolLayer::getDefaultTextColor() {
return { Color::black() };
if (value.isDataDriven()) {
impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
} else {
impl->observer->onLayerPaintPropertyChanged(*this);
}
}
void SymbolLayer::setTextOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
impl->paint.setTransition<TextOpacity>(value, klass);
}
PropertyValue<Color> SymbolLayer::getTextColor(const optional<std::string>& klass) const {
DataDrivenPropertyValue<Color> SymbolLayer::getDefaultTextColor() {
return { Color::black() };
}
DataDrivenPropertyValue<Color> SymbolLayer::getTextColor(const optional<std::string>& klass) const {
return impl->paint.get<TextColor>(klass);
}
void SymbolLayer::setTextColor(PropertyValue<Color> value, const optional<std::string>& klass) {
void SymbolLayer::setTextColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getTextColor(klass))
return;
impl->paint.set<TextColor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
if (value.isDataDriven()) {
impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
} else {
impl->observer->onLayerPaintPropertyChanged(*this);
}
}
void SymbolLayer::setTextColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
impl->paint.setTransition<TextColor>(value, klass);
}
PropertyValue<Color> SymbolLayer::getDefaultTextHaloColor() {
DataDrivenPropertyValue<Color> SymbolLayer::getDefaultTextHaloColor() {
return { {} };
}
PropertyValue<Color> SymbolLayer::getTextHaloColor(const optional<std::string>& klass) const {
DataDrivenPropertyValue<Color> SymbolLayer::getTextHaloColor(const optional<std::string>& klass) const {
return impl->paint.get<TextHaloColor>(klass);
}
void SymbolLayer::setTextHaloColor(PropertyValue<Color> value, const optional<std::string>& klass) {
void SymbolLayer::setTextHaloColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getTextHaloColor(klass))
return;
impl->paint.set<TextHaloColor>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
if (value.isDataDriven()) {
impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
} else {
impl->observer->onLayerPaintPropertyChanged(*this);
}
}
void SymbolLayer::setTextHaloColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
impl->paint.setTransition<TextHaloColor>(value, klass);
}
PropertyValue<float> SymbolLayer::getDefaultTextHaloWidth() {
DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextHaloWidth() {
return { 0 };
}
PropertyValue<float> SymbolLayer::getTextHaloWidth(const optional<std::string>& klass) const {
DataDrivenPropertyValue<float> SymbolLayer::getTextHaloWidth(const optional<std::string>& klass) const {
return impl->paint.get<TextHaloWidth>(klass);
}
void SymbolLayer::setTextHaloWidth(PropertyValue<float> value, const optional<std::string>& klass) {
void SymbolLayer::setTextHaloWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getTextHaloWidth(klass))
return;
impl->paint.set<TextHaloWidth>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
if (value.isDataDriven()) {
impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
} else {
impl->observer->onLayerPaintPropertyChanged(*this);
}
}
void SymbolLayer::setTextHaloWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
impl->paint.setTransition<TextHaloWidth>(value, klass);
}
PropertyValue<float> SymbolLayer::getDefaultTextHaloBlur() {
DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextHaloBlur() {
return { 0 };
}
PropertyValue<float> SymbolLayer::getTextHaloBlur(const optional<std::string>& klass) const {
DataDrivenPropertyValue<float> SymbolLayer::getTextHaloBlur(const optional<std::string>& klass) const {
return impl->paint.get<TextHaloBlur>(klass);
}
void SymbolLayer::setTextHaloBlur(PropertyValue<float> value, const optional<std::string>& klass) {
void SymbolLayer::setTextHaloBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getTextHaloBlur(klass))
return;
impl->paint.set<TextHaloBlur>(value, klass);
impl->observer->onLayerPaintPropertyChanged(*this);
if (value.isDataDriven()) {
impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
} else {
impl->observer->onLayerPaintPropertyChanged(*this);
}
}
void SymbolLayer::setTextHaloBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) {

View File

@@ -16,9 +16,14 @@ bool SymbolLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters)
// text-size and icon-size are layout properties but they also need to be evaluated as paint properties:
iconSize = layout.evaluate<IconSize>(parameters);
textSize = layout.evaluate<TextSize>(parameters);
passes = ((paint.evaluated.get<IconOpacity>() > 0 && (paint.evaluated.get<IconColor>().a > 0 || paint.evaluated.get<IconHaloColor>().a > 0) && iconSize > 0)
|| (paint.evaluated.get<TextOpacity>() > 0 && (paint.evaluated.get<TextColor>().a > 0 || paint.evaluated.get<TextHaloColor>().a > 0) && textSize > 0))
auto hasIconOpacity = paint.evaluated.get<IconColor>().constantOr(Color::black()).a > 0 ||
paint.evaluated.get<IconHaloColor>().constantOr(Color::black()).a > 0;
auto hasTextOpacity = paint.evaluated.get<TextColor>().constantOr(Color::black()).a > 0 ||
paint.evaluated.get<TextHaloColor>().constantOr(Color::black()).a > 0;
passes = ((paint.evaluated.get<IconOpacity>().constantOr(1) > 0 && hasIconOpacity && iconSize > 0)
|| (paint.evaluated.get<TextOpacity>().constantOr(1) > 0 && hasTextOpacity && textSize > 0))
? RenderPass::Translucent : RenderPass::None;
return paint.hasTransition();
@@ -38,20 +43,43 @@ std::unique_ptr<SymbolLayout> SymbolLayer::Impl::createLayout(const BucketParame
*spriteAtlas);
}
SymbolPropertyValues SymbolLayer::Impl::iconPropertyValues(const SymbolLayoutProperties::Evaluated& layout_) const {
return SymbolPropertyValues {
layout_.get<IconRotationAlignment>(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment
layout_.get<IconRotationAlignment>(),
layout_.get<IconSize>(),
IconPaintProperties::Evaluated SymbolLayer::Impl::iconPaintProperties() const {
return IconPaintProperties::Evaluated {
paint.evaluated.get<IconOpacity>(),
paint.evaluated.get<IconColor>(),
paint.evaluated.get<IconHaloColor>(),
paint.evaluated.get<IconHaloWidth>(),
paint.evaluated.get<IconHaloBlur>(),
paint.evaluated.get<IconTranslate>(),
paint.evaluated.get<IconTranslateAnchor>()
};
}
TextPaintProperties::Evaluated SymbolLayer::Impl::textPaintProperties() const {
return TextPaintProperties::Evaluated {
paint.evaluated.get<TextOpacity>(),
paint.evaluated.get<TextColor>(),
paint.evaluated.get<TextHaloColor>(),
paint.evaluated.get<TextHaloWidth>(),
paint.evaluated.get<TextHaloBlur>(),
paint.evaluated.get<TextTranslate>(),
paint.evaluated.get<TextTranslateAnchor>()
};
}
SymbolPropertyValues SymbolLayer::Impl::iconPropertyValues(const SymbolLayoutProperties::Evaluated& layout_) const {
return SymbolPropertyValues {
layout_.get<IconRotationAlignment>(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment
layout_.get<IconRotationAlignment>(),
layout_.get<IconSize>(),
paint.evaluated.get<IconTranslate>(),
paint.evaluated.get<IconTranslateAnchor>(),
iconSize,
1.0f
1.0f,
paint.evaluated.get<IconHaloColor>().constantOr(Color::black()).a > 0 &&
paint.evaluated.get<IconHaloWidth>().constantOr(1),
paint.evaluated.get<IconColor>().constantOr(Color::black()).a > 0
};
}
@@ -60,15 +88,13 @@ SymbolPropertyValues SymbolLayer::Impl::textPropertyValues(const SymbolLayoutPro
layout_.get<TextPitchAlignment>(),
layout_.get<TextRotationAlignment>(),
layout_.get<TextSize>(),
paint.evaluated.get<TextOpacity>(),
paint.evaluated.get<TextColor>(),
paint.evaluated.get<TextHaloColor>(),
paint.evaluated.get<TextHaloWidth>(),
paint.evaluated.get<TextHaloBlur>(),
paint.evaluated.get<TextTranslate>(),
paint.evaluated.get<TextTranslateAnchor>(),
textSize,
24.0f
24.0f,
paint.evaluated.get<TextHaloColor>().constantOr(Color::black()).a > 0 &&
paint.evaluated.get<TextHaloWidth>().constantOr(1),
paint.evaluated.get<TextColor>().constantOr(Color::black()).a > 0
};
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include <mbgl/util/variant.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
@@ -10,6 +11,30 @@ class SpriteAtlas;
class SymbolLayout;
namespace style {
// {icon,text}-specific paint-property packs for use in the symbol Programs.
// Since each program deals either with icons or text, using a smaller property set
// lets us avoid unnecessarily binding attributes for properties the program wouldn't use.
class IconPaintProperties : public PaintProperties<
IconOpacity,
IconColor,
IconHaloColor,
IconHaloWidth,
IconHaloBlur,
IconTranslate,
IconTranslateAnchor
> {};
class TextPaintProperties : public PaintProperties<
TextOpacity,
TextColor,
TextHaloColor,
TextHaloWidth,
TextHaloBlur,
TextTranslate,
TextTranslateAnchor
> {};
// Repackaging evaluated values from SymbolLayoutProperties + SymbolPaintProperties
// for genericity over icons vs. text.
@@ -21,24 +46,14 @@ public:
float layoutSize;
// Paint
float opacity;
Color color;
Color haloColor;
float haloWidth;
float haloBlur;
std::array<float, 2> translate;
TranslateAnchorType translateAnchor;
float paintSize;
float sdfScale; // Constant (1.0 or 24.0)
bool hasHalo() const {
return haloColor.a > 0.0f && haloWidth > 0.0f;
}
bool hasForeground() const {
return color.a > 0.0f;
}
bool hasHalo;
bool hasFill;
};
class SymbolLayer::Impl : public Layer::Impl {
@@ -54,6 +69,9 @@ public:
std::unique_ptr<SymbolLayout> createLayout(const BucketParameters&, const std::vector<const Layer*>&,
const GeometryTileLayer&) const;
IconPaintProperties::Evaluated iconPaintProperties() const;
TextPaintProperties::Evaluated textPaintProperties() const;
SymbolPropertyValues iconPropertyValues(const SymbolLayoutProperties::Evaluated&) const;
SymbolPropertyValues textPropertyValues(const SymbolLayoutProperties::Evaluated&) const;

View File

@@ -180,23 +180,23 @@ struct TextOptional : LayoutProperty<bool> {
static bool defaultValue() { return false; }
};
struct IconOpacity : PaintProperty<float> {
struct IconOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> {
static float defaultValue() { return 1; }
};
struct IconColor : PaintProperty<Color> {
struct IconColor : DataDrivenPaintProperty<Color, attributes::a_fill_color> {
static Color defaultValue() { return Color::black(); }
};
struct IconHaloColor : PaintProperty<Color> {
struct IconHaloColor : DataDrivenPaintProperty<Color, attributes::a_halo_color> {
static Color defaultValue() { return {}; }
};
struct IconHaloWidth : PaintProperty<float> {
struct IconHaloWidth : DataDrivenPaintProperty<float, attributes::a_halo_width> {
static float defaultValue() { return 0; }
};
struct IconHaloBlur : PaintProperty<float> {
struct IconHaloBlur : DataDrivenPaintProperty<float, attributes::a_halo_blur> {
static float defaultValue() { return 0; }
};
@@ -208,23 +208,23 @@ struct IconTranslateAnchor : PaintProperty<TranslateAnchorType> {
static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; }
};
struct TextOpacity : PaintProperty<float> {
struct TextOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> {
static float defaultValue() { return 1; }
};
struct TextColor : PaintProperty<Color> {
struct TextColor : DataDrivenPaintProperty<Color, attributes::a_fill_color> {
static Color defaultValue() { return Color::black(); }
};
struct TextHaloColor : PaintProperty<Color> {
struct TextHaloColor : DataDrivenPaintProperty<Color, attributes::a_halo_color> {
static Color defaultValue() { return {}; }
};
struct TextHaloWidth : PaintProperty<float> {
struct TextHaloWidth : DataDrivenPaintProperty<float, attributes::a_halo_width> {
static float defaultValue() { return 0; }
};
struct TextHaloBlur : PaintProperty<float> {
struct TextHaloBlur : DataDrivenPaintProperty<float, attributes::a_halo_blur> {
static float defaultValue() { return 0; }
};

View File

@@ -3,16 +3,15 @@
namespace mbgl {
PositionedIcon shapeIcon(const SpriteAtlasElement& image,
const SymbolFeature& feature) {
float dx = feature.iconOffset[0];
float dy = feature.iconOffset[1];
PositionedIcon shapeIcon(const SpriteAtlasElement& image, const std::array<float, 2>& iconOffset, const float iconRotation) {
float dx = iconOffset[0];
float dy = iconOffset[1];
float x1 = dx - image.spriteImage->getWidth() / 2.0f;
float x2 = x1 + image.spriteImage->getWidth();
float y1 = dy - image.spriteImage->getHeight() / 2.0f;
float y2 = y1 + image.spriteImage->getHeight();
return PositionedIcon(image, y1, y2, x1, x2, feature.iconRotation);
return PositionedIcon(image, y1, y2, x1, x2, iconRotation);
}
} // namespace mbgl

View File

@@ -36,7 +36,6 @@ public:
explicit operator bool() const { return image && (*image).pos.hasArea(); }
};
PositionedIcon shapeIcon(const SpriteAtlasElement&,
const SymbolFeature&);
PositionedIcon shapeIcon(const SpriteAtlasElement&, const std::array<float, 2>& iconOffset, const float iconRotation);
} // namespace mbgl

View File

@@ -15,9 +15,23 @@ class VectorTileLayer;
using packed_iter_type = protozero::iterator_range<protozero::pbf_reader::const_uint32_iterator>;
struct VectorTileLayerData {
VectorTileLayerData(std::shared_ptr<const std::string>);
// Hold a reference to the underlying pbf data that backs the lazily-built
// components of the owning VectorTileLayer and VectorTileFeature objects
std::shared_ptr<const std::string> data;
uint32_t version = 1;
uint32_t extent = 4096;
std::unordered_map<std::string, uint32_t> keysMap;
std::vector<std::reference_wrapper<const std::string>> keys;
std::vector<Value> values;
};
class VectorTileFeature : public GeometryTileFeature {
public:
VectorTileFeature(protozero::pbf_reader, const VectorTileLayer&);
VectorTileFeature(protozero::pbf_reader, std::shared_ptr<VectorTileLayerData> layerData);
FeatureType getType() const override { return type; }
optional<Value> getValue(const std::string&) const override;
@@ -26,16 +40,16 @@ public:
GeometryCollection getGeometries() const override;
private:
const VectorTileLayer& layer;
std::shared_ptr<VectorTileLayerData> layerData;
optional<FeatureIdentifier> id;
FeatureType type = FeatureType::Unknown;
packed_iter_type tags_iter;
packed_iter_type geometry_iter;
};
class VectorTileLayer : public GeometryTileLayer {
public:
VectorTileLayer(protozero::pbf_reader);
VectorTileLayer(protozero::pbf_reader, std::shared_ptr<const std::string>);
std::size_t featureCount() const override { return features.size(); }
std::unique_ptr<GeometryTileFeature> getFeature(std::size_t) const override;
@@ -46,12 +60,8 @@ private:
friend class VectorTileFeature;
std::string name;
uint32_t version = 1;
uint32_t extent = 4096;
std::unordered_map<std::string, uint32_t> keysMap;
std::vector<std::reference_wrapper<const std::string>> keys;
std::vector<Value> values;
std::vector<protozero::pbf_reader> features;
std::shared_ptr<VectorTileLayerData> data;
};
class VectorTileData : public GeometryTileData {
@@ -117,8 +127,8 @@ Value parseValue(protozero::pbf_reader data) {
return false;
}
VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf, const VectorTileLayer& layer_)
: layer(layer_) {
VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf, std::shared_ptr<VectorTileLayerData> layerData_)
: layerData(std::move(layerData_)) {
while (feature_pbf.next()) {
switch (feature_pbf.tag()) {
case 1: // id
@@ -141,8 +151,8 @@ VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf, const Ve
}
optional<Value> VectorTileFeature::getValue(const std::string& key) const {
auto keyIter = layer.keysMap.find(key);
if (keyIter == layer.keysMap.end()) {
auto keyIter = layerData->keysMap.find(key);
if (keyIter == layerData->keysMap.end()) {
return optional<Value>();
}
@@ -151,7 +161,7 @@ optional<Value> VectorTileFeature::getValue(const std::string& key) const {
while (start_itr != end_itr) {
uint32_t tag_key = static_cast<uint32_t>(*start_itr++);
if (layer.keysMap.size() <= tag_key) {
if (layerData->keysMap.size() <= tag_key) {
throw std::runtime_error("feature referenced out of range key");
}
@@ -160,12 +170,12 @@ optional<Value> VectorTileFeature::getValue(const std::string& key) const {
}
uint32_t tag_val = static_cast<uint32_t>(*start_itr++);;
if (layer.values.size() <= tag_val) {
if (layerData->values.size() <= tag_val) {
throw std::runtime_error("feature referenced out of range value");
}
if (tag_key == keyIter->second) {
return layer.values[tag_val];
return layerData->values[tag_val];
}
}
@@ -182,7 +192,7 @@ std::unordered_map<std::string,Value> VectorTileFeature::getProperties() const {
throw std::runtime_error("uneven number of feature tag ids");
}
uint32_t tag_val = static_cast<uint32_t>(*start_itr++);
properties[layer.keys.at(tag_key)] = layer.values.at(tag_val);
properties[layerData->keys.at(tag_key)] = layerData->values.at(tag_val);
}
return properties;
}
@@ -196,7 +206,7 @@ GeometryCollection VectorTileFeature::getGeometries() const {
uint32_t length = 0;
int32_t x = 0;
int32_t y = 0;
const float scale = float(util::EXTENT) / layer.extent;
const float scale = float(util::EXTENT) / layerData->extent;
GeometryCollection lines;
@@ -234,7 +244,7 @@ GeometryCollection VectorTileFeature::getGeometries() const {
}
}
if (layer.version >= 2 || type != FeatureType::Polygon) {
if (layerData->version >= 2 || type != FeatureType::Polygon) {
return lines;
}
@@ -250,7 +260,7 @@ const GeometryTileLayer* VectorTileData::getLayer(const std::string& name) const
parsed = true;
protozero::pbf_reader tile_pbf(*data);
while (tile_pbf.next(3)) {
VectorTileLayer layer(tile_pbf.get_message());
VectorTileLayer layer(tile_pbf.get_message(), data);
layers.emplace(layer.name, std::move(layer));
}
}
@@ -262,7 +272,13 @@ const GeometryTileLayer* VectorTileData::getLayer(const std::string& name) const
return nullptr;
}
VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf) {
VectorTileLayerData::VectorTileLayerData(std::shared_ptr<const std::string> pbfData) :
data(std::move(pbfData))
{}
VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf, std::shared_ptr<const std::string> pbfData)
: data(std::make_shared<VectorTileLayerData>(std::move(pbfData)))
{
while (layer_pbf.next()) {
switch (layer_pbf.tag()) {
case 1: // name
@@ -273,18 +289,18 @@ VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf) {
break;
case 3: // keys
{
auto iter = keysMap.emplace(layer_pbf.get_string(), keysMap.size());
keys.emplace_back(std::reference_wrapper<const std::string>(iter.first->first));
auto iter = data->keysMap.emplace(layer_pbf.get_string(), data->keysMap.size());
data->keys.emplace_back(std::reference_wrapper<const std::string>(iter.first->first));
}
break;
case 4: // values
values.emplace_back(parseValue(layer_pbf.get_message()));
data->values.emplace_back(parseValue(layer_pbf.get_message()));
break;
case 5: // extent
extent = layer_pbf.get_uint32();
data->extent = layer_pbf.get_uint32();
break;
case 15: // version
version = layer_pbf.get_uint32();
data->version = layer_pbf.get_uint32();
break;
default:
layer_pbf.skip();
@@ -294,7 +310,7 @@ VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf) {
}
std::unique_ptr<GeometryTileFeature> VectorTileLayer::getFeature(std::size_t i) const {
return std::make_unique<VectorTileFeature>(features.at(i), *this);
return std::make_unique<VectorTileFeature>(features.at(i), data);
}
std::string VectorTileLayer::getName() const {

View File

@@ -61,9 +61,11 @@ TEST(VectorTile, Issue7615) {
style::SymbolLayer symbolLayer("symbol", "source");
auto symbolBucket = std::make_shared<SymbolBucket>(
style::SymbolLayoutProperties::Evaluated(),
std::unordered_map<std::string, style::SymbolPaintProperties::Evaluated>(),
std::unordered_map<
std::string,
std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>(),
0.0f, false, false);
// Simulate placement of a symbol layer.
tile.onPlacement(GeometryTile::PlacementResult {
{{

View File

@@ -8,95 +8,131 @@ const std::u16string bbb = u"b";
using namespace mbgl;
class GeometryTileFeatureStub : public GeometryTileFeature {
public:
GeometryTileFeatureStub(optional<FeatureIdentifier> id_, FeatureType type_, GeometryCollection geometry_,
std::unordered_map<std::string, Value> properties_) :
id(id_),
type(type_),
geometry(geometry_),
properties(properties_)
{}
FeatureType getType() const override { return type; }
optional<Value> getValue(const std::string& key) const override {
auto it = properties.find(key);
if (it != properties.end()) {
return it->second;
}
return {};
};
std::unordered_map<std::string,Value> getProperties() const override { return properties; };
optional<FeatureIdentifier> getID() const override { return id; };
GeometryCollection getGeometries() const override { return geometry; };
optional<FeatureIdentifier> id;
FeatureType type;
GeometryCollection geometry;
std::unordered_map<std::string,Value> properties;
};
class SymbolFeatureStub : public SymbolFeature {
public:
SymbolFeatureStub(optional<FeatureIdentifier> id_, FeatureType type_, GeometryCollection geometry_,
std::unordered_map<std::string, Value> properties_, optional<std::u16string> text_,
optional<std::string> icon_, std::size_t index_) :
SymbolFeature(std::make_unique<GeometryTileFeatureStub>(id_, type_, geometry_, properties_))
{
text = text_;
icon = icon_;
index = index_;
}
};
TEST(MergeLines, SameText) {
// merges lines with the same text
std::vector<mbgl::SymbolFeature> input1 = {
{ FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, bbb, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{{8, 0}, {9, 0}}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{{6, 0}, {7, 0}, {8, 0}}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{{5, 0}, {6, 0}}}, aaa, {}, {{0, 0}}, 0, 0 }
};
std::vector<mbgl::SymbolFeature> input1;
input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, {}, aaa, {}, 0));
input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, {}, bbb, {}, 0));
input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{8, 0}, {9, 0}}}, {}, aaa, {}, 0));
input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, {}, aaa, {}, 0));
input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{6, 0}, {7, 0}, {8, 0}}}, {}, aaa, {}, 0));
input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{5, 0}, {6, 0}}}, {}, aaa, {}, 0));
const std::vector<mbgl::SymbolFeature> expected1 = {
{ FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, bbb, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{{5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{}}, aaa, {}, {{0, 0}}, 0, 0 }
const std::vector<GeometryTileFeatureStub> expected1 = {
{ {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}}, {} },
{ {}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, {} },
{ {}, FeatureType::LineString, {{{5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}}}, {} },
{ {}, FeatureType::LineString, {{}}, {} },
{ {}, FeatureType::LineString, {{}}, {} },
{ {}, FeatureType::LineString, {{}}, {} }
};
mbgl::util::mergeLines(input1);
for (int i = 0; i < 6; i++) {
EXPECT_TRUE(input1[i].geometry == expected1[i].geometry);
EXPECT_TRUE(input1[i].geometry == expected1[i].getGeometries());
}
}
TEST(MergeLines, BothEnds) {
// mergeLines handles merge from both ends
std::vector<mbgl::SymbolFeature> input2 = {
{ FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, {{0, 0}}, 0, 0 }
};
std::vector<mbgl::SymbolFeature> input2;
input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, {}, aaa, {}, 0 });
input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, {}, aaa, {}, 0 });
input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, {}, aaa, {}, 0 });
const std::vector<mbgl::SymbolFeature> expected2 = {
{ FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{}}, aaa, {}, {{0, 0}}, 0, 0 }
const std::vector<GeometryTileFeatureStub> expected2 = {
{ {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}}}, {} },
{ {}, FeatureType::LineString, {{}}, {} },
{ {}, FeatureType::LineString, {{}}, {} }
};
mbgl::util::mergeLines(input2);
for (int i = 0; i < 3; i++) {
EXPECT_TRUE(input2[i].geometry == expected2[i].geometry);
EXPECT_TRUE(input2[i].geometry == expected2[i].getGeometries());
}
}
TEST(MergeLines, CircularLines) {
// mergeLines handles circular lines
std::vector<mbgl::SymbolFeature> input3 = {
{ FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{{4, 0}, {0, 0}}}, aaa, {}, {{0, 0}}, 0, 0 }
};
std::vector<mbgl::SymbolFeature> input3;
input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, {}, aaa, {}, 0 });
input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, {}, aaa, {}, 0 });
input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{4, 0}, {0, 0}}}, {}, aaa, {}, 0 });
const std::vector<mbgl::SymbolFeature> expected3 = {
{ FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 0}}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{}}, aaa, {}, {{0, 0}}, 0, 0 },
{ FeatureType::LineString, {{}}, aaa, {}, {{0, 0}}, 0, 0 }
const std::vector<GeometryTileFeatureStub> expected3 = {
{ {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 0}}}, {} },
{ {}, FeatureType::LineString, {{}}, {} },
{ {}, FeatureType::LineString, {{}}, {} }
};
mbgl::util::mergeLines(input3);
for (int i = 0; i < 3; i++) {
EXPECT_TRUE(input3[i].geometry == expected3[i].geometry);
EXPECT_TRUE(input3[i].geometry == expected3[i].getGeometries());
}
}
TEST(MergeLines, EmptyOuterGeometry) {
std::vector<mbgl::SymbolFeature> input = {
{ FeatureType::LineString, {}, aaa, {}, {{0, 0}}, 0, 0 },
};
std::vector<mbgl::SymbolFeature> input;
input.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {}, {}, aaa, {}, 0 });
const std::vector<mbgl::SymbolFeature> expected = input;
const std::vector<GeometryTileFeatureStub> expected = { { {}, FeatureType::LineString, {}, {} } };
mbgl::util::mergeLines(input);
EXPECT_EQ(expected[0].geometry, input[0].geometry);
EXPECT_EQ(input[0].geometry, expected[0].getGeometries());
}
TEST(MergeLines, EmptyInnerGeometry) {
std::vector<mbgl::SymbolFeature> input = {
{ FeatureType::LineString, {{}}, aaa, {}, {{0, 0}}, 0, 0 },
};
std::vector<mbgl::SymbolFeature> input;
input.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{}}, {}, aaa, {}, 0 });
const std::vector<mbgl::SymbolFeature> expected = input;
const std::vector<GeometryTileFeatureStub> expected = { { {}, FeatureType::LineString, {{}}, {} } };
mbgl::util::mergeLines(input);
EXPECT_EQ(expected[0].geometry, input[0].geometry);
EXPECT_EQ(input[0].geometry, expected[0].getGeometries());
}