I got the following error when I was trying to select features using a geometry from a SketchTool.
var pFeatures = pActiveView.GetFeatures(pGeometry);
"3D views only support selecting features interactively using geometry in screen coordinates relative to the top-left corner of the view."
I changed SketchOutputMode from Map to Screen. I had the same error. Any ideas?
This sample does what you need (in 2D and 3D): Map-Exploration - Identify With SketchTool
If you look at CustomIdentify.cs you will see the code snippet you are looking for.
Let me know if that works for you,
Wolf
Thank you very much, Wolf. It is working now!
Hi Wolfgang,
Is it possible to convert a geometry in screen coordinates to one in map coordinates? Or from map coordinates to screen coordinates? In ArcObjects, you are able to do so. But I could not find the similar APIs in Pro.
Hi Fayu,
You can use the following snippet to project your geometry to your Map's spatial reference:
var mapGeom = GeometryEngine.Instance.Project(screenGeometry,
MapView.Active.Map.SpatialReference);
Hi Wolfgang,
That is really an idea. I tried to implement this in my program and I got the following error:
System.ArgumentNullException: Value cannot be null.
Parameter name: Spatial reference is null.
The spatial reference of screen geometry is empty. That may cause the exception. But how to create a screen geometry with valid spatial reference?
Best regards,
Fayu
Sorry, I guess I should have tried this first. It would have been my preferred implementation. It appears that when you use SketchOutputMode = SketchOutputMode.Screen the OnSketchCompleteAsync geometry parameter has a null spatial reference (hence the exception you get). Most API functions actually allow you to directly use this 'screen spatial referenced' geometry, but if you want to get a MapPoint, Line, Polygone etc. you need to use the MapView.Active.ClientToMap method to convert to a useful geometry. So the short answer can be found in this snippet:
protected async override Task<bool> OnSketchCompleteAsync(Geometry geometry)
{
if (geometry.SpatialReference == null)
{
// screen coordinates
var screenPointAsMapPoint = geometry as MapPoint;
if (screenPointAsMapPoint != null)
{
var pnt = new System.Windows.Point {
X = screenPointAsMapPoint.X,
Y = screenPointAsMapPoint.Y};
var mapScreenPoint = await QueuedTask.Run<MapPoint>(
() => MapView.Active.ClientToMap(pnt));
_graphic = await this.AddOverlayAsync(mapScreenPoint, _pointSymbol.MakeSymbolReference());
}
}
}
For the long answer I tried the sample snippet below by creating a tool called MapToolScreenToMap. This tool uses the screen coordinates (points only) and converts the Point to a MapPoint using the current Map's spatial reference. I tried both 2D and 3D, both seem to work.
internal class MapToolScreenToMap : MapTool
{
private CIMPointSymbol _pointSymbol = null;
private IDisposable _graphic = null;
public MapToolScreenToMap()
{
IsSketchTool = true;
SketchType = SketchGeometryType.Point;
SketchOutputMode = SketchOutputMode.Screen;
}
protected async override Task OnToolActivateAsync(bool active)
{
if (_pointSymbol == null) _pointSymbol = await CreatePointSymbolAsync();
}
protected async override Task<bool> OnSketchCompleteAsync(Geometry geometry)
{
if (geometry.SpatialReference == null)
{
// screen coordinates
var screenPointAsMapPoint = geometry as MapPoint;
if (screenPointAsMapPoint != null) {
var mapScreenPoint = await QueuedTask.Run<MapPoint>( () => MapView.Active.ClientToMap(new System.Windows.Point { X=screenPointAsMapPoint.X, Y =screenPointAsMapPoint.Y}));
_graphic = await this.AddOverlayAsync(mapScreenPoint, _pointSymbol.MakeSymbolReference());
}
}
else
{
// map coordinates
_graphic = await this.AddOverlayAsync(geometry, _pointSymbol.MakeSymbolReference());
}
return true;
}
protected override Task OnToolDeactivateAsync(bool hasMapViewChanged)
{
if (_graphic != null) _graphic.Dispose();//Clear out the old overlay
_graphic = null;
return base.OnToolDeactivateAsync(hasMapViewChanged);
}
internal static Task<CIMPointSymbol> CreatePointSymbolAsync()
{
return QueuedTask.Run(() => SymbolFactory.Instance.ConstructPointSymbol(ColorFactory.Instance.RedRGB, 14, SimpleMarkerStyle.Circle));
}
}