Line of sight (location)

View on GitHub
Sample viewer app

Perform a line of sight analysis between two points in real time.

Line of sight (location)

Use case

A line of sight analysis can be used to assess whether a view is obstructed between an observer and a target. Obstructing features could either be natural, like topography, or man-made, like buildings. Consider an events planning company wanting to commemorate a national event by lighting sequential beacons across hill summits or roof tops. To guarantee a successful event, ensuring an unobstructed line of sight between neighboring beacons would allow each beacon to be activated as intended.

How to use the sample

Tap on the map to set the observer location. Tap and hold to drag the line of sight target. A red segment on the line means the view between observer and target is obstructed, whereas green means the view is unobstructed.

How it works

  1. Create an AGSAnalysisOverlay and add it to the scene view.
  2. Track the screen taps using the AGSGeoViewTouchDelegate.
  3. Create an AGSLocationLineOfSight with the map points.
  4. Update the target location when needed.

Relevant API

  • AGSAnalysisOverlay
  • AGSLocationLineOfSight
  • AGSSceneView

Tags

3D, line of sight, visibility, visibility analysis

Sample Code

LineOfSightLocationViewController.swift
                                                                                             
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Copyright 2018 Esri.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import UIKit
import ArcGIS

class LineOfSightLocationViewController: UIViewController, AGSGeoViewTouchDelegate {
    @IBOutlet weak var sceneView: AGSSceneView!
    @IBOutlet weak var observerInstructionLabel: UILabel!
    @IBOutlet weak var targetInstructionLabel: UILabel!

    private var lineOfSight: AGSLocationLineOfSight? {
        willSet {
            sceneView.analysisOverlays.removeAllObjects()
        }
        didSet {
            guard let lineOfSight = lineOfSight else {
                targetInstructionLabel.isHidden = true
                return
            }

            targetInstructionLabel.isHidden = false

            // create an analysis overlay using a single Line of Sight and add it to the scene view
            let analysisOverlay = AGSAnalysisOverlay()
            analysisOverlay.analyses.add(lineOfSight)
            sceneView.analysisOverlays.add(analysisOverlay)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // add the source code button item to the right of navigation bar
        (navigationItem.rightBarButtonItem as! SourceCodeBarButtonItem).filenames = ["LineOfSightLocationViewController"]

        // initialize the scene with an imagery basemap
        let scene = AGSScene(basemap: .imagery())

        // assign the scene to the scene view
        sceneView.scene = scene

        /// The url of the Terrain 3D ArcGIS REST Service.
        let worldElevationServiceURL = URL(string: "https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer")!
        // initialize the elevation source with the service URL and add it to the base surface of the scene
        let elevationSrc = AGSArcGISTiledElevationSource(url: worldElevationServiceURL)
        scene.baseSurface?.elevationSources.append(elevationSrc)

        // set the viewpoint specified by the camera position
        let camera = AGSCamera(location: AGSPoint(x: -73.0815, y: -49.3272, z: 4059, spatialReference: .wgs84()), heading: 11, pitch: 62, roll: 0)
        sceneView.setViewpointCamera(camera)

        // set touch delegate on scene view as self
        sceneView.touchDelegate = self

        // set the line width (default 1.0). This setting is applied to all line of sight analysis in the view
        AGSLineOfSight.setLineWidth(2.0)
    }

    // MARK: - AGSGeoViewTouchDelegate

    func geoView(_ geoView: AGSGeoView, didTapAtScreenPoint screenPoint: CGPoint, mapPoint: AGSPoint) {
        // user tapped to place Line of Sight observer. Create Line of Sight analysis if need be
        if lineOfSight == nil {
            // set initial Line of Sight analysis with tapped point
            lineOfSight = AGSLocationLineOfSight(observerLocation: mapPoint, targetLocation: mapPoint)
        } else {
            // update the observer location
            lineOfSight?.observerLocation = mapPoint
        }
    }

    func geoView(_ geoView: AGSGeoView, didLongPressAtScreenPoint screenPoint: CGPoint, mapPoint: AGSPoint) {
        // update the target location
        lineOfSight?.targetLocation = mapPoint
    }

    func geoView(_ geoView: AGSGeoView, didMoveLongPressToScreenPoint screenPoint: CGPoint, mapPoint: AGSPoint) {
        // update the target location
        lineOfSight?.targetLocation = mapPoint
    }
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.