Select to view content in your preferred language

AGSSceneView.locationToScreen method returns wrong values.

619
7
Jump to solution
07-18-2022 05:42 AM
YoussefMAHERZI
New Contributor III

This method returns wrong values when the scene has an elevation.

After further debugging I found out that this method expect the absolute altitude (including baseSurface elevation) but the shapes we draw have their altitude relative to the ground.

As a consequence, when the map has an elevation on the baseSurface and we use the same AGSPoint to draw a shape then in AGSSceneView.locationToScreen, the result of this function is not corresponding to what is displayed on the screen.

0 Kudos
1 Solution

Accepted Solutions
MarkDostal
Esri Regular Contributor

Thank you for the code, it helped reproduce things here.  After speaking with a member of our 3D team, I found a solution to your problem.  The LocationToScreen method takes an input MapPoint but its not aware of SurfacePlacement modes unlike Graphics in a Layer.  The MapPoint will be treated as absolute.  To work around this, you will need to retrieve the elevation value for the X,Y of the point and add it to the Z value of the graphic/geometry you want to input into the LocationToScreen method.

sceneView.scene?.baseSurface?.elevation(for:, completion:) will retrieve the elevation, which you would then add to the Z value of your point.

I realize you mentioned that method earlier, and that it is asynchronous, but hopefully it won't be too difficult to incorporate it into your code.

Let me know if I can be of further assistance,

Mark

View solution in original post

0 Kudos
7 Replies
MarkDostal
Esri Regular Contributor

Thank you for your question!  There are a couple of things you can try.

- You can try using the - (AGSPoint *)screenToBaseSurface:(CGPoint)screenPoint; method instead.  That method Converts the specified screen point to a location on the base surface i.e. ignoring any 3D features/graphics on or above the surface that may be intersecting the screen point. The location returned will have a z-value corresponding to the elevation at the intersecting surface.

- Depending on if your features/graphics are in a layer or in a graphics overlay, look at the 

AGSSurfacePlacement and AGSLayerSceneProperties classes. AGSLayerSceneProperties has a AGSSurfacePlacement property, which specifies how data belonging to the layer should be placed in relation to the scene's surface. Both AGSGraphicsOverlay and AGSFeatureLayer have a AGSLayerSceneProperties property which you can use to specify how the data is placed.

If that doesn't solve your issue, or if you have more questions, please reach out!

Mark

0 Kudos
YoussefMAHERZI
New Contributor III

Hello @MarkDostal and thank you for your quick response.
We just need to know where the graphic is displayed on the screen, and to do that I don't know which screenPoint I should use to call - (AGSPoint *)screenToBaseSurface:(CGPoint)screenPoint; since I may have different elevations on the screen. We tried sceneView.scene?.baseSurface?.elevation(for: point, completion: completion) to get the elevation but it is unfortunatly asynchrone hence too complicated to use in our case.

Concerning AGSSurfacePlacement, we use AGSGraphicsOverlay and the items are placed relatively to the ground which is what we needs.

0 Kudos
MarkDostal
Esri Regular Contributor

Sorry, I think I misunderstood your initial question, which was to get a screen location.  So, obviously, screenToBaseSurface won't work.  What do you want to do with the screen point once you have it?  The screen location of a particular map point/graphic/feature will change as the map is panned/zoomed.

What kind of issues are you seeing with AGSSceneView.locationToScreen?  A screen shot would be helpful, if possible.

Thanks,

Mark

0 Kudos
YoussefMAHERZI
New Contributor III

Hi,

I have a graphic displayed in a 3D map and I just want to know if the graphic is visible on the map and with some padding, not too close to the edge.
The problem is when the baseSurface of the map has an elevation, the result returned by AGSSceneView.locationToScreen is wrong. It returns that the shape is visible on screen with y = 15 when in reality the shape is off screen with y ~= -10. I use the same AGSPoint to draw the shape and as a parameter to AGSSceneView.locationToScreen.

 

0 Kudos
MarkDostal
Esri Regular Contributor

I've tried a few things out on my end, but to make sure I'm understanding things correctly, can you send me the coordinates and SR of the `AGSPoint` used to draw the graphic?  Also, the `SceneView`s `currentViewpointCamera`?  I can then replicate what you're seeing.

For example:

                print("currentViewpointCamera: \(sceneView.currentViewpointCamera())")

                print("geometry = \(g.geometry)")

Which gives this output:

currentViewpointCamera: AGSCamera: heading: 330.00, pitch: 97.00, roll: 0.00, location: AGSPoint: (-4.459500, 48.388900, 80.000000, nan), sr: 4326
geometry = Optional(AGSPoint: (-4.460926, 48.390397, 71.284401, nan), sr: 4326)

If you could also provide the elevation source you are using (if it's OK to share), that would be great.

That way I can recreate the issue here and delve into it some more.

Thank you for your patience!

Mark

0 Kudos
YoussefMAHERZI
New Contributor III

Hi,

I created a demo project to show screen location in the console. 

When surfacePlacement = .absolute, the method works correctly but when it's .relative the returned result is wrong.
How should we get the location of a graphic on the screen if we use the relative altitude ?

0 Kudos
MarkDostal
Esri Regular Contributor

Thank you for the code, it helped reproduce things here.  After speaking with a member of our 3D team, I found a solution to your problem.  The LocationToScreen method takes an input MapPoint but its not aware of SurfacePlacement modes unlike Graphics in a Layer.  The MapPoint will be treated as absolute.  To work around this, you will need to retrieve the elevation value for the X,Y of the point and add it to the Z value of the graphic/geometry you want to input into the LocationToScreen method.

sceneView.scene?.baseSurface?.elevation(for:, completion:) will retrieve the elevation, which you would then add to the Z value of your point.

I realize you mentioned that method earlier, and that it is asynchronous, but hopefully it won't be too difficult to incorporate it into your code.

Let me know if I can be of further assistance,

Mark

0 Kudos