Select to view content in your preferred language

Graphic Selection based on Draw Envelope issue

919
8
04-21-2010 02:06 PM
TonyBacon
Deactivated User
I have a FeatureLayer. I want to set the Graphic.Selected property for all of the Graphics that fall within a rectangle created with Draw. As I understand it Draw generates Geometries based on the Map controls spatial reference. The method for selection Graphics displayed by the FeatureLayer is FindGraphicsInHostCoordinates so I need to convert the Envelope returned by Draw to the Host Coordinates and I am using MapToScreen to accomplish this.

The problem is that the results from FindGraphicsInHostCoordinates does not include all of the graphics within the Envelope. The results are close to what I would expect if the Envelope was half as wide as what was drawn.

I don't know if the problem is in the Envelope returned by Draw, the conversion to host coordinates performed by MapToScreen or the locating of the graphics peformed by FindGraphicsInHostCoordinates. Or if maybe sleep apnea is preventing me from seeing the obvious. Here is the latest rendition of the code that I am using:

FeatureLayer sitesFeatureLayer = MyMap.Layers["NRA Site Points (FeatureLayer)"] as FeatureLayer;
Envelope selectedArea = args.Geometry as Envelope;
Point ul = MyMap.MapToScreen(new MapPoint(selectedArea.XMin, selectedArea.YMax));
Point ll = MyMap.MapToScreen(new MapPoint(selectedArea.XMin, selectedArea.YMin));
Point lr = MyMap.MapToScreen(new MapPoint(selectedArea.XMax, selectedArea.YMin));
double width = lr.X - ll.X;
double height = ll.Y - ul.Y;
Rect screenRect = new Rect(ul, new Size(width, height));
IEnumerable<Graphic> selectedSites = sitesFeatureLayer.FindGraphicsInHostCoordinates(screenRect);
foreach (Graphic feature in selectedSites) {
feature.Selected = !feature.Selected;
}

Sure hope someone has an answer to this as I am quite stumped.
0 Kudos
8 Replies
DanielWalton
Frequent Contributor
Another approach:

FeatureLayer sitesFeatureLayer = MyMap.Layers["NRA Site Points (FeatureLayer)"] as FeatureLayer;
Envelope selectedArea = args.Geometry as Envelope;
foreach (Graphic feature in sitesFeatureLayer.Graphics) 
{
    if (selectedArea.Intersects(feature.Geometry.Extent))
        feature.Selected = !feature.Selected;
}
0 Kudos
TonyBacon
Deactivated User
Thanks Dan that did the trick.

Come to think of it even if my approach had worked it would not have been as efficient as there would be two loops over the graphics enumeration, one internally by FindGraphicsInHostCoordinates and then one to set the Selected property. This get's it done in one.

Appreciate the help.
0 Kudos
dotMorten_esri
Esri Notable Contributor
Dan's approach only selected based on the envelope of the geometries, and not the actual geometries themselves, so you risk getting a lot of false-positives.
Note that the method says "host coordinates". The method you use for transforming to screen coordinates are relative to the map, not the host.
You can get a method for transforming between the two by doing:
Point screenPointRelativeToHost = map.TransformToVisual(Application.Current.RootVisual).Transform(screenPointRelativeToMap);

The method is based on Silverlight's FindElementsInHostCoordinates which you can read about here: http://msdn.microsoft.com/en-us/library/system.windows.media.visualtreehelper.findelementsinhostcoor...

Your argument for why Dan's method is more efficient is not true, since you will only be looping on the features you selected, where in Dan's you loop on ALL features and perform a manual intersection test. The above method instead uses Silverlight's internal unmanaged efficient mechanism for doing screen-hit testing and will even take the symbology into account (a point is infinitely small in Dan's approach, but in the above it's the size of the symbol, so selections will make more sense to the user).
Having said that though, I doubt any of them is of a major concern performance wise.
0 Kudos
DanielWalton
Frequent Contributor
The above method instead uses Silverlight's internal unmanaged efficient mechanism for doing screen-hit testing and will even take the symbology into account


Morten,

Is there a way to use this function without taking the symbols into account (i.e. for more geographically accurate querying)? Also, I've been looking around for an efficient implementation of a polygon intersection algorithm (pref. in C#) so that we can do accurate spatial queries without having to use services. Have you found any?

Thanks,
Dan
0 Kudos
dotMorten_esri
Esri Notable Contributor
For that you should use the service using QueryTask. If not, you have to build your own intersection algorithm.
0 Kudos
TonyBacon
Deactivated User
Dan's approach only selected based on the envelope of the geometries...


Thanks Morton, I was so relieved to have something appear to work I did not notice this. Also thanks for the differntiation regarding Visual vs Host. I was not quite sure how to interpret Host and had infact miss-interpreted it as Visual.
0 Kudos
AgatinoLa_Rosa
Emerging Contributor
I have a world map and want to draw a rectangle showing the full extent of a layer. I cannot see the graphics on the map. Any help?

        private void DrawBox(Layer thisLayer)
        {

            GraphicsLayer thisGraphicLayer = MyMap.Layers["BoxLayer"(defined in xaml)] as GraphicsLayer;
            Envelope thisExtent = (Envelope)thisLayer.Extent;
            MapPoint thisUpperCorner = new MapPoint();
            thisUpperCorner.X = thisExtent.XMin;
            thisUpperCorner.Y = thisExtent.YMax;
            MapPoint thisLowerCorner = new MapPoint();
            thisLowerCorner.X = thisExtent.XMax;
            thisLowerCorner.Y = thisExtent.YMin;

            PointCollection thisBoxPoints = new PointCollection();
            thisBoxPoints.Add(thisUpperCorner);
            thisBoxPoints.Add(thisLowerCorner);

            Polygon thisBox = new Polygon();
            thisBox.Rings.Add(thisBoxPoints);

            Graphic thisGraphicBox = new Graphic()
            {
                Geometry = thisBox,
                Symbol = this.RedFillSymbol (defined in xaml)
            };

            thisGraphicLayer.Graphics.Add(thisGraphicBox);

        }
0 Kudos
AgatinoLa_Rosa
Emerging Contributor
I solved my issue. Polygon requests a closed set of points. I had in mind the Envelope.
0 Kudos