Implement icon-anchor property
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-anchor"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<SymbolAnchorType>, &SymbolLayer::setIconAnchor>;
|
||||
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>;
|
||||
@@ -55,7 +56,7 @@ auto makeLayoutPropertySetters() {
|
||||
result["text-line-height"] = &setProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setTextLineHeight>;
|
||||
result["text-letter-spacing"] = &setProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setTextLetterSpacing>;
|
||||
result["text-justify"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<TextJustifyType>, &SymbolLayer::setTextJustify>;
|
||||
result["text-anchor"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<TextAnchorType>, &SymbolLayer::setTextAnchor>;
|
||||
result["text-anchor"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<SymbolAnchorType>, &SymbolLayer::setTextAnchor>;
|
||||
result["text-max-angle"] = &setProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setTextMaxAngle>;
|
||||
result["text-rotate"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextRotate>;
|
||||
result["text-padding"] = &setProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setTextPadding>;
|
||||
|
||||
@@ -98,6 +98,10 @@ public:
|
||||
DataDrivenPropertyValue<std::array<float, 2>> getIconOffset() const;
|
||||
void setIconOffset(DataDrivenPropertyValue<std::array<float, 2>>);
|
||||
|
||||
static DataDrivenPropertyValue<SymbolAnchorType> getDefaultIconAnchor();
|
||||
DataDrivenPropertyValue<SymbolAnchorType> getIconAnchor() const;
|
||||
void setIconAnchor(DataDrivenPropertyValue<SymbolAnchorType>);
|
||||
|
||||
static PropertyValue<AlignmentType> getDefaultIconPitchAlignment();
|
||||
PropertyValue<AlignmentType> getIconPitchAlignment() const;
|
||||
void setIconPitchAlignment(PropertyValue<AlignmentType>);
|
||||
@@ -138,9 +142,9 @@ public:
|
||||
DataDrivenPropertyValue<TextJustifyType> getTextJustify() const;
|
||||
void setTextJustify(DataDrivenPropertyValue<TextJustifyType>);
|
||||
|
||||
static DataDrivenPropertyValue<TextAnchorType> getDefaultTextAnchor();
|
||||
DataDrivenPropertyValue<TextAnchorType> getTextAnchor() const;
|
||||
void setTextAnchor(DataDrivenPropertyValue<TextAnchorType>);
|
||||
static DataDrivenPropertyValue<SymbolAnchorType> getDefaultTextAnchor();
|
||||
DataDrivenPropertyValue<SymbolAnchorType> getTextAnchor() const;
|
||||
void setTextAnchor(DataDrivenPropertyValue<SymbolAnchorType>);
|
||||
|
||||
static PropertyValue<float> getDefaultTextMaxAngle();
|
||||
PropertyValue<float> getTextMaxAngle() const;
|
||||
|
||||
@@ -68,7 +68,7 @@ enum class TextJustifyType : uint8_t {
|
||||
Right
|
||||
};
|
||||
|
||||
enum class TextAnchorType : uint8_t {
|
||||
enum class SymbolAnchorType : uint8_t {
|
||||
Center,
|
||||
Left,
|
||||
Right,
|
||||
|
||||
Submodule mapbox-gl-js updated: 3730e8377f...5f4d86d276
@@ -160,6 +160,62 @@ public final class Property {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ICON_TEXT_FIT {}
|
||||
|
||||
// ICON_ANCHOR: Part of the icon placed closest to the anchor.
|
||||
|
||||
/**
|
||||
* The center of the icon is placed closest to the anchor.
|
||||
*/
|
||||
public static final String ICON_ANCHOR_CENTER = "center";
|
||||
/**
|
||||
* The left side of the icon is placed closest to the anchor.
|
||||
*/
|
||||
public static final String ICON_ANCHOR_LEFT = "left";
|
||||
/**
|
||||
* The right side of the icon is placed closest to the anchor.
|
||||
*/
|
||||
public static final String ICON_ANCHOR_RIGHT = "right";
|
||||
/**
|
||||
* The top of the icon is placed closest to the anchor.
|
||||
*/
|
||||
public static final String ICON_ANCHOR_TOP = "top";
|
||||
/**
|
||||
* The bottom of the icon is placed closest to the anchor.
|
||||
*/
|
||||
public static final String ICON_ANCHOR_BOTTOM = "bottom";
|
||||
/**
|
||||
* The top left corner of the icon is placed closest to the anchor.
|
||||
*/
|
||||
public static final String ICON_ANCHOR_TOP_LEFT = "top-left";
|
||||
/**
|
||||
* The top right corner of the icon is placed closest to the anchor.
|
||||
*/
|
||||
public static final String ICON_ANCHOR_TOP_RIGHT = "top-right";
|
||||
/**
|
||||
* The bottom left corner of the icon is placed closest to the anchor.
|
||||
*/
|
||||
public static final String ICON_ANCHOR_BOTTOM_LEFT = "bottom-left";
|
||||
/**
|
||||
* The bottom right corner of the icon is placed closest to the anchor.
|
||||
*/
|
||||
public static final String ICON_ANCHOR_BOTTOM_RIGHT = "bottom-right";
|
||||
|
||||
/**
|
||||
* Part of the icon placed closest to the anchor.
|
||||
*/
|
||||
@StringDef({
|
||||
ICON_ANCHOR_CENTER,
|
||||
ICON_ANCHOR_LEFT,
|
||||
ICON_ANCHOR_RIGHT,
|
||||
ICON_ANCHOR_TOP,
|
||||
ICON_ANCHOR_BOTTOM,
|
||||
ICON_ANCHOR_TOP_LEFT,
|
||||
ICON_ANCHOR_TOP_RIGHT,
|
||||
ICON_ANCHOR_BOTTOM_LEFT,
|
||||
ICON_ANCHOR_BOTTOM_RIGHT,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ICON_ANCHOR {}
|
||||
|
||||
// ICON_PITCH_ALIGNMENT: Orientation of icon when map is pitched.
|
||||
|
||||
/**
|
||||
|
||||
@@ -1881,6 +1881,29 @@ public class PropertyFactory {
|
||||
return new LayoutPropertyValue<>("icon-offset", function);
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of the icon placed closest to the anchor.
|
||||
*
|
||||
* @param value a String value
|
||||
* @return property wrapper around String
|
||||
*/
|
||||
public static PropertyValue<String> iconAnchor(@Property.ICON_ANCHOR String value) {
|
||||
return new LayoutPropertyValue<>("icon-anchor", value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Part of the icon placed closest to the anchor.
|
||||
*
|
||||
* @param <T> the function input type
|
||||
* @param function a wrapper function for String
|
||||
* @return property wrapper around a String function
|
||||
*/
|
||||
public static <T> PropertyValue<Function<T, String>> iconAnchor(Function<T, String> function) {
|
||||
return new LayoutPropertyValue<>("icon-anchor", function);
|
||||
}
|
||||
|
||||
/**
|
||||
* Orientation of icon when map is pitched.
|
||||
*
|
||||
|
||||
@@ -251,6 +251,16 @@ public class SymbolLayer extends Layer {
|
||||
return (PropertyValue<Float[]>) new PropertyValue("icon-offset", nativeGetIconOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IconAnchor property
|
||||
*
|
||||
* @return property wrapper value around String
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public PropertyValue<String> getIconAnchor() {
|
||||
return (PropertyValue<String>) new PropertyValue("icon-anchor", nativeGetIconAnchor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IconPitchAlignment property
|
||||
*
|
||||
@@ -901,6 +911,8 @@ public class SymbolLayer extends Layer {
|
||||
|
||||
private native Object nativeGetIconOffset();
|
||||
|
||||
private native Object nativeGetIconAnchor();
|
||||
|
||||
private native Object nativeGetIconPitchAlignment();
|
||||
|
||||
private native Object nativeGetTextPitchAlignment();
|
||||
|
||||
@@ -1213,6 +1213,111 @@ public class SymbolLayerTest extends BaseActivityTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIconAnchorAsConstant() {
|
||||
validateTestSetup();
|
||||
setupLayer();
|
||||
Timber.i("icon-anchor");
|
||||
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
|
||||
@Override
|
||||
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(iconAnchor(ICON_ANCHOR_CENTER));
|
||||
assertEquals((String) layer.getIconAnchor().getValue(), (String) ICON_ANCHOR_CENTER);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIconAnchorAsCameraFunction() {
|
||||
validateTestSetup();
|
||||
setupLayer();
|
||||
Timber.i("icon-anchor");
|
||||
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
|
||||
@Override
|
||||
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set
|
||||
layer.setProperties(
|
||||
iconAnchor(
|
||||
zoom(
|
||||
interval(
|
||||
stop(2, iconAnchor(ICON_ANCHOR_CENTER))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Verify
|
||||
assertNotNull(layer.getIconAnchor());
|
||||
assertNotNull(layer.getIconAnchor().getFunction());
|
||||
assertEquals(CameraFunction.class, layer.getIconAnchor().getFunction().getClass());
|
||||
assertEquals(IntervalStops.class, layer.getIconAnchor().getFunction().getStops().getClass());
|
||||
assertEquals(1, ((IntervalStops) layer.getIconAnchor().getFunction().getStops()).size());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIconAnchorAsIdentitySourceFunction() {
|
||||
validateTestSetup();
|
||||
setupLayer();
|
||||
Timber.i("icon-anchor");
|
||||
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
|
||||
@Override
|
||||
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set
|
||||
layer.setProperties(
|
||||
iconAnchor(property("FeaturePropertyA", Stops.<String>identity()))
|
||||
);
|
||||
|
||||
// Verify
|
||||
assertNotNull(layer.getIconAnchor());
|
||||
assertNotNull(layer.getIconAnchor().getFunction());
|
||||
assertEquals(SourceFunction.class, layer.getIconAnchor().getFunction().getClass());
|
||||
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconAnchor().getFunction()).getProperty());
|
||||
assertEquals(IdentityStops.class, layer.getIconAnchor().getFunction().getStops().getClass());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIconAnchorAsIntervalSourceFunction() {
|
||||
validateTestSetup();
|
||||
setupLayer();
|
||||
Timber.i("icon-anchor");
|
||||
invoke(mapboxMap, new MapboxMapAction.OnInvokeActionListener() {
|
||||
@Override
|
||||
public void onInvokeAction(UiController uiController, MapboxMap mapboxMap) {
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set
|
||||
layer.setProperties(
|
||||
iconAnchor(
|
||||
property(
|
||||
"FeaturePropertyA",
|
||||
interval(
|
||||
stop(1, iconAnchor(ICON_ANCHOR_CENTER))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Verify
|
||||
assertNotNull(layer.getIconAnchor());
|
||||
assertNotNull(layer.getIconAnchor().getFunction());
|
||||
assertEquals(SourceFunction.class, layer.getIconAnchor().getFunction().getClass());
|
||||
assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconAnchor().getFunction()).getProperty());
|
||||
assertEquals(IntervalStops.class, layer.getIconAnchor().getFunction().getStops().getClass());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIconPitchAlignmentAsConstant() {
|
||||
validateTestSetup();
|
||||
|
||||
@@ -111,6 +111,9 @@ global.propertyNativeType = function (property) {
|
||||
if (/-(rotation|pitch|illumination)-alignment$/.test(property.name)) {
|
||||
return 'AlignmentType';
|
||||
}
|
||||
if (/^(text|icon)-anchor$/.test(property.name)) {
|
||||
return 'SymbolAnchorType';
|
||||
}
|
||||
switch (property.type) {
|
||||
case 'boolean':
|
||||
return 'bool';
|
||||
@@ -267,6 +270,9 @@ global.evaluatedType = function (property) {
|
||||
if (/-(rotation|pitch|illumination)-alignment$/.test(property.name)) {
|
||||
return 'AlignmentType';
|
||||
}
|
||||
if (/^(text|icon)-anchor$/.test(property.name)) {
|
||||
return 'SymbolAnchorType';
|
||||
}
|
||||
if (/position/.test(property.name)) {
|
||||
return 'Position';
|
||||
}
|
||||
|
||||
@@ -58,15 +58,15 @@ struct Converter<jni::jobject*, mbgl::style::IconTextFitType> {
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<jni::jobject*, mbgl::style::TextJustifyType> {
|
||||
Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::TextJustifyType& value) const {
|
||||
struct Converter<jni::jobject*, mbgl::style::SymbolAnchorType> {
|
||||
Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::SymbolAnchorType& value) const {
|
||||
return convert<jni::jobject*, std::string>(env, toString(value));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<jni::jobject*, mbgl::style::TextAnchorType> {
|
||||
Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::TextAnchorType& value) const {
|
||||
struct Converter<jni::jobject*, mbgl::style::TextJustifyType> {
|
||||
Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::TextJustifyType& value) const {
|
||||
return convert<jni::jobject*, std::string>(env, toString(value));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -109,6 +109,41 @@ namespace conversion {
|
||||
}
|
||||
}
|
||||
|
||||
// icon-anchor
|
||||
inline std::string toString(mbgl::style::SymbolAnchorType value) {
|
||||
switch (value) {
|
||||
case mbgl::style::SymbolAnchorType::Center:
|
||||
return "center";
|
||||
break;
|
||||
case mbgl::style::SymbolAnchorType::Left:
|
||||
return "left";
|
||||
break;
|
||||
case mbgl::style::SymbolAnchorType::Right:
|
||||
return "right";
|
||||
break;
|
||||
case mbgl::style::SymbolAnchorType::Top:
|
||||
return "top";
|
||||
break;
|
||||
case mbgl::style::SymbolAnchorType::Bottom:
|
||||
return "bottom";
|
||||
break;
|
||||
case mbgl::style::SymbolAnchorType::TopLeft:
|
||||
return "top-left";
|
||||
break;
|
||||
case mbgl::style::SymbolAnchorType::TopRight:
|
||||
return "top-right";
|
||||
break;
|
||||
case mbgl::style::SymbolAnchorType::BottomLeft:
|
||||
return "bottom-left";
|
||||
break;
|
||||
case mbgl::style::SymbolAnchorType::BottomRight:
|
||||
return "bottom-right";
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
// text-justify
|
||||
inline std::string toString(mbgl::style::TextJustifyType value) {
|
||||
switch (value) {
|
||||
@@ -126,41 +161,6 @@ namespace conversion {
|
||||
}
|
||||
}
|
||||
|
||||
// text-anchor
|
||||
inline std::string toString(mbgl::style::TextAnchorType value) {
|
||||
switch (value) {
|
||||
case mbgl::style::TextAnchorType::Center:
|
||||
return "center";
|
||||
break;
|
||||
case mbgl::style::TextAnchorType::Left:
|
||||
return "left";
|
||||
break;
|
||||
case mbgl::style::TextAnchorType::Right:
|
||||
return "right";
|
||||
break;
|
||||
case mbgl::style::TextAnchorType::Top:
|
||||
return "top";
|
||||
break;
|
||||
case mbgl::style::TextAnchorType::Bottom:
|
||||
return "bottom";
|
||||
break;
|
||||
case mbgl::style::TextAnchorType::TopLeft:
|
||||
return "top-left";
|
||||
break;
|
||||
case mbgl::style::TextAnchorType::TopRight:
|
||||
return "top-right";
|
||||
break;
|
||||
case mbgl::style::TextAnchorType::BottomLeft:
|
||||
return "bottom-left";
|
||||
break;
|
||||
case mbgl::style::TextAnchorType::BottomRight:
|
||||
return "bottom-right";
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
// text-transform
|
||||
inline std::string toString(mbgl::style::TextTransformType value) {
|
||||
switch (value) {
|
||||
|
||||
@@ -125,6 +125,12 @@ namespace android {
|
||||
return jni::Object<jni::ObjectTag>(*converted);
|
||||
}
|
||||
|
||||
jni::Object<jni::ObjectTag> SymbolLayer::getIconAnchor(jni::JNIEnv& env) {
|
||||
using namespace mbgl::android::conversion;
|
||||
Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconAnchor());
|
||||
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());
|
||||
@@ -520,6 +526,7 @@ namespace android {
|
||||
METHOD(&SymbolLayer::getIconPadding, "nativeGetIconPadding"),
|
||||
METHOD(&SymbolLayer::getIconKeepUpright, "nativeGetIconKeepUpright"),
|
||||
METHOD(&SymbolLayer::getIconOffset, "nativeGetIconOffset"),
|
||||
METHOD(&SymbolLayer::getIconAnchor, "nativeGetIconAnchor"),
|
||||
METHOD(&SymbolLayer::getIconPitchAlignment, "nativeGetIconPitchAlignment"),
|
||||
METHOD(&SymbolLayer::getTextPitchAlignment, "nativeGetTextPitchAlignment"),
|
||||
METHOD(&SymbolLayer::getTextRotationAlignment, "nativeGetTextRotationAlignment"),
|
||||
|
||||
@@ -59,6 +59,8 @@ public:
|
||||
|
||||
jni::Object<jni::ObjectTag> getIconOffset(jni::JNIEnv&);
|
||||
|
||||
jni::Object<jni::ObjectTag> getIconAnchor(jni::JNIEnv&);
|
||||
|
||||
jni::Object<jni::ObjectTag> getIconPitchAlignment(jni::JNIEnv&);
|
||||
|
||||
jni::Object<jni::ObjectTag> getTextPitchAlignment(jni::JNIEnv&);
|
||||
|
||||
@@ -148,6 +148,9 @@ global.mbglTestValue = function (property, layerType) {
|
||||
if (/-(rotation|pitch)-alignment$/.test(originalPropertyName(property))) {
|
||||
type = 'Alignment';
|
||||
}
|
||||
if (/^(text|icon)-anchor$/.test(originalPropertyName(property))) {
|
||||
type = 'SymbolAnchor'
|
||||
}
|
||||
let value = camelize(_.last(_.keys(property.values)));
|
||||
if (property['light-property']) {
|
||||
return `mbgl::style::Light${type}Type::${value}`;
|
||||
@@ -500,6 +503,9 @@ global.mbglType = function(property) {
|
||||
if (/-(rotation|pitch)-alignment$/.test(originalPropertyName(property))) {
|
||||
type = 'Alignment';
|
||||
}
|
||||
if (/^(text|icon)-anchor$/.test(originalPropertyName(property))) {
|
||||
type = 'SymbolAnchor'
|
||||
}
|
||||
return `mbgl::style::${type}Type`;
|
||||
}
|
||||
case 'color':
|
||||
@@ -648,10 +654,10 @@ while ((match = exampleRegex.exec(examplesSrc)) !== null) {
|
||||
let testMethodName = match[1],
|
||||
indentation = match[2],
|
||||
exampleCode = match[3];
|
||||
|
||||
|
||||
// Trim leading whitespace from the example code.
|
||||
exampleCode = exampleCode.replace(new RegExp('^' + indentation, 'gm'), '');
|
||||
|
||||
|
||||
examples[testMethodName] = exampleCode;
|
||||
}
|
||||
|
||||
@@ -663,13 +669,13 @@ global.guideExample = function (guide, exampleId, os) {
|
||||
console.error(`MGLDocumentationExampleTests.test${testMethodName}() not found.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
// Resolve conditional compilation blocks.
|
||||
example = example.replace(/^(\s*)#if\s+os\((iOS|macOS)\)\n([^]*?)(?:^\1#else\n([^]*?))?^\1#endif\b\n?/gm,
|
||||
function (m, indentation, ifOs, ifCase, elseCase) {
|
||||
return (os === ifOs ? ifCase : elseCase).replace(new RegExp('^ ', 'gm'), '');
|
||||
}).replace(/\n$/, '');
|
||||
|
||||
|
||||
return '```swift\n' + example + '\n```';
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,51 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Part of the icon placed closest to the anchor.
|
||||
|
||||
Values of this type are used in the `MGLSymbolStyleLayer.iconAnchor`
|
||||
property.
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, MGLIconAnchor) {
|
||||
/**
|
||||
The center of the icon is placed closest to the anchor.
|
||||
*/
|
||||
MGLIconAnchorCenter,
|
||||
/**
|
||||
The left side of the icon is placed closest to the anchor.
|
||||
*/
|
||||
MGLIconAnchorLeft,
|
||||
/**
|
||||
The right side of the icon is placed closest to the anchor.
|
||||
*/
|
||||
MGLIconAnchorRight,
|
||||
/**
|
||||
The top of the icon is placed closest to the anchor.
|
||||
*/
|
||||
MGLIconAnchorTop,
|
||||
/**
|
||||
The bottom of the icon is placed closest to the anchor.
|
||||
*/
|
||||
MGLIconAnchorBottom,
|
||||
/**
|
||||
The top left corner of the icon is placed closest to the anchor.
|
||||
*/
|
||||
MGLIconAnchorTopLeft,
|
||||
/**
|
||||
The top right corner of the icon is placed closest to the anchor.
|
||||
*/
|
||||
MGLIconAnchorTopRight,
|
||||
/**
|
||||
The bottom left corner of the icon is placed closest to the anchor.
|
||||
*/
|
||||
MGLIconAnchorBottomLeft,
|
||||
/**
|
||||
The bottom right corner of the icon is placed closest to the anchor.
|
||||
*/
|
||||
MGLIconAnchorBottomRight,
|
||||
};
|
||||
|
||||
/**
|
||||
Orientation of icon when map is pitched.
|
||||
|
||||
@@ -344,6 +389,34 @@ MGL_EXPORT
|
||||
|
||||
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconAllowOverlap __attribute__((unavailable("Use iconAllowsOverlap instead.")));
|
||||
|
||||
/**
|
||||
Part of the icon placed closest to the anchor.
|
||||
|
||||
The default value of this property is an `MGLStyleValue` object containing an
|
||||
`NSValue` object containing `MGLIconAnchorCenter`. 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:
|
||||
* `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<NSValue *> *iconAnchor;
|
||||
|
||||
/**
|
||||
If true, other symbols can be visible even if they collide with the icon.
|
||||
|
||||
@@ -1983,6 +2056,19 @@ MGL_EXPORT
|
||||
|
||||
#pragma mark Working with Symbol Style Layer Attribute Values
|
||||
|
||||
/**
|
||||
Creates a new value object containing the given `MGLIconAnchor` enumeration.
|
||||
|
||||
@param iconAnchor The value for the new object.
|
||||
@return A new value object that contains the enumeration value.
|
||||
*/
|
||||
+ (instancetype)valueWithMGLIconAnchor:(MGLIconAnchor)iconAnchor;
|
||||
|
||||
/**
|
||||
The `MGLIconAnchor` enumeration representation of the value.
|
||||
*/
|
||||
@property (readonly) MGLIconAnchor MGLIconAnchorValue;
|
||||
|
||||
/**
|
||||
Creates a new value object containing the given `MGLIconPitchAlignment` enumeration.
|
||||
|
||||
|
||||
@@ -13,6 +13,18 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
MBGL_DEFINE_ENUM(MGLIconAnchor, {
|
||||
{ MGLIconAnchorCenter, "center" },
|
||||
{ MGLIconAnchorLeft, "left" },
|
||||
{ MGLIconAnchorRight, "right" },
|
||||
{ MGLIconAnchorTop, "top" },
|
||||
{ MGLIconAnchorBottom, "bottom" },
|
||||
{ MGLIconAnchorTopLeft, "top-left" },
|
||||
{ MGLIconAnchorTopRight, "top-right" },
|
||||
{ MGLIconAnchorBottomLeft, "bottom-left" },
|
||||
{ MGLIconAnchorBottomRight, "bottom-right" },
|
||||
});
|
||||
|
||||
MBGL_DEFINE_ENUM(MGLIconPitchAlignment, {
|
||||
{ MGLIconPitchAlignmentMap, "map" },
|
||||
{ MGLIconPitchAlignmentViewport, "viewport" },
|
||||
@@ -166,6 +178,23 @@ namespace mbgl {
|
||||
return self.iconAllowsOverlap;
|
||||
}
|
||||
|
||||
- (void)setIconAnchor:(MGLStyleValue<NSValue *> *)iconAnchor {
|
||||
MGLAssertStyleLayerIsValid();
|
||||
|
||||
auto mbglValue = MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLIconAnchor>().toDataDrivenPropertyValue(iconAnchor);
|
||||
self.rawLayer->setIconAnchor(mbglValue);
|
||||
}
|
||||
|
||||
- (MGLStyleValue<NSValue *> *)iconAnchor {
|
||||
MGLAssertStyleLayerIsValid();
|
||||
|
||||
auto propertyValue = self.rawLayer->getIconAnchor();
|
||||
if (propertyValue.isUndefined()) {
|
||||
return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLIconAnchor>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconAnchor());
|
||||
}
|
||||
return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLIconAnchor>().toDataDrivenStyleValue(propertyValue);
|
||||
}
|
||||
|
||||
- (void)setIconIgnoresPlacement:(MGLStyleValue<NSNumber *> *)iconIgnoresPlacement {
|
||||
MGLAssertStyleLayerIsValid();
|
||||
|
||||
@@ -586,7 +615,7 @@ namespace mbgl {
|
||||
- (void)setTextAnchor:(MGLStyleValue<NSValue *> *)textAnchor {
|
||||
MGLAssertStyleLayerIsValid();
|
||||
|
||||
auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toDataDrivenPropertyValue(textAnchor);
|
||||
auto mbglValue = MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toDataDrivenPropertyValue(textAnchor);
|
||||
self.rawLayer->setTextAnchor(mbglValue);
|
||||
}
|
||||
|
||||
@@ -595,9 +624,9 @@ namespace mbgl {
|
||||
|
||||
auto propertyValue = self.rawLayer->getTextAnchor();
|
||||
if (propertyValue.isUndefined()) {
|
||||
return MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextAnchor());
|
||||
return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextAnchor());
|
||||
}
|
||||
return MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toDataDrivenStyleValue(propertyValue);
|
||||
return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toDataDrivenStyleValue(propertyValue);
|
||||
}
|
||||
|
||||
- (void)setTextFontNames:(MGLStyleValue<NSArray<NSString *> *> *)textFontNames {
|
||||
@@ -1344,6 +1373,16 @@ namespace mbgl {
|
||||
|
||||
@implementation NSValue (MGLSymbolStyleLayerAdditions)
|
||||
|
||||
+ (NSValue *)valueWithMGLIconAnchor:(MGLIconAnchor)iconAnchor {
|
||||
return [NSValue value:&iconAnchor withObjCType:@encode(MGLIconAnchor)];
|
||||
}
|
||||
|
||||
- (MGLIconAnchor)MGLIconAnchorValue {
|
||||
MGLIconAnchor iconAnchor;
|
||||
[self getValue:&iconAnchor];
|
||||
return iconAnchor;
|
||||
}
|
||||
|
||||
+ (NSValue *)valueWithMGLIconPitchAlignment:(MGLIconPitchAlignment)iconPitchAlignment {
|
||||
return [NSValue value:&iconPitchAlignment withObjCType:@encode(MGLIconPitchAlignment)];
|
||||
}
|
||||
|
||||
@@ -87,6 +87,40 @@
|
||||
XCTAssertThrowsSpecificNamed(layer.iconAllowsOverlap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
|
||||
}
|
||||
|
||||
// icon-anchor
|
||||
{
|
||||
XCTAssertTrue(rawLayer->getIconAnchor().isUndefined(),
|
||||
@"icon-anchor should be unset initially.");
|
||||
MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconAnchor;
|
||||
|
||||
MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconAnchor:MGLIconAnchorBottomRight]];
|
||||
layer.iconAnchor = constantStyleValue;
|
||||
mbgl::style::DataDrivenPropertyValue<mbgl::style::SymbolAnchorType> propertyValue = { mbgl::style::SymbolAnchorType::BottomRight };
|
||||
XCTAssertEqual(rawLayer->getIconAnchor(), propertyValue,
|
||||
@"Setting iconAnchor to a constant value should update icon-anchor.");
|
||||
XCTAssertEqualObjects(layer.iconAnchor, constantStyleValue,
|
||||
@"iconAnchor should round-trip constant values.");
|
||||
|
||||
MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
|
||||
layer.iconAnchor = functionStyleValue;
|
||||
|
||||
mbgl::style::IntervalStops<mbgl::style::SymbolAnchorType> intervalStops = { {{18, mbgl::style::SymbolAnchorType::BottomRight}} };
|
||||
propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolAnchorType> { intervalStops };
|
||||
|
||||
XCTAssertEqual(rawLayer->getIconAnchor(), propertyValue,
|
||||
@"Setting iconAnchor to a camera function should update icon-anchor.");
|
||||
XCTAssertEqualObjects(layer.iconAnchor, functionStyleValue,
|
||||
@"iconAnchor should round-trip camera functions.");
|
||||
|
||||
|
||||
|
||||
layer.iconAnchor = nil;
|
||||
XCTAssertTrue(rawLayer->getIconAnchor().isUndefined(),
|
||||
@"Unsetting iconAnchor should return icon-anchor to the default value.");
|
||||
XCTAssertEqualObjects(layer.iconAnchor, defaultStyleValue,
|
||||
@"iconAnchor should return the default value after being unset.");
|
||||
}
|
||||
|
||||
// icon-ignore-placement
|
||||
{
|
||||
XCTAssertTrue(rawLayer->getIconIgnorePlacement().isUndefined(),
|
||||
@@ -931,7 +965,7 @@
|
||||
|
||||
MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomRight]];
|
||||
layer.textAnchor = constantStyleValue;
|
||||
mbgl::style::DataDrivenPropertyValue<mbgl::style::TextAnchorType> propertyValue = { mbgl::style::TextAnchorType::BottomRight };
|
||||
mbgl::style::DataDrivenPropertyValue<mbgl::style::SymbolAnchorType> propertyValue = { mbgl::style::SymbolAnchorType::BottomRight };
|
||||
XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue,
|
||||
@"Setting textAnchor to a constant value should update text-anchor.");
|
||||
XCTAssertEqualObjects(layer.textAnchor, constantStyleValue,
|
||||
@@ -940,8 +974,8 @@
|
||||
MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
|
||||
layer.textAnchor = functionStyleValue;
|
||||
|
||||
mbgl::style::IntervalStops<mbgl::style::TextAnchorType> intervalStops = { {{18, mbgl::style::TextAnchorType::BottomRight}} };
|
||||
propertyValue = mbgl::style::CameraFunction<mbgl::style::TextAnchorType> { intervalStops };
|
||||
mbgl::style::IntervalStops<mbgl::style::SymbolAnchorType> intervalStops = { {{18, mbgl::style::SymbolAnchorType::BottomRight}} };
|
||||
propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolAnchorType> { intervalStops };
|
||||
|
||||
XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue,
|
||||
@"Setting textAnchor to a camera function should update text-anchor.");
|
||||
@@ -2345,6 +2379,7 @@
|
||||
|
||||
- (void)testPropertyNames {
|
||||
[self testPropertyName:@"icon-allows-overlap" isBoolean:YES];
|
||||
[self testPropertyName:@"icon-anchor" isBoolean:NO];
|
||||
[self testPropertyName:@"icon-ignores-placement" isBoolean:YES];
|
||||
[self testPropertyName:@"icon-image-name" isBoolean:NO];
|
||||
[self testPropertyName:@"icon-offset" isBoolean:NO];
|
||||
@@ -2396,6 +2431,15 @@
|
||||
}
|
||||
|
||||
- (void)testValueAdditions {
|
||||
XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorCenter].MGLIconAnchorValue, MGLIconAnchorCenter);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorLeft].MGLIconAnchorValue, MGLIconAnchorLeft);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorRight].MGLIconAnchorValue, MGLIconAnchorRight);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorTop].MGLIconAnchorValue, MGLIconAnchorTop);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorBottom].MGLIconAnchorValue, MGLIconAnchorBottom);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorTopLeft].MGLIconAnchorValue, MGLIconAnchorTopLeft);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorTopRight].MGLIconAnchorValue, MGLIconAnchorTopRight);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorBottomLeft].MGLIconAnchorValue, MGLIconAnchorBottomLeft);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorBottomRight].MGLIconAnchorValue, MGLIconAnchorBottomRight);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentMap].MGLIconPitchAlignmentValue, MGLIconPitchAlignmentMap);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentViewport].MGLIconPitchAlignmentValue, MGLIconPitchAlignmentViewport);
|
||||
XCTAssertEqual([NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentAuto].MGLIconPitchAlignmentValue, MGLIconPitchAlignmentAuto);
|
||||
|
||||
@@ -29,6 +29,9 @@ global.evaluatedType = function (property) {
|
||||
if (/-(rotation|pitch|illumination)-alignment$/.test(property.name)) {
|
||||
return 'AlignmentType';
|
||||
}
|
||||
if (/^(text|icon)-anchor$/.test(property.name)) {
|
||||
return 'SymbolAnchorType';
|
||||
}
|
||||
if (/position/.test(property.name)) {
|
||||
return 'Position';
|
||||
}
|
||||
|
||||
@@ -233,6 +233,7 @@ void SymbolLayout::prepare(const GlyphMap& glyphMap, const GlyphPositions& glyph
|
||||
shapedIcon = PositionedIcon::shapeIcon(
|
||||
imagePositions.at(*feature.icon),
|
||||
layout.evaluate<IconOffset>(zoom, feature),
|
||||
layout.evaluate<IconAnchor>(zoom, feature),
|
||||
layout.evaluate<IconRotate>(zoom, feature) * util::DEG2RAD);
|
||||
if (image->second->sdf) {
|
||||
sdfIcons = true;
|
||||
|
||||
@@ -34,7 +34,7 @@ template class CategoricalStops<std::array<float, 2>>;
|
||||
template class CategoricalStops<std::string>;
|
||||
template class CategoricalStops<TextTransformType>;
|
||||
template class CategoricalStops<TextJustifyType>;
|
||||
template class CategoricalStops<TextAnchorType>;
|
||||
template class CategoricalStops<SymbolAnchorType>;
|
||||
template class CategoricalStops<LineJoinType>;
|
||||
|
||||
} // namespace style
|
||||
|
||||
@@ -50,12 +50,12 @@ optional<TextJustifyType> IdentityStops<TextJustifyType>::evaluate(const Value&
|
||||
}
|
||||
|
||||
template <>
|
||||
optional<TextAnchorType> IdentityStops<TextAnchorType>::evaluate(const Value& value) const {
|
||||
optional<SymbolAnchorType> IdentityStops<SymbolAnchorType>::evaluate(const Value& value) const {
|
||||
if (!value.is<std::string>()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return Enum<TextAnchorType>::toEnum(value.get<std::string>());
|
||||
return Enum<SymbolAnchorType>::toEnum(value.get<std::string>());
|
||||
}
|
||||
|
||||
template <>
|
||||
|
||||
@@ -332,6 +332,22 @@ void SymbolLayer::setIconOffset(DataDrivenPropertyValue<std::array<float, 2>> va
|
||||
baseImpl = std::move(impl_);
|
||||
observer->onLayerChanged(*this);
|
||||
}
|
||||
DataDrivenPropertyValue<SymbolAnchorType> SymbolLayer::getDefaultIconAnchor() {
|
||||
return IconAnchor::defaultValue();
|
||||
}
|
||||
|
||||
DataDrivenPropertyValue<SymbolAnchorType> SymbolLayer::getIconAnchor() const {
|
||||
return impl().layout.get<IconAnchor>();
|
||||
}
|
||||
|
||||
void SymbolLayer::setIconAnchor(DataDrivenPropertyValue<SymbolAnchorType> value) {
|
||||
if (value == getIconAnchor())
|
||||
return;
|
||||
auto impl_ = mutableImpl();
|
||||
impl_->layout.get<IconAnchor>() = value;
|
||||
baseImpl = std::move(impl_);
|
||||
observer->onLayerChanged(*this);
|
||||
}
|
||||
PropertyValue<AlignmentType> SymbolLayer::getDefaultIconPitchAlignment() {
|
||||
return IconPitchAlignment::defaultValue();
|
||||
}
|
||||
@@ -492,15 +508,15 @@ void SymbolLayer::setTextJustify(DataDrivenPropertyValue<TextJustifyType> value)
|
||||
baseImpl = std::move(impl_);
|
||||
observer->onLayerChanged(*this);
|
||||
}
|
||||
DataDrivenPropertyValue<TextAnchorType> SymbolLayer::getDefaultTextAnchor() {
|
||||
DataDrivenPropertyValue<SymbolAnchorType> SymbolLayer::getDefaultTextAnchor() {
|
||||
return TextAnchor::defaultValue();
|
||||
}
|
||||
|
||||
DataDrivenPropertyValue<TextAnchorType> SymbolLayer::getTextAnchor() const {
|
||||
DataDrivenPropertyValue<SymbolAnchorType> SymbolLayer::getTextAnchor() const {
|
||||
return impl().layout.get<TextAnchor>();
|
||||
}
|
||||
|
||||
void SymbolLayer::setTextAnchor(DataDrivenPropertyValue<TextAnchorType> value) {
|
||||
void SymbolLayer::setTextAnchor(DataDrivenPropertyValue<SymbolAnchorType> value) {
|
||||
if (value == getTextAnchor())
|
||||
return;
|
||||
auto impl_ = mutableImpl();
|
||||
|
||||
@@ -87,6 +87,11 @@ struct IconOffset : DataDrivenLayoutProperty<std::array<float, 2>> {
|
||||
static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; }
|
||||
};
|
||||
|
||||
struct IconAnchor : DataDrivenLayoutProperty<SymbolAnchorType> {
|
||||
static constexpr const char * key = "icon-anchor";
|
||||
static SymbolAnchorType defaultValue() { return SymbolAnchorType::Center; }
|
||||
};
|
||||
|
||||
struct IconPitchAlignment : LayoutProperty<AlignmentType> {
|
||||
static constexpr const char * key = "icon-pitch-alignment";
|
||||
static AlignmentType defaultValue() { return AlignmentType::Auto; }
|
||||
@@ -137,9 +142,9 @@ struct TextJustify : DataDrivenLayoutProperty<TextJustifyType> {
|
||||
static TextJustifyType defaultValue() { return TextJustifyType::Center; }
|
||||
};
|
||||
|
||||
struct TextAnchor : DataDrivenLayoutProperty<TextAnchorType> {
|
||||
struct TextAnchor : DataDrivenLayoutProperty<SymbolAnchorType> {
|
||||
static constexpr const char * key = "text-anchor";
|
||||
static TextAnchorType defaultValue() { return TextAnchorType::Center; }
|
||||
static SymbolAnchorType defaultValue() { return SymbolAnchorType::Center; }
|
||||
};
|
||||
|
||||
struct TextMaxAngle : LayoutProperty<float> {
|
||||
@@ -259,6 +264,7 @@ class SymbolLayoutProperties : public Properties<
|
||||
IconPadding,
|
||||
IconKeepUpright,
|
||||
IconOffset,
|
||||
IconAnchor,
|
||||
IconPitchAlignment,
|
||||
TextPitchAlignment,
|
||||
TextRotationAlignment,
|
||||
|
||||
@@ -53,16 +53,16 @@ MBGL_DEFINE_ENUM(SymbolPlacementType, {
|
||||
{ SymbolPlacementType::Line, "line" },
|
||||
});
|
||||
|
||||
MBGL_DEFINE_ENUM(TextAnchorType, {
|
||||
{ TextAnchorType::Center, "center" },
|
||||
{ TextAnchorType::Left, "left" },
|
||||
{ TextAnchorType::Right, "right" },
|
||||
{ TextAnchorType::Top, "top" },
|
||||
{ TextAnchorType::Bottom, "bottom" },
|
||||
{ TextAnchorType::TopLeft, "top-left" },
|
||||
{ TextAnchorType::TopRight, "top-right" },
|
||||
{ TextAnchorType::BottomLeft, "bottom-left" },
|
||||
{ TextAnchorType::BottomRight, "bottom-right" }
|
||||
MBGL_DEFINE_ENUM(SymbolAnchorType, {
|
||||
{ SymbolAnchorType::Center, "center" },
|
||||
{ SymbolAnchorType::Left, "left" },
|
||||
{ SymbolAnchorType::Right, "right" },
|
||||
{ SymbolAnchorType::Top, "top" },
|
||||
{ SymbolAnchorType::Bottom, "bottom" },
|
||||
{ SymbolAnchorType::TopLeft, "top-left" },
|
||||
{ SymbolAnchorType::TopRight, "top-right" },
|
||||
{ SymbolAnchorType::BottomLeft, "bottom-left" },
|
||||
{ SymbolAnchorType::BottomRight, "bottom-right" }
|
||||
});
|
||||
|
||||
MBGL_DEFINE_ENUM(TextJustifyType, {
|
||||
|
||||
@@ -11,12 +11,63 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
PositionedIcon PositionedIcon::shapeIcon(const ImagePosition& image, const std::array<float, 2>& iconOffset, const float iconRotation) {
|
||||
struct AnchorAlignment {
|
||||
AnchorAlignment(float horizontal_, float vertical_)
|
||||
: horizontalAlign(horizontal_), verticalAlign(vertical_) {
|
||||
}
|
||||
|
||||
float horizontalAlign;
|
||||
float verticalAlign;
|
||||
};
|
||||
|
||||
AnchorAlignment getAnchorAlignment(style::SymbolAnchorType anchor) {
|
||||
float horizontalAlign = 0.5;
|
||||
float verticalAlign = 0.5;
|
||||
|
||||
switch (anchor) {
|
||||
case style::SymbolAnchorType::Top:
|
||||
case style::SymbolAnchorType::Bottom:
|
||||
case style::SymbolAnchorType::Center:
|
||||
break;
|
||||
case style::SymbolAnchorType::Right:
|
||||
case style::SymbolAnchorType::TopRight:
|
||||
case style::SymbolAnchorType::BottomRight:
|
||||
horizontalAlign = 1;
|
||||
break;
|
||||
case style::SymbolAnchorType::Left:
|
||||
case style::SymbolAnchorType::TopLeft:
|
||||
case style::SymbolAnchorType::BottomLeft:
|
||||
horizontalAlign = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (anchor) {
|
||||
case style::SymbolAnchorType::Left:
|
||||
case style::SymbolAnchorType::Right:
|
||||
case style::SymbolAnchorType::Center:
|
||||
break;
|
||||
case style::SymbolAnchorType::Bottom:
|
||||
case style::SymbolAnchorType::BottomLeft:
|
||||
case style::SymbolAnchorType::BottomRight:
|
||||
verticalAlign = 1;
|
||||
break;
|
||||
case style::SymbolAnchorType::Top:
|
||||
case style::SymbolAnchorType::TopLeft:
|
||||
case style::SymbolAnchorType::TopRight:
|
||||
verticalAlign = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return AnchorAlignment(horizontalAlign, verticalAlign);
|
||||
}
|
||||
|
||||
PositionedIcon PositionedIcon::shapeIcon(const ImagePosition& image, const std::array<float, 2>& iconOffset, style::SymbolAnchorType iconAnchor, const float iconRotation) {
|
||||
AnchorAlignment anchorAlign = getAnchorAlignment(iconAnchor);
|
||||
float dx = iconOffset[0];
|
||||
float dy = iconOffset[1];
|
||||
float x1 = dx - image.displaySize()[0] / 2.0f;
|
||||
float x1 = dx - image.displaySize()[0] * anchorAlign.horizontalAlign;
|
||||
float x2 = x1 + image.displaySize()[0];
|
||||
float y1 = dy - image.displaySize()[1] / 2.0f;
|
||||
float y1 = dy - image.displaySize()[1] * anchorAlign.verticalAlign;
|
||||
float y2 = y1 + image.displaySize()[1];
|
||||
|
||||
return PositionedIcon { image, y1, y2, x1, x2, iconRotation };
|
||||
@@ -200,7 +251,7 @@ void shapeLines(Shaping& shaping,
|
||||
const std::vector<std::u16string>& lines,
|
||||
const float spacing,
|
||||
const float lineHeight,
|
||||
const style::TextAnchorType textAnchor,
|
||||
const style::SymbolAnchorType textAnchor,
|
||||
const style::TextJustifyType textJustify,
|
||||
const float verticalHeight,
|
||||
const WritingModeType writingMode,
|
||||
@@ -258,58 +309,23 @@ void shapeLines(Shaping& shaping,
|
||||
y += lineHeight;
|
||||
}
|
||||
|
||||
float horizontalAlign = 0.5;
|
||||
float verticalAlign = 0.5;
|
||||
auto anchorAlign = getAnchorAlignment(textAnchor);
|
||||
|
||||
switch (textAnchor) {
|
||||
case style::TextAnchorType::Top:
|
||||
case style::TextAnchorType::Bottom:
|
||||
case style::TextAnchorType::Center:
|
||||
break;
|
||||
case style::TextAnchorType::Right:
|
||||
case style::TextAnchorType::TopRight:
|
||||
case style::TextAnchorType::BottomRight:
|
||||
horizontalAlign = 1;
|
||||
break;
|
||||
case style::TextAnchorType::Left:
|
||||
case style::TextAnchorType::TopLeft:
|
||||
case style::TextAnchorType::BottomLeft:
|
||||
horizontalAlign = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (textAnchor) {
|
||||
case style::TextAnchorType::Left:
|
||||
case style::TextAnchorType::Right:
|
||||
case style::TextAnchorType::Center:
|
||||
break;
|
||||
case style::TextAnchorType::Bottom:
|
||||
case style::TextAnchorType::BottomLeft:
|
||||
case style::TextAnchorType::BottomRight:
|
||||
verticalAlign = 1;
|
||||
break;
|
||||
case style::TextAnchorType::Top:
|
||||
case style::TextAnchorType::TopLeft:
|
||||
case style::TextAnchorType::TopRight:
|
||||
verticalAlign = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
align(shaping, justify, horizontalAlign, verticalAlign,
|
||||
maxLineLength, lineHeight, lines.size());
|
||||
align(shaping, justify, anchorAlign.horizontalAlign, anchorAlign.verticalAlign, maxLineLength,
|
||||
lineHeight, lines.size());
|
||||
const uint32_t height = lines.size() * lineHeight;
|
||||
|
||||
// Calculate the bounding box
|
||||
shaping.top += -verticalAlign * height;
|
||||
shaping.top += -anchorAlign.verticalAlign * height;
|
||||
shaping.bottom = shaping.top + height;
|
||||
shaping.left += -horizontalAlign * maxLineLength;
|
||||
shaping.left += -anchorAlign.horizontalAlign * maxLineLength;
|
||||
shaping.right = shaping.left + maxLineLength;
|
||||
}
|
||||
|
||||
const Shaping getShaping(const std::u16string& logicalInput,
|
||||
const float maxWidth,
|
||||
const float lineHeight,
|
||||
const style::TextAnchorType textAnchor,
|
||||
const style::SymbolAnchorType textAnchor,
|
||||
const style::TextJustifyType textJustify,
|
||||
const float spacing,
|
||||
const Point<float>& translate,
|
||||
|
||||
@@ -32,7 +32,10 @@ private:
|
||||
float _angle;
|
||||
|
||||
public:
|
||||
static PositionedIcon shapeIcon(const ImagePosition&, const std::array<float, 2>& iconOffset, const float iconRotation);
|
||||
static PositionedIcon shapeIcon(const ImagePosition&,
|
||||
const std::array<float, 2>& iconOffset,
|
||||
style::SymbolAnchorType iconAnchor,
|
||||
const float iconRotation);
|
||||
|
||||
const ImagePosition& image() const { return _image; }
|
||||
float top() const { return _top; }
|
||||
@@ -45,7 +48,7 @@ public:
|
||||
const Shaping getShaping(const std::u16string& string,
|
||||
float maxWidth,
|
||||
float lineHeight,
|
||||
style::TextAnchorType textAnchor,
|
||||
style::SymbolAnchorType textAnchor,
|
||||
style::TextJustifyType textJustify,
|
||||
float spacing,
|
||||
const Point<float>& translate,
|
||||
|
||||
@@ -17,7 +17,7 @@ TEST(getIconQuads, normal) {
|
||||
style::Image::Impl("test", PremultipliedImage({1,1}), 1.0)
|
||||
};
|
||||
|
||||
auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -6.5f, -4.5f }}, 0);
|
||||
auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -6.5f, -4.5f }}, SymbolAnchorType::Center, 0);
|
||||
|
||||
GeometryCoordinates line;
|
||||
Shaping shapedText;
|
||||
@@ -42,7 +42,7 @@ TEST(getIconQuads, style) {
|
||||
style::Image::Impl("test", PremultipliedImage({1,1}), 1.0)
|
||||
};
|
||||
|
||||
auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, 0);
|
||||
auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0);
|
||||
|
||||
GeometryCoordinates line;
|
||||
Shaping shapedText;
|
||||
|
||||
Reference in New Issue
Block a user