I have a Map Tool that listens for a click on the map to then search for shapes (mainly lines and points). I already have the settings enabled to use the visual shape to increase the click area, but is it possible to extend that even further? I know that you can use a circle to increase the search area, but that makes zoomed-in clicks much wider than zoomed out clicks. Is there a way to scale the circle to the screen size, so for example, I would search and extra 4 pixels in all directions?
Solved! Go to Solution.
protected override async Task<bool> OnSketchCompleteAsync(Geometry geometry) {
return await QueuedTask.Run<bool>(async () => {
// geometry is a point
var clickedPnt = geometry as MapPoint;
if (clickedPnt == null)
return false;
float tolerance = 4.0f; // Buffer size
// Take the screen-space point and buffer it by the tolerance
var topLeft = new Coordinate2D(clickedPnt.X - tolerance, clickedPnt.Y + tolerance);
var bottomRight = new Coordinate2D(clickedPnt.X + tolerance, clickedPnt.Y - tolerance);
Geometry envelopeGeometry = EnvelopeBuilderEx.CreateEnvelope(topLeft, bottomRight);
if (envelopeGeometry == null)
return false;
var result = ActiveMapView.GetFeatures(envelopeGeometry);
foreach (var kvp in result.ToDictionary()){
// Do Stuff
}
return true; // Return T/F based on the above loop
});
}
Thanks for pointing me to that!
I found a mistake in that example, though. The envelope created is never used, and if it were used, it wouldn't find the correct target due to a differing spatial reference id.
Here is the correct code:
Thanks for pointing out the issue with the sample, i will correct the issue for the upcoming 3.2 release.
This code uses a circle around the click point using the pixel tolerance as the radius:
// pixel tolerance
var toleranceInScreenUnits = 10;
// Use bottomRight to popup the dynamic menu result
bottomRight = new Point(clickedPnt.X + toleranceInScreenUnits, clickedPnt.Y + toleranceInScreenUnits);
var toleranceInMapUnits = GetScreenPointsInMapUnits(toleranceInScreenUnits, MapView.Active);
// Create a search circle around the click point using the pixel tolerance as a radius
var pnt = MapView.Active.ClientToMap(new Point(clickedPnt.X, clickedPnt.Y));
var arcSegment = EllipticArcBuilderEx.CreateCircle(pnt.Coordinate2D, toleranceInMapUnits, ArcOrientation.ArcClockwise, pnt.SpatialReference);
var circlePolygon = PolygonBuilderEx.CreatePolygon(new[] { arcSegment });
//Get the features that intersect the search circle polygon
var result = ActiveMapView.GetFeatures(circlePolygon);
Here is a screenshot that show the search polygon on the map:
Hi,
Look at ArcGIS Pro SDK community sample
It uses MapTool with SketchOutputMode equal SketchOutputMode.Screen.
In OnToolActivateAsync method it expands clicked point extent by 3 pixels.
protected override async Task<bool> OnSketchCompleteAsync(Geometry geometry) {
return await QueuedTask.Run<bool>(async () => {
// geometry is a point
var clickedPnt = geometry as MapPoint;
if (clickedPnt == null)
return false;
float tolerance = 4.0f; // Buffer size
// Take the screen-space point and buffer it by the tolerance
var topLeft = new Coordinate2D(clickedPnt.X - tolerance, clickedPnt.Y + tolerance);
var bottomRight = new Coordinate2D(clickedPnt.X + tolerance, clickedPnt.Y - tolerance);
Geometry envelopeGeometry = EnvelopeBuilderEx.CreateEnvelope(topLeft, bottomRight);
if (envelopeGeometry == null)
return false;
var result = ActiveMapView.GetFeatures(envelopeGeometry);
foreach (var kvp in result.ToDictionary()){
// Do Stuff
}
return true; // Return T/F based on the above loop
});
}
Thanks for pointing me to that!
I found a mistake in that example, though. The envelope created is never used, and if it were used, it wouldn't find the correct target due to a differing spatial reference id.
Here is the correct code:
Thanks for pointing out the issue with the sample, i will correct the issue for the upcoming 3.2 release.
This code uses a circle around the click point using the pixel tolerance as the radius:
// pixel tolerance
var toleranceInScreenUnits = 10;
// Use bottomRight to popup the dynamic menu result
bottomRight = new Point(clickedPnt.X + toleranceInScreenUnits, clickedPnt.Y + toleranceInScreenUnits);
var toleranceInMapUnits = GetScreenPointsInMapUnits(toleranceInScreenUnits, MapView.Active);
// Create a search circle around the click point using the pixel tolerance as a radius
var pnt = MapView.Active.ClientToMap(new Point(clickedPnt.X, clickedPnt.Y));
var arcSegment = EllipticArcBuilderEx.CreateCircle(pnt.Coordinate2D, toleranceInMapUnits, ArcOrientation.ArcClockwise, pnt.SpatialReference);
var circlePolygon = PolygonBuilderEx.CreatePolygon(new[] { arcSegment });
//Get the features that intersect the search circle polygon
var result = ActiveMapView.GetFeatures(circlePolygon);
Here is a screenshot that show the search polygon on the map:
Thank you for that!
Where does GetScreenPointsInMapUnits come from?
Sorry i forgot to include the GetScreenPointsInMapUnits method in my snippet above.
private double GetScreenPointsInMapUnits (double pixels, MapView mapView)
{
var left = new Point(0, 0);
var right = new Point(0, pixels);
var pntLeft = mapView.ClientToMap(left);
var pntRight = mapView.ClientToMap(right);
var line = LineBuilderEx.CreateLineSegment (pntLeft, pntRight);
return line.Length;
}
In essence the method takes the tolerance in screen units (i.e. pixels) and returns the tolerance in units for the current active map's spatial reference. So when i generate the circle geometry for the search i can then use toleranceInMapUnits as the radius for the circle.