Querying, selecting, and buffering spatial data


Summary Querying the content of a spatial data source provides an application user with the ability to interact with and utilize attributes, feature geometry, and image information in the same or a related data source. The .NET ArcIMS application programming interface (API) enables a developer to query feature layers and image layers exposed in an image service or an ArcMap service.

In this topic


Querying feature layers

Feature layers can be queried using one of the following methods:
  • Attribute only—An attribute query is defined using Structured Query Language (SQL) in a where clause. The SQL statement uses fields and associated values or value ranges within the queried layer to filter returned content.
  • Spatial only—The intersection between user-defined feature geometry and features in a data layer determine returned content. 
  • Attribute and spatial—Both attributes and feature geometry are used to query a data layer and determine returned content.
Returned content can take the form of attribute data or a map image. Map image content can be further defined by either displaying a subset of an existing layer or creating a new layer to display selected features. In all cases, the query process can be enhanced by using a buffer to further refine returned content.
The ESRI.ArcGIS.ADF.IMS.Carto.Layer namespace contains the following primary classes that query feature layers:
  • Filter
  • QueryParameters
  • FeatureLayer
Filter defines both the attribute and spatial component in a query. The attribute component is modified using the Filter.WhereExpression property as shown in the following code:
[C#]
Filter filter = new Filter();
filter.WhereExpression = "CITY_NAME = 'Phoenix'";
The spatial component is modified by setting the Filter.Geometry property to feature geometry created using the following classes from the ESRI.ArcGIS.ADF.Web.Geometry namespace:
  • Envelope
  • Point
  • Multipoint
  • Polyline
  • Polygon
How a filter is implemented determines what type of content is returned. If a filter is associated with QueryParameters, it returns filtered attributes; otherwise it filters features rendered in a map image. In all cases, the filter is applied to a feature layer via a property or method on the FeatureLayer class.
The Filter.Geometry property is shown in the following code:
[C#]
Filter filter = new Filter();
Envelope envelope = new Envelope( - 119, 32,  - 113, 35);
filter.Geometry = envelope;

Querying image (raster) layers

The ArcIMS API can be used to query image layers in an ArcIMS service. The ImageLayer.Identify() method returns a collection of multibands within an image. Each multiband can contain a set of bands. Each band contains a single pixel value for a given coordinate location. This process is shown in the following code:
[C#]
Layer layer = layercollection.FindByName("sanfran.tif");
ImageLayer imagelayer = (ImageLayer)layer;
Point point = new Point( - 122.475, 37.648);
MultibandCollection multicollection = imagelayer.Identify(point);
IEnumerator iecollection = multicollection.GetEnumerator();
while (iecollection.MoveNext())
{
    Multiband multiband = (Multiband)iecollection.Current;
    IEnumerator ieband = multiband.GetEnumerator();
    while (ieband.MoveNext())
    {
        double bandvalue = (double)ieband.Current;
    }
}

Selecting and displaying a subset of features

To subset features in a feature layer and render them in a map, apply the filter to the FeatureLayer directly via the FeatureLayer.Filter property as shown in the following code:
[C#]
FeatureLayer featurelayer = (FeatureLayer)layer;
Filter filter = new Filter();
filter.WhereExpression = "CITY_NAME = 'Phoenix'";
Envelope envelope = new Envelope( - 119, 32,  - 113, 35);
filter.Geometry = envelope;
featurelayer.Filter = filter;
mapview.Draw();
The renderer that is defined for the feature layer in the map service is used to render features in the map.

Returning attributes of a features subset

The following steps illustrate how to return attributes associated with a subset of features in a feature layer:
  1. Create a QueryParameters instance.
  2. Set the QueryFilter property to a filter.
  3. Call the FeatureLayer.Query() method. 
A FeatureTable containing attributes and feature geometry is returned. The Filter.SubFields property determines the fields in the FeatureTable. By default, the subfields specified in the map service configuration file dictate the fields that are returned.
This process is shown in the following code:
[C#]
FeatureLayer featurelayer = (FeatureLayer)layer;
Filter filter = new Filter();
filter.WhereExpression = "CITY_NAME = 'Phoenix'";
Envelope envelope = new Envelope( - 119, 32,  - 113, 35);
filter.Geometry = envelope;
QueryParameters queryparams = new QueryParameters();
queryparams.QueryFilter = filter;
FeatureTable featuretable = featurelayer.Query(queryparams);
The FeatureTable class extends from the common ADO.NET System.Data.DataTable class; therefore, it can be utilized by any other DataTable in .NET. For example, it can be bound to a DataGrid or GridView control via the Source property or iterated through its data values using an enumerator retrieved via the GetEnumerator() method.

Returning geometry associated with features

By default, an attribute query does not return feature or envelope geometry. You can enable these capabilities by working with a set of properties on a QueryParameters instance. The following table shows the properties to set to true to return the appropriate geometry when querying a feature layer:
Property
Geometry returned*
ReturnGeometries
Feature geometry
ReturnEnvelope
Envelope of each feature returned in the query
ReturnGlobalEnvelope
Envelope of all features returned in the query
*Returned geometry types are in the ESRI.ArcGIS.ADF.IMS.Geometry namespace.

Returning a feature count

To return the number of features selected, use the FeatureLayer.GetFeatureCount() method. This method has two parameters: Filter and SelectionBuffer. SelectionBuffer can be used to define buffer properties and to further refine the request for a count of features as shown in the following code. If a buffer does not need to be used, the second parameter can be set to null.
[C#]
SelectionBuffer selectionbuffer = new SelectionBuffer(flayer, "");
selectionbuffer.Distance = 100;
int featurecount = flayer.GetFeatureCount(filter, selectionbuffer);

Iterating through a subset of features

For performance reasons, it may be necessary to limit the number of queried features to a manageable amount. The number of features queried, and the number of fields for each feature, increase the time needed by ArcIMS to process the transaction. The maximum number of feature attributes returned via a query can be set on the ArcIMS server or set by the client.
To limit the number of features requested from an ArcIMS service via the ArcIMS API (a client to ArcIMS), use the QueryParameter.FeatureLimit property and FeatureLayer.Query() method. The FeatureLimit property sets the maximum number of feature attributes returned from querying a feature layer. The Query() method is overridden to include a reference to the id value of the first feature to return. ArcIMS maintains a unique id for each feature in a feature layer exposed in a service. The unique id is determined by the physical location of a data row in the source dataset.
This process is shown in the following code: 
[C#]
QueryParameters queryparams = new QueryParameters(filter);
int FEATURE_LIMIT = 10;
queryparams.FeatureLimit = FEATURE_LIMIT;
int BEGIN_RECORD = 1;
FeatureTable featuretable;
DataTable mergetable = new DataTable();
do
{
    featuretable = featurelayer.Query(queryparams, BEGIN_RECORD);
    mergetable.Merge(featuretable);
    BEGIN_RECORD += FEATURE_LIMIT;
}

while (featuretable.HasMore);
The list of feature ids for a feature layer is one-based; thus, the first row (feature) in a dataset has an id value of one (1).
The feature order can only be changed in the underlying dataset; it cannot be changed via a where expression statement (for example, ORDER BY).

Displaying selected features

To display a subset of queried features as a selection on a map, create a FeatureLayer in which to store the selected features. The FeatureLayer.CreateSelectionLayer() method uses a filter, a renderer, and a layer id to create a new FeatureLayer to display selected features as shown in the following code. A renderer must be created for the new FeatureLayer to display the selected features. The layer id should consist of a unique string to identify the new FeatureLayer from other layers in the map service.
[C#]
FeatureLayer featurelayer = (FeatureLayer)layer;
Filter filter = new Filter();
filter.WhereExpression = "CITY_NAME = 'Phoenix'";
Envelope envelope = new Envelope( - 119, 32,  - 113, 35);
filter.Geometry = envelope;

SimpleRenderer simplerenderer = new SimpleRenderer();
SimpleMarkerSymbol sms = new SimpleMarkerSymbol();
sms.Color = System.Drawing.Color.Yellow;
simplerenderer.Symbol = sms;

FeatureLayer selectionlayer = featurelayer.CreateSelectionLayer(filter,
    simplerenderer, "myselectionid");
mapview.Layers.Add(selectionlayer);
mapview.Draw();

Buffering

A buffer is defined as the area within a specified distance around a feature. The query process implemented by the AXL Object API can be enhanced by using buffers on selected features or feature geometry. Buffers are generated to perform the following:
  • Display a buffer in a map
  • Return buffer geometry
  • Display features selected by the buffer in a map
  • Return attributes of features selected by a buffer
The ESRI.ArcGIS.ADF.IMS.Carto.Layer namespace contains two classes to generate buffers: DisplayBuffer and SelectionBuffer. In general, DisplayBuffer is used to display the buffer in a map. SelectionBuffer is used to either display features selected by a buffer in a map, or return attributes of features selected by a buffer. Both of these require setting their Distance property to a valid value in map units. By default, map units are set in a map service; however, they can be modified by setting the Units property.

Displaying a buffer

The FeatureLayer.CreateBufferLayer() method generates a FeatureLayer containing buffer geometry. The buffer is generated on the feature layer that calls the CreateBufferLayer() method. This method requires the following parameters:
  • Filter—Defines the attribute and spatial component used to select features on which a buffer is created.
  • DisplayBuffer—Stores buffer-specific information, such as distance and map units.
  • Renderer—Defines how the buffer is rendered in the map.
  • String—Defines a unique layer id for the new FeatureLayer.
These parameters are shown in the following code:
[C#]
FeatureLayer featurelayer = (FeatureLayer)layer;
Filter filter = new Filter();
filter.WhereExpression = "CITY_NAME = 'Phoenix'";
Envelope envelope = new Envelope( - 119, 32,  - 113, 35);
filter.Geometry = envelope;

DisplayBuffer displaybuffer = new DisplayBuffer();
displaybuffer.Distance = 200;
displaybuffer.Units = BufferUnits.Miles;

SimpleRenderer bufferrenderer = new SimpleRenderer();
SimpleFillSymbol sfs = new SimpleFillSymbol();
sfs.Color = System.Drawing.Color.Yellow;
sfs.Transparency = 50.0;
bufferrenderer.Symbol = sfs;

FeatureLayer bufferlayer = featurelayer.CreateBufferLayer(filter, displaybuffer,
    bufferrenderer, "mybuffer");
mapview.Layers.Add(bufferlayer);
mapview.Draw();
Once the new FeatureLayer is created, it must be added to the map to be visible.

Returning buffer geometry

To return the geometry of a buffer, use SelectionBuffer without a target layer, and perform the following steps:
  1. Create a QueryParameters instance.
  2. Set the QueryFilter property to a filter that selects the features on which to construct a buffer.
  3. Set the SelectionBuffer property to the SelectionBuffer instance without the target layer defined.
  4. Call the FeatureLayer.Query() method.
This process is shown in the following code. The FeatureTable returned contains the buffer geometry in a single column named #SHAPE#. If only one buffer is created, the FeatureTable will contain only one row.
[C#]
FeatureLayer featurelayer = (FeatureLayer)layer;
Filter filter = new Filter();
filter.WhereExpression = "CITY_NAME = 'Phoenix'";

SelectionBuffer selectionbuffer = new SelectionBuffer();
selectionbuffer.Distance = 200;
selectionbuffer.Units = BufferUnits.Miles;

QueryParameters queryparams = new QueryParameters();
queryparams.QueryFilter = filter;
queryparams.SelectionBuffer = selectionbuffer;
queryparams.ReturnGeometries = true;

FeatureTable featuretable = featurelayer.Query(queryparams);

Displaying features selected by the buffer

The FeatureLayer.CreateBufferSelectionLayer() method generates a FeatureLayer containing features selected by the buffer. The buffer is generated on the feature layer that calls the CreateBufferSelectionLayer() method and can select features in the same layer or a different feature layer. The feature layer in which the selection occurs is called the target layer. The CreateBufferSelectionLayer() method requires the following parameters:
  • Filter—Defines the attribute and spatial component used to select features on which a buffer is created.
  • SelectionBuffer—Defines the target layer and an optional target layer where clause, as well as buffer distance and units. The target layer where clause can be used to further refine the query on the target layer. 
  • Renderer—Defines how the selected features are displayed; its symbol type must be appropriate for the selected feature type. For example, a marker symbol can be used to render point features, while a fill symbol cannot.
  • String—Defines a unique layer id for the new FeatureLayer. Once the new FeatureLayer is created, it must be added to the map to be visible.
These parameters are shown in the following code:
[C#]
FeatureLayer featurelayer = (FeatureLayer)layer;
Filter filter = new Filter();
Filter.WhereExpression = "CITY_NAME = 'Phoenix'";
Envelope envelope = new Envelope( - 119, 32,  - 113, 35);
filter.Geometry = envelope;

FeatureLayer targetlayer = (FeatureLayer)layercollection.FindByName("States");
string targetwhere = "";

SelectionBuffer selectionbuffer = new SelectionBuffer(targetlayer, targetwhere);
selectionbuffer.Distance = 200;
selectionbuffer.Units = BufferUnits.Miles;

SimpleRenderer targetrenderer = new SimpleRenderer();
SimpleFillSymbol sfs = new SimpleFillSymbol();
sfs.Color = System.Drawing.Color.Yellow;
targetrenderer.Symbol = sfs;

FeatureLayer selectionlayer = featurelayer.CreateBufferSelectionLayer(filter,
    selectionbuffer, targetrenderer, "mybufferselection");
mapview.Layers.Add(selectionlayer);
mapview.Draw();
When the buffer distance is set to 0, the inherent feature geometry of a feature layer can be used to evaluate spatial relationships in the same or another feature layer.

Returning feature attributes selected by the buffer

The following steps illustrate how to return attributes associated with features selected using a buffer:
  1. Create a QueryParameters instance.
  2. Set the QueryFilter property to a filter.
  3. Set the SelectionBuffer property to a BufferSelection.
  4. Call the FeatureLayer.Query() method. 
A FeatureTable containing attributes and feature geometry is returned.
This process is shown in the following code:
[C#]
FeatureLayer featurelayer = (FeatureLayer)layer;
Filter filter = new Filter();
Filter.WhereExpression = "CITY_NAME = 'Phoenix'";
Envelope envelope = new Envelope( - 119, 32,  - 113, 35);
filter.Geometry = envelope;

FeatureLayer targetlayer = (FeatureLayer)layercollection.FindByName("States");
string targetwhere = "";

SelectionBuffer selectionbuffer = new SelectionBuffer(targetlayer, targetwhere);
selectionbuffer.Distance = 200;
selectionbuffer.Units = BufferUnits.Miles;

QueryParameters queryparams = new QueryParameters();
queryparams.QueryFilter = filter;
queryparams.SelectionBuffer = selectionbuffer;
FeatureTable featuretable = featurelayer.Query(queryparams)
By default, subfields specified for the target layer in the map service configuration file dictate the fields that are returned. SelectionBuffer defines the target layer and an optional target layer where clause, as well as buffer distance and units. The target layer where clause can be used to further refine the query on the target layer.

Selection tolerance

Often when querying features in a map using geometry (such as an extent box or a point via a mouse click), the application developer must account for user error. For example, an application user clicks a map and selects features in a layer. However, due to imprecision in the usability of the application (such as converting pixel to map coordinates or lack of user visibility), the features are not selected. Another scenario involves using graphic or user-defined geometry to select features in a feature layer. For example, a user wants to locate all features within a distance from a geocoded point, represented as a graphic point on a map.
The Filter class defines two properties to account for these situations: Tolerance and ToleranceUnits. If the Filter.Geometry property is set to a valid geometry object, the Tolerance property defines the distance around the geometry in map units defined by the Units property. This constructs a buffer around the filter's geometry object. The filter can be used to subset and select features as well as return selected attributes as previously discussed.

Limitations

The filter for a target layer can only define a where clause via the SelectionBuffer.WhereExpression property. Additional filter properties, such as Subfields and Geometry, cannot be defined on a target layer.