Clamp Graphics to ground altitude

544
5
Jump to solution
12-29-2020 01:35 PM
VictorBerchet
New Contributor III

I am implementing 3D live tracking using a SceneView with the JS API.

The app (flyxc.app) display the live track and some markers for messages and pilots:

arcgis_gnd_alt.jpeg

The app uses a GraphicsLayer for the tracks and the markers and a GraphicsLayer 'on-the-ground' for track shadows.

One issue I have is that some markers and the tracks could be rendered below the ground while I would like their elevation to never be below the ground.

I guess one way to solve this would be to use the ElevationSampler and compute the maximum of (fix altitude, sampled ground altitude). However it doesn't seem trivial: it probably should take the resolution of the sampler into account and recompute the sampled ground altitude when it changes.

If someone at Arcgis reads this, do you think a 'clamp-to-ground' mode would make sense in addition to the other available modes ? Or maybe there is an other robust way to achieve that ?

Thanks for your help and the great API,

Vic

1 Solution

Accepted Solutions
JohnGrayson
Esri Regular Contributor

If you're using a GraphicsLayer then one possible approach to research is the use of the 'relative-to-ground' setting, but instead of using the altitude value directly, you could calculate a 'relative altitude' value for each marker once before adding the Graphic to the GraphicsLayer.  One approach would be to use an ElevationSampler, but you might have other more appropriate methodologies depending on the data source. You can adjust the geometry Z directly, or if stored as an attribute, you can use the featureExpressionInfo instead of the geometry Z value. 

View solution in original post

5 Replies
JohnGrayson
Esri Regular Contributor

If you're using a GraphicsLayer then one possible approach to research is the use of the 'relative-to-ground' setting, but instead of using the altitude value directly, you could calculate a 'relative altitude' value for each marker once before adding the Graphic to the GraphicsLayer.  One approach would be to use an ElevationSampler, but you might have other more appropriate methodologies depending on the data source. You can adjust the geometry Z directly, or if stored as an attribute, you can use the featureExpressionInfo instead of the geometry Z value. 

VictorBerchet
New Contributor III

Thank for your answer John.

I fail to see how 'relative-to-ground' would help. I would still need the ArcGis ground altitude to compute the relative altitude, right ?

My understanding is that the ground altitude returned by the sampler varies with the resolution (i.e. the zoom level). That is what I observe on my app with markers becoming visible/hidden according to the zoom level. It is also easy to imagine that if the marker is located close to a cliff and the resolution is low then it is easy to get the altitude wrong with a lower resolution.

I was kind of hopping that there would be an easy hook in the ArcGis code where the it would be easy to retrieve the ground elevation, i.e. using a featureExpressionInfo as you mentioned.

The kind of problems I can foresee using an elevation sampler:

  • The sampler is not in sync with the displayed globe,
  • Having to listen on the sampler "change" event to recompute all the ground altitudes,
  • ...

It might give it a try if there is no better & easy solutions - those are too rare in SW dev 😉

VictorBerchet
New Contributor III

John,

I tried using the ElevationSampler and it actually works quite well.

I was mistakingly remembering that the API was async and was concerned about performances. But as the API is sync I guess it is a ~simple~ lookup, right ?

It will work great for my use case. I will set geometry z to max(gps fix, sampled ground altitude) and I should be all set.

Thanks !

Edit: Also for reference the sampler already takes into account exaggeration when set up as in the sample code.

JohnGrayson
Esri Regular Contributor

Please note that the ElevationSampler is available at various levels and depending on how you obtain the ElevationSampler it might be sync or async.  The async use-case is when you want to specify a specific/best elevation resolution in which case you might see additional requests going back to the service and thus async. This is for the one-time calculation use-case to achieve the best 'relative-to-ground' value (gps fix - sampled elevation).  When using the sync methods you'll be working against the current elevations in the view and you might still run into your original situation as the elevations under the marker location will change during navigation. Another possible approach is to use the sync version whenever the ElevationSampler changed event happens and the view is stationary, then update the marker geometries in the current view, but this might not be practical when a large number of markers are in the view.  In either use-case, using 'relative-to-ground' should ensure your markers are not displayed under the ground elevations.

VictorBerchet
New Contributor III

I am retrieving the sampler from the groundView of my scene.

It is sync and matches the currently shown ground elevation as you noted in your previous message. That is great for my use case.

A better accuracy (the async sampler) would not help my use case as I only want to display markers above the current ground.

As you also noted, one "problem" I have is that when the underlying data changes the markers could be off until their z is updated. The "changed" event is no really helpful as it basically fires at a high rate as soon as the view moves. One way to improve the situation would be to debounce the event handler. I have decided not to go down this path for now as I refresh the live tracking every 2mn or so and it should be good enough for now.

To keep things simple I am also not using "relative-to-ground" as I would have to create yet another layer. Again the ~2mn delay should be ok with my use case.

So basically I'm very happy with the integration. It is not perfect but it is great. I love working with the JS API which is simple yet powerful. Here is my code for reference - there is still room improvement on my side. I also really appreciate the great the support provided by the ESRI team, thanks for that!

I have a few ideas / comments / feedback on the API:

My live tracking data is GeoJSON. I can not use a GeoJSON layer because it wouldn't support altitude exaggeration. It would certainly be possible to subclass the layer to add support but it would be great if exaggeration is better supported out of the box.

My app tracks paraglider pilots. The "absolute" or "relative-to-ground" are not ideal for that as the lines and markers should not be below the ground. A "clamp-to-ground" mode would be ideal here - I feel it would be easier to implement within the API that trying to achieve it with client code. An example would be lines: imagine a track going over a hill. If the sampling interval is such that that there is one fix before the hill and one fix after the hill then the line would go through the hill. The current API is great if the object is on the ground but is less ideal for flying objects. I could super-sample the track to emulate a clamp to ground but it would be a lot of code. The primary use case is when pilots are higher above the ground.

Have a great day,

Vic

 

0 Kudos