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
- Create a
GraphicsOverlay
and add it to theMapView
. - Use
PolygonBuilder
to create two polygons. - Add the overlapping polygons to the graphics overlay.
- 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.
- 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
// [WriteFile Name=SpatialOperations, Category=Geometry]
// [Legal]
// 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.
// [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 "SimpleLineSymbol.h"
#include "GeometryEngine.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);
addPolygons();
m_mapView->graphicsOverlays()->append(m_inputsOverlay);
m_mapView->graphicsOverlays()->append(m_outputsOverlay);
m_map->setInitialViewpoint(Viewpoint(Point(-13453, 6710127, SpatialReference::webMercator()), 30000));
}
void SpatialOperations::addPolygons()
{
// create blue polygon
PolygonBuilder polygonBuilder1(SpatialReference::webMercator());
polygonBuilder1.addPoint(-13960, 6709400);
polygonBuilder1.addPoint(-14660, 6710000);
polygonBuilder1.addPoint(-13760, 6710730);
polygonBuilder1.addPoint(-13300, 6710500);
polygonBuilder1.addPoint(-13160, 6710100);
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);
outerRing->addPoint(-13060, 6711030);
outerRing->addPoint(-12160, 6710730);
outerRing->addPoint(-13160, 6709700);
outerRing->addPoint(-14560, 6710730);
outerRing->addPoint(-13060, 6711030);
// inner ring
Part* innerRing = new Part(SpatialReference::webMercator(), this);
innerRing->addPoint(-13060, 6710910);
innerRing->addPoint(-14160, 6710630);
innerRing->addPoint(-13160, 6709900);
innerRing->addPoint(-12450, 6710660);
innerRing->addPoint(-13060, 6710910);
PolygonBuilder polygonBuilder2(SpatialReference::webMercator());
polygonBuilder2.parts()->addPart(outerRing);
polygonBuilder2.parts()->addPart(innerRing);
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)
{
if (!m_map || m_map->loadStatus() != LoadStatus::Loaded)
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);
}