Learn how to perform and display a viewshed analysis in a 3D scene.
Viewshed analysis determines the visibility of terrain, buildings, and other 3D objects from an observer's location within a scene (using a specified field of view). The result indicates which areas are visible and which are obstructed when viewed from the observer's perspective.
In this tutorial, you will perform and display a viewshed analysis in a web scene. Your viewshed analysis will show visibility (visible or obstructed) and can be used to determine which hotspots in the Yosemite Valley are visible from a specified observer's perspective.
Prerequisites
Before starting this tutorial:
-
You need an ArcGIS Location Platform or ArcGIS Online account.
-
Your system meets the system requirements.
Steps
Open the Xcode project
-
To start this tutorial, first complete the Display a web scene tutorial or download and unzip the solution.
-
Open the
.xcodeproj
file in Xcode. -
If you downloaded the solution, get an access token and set the API key.
An API Key gives your app access to secure resources used in this tutorial.
-
Go to the Create an API key tutorial to obtain a new API key access token using your ArcGIS Location Platform or ArcGIS Online account. Ensure that the following privilege is enabled: Location services > Basemaps > Basemap styles service. Copy the access token as it will be used in the next step.
-
In Xcode, in the Project Navigator, click MainApp.swift.
-
In the Editor, set the
ArcGISEnvironment.apiKey
property on theArcGIS
with your access token.Environment MainApp.swiftUse dark colors for code blocks init() { ArcGISEnvironment.apiKey = APIKey("<#YOUR-ACCESS-TOKEN#>") }
-
Get the web scene item ID
You can use ArcGIS tools to create and view web scenes. Use the Scene Viewer to identify the web scene item ID. This item ID will be used later in the tutorial.
- Go to the Yosemite Valley Hotspots web scene in the Scene Viewer in ArcGIS Online. This web scene displays terrain and hotspots in the Yosemite Valley.
- Make a note of the item ID at the end of the browser's URL. The item ID should be 7558ee942b2547019f66885c44d4f0b1.
Update the scene
-
In Xcode, in the Project Navigator, click ContentView.swift.
-
In the editor, modify the
scene
variable to create aScene
for the web scene. To do this, create a portal item providing the web scene's item ID and aPortal
referencing ArcGIS Online.ContentView.swiftUse dark colors for code blocks 65 66 67 72 73 74Change line Change line Change line Change line // The Yosemite Valley hotspots scene. @State private var scene: ArcGIS.Scene = { let portalItem = PortalItem( portal: .arcGISOnline(connection: .anonymous), id: Item.ID("7558ee942b2547019f66885c44d4f0b1")! ) return Scene(item: portalItem) }()
Create a viewshed analysis
Visual analyses are used to help you make sense of complex 3D data contained by a scene. Use a LocationViewshed
to perform and display a viewshed analysis using a 3D point to define the observer's location.
-
Create a private class named
Model
of typeObservable
and an accompanying State Object reference in theObject Content
struct. See the programming patterns page for more information on how to manage states.View ContentView.swiftUse dark colors for code blocks 16 17 18 22 23 24 27 28 29 30 31 32 33 34 35 36 37Add line. Add line. Add line. Add line. Add line. import SwiftUI import ArcGIS private class Model: ObservableObject { } struct ContentView: View { // An ObservableObject containing the scene, graphics overlay, and analysis overlay. @StateObject private var model = Model() // The Yosemite Valley hotspots scene. @State private var scene: ArcGIS.Scene = { let portalItem = PortalItem( portal: .arcGISOnline(connection: .anonymous), id: Item.ID("7558ee942b2547019f66885c44d4f0b1")! ) return Scene(item: portalItem) }()
-
Create an
AnalysisOverlay
namedanalysis
to contain and display the viewshed analyses.Overlay An analysis overlay is a container for
Analysis
objects. It is used with a scene view to display visual analyses on a scene. You can add more than one analysis overlay to a scene view. Analysis overlays are displayed on top of all other layers and graphics overlays.ContentView.swiftUse dark colors for code blocks 19 20 23 24Add line. Add line. private class Model: ObservableObject { // The analysis overlay to be added to the scene. let analysisOverlay = AnalysisOverlay() }
-
Create a private
LocationViewshed
namedviewshed
.The viewshed analysis is added to a scene view using an analysis overlay. An analysis overlay is a container for analyses. It can be used to display visual analyses in a scene view. You can add more than one analysis overlay and they are displayed on top of all other layers.
ContentView.swiftUse dark colors for code blocks 19 20 21 22 23 25 26Add line. private class Model: ObservableObject { // The analysis overlay to be added to the scene. let analysisOverlay = AnalysisOverlay() let viewshed: LocationViewshed }
-
Create a
Double
variable namedmax
to track the viewshed's maximum distance. Set the viewshed'sDistance max
property to the model'sDistance max
property in aDistance did
observer to update the maximum distance when needed.Set ContentView.swiftUse dark colors for code blocks 19 20 21 22 23 24 25 31 32Add line. Add line. Add line. Add line. Add line. private class Model: ObservableObject { // The analysis overlay to be added to the scene. let analysisOverlay = AnalysisOverlay() let viewshed: LocationViewshed var maxDistance: Double { didSet { viewshed.maxDistance = maxDistance } } }
-
In
init()
, initialize all of the properties, make the viewshed not visible upon launch, and add the viewshed to the analysis overlay.ContentView.swiftUse dark colors for code blocks 19 20 21 22 23 24 25 26 27 28 29 30 31 46 47Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. private class Model: ObservableObject { // The analysis overlay to be added to the scene. let analysisOverlay = AnalysisOverlay() let viewshed: LocationViewshed var maxDistance: Double { didSet { viewshed.maxDistance = maxDistance } } init() { self.viewshed = LocationViewshed( location: Point(latitude: 0, longitude: 0), heading: 0, pitch: 90, horizontalAngle: 360, verticalAngle: 180, minDistance: 10, maxDistance: 12_000 ) viewshed.isVisible = false analysisOverlay.addAnalysis(viewshed) maxDistance = viewshed.maxDistance! } }
-
Define a private method named
set
that receives a point as a parameter. This method is used to set the location of the viewshed and make it visible, if it is not visible already.Viewshed Location(point :) ContentView.swiftUse dark colors for code blocks 53 54Add line. Add line. Add line. Add line. Add line. Add line. func setViewshedLocation(point: Point) { viewshed.location = point if !viewshed.isVisible { viewshed.isVisible = true } } }
-
Define a private method named
hide
. This method is used to hide the viewshed.Viewshed() ContentView.swiftUse dark colors for code blocks 47 48 49 50 51 52 53 57 58Add line. Add line. Add line. func setViewshedLocation(point: Point) { viewshed.location = point if !viewshed.isVisible { viewshed.isVisible = true } } func hideViewshed() { viewshed.isVisible = false } }
Display the viewshed analysis with touch events
Touch events determine where to place the observer for the viewshed analysis. A user will long-press and drag to reveal and move the observer's location.
-
The first step to displaying the analyses is to add the analysis overlay to the scene view. In the
Content
struct, modify the scene view to add the model's analysis overlay.View ContentView.swiftUse dark colors for code blocks 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 79 80 81 82Add line. struct ContentView: View { // An ObservableObject containing the scene, graphics overlay, and analysis overlay. @StateObject private var model = Model() // The Yosemite Valley hotspots scene. @State private var scene: ArcGIS.Scene = { let portalItem = PortalItem( portal: .arcGISOnline(connection: .anonymous), id: Item.ID("7558ee942b2547019f66885c44d4f0b1")! ) return Scene(item: portalItem) }() var body: some View { SceneView(scene: scene, analysisOverlays: [model.analysisOverlay]) } }
-
To add or move the viewshed analysis upon long press and drag, add the
on
method to theLong Press Gesture(perform :) Scene
. In the closure, call the previously createdView set
method, passing in theViewshed Location(point :) scene
.Point ContentView.swiftUse dark colors for code blocks 76 77 78 79 84 85Add line. Add line. Add line. Add line. var body: some View { SceneView(scene: scene, analysisOverlays: [model.analysisOverlay]) .onLongPressGesture { _, scenePoint in guard let scenePoint = scenePoint else { return } model.setViewshedLocation(point: scenePoint) } }
Add a UI to control the viewshed analysis
To control the viewshed analysis, some UI elements are required.
-
Add a toolbar to the bottom of the scene view.
ContentView.swiftUse dark colors for code blocks 76 77 78 79 80 81 82 83 84 90 91Add line. Add line. Add line. Add line. Add line. var body: some View { SceneView(scene: scene, analysisOverlays: [model.analysisOverlay]) .onLongPressGesture { _, scenePoint in guard let scenePoint = scenePoint else { return } model.setViewshedLocation(point: scenePoint) } .toolbar { ToolbarItemGroup(placement: .bottomBar) { } } }
-
Add a
Slider
namedslider
to the toolbar with the model'smax
property as its value andDistance 10...12
as the range. The slider changes the viewshed's maximum distance by expanding or contracting the size of the observer's field of view. The_000 maximum
andValue minimum
properties define the range of values the user can select to calculate the viewshed. You set an action on the slider using a selector for a method that will be added in a later step.Value ContentView.swiftUse dark colors for code blocks 85 86 87 90 91 92Add line. Add line. .toolbar { ToolbarItemGroup(placement: .bottomBar) { Slider(value: $model.maxDistance, in: 10...12_000) .frame(width: 300) } }
-
Lastly, create a toolbar and add a "Clear" button to reset the analysis overlay. The "Clear" button calls the previously created
hide
method. This will allow users a fresh start to make more analyses.Viewshed() ContentView.swiftUse dark colors for code blocks 85 86 87 88 89 90 96 97 98Add line. Add line. Add line. Add line. Add line. .toolbar { ToolbarItemGroup(placement: .bottomBar) { Slider(value: $model.maxDistance, in: 10...12_000) .frame(width: 300) Spacer() Button("Clear") { // Resets the line of sight. model.hideViewshed() } } }
Run the app
Press Command + R to run the app.
If you are using the Xcode simulator your system must meet these minimum requirements: macOS 14 (Sonoma), Xcode 16, iOS 18. If you are using a physical device, then refer to the system requirements.
You should see a scene of hotspots in the Yosemite Valley. Long-press and drag to display and move a viewshed analysis to explore the visibility of terrain from various locations.
What's next?
Learn how to use additional API features, ArcGIS location services, and ArcGIS tools in these tutorials: