Tolerance units for IQueryFunctionality.Identify method
This is one of those issues on which I had spent quite a bit of time on trying to figure out the problem only to find out that it is an ESRI bug. I was having a hard time trying to get the identify on the features in the “FeatureGraphicsLayer” to work right. The issue i was having was that the identify on the features in the “FeatureGraphicsLayer” was acting funny when the map is zoomed in real close. The IQueryFunctionality.Identify(…) was returning results even when the user was clicking away from the features. When the user is zoomed out quite far in the map this is either not noticeable or it was returning more search features than it should. After eliminating a lot of possibilities, I narrowed down the problem to the value I am passing into the tolerance parameter of the Identify(…) function. As with all the Web ADF library, the documentation for the function and its parameters were missing. I had no way of finding out the units of the value I was passing into the tolerance parameter of the function. I was expecting it to be in pixels as it is with the ArcGIS Server layers. But things were not working as expected.
I emailed someone at ESRI (who will remain anonymous) about this issue and got this reply back.
Here is some information on tolerance with the IQueryFunctionality.Identify method:
The tolerance is in pixels around input geometry. It’s used in a call to the Identify method on the SOAP proxy (MapServerProxy or MapServerDcomProxy). The current extent of the map and the map size in pixels are used as input parameters to the method.
The tolerance is in pixels around an input point. It’s used to construct an IMS Envelope for an IMS Filter used in a call to FeatureLayer.Query() in the IMS API. The current extent of the map and the map size in pixels are used to construct the search envelope.
Web ADF Graphics:
The tolerance is the percentage expansion around an input point using the graphics data source’s full extent. This is a bug (NIM009302). The tolerance should be in pixels, and it should use the current extent of the map to construct a search envelope.
If only I had known about this beforehand or if ESRI had made an tiny effort to document their library, I could saved myself a whole bunch of time and mental agony. With this new information, I was able to work around the problem by simply converting the points in the results table into screen points and doing a simple distance calculation between them screen point of the user click and identifying the closest feature to the user click point.
Here is the code sample to do the above
/// Gets the index of the closest row if there are any points in the table that fall within the pixel tolerance that is specified.
/// If there are no points within the specified pixel tolerance then a NULL value is returned
/// <param name=”clickScreenPoint”>The click screen point.</param>
/// <param name=”resultsTable”>The results table.</param>
/// <param name=”pixelTolerance”>The tolerance value in pixels.</param>
/// <param name=”mapEnvelope”>The map envelope.</param>
/// <param name=”mapWidth”>Width of the map.</param>
/// <param name=”mapHeight”>Height of the map.</param>
private int? GetClosestRowIndex(System.Drawing.Point clickScreenPoint, System.Data.DataTable resultsTable, double pixelTolerance, ESRI.ArcGIS.ADF.Web.Geometry.Envelope mapEnvelope, int mapWidth, int mapHeight)
System.Data.DataRowCollection rows = resultsTable.Rows;
int? minIndex = null;
int count = 0;
foreach (System.Data.DataRow row in rows)
p = row[“GeometryElement”] as ESRI.ArcGIS.ADF.Web.Geometry.Point;
currentScreenPoint = p.ToScreenPoint(mapEnvelope, mapWidth, mapHeight);
distance = DistanceBetweenPoints(clickScreenPoint, currentScreenPoint);
if (distance < pixelTolerance)
pixelTolerance = distance;
minIndex = count;
/// Calculates the simple distance between the two screen points specified.
/// <param name=”point1″>The point1.</param>
/// <param name=”point2″>The point2.</param>
public double DistanceBetweenPoints(System.Drawing.Point point1, System.Drawing.Point point2)
double xd = point2.X – point1.X;
double yd = point2.Y – point1.Y;
return Math.Sqrt((xd * xd) + (yd * yd));