Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setting elevation incorrect outside of west coast north america #655

Closed
kfarr opened this issue Jun 18, 2024 · 7 comments · Fixed by #720
Closed

setting elevation incorrect outside of west coast north america #655

kfarr opened this issue Jun 18, 2024 · 7 comments · Fixed by #720
Assignees

Comments

@kfarr
Copy link
Collaborator

kfarr commented Jun 18, 2024

setting elevation of 3dtiles from google maps lat/long was incorrect – using a ‘constant’ to convert between is faulty for the following cases

  • longitudes other than US / western hemisphere. More research on how to convert between elevation and google 3d tiles height (aka cesium 3dtiles standard)
  • setting proper height of 3dtiles also doesn't work as expected for northwestern hemisphere high elevation areas such as 48.4069835, -114.3008482 example scene https://3dstreet.app/#/scenes/d26ddfeb-7e46-4c63-bd22-bd58d100b049.json

To reproduce:

  • create a new scene
  • search for this location 48.4069975, -114.3008965 and then click somewhere on the map to fetch the proper "elevation" value from google maps, such as 938.46m
  • then add google maps 3d from add entity panel
  • notice that you are "below" the ground surface

Why?

  • the elevation value of the geospatial component is correctly set
  • however, the height value of the google 3d tiles is not

Question:

  • how to calculate the proper height value of threejs 3d tiles loader based on elevation
  • Today we do this with a "constant" that only appears to work in west coast US
    height: data.elevation - this.elevationHeightConstant,
  • what is elevation? what are the units of elevation that the google map api uses?
  • what is height? what are the units of height that threejs 3d tiles loader uses?

How to find the answer:

  • start looking at the documentation for each of these things to answer the quesetions above
  • "cheat" by asking other experts instead?

Related concepts:

  • how to "clamp to ground" with our implementation of threejs 3d tiles? is that possible?
@kfarr kfarr converted this from a draft issue Jun 18, 2024
@kfarr kfarr changed the title setting elevation incorrect outside of western hemisphere setting elevation incorrect outside of west coast north america Jun 21, 2024
@kfarr
Copy link
Collaborator Author

kfarr commented Jul 4, 2024

@bkovitz and I did some work this afternoon on using an old fashioned raycaster to find the ground

Here is a quick video of the attempt showing raycaster events for a box geometry but not the 3dtiles:
https://github.com/nytimes/three-loader-3dtiles/assets/470477/a98ed4ad-2b32-4796-93c5-88d4dfee0ea2

Here is a link to the WIP raycaster demo that does not work yet...
https://3dstreet.github.io/aframe-loader-3dtiles-component/examples/google-tiles-raycaster/

https://github.com/3DStreet/aframe-loader-3dtiles-component/blob/dev/examples/google-tiles-raycaster/index.html#L60

Instead, we may need to go lower level. This is a key part of the draping example.
https://github.com/nytimes/three-loader-3dtiles/blob/dev/src/draping.ts#L148

A super hacky hack could be creating a bespoke geojson with 1 point or a polygon around the same centerpoint as the scene long/lat, then use the working drape function from avner, then find a vertex from that polygon and locate it

looking at the a-frame raycaster component, it only intersects with elements in the a-frame scene graph (dom):
https://github.com/aframevr/aframe/blob/ca7b02ddd7bfa9d606cbbe7b092eb0c08afe5728/src/components/raycaster.js#L183

So perhaps after getting objects on line 185, we can then add all of the children object3d from the visible 3dtiles, see here: nytimes/three-loader-3dtiles#97

@kfarr kfarr moved this from To Do - High Prio to In progress in 3DStreet Dev Tracking Jul 4, 2024
@kfarr kfarr self-assigned this Jul 4, 2024
@Algorush
Copy link
Collaborator

Algorush commented Jul 8, 2024

I read this thread. Is it okay if I try to resolve this issue using the method suggested by Avnerus? Convert height from EGM96 Geoid format to desired format using Math.gl library? Maybe it would be easier

@Algorush
Copy link
Collaborator

Algorush commented Jul 8, 2024

In the process of my searches, I found that the height in the Google Maps API is indeed transmitted in the GM96 format, while the coordinates are in the WGS84 format. I also discovered that it is possible to get elevation information by coordinates in WGS84 format through other APIs such as: Open Elevation API, NASA, USGS Elevation Point Query Service. Or we can convert the height from EGM96 to WGS 84 using the egm96-universal translator (https://www.npmjs.com/package/egm96-universal) or proj4 library, for example. But transator is heavy (2,5mb).

@bkovitz
Copy link
Contributor

bkovitz commented Jul 8, 2024

Alexander, that sounds like promising info: that the elevation is EGM96 but the coordinates are WGS84 (very surprising!). If you could get that to work, it would be a principled solution. The solution that @kfarr and I put in on Saturday is somewhat unprincipled but it's very simple—just a few lines of code. It "empirically" finds the ground by doing a raycast from a high elevation straight down and seeing what it intersects. This avoids the problem that elevation databases can have inaccuracies, but it might still go wrong because tiles of different Levels of Detail get loaded into memory gradually and the raycaster might find a huge, coarse tile and therefore misjudge the elevation.

It might be worthwhile to implement the EGM96–WGS84 translation and then try out both methods at a variety of different geographical locations to see which method is truly reliable. All that really matters, of course, is that the eyepoint of the camera start out somewhat above ground. Even hundreds of meters above ground is OK, but below ground is not OK.

@kfarr
Copy link
Collaborator Author

kfarr commented Jul 8, 2024

@bkovitz @Algorush I also spent some time last night on the ability to do this via math instead of raycaster. Ben and I feared that the Ground Elevation Model would require interpolation and therefore be inaccurate. However, in my testing the accuracy is plenty good, but the remaining issue is that it uses a large GEM dataset either on the client (minimum 500k up to many megabytes) or needs to be a backend service that we or others host.

Here are 2 precise examples to validate this method. I used the NOAA API however that only works for US locations. There does not appear to be a simple / free / open api like this for all global lat/long points.

Rural location in Montana:

  • lat: 48.4069835;
  • long: -114.3008482;
  • elevation from google api: 938.07
  • actual height google 3d tiles height: 922.508 (result of 955 - constant of 32.492)
  • saved in our database in street-geo component: 955m (modified manually)
  • geoid height: -16.09 // https://geodesy.noaa.gov/api/geoid/ght?lat=48.4069835&lon=-114.3008482
  • calculating elevation from google API + geoid height = expected value

Hetch Hetchy reservoir / Yosemite:

A few options to proceed:

  1. refine the "empirical" method that Ben and I created
  2. explore creating a cloud function with the GEM model in memory so that we can query it

I vote to continue (1)

@Algorush
Copy link
Collaborator

Algorush commented Jul 8, 2024

I can also try to make a cloud (Firebase?) function that will accept lat, long and return the height in WGS84 to the request.
The function will make requests to Google Maps for the height in EGM96, convert it to WGS84 using a ready-made library (edm-universal) or I can write my own version with proj4 or Math.gl and return the height in WGS84 to the request

@kfarr kfarr linked a pull request Jul 21, 2024 that will close this issue
5 tasks
@kfarr
Copy link
Collaborator Author

kfarr commented Jul 21, 2024

Ok I have a PR for review: #720

On a sidenote, I used the local firebase emulator which was helpful to avoid waiting for time to deploy firebase function to dev server:

I also deployed on dev server:
https://us-central1-dev-3dstreet.cloudfunctions.net/getGeoidHeight?lat=48.4069835&lon=-114.3008482

compare response to:
https://geodesy.noaa.gov/api/geoid/ght?lat=48.4069835&lon=-114.3008482

it's within a half a meter accuracy for that long/lat, that's plenty great and we can add a few meters to be safe? (to ensure that we're always above ground and not below ground?)

but we should test a few more lat/long locations

next steps:

  • add as a new field to geospatial component such as geoid-height
  • consider fetching google elevation service height value for long/lat
  • do calculation to figure out geoid height relation to 3dtiles height value and set that
  • add new value to user interface -- ux questions -- which one to display? topographical? both? none?

@github-project-automation github-project-automation bot moved this from In progress to Done in 3DStreet Dev Tracking Jul 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

3 participants