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. 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 64 65 66 71 72 73Change 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
. See the programming patterns page for more information on how to manage states.Object ContentView.swiftUse dark colors for code blocks Add line. Add line. Add line. private class Model: ObservableObject { }
-
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 18 19 22 23Add 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.
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 18 19 20 21 22 23 24 30 31Add 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.
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 52 53Add 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()
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 and graphics is to add the analysis and graphics overlays to the scene view. In the
Content
struct, create a variable of typeView Model
with a@
property wrapper and add the overlays to the scene view.State Object ContentView.swiftUse dark colors for code blocks 59 60 63 64 65 66 67 68 69 70 71 72 73 74 75 76Add line. Add 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) }() }
-
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 and graphics overlays. 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 Monterey 12.5, Xcode 15, iOS 17. 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: