Show result of spatial relationships

View on GitHubSample viewer app

Determine spatial relationships between two geometries.

Image of show result of spatial relationships

Use case

In case of a natural disaster, emergency services can represent the affected areas using polygons. By determining the spatial relationships between these and any other existing features such as populated areas, infrastructure, or natural resources, it is possible to quickly determine which of the existing features might be affected or is in further danger, helping to assess risk and define further action.

How to use the sample

Select one of the three graphics. The relationships dialog will show the spatial relationships the selected graphic has to the other graphic geometries.

How it works

  1. Get the geometry from two different graphics. In this example the geometry of the selected graphic is compared to the geometry of each unselected graphic.
  2. Use the methods in GeometryEngine to check the relationship between the geometries, e.g. SpatialRelationship.Contains, SpatialRelationship.Disjoint, SpatialRelationship.Intersects, etc. If the method returns true, the relationship exists.

Relevant API

  • Geometry
  • GeometryEngine
  • GeometryType
  • Graphic
  • Point
  • Polygon
  • Polyline

Tags

geometries, relationship, spatial analysis

Sample Code

MainActivity.ktMainActivity.ktRelationshipsDialog.kt
Use dark colors for code blocksCopy
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/* Copyright 2022 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.
 *
 */

package com.esri.arcgismaps.sample.showresultofspatialrelationships

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.lifecycleScope
import com.arcgismaps.ApiKey
import com.arcgismaps.ArcGISEnvironment
import com.arcgismaps.Color
import com.arcgismaps.data.SpatialRelationship
import com.arcgismaps.geometry.Geometry
import com.arcgismaps.geometry.GeometryEngine
import com.arcgismaps.geometry.Point
import com.arcgismaps.geometry.Polygon
import com.arcgismaps.geometry.PolygonBuilder
import com.arcgismaps.geometry.Polyline
import com.arcgismaps.geometry.PolylineBuilder
import com.arcgismaps.geometry.SpatialReference
import com.arcgismaps.mapping.ArcGISMap
import com.arcgismaps.mapping.BasemapStyle
import com.arcgismaps.mapping.Viewpoint
import com.arcgismaps.mapping.symbology.SimpleFillSymbol
import com.arcgismaps.mapping.symbology.SimpleFillSymbolStyle
import com.arcgismaps.mapping.symbology.SimpleLineSymbol
import com.arcgismaps.mapping.symbology.SimpleLineSymbolStyle
import com.arcgismaps.mapping.symbology.SimpleMarkerSymbol
import com.arcgismaps.mapping.symbology.SimpleMarkerSymbolStyle
import com.arcgismaps.mapping.view.Graphic
import com.arcgismaps.mapping.view.GraphicsOverlay
import com.arcgismaps.mapping.view.ScreenCoordinate
import com.esri.arcgismaps.sample.showresultofspatialrelationships.databinding.ActivityMainBinding
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.launch


class MainActivity : AppCompatActivity() {

    // set up data binding for the activity
    private val activityMainBinding: ActivityMainBinding by lazy {
        DataBindingUtil.setContentView(this, R.layout.activity_main)
    }

    // create a MapView using binding
    private val mapView by lazy {
        activityMainBinding.mapView
    }

    // create a graphics overlay
    private val graphicsOverlay by lazy {
        GraphicsOverlay()
    }

    // text view to display the selected graphic
    private val selectedGraphicTV by lazy {
        activityMainBinding.selectedGraphicTV
    }

    // create the polygon graphic
    private val polygonGraphic by lazy {
        // add polygon points to the polygon builder
        val polygonBuilder = PolygonBuilder(SpatialReference.webMercator()) {
            addPoint(Point(-5991501.677830, 5599295.131468))
            addPoint(Point(-6928550.398185, 2087936.739807))
            addPoint(Point(-3149463.800709, 1840803.011362))
            addPoint(Point(-1563689.043184, 3714900.452072))
            addPoint(Point(-3180355.516764, 5619889.608838))
        }
        // create a polygon from the polygon builder
        val polygon = polygonBuilder.toGeometry()
        val polygonSymbol = SimpleFillSymbol(
            SimpleFillSymbolStyle.ForwardDiagonal, Color.green,
            SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.green, 2f)
        )
        Graphic(polygon, polygonSymbol)
    }


    // create the polyline graphic
    private val polylineGraphic by lazy {
        // add polyline points to the polyline builder
        val polylineBuilder = PolylineBuilder(SpatialReference.webMercator()) {
            addPoint(Point(-4354240.726880, -609939.795721))
            addPoint(Point(-3427489.245210, 2139422.933233))
            addPoint(Point(-2109442.693501, 4301843.057130))
            addPoint(Point(-1810822.771630, 7205664.366363))
        }
        // create a polyline graphic
        val polyline = polylineBuilder.toGeometry()
        val polylineSymbol = SimpleLineSymbol(SimpleLineSymbolStyle.Dash, Color.red, 4f)
        Graphic(polyline, polylineSymbol)
    }


    // create the point graphic
    private val pointGraphic by lazy {
        // create a point graphic
        val point = Point(-4487263.495911, 3699176.480377, SpatialReference.webMercator())
        val locationMarker = SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle, Color.blue, 10f)
        Graphic(point, locationMarker)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // authentication with an API key or named user is
        // required to access basemaps and other location services
        ArcGISEnvironment.apiKey = ApiKey.create(BuildConfig.API_KEY)
        // add MapView to the lifecycle
        lifecycle.addObserver(mapView)
        mapView.apply {
            // add a map with a topographic basemap style
            map = ArcGISMap(BasemapStyle.ArcGISTopographic)
            // set selection color
            selectionProperties.color = Color.red
            // add graphics overlay
            graphicsOverlays.add(graphicsOverlay)
            //set viewpoint
            setViewpoint(Viewpoint(33.183564, -42.428668, 90000000.0))
        }
        // add the graphics to the graphics overlay
        graphicsOverlay.graphics.addAll(listOf(polygonGraphic, polylineGraphic, pointGraphic))
        // set an on touch listener on the map view
        lifecycleScope.launch {
            mapView.onSingleTapConfirmed.collect { tapEvent ->
                // get the tapped coordinate
                val screenCoordinate = tapEvent.screenCoordinate
                // identify the relationships of tapped graphic
                identifyGraphicRelationships(screenCoordinate)
            }
        }
    }

    /**
     * Identifies the selected graphic tapped at the [screenCoordinate]
     * and finds the relations to other graphics on the map.
     */
    private suspend fun identifyGraphicRelationships(screenCoordinate: ScreenCoordinate) {
        // get the graphic selected at the given ScreenCoordinate
        val identifyGraphicsOverlayResult =
            mapView.identifyGraphicsOverlay(graphicsOverlay, screenCoordinate, 1.0, false)
        // get identified graphics overlay, else show an error
        val identifyGraphicsOverlay = identifyGraphicsOverlayResult.getOrElse {
            return showError(it.message.toString())
        }
        // get the identified selected graphics
        val identifiedGraphics = identifyGraphicsOverlay.graphics
        // if no graphic was selected
        if (identifiedGraphics.isEmpty()) {
            // display text and clear selected
            selectedGraphicTV.text = getString(R.string.select_graphic)
            graphicsOverlay.clearSelection()
            return
        }
        // create HashMap that will hold relationships in between graphics
        val relationships = mutableMapOf<String, List<SpatialRelationship>>()
        // add the graphics as keys to the hashmap
        relationships["Point"] = emptyList()
        relationships["Polyline"] = emptyList()
        relationships["Polygon"] = emptyList()
        // select the identified graphic
        graphicsOverlay.clearSelection()
        // get the first graphic identified
        val identifiedGraphic = identifiedGraphics[0]
        // set the identified graphic to be selected
        identifiedGraphic.isSelected = true
        // tracks the type of geometry selected
        var selectedGraphicName = ""
        // find the geometry of the selected graphic
        when (val selectedGeometry = identifiedGraphic.geometry) {
            // if selected geometry is a point
            is Point -> {
                // get the point-polyline relationships
                relationships["Polyline"] =
                    getSpatialRelationships(selectedGeometry, polylineGraphic.geometry)
                // get the point-polygon relationships
                relationships["Polygon"] =
                    getSpatialRelationships(selectedGeometry, polygonGraphic.geometry)
                // update the name of the selected geometry
                selectedGraphicName = "Point"
            }
            // if selected geometry is a polyline
            is Polyline -> {
                // get the polyline-polygon relationships
                relationships["Polygon"] =
                    getSpatialRelationships(selectedGeometry, polygonGraphic.geometry)
                // get the polyline-point relationships
                relationships["Point"] =
                    getSpatialRelationships(selectedGeometry, pointGraphic.geometry)
                // update the name of the selected geometry
                selectedGraphicName = "Polyline"
            }
            // if selected geometry is a polygon
            is Polygon -> {
                // get the polygon-polyline relationships
                relationships["Polyline"] =
                    getSpatialRelationships(selectedGeometry, polylineGraphic.geometry)
                // get the polygon-point relationships
                relationships["Point"] =
                    getSpatialRelationships(selectedGeometry, pointGraphic.geometry)
                // update the name of the selected geometry
                selectedGraphicName = "Polygon"
            }
            // no other graphic on map
            else -> {}
        }
        // display selected graphic text
        selectedGraphicTV.text = "$selectedGraphicName geometry is selected"
        // create and display a dialog with the established graphics
        RelationshipsDialog(layoutInflater, this, relationships, selectedGraphicName).createAndDisplayDialog()

    }

    /**
     * Gets a list of spatial relationships that the [a] geometry has to the [b] geometry.
     */
    private fun getSpatialRelationships(
        a: Geometry?,
        b: Geometry?
    ): List<SpatialRelationship> {
        // check if either geometry is null
        if (a == null || b == null) {
            return emptyList()
        }
        val relationships: MutableList<SpatialRelationship> = mutableListOf()
        if (GeometryEngine.crosses(a, b))
            relationships.add(SpatialRelationship.Crosses)
        if (GeometryEngine.contains(a, b))
            relationships.add(SpatialRelationship.Contains)
        if (GeometryEngine.disjoint(a, b))
            relationships.add(SpatialRelationship.Disjoint)
        if (GeometryEngine.intersects(a, b))
            relationships.add(SpatialRelationship.Intersects)
        if (GeometryEngine.overlaps(a, b))
            relationships.add(SpatialRelationship.Overlaps)
        if (GeometryEngine.touches(a, b))
            relationships.add(SpatialRelationship.Touches)
        if (GeometryEngine.within(a, b))
            relationships.add(SpatialRelationship.Within)
        return relationships
    }

    private fun showError(message: String) {
        Log.e(localClassName, message)
        Snackbar.make(mapView, message, Snackbar.LENGTH_SHORT).show()
    }

    private val Color.Companion.blue: Color
        get() {
            return fromRgba(0, 0, 255, 255)
        }
}

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