Find the union, intersection, or difference of two geometries.

Use case
The different spatial operations (union, difference, symmetric difference, and intersection) can be used for a variety of spatial analyses. For example, government authorities may use the intersect operation to determine whether a proposed road cuts through a restricted piece of land such as a nature reserve or a private property.
When these operations are chained together, they become even more powerful. An analysis of food deserts within an urban area might begin by union-ing service areas of grocery stores, farmers markets, and food co-ops. Taking the difference between this single geometry of all services areas and that of a polygon delineating a neighborhood would reveal the areas within that neighborhood where access to healthy, whole foods may not exist.
How to use the sample
The sample provides an option to select a spatial operation. When an operation is selected, the resulting geometry is shown in red.
How it works
- Create a
GraphicsOverlayobject. - Create
Graphicinstances for the overlapping polygons and result. - Add the overlapping polygons and result graphics to the graphics overlay.
- Perform spatial relationships between the polygons by using the appropriate operation:
static GeometryEngine.union(_:_:)- This method returns the two geometries united together as one geometry.static GeometryEngine.difference(_:_:)- This method returns the difference between two geometries.static GeometryEngine.symmetricDifference(_:_:)- This method returns any part of two geometries that do not intersect.static GeometryEngine.intersection(_:_:)- This method returns the intersection of two geometries.
- Use the geometry that is returned from the method call to update the geometry of the results graphic.
Relevant API
- Geometry
- GeometryEngine
- Graphic
- GraphicsOverlay
- static GeometryEngine.difference(::)
- static GeometryEngine.intersection(::)
- static GeometryEngine.symmetricDifference(::)
- static GeometryEngine.union(::)
Tags
analysis, combine, difference, geometry, intersection, merge, polygon, union
Sample code
// 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//// https://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 ArcGISimport SwiftUI
struct ShowResultOfSpatialOperationsView: View { /// The current spatial operation performed. @State private var spatialOperation = SpatialOperation.none
/// The view model for the sample. @StateObject private var model = Model()
var body: some View { MapView(map: model.map, graphicsOverlays: [model.graphicsOverlay]) .onChange(of: spatialOperation) { model.performOperation(spatialOperation) } .toolbar { ToolbarItem(placement: .bottomBar) { Picker("Spatial Operation", selection: $spatialOperation) { ForEach(SpatialOperation.allCases, id: \.self) { operation in Text(operation.label) } } } } }}
private extension ShowResultOfSpatialOperationsView { /// An enum of spatial operations. enum SpatialOperation: CaseIterable { case intersection, symmetricDifference, difference, union, none
/// A human-readable label for each spatial operation. var label: String { switch self { case .none: return "None" case .union: return "Union" case .difference: return "Difference" case .symmetricDifference: return "Symmetric Difference" case .intersection: return "Intersection" } } }
/// The model used to store the geo model and other expensive objects /// used in this view. class Model: ObservableObject { /// A map with a topographic basemap style and initial viewpoint. let map: Map = { let map = Map(basemapStyle: .arcGISTopographic) map.initialViewpoint = Viewpoint( center: Point(x: -13453, y: 6710127, spatialReference: .webMercator), scale: 30_000 ) return map }()
/// A graphics overlay for the map view. let graphicsOverlay: GraphicsOverlay = { // Creates the graphics for the two polygons and result. let polygonOneGraphic = Graphic( geometry: .polygon1, symbol: SimpleFillSymbol(color: .blue, outline: .simple) )
let polygonTwoGraphic = Graphic( geometry: .polygon2, symbol: SimpleFillSymbol(color: .green, outline: .simple) )
let resultGraphic = Graphic( symbol: SimpleFillSymbol(color: .red, outline: .simple) )
// Adds the graphics to the overlay. return GraphicsOverlay(graphics: [polygonOneGraphic, polygonTwoGraphic, resultGraphic]) }()
/// A graphic representing the result of the spatial operation. var resultGraphic: Graphic { graphicsOverlay.graphics.last! }
/// Updates the result graphic based on the spatial operation. func performOperation(_ spatialOperation: SpatialOperation) { let resultGeometry: Geometry? // Updates the geometry based on the selected spatial operation. switch spatialOperation { case .none: resultGeometry = nil case .union: resultGeometry = GeometryEngine.union(.polygon1, .polygon2) case .difference: resultGeometry = GeometryEngine.difference(.polygon1, .polygon2) case .symmetricDifference: resultGeometry = GeometryEngine.symmetricDifference(.polygon1, .polygon2) case .intersection: resultGeometry = GeometryEngine.intersection(.polygon1, .polygon2) } // Updates the result graphic geometry. resultGraphic.geometry = resultGeometry } }}
private extension LineSymbol { /// A solid, thin, black line. static var simple: LineSymbol { SimpleLineSymbol(style: .solid, color: .black, width: 1) }}
private extension Geometry { /// The geometry for polygon one. static var polygon1: Geometry { Polygon( points: [ Point(x: -13960, y: 6709400), Point(x: -14660, y: 6710000), Point(x: -13760, y: 6710730), Point(x: -13300, y: 6710500), Point(x: -13160, y: 6710100) ], spatialReference: .webMercator ) }
/// The geometry for polygon two. static var polygon2: Geometry { Polygon( parts: [ // The outer ring. MutablePart( points: [ Point(x: -13060, y: 6711030), Point(x: -12160, y: 6710730), Point(x: -13160, y: 6709700), Point(x: -14560, y: 6710730), Point(x: -13060, y: 6711030) ], spatialReference: .webMercator ), // The inner ring. MutablePart( points: [ Point(x: -13060, y: 6710910), Point(x: -14160, y: 6710630), Point(x: -13160, y: 6709900), Point(x: -12450, y: 6710660), Point(x: -13060, y: 6710910) ], spatialReference: .webMercator ) ] ) }}
#Preview { NavigationStack { ShowResultOfSpatialOperationsView() }}