# Spatial operations

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, farmer's 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

1. Create a `GraphicsOverlay` and add it to the `MapView`.
2. Use `PolygonBuilder` to create two polygons.
3. Add the overlapping polygons to the graphics overlay.
4. Perform spatial relationships between the polygons by using the appropriate operation:
• `GeometryEngine::union(geometry1, geometry2)` - This method returns the two geometries united together as one geometry.
• `GeometryEngine::difference(geometry1, geometry2)` - This method returns any part of Geometry2 that does not intersect Geometry1.
• `GeometryEngine::symmetricDifference(geometry1, geometry2)` - This method returns any part of Geometry1 or Geometry2 which do not intersect.
• `GeometryEngine::intersection(geometry1, geometry2)` - This method returns the intersection of Geometry1 and Geometry2.
5. Use the geometry that is returned from the method call to create a new `Graphic` and add it to the graphics overlay for it to be displayed.

## Relevant API

• Geometry
• GeometryEngine
• GeometryEngine::difference
• GeometryEngine::intersection
• GeometryEngine::symmetricDifference
• GeometryEngine::union
• Graphic
• GraphicsOverlay

## Tags

analysis, combine, difference, geometry, intersection, merge, polygon, union

## Sample Code

SpatialOperations.cppSpatialOperations.cppSpatialOperations.hSpatialOperations.qml
Use dark colors for code blocksCopy
``````// [WriteFile Name=SpatialOperations, Category=Geometry]
// [Legal]

// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

// Unless required by applicable law or agreed to in writing, software
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// [Legal]

#ifdef PCH_BUILD
#include "pch.hpp"
#endif // PCH_BUILD

#include "SpatialOperations.h"

#include "Map.h"
#include "MapQuickView.h"
#include "Basemap.h"
#include "Point.h"
#include "Part.h"
#include "PolygonBuilder.h"
#include "SimpleFillSymbol.h"
#include "GeometryEngine.h"
#include "MapTypes.h"
#include "GraphicsOverlayListModel.h"
#include "GraphicListModel.h"
#include "Graphic.h"
#include "SymbolTypes.h"
#include "PartCollection.h"
#include "GraphicsOverlay.h"
#include "SpatialReference.h"
#include "Viewpoint.h"

using namespace Esri::ArcGISRuntime;

SpatialOperations::SpatialOperations(QQuickItem* parent /* = nullptr */):
QQuickItem(parent),
m_polygon1(Geometry()),
m_polygon2(Geometry()),
m_inputsOverlay (new GraphicsOverlay(this)),
m_outputsOverlay (new GraphicsOverlay(this)),
m_geometryOperations { QStringLiteral("None"),       QStringLiteral("Union")
, QStringLiteral("Difference"), QStringLiteral("Symmetric difference")
, QStringLiteral("Intersection") }
{
}

void SpatialOperations::init()
{
// Register the map view for QML
qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView");
qmlRegisterType<SpatialOperations>("Esri.Samples", 1, 0, "SpatialOperationsSample");
}

void SpatialOperations::componentComplete()
{
QQuickItem::componentComplete();

m_map = new Map(BasemapStyle::ArcGISTopographic, this);
m_mapView->setMap(m_map);

m_mapView->graphicsOverlays()->append(m_inputsOverlay);
m_mapView->graphicsOverlays()->append(m_outputsOverlay);
m_map->setInitialViewpoint(Viewpoint(Point(-13453, 6710127, SpatialReference::webMercator()), 30000));
}
{
// create blue polygon
PolygonBuilder polygonBuilder1(SpatialReference::webMercator());

SimpleFillSymbol* fillSymbol1 = new SimpleFillSymbol(SimpleFillSymbolStyle::Solid, QColor("blue"), this);
m_polygon1 = polygonBuilder1.toGeometry();
m_inputsOverlay->graphics()->append(new Graphic(m_polygon1, fillSymbol1, this));

// create green polygon
// outer ring
Part* outerRing = new Part(SpatialReference::webMercator(), this);

// inner ring
Part* innerRing = new Part(SpatialReference::webMercator(), this);

PolygonBuilder polygonBuilder2(SpatialReference::webMercator());
m_polygon2 = polygonBuilder2.toGeometry();
SimpleFillSymbol* fillSymbol2 = new SimpleFillSymbol(SimpleFillSymbolStyle::Solid, QColor("green"), this);
m_inputsOverlay->graphics()->append(new Graphic(m_polygon2, fillSymbol2, this));
}

MapQuickView* SpatialOperations::mapQuickView() const
{
return m_mapView;
}

void SpatialOperations::setMapQuickView(MapQuickView* mapQuickView)
{
m_mapView = mapQuickView;
emit mapQuickViewChanged();
}

void SpatialOperations::applyGeometryOperation(int index)
{
return;

// Perform geometry calculations
Geometry resultPolygon;
switch (index) {
case 1:
resultPolygon = GeometryEngine::unionOf(m_polygon1, m_polygon2);
break;
case 2:
resultPolygon = GeometryEngine::difference(m_polygon1, m_polygon2);
break;
case 3:
resultPolygon = GeometryEngine::symmetricDifference(m_polygon1, m_polygon2);
break;
case 4:
resultPolygon = GeometryEngine::intersection(m_polygon1, m_polygon2);
break;
case 0:
default:
break;
}

// Clear previous results
m_outputsOverlay->graphics()->clear();
if (resultPolygon.isEmpty())
return;

// Add the resulting polygon as a Graphic
SimpleFillSymbol* fillSymbol = new SimpleFillSymbol(SimpleFillSymbolStyle::Solid, QColor("red"), this);
Graphic* graphic = new Graphic(resultPolygon, fillSymbol, this);
m_outputsOverlay->graphics()->append(graphic);
}``````