This API includes ExploratoryViewshed and ExploratoryLineOfSight classes to provide fast and dynamic (but strictly visual) analysis of data in a scene (including the terrain surface, scene layers, and 3D objects). The exploratory analysis API only considers data that is currently visible in the scene. You apply the analyses to the scene using the AnalysisOverlay class, and the results are updated dynamically as layers are added or removed, features are updated, camera position changes, and so on.
Exploratory analyses results are rendered quickly by the GPU but cannot be persisted. This is ideal for use cases that require responsive, interactive, and strictly visual evaluation of results that change frequently. However, since no features or output geometry are produced, use cases such as persisting result shapes or performing hit tests with other features are not supported.
Analysis results are influenced by the level of detail of the current display (distance of the camera to the surface), and the analysis results are therefore likely to change as you interact with the scene view.
Exploratory viewshed
Viewsheds show the visible and obstructed areas within an observer's field of view. The 3D shape inside which visibility is evaluated is called the frustum. The frustum is defined by the observer's location, horizontal and vertical angles of vision, minimum and maximum distance, heading, and pitch. The frustum represents the full volume being evaluated within the observer's field of vision and can be displayed as part of the viewshed analysis result.
The symbols you provide to display visible and obstructed areas in the viewshed result are applied to all viewshed analyses in your scene view. While you can add several viewsheds to your scene, result symbology cannot be set individually. If adding several viewshed analyses to your scene view, transparency in your visibility colors helps visualize overlapping areas by making them appear darker.
Exploratory line of sight
Line of sight analysis shows visibility along a line connecting a pair of observer and target locations. The result indicates if the target is visible from the observer and displays visible and obstructed segments to show where visibility is blocked.
In addition to visible and obstructed line segments, portions of the line may have an unknown visibility state. These lines (displayed in gray by default) indicate that visibility cannot be reliably evaluated with the currently available data. For example, visibility may become unknown if the camera position is changed so that either the target or the observer for the line of sight is no longer displayed. In that situation, data outside the visible display may have been unloaded from the scene. The unloaded data may have contained obstructions to the line of sight that are no longer present.
A line of sight analysis represents a single line from observer to target. To make sight lines from multiple vantage points, you must create multiple analysis instances. A group of related line of site analyses (for the same observer, for example) can be managed in a single analysis overlay.
Examples
Exploratory viewshed from a moving GeoElement
You may want to see a viewshed for an observer whose location, heading, or pitch update frequently. For example, you may want to display a viewshed for the pilot of a search plane as it flies over the terrain. As an element representing the aircraft changes its position in the scene view, you'd like the viewshed result to update accordingly. This can be accomplished using ExploratoryGeoElementViewshed scene analysis, which takes a GeoElement (of point geometry type) to define the observer's position. Since the viewshed is based on the geoelement, any change in its position (location, heading, pitch, and so on) will update the viewshed result. You can also specify offset values for the observer relative to the element. This is useful for more accurately representing an observer position inside a moving craft, for example.
To add a ExploratoryGeoElementViewshed analysis to your scene view:
-
Create a point geoelement to represent the observer in the viewshed. Add the element to the scene view.
-
Create a new
ExploratoryGeoElementViewshed. In the constructor, define the observer by passing in the geoelement, horizontal and vertical field of view, minimum and maximum distance, and heading and pitch offsets.Use dark colors for code blocks Copy // Define horizontal/vertical field of vision and minimum/maximum distance for visibility (meters). val horizontalViewAngle = 40.0 val verticalViewAngle = 60.0 val minViewDistanceMeters = 0.0 val maxViewDistanceMeters = 1000.0 // Define pitch and heading offsets (if any). val headingOffset = 0.0 val pitchOffset = 0.0 // Create the viewshed analysis using a geoelement (a graphic) to define the observer. val viewFromPlane = ExploratoryGeoElementViewshed( geoElement = planeGraphic, horizontalAngle = horizontalViewAngle, verticalAngle = verticalViewAngle, minDistance = minViewDistanceMeters, maxDistance = maxViewDistanceMeters, headingOffset = headingOffset, pitchOffset = pitchOffset ) -
Optional: Define offset values to define the X, Y, and Z location of the observer relative to the element. These offsets are defined in meters using a coordinate system relative to the center of the object, where X is to the right or left, Y is forward or back, and Z is up and down. To place an observer in the driver's seat of a car, for example, you might place her 60 centimeters from the left of the car center, 70 centimeters forward from center, and 40 centimeters above the center. These offset values would be (-0.6, 0.7, 0.4).
Use dark colors for code blocks Copy // Apply x/y/z offsets (meters) to accurately place the observer. viewFromPlane.offsetX = 9.0 viewFromPlane.offsetY = 9.0 viewFromPlane.offsetZ = 1.0 -
Optional: Provide custom colors for analysis results: visible areas, obstructed areas, and frustum. To show the frustum in the results, set the frustum outline visibility to true.
Use dark colors for code blocks Copy // Define new colors for the frustum outline and for visible/obstructed areas in the viewshed result. val visibleColor = Color.fromRgba(222, 0, 255, 255) val obstructedColor = Color.fromRgba(255, 99, 71, 150) val frustumOutlineColor = Color.fromRgba(70, 130, 180, 255) // These are companion properties on the ExploratoryViewshed base class that apply to all viewshed analyses in the scene view. ExploratoryViewshed.visibleColor = visibleColor ExploratoryViewshed.obstructedColor = obstructedColor ExploratoryViewshed.frustumOutlineColor = frustumOutlineColor // Show the frustum outline for this analysis. viewFromPlane.frustumOutlineVisible = true -
Add the analysis to an analysis overlay to display the results.
Use dark colors for code blocks Copy // Add viewshed to an analysis overlay. analysisOverlay.analyses.add(viewFromPlane) analysisOverlays.add(analysisOverlay)
As the position of the geoelement changes, the viewshed results will update accordingly.
Exploratory line of sight from a moving GeoElement
To evaluate line of sight from a moving GeoElement, use a ExploratoryGeoElementLineOfSight analysis. This analyzes visibility between point geoelements that represent the observer and target. As the position of these elements is updated (from a GPS feed, for example), the line of sight result will also be updated. As with the ExploratoryLocationLineOfSight analysis, you can handle target visibility changes to receive a notification each time the target becomes visible or obstructed. In the following image, for example, the target geoelement is selected when it becomes visible and unselected when it is obstructed.

To add a ExploratoryGeoElementLineOfSight analysis to your scene view:
-
Create a new
ExploratoryGeoElementLineOfSight. In the constructor, define the observer and target by passing in geoelements (with point geometry) that define their location.Use dark colors for code blocks Copy // Create a line of sight and define the observer and target with point geoelements. // In this example, the observer is looking out a window of the Empire State Building // and the target is a taxi circling the block. val empireStateBuildingTaxiLOS = ExploratoryGeoElementLineOfSight( observerGeoElement = observer, targetGeoElement = taxi ) -
Optional: Define offset values to apply to the observer and/or target locations (x, y, z). These offsets are defined in meters using a coordinate system relative to the center of the object, where X is to the right or left, Y is forward or back, and Z is up and down. To place an observer in the driver's seat of a car, for example, you might place her 60 centimeters from the left of the car center, 70 centimeters forward from center, and 40 centimeters above the center. These offset values would be (-0.6, 0.7, 0.4).
Use dark colors for code blocks Copy // Apply some offsets (values are meters). empireStateBuildingTaxiLOS.observerOffsetX = 1.0 empireStateBuildingTaxiLOS.observerOffsetY = 2.0 empireStateBuildingTaxiLOS.targetOffsetX = 1.0 empireStateBuildingTaxiLOS.targetOffsetZ = 2.5 -
Optional: Assign custom colors for visible and obstructed line segments in the analysis results. These are green and red by default.
Use dark colors for code blocks Copy // Define colors. val visibleColor = Color.fromRgba(0, 255, 127, 150) val obstructedColor = Color.fromRgba(255, 99, 71, 150) // These are companion properties of ExploratoryLineOfSight base class that apply to all lines of sight in the scene view. ExploratoryLineOfSight.visibleColor = visibleColor ExploratoryLineOfSight.obstructedColor = obstructedColor ExploratoryLineOfSight.lineWidth = 3f -
Add the analysis to an analysis overlay to display the results.
Use dark colors for code blocks Copy analysisOverlay.analyses.add(empireStateBuildingTaxiLOS) analysisOverlays.add(analysisOverlay) -
Optional: Handle an event to know when target visibility changes.
Use dark colors for code blocks Copy lifecycleScope.launch { empireStateBuildingTaxiLOS.targetVisibility.collect { lineOfSightTargetVisibility -> val visibility = when (lineOfSightTargetVisibility) { ExploratoryLineOfSightTargetVisibility.Obstructed -> "obstructed" ExploratoryLineOfSightTargetVisibility.Visible -> "visible" ExploratoryLineOfSightTargetVisibility.Unknown -> "unknown" } logInfo("lineOfSightTargetVisibility is now: $visibility") } }