Select features in 3D view

701
6
03-15-2019 05:15 PM
FayuLai
New Contributor II

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?

Tags (2)
0 Kudos
6 Replies
Wolf
by Esri Regular Contributor
Esri Regular Contributor

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

0 Kudos
FayuLai
New Contributor II

Thank you very much, Wolf. It is working now!

0 Kudos
FayuLai
New Contributor II

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.

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

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);
0 Kudos
FayuLai
New Contributor II

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

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

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

}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos