How to use the Geometry task

Operations

Each operation provided by the Geometry task has a method to invoke the operation, an event that is fired when the operation is complete, a property that is updated when the operation is complete, and a particular type of results. For each operation, the method to invoke it follows the form <operation name>Async, the event fired upon completion is called <operation name>Completed, and the property updated is named <operation name>LastResult. For instance, the method to initiate a buffer operation is BufferAsync, the completed event is BufferCompleted, and the results property is BufferLastResult. For each operation, results are wrapped in an event arguments object and passed to the second parameter of the completed event handler. Attaching an event handler to the completed event allows you to manipulate results as soon as a geometric operation is complete. Additionally, the <operation name>LastResult property is updated with the same results. This property allows you to use data binding to automatically update controls with the new results and provides an easy way to store the collection of results for later reference (for example, when selecting a corresponding item from a ComboBox).

The geometric operations are summarized in the table below.

Operation

Description

AreasAndLengthsAsync

Calculates the areas and lengths of each specified polygon.

AutoCompleteAsync

The AutoComplete operation simplifies the process of constructing new polygons that are adjacent to other polygons. It constructs polygons that fill in the gaps between existing polygons and a set of polylines.

BufferAsync

Buffers a set of geometries.

ConvexHullAsync

The convexHull operation returns the convex hull of the input geometry. The input geometry can be a point, multipoint, polyline or polygon. The hull is typically a polygon but can also be a polyline or point in degenerate cases.

CutAsync

Splits input polylines or polygons where they cross a cutting polyline.

DensifyAsync

This operation densifies geometries by plotting points between existing vertices.

DifferenceAsync

Constructs the set-theoretic difference between an array of geometries and another geometry.

DistanceAsync

The distance operation reports the planar (projected space) / geodesic shortest distance between A and B. Distance is reported in the linear units specified by the DistanceUnit property of the DistanceParameters object or in the spatial reference units of the geometries if the DistanceUnit is not specified.

GeneralizeAsync

Applies Douglas-Poiker generalization to the input polylines and polygons.

IntersectAsync

Constructs the set-theoretic intersection between an collection of geometries and another geometry. Only the geometries of the collection that intersect will be returned.

LabelPointsAsync

Generates a set of points suitable for displaying labels for the given set of Graphics.

LengthsAsync

Calculates the lengths of each specified polyline.

OffsetAsync

Constructs offset copies of the input polylines or polygons.

ProjectAsync

Projects a set of Graphics into a new SpatialReference

RelationAsync

Computes the set of pairs of geometries from graphics1 and graphics2 that belong to the specified relation. Both arrays are assumed to be in the same spatial reference. The relations are evaluated in 2D. Z coordinates are not used. Geometry types cannot be mixed within an array. Note that if the spatialRelationship is specified as esriGeometryRelationRelation, the relationParam parameter describes the spatial relationship and must be specified.

ReshapeAsync

Reshapes a polyline or a part of a polygon using a reshaping line.

SimplifyAsync

Alters the given geometries to make their definitions topologically legal with respect to their geometry type.

TrimExtendAsync

This operation trims / extends each polyline specified in the input IList<Polyline>, using the user specified guide polylines. When trimming features, the part to the left of the oriented cutting line is preserved in the output and the other part is discarded. An empty polyline is added to the output IList<Graphic> if the corresponding input polyline is neither cut nor extended.

UnionAsync

This operation constructs the set-theoretic union of the geometries in the input collection. All inputs must be of the same type.

Usage

To use any of the Geometry task's operations, you first need to instantiate a GeometryService task object and specify the underlying geometry service to use for performing geometric operations. Like all tasks, the Geometry task is declared and initialized in the code-behind because tasks alone do not define any user interface, but rather encapsulate pieces of execution logic.

The geometry service can be specified by passing the service's URL to the task's constructor as shown below. To find the URL, you can use the ArcGIS Services Directory. See the Discovering services topic for more information. Alternatively you can use a LocalGeometryService hosted by the runtime local server.

GeometryService geometryService = new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
    "Geometry/GeometryServer");

To programmatically manipulate an operation's results as soon as the operation is complete, wire a handler for the operation's completed event to the task. For instance, if you want to do this for the AreasAndLengths operation, you would declare a method to handle the event as follows:

private void GeometryService_AreasAndLengthsCompleted(object sender, AreasAndLengthsEventArgs args)
{
}

Then, in the block of code where you've initialized the GeometryService object, you would associate the handler with it:

GeometryService geometryService = new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
    "Geometry/GeometryServer");
geometryService.AreasAndLengthsCompleted += GeometryService_AreasAndLengthsCompleted;

The sections that follow show how to use some of the Geometry task's operations, including snippets of .NET code for executing the operation and handling its results. These samples assume that code for retrieving operation input and specifying a place for operation output (e.g. a GraphicsLayer declared in XAML) has already been implemented. All the code is written in C#.

AreasAndLengths

The AreasAndLengths operation calculates the areas and perimeters of a list of polygon graphics. Since GraphicsLayers store their features as lists of graphics, a common usage pattern for this operation is to retrieve a GraphicsLayer and pass its Graphics collection to the operation as shown below. The code assumes that a Map with an x:Name of "MyMap" that contains a GraphicsLayer with an ID of "MyPolygonGraphicsLayer" has already been created.

GeometryService geometryService = new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
    "Geometry/GeometryServer");
geometryService.AreasAndLengthsCompleted += GeometryService_AreasAndLengthsCompleted;
GraphicsLayer graphicsLayer = MyMap.Layers["MyPolygonGraphicsLayer"] as GraphicsLayer;
geometryService.AreasAndLengthsAsync(graphicsLayer.Graphics.ToList());

The areas and lengths returned by the operation are in two list of doubles stored in the Results.Areas and Results.Lengths properties of the result object. The result object is accessible through either the second parameter of an AreasAndLengthsCompleted event handler or the AreasAndLengthsLastResult property of the GeometryService object. The code below shows accessing results in an event handler. The example iterates through the results, building a string with the calculated areas and perimeters. The returned values are at the same indexes in their respective lists as the input graphics from which the values were calculated.

private void GeometryService_AreasAndLengthsCompleted(object sender, AreasAndLengthsEventArgs args)
{
	string results = "";
	for (int i = 0; i < args.Results.Areas.Count; i++)
	{
		results += string.Format("Graphic {0}: Area = {1}, Perimeter = {2}\n", i, args.Results.Areas[i],
			args.Results.Lengths[i]);
	}
}

Buffer

The Buffer operation creates polygon graphics with geometries that are calculated by applying a buffer of a specified distance around a list of input graphics. The operation takes a BufferParameters object as its input, which, in addition to the graphics to be buffered, specifies the buffer distances and units, the spatial references to use during the operation and for the output graphics, and whether to union overlapping output buffers. The code below assumes that a Map control with an x:Name of "MyMap" has already been created. A BufferParameters object is initialized such that the buffer operation's units will be miles, its spatial reference will be World Hotine, the output's spatial reference will match that of MyMap, and overlapping output features will be unioned. Note that the operation spatial reference here, World Hotine, is well-suited to minimizing projection distortion in geometric operations when the location of the operation may be anywhere in the world. Other projections will be more suitable when the possible locations for the operation are limited to a smaller area.

GeometryService geometryService = new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
    "Geometry/GeometryServer");
geometryService.BufferCompleted += GeometryService_BufferCompleted;

BufferParameters bufferParameters = new BufferParameters()
{
    Unit = LinearUnit.StatuteMile,
    BufferSpatialReference = new SpatialReference(54025),
    OutSpatialReference = MyMap.SpatialReference,
    UnionResults = true
};

Each distance specified on the Buffer Parameters object is applied to each graphic that is buffered. The code below specifies distances of 10 and 20 miles. Note that the Distances property is read-only, so distances must be specified through the Add or AddRange methods.

GeometryService geometryService = new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
    "Geometry/GeometryServer");
geometryService.BufferCompleted += GeometryService_BufferCompleted;

BufferParameters bufferParameters = new BufferParameters()
{
    Unit = LinearUnit.StatuteMile,
    BufferSpatialReference = new SpatialReference(54025),
    OutSpatialReference = MyMap.SpatialReference,
    UnionResults = true
};

bufferParameters.Distances.AddRange(new double[] { 10, 20 });

Since GraphicsLayers store their features as lists of graphics, a common use of this operation is to buffer all the features in a GraphicsLayer as shown below. The code assumes that a GraphicsLayer with an ID of "MyGraphicsLayer" has already been created. Once all the buffer parameters have been specified, executing the operation is done by passing the BufferParameters object to the BufferAsync method.

GeometryService geometryService = new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
    "Geometry/GeometryServer");
geometryService.BufferCompleted += GeometryService_BufferCompleted;

BufferParameters bufferParameters = new BufferParameters()
{
    Unit = LinearUnit.StatuteMile,
    BufferSpatialReference = new SpatialReference(54025),
    OutSpatialReference = MyMap.SpatialReference,
    UnionResults = true
};

bufferParameters.Distances.AddRange(new double[] { 10, 20 });
GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer;
bufferParameters.Features.AddRange(graphicsLayer.Graphics);

geometryService.BufferAsync(bufferParameters);

The operation returns a list of Graphic objects containing the buffer geometries in the Results property of the result object. The result object is accessible through either the second parameter of a BufferCompleted event handler or the BufferLastResult property of the GeometryService object. The code below shows accessing results in an event handler. The example iterates through the results, applying a symbol to each and adding it to a GraphicsLayer. The code assumes that a Map with an x:Name of "MyMap" containing a GraphicsLayer with an ID of "MyGraphicsLayer" and a symbol with an x:Name of "DefaultBufferSymbol" have already been created.

void GeometryService_BufferCompleted(object sender, GraphicsEventArgs args)
{
    GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer;

    foreach (Graphic graphic in args.Results)
    {
        graphic.Symbol = DefaultBufferSymbol;
        graphicsLayer.Graphics.Add(graphic);
    }
}

LabelPoints

The LabelPoints operation creates points that are well-suited to be label locations for a list of input graphics. Since GraphicsLayers store their features as lists of graphics, a common usage pattern for this operation is to retrieve a GraphicsLayer and pass its Graphics collection to the operation as shown below. The code assumes that a Map with an x:Name of "MyMap" that contains a GraphicsLayer with an ID of "MyGraphicsLayer" has already been created.

GeometryService geometryService = new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
    "Geometry/GeometryServer");
geometryService.LabelPointsCompleted += GeometryService_LabelPointsCompleted;
GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer;
geometryService.LabelPointsAsync(graphicsLayer.Graphics.ToList());

The operation returns a list of Graphic objects containing the label points in the Results property of the result object. The result object is accessible through either the second parameter of a LabelPointsCompleted event handler or the LabelPointsLastResult property of the GeometryService object. The code below shows accessing results in an event handler. The example iterates through the results, applying a symbol to each and adding it to a GraphicsLayer. The code assumes that a Map with an x:Name of "MyMap" containing a GraphicsLayer with an ID of "MyResultsGraphicsLayer" and a symbol with an x:Name of "DefaultMarkerSymbol" have already been created.

void GeometryService_LabelPointsCompleted(object sender, GraphicsEventArgs args)
{
    GraphicsLayer graphicsLayer = MyMap.Layers["MyResultsGraphicsLayer"] as GraphicsLayer;

    foreach (Graphic graphic in args.Results)
    {
        graphic.Symbol = DefaultMarkerSymbol;
        graphicsLayer.Graphics.Add(graphic);
    }
}

Lengths

The Lengths operation calculates the lenths of a list of polyline graphics. Since GraphicsLayers store their features as lists of graphics, a common usage pattern for this operation is to retrieve a GraphicsLayer and pass its Graphics collection to the operation as shown below. The code assumes that a Map with an x:Name of "MyMap" that contains a GraphicsLayer with an ID of "MyPolylineGraphicsLayer" has already been created.

GeometryService geometryService = 
    new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/" +
        "rest/services/Geometry/GeometryServer");
geometryService.LengthsCompleted += GeometryService_LengthsCompleted;
GraphicsLayer graphicsLayer = MyMap.Layers["MyPolylineGraphicsLayer"] as GraphicsLayer;
geometryService.LengthsAsync(graphicsLayer.Graphics.ToList());

The lengths returned by the operation are in a list of doubles stored in the Results property of the result object. The result object is accessible through either the second parameter of a LengthsCompleted event handler or the LengthsLastResult property of the GeometryService object. The code below shows accessing results in an event handler. The example simply iterates through the results, building a string with the calculated lengths. The returned values are at the same index in the results list as the input graphics from which the value was calculated.

private void GeometryService_LengthsCompleted(object sender, LengthsEventArgs args)
{
	string results = "";
	for (int i = 0; i < args.Results.Count; i++)
	{
		results += string.Format("Graphic {0}: Length = {1}\n", i, args.Results[i]);
	}
}

Project

The Project operation projects a list of graphics into a new spatial reference. Since GraphicsLayers store their features as lists of graphics, a common usage pattern for this operation is to retrieve a GraphicsLayer and pass its Graphics collection to the operation as shown below. This can be useful, for instance, before using the AreasAndLengths or Lengths operations, since those operations calculate distances in the units of the input graphics' spatial reference. The output spatial reference must also be specified when invoking the project method. The snippet below assumes that a Map with an x:Name of "MyMap" that contains a GraphicsLayer with an ID of "MyGraphicsLayer" has already been created. The spatial reference specified is the World Hotine projection.

GeometryService geometryService = new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
    "Geometry/GeometryServer");
geometryService.ProjectCompleted += GeometryService_ProjectCompleted;
GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer;
geometryService.ProjectAsync(graphicsLayer.Graphics.ToList(), new SpatialReference(54025));

The operation returns a list of Graphics having geometries that are in the spatial reference that you specified in the call to ProjectAsync. The graphics are accessible through either the second parameter of a ProjectCompleted event handler or the ProjectLastResult property of the GeometryService object. The code below shows passing the results to an AreasAndLengths operation. When coupled with call to ProjectAsync in the snippet above, the dimensions calculated by the AreasAndLengths operation will be in meters.

private void GeometryService_ProjectCompleted(object sender, ESRI.ArcGIS.Client.Tasks.GraphicsEventArgs args)
{
    GeometryService geometryService = new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
        "Geometry/GeometryServer");
    geometryService.AreasAndLengthsCompleted += GeometryService_AreasAndLengthsCompleted;
    geometryService.AreasAndLengthsAsync(args.Results);
}

Relation

The Relation operation determines whether a spatial relationship is true between two sets of input graphics. Since GraphicsLayers store their features as lists of graphics, one common use of this operation is to retrieve two GraphicsLayers and pass their Graphics collections to the operation along with the relationship to be tested. When the operation executes, it will check each geometry in the first list against each geometry in the second list to see whether the specified relationship is true. The code below shows this usage and assumes that a Map with an x:Name of "MyMap" that contains GraphicsLayers with IDs of "MyPointGraphicsLayer" and "MyPolygonGraphicsLayer" has already been created.

GeometryService geometryService = new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
    "Geometry/GeometryServer");
geometryService.RelationCompleted += GeometryService_RelationCompleted;
GraphicsLayer pointGraphicsLayer = MyMap.Layers["MyPointGraphicsLayer"] as GraphicsLayer;
GraphicsLayer polygonGraphicsLayer = MyMap.Layers["MyPolygonGraphicsLayer"] as GraphicsLayer;
geometryService.RelationAsync(pointGraphicsLayer.Graphics.ToList(), polygonGraphicsLayer.Graphics.ToList(),
    GeometryRelation.esriGeometryRelationWithin, null);

If you want to test a relationship that is not included in the GeometryRelation enumeration, then you can define the GeometryRelation parameter as esriGeometryRelationRelation and specify the fourth parameter as a Shape Comparison Language string that defines the desired relationship. For instance, the example below will check the polygons in the "MyPolygonGraphicsLayer" GraphicsLayer to see whether they share boundaries but not interiors. That is, that the polygons intersect such that the geometry of their intersection is a line.

GeometryService geometryService = new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
    "Geometry/GeometryServer");
geometryService.RelationCompleted += GeometryService_RelationCompleted;
GraphicsLayer polygonGraphicsLayer = MyMap.Layers["MyPolygonGraphicsLayer"] as GraphicsLayer;
string sclRelationship = "dim(g1.boundary, g2.boundary) = linear AND intersect(g1.interior, g2.interior) = false";
geometryService.RelationAsync(polygonGraphicsLayer.Graphics.ToList(), polygonGraphicsLayer.Graphics.ToList(),
    GeometryRelation.esriGeometryRelationRelation, sclRelationship);

The operation returns a list of results that contains the indexes of the pairs of features for which the specified relationship is true. This information is encapsulated as a list of GeometryRelationPair objects that is stored in the Results property of the result object. The result object is accessible through either the second parameter of a RelationCompleted event handler or the RelationLastResult property of the GeometryService object. Each GeometryRelationPair object contains two properties—Graphic1Index and Graphic2Index. Graphic1Index stores the index of the graphic in the first input list of graphics, while Graphic2Index stores the index of the graphic in the second input list of graphics. The code below shows accessing results in an event handler. The example assumes that a Relation similar to the one in the first snippet above has been executed and iterates through the results, building a string indicating which points are within which polygon.

private void GeometryService_RelationCompleted(object sender, RelationEventArgs args)
{
    string results = "";
    for (int i = 0; i < args.Results.Count; i++)
    {
        results += string.Format("Point {0} is within polygon {1}.\n", args.Results[i].Graphic1Index, 
            args.Results[i].Graphic2Index);
    }
}

Simplify

The Simplify operation converts the geometries of a list of input graphics from complex to simple. This is important when using geometries for spatial queries because the results may not be accurate if the input geometries are not simplified. Simplifying geometries can also improve rendering performance. Since GraphicsLayers store their features as lists of graphics, a common usage pattern for this operation is to retrieve a GraphicsLayer and pass its Graphics collection to the operation as shown below. The code assumes that a Map with an x:Name of "MyMap" that contains a GraphicsLayer with an ID of "MyGraphicsLayer" has already been created.

GeometryService geometryService = new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
    "Geometry/GeometryServer");
geometryService.SimplifyCompleted += GeometryService_SimplifyCompleted;
GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer;
geometryService.SimplifyAsync(graphicsLayer.Graphics.ToList());

The operation returns a list of Graphic objects containing the simplified geometries in the Results property of the result object. The result object is accessible through either the second parameter of a SimplifyCompleted event handler or the SimplifyLastResult property of the GeometryService object. The code below shows accessing results in an event handler. The example iterates through the results, applying a symbol to each and adding it to a GraphicsLayer. The code assumes that a Map with an x:Name of "MyMap" containing a GraphicsLayer with an ID of "MyResultsGraphicsLayer" and a symbol with an x:Name of "DefaultSymbol" have already been created.

void GeometryService_SimplifyCompleted(object sender, GraphicsEventArgs args)
{
    GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer;

    foreach (Graphic graphic in args.Results)
    {
        graphic.Symbol = DefaultSymbol;
        graphicsLayer.Graphics.Add(graphic);
    }
}

1/27/2015