Learn how to evaluate the horizontal, vertical, and direct distances between two points in a 3D Scene.
A distance measurement analysis is a type of measurement analysis that calculates and displays the distance between start point and end point locations. The analysis evaluates the vertical, horizontal, and direct distances between the two 3D points and renders a measurement visualization on-screen.
In this tutorial you will perform and display a distance measurement analysis in a web scene
Prerequisites
Before starting this tutorial:
-
You need an ArcGIS Location Platform or ArcGIS Online account.
-
Your system meets the system requirements.
Develop or Download
You have two options for completing this tutorial:
Option 1: Develop the code
To start the tutorial, complete the Display a web scene tutorial. This creates a scene to display the trails, trailheads, and parks in the Santa Monica Mountains.
Continue with the following instructions to evaluate the horizontal, vertical, and direct distances between two points in a 3D Scene.
Get the web scene item ID
You can use ArcGIS tools
- Go to the Yosemite Valley Hotspots web scene in the Scene Viewer in ArcGIS Online
ArcGIS Online is a GIS mapping, analytics, data hosting, and content management software as a service (SaaS) product. It includes applications, tools, APIs, and location services for users and developers. It is subscription-based and requires an ArcGIS Online account. . This web scene displays terrain and hotspots in the Yosemite Valley. - Make a note of the item ID
An item ID is a unique identifier representing a single item stored, managed, and accessed in a portal, such as a web map, hosted layer, or file. 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
scenevariable to create aScenefor the web scene. To do this, create a portal item providing the web scene's item IDAn item ID is a unique identifier representing a single item stored, managed, and accessed in a portal, such as a web map, hosted layer, or file. and aPortalreferencing ArcGIS Online.ContentView.swiftUse dark colors for code blocks 58 59 60 65 66 67Change 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 distance measurement analysis
Use a LocationDistanceMeasurement to perform and display a distance measurement analysis using 3D points to define the start and end locations.
-
Create a private class named
Modelof typeObservableand an accompanying State Object reference in the ContentView struct. See the programming patterns page for more information on how to manage states.Object ContentView.swiftUse dark colors for code blocks 21 22 23 26Add line. Add line. Add line. Add line. Add line. private class Model: ObservableObject { } struct ContentView: View { // An ObservableObject containing the scene, and analysis overlay. @StateObject private var model = Model() -
Create an
AnalysisOverlaynamedanalysisto contain and display the distance measurement analyses.Overlay An analysis overlay is a container for
Analysisobjects, such as theLocationDistanceMeasurement. It is used to render visual analyses on a sceneA scene is a collection of layers that are displayed in 3D. It is typically composed of a basemap layer, data layers, and 3D data. in a scene viewA scene view is a user interface that displays scene layers and graphics in 3D. It uses a camera to control the visible area of the scene and supports user interactions such as pan, zoom, tilt, and rotate. . You can add more than one analysis overlay to a scene view. Analysis overlays are displayed on top of all other layersA layer is a reference to a collection of geographic data that is used to access and display data. The data for layers are typically provided by the basemap layer service and data services. and graphics overlaysA graphics overlay is a client-side, temporary container of graphics to display on a map view or scene view. .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
LocationDistanceMeasurementnamedmeasurement. Upon launch, the distance measurement visualization should not be visible.ContentView.swiftUse dark colors for code blocks 18 19 20 21 22 30 31Add 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 measurement: LocationDistanceMeasurement = { let point = Point(x: -119.5968, y: 37.7567, z: 58.5011, spatialReference: .wgs84) let measurement = LocationDistanceMeasurement(startLocation: point, endLocation: point) measurement.isVisible = false measurement.unitSystem = .metric return measurement }() } -
In
init(), add the distance measurement to the analysis overlay.The distance measurement 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
A layer is a reference to a collection of geographic data that is used to access and display data. The data for layers are typically provided by the basemap layer service and data services. .ContentView.swiftUse dark colors for code blocks 18 19 20 21 22 23 24 25 26 27 28 29 30 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51Add line. Add line. Add line. private class Model: ObservableObject { // The analysis overlay to be added to the scene. let analysisOverlay = AnalysisOverlay() let measurement: LocationDistanceMeasurement = { let point = Point(x: -119.5968, y: 37.7567, z: 58.5011, spatialReference: .wgs84) let measurement = LocationDistanceMeasurement(startLocation: point, endLocation: point) measurement.isVisible = false measurement.unitSystem = .metric return measurement }() init() { analysisOverlay.addAnalysis(measurement) } func moveDistanceMeasurement(point: Point) { if measurement.startLocation == measurement.endLocation { measurement.startLocation = point } else { measurement.endLocation = point } measurement.isVisible = true } func clearMeasurement() { measurement.isVisible = false let point = Point(x: 0, y: 0, z: 0, m: 0, spatialReference: .wgs84) measurement.startLocation = point measurement.endLocation = point } } -
Define a method named
movethat receives a pointDistance Measurement(point :) A point is a type of geometry containing a single set of as a parameter. This method is used to set the distance measurement analysis and make it visible, if it's not visible already.x,ycoordinates and a spatial reference.ContentView.swiftUse dark colors for code blocks 43Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. func moveDistanceMeasurement(point: Point) { if measurement.startLocation == measurement.endLocation { measurement.startLocation = point } else { measurement.endLocation = point } measurement.isVisible = true } -
Define a private method named
clear. This method is used to hide and clear the distance measurement analysis. Set the measurement's visibility toMeasurement() falseand reset the start and end locations to allow new measurements.ContentView.swiftUse dark colors for code blocks 35 36 37 38 39 40 41 42 43Add line. Add line. Add line. Add line. Add line. Add line. func moveDistanceMeasurement(point: Point) { if measurement.startLocation == measurement.endLocation { measurement.startLocation = point } else { measurement.endLocation = point } measurement.isVisible = true } func clearMeasurement() { measurement.isVisible = false let point = Point(x: 0, y: 0, z: 0, m: 0, spatialReference: .wgs84) measurement.startLocation = point measurement.endLocation = point }
Display the distance measurement analysis with touch events
Touch events determine where to perform and display the distance measurement analysis. A user can tap to add start and end points or long-press and drag to move the distance measurement analysis' location around the screen.
-
The first step to displaying the analyses is to add the analysis to the scene view. Modify the scene view to add the analysis overlay.
ContentView.swiftUse dark colors for code blocks 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 73 74 75 76 77Change line struct ContentView: View { // An ObservableObject containing the scene, 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 { VStack { SceneView(scene: scene, analysisOverlays: [model.analysisOverlay]) } } } -
When a user performs a single touch or a long-press touch event, call
move.Distance Measurement(point :) ContentView.swiftUse dark colors for code blocks 69 70 71 72 73 82 83 84Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. var body: some View { VStack { SceneView(scene: scene, analysisOverlays: [model.analysisOverlay]) .onSingleTapGesture { _, scenePoint in guard let scenePoint else { return } model.moveDistanceMeasurement(point: scenePoint) } .onLongPressGesture { _, scenePoint in guard let scenePoint else { return } model.moveDistanceMeasurement(point: scenePoint) } } }
Add a UI to control the distance measurement analysis
To control the distance measurement analysis, some UI is required.
-
Add a toolbar and create a "Clear" button. The button hides and clears the distance measurement analysis from the scene. When the button is selected, call the
Clearmethod.Measurement ContentView.swiftUse dark colors for code blocks 69 70 71 72 73 74 75 76 77 78 79 80 81 82 91 92 93Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. var body: some View { VStack { SceneView(scene: scene, analysisOverlays: [model.analysisOverlay]) .onSingleTapGesture { _, scenePoint in guard let scenePoint else { return } model.moveDistanceMeasurement(point: scenePoint) } .onLongPressGesture { _, scenePoint in guard let scenePoint else { return } model.moveDistanceMeasurement(point: scenePoint) } .toolbar { ToolbarItemGroup(placement: .bottomBar) { Button("Clear") { // Resets the distance measurement. model.clearMeasurement() } } } } }
Format measurements for readability
Display the distance measurement results in a reader-friendly format.
-
In the
Content, add threeView @variables to contain the text measurements.State ContentView.swiftUse dark colors for code blocks 58 59 60 61 62 63 64 65 66 67 68 72 73 74 75 76Add line. Add line. Add 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) }() @State private var directDistanceText = "--" @State private var horizontalDistanceText = "--" @State private var verticalDistanceText = "--" var body: some View { VStack { SceneView(scene: scene, analysisOverlays: [model.analysisOverlay]) -
Create a private extension outside of the
Contentstruct namedView Format. Create a variable namedStyle distanceand set the format style to abbreviated, used as provided, and 2 decimal places.ContentView.swiftUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. private extension FormatStyle where Self == Measurement<UnitLength>.FormatStyle { /// The format style for the distances. static var distance: Self { .measurement(width: .abbreviated, usage: .asProvided, numberFormatStyle: .number.precision(.fractionLength(2))) } } -
Add a task function to the
Scenethat produces formatted measurements as the values change.View ContentView.swiftUse dark colors for code blocks 76 77 78 79 80 81 82 83 84 85 86Add line. Add line. Add line. Add line. Add line. Add line. Add line. SceneView(scene: scene, analysisOverlays: [model.analysisOverlay]) .onSingleTapGesture { _, scenePoint in guard let scenePoint else { return } model.moveDistanceMeasurement(point: scenePoint) } .onLongPressGesture { _, scenePoint in guard let scenePoint else { return } model.moveDistanceMeasurement(point: scenePoint) } .task { for await measurements in model.measurement.measurements { directDistanceText = measurements.directDistance.formatted(.distance) horizontalDistanceText = measurements.horizontalDistance.formatted(.distance) verticalDistanceText = measurements.verticalDistance.formatted(.distance) } } -
Add text above the toolbar to display the measurements.
ContentView.swiftUse dark colors for code blocks 99 100 101 102 103 104 105 106 107Add line. Add line. Add line. Add line. Text("Direct: \(directDistanceText)") Text("Horizontal: \(horizontalDistanceText)") Text("Vertical: \(verticalDistanceText)") Spacer() .toolbar { ToolbarItemGroup(placement: .bottomBar) { Button("Clear") { // Resets the distance measurement. model.clearMeasurement() } } } -
In the Project Navigator, click MainApp.swift. Change the
ignoresmethod to specify the top edge. This will make the text visible.Safe Area( _:edges :) MainApp.swiftUse dark colors for code blocks 56 57 58 59 61 62 63Change line var body: some SwiftUI.Scene { WindowGroup { ContentView() .ignoresSafeArea(edges: .top) } }
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. Tap to set start and end locations. Long-press and drag to display and move a distance measurement analysis to evaluate the horizontal, vertical, and direct distances between two park locations.
Alternatively, you can download the tutorial solution, as follows.
Option 2: Download the solution
-
Click the
Download solutionlink under Solution and unzip the file to a location on your machine. -
Open the
.xcodeprojfile in Xcode.
Since the downloaded solution does not contain authentication credentials, you must first set up authentication to create credentials, and then add the developer credentials to the solution.
Set up authentication
To access the secure ArcGIS location services
You can implement API key authentication or user authentication in this tutorial. Compare the differences below:
API key authentication
- Users are not required to sign in.
- Requires creating an API key credential
API key credentials are an item that contains the parameters used to create and manage long-lived access tokens for API key authentication. They are a type of developer credential. with the correct privileges. - API keys
An API key is a long-lived access token created using API key credentials. They are valid for up to one year and are typically embedded directly into client applications. are long-lived access tokens. - Service usage is billed to the API key owner/developer.
- Simplest authentication method to implement.
- Recommended approach for new ArcGIS developers.
Learn more in API key authentication.
User authentication
- Users are required to sign in with an ArcGIS account
An ArcGIS account is an identity with a user type and set of privileges that can access specific ArcGIS products, tools, APIs, services, and resources. The main account types that can be used for development are an ArcGIS Location Platform account, ArcGIS Online account, and ArcGIS Enterprise account. ArcGIS Location Platform and ArcGIS Online accounts are also associated with a subscription. . - User accounts must have privilege
Privileges are a set of permissions assigned to ArcGIS accounts, developer credentials, and applications that grant access to secure resources and functionality in ArcGIS. to access the ArcGIS servicesA service, also known as an ArcGIS service, is software that supports an ArcGIS REST API and provides geospatial functionality or data. A service can be hosted by Esri or in ArcGIS Enterprise. used in application. - Requires creating OAuth credentials
OAuth credentials are an item that contains parameters required to implement user authentication or app authentication, including a .client_id,client_secret, and redirect URIs. They are a type of developer credential. - Application uses a redirect URL and client ID.
- Service usage is billed to the organization of the user signed into the application.
Learn more in User authentication.
To complete this tutorial, click on the tab in the switcher below for your authentication type of choice, either API key authentication or User authentication.
Create a new API key access token
-
Complete the Create an API key tutorial and create an API key with the following privilege(s)
Privileges are a set of permissions assigned to ArcGIS accounts, developer credentials, and applications that grant access to secure resources and functionality in ArcGIS. :- Privileges
- Location services > Basemaps
- Privileges
-
Copy and paste the API key access token into a safe location. It will be used in a later step.
Set developer credentials in the solution
To allow your app users to access ArcGIS location services
Pass your API Key access token to the ArcGISEnvironment.
-
In the Project Navigator, click MainApp.swift.
-
Set the
AuthenticationtoMode .api.Key MainApp.swiftUse dark colors for code blocks // Change the `AuthenticationMode` to `.apiKey` if your application uses API key authentication. private var authenticationMode: AuthenticationMode { .apiKey } -
Set the
apiproperty with your API key access token.Key MainApp.swiftUse dark colors for code blocks // Please enter an API key access token if your application uses API key authentication. private let apiKey = APIKey("<#YOUR-ACCESS-TOKEN#>")
Best Practice: The access token is stored directly in the code as a convenience for this tutorial. Do not store credentials directly in source code in a production environment.
Run the solution
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. Tap to set start and end locations. Long-press and drag to display and move a distance measurement analysis to evaluate the horizontal, vertical, and direct distances between two park locations.
What's next?
Learn how to use additional API features, ArcGIS location services, and ArcGIS tools in these tutorials: