# Perform 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

Select a spatial operation from the overflow menu. When an operation is selected, the resulting geometry is shown in red.

## How it works

1. Create two `GraphicsOverlay`s, one to show polygons and another to show the relationships between them.
2. Define a `PointCollection` of each `Geometry`.
3. Add the overlapping polygons to a 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. Add the resultant geometry to a new `Graphic` and display it by adding it to the second `GraphicsOverlay`.

## 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

MainActivity.java
Use dark colors for code blocksCopy

``````/*
*
* 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
*/

package com.esri.arcgisruntime.sample.performspatialoperations;

import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;
import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
import com.esri.arcgisruntime.geometry.Geometry;
import com.esri.arcgisruntime.geometry.GeometryEngine;
import com.esri.arcgisruntime.geometry.Part;
import com.esri.arcgisruntime.geometry.PartCollection;
import com.esri.arcgisruntime.geometry.Point;
import com.esri.arcgisruntime.geometry.PointCollection;
import com.esri.arcgisruntime.geometry.Polygon;
import com.esri.arcgisruntime.geometry.SpatialReferences;
import com.esri.arcgisruntime.mapping.ArcGISMap;
import com.esri.arcgisruntime.mapping.BasemapStyle;
import com.esri.arcgisruntime.mapping.view.Graphic;
import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
import com.esri.arcgisruntime.mapping.view.MapView;
import com.esri.arcgisruntime.symbology.SimpleFillSymbol;
import com.esri.arcgisruntime.symbology.SimpleLineSymbol;

public class MainActivity extends AppCompatActivity {

final private GraphicsOverlay inputGeometryOverlay = new GraphicsOverlay();
final private GraphicsOverlay resultGeometryOverlay = new GraphicsOverlay();
// simple black (0xFF000000) line symbol for outlines
final private SimpleLineSymbol lineSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, 0xFF000000, 1);
final private SimpleFillSymbol resultFillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, 0xFFE91F1F,
lineSymbol);
private Polygon inputPolygon1;
private Polygon inputPolygon2;
// The spatial operation switching menu items.
private MapView mMapView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// authentication with an API key or named user is required to access basemaps and other
// location services
ArcGISRuntimeEnvironment.setApiKey(BuildConfig.API_KEY);

mMapView = findViewById(R.id.mapView);

// create ArcGISMap with topographic basemap
ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_LIGHT_GRAY);
mMapView.setMap(map);

// create graphics overlays to show the inputs and results of the spatial operation

// create input polygons and add graphics to display these polygons in an overlay
createPolygons();

// center the map view on the input geometries
Geometry viewpointGeom = GeometryEngine.union(inputPolygon1, inputPolygon2).getExtent();
mMapView.setViewpointGeometryAsync(viewpointGeom, 20);
}

@Override
// Inflate the menu; this adds items to the action bar if it is present.

// Get the menu items that perform spatial operations.

// set the 'no-op' menu item checked by default

return true;
}

@Override
int itemId = item.getItemId();

// clear previous operation result
resultGeometryOverlay.getGraphics().clear();

// perform spatial operations and add results as graphics, depending on the option selected
// if-else is used because this sample is used elsewhere as a Library module
if (itemId == R.id.action_no_operation) {
// no spatial operation - graphics have been cleared previously
return true;
} else if (itemId == R.id.action_intersection) {
showGeometry(GeometryEngine.intersection(inputPolygon1, inputPolygon2));
return true;
} else if (itemId == R.id.action_union) {
showGeometry(GeometryEngine.union(inputPolygon1, inputPolygon2));
return true;
} else if (itemId == R.id.action_difference) {
// note that the difference method gives different results depending on the order of input geometries
showGeometry(GeometryEngine.difference(inputPolygon1, inputPolygon2));
return true;
} else if (itemId == R.id.action_symmetric_difference) {
showGeometry(GeometryEngine.symmetricDifference(inputPolygon1, inputPolygon2));
return true;
} else {
return super.onOptionsItemSelected(item);
}
}

private void showGeometry(Geometry resultGeometry) {
// add a graphic from the result geometry, showing result in red (0xFFE91F1F)
Graphic resultGraphic = new Graphic(resultGeometry, resultFillSymbol);

// select the result to highlight it
resultGraphic.setSelected(true);
}

private void createPolygons() {

// create input polygon 1
PointCollection pointsPoly = new PointCollection(SpatialReferences.getWebMercator());
inputPolygon1 = new Polygon(pointsPoly);

// create and add a blue graphic to show input polygon 1
SimpleFillSymbol fillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, 0x990000CC, lineSymbol);

// create input polygon 2 with a green (0xFF009900) symbol
// outer ring
PointCollection outerRingSegmentCollection = new PointCollection(SpatialReferences.getWebMercator());
Part outerRing = new Part(outerRingSegmentCollection);

// inner ring
PointCollection innerRingSegmentCollection = new PointCollection(SpatialReferences.getWebMercator());
Part innerRing = new Part(innerRingSegmentCollection);

// add both parts (rings) to a part collection and create a geometry from it
PartCollection polygonParts = new PartCollection(outerRing);
inputPolygon2 = new Polygon(polygonParts);

// create and add a green graphic to show input polygon 2
fillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, 0x99009900, lineSymbol);
}

@Override
protected void onPause() {
mMapView.pause();
super.onPause();
}

@Override
protected void onResume() {
super.onResume();
mMapView.resume();
}

@Override
protected void onDestroy() {
super.onDestroy();
mMapView.dispose();
}
}``````