Find the nearest geometry to the point

4766
4
08-20-2010 01:42 AM
xariaD
by
New Contributor III
How can we find the nearest polygon to a MapPoint when mouse is clicked on the map?
0 Kudos
4 Replies
TerryGiles
Occasional Contributor III
You could try using the DistanceAsynch method on the GeometryService.  Only hard part is that it looks like it only takes a single geometry for both the input (your map click) and the target (in this case one of your polygons).  You could query the polygon layer w/ the current map extent and then pass the geometry of each feature in the returned featureset to the Distance operation and simply keep track of the lowest distance and that features ID.  But, if there are no features from the polygon layer currently in the extent, that won't work... you could add some logic that if no features are returned within the map extent to try again w/ a 25% larger extent and keep bumping that up until there's a least one feature returned from the spatial query.
0 Kudos
JenniferNery
Esri Regular Contributor
This is one way of finding the nearest geometry but it can be optimized. This sample assumes you are only checking against one layer and will select the closest graphic.

The con for doing this is, you will be making async call on every graphic. You might want to refer to Buffer a Point and Intersect samples too. Another idea is to buffer the point returned by MapClick until you find geometries intersecting the buffered point. These intersecting geometries become your candidates for calling DistanceAsync. This may limit the number of async calls you make. At worse case, you may need to keep buffering the point only to find all geometries will intersect it, which means you will be calling DistanceAsync on all geometries anyway. I'm not sure how likely this scenario is but you have to remember too that there can be at most 1000 features returned for ArcGIS Server 10 or 500 for ArcGIS Server 9.31.

        public MainPage()
        {
            InitializeComponent();
            polygonLayer = this.MyMap.Layers["Polygon"] as FeatureLayer;
            geometryService = new GeometryService("http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer");
            geometryService.DistanceCompleted += new EventHandler<DistanceEventArgs>(GeometryService_DistanceCompleted);
            distanceParameter = new DistanceParameters()
            {
                DistanceUnit = LinearUnit.Kilometer,
                Geodesic = true
            };
        }

        FeatureLayer polygonLayer;
        GeometryService geometryService;
        DistanceParameters distanceParameter;
        Graphic closestGraphic;
        double distanceRecorded;

        private void MyMap_MouseClick(object sender, Map.MouseEventArgs e)
        {
            closestGraphic = null;
            distanceRecorded = 0;
            if (polygonLayer != null && polygonLayer.Graphics != null && polygonLayer.Graphics.Count > 0)
            {
                int i = 0;
                Graphic g = polygonLayer.Graphics;
                geometryService.DistanceAsync(e.MapPoint, g.Geometry, distanceParameter, new object[]{polygonLayer.Graphics, i, e.MapPoint});
            }
        }
   
        private void GeometryService_DistanceCompleted(object sender, DistanceEventArgs e)
        {
            object[] distanceParams = e.UserState as object[];
            if (distanceParams != null && distanceParams.Length == 3 && 
                distanceParams[0] is GraphicCollection && distanceParams[1] is int
                && distanceParams[2] is MapPoint)
            {
                GraphicCollection graphics = distanceParams[0] as GraphicCollection;
                int index = (int)distanceParams[1];
                MapPoint mp = distanceParams[2] as MapPoint;
                if (closestGraphic == null || distanceRecorded > e.Distance)
                {
                    distanceRecorded = e.Distance;
                    closestGraphic = graphics[index];
                }
                index++;
                if (index < graphics.Count)
                {
                    Graphic g = polygonLayer.Graphics[index];
                    geometryService.DistanceAsync(mp, g.Geometry, distanceParameter, new object[] { polygonLayer.Graphics, index, mp });
                }
                else
                {
                    foreach (Graphic g in graphics)
                    {
                        if (g == closestGraphic) 
                            g.Selected = true;
                        else
                            g.Selected = false;
                    }                    
                }
            }
        }
0 Kudos
ChrisBradberry
Occasional Contributor
Another way to do this is to prepare a theissen polygon layer first, put that in your service but don't draw it, and then you will only need one call to get the closest polygon ID with a simple query. 

You can make a theissen polygon directly if you have input points.  Otherwise, you will need to use the feature to points command in Arcmap to turn the polygon vertices into points, then use the create theissen polygons with the all fields option.  This will put a polygon around each point with the id of the polygon attached to each point.  Next dissolve on the input fid to make one theissen polygon per input polygon (this is not really necessary, but will give a more generalized data set).  Now you a data layer that allows you to click on the map and bring back the id of the closest polygon.

Chris
0 Kudos
ferrahdjedjiga
New Contributor
Yours probleme ma permis to resolve le mien,thanks
0 Kudos