Learn how to perform and display a line of sight analysis in a 3D scene.
A line of sight analysis is a type of visibility analysis that calculates visibility (visible or obstructed) between a designated observer and target. It calculates whether the target is visible to the observer based on the environment and renders a line indicating visibility on the map.
In this tutorial, you will perform and display a line of sight analysis in a web scene. Your line of sight analysis will show which targets (hot spots) are visible, based on the terrain, from specified observation points in the Yosemite Valley.
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 105 106 107 112 113 114Change 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) }()
Set observer and target symbols
Your app will use graphics to depict the locations of the analyses observer and targets.
-
Create a private class named
Model
of typeObservable
. See the programming patterns page for more information on how to manage states.Object -
Create a
GraphicsOverlay
namedgraphics
and set some of its properties to display the observer and targets graphics.Overlay A graphics overlay is a container for graphics. It is used with a scene view to display graphics on a scene. You can add more than one graphics overlay to a scene view. Graphics overlays are displayed on top of all the other layers.
ContentView.swiftUse dark colors for code blocks 18 19 20 28 29 30 31Add line. Add line. Add line. Add line. Add line. Add line. Add line. private class Model: ObservableObject { // MARK: Graphics // The graphics overlay to add graphics to. let graphicsOverlay: GraphicsOverlay = { let graphicsOverlay = GraphicsOverlay() graphicsOverlay.sceneProperties.surfacePlacement = .absolute graphicsOverlay.sceneProperties.altitudeOffset = 5 return graphicsOverlay }() }
-
Create a private
Symbol
namedobserver
with a black fill color and white outline. Create another private symbol namedSymbol target
with a white fill color and black outline. These symbols are used to depict the location of the line of sight analyses observer and target respectively. Both symbols will be used to make graphics when the locations are determined.Symbol ContentView.swiftUse dark colors for code blocks 18 19 20 21 22 23 24 25 26 27 28 58 59 60 61Add 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. 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. Add line. Add line. private class Model: ObservableObject { // MARK: Graphics // The graphics overlay to add graphics to. let graphicsOverlay: GraphicsOverlay = { let graphicsOverlay = GraphicsOverlay() graphicsOverlay.sceneProperties.surfacePlacement = .absolute graphicsOverlay.sceneProperties.altitudeOffset = 5 return graphicsOverlay }() // The symbol to indicate the observer. private let observerSymbol: Symbol = { let symbol = SimpleMarkerSymbol( style: .circle, color: .black, size: 20 ) symbol.outline = SimpleLineSymbol( style: .solid, color: .white, width: 2 ) return symbol }() // The symbol to indicate the target. private var targetSymbol: Symbol = { let symbol = SimpleMarkerSymbol( style: .circle, color: .white, size: 20 ) symbol.outline = SimpleLineSymbol( style: .solid, color: .black, width: 2 ) return symbol }() }
Create line of sight analyses
Visual analyses help you make sense of complex 3D data contained by a scene. Use a LocationLineOfSight
to perform and display a line of sight analysis using observer and target locations.
-
Create an
AnalysisOverlay
namedanalysis
to contain and display the line of sight 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 64Add line. Add line. Add line. // MARK: Analysis // The analysis overlay to be added to the scene. let analysisOverlay = AnalysisOverlay()
-
Create a private variable named
observer
of typeLocation Point
.ContentView.swiftUse dark colors for code blocks 61 62 63 64 67Add line. Add line. // MARK: Analysis // The analysis overlay to be added to the scene. let analysisOverlay = AnalysisOverlay() // The location of the observer. private var observerLocation: Point?
-
Define a private method named
create
that accepts aLine Of Sight(scene Point :) Point
as a parameter. This method creates aLocationLineOfSight
analysis, adds it to the scene view analysis overlay, and adds the observer and target graphics to the graphics overlay.A
LocationLineOfSight
is used to perform and display a line of sight analysis between twoPoint
types, like a feature or graphic. Alternatively, you can perform and display a line of sight analysis between twoGeoElement
or graphic using aGeo
.Element Line Of Sight ContentView.swiftUse dark colors for code blocks 61 62 63 64 65 66 67 72Add line. Add line. Add line. Add line. // MARK: Analysis // The analysis overlay to be added to the scene. let analysisOverlay = AnalysisOverlay() // The location of the observer. private var observerLocation: Point? // Creates the line of sight with the scene point. func createLineOfSight(scenePoint: Point) { }
-
If the
observer
has no value, set it equal toLocation scene
. Create and display a graphic for the observer using the observer symbol previously created.Point ContentView.swiftUse dark colors for code blocks 61 62 63 64 65 66 67 68 69 70 78 79 80Add line. Add line. Add line. Add line. Add line. Add line. Add line. // MARK: Analysis // The analysis overlay to be added to the scene. let analysisOverlay = AnalysisOverlay() // The location of the observer. private var observerLocation: Point? // Creates the line of sight with the scene point. func createLineOfSight(scenePoint: Point) { if observerLocation == nil { // Updates the observer location. observerLocation = scenePoint // Adds the observer graphic to the graphics overlay. let observerGraphic = Graphic(geometry: scenePoint, symbol: observerSymbol) graphicsOverlay.addGraphic(observerGraphic) } }
-
If
observer
has a value, create a newLocation LocationLineOfSight
analysis using theobserver
andLocation scene
. Add the line of sight analysis to the analysis overlay usingPoint add
. Create the target graphic and add it to the graphics overlay to show the target point.Analysis( _:) ContentView.swiftUse dark colors for code blocks 68 69 70 71 72 73 74 75 76 77 78 88 89Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. // Creates the line of sight with the scene point. func createLineOfSight(scenePoint: Point) { if observerLocation == nil { // Updates the observer location. observerLocation = scenePoint // Adds the observer graphic to the graphics overlay. let observerGraphic = Graphic(geometry: scenePoint, symbol: observerSymbol) graphicsOverlay.addGraphic(observerGraphic) } else if let observerLocation { // Creates and sets the line of sight analysis with the tapped scene point. let lineOfSight = LocationLineOfSight(observerLocation: observerLocation, targetLocation: scenePoint) // Adds the line of sight to the analysis overlay. analysisOverlay.addAnalysis(lineOfSight) // Creates a target graphic and adds it to the graphics overlay. let targetGraphic = Graphic(geometry: scenePoint, symbol: targetSymbol) graphicsOverlay.addGraphic(targetGraphic) } }
-
Define a private method named
clear
to remove all line of sight analyses from the scene view, remove all graphics from the graphics overlay, and set theAnalyses() line
variable toOf Sight nil
.ContentView.swiftUse dark colors for code blocks 79 80 81 82 83 84 85 86 87 88 89 90Add line. Add line. Add line. Add line. Add line. Add line. else if let observerLocation { // Creates and sets the line of sight analysis with the tapped scene point. let lineOfSight = LocationLineOfSight(observerLocation: observerLocation, targetLocation: scenePoint) // Adds the line of sight to the analysis overlay. analysisOverlay.addAnalysis(lineOfSight) // Creates a target graphic and adds it to the graphics overlay. let targetGraphic = Graphic(geometry: scenePoint, symbol: targetSymbol) graphicsOverlay.addGraphic(targetGraphic) } } // Resets the observer location and clears all graphics and analyses. func clearAnalyses() { analysisOverlay.removeAllAnalyses() graphicsOverlay.removeAllGraphics() observerLocation = nil }
Display the line of sight analyses with touch events
Touch events determine where to place the observer and targets as well as display line of sight analyses. A user taps to place targets and then long-press and drags to place the observer and display line of sight analyses.
-
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 100 101 104 105 106 107 108 109 110 111 112 113 114 115 116 117 119 120 121 122Add line. Add line. Change 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, graphicsOverlays: [model.graphicsOverlay], analysisOverlays: [model.analysisOverlay]) } }
-
To add a new line of sight with each tap, add the
on
method to theSingle Tap Gesture(perform :) Scene
. In the closure, call the previously createdView create
method, passing in theLine Of Sight(scene Point :) scene
.Point ContentView.swiftUse dark colors for code blocks 116 117 118 119 125 126Add line. Add line. Add line. Add line. Add line. var body: some View { SceneView(scene: scene, graphicsOverlays: [model.graphicsOverlay], analysisOverlays: [model.analysisOverlay]) .onSingleTapGesture { _, scenePoint in // Places an observer point upon single touch. guard let scenePoint else { return } model.createLineOfSight(scenePoint: scenePoint) } }
Add a UI to control the line of sight analyses
To control the line of sight analyses, some UI is required.
-
Lastly, create a toolbar and add a "Clear" button to reset the analysis and graphics overlays. The "Clear" button calls the previously created
clear
method. This will allow users a fresh start to make more analyses.Analyses() ContentView.swiftUse dark colors for code blocks 116 117 118 119 120 121 122 123 124 125 134 135Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. var body: some View { SceneView(scene: scene, graphicsOverlays: [model.graphicsOverlay], analysisOverlays: [model.analysisOverlay]) .onSingleTapGesture { _, scenePoint in // Places an observer point upon single touch. guard let scenePoint else { return } model.createLineOfSight(scenePoint: scenePoint) } .toolbar { ToolbarItemGroup(placement: .bottomBar) { Button("Clear") { // Resets the line of sight. model.clearAnalyses() } } } }
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 set the location of the observer and tap to add target locations. The application performs and displays line of sight analyses between the observer and its targets.