Skip to content

Commit 1cbddb0

Browse files
RD-1319: Add hillshade layer (#219)
1 parent 6c22a0b commit 1cbddb0

File tree

6 files changed

+387
-0
lines changed

6 files changed

+387
-0
lines changed

Examples/Hillshade+SwiftUI.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//
2+
// Hillshade+SwiftUI.swift
3+
// MapTilerSDK Examples
4+
//
5+
6+
import SwiftUI
7+
import MapTilerSDK
8+
9+
/// Demonstrates adding a hillshade layer sourced from Terrain RGB DEM tiles.
10+
struct HillshadeExample: View {
11+
@State private var referenceStyle: MTMapReferenceStyle = .basic
12+
@State private var styleVariant: MTMapStyleVariant? = .defaultVariant
13+
@State private var mapView = MTMapView(options: MTMapOptions(zoom: 3.0))
14+
15+
init() {
16+
Task { await MTConfig.shared.setAPIKey("YOUR_API_KEY") }
17+
}
18+
19+
var body: some View {
20+
MTMapViewContainer(map: mapView) {}
21+
.referenceStyle(referenceStyle)
22+
.styleVariant(styleVariant)
23+
.didInitialize { Task { await addHillshade() } }
24+
}
25+
26+
private func addHillshade() async {
27+
guard let style = mapView.style else { return }
28+
29+
guard let apiKey = await MTConfig.shared.getAPIKey() else { return }
30+
31+
guard let url = URL(
32+
string: "https://api.maptiler.com/tiles/terrain-rgb-v2/tiles.json?key=\(apiKey)"
33+
) else { return }
34+
35+
let dem = MTRasterDEMSource(identifier: "hillshadeSource", url: url)
36+
37+
do {
38+
try await style.addSource(dem)
39+
40+
var hills = MTHillshadeLayer(identifier: "hills", sourceIdentifier: dem.identifier)
41+
hills.visibility = .visible
42+
hills.shadowColor = UIColor(hex: "#473B24")
43+
44+
try await style.addLayer(hills)
45+
} catch {
46+
print("Failed to add hillshade: \(error)")
47+
}
48+
}
49+
}

Sources/MapTilerSDK/Commands/Style/AddLayer.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ package struct AddLayer: MTCommand {
2121
return handleMTLineLayer(layer)
2222
} else if let layer = layer as? MTRasterLayer {
2323
return handleMTRasterLayer(layer)
24+
} else if let layer = layer as? MTHillshadeLayer {
25+
return handleMTHillshadeLayer(layer)
2426
} else if let layer = layer as? MTCircleLayer {
2527
return handleMTCircleLayer(layer)
2628
}
@@ -84,6 +86,14 @@ package struct AddLayer: MTCommand {
8486
return "\(MTBridge.mapObject).addLayer(\(unquoteExpressions(in: layerString)));"
8587
}
8688

89+
private func handleMTHillshadeLayer(_ layer: MTHillshadeLayer) -> JSString {
90+
guard let layerString: JSString = layer.toJSON() else {
91+
return emptyReturnValue
92+
}
93+
94+
return "\(MTBridge.mapObject).addLayer(\(unquoteExpressions(in: layerString)));"
95+
}
96+
8797
private func handleMTCircleLayer(_ layer: MTCircleLayer) -> JSString {
8898
guard let layerString: JSString = layer.toJSON() else {
8999
return emptyReturnValue

Sources/MapTilerSDK/Commands/Style/AddLayers.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ package struct AddLayers: MTCommand {
2626
jsString.append(handleMTLineLayer(layer))
2727
} else if let layer = layer as? MTRasterLayer {
2828
jsString.append(handleMTRasterLayer(layer))
29+
} else if let layer = layer as? MTHillshadeLayer {
30+
jsString.append(handleMTHillshadeLayer(layer))
2931
} else if let layer = layer as? MTCircleLayer {
3032
jsString.append(handleMTCircleLayer(layer))
3133
}
@@ -86,6 +88,14 @@ package struct AddLayers: MTCommand {
8688
return "\(MTBridge.mapObject).addLayer(\(layerString));"
8789
}
8890

91+
private func handleMTHillshadeLayer(_ layer: MTHillshadeLayer) -> JSString {
92+
guard let layerString: JSString = layer.toJSON() else {
93+
return emptyReturnValue
94+
}
95+
96+
return "\(MTBridge.mapObject).addLayer(\(layerString));"
97+
}
98+
8999
private func handleMTCircleLayer(_ layer: MTCircleLayer) -> JSString {
90100
guard let layerString: JSString = layer.toJSON() else {
91101
return emptyReturnValue
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// Copyright (c) 2026, MapTiler
3+
// All rights reserved.
4+
// SPDX-License-Identifier: BSD 3-Clause
5+
//
6+
// MTHillshadeIlluminationAnchor.swift
7+
// MapTilerSDK
8+
//
9+
10+
/// Direction of light source when map is rotated.
11+
public enum MTHillshadeIlluminationAnchor: String {
12+
/// The hillshade illumination is relative to the north direction.
13+
case map
14+
15+
/// The hillshade illumination is relative to the top of the viewport.
16+
case viewport
17+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//
2+
// Copyright (c) 2026, MapTiler
3+
// All rights reserved.
4+
// SPDX-License-Identifier: BSD 3-Clause
5+
//
6+
// MTHillshadeLayer+DSL.swift
7+
// MapTilerSDK
8+
//
9+
10+
import UIKit
11+
12+
// DSL
13+
extension MTHillshadeLayer {
14+
/// Adds layer to map DSL style.
15+
///
16+
/// Prefer `MTStyle/addLayer(_:)` on MTMapView instead.
17+
public func addToMap(_ mapView: MTMapView) {
18+
Task {
19+
let layer = MTHillshadeLayer(
20+
identifier: self.identifier,
21+
sourceIdentifier: self.sourceIdentifier,
22+
maxZoom: self.maxZoom,
23+
minZoom: self.minZoom,
24+
sourceLayer: self.sourceLayer,
25+
accentColor: self.accentColor,
26+
exaggeration: self.exaggeration,
27+
highlightColor: self.highlightColor,
28+
illuminationAnchor: self.illuminationAnchor,
29+
illuminationDirection: self.illuminationDirection,
30+
shadowColor: self.shadowColor,
31+
visibility: self.visibility
32+
)
33+
34+
try await mapView.style?.addLayer(layer)
35+
}
36+
}
37+
38+
// MARK: - Modifiers (not to be used outside DSL)
39+
@discardableResult
40+
public func maxZoom(_ value: Double) -> Self {
41+
self.maxZoom = value
42+
return self
43+
}
44+
45+
@discardableResult
46+
public func minZoom(_ value: Double) -> Self {
47+
self.minZoom = value
48+
return self
49+
}
50+
51+
@discardableResult
52+
public func sourceLayer(_ value: String) -> Self {
53+
self.sourceLayer = value
54+
return self
55+
}
56+
57+
@discardableResult
58+
public func accentColor(_ value: UIColor) -> Self {
59+
self.accentColor = value
60+
return self
61+
}
62+
63+
@discardableResult
64+
public func exaggeration(_ value: Double) -> Self {
65+
self.exaggeration = value
66+
return self
67+
}
68+
69+
@discardableResult
70+
public func highlightColor(_ value: UIColor) -> Self {
71+
self.highlightColor = value
72+
return self
73+
}
74+
75+
@discardableResult
76+
public func illuminationAnchor(_ value: MTHillshadeIlluminationAnchor) -> Self {
77+
self.illuminationAnchor = value
78+
return self
79+
}
80+
81+
@discardableResult
82+
public func illuminationDirection(_ value: Double) -> Self {
83+
self.illuminationDirection = value
84+
return self
85+
}
86+
87+
@discardableResult
88+
public func shadowColor(_ value: UIColor) -> Self {
89+
self.shadowColor = value
90+
return self
91+
}
92+
93+
@discardableResult
94+
public func visibility(_ value: MTLayerVisibility) -> Self {
95+
self.visibility = value
96+
return self
97+
}
98+
}

0 commit comments

Comments
 (0)