[core] Update shaders.
Implements 'icon-pitch-alignment' (issue #9345) Fixes issue #9456 (map-aligned point label regression)
This commit is contained in:
@@ -45,6 +45,7 @@ auto makeLayoutPropertySetters() {
|
||||
result["icon-padding"] = &setProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setIconPadding>;
|
||||
result["icon-keep-upright"] = &setProperty<V, SymbolLayer, PropertyValue<bool>, &SymbolLayer::setIconKeepUpright>;
|
||||
result["icon-offset"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<std::array<float, 2>>, &SymbolLayer::setIconOffset>;
|
||||
result["icon-pitch-alignment"] = &setProperty<V, SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setIconPitchAlignment>;
|
||||
result["text-pitch-alignment"] = &setProperty<V, SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setTextPitchAlignment>;
|
||||
result["text-rotation-alignment"] = &setProperty<V, SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setTextRotationAlignment>;
|
||||
result["text-field"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<std::string>, &SymbolLayer::setTextField>;
|
||||
|
||||
@@ -98,6 +98,10 @@ public:
|
||||
DataDrivenPropertyValue<std::array<float, 2>> getIconOffset() const;
|
||||
void setIconOffset(DataDrivenPropertyValue<std::array<float, 2>>);
|
||||
|
||||
static PropertyValue<AlignmentType> getDefaultIconPitchAlignment();
|
||||
PropertyValue<AlignmentType> getIconPitchAlignment() const;
|
||||
void setIconPitchAlignment(PropertyValue<AlignmentType>);
|
||||
|
||||
static PropertyValue<AlignmentType> getDefaultTextPitchAlignment();
|
||||
PropertyValue<AlignmentType> getTextPitchAlignment() const;
|
||||
void setTextPitchAlignment(PropertyValue<AlignmentType>);
|
||||
|
||||
@@ -15,6 +15,10 @@ public:
|
||||
constexpr uint32_t area() const {
|
||||
return width * height;
|
||||
}
|
||||
|
||||
constexpr float aspectRatio() const {
|
||||
return static_cast<float>(width) / static_cast<float>(height);
|
||||
}
|
||||
|
||||
constexpr bool isEmpty() const {
|
||||
return width == 0 || height == 0;
|
||||
|
||||
@@ -160,6 +160,32 @@ public final class Property {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ICON_TEXT_FIT {}
|
||||
|
||||
// ICON_PITCH_ALIGNMENT: Orientation of icon when map is pitched.
|
||||
|
||||
/**
|
||||
* The icon is aligned to the plane of the map.
|
||||
*/
|
||||
public static final String ICON_PITCH_ALIGNMENT_MAP = "map";
|
||||
/**
|
||||
* The icon is aligned to the plane of the viewport.
|
||||
*/
|
||||
public static final String ICON_PITCH_ALIGNMENT_VIEWPORT = "viewport";
|
||||
/**
|
||||
* Automatically matches the value of {@link ICON_ROTATION_ALIGNMENT}.
|
||||
*/
|
||||
public static final String ICON_PITCH_ALIGNMENT_AUTO = "auto";
|
||||
|
||||
/**
|
||||
* Orientation of icon when map is pitched.
|
||||
*/
|
||||
@StringDef({
|
||||
ICON_PITCH_ALIGNMENT_MAP,
|
||||
ICON_PITCH_ALIGNMENT_VIEWPORT,
|
||||
ICON_PITCH_ALIGNMENT_AUTO,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ICON_PITCH_ALIGNMENT {}
|
||||
|
||||
// TEXT_PITCH_ALIGNMENT: Orientation of text when map is pitched.
|
||||
|
||||
/**
|
||||
|
||||
@@ -1881,6 +1881,29 @@ public class PropertyFactory {
|
||||
return new LayoutPropertyValue<>("icon-offset", function);
|
||||
}
|
||||
|
||||
/**
|
||||
* Orientation of icon when map is pitched.
|
||||
*
|
||||
* @param value a String value
|
||||
* @return property wrapper around String
|
||||
*/
|
||||
public static PropertyValue<String> iconPitchAlignment(@Property.ICON_PITCH_ALIGNMENT String value) {
|
||||
return new LayoutPropertyValue<>("icon-pitch-alignment", value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Orientation of icon when map is pitched.
|
||||
*
|
||||
* @param <Z> the zoom parameter type
|
||||
* @param function a wrapper {@link CameraFunction} for String
|
||||
* @return property wrapper around a String function
|
||||
*/
|
||||
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> iconPitchAlignment(CameraFunction<Z, String> function) {
|
||||
return new LayoutPropertyValue<>("icon-pitch-alignment", function);
|
||||
}
|
||||
|
||||
/**
|
||||
* Orientation of text when map is pitched.
|
||||
*
|
||||
|
||||
@@ -251,6 +251,16 @@ public class SymbolLayer extends Layer {
|
||||
return (PropertyValue<Float[]>) new PropertyValue("icon-offset", nativeGetIconOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IconPitchAlignment property
|
||||
*
|
||||
* @return property wrapper value around String
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public PropertyValue<String> getIconPitchAlignment() {
|
||||
return (PropertyValue<String>) new PropertyValue("icon-pitch-alignment", nativeGetIconPitchAlignment());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TextPitchAlignment property
|
||||
*
|
||||
@@ -891,6 +901,8 @@ public class SymbolLayer extends Layer {
|
||||
|
||||
private native Object nativeGetIconOffset();
|
||||
|
||||
private native Object nativeGetIconPitchAlignment();
|
||||
|
||||
private native Object nativeGetTextPitchAlignment();
|
||||
|
||||
private native Object nativeGetTextRotationAlignment();
|
||||
|
||||
@@ -43,8 +43,7 @@ public class Light {
|
||||
*
|
||||
* @return anchor as String
|
||||
*/
|
||||
@Property.ANCHOR
|
||||
public String getAnchor() {
|
||||
@Property.ANCHOR public String getAnchor() {
|
||||
return nativeGetAnchor();
|
||||
}
|
||||
|
||||
@@ -107,7 +106,7 @@ public class Light {
|
||||
*
|
||||
* @return color as String
|
||||
*/
|
||||
public String getColor() {
|
||||
public String getColor() {
|
||||
return nativeGetColor();
|
||||
}
|
||||
|
||||
@@ -143,7 +142,7 @@ public class Light {
|
||||
*
|
||||
* @return intensity as Float
|
||||
*/
|
||||
public float getIntensity() {
|
||||
public float getIntensity() {
|
||||
return nativeGetIntensity();
|
||||
}
|
||||
|
||||
@@ -166,30 +165,17 @@ public class Light {
|
||||
}
|
||||
|
||||
private native void nativeSetAnchor(String anchor);
|
||||
|
||||
private native String nativeGetAnchor();
|
||||
|
||||
private native void nativeSetPosition(Position position);
|
||||
|
||||
private native Position nativeGetPosition();
|
||||
|
||||
private native TransitionOptions nativeGetPositionTransition();
|
||||
|
||||
private native void nativeSetPositionTransition(long duration, long delay);
|
||||
|
||||
private native void nativeSetColor(String color);
|
||||
|
||||
private native String nativeGetColor();
|
||||
|
||||
private native TransitionOptions nativeGetColorTransition();
|
||||
|
||||
private native void nativeSetColorTransition(long duration, long delay);
|
||||
|
||||
private native void nativeSetIntensity(float intensity);
|
||||
|
||||
private native float nativeGetIntensity();
|
||||
|
||||
private native TransitionOptions nativeGetIntensityTransition();
|
||||
|
||||
private native void nativeSetIntensityTransition(long duration, long delay);
|
||||
}
|
||||
@@ -1052,11 +1052,16 @@ public class CircleLayerTest extends BaseActivityTest {
|
||||
validateTestSetup();
|
||||
setupLayer();
|
||||
Timber.i("circle-pitch-alignment");
|
||||
assertNotNull(layer);
|
||||
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
|
||||
@Override
|
||||
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(circlePitchAlignment(CIRCLE_PITCH_ALIGNMENT_MAP));
|
||||
assertEquals((String) layer.getCirclePitchAlignment().getValue(), (String) CIRCLE_PITCH_ALIGNMENT_MAP);
|
||||
// Set and Get
|
||||
layer.setProperties(circlePitchAlignment(CIRCLE_PITCH_ALIGNMENT_MAP));
|
||||
assertEquals((String) layer.getCirclePitchAlignment().getValue(), (String) CIRCLE_PITCH_ALIGNMENT_MAP);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1064,25 +1069,30 @@ public class CircleLayerTest extends BaseActivityTest {
|
||||
validateTestSetup();
|
||||
setupLayer();
|
||||
Timber.i("circle-pitch-alignment");
|
||||
assertNotNull(layer);
|
||||
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
|
||||
@Override
|
||||
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set
|
||||
layer.setProperties(
|
||||
circlePitchAlignment(
|
||||
zoom(
|
||||
interval(
|
||||
stop(2, circlePitchAlignment(CIRCLE_PITCH_ALIGNMENT_MAP))
|
||||
// Set
|
||||
layer.setProperties(
|
||||
circlePitchAlignment(
|
||||
zoom(
|
||||
interval(
|
||||
stop(2, circlePitchAlignment(CIRCLE_PITCH_ALIGNMENT_MAP))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
);
|
||||
|
||||
// Verify
|
||||
assertNotNull(layer.getCirclePitchAlignment());
|
||||
assertNotNull(layer.getCirclePitchAlignment().getFunction());
|
||||
assertEquals(CameraFunction.class, layer.getCirclePitchAlignment().getFunction().getClass());
|
||||
assertEquals(IntervalStops.class, layer.getCirclePitchAlignment().getFunction().getStops().getClass());
|
||||
assertEquals(1, ((IntervalStops) layer.getCirclePitchAlignment().getFunction().getStops()).size());
|
||||
// Verify
|
||||
assertNotNull(layer.getCirclePitchAlignment());
|
||||
assertNotNull(layer.getCirclePitchAlignment().getFunction());
|
||||
assertEquals(CameraFunction.class, layer.getCirclePitchAlignment().getFunction().getClass());
|
||||
assertEquals(IntervalStops.class, layer.getCirclePitchAlignment().getFunction().getStops().getClass());
|
||||
assertEquals(1, ((IntervalStops) layer.getCirclePitchAlignment().getFunction().getStops()).size());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -865,19 +865,24 @@ public class LineLayerTest extends BaseActivityTest {
|
||||
validateTestSetup();
|
||||
setupLayer();
|
||||
Timber.i("line-width");
|
||||
assertNotNull(layer);
|
||||
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
|
||||
@Override
|
||||
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set
|
||||
layer.setProperties(
|
||||
lineWidth(property("FeaturePropertyA", Stops.<Float>identity()))
|
||||
);
|
||||
// Set
|
||||
layer.setProperties(
|
||||
lineWidth(property("FeaturePropertyA", Stops.<Float>identity()))
|
||||
);
|
||||
|
||||
// Verify
|
||||
assertNotNull(layer.getLineWidth());
|
||||
assertNotNull(layer.getLineWidth().getFunction());
|
||||
assertEquals(SourceFunction.class, layer.getLineWidth().getFunction().getClass());
|
||||
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineWidth().getFunction()).getProperty());
|
||||
assertEquals(IdentityStops.class, layer.getLineWidth().getFunction().getStops().getClass());
|
||||
// Verify
|
||||
assertNotNull(layer.getLineWidth());
|
||||
assertNotNull(layer.getLineWidth().getFunction());
|
||||
assertEquals(SourceFunction.class, layer.getLineWidth().getFunction().getClass());
|
||||
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineWidth().getFunction()).getProperty());
|
||||
assertEquals(IdentityStops.class, layer.getLineWidth().getFunction().getStops().getClass());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -885,26 +890,31 @@ public class LineLayerTest extends BaseActivityTest {
|
||||
validateTestSetup();
|
||||
setupLayer();
|
||||
Timber.i("line-width");
|
||||
assertNotNull(layer);
|
||||
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
|
||||
@Override
|
||||
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set
|
||||
layer.setProperties(
|
||||
lineWidth(
|
||||
property(
|
||||
"FeaturePropertyA",
|
||||
exponential(
|
||||
stop(0.3f, lineWidth(0.3f))
|
||||
).withBase(0.5f)
|
||||
)
|
||||
)
|
||||
);
|
||||
// Set
|
||||
layer.setProperties(
|
||||
lineWidth(
|
||||
property(
|
||||
"FeaturePropertyA",
|
||||
exponential(
|
||||
stop(0.3f, lineWidth(0.3f))
|
||||
).withBase(0.5f)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Verify
|
||||
assertNotNull(layer.getLineWidth());
|
||||
assertNotNull(layer.getLineWidth().getFunction());
|
||||
assertEquals(SourceFunction.class, layer.getLineWidth().getFunction().getClass());
|
||||
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineWidth().getFunction()).getProperty());
|
||||
assertEquals(ExponentialStops.class, layer.getLineWidth().getFunction().getStops().getClass());
|
||||
// Verify
|
||||
assertNotNull(layer.getLineWidth());
|
||||
assertNotNull(layer.getLineWidth().getFunction());
|
||||
assertEquals(SourceFunction.class, layer.getLineWidth().getFunction().getClass());
|
||||
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineWidth().getFunction()).getProperty());
|
||||
assertEquals(ExponentialStops.class, layer.getLineWidth().getFunction().getStops().getClass());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -912,29 +922,35 @@ public class LineLayerTest extends BaseActivityTest {
|
||||
validateTestSetup();
|
||||
setupLayer();
|
||||
Timber.i("line-width");
|
||||
assertNotNull(layer);
|
||||
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
|
||||
@Override
|
||||
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set
|
||||
layer.setProperties(
|
||||
lineWidth(
|
||||
property(
|
||||
"FeaturePropertyA",
|
||||
categorical(
|
||||
stop(1.0f, lineWidth(0.3f))
|
||||
// Set
|
||||
layer.setProperties(
|
||||
lineWidth(
|
||||
property(
|
||||
"FeaturePropertyA",
|
||||
categorical(
|
||||
stop(1.0f, lineWidth(0.3f))
|
||||
)
|
||||
).withDefaultValue(lineWidth(0.3f))
|
||||
)
|
||||
).withDefaultValue(lineWidth(0.3f))
|
||||
)
|
||||
);
|
||||
);
|
||||
|
||||
// Verify
|
||||
assertNotNull(layer.getLineWidth());
|
||||
assertNotNull(layer.getLineWidth().getFunction());
|
||||
assertEquals(SourceFunction.class, layer.getLineWidth().getFunction().getClass());
|
||||
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineWidth().getFunction()).getProperty());
|
||||
assertEquals(CategoricalStops.class, layer.getLineWidth().getFunction().getStops().getClass());
|
||||
assertNotNull(((SourceFunction) layer.getLineWidth().getFunction()).getDefaultValue());
|
||||
assertNotNull(((SourceFunction) layer.getLineWidth().getFunction()).getDefaultValue().getValue());
|
||||
assertEquals(0.3f, ((SourceFunction) layer.getLineWidth().getFunction()).getDefaultValue().getValue());
|
||||
}
|
||||
});
|
||||
|
||||
// Verify
|
||||
assertNotNull(layer.getLineWidth());
|
||||
assertNotNull(layer.getLineWidth().getFunction());
|
||||
assertEquals(SourceFunction.class, layer.getLineWidth().getFunction().getClass());
|
||||
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineWidth().getFunction()).getProperty());
|
||||
assertEquals(CategoricalStops.class, layer.getLineWidth().getFunction().getStops().getClass());
|
||||
assertNotNull(((SourceFunction) layer.getLineWidth().getFunction()).getDefaultValue());
|
||||
assertNotNull(((SourceFunction) layer.getLineWidth().getFunction()).getDefaultValue().getValue());
|
||||
assertEquals(0.3f, ((SourceFunction) layer.getLineWidth().getFunction()).getDefaultValue().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -942,34 +958,39 @@ public class LineLayerTest extends BaseActivityTest {
|
||||
validateTestSetup();
|
||||
setupLayer();
|
||||
Timber.i("line-width");
|
||||
assertNotNull(layer);
|
||||
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
|
||||
@Override
|
||||
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set
|
||||
layer.setProperties(
|
||||
lineWidth(
|
||||
composite(
|
||||
"FeaturePropertyA",
|
||||
exponential(
|
||||
stop(0, 0.3f, lineWidth(0.9f))
|
||||
).withBase(0.5f)
|
||||
).withDefaultValue(lineWidth(0.3f))
|
||||
)
|
||||
);
|
||||
// Set
|
||||
layer.setProperties(
|
||||
lineWidth(
|
||||
composite(
|
||||
"FeaturePropertyA",
|
||||
exponential(
|
||||
stop(0, 0.3f, lineWidth(0.9f))
|
||||
).withBase(0.5f)
|
||||
).withDefaultValue(lineWidth(0.3f))
|
||||
)
|
||||
);
|
||||
|
||||
// Verify
|
||||
assertNotNull(layer.getLineWidth());
|
||||
assertNotNull(layer.getLineWidth().getFunction());
|
||||
assertEquals(CompositeFunction.class, layer.getLineWidth().getFunction().getClass());
|
||||
assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getLineWidth().getFunction()).getProperty());
|
||||
assertEquals(ExponentialStops.class, layer.getLineWidth().getFunction().getStops().getClass());
|
||||
assertEquals(1, ((ExponentialStops) layer.getLineWidth().getFunction().getStops()).size());
|
||||
// Verify
|
||||
assertNotNull(layer.getLineWidth());
|
||||
assertNotNull(layer.getLineWidth().getFunction());
|
||||
assertEquals(CompositeFunction.class, layer.getLineWidth().getFunction().getClass());
|
||||
assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getLineWidth().getFunction()).getProperty());
|
||||
assertEquals(ExponentialStops.class, layer.getLineWidth().getFunction().getStops().getClass());
|
||||
assertEquals(1, ((ExponentialStops) layer.getLineWidth().getFunction().getStops()).size());
|
||||
|
||||
ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
|
||||
(ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getLineWidth().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);
|
||||
ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
|
||||
(ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getLineWidth().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
|
||||
|
||||
@@ -1213,6 +1213,54 @@ public class SymbolLayerTest extends BaseActivityTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIconPitchAlignmentAsConstant() {
|
||||
validateTestSetup();
|
||||
setupLayer();
|
||||
Timber.i("icon-pitch-alignment");
|
||||
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
|
||||
@Override
|
||||
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(iconPitchAlignment(ICON_PITCH_ALIGNMENT_MAP));
|
||||
assertEquals((String) layer.getIconPitchAlignment().getValue(), (String) ICON_PITCH_ALIGNMENT_MAP);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIconPitchAlignmentAsCameraFunction() {
|
||||
validateTestSetup();
|
||||
setupLayer();
|
||||
Timber.i("icon-pitch-alignment");
|
||||
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
|
||||
@Override
|
||||
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set
|
||||
layer.setProperties(
|
||||
iconPitchAlignment(
|
||||
zoom(
|
||||
interval(
|
||||
stop(2, iconPitchAlignment(ICON_PITCH_ALIGNMENT_MAP))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Verify
|
||||
assertNotNull(layer.getIconPitchAlignment());
|
||||
assertNotNull(layer.getIconPitchAlignment().getFunction());
|
||||
assertEquals(CameraFunction.class, layer.getIconPitchAlignment().getFunction().getClass());
|
||||
assertEquals(IntervalStops.class, layer.getIconPitchAlignment().getFunction().getStops().getClass());
|
||||
assertEquals(1, ((IntervalStops) layer.getIconPitchAlignment().getFunction().getStops()).size());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTextPitchAlignmentAsConstant() {
|
||||
validateTestSetup();
|
||||
|
||||
@@ -125,6 +125,12 @@ namespace android {
|
||||
return jni::Object<jni::ObjectTag>(*converted);
|
||||
}
|
||||
|
||||
jni::Object<jni::ObjectTag> SymbolLayer::getIconPitchAlignment(jni::JNIEnv& env) {
|
||||
using namespace mbgl::android::conversion;
|
||||
Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconPitchAlignment());
|
||||
return jni::Object<jni::ObjectTag>(*converted);
|
||||
}
|
||||
|
||||
jni::Object<jni::ObjectTag> SymbolLayer::getTextPitchAlignment(jni::JNIEnv& env) {
|
||||
using namespace mbgl::android::conversion;
|
||||
Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextPitchAlignment());
|
||||
@@ -514,6 +520,7 @@ namespace android {
|
||||
METHOD(&SymbolLayer::getIconPadding, "nativeGetIconPadding"),
|
||||
METHOD(&SymbolLayer::getIconKeepUpright, "nativeGetIconKeepUpright"),
|
||||
METHOD(&SymbolLayer::getIconOffset, "nativeGetIconOffset"),
|
||||
METHOD(&SymbolLayer::getIconPitchAlignment, "nativeGetIconPitchAlignment"),
|
||||
METHOD(&SymbolLayer::getTextPitchAlignment, "nativeGetTextPitchAlignment"),
|
||||
METHOD(&SymbolLayer::getTextRotationAlignment, "nativeGetTextRotationAlignment"),
|
||||
METHOD(&SymbolLayer::getTextField, "nativeGetTextField"),
|
||||
|
||||
@@ -59,6 +59,8 @@ public:
|
||||
|
||||
jni::Object<jni::ObjectTag> getIconOffset(jni::JNIEnv&);
|
||||
|
||||
jni::Object<jni::ObjectTag> getIconPitchAlignment(jni::JNIEnv&);
|
||||
|
||||
jni::Object<jni::ObjectTag> getTextPitchAlignment(jni::JNIEnv&);
|
||||
|
||||
jni::Object<jni::ObjectTag> getTextRotationAlignment(jni::JNIEnv&);
|
||||
|
||||
@@ -7,6 +7,27 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Orientation of icon when map is pitched.
|
||||
|
||||
Values of this type are used in the `MGLSymbolStyleLayer.iconPitchAlignment`
|
||||
property.
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, MGLIconPitchAlignment) {
|
||||
/**
|
||||
The icon is aligned to the plane of the map.
|
||||
*/
|
||||
MGLIconPitchAlignmentMap,
|
||||
/**
|
||||
The icon is aligned to the plane of the viewport.
|
||||
*/
|
||||
MGLIconPitchAlignmentViewport,
|
||||
/**
|
||||
Automatically matches the value of `iconRotationAlignment`.
|
||||
*/
|
||||
MGLIconPitchAlignmentAuto,
|
||||
};
|
||||
|
||||
/**
|
||||
In combination with `symbolPlacement`, determines the rotation behavior of
|
||||
icons.
|
||||
@@ -476,6 +497,24 @@ MGL_EXPORT
|
||||
*/
|
||||
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconPadding;
|
||||
|
||||
/**
|
||||
Orientation of icon when map is pitched.
|
||||
|
||||
The default value of this property is an `MGLStyleValue` object containing an
|
||||
`NSValue` object containing `MGLIconPitchAlignmentAuto`. Set this property to
|
||||
`nil` to reset it to the default value.
|
||||
|
||||
This property is only applied to the style if `iconImageName` is non-`nil`.
|
||||
Otherwise, it is ignored.
|
||||
|
||||
You can set this property to an instance of:
|
||||
|
||||
* `MGLConstantStyleValue`
|
||||
* `MGLCameraStyleFunction` with an interpolation mode of
|
||||
`MGLInterpolationModeInterval`
|
||||
*/
|
||||
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconPitchAlignment;
|
||||
|
||||
/**
|
||||
Rotates the icon clockwise.
|
||||
|
||||
@@ -1924,6 +1963,19 @@ MGL_EXPORT
|
||||
|
||||
#pragma mark Working with Symbol Style Layer Attribute Values
|
||||
|
||||
/**
|
||||
Creates a new value object containing the given `MGLIconPitchAlignment` enumeration.
|
||||
|
||||
@param iconPitchAlignment The value for the new object.
|
||||
@return A new value object that contains the enumeration value.
|
||||
*/
|
||||
+ (instancetype)valueWithMGLIconPitchAlignment:(MGLIconPitchAlignment)iconPitchAlignment;
|
||||
|
||||
/**
|
||||
The `MGLIconPitchAlignment` enumeration representation of the value.
|
||||
*/
|
||||
@property (readonly) MGLIconPitchAlignment MGLIconPitchAlignmentValue;
|
||||
|
||||
/**
|
||||
Creates a new value object containing the given `MGLIconRotationAlignment` enumeration.
|
||||
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
MBGL_DEFINE_ENUM(MGLIconPitchAlignment, {
|
||||
{ MGLIconPitchAlignmentMap, "map" },
|
||||
{ MGLIconPitchAlignmentViewport, "viewport" },
|
||||
{ MGLIconPitchAlignmentAuto, "auto" },
|
||||
});
|
||||
|
||||
MBGL_DEFINE_ENUM(MGLIconRotationAlignment, {
|
||||
{ MGLIconRotationAlignmentMap, "map" },
|
||||
{ MGLIconRotationAlignmentViewport, "viewport" },
|
||||
@@ -259,6 +265,23 @@ namespace mbgl {
|
||||
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
|
||||
}
|
||||
|
||||
- (void)setIconPitchAlignment:(MGLStyleValue<NSValue *> *)iconPitchAlignment {
|
||||
MGLAssertStyleLayerIsValid();
|
||||
|
||||
auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconPitchAlignment>().toEnumPropertyValue(iconPitchAlignment);
|
||||
self.rawLayer->setIconPitchAlignment(mbglValue);
|
||||
}
|
||||
|
||||
- (MGLStyleValue<NSValue *> *)iconPitchAlignment {
|
||||
MGLAssertStyleLayerIsValid();
|
||||
|
||||
auto propertyValue = self.rawLayer->getIconPitchAlignment();
|
||||
if (propertyValue.isUndefined()) {
|
||||
return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconPitchAlignment>().toEnumStyleValue(self.rawLayer->getDefaultIconPitchAlignment());
|
||||
}
|
||||
return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconPitchAlignment>().toEnumStyleValue(propertyValue);
|
||||
}
|
||||
|
||||
- (void)setIconRotation:(MGLStyleValue<NSNumber *> *)iconRotation {
|
||||
MGLAssertStyleLayerIsValid();
|
||||
|
||||
@@ -1321,6 +1344,16 @@ namespace mbgl {
|
||||
|
||||
@implementation NSValue (MGLSymbolStyleLayerAdditions)
|
||||
|
||||
+ (NSValue *)valueWithMGLIconPitchAlignment:(MGLIconPitchAlignment)iconPitchAlignment {
|
||||
return [NSValue value:&iconPitchAlignment withObjCType:@encode(MGLIconPitchAlignment)];
|
||||
}
|
||||
|
||||
- (MGLIconPitchAlignment)MGLIconPitchAlignmentValue {
|
||||
MGLIconPitchAlignment iconPitchAlignment;
|
||||
[self getValue:&iconPitchAlignment];
|
||||
return iconPitchAlignment;
|
||||
}
|
||||
|
||||
+ (NSValue *)valueWithMGLIconRotationAlignment:(MGLIconRotationAlignment)iconRotationAlignment {
|
||||
return [NSValue value:&iconRotationAlignment withObjCType:@encode(MGLIconRotationAlignment)];
|
||||
}
|
||||
|
||||
@@ -301,6 +301,45 @@
|
||||
XCTAssertThrowsSpecificNamed(layer.iconPadding = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
|
||||
}
|
||||
|
||||
// icon-pitch-alignment
|
||||
{
|
||||
XCTAssertTrue(rawLayer->getIconPitchAlignment().isUndefined(),
|
||||
@"icon-pitch-alignment should be unset initially.");
|
||||
MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconPitchAlignment;
|
||||
|
||||
MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentAuto]];
|
||||
layer.iconPitchAlignment = constantStyleValue;
|
||||
mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto };
|
||||
XCTAssertEqual(rawLayer->getIconPitchAlignment(), propertyValue,
|
||||
@"Setting iconPitchAlignment to a constant value should update icon-pitch-alignment.");
|
||||
XCTAssertEqualObjects(layer.iconPitchAlignment, constantStyleValue,
|
||||
@"iconPitchAlignment should round-trip constant values.");
|
||||
|
||||
MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
|
||||
layer.iconPitchAlignment = functionStyleValue;
|
||||
|
||||
mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = { {{18, mbgl::style::AlignmentType::Auto}} };
|
||||
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
|
||||
|
||||
XCTAssertEqual(rawLayer->getIconPitchAlignment(), propertyValue,
|
||||
@"Setting iconPitchAlignment to a camera function should update icon-pitch-alignment.");
|
||||
XCTAssertEqualObjects(layer.iconPitchAlignment, functionStyleValue,
|
||||
@"iconPitchAlignment should round-trip camera functions.");
|
||||
|
||||
|
||||
|
||||
layer.iconPitchAlignment = nil;
|
||||
XCTAssertTrue(rawLayer->getIconPitchAlignment().isUndefined(),
|
||||
@"Unsetting iconPitchAlignment should return icon-pitch-alignment to the default value.");
|
||||
XCTAssertEqualObjects(layer.iconPitchAlignment, defaultStyleValue,
|
||||
@"iconPitchAlignment should return the default value after being unset.");
|
||||
|
||||
functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
|
||||
XCTAssertThrowsSpecificNamed(layer.iconPitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
|
||||
functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
|
||||
XCTAssertThrowsSpecificNamed(layer.iconPitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
|
||||
}
|
||||
|
||||
// icon-rotate
|
||||
{
|
||||
XCTAssertTrue(rawLayer->getIconRotate().isUndefined(),
|
||||
@@ -2321,6 +2360,7 @@
|
||||
[self testPropertyName:@"icon-offset" isBoolean:NO];
|
||||
[self testPropertyName:@"is-icon-optional" isBoolean:YES];
|
||||
[self testPropertyName:@"icon-padding" isBoolean:NO];
|
||||
[self testPropertyName:@"icon-pitch-alignment" isBoolean:NO];
|
||||
[self testPropertyName:@"icon-rotation" isBoolean:NO];
|
||||
[self testPropertyName:@"icon-rotation-alignment" isBoolean:NO];
|
||||
[self testPropertyName:@"icon-scale" isBoolean:NO];
|
||||
@@ -2366,6 +2406,9 @@
|
||||
}
|
||||
|
||||
- (void)testValueAdditions {
|
||||
XCTAssertEqual([NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentMap].MGLIconPitchAlignmentValue, MGLIconPitchAlignmentMap);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentViewport].MGLIconPitchAlignmentValue, MGLIconPitchAlignmentViewport);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentAuto].MGLIconPitchAlignmentValue, MGLIconPitchAlignmentAuto);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentMap].MGLIconRotationAlignmentValue, MGLIconRotationAlignmentMap);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentViewport].MGLIconRotationAlignmentValue, MGLIconRotationAlignmentViewport);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentAuto].MGLIconRotationAlignmentValue, MGLIconRotationAlignmentAuto);
|
||||
|
||||
@@ -75,10 +75,13 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
|
||||
}
|
||||
}
|
||||
|
||||
// If unspecified `text-pitch-alignment` inherits `text-rotation-alignment`
|
||||
// If unspecified `*-pitch-alignment` inherits `*-rotation-alignment`
|
||||
if (layout.get<TextPitchAlignment>() == AlignmentType::Auto) {
|
||||
layout.get<TextPitchAlignment>() = layout.get<TextRotationAlignment>();
|
||||
}
|
||||
if (layout.get<IconPitchAlignment>() == AlignmentType::Auto) {
|
||||
layout.get<IconPitchAlignment>() = layout.get<IconRotationAlignment>();
|
||||
}
|
||||
|
||||
const bool hasText = has<TextField>(layout) && !layout.get<TextFont>().empty();
|
||||
const bool hasIcon = has<IconImage>(layout);
|
||||
|
||||
@@ -52,6 +52,11 @@ Values makeValues(const bool isText,
|
||||
const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1.0, state.getZoom());
|
||||
const bool pitchWithMap = values.pitchAlignment == style::AlignmentType::Map;
|
||||
const bool rotateWithMap = values.rotationAlignment == style::AlignmentType::Map;
|
||||
|
||||
// Line label rotation happens in `updateLineLabels`
|
||||
// Pitched point labels are automatically rotated by the labelPlaneMatrix projection
|
||||
// Unpitched point labels need to have their rotation applied after projection
|
||||
const bool rotateInShader = rotateWithMap && !pitchWithMap && !alongLine;
|
||||
|
||||
mat4 labelPlaneMatrix;
|
||||
if (alongLine) {
|
||||
@@ -84,6 +89,8 @@ Values makeValues(const bool isText,
|
||||
uniforms::u_pitch::Value{ state.getPitch() },
|
||||
uniforms::u_pitch_with_map::Value{ pitchWithMap },
|
||||
uniforms::u_max_camera_distance::Value{ values.maxCameraDistance },
|
||||
uniforms::u_rotate_symbol::Value{ rotateInShader },
|
||||
uniforms::u_aspect_ratio::Value{ state.getSize().aspectRatio() },
|
||||
std::forward<Args>(args)...
|
||||
};
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_feature_constant);
|
||||
MBGL_DEFINE_UNIFORM_SCALAR(float, u_size_t);
|
||||
MBGL_DEFINE_UNIFORM_SCALAR(float, u_size);
|
||||
MBGL_DEFINE_UNIFORM_SCALAR(float, u_max_camera_distance);
|
||||
MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_symbol);
|
||||
MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio);
|
||||
} // namespace uniforms
|
||||
|
||||
struct SymbolLayoutAttributes : gl::Attributes<
|
||||
@@ -348,7 +350,9 @@ class SymbolIconProgram : public SymbolProgram<
|
||||
uniforms::u_camera_to_center_distance,
|
||||
uniforms::u_pitch,
|
||||
uniforms::u_pitch_with_map,
|
||||
uniforms::u_max_camera_distance>,
|
||||
uniforms::u_max_camera_distance,
|
||||
uniforms::u_rotate_symbol,
|
||||
uniforms::u_aspect_ratio>,
|
||||
style::IconPaintProperties>
|
||||
{
|
||||
public:
|
||||
@@ -387,6 +391,8 @@ class SymbolSDFProgram : public SymbolProgram<
|
||||
uniforms::u_pitch,
|
||||
uniforms::u_pitch_with_map,
|
||||
uniforms::u_max_camera_distance,
|
||||
uniforms::u_rotate_symbol,
|
||||
uniforms::u_aspect_ratio,
|
||||
uniforms::u_gamma_scale,
|
||||
uniforms::u_is_halo>,
|
||||
PaintProperties>
|
||||
@@ -409,6 +415,8 @@ public:
|
||||
uniforms::u_pitch,
|
||||
uniforms::u_pitch_with_map,
|
||||
uniforms::u_max_camera_distance,
|
||||
uniforms::u_rotate_symbol,
|
||||
uniforms::u_aspect_ratio,
|
||||
uniforms::u_gamma_scale,
|
||||
uniforms::u_is_halo>,
|
||||
PaintProperties>;
|
||||
|
||||
@@ -82,7 +82,7 @@ style::TextPaintProperties::PossiblyEvaluated RenderSymbolLayer::textPaintProper
|
||||
|
||||
style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) const {
|
||||
return style::SymbolPropertyValues {
|
||||
layout_.get<style::IconRotationAlignment>(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment
|
||||
layout_.get<style::IconPitchAlignment>(),
|
||||
layout_.get<style::IconRotationAlignment>(),
|
||||
layout_.get<style::IconKeepUpright>(),
|
||||
evaluated.get<style::IconTranslate>(),
|
||||
|
||||
@@ -19,6 +19,8 @@ uniform highp float u_size_t; // used to interpolate between zoom stops when siz
|
||||
uniform highp float u_size; // used when size is both zoom and feature constant
|
||||
uniform highp float u_camera_to_center_distance;
|
||||
uniform highp float u_pitch;
|
||||
uniform bool u_rotate_symbol;
|
||||
uniform highp float u_aspect_ratio;
|
||||
uniform highp float u_collision_y_stretch;
|
||||
|
||||
|
||||
@@ -83,8 +85,19 @@ void main() {
|
||||
|
||||
float fontScale = u_is_text ? size / 24.0 : size;
|
||||
|
||||
highp float angle_sin = sin(segment_angle);
|
||||
highp float angle_cos = cos(segment_angle);
|
||||
highp float symbol_rotation = 0.0;
|
||||
if (u_rotate_symbol) {
|
||||
// See comments in symbol_sdf.vertex
|
||||
vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1);
|
||||
|
||||
vec2 a = projectedPoint.xy / projectedPoint.w;
|
||||
vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w;
|
||||
|
||||
symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x);
|
||||
}
|
||||
|
||||
highp float angle_sin = sin(segment_angle + symbol_rotation);
|
||||
highp float angle_cos = cos(segment_angle + symbol_rotation);
|
||||
mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos);
|
||||
|
||||
vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0);
|
||||
|
||||
@@ -73,6 +73,8 @@ uniform mat4 u_gl_coord_matrix;
|
||||
uniform bool u_is_text;
|
||||
uniform bool u_pitch_with_map;
|
||||
uniform highp float u_pitch;
|
||||
uniform bool u_rotate_symbol;
|
||||
uniform highp float u_aspect_ratio;
|
||||
uniform highp float u_camera_to_center_distance;
|
||||
uniform highp float u_collision_y_stretch;
|
||||
|
||||
@@ -151,8 +153,21 @@ void main() {
|
||||
|
||||
float fontScale = u_is_text ? size / 24.0 : size;
|
||||
|
||||
highp float angle_sin = sin(segment_angle);
|
||||
highp float angle_cos = cos(segment_angle);
|
||||
highp float symbol_rotation = 0.0;
|
||||
if (u_rotate_symbol) {
|
||||
// Point labels with 'rotation-alignment: map' are horizontal with respect to tile units
|
||||
// To figure out that angle in projected space, we draw a short horizontal line in tile
|
||||
// space, project it, and measure its angle in projected space.
|
||||
vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1);
|
||||
|
||||
vec2 a = projectedPoint.xy / projectedPoint.w;
|
||||
vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w;
|
||||
|
||||
symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x);
|
||||
}
|
||||
|
||||
highp float angle_sin = sin(segment_angle + symbol_rotation);
|
||||
highp float angle_cos = cos(segment_angle + symbol_rotation);
|
||||
mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos);
|
||||
|
||||
vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0);
|
||||
|
||||
@@ -332,6 +332,22 @@ void SymbolLayer::setIconOffset(DataDrivenPropertyValue<std::array<float, 2>> va
|
||||
baseImpl = std::move(impl_);
|
||||
observer->onLayerChanged(*this);
|
||||
}
|
||||
PropertyValue<AlignmentType> SymbolLayer::getDefaultIconPitchAlignment() {
|
||||
return IconPitchAlignment::defaultValue();
|
||||
}
|
||||
|
||||
PropertyValue<AlignmentType> SymbolLayer::getIconPitchAlignment() const {
|
||||
return impl().layout.get<IconPitchAlignment>();
|
||||
}
|
||||
|
||||
void SymbolLayer::setIconPitchAlignment(PropertyValue<AlignmentType> value) {
|
||||
if (value == getIconPitchAlignment())
|
||||
return;
|
||||
auto impl_ = mutableImpl();
|
||||
impl_->layout.get<IconPitchAlignment>() = value;
|
||||
baseImpl = std::move(impl_);
|
||||
observer->onLayerChanged(*this);
|
||||
}
|
||||
PropertyValue<AlignmentType> SymbolLayer::getDefaultTextPitchAlignment() {
|
||||
return TextPitchAlignment::defaultValue();
|
||||
}
|
||||
|
||||
@@ -87,6 +87,11 @@ struct IconOffset : DataDrivenLayoutProperty<std::array<float, 2>> {
|
||||
static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; }
|
||||
};
|
||||
|
||||
struct IconPitchAlignment : LayoutProperty<AlignmentType> {
|
||||
static constexpr const char * key = "icon-pitch-alignment";
|
||||
static AlignmentType defaultValue() { return AlignmentType::Auto; }
|
||||
};
|
||||
|
||||
struct TextPitchAlignment : LayoutProperty<AlignmentType> {
|
||||
static constexpr const char * key = "text-pitch-alignment";
|
||||
static AlignmentType defaultValue() { return AlignmentType::Auto; }
|
||||
@@ -254,6 +259,7 @@ class SymbolLayoutProperties : public Properties<
|
||||
IconPadding,
|
||||
IconKeepUpright,
|
||||
IconOffset,
|
||||
IconPitchAlignment,
|
||||
TextPitchAlignment,
|
||||
TextRotationAlignment,
|
||||
TextField,
|
||||
|
||||
Reference in New Issue
Block a user