Skip to content

[New] Apply hillshade renderer to raster #592

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 45 commits into from
May 7, 2025
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
f6fba1a
add sample
rolson May 5, 2025
2e0a633
fix offline data
rolson May 5, 2025
a32751c
apply renderer
rolson May 5, 2025
990a524
update sample code
rolson May 5, 2025
ff25f16
add error handling
rolson May 5, 2025
8f7409d
fix sample
rolson May 5, 2025
42b7a56
simplify
rolson May 6, 2025
32515f1
start adding settings view
rolson May 6, 2025
fefaa70
add snippet
rolson May 6, 2025
4f52d21
add preview
rolson May 6, 2025
ee199fa
try not to use a model
rolson May 6, 2025
953d63c
fixes
rolson May 6, 2025
f190a9d
make state private
rolson May 6, 2025
6af7169
update screenshots
rolson May 6, 2025
b258fc9
update metadata
rolson May 6, 2025
62b02c7
fix popover
rolson May 6, 2025
7438313
comment
rolson May 6, 2025
7038b36
Merge branch 'v.next' into ryan/ApplyHillshadeRendererToRaster
rolson May 6, 2025
f2ca3f6
reorder image names
rolson May 6, 2025
e98eb9c
update category
rolson May 6, 2025
f0cc049
update proj
rolson May 6, 2025
d2e93c9
Apply suggestions from code review
rolson May 6, 2025
e871741
remove comment
rolson May 6, 2025
dc1fa31
Merge branch 'ryan/ApplyHillshadeRendererToRaster' of https://github.…
rolson May 6, 2025
b5974c3
pr feedback
rolson May 6, 2025
1b74a8e
remove preview
rolson May 6, 2025
364b345
pr feedback
rolson May 6, 2025
3b73cbe
Apply suggestions from code review
rolson May 7, 2025
fc48505
odr resource updates
rolson May 7, 2025
12a59e4
Merge branch 'ryan/ApplyHillshadeRendererToRaster' of https://github.…
rolson May 7, 2025
6ef72e4
odr fixes
rolson May 7, 2025
3ff6bd2
fix compile error
rolson May 7, 2025
198b8f3
fix odr resource
rolson May 7, 2025
8832161
update link
rolson May 7, 2025
02adeed
Merge branch 'v.next' into ryan/ApplyHillshadeRendererToRaster
rolson May 7, 2025
0e91139
add settings view to copy files phase
rolson May 7, 2025
e0a607d
remove file
rolson May 7, 2025
4079e83
Apply suggestions from code review
rolson May 7, 2025
6252280
Update Samples.xcodeproj/project.pbxproj
rolson May 7, 2025
941dd1e
re-sort
rolson May 7, 2025
c210c71
Merge branch 'ryan/ApplyHillshadeRendererToRaster' of https://github.…
rolson May 7, 2025
0c16d27
sort portal data folder
rolson May 7, 2025
f7654a3
add dismiss button
rolson May 7, 2025
6de6f71
update screen shot
rolson May 7, 2025
3bab19c
Merge branch 'v.next' into ryan/ApplyHillshadeRendererToRaster
rolson May 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Samples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@
883C121729C914E100062FF9 /* DownloadPreplannedMapAreaView.MapPicker.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = 883C121429C9136600062FF9 /* DownloadPreplannedMapAreaView.MapPicker.swift */; };
883C121829C914E100062FF9 /* DownloadPreplannedMapAreaView.Model.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = E0D04FF128A5390000747989 /* DownloadPreplannedMapAreaView.Model.swift */; };
883C121929C914E100062FF9 /* DownloadPreplannedMapAreaView.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = E070A0A2286F3B6000F2B606 /* DownloadPreplannedMapAreaView.swift */; };
88E52E6F2DC96C3F00F48409 /* ApplyHillshadeRendererToRasterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E52E6E2DC96C3F00F48409 /* ApplyHillshadeRendererToRasterView.swift */; };
88E52E702DC970A800F48409 /* ApplyHillshadeRendererToRasterView.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = 88E52E6E2DC96C3F00F48409 /* ApplyHillshadeRendererToRasterView.swift */; };
88E52E7F2DC97ED700F48409 /* srtm in Resources */ = {isa = PBXBuildFile; fileRef = 88E52E7E2DC97EC700F48409 /* srtm */; settings = {ASSET_TAGS = (ApplyHillshadeRendererToRaster, ); }; };
88E52E812DCA703B00F48409 /* ApplyHillshadeRendererToRasterView.SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E52E802DCA703B00F48409 /* ApplyHillshadeRendererToRasterView.SettingsView.swift */; };
88F93CC129C3D59D0006B28E /* CreateAndEditGeometriesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F93CC029C3D59C0006B28E /* CreateAndEditGeometriesView.swift */; };
88F93CC229C4D3480006B28E /* CreateAndEditGeometriesView.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = 88F93CC029C3D59C0006B28E /* CreateAndEditGeometriesView.swift */; };
9503056E2C46ECB70091B32D /* ShowDeviceLocationUsingIndoorPositioningView.Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9503056D2C46ECB70091B32D /* ShowDeviceLocationUsingIndoorPositioningView.Model.swift */; };
Expand Down Expand Up @@ -615,6 +619,7 @@
dstPath = "";
dstSubfolderSpec = 7;
files = (
88E52E702DC970A800F48409 /* ApplyHillshadeRendererToRasterView.swift in Copy Source Code Files */,
00FA4E5F2DC568DF008A34CF /* AddRastersAndFeatureTablesFromGeopackageView.swift in Copy Source Code Files */,
0072C7FB2DBAC1A0001502CA /* AddIntegratedMeshLayerView.swift in Copy Source Code Files */,
1C38915E2DBC3EDC00ADFDDC /* AddWFSLayerView.swift in Copy Source Code Files */,
Expand Down Expand Up @@ -971,6 +976,9 @@
79B7B8092A1BF8EC00F57C27 /* CreateAndSaveKMLView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateAndSaveKMLView.swift; sourceTree = "<group>"; };
79D84D0D2A815C5B00F45262 /* AddCustomDynamicEntityDataSourceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddCustomDynamicEntityDataSourceView.swift; sourceTree = "<group>"; };
883C121429C9136600062FF9 /* DownloadPreplannedMapAreaView.MapPicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadPreplannedMapAreaView.MapPicker.swift; sourceTree = "<group>"; };
88E52E6E2DC96C3F00F48409 /* ApplyHillshadeRendererToRasterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplyHillshadeRendererToRasterView.swift; sourceTree = "<group>"; };
88E52E7E2DC97EC700F48409 /* srtm */ = {isa = PBXFileReference; lastKnownFileType = folder; path = srtm; sourceTree = "<group>"; };
88E52E802DCA703B00F48409 /* ApplyHillshadeRendererToRasterView.SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplyHillshadeRendererToRasterView.SettingsView.swift; sourceTree = "<group>"; };
88F93CC029C3D59C0006B28E /* CreateAndEditGeometriesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateAndEditGeometriesView.swift; sourceTree = "<group>"; };
9503056D2C46ECB70091B32D /* ShowDeviceLocationUsingIndoorPositioningView.Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowDeviceLocationUsingIndoorPositioningView.Model.swift; sourceTree = "<group>"; };
9537AFD62C220EF0000923C5 /* ExchangeSetwithoutUpdates */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ExchangeSetwithoutUpdates; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1365,6 +1373,7 @@
004A2BA12BED456500C297CE /* Apply scheduled updates to preplanned map area */,
4C8126DB2DBBCED7006EF7D2 /* Apply style to WMS layer */,
D75362CC2A1E862B00D83028 /* Apply unique value renderer */,
88E52E6D2DC969CF00F48409 /* Apply hillshade renderer to raster */,
1C8EC7422BAE2891001A6929 /* Augment reality to collect data */,
D7084FA42AD771AA00EC7F4F /* Augment reality to fly over scene */,
1C2538472BABAC7B00337307 /* Augment reality to navigate route */,
Expand Down Expand Up @@ -1595,6 +1604,7 @@
00CCB8A6285D059300BBAB70 /* Portal Data */ = {
isa = PBXGroup;
children = (
88E52E712DC97BA500F48409 /* ae9739163a76437ea02482e1a807b806 */,
D762DA0D2D94C750001052DD /* 0fd3a39660d54c12b05d5f81f207dffd */,
D74C8C002ABA6202007C76B8 /* 1bd036f221f54a99abc9e46ff3511cbf */,
D7781D472B7EB03400E53C51 /* 4caec8c55ea2463982f1af7d9611b8d5 */,
Expand Down Expand Up @@ -2046,6 +2056,23 @@
path = "Add custom dynamic entity data source";
sourceTree = "<group>";
};
88E52E6D2DC969CF00F48409 /* Apply hillshade renderer to raster */ = {
isa = PBXGroup;
children = (
88E52E6E2DC96C3F00F48409 /* ApplyHillshadeRendererToRasterView.swift */,
88E52E802DCA703B00F48409 /* ApplyHillshadeRendererToRasterView.SettingsView.swift */,
);
path = "Apply hillshade renderer to raster";
sourceTree = "<group>";
};
88E52E712DC97BA500F48409 /* ae9739163a76437ea02482e1a807b806 */ = {
isa = PBXGroup;
children = (
88E52E7E2DC97EC700F48409 /* srtm */,
);
path = ae9739163a76437ea02482e1a807b806;
sourceTree = "<group>";
};
88F93CBE29C3D4E30006B28E /* Create and edit geometries */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -3428,6 +3455,7 @@
AnimateImagesWithImageOverlay,
ApplyDictionaryRendererToFeatureLayer,
ApplyDictionaryRendererToGraphicsOverlay,
ApplyHillshadeRendererToRaster,
ApplyScheduledUpdatesToPreplannedMapArea,
AugmentRealityToShowTabletopScene,
ChangeCameraController,
Expand Down Expand Up @@ -3513,6 +3541,7 @@
D74C8C022ABA6202007C76B8 /* emoji-mobile.stylx in Resources */,
D7CE9FA32AE2F595008F7A5F /* san-diego-eagle-locator in Resources */,
D70539102CD012BB00F63F4A /* militaryoverlay.geodatabase in Resources */,
88E52E7F2DC97ED700F48409 /* srtm in Resources */,
D76000B72AF19FCA00B3084D /* SanFrancisco.mmpk in Resources */,
D762AF652BF6A96100ECE3C7 /* loudoun_anno.geodatabase in Resources */,
792222DD2A81AA5D00619FFE /* AIS_MarineCadastre_SelectedVessels_CustomDataSource.jsonl in Resources */,
Expand Down Expand Up @@ -3748,6 +3777,7 @@
D751018E2A2E962D00B8FA48 /* IdentifyLayerFeaturesView.swift in Sources */,
F1E71BF1289473760064C33F /* AddRasterFromFileView.swift in Sources */,
00B04273282EC59E0072E1B4 /* AboutView.swift in Sources */,
88E52E6F2DC96C3F00F48409 /* ApplyHillshadeRendererToRasterView.swift in Sources */,
7573E81F29D6134C00BEED9C /* TraceUtilityNetworkView.swift in Sources */,
D7781D4B2B7ECCB700E53C51 /* NavigateRouteWithReroutingView.Model.swift in Sources */,
4D2ADC6929C50C4C003B367F /* AddDynamicEntityLayerView.SettingsView.swift in Sources */,
Expand Down Expand Up @@ -3802,6 +3832,7 @@
D7114A0D2BDC6A3300FA68CA /* EditWithBranchVersioningView.Model.swift in Sources */,
00B04FB5283EEBA80026C882 /* DisplayOverviewMapView.swift in Sources */,
D718A1E72B570F7500447087 /* OrbitCameraAroundObjectView.Model.swift in Sources */,
88E52E812DCA703B00F48409 /* ApplyHillshadeRendererToRasterView.SettingsView.swift in Sources */,
D71C5F642AAA7A88006599FD /* CreateSymbolStylesFromWebStylesView.swift in Sources */,
D7CC33FF2A31475C00198EDF /* ShowLineOfSightBetweenPointsView.swift in Sources */,
D70BE5792A5624A80022CA02 /* CategoriesView.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2025 Esri
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import ArcGIS
import SwiftUI

extension ApplyHillshadeRendererToRasterView {
struct SettingsView: View {
/// The renderer that this view updates.
@Binding var renderer: HillshadeRenderer
/// The altitude angle of the renderer.
@State private var altitude: Double = 0
/// The azimuth angle of the renderer.
@State private var azimuth: Double = 0
/// The slope type of the renderer.
@State private var slopeType: HillshadeRenderer.SlopeType?

var body: some View {
NavigationStack {
Form {
Section {
LabeledContent("Altitude", value: altitude, format: .number)
Slider(value: $altitude, in: 0...360, step: 1)
}
Section {
LabeledContent("Azimuth", value: azimuth, format: .number)
Slider(value: $azimuth, in: 0...360, step: 1)
}
Section {
Picker("Slope Type", selection: $slopeType) {
Text("None")
.tag(nil as HillshadeRenderer.SlopeType?)
Text("Degree")
.tag(Optional(HillshadeRenderer.SlopeType.degree))
Text("Percent Rise")
.tag(Optional(HillshadeRenderer.SlopeType.percentRise))
Text("Scaled")
.tag(Optional(HillshadeRenderer.SlopeType.scaled))
}
}
}
.onAppear {
// Initialize the state when the view appears.
altitude = renderer.altitude.converted(to: .degrees).value
azimuth = renderer.azimuth.converted(to: .degrees).value
slopeType = renderer.slopeType
}
.onChange(of: altitude) { updateRenderer(previousRenderer: renderer) }
.onChange(of: azimuth) { updateRenderer(previousRenderer: renderer) }
.onChange(of: slopeType) { updateRenderer(previousRenderer: renderer) }
.navigationTitle("Hillshade Renderer Settings")
.navigationBarTitleDisplayMode(.inline)
}
}

/// Updates the renderer to the latest state.
func updateRenderer(previousRenderer: HillshadeRenderer) {
renderer = HillshadeRenderer(
altitude: altitude,
azimuth: azimuth,
slopeType: slopeType,
zFactor: previousRenderer.zFactor,
pixelSizeFactor: previousRenderer.pixelSizeFactor,
pixelSizePower: previousRenderer.pixelSizePower,
outputBitDepth: previousRenderer.outputBitDepth
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright 2025 Esri
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import ArcGIS
import SwiftUI

struct ApplyHillshadeRendererToRasterView: View {
/// The model used to store the geo model and other expensive objects
/// used in this view.
class Model: ObservableObject {
/// The map that will be shown.
let map: Map

/// The raster layer in the map.
private let rasterLayer: RasterLayer

/// The raster renderer.
var renderer: HillshadeRenderer {
didSet {
// When the renderer is updated, update the layer accordingly.
rasterLayer.renderer = renderer
}
}

init() {
// Gets the raster file URL.
let rasterFileURL = Bundle.main.url(forResource: "srtm", withExtension: "tiff", subdirectory: "srtm")!

// Creates a raster with the file URL.
let raster = Raster(fileURL: rasterFileURL)

// Creates a raster layer using the raster object.
rasterLayer = RasterLayer(raster: raster)

// Apply the hillshade renderer to the raster layer.
renderer = HillshadeRenderer(
altitude: 45,
azimuth: 315,
slopeType: nil,
zFactor: 0.000016,
pixelSizeFactor: 1,
pixelSizePower: 1,
outputBitDepth: 8
)
rasterLayer.renderer = renderer

// Create our map.
map = Map(basemap: .init(baseLayer: rasterLayer))
}
}

/// The view model for the sample.
@StateObject private var model = Model()

/// A boolean value indicating if the settings panel is presented.
@State private var isSettingsPanelPresented: Bool = false

var body: some View {
// Creates a map view to display the map.
MapView(map: model.map)
.toolbar {
ToolbarItem(placement: .bottomBar) {
Button {
isSettingsPanelPresented = true
} label: {
Text("Settings")
}
.popover(isPresented: $isSettingsPanelPresented, arrowEdge: .bottom) {
ApplyHillshadeRendererToRasterView.SettingsView(
renderer: $model.renderer
)
.presentationDetents([.medium])
.frame(idealWidth: 320, idealHeight: 380)
}
}
}
}
}

#Preview {
ApplyHillshadeRendererToRasterView()
}
32 changes: 32 additions & 0 deletions Shared/Samples/Apply hillshade renderer to raster/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Apply hillshade renderer to raster

Apply a hillshade renderer to a raster.

![Image of Apply hillshade renderer to raster sample](ApplyHillshadeRendererToRaster.png)

## Use case

An environmental agency may track coastal erosion by comparing images of an area taken over a longer period of time with hillshade renderers applied.

## How to use the sample

Choose and adjust the settings to update the hillshade renderer on the raster layer. The sample allows you to change the Altitude, Azimuth, and Slope Type.

## How it works

1. Create a `Raster` from a grayscale raster file.
2. Create a `RasterLayer` from the raster.
3. Create a `Basemap` from the raster layer and set it to the map.
4. Create a `HillshadeRenderer`, specifying the altitude, azimuth, slope type and other properties.
5. Set the hillshade renderer to be used on the raster layer.

## Relevant API

* Basemap
* HillshadeRenderer
* Raster
* RasterLayer

## Tags

altitude, angle, azimuth, raster, slope, visualization
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"category": "Visualization",
"description": "Apply a hillshade renderer to a raster.",
"ignore": false,
"images": [
"apply-hillshade-renderer-to-raster-settings.png",
"apply-hillshade-renderer-to-raster.png"
],
"keywords": [
"altitude",
"angle",
"azimuth",
"raster",
"slope",
"visualization",
"Basemap",
"HillshadeRenderer",
"Raster",
"RasterLayer"
],
"offline_data": [
"ae9739163a76437ea02482e1a807b806"
],
"redirect_from": [],
"relevant_apis": [
"Basemap",
"HillshadeRenderer",
"Raster",
"RasterLayer"
],
"snippets": [
"ApplyHillshadeRendererToRasterView.swift",
"ApplyHillshadeRendererToRasterView.SettingsView.swift"
],
"title": "Apply hillshade renderer to raster"
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.