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 // sample headers #include "SpatialOperations.h" // ArcGIS Maps SDK headers #include "Basemap.h" #include "GeometryEngine.h" #include "Graphic.h" #include "GraphicListModel.h" #include "GraphicsOverlay.h" #include "GraphicsOverlayListModel.h" #include "Map.h" #include "MapQuickView.h" #include "MapTypes.h" #include "Part.h" #include "PartCollection.h" #include "Point.h" #include "PolygonBuilder.h" #include "SimpleFillSymbol.h" #include "SpatialReference.h" #include "SymbolTypes.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); 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); }