diff --git a/Apps/Examples/Examples/All Examples/BuildingExtrusionsExample.swift b/Apps/Examples/Examples/All Examples/BuildingExtrusionsExample.swift index bee87263040..d618249037b 100644 --- a/Apps/Examples/Examples/All Examples/BuildingExtrusionsExample.swift +++ b/Apps/Examples/Examples/All Examples/BuildingExtrusionsExample.swift @@ -98,6 +98,11 @@ final class BuildingExtrusionsExample: UIViewController, ExampleProtocol { // See https://docs.mapbox.com/mapbox-gl-js/example/3d-buildings/ for equivalent gl-js example internal func addBuildingExtrusions() { + let wallOnlyThreshold = 20 + let extrudeFilter = Exp(.eq) { + Exp(.get) { "extrude" } + "true" + } var layer = FillExtrusionLayer(id: "3d-buildings", source: "composite") layer.minZoom = 15 @@ -105,11 +110,12 @@ final class BuildingExtrusionsExample: UIViewController, ExampleProtocol { layer.fillExtrusionColor = .constant(StyleColor(.lightGray)) layer.fillExtrusionOpacity = .constant(0.6) - layer.filter = Exp(.eq) { - Exp(.get) { - "extrude" + layer.filter = Exp(.all) { + extrudeFilter + Exp(.gt) { + Exp(.get) { "height" } + wallOnlyThreshold } - "true" } layer.fillExtrusionHeight = .expression( @@ -140,6 +146,20 @@ final class BuildingExtrusionsExample: UIViewController, ExampleProtocol { layer.fillExtrusionAmbientOcclusionRadius = .constant(3.0) try! mapView.mapboxMap.addLayer(layer) + + var wallsOnlyExtrusionLayer = layer + wallsOnlyExtrusionLayer.id = "3d-buildings-wall" + wallsOnlyExtrusionLayer.filter = Exp(.all) { + extrudeFilter + Exp(.lte) { + Exp(.get) { "height" } + wallOnlyThreshold + } + } + + wallsOnlyExtrusionLayer.fillExtrusionLineWidth = .constant(2) + + try! mapView.mapboxMap.addLayer(wallsOnlyExtrusionLayer) } // MARK: - Actions diff --git a/CHANGELOG.md b/CHANGELOG.md index 855601c3196..67010df864f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Mapbox welcomes participation and contributions from everyone. +## main + +* Add experimental `FillExtrusionLayer.fillExtrusionLineWidth` that can switches fill extrusion rendering into wall rendering mode. Use this property to render the feature with the given width over the outlines of the geometry. + ## 11.7.0-beta.1 - 30 August, 2024 * Expose data-driven properties on annotation managers. Now it's possible to set data-driven properties globally on annotation manager and specify per-annotation overrides. diff --git a/Sources/MapboxMaps/Style/Generated/Layers/FillExtrusionLayer.swift b/Sources/MapboxMaps/Style/Generated/Layers/FillExtrusionLayer.swift index d12770e6ecb..ce0f600c7a9 100644 --- a/Sources/MapboxMaps/Style/Generated/Layers/FillExtrusionLayer.swift +++ b/Sources/MapboxMaps/Style/Generated/Layers/FillExtrusionLayer.swift @@ -162,6 +162,15 @@ public struct FillExtrusionLayer: Layer, Equatable { /// Transition options for `fillExtrusionHeight`. public var fillExtrusionHeightTransition: StyleTransition? + /// If a non-zero value is provided, it sets the fill-extrusion layer into wall rendering mode. The value is used to render the feature with the given width over the outlines of the geometry. Note: This property is experimental and some other fill-extrusion properties might not be supported with non-zero line width. + /// Default value: 0. Minimum value: 0. + @_documentation(visibility: public) + @_spi(Experimental) public var fillExtrusionLineWidth: Value? + + /// Transition options for `fillExtrusionLineWidth`. + @_documentation(visibility: public) + @_spi(Experimental) public var fillExtrusionLineWidthTransition: StyleTransition? + /// The opacity of the entire fill extrusion layer. This is rendered on a per-layer, not per-feature, basis, and data-driven styling is not available. /// Default value: 1. Value range: [0, 1] public var fillExtrusionOpacity: Value? @@ -249,6 +258,8 @@ public struct FillExtrusionLayer: Layer, Equatable { try paintContainer.encodeIfPresent(fillExtrusionFloodLightWallRadiusTransition, forKey: .fillExtrusionFloodLightWallRadiusTransition) try paintContainer.encodeIfPresent(fillExtrusionHeight, forKey: .fillExtrusionHeight) try paintContainer.encodeIfPresent(fillExtrusionHeightTransition, forKey: .fillExtrusionHeightTransition) + try paintContainer.encodeIfPresent(fillExtrusionLineWidth, forKey: .fillExtrusionLineWidth) + try paintContainer.encodeIfPresent(fillExtrusionLineWidthTransition, forKey: .fillExtrusionLineWidthTransition) try paintContainer.encodeIfPresent(fillExtrusionOpacity, forKey: .fillExtrusionOpacity) try paintContainer.encodeIfPresent(fillExtrusionOpacityTransition, forKey: .fillExtrusionOpacityTransition) try paintContainer.encodeIfPresent(fillExtrusionPattern, forKey: .fillExtrusionPattern) @@ -306,6 +317,8 @@ public struct FillExtrusionLayer: Layer, Equatable { fillExtrusionFloodLightWallRadiusTransition = try paintContainer.decodeIfPresent(StyleTransition.self, forKey: .fillExtrusionFloodLightWallRadiusTransition) fillExtrusionHeight = try paintContainer.decodeIfPresent(Value.self, forKey: .fillExtrusionHeight) fillExtrusionHeightTransition = try paintContainer.decodeIfPresent(StyleTransition.self, forKey: .fillExtrusionHeightTransition) + fillExtrusionLineWidth = try paintContainer.decodeIfPresent(Value.self, forKey: .fillExtrusionLineWidth) + fillExtrusionLineWidthTransition = try paintContainer.decodeIfPresent(StyleTransition.self, forKey: .fillExtrusionLineWidthTransition) fillExtrusionOpacity = try paintContainer.decodeIfPresent(Value.self, forKey: .fillExtrusionOpacity) fillExtrusionOpacityTransition = try paintContainer.decodeIfPresent(StyleTransition.self, forKey: .fillExtrusionOpacityTransition) fillExtrusionPattern = try paintContainer.decodeIfPresent(Value.self, forKey: .fillExtrusionPattern) @@ -374,6 +387,8 @@ public struct FillExtrusionLayer: Layer, Equatable { case fillExtrusionFloodLightWallRadiusTransition = "fill-extrusion-flood-light-wall-radius-transition" case fillExtrusionHeight = "fill-extrusion-height" case fillExtrusionHeightTransition = "fill-extrusion-height-transition" + case fillExtrusionLineWidth = "fill-extrusion-line-width" + case fillExtrusionLineWidthTransition = "fill-extrusion-line-width-transition" case fillExtrusionOpacity = "fill-extrusion-opacity" case fillExtrusionOpacityTransition = "fill-extrusion-opacity-transition" case fillExtrusionPattern = "fill-extrusion-pattern" @@ -752,6 +767,29 @@ extension FillExtrusionLayer { with(self, setter(\.fillExtrusionHeight, .expression(expression))) } + /// If a non-zero value is provided, it sets the fill-extrusion layer into wall rendering mode. The value is used to render the feature with the given width over the outlines of the geometry. Note: This property is experimental and some other fill-extrusion properties might not be supported with non-zero line width. + /// Default value: 0. Minimum value: 0. + @_documentation(visibility: public) + @_spi(Experimental) + public func fillExtrusionLineWidth(_ constant: Double) -> Self { + with(self, setter(\.fillExtrusionLineWidth, .constant(constant))) + } + + /// Transition property for `fillExtrusionLineWidth` + @_documentation(visibility: public) + @_spi(Experimental) + public func fillExtrusionLineWidthTransition(_ transition: StyleTransition) -> Self { + with(self, setter(\.fillExtrusionLineWidthTransition, transition)) + } + + /// If a non-zero value is provided, it sets the fill-extrusion layer into wall rendering mode. The value is used to render the feature with the given width over the outlines of the geometry. Note: This property is experimental and some other fill-extrusion properties might not be supported with non-zero line width. + /// Default value: 0. Minimum value: 0. + @_documentation(visibility: public) + @_spi(Experimental) + public func fillExtrusionLineWidth(_ expression: Exp) -> Self { + with(self, setter(\.fillExtrusionLineWidth, .expression(expression))) + } + /// The opacity of the entire fill extrusion layer. This is rendered on a per-layer, not per-feature, basis, and data-driven styling is not available. /// Default value: 1. Value range: [0, 1] public func fillExtrusionOpacity(_ constant: Double) -> Self { diff --git a/Tests/MapboxMapsTests/Style/Generated/IntegrationTests/Layers/FillExtrusionLayerIntegrationTests.swift b/Tests/MapboxMapsTests/Style/Generated/IntegrationTests/Layers/FillExtrusionLayerIntegrationTests.swift index c0ac85b337f..83411e697eb 100644 --- a/Tests/MapboxMapsTests/Style/Generated/IntegrationTests/Layers/FillExtrusionLayerIntegrationTests.swift +++ b/Tests/MapboxMapsTests/Style/Generated/IntegrationTests/Layers/FillExtrusionLayerIntegrationTests.swift @@ -53,6 +53,8 @@ final class FillExtrusionLayerIntegrationTests: MapViewIntegrationTestCase { layer.fillExtrusionFloodLightWallRadiusTransition = StyleTransition(duration: 10.0, delay: 10.0) layer.fillExtrusionHeight = Value.testConstantValue() layer.fillExtrusionHeightTransition = StyleTransition(duration: 10.0, delay: 10.0) + layer.fillExtrusionLineWidth = Value.testConstantValue() + layer.fillExtrusionLineWidthTransition = StyleTransition(duration: 10.0, delay: 10.0) layer.fillExtrusionOpacity = Value.testConstantValue() layer.fillExtrusionOpacityTransition = StyleTransition(duration: 10.0, delay: 10.0) layer.fillExtrusionPattern = Value.testConstantValue() diff --git a/Tests/MapboxMapsTests/Style/Generated/Layers/FillExtrusionLayerTests.swift b/Tests/MapboxMapsTests/Style/Generated/Layers/FillExtrusionLayerTests.swift index 4ef0a2bf3c4..778a0b7841c 100644 --- a/Tests/MapboxMapsTests/Style/Generated/Layers/FillExtrusionLayerTests.swift +++ b/Tests/MapboxMapsTests/Style/Generated/Layers/FillExtrusionLayerTests.swift @@ -106,6 +106,8 @@ final class FillExtrusionLayerTests: XCTestCase { layer.fillExtrusionFloodLightWallRadiusTransition = StyleTransition(duration: 10.0, delay: 10.0) layer.fillExtrusionHeight = Value.testConstantValue() layer.fillExtrusionHeightTransition = StyleTransition(duration: 10.0, delay: 10.0) + layer.fillExtrusionLineWidth = Value.testConstantValue() + layer.fillExtrusionLineWidthTransition = StyleTransition(duration: 10.0, delay: 10.0) layer.fillExtrusionOpacity = Value.testConstantValue() layer.fillExtrusionOpacityTransition = StyleTransition(duration: 10.0, delay: 10.0) layer.fillExtrusionPattern = Value.testConstantValue() @@ -147,6 +149,7 @@ final class FillExtrusionLayerTests: XCTestCase { XCTAssertEqual(layer.fillExtrusionFloodLightIntensity, Value.testConstantValue()) XCTAssertEqual(layer.fillExtrusionFloodLightWallRadius, Value.testConstantValue()) XCTAssertEqual(layer.fillExtrusionHeight, Value.testConstantValue()) + XCTAssertEqual(layer.fillExtrusionLineWidth, Value.testConstantValue()) XCTAssertEqual(layer.fillExtrusionOpacity, Value.testConstantValue()) XCTAssertEqual(layer.fillExtrusionPattern, Value.testConstantValue()) XCTAssertEqual(layer.fillExtrusionRoundedRoof, Value.testConstantValue()) @@ -183,6 +186,7 @@ final class FillExtrusionLayerTests: XCTestCase { .fillExtrusionFloodLightIntensity(Double.testConstantValue()) .fillExtrusionFloodLightWallRadius(Double.testConstantValue()) .fillExtrusionHeight(Double.testConstantValue()) + .fillExtrusionLineWidth(Double.testConstantValue()) .fillExtrusionOpacity(Double.testConstantValue()) .fillExtrusionPattern(String.testConstantValue()) .fillExtrusionRoundedRoof(Bool.testConstantValue()) @@ -213,6 +217,7 @@ final class FillExtrusionLayerTests: XCTestCase { XCTAssertEqual(layer.fillExtrusionFloodLightIntensity, Value.constant(Double.testConstantValue())) XCTAssertEqual(layer.fillExtrusionFloodLightWallRadius, Value.constant(Double.testConstantValue())) XCTAssertEqual(layer.fillExtrusionHeight, Value.constant(Double.testConstantValue())) + XCTAssertEqual(layer.fillExtrusionLineWidth, Value.constant(Double.testConstantValue())) XCTAssertEqual(layer.fillExtrusionOpacity, Value.constant(Double.testConstantValue())) XCTAssertEqual(layer.fillExtrusionPattern, Value.constant(.name(String.testConstantValue()))) XCTAssertEqual(layer.fillExtrusionRoundedRoof, Value.constant(Bool.testConstantValue()))