Vishful thinking…

Tolerance units for IQueryFunctionality.Identify method

Posted in ArcGIS, ESRI by viswaug on August 25, 2007

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:

ArcGIS Server:  

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.   

  ArcIMS:
  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

    /// <summary>

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

    /// </summary>

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

    /// <returns></returns>

    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;

        ESRI.ArcGIS.ADF.Web.Geometry.Point p;

        double distance;

        int? minIndex = null;

        int count = 0;

 

        System.Drawing.Point currentScreenPoint;

 

        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;

            }

            count++;

        }

        return minIndex;

    }

 

    /// <summary>

    /// Calculates the simple distance between the two screen points specified.

    /// </summary>

    /// <param name=”point1″>The point1.</param>

    /// <param name=”point2″>The point2.</param>

    /// <returns></returns>

    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));

    }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: