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

Instantiate a 3d model at a given GPS location #30

Closed
Biouche opened this issue Sep 16, 2024 · 7 comments
Closed

Instantiate a 3d model at a given GPS location #30

Biouche opened this issue Sep 16, 2024 · 7 comments

Comments

@Biouche
Copy link

Biouche commented Sep 16, 2024

Hello @ebeaufay,

I've been reading your code and docs and tried to instantiate a model at a given lat/long/height on a Google 3d tile but I couldn't succeed.

Do you have hints on how I could achieve that ?

Thank you for your help,
Bioush

@ebeaufay
Copy link
Owner

My strategy with this library is to "unreference" Google earth so that a specific point on the surface is at 0,0,0.

Then, georeferencing your own model is easy.

I'll make a better demo but here's one that shouldn't be too hard to understand https://drive.google.com/file/d/1WPT7yvMyoXIt6e9TqzfRqWFmtiDuGDTZ/view?usp=drivesdk

With the "UltraGlobe" lib, I do the opposite transform

@Biouche
Copy link
Author

Biouche commented Sep 17, 2024

Hey @ebeaufay thank you for you quick answer,

Here is the detail of what I did leading to unsuccessful positioning :

// Import dependencies
...
// init scene, camera, renderer, tile loader, camera controller
...
// Init google tileset

const google = new OGC3DTile({
    url: "https://tile.googleapis.com/v1/3dtiles/root.json",
    queryParams: { key: "MY_KEY" },
    geometricErrorMultiplier: geometricErrorMultiplier,
    tileLoader: tileLoader,
    loadingStrategy: loadingStrategy,
    distanceBias: distanceBias,
    displayCopyright: true,
    static: false,
    renderer: renderer
});

earthAntiGeoreferencing(google, TILESET_LON, TILESET_LAT, TILESET_HEIGHT);
scene.add(google);

Then for 3D Model instancing:

// GPS Coordinates
const modelGPSCoord = new THREE.Vector3(MODEL_LON, MODEL_LAT, MODEL_HEIGHT);
const googleTilesetCoord= new THREE.Vector3(TILESET_LON, TILESET_LAT, TILESET_HEIGHT);

// Convert to cartesian coordinates
const modelCartesianCoord = llhToCartesianFast(modelGPSCoord.x, modelGPSCoord.y, modelGPSCoord.z);
const tilesetCartesianCoord = llhToCartesianFast(googleTilesetCoord.x, googleTilesetCoord.y, googleTilesetCoord.z);

// Compute model local offset
const targetPos = new THREE.Vector3(
    modelCartesianCoord.x - tilesetCartesianCoord.x, 
    modelCartesianCoord.y - tilesetCartesianCoord.y, 
    modelCartesianCoord.z - tilesetCartesianCoord.z
);

// Instantiate model at 'targetPos' in THREE scene
...

Using this strategy, the model doesn't appear in the correct position.

Thanks,
Bioush

@ebeaufay
Copy link
Owner

is your model georeferenced?

if you open it in blender, is it centered on 0,0,0?

If so, you don't need to transform the model, you only transform the google tiles.

Leave your model in it's original coordinate system and transform google earth data with
earthAntiGeoreferencing(google, MODEL_LON, MODEL_LAT, MODEL_HEIGHT).

then if it's not perfect, you can still move your model a bit to bring it higher, a bit more to the left or whatever in local cartesian coordinates.

If your model is georeferenced, the question becomes in what reference because there are thousands and ideally, you'll have to apply the transformation to every vertex rather than to the entire model.

@Biouche
Copy link
Author

Biouche commented Sep 18, 2024

Thank you.

My model centered on 0,0,0, not having georeferenced coordinates.
I understand your solution, but this would not work if I want to instantiate multiple models associated to different geodetic coordinates.
I would like to be able to find cartesian coordinates for 3D models from geodetic coordinates. THREEJS world origin would be associated to the geodetic coordinates given in earthAntiGeoreferencing function. Then it would be about finding the right offset for any geodetic coordinates regarding this 'center'.

@ebeaufay
Copy link
Owner

Hmmh, I see
I guess choose a lon lat to center Google tiles on

Then compute the 2d vector in meters between the Google center point and your model desired center point. Apply that directly to the model "position".

That's different from "llhToCartesian". That method computes the Cartesian coordinates for a lon lat height relative to the center of the earth.

What you want is simpler. You need a method that computes the 2d vector in meters between 2 llh points.

I guess ask chatGpt for one. Normally, the earth needs to be considered as an ellipsoid "wgs 84" but for small distances, you can get away with a sphere approximation

I'll make a layer in UltraGlobe to handle all this automatically but the lib is still a bit young. I think you're on the right track like this

@Biouche
Copy link
Author

Biouche commented Sep 23, 2024

Ok thank you I will try and post a solution here !

@Biouche
Copy link
Author

Biouche commented Sep 25, 2024

So here is the solution I used to compute the 2D vector from the Google center point to the coordinates of my model :

function distanceBetweenllh(llhReference, llhDestination) {
    // Average radius of the Earth in meters
    const R = 6371000; 

    // Convert latitude and longitude to radians
    const lat1Rad = THREE.MathUtils.degToRad(llhReference.lat);
    const lon1Rad = THREE.MathUtils.degToRad(llhReference.long);
    const lat2Rad = THREE.MathUtils.degToRad(llhDestination.lat);
    const lon2Rad = THREE.MathUtils.degToRad(llhDestination.long);

    // Differences in latitude and longitude
    const dLat = lat2Rad - lat1Rad;
    const dLon = lon2Rad - lon1Rad;

    // Distance in meters
    const x = R * dLon * Math.cos((lat1Rad + lat2Rad) / 2);
    const y = R * dLat;

    // Return 2D vector
    return { x: x, y: y };
}


Then you should convert this vector to Three js coordinate system:

const modelPos = new THREE.Vector3(vec2d.x, modelAltitude, -vec2d.y) 

Note that this method is fine for distances within a few kilometers, but will give unprecise results with higher distances.

For more precise calculation you can have a look at Haversine Formula.

@Biouche Biouche closed this as completed Sep 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants