Work with lat, lon (EPSG: 4326) coordinates

Hi everyone,

I have data with lat, lon coords and I would like to visualize them in 3D space. Is there a way to set scene reference system to use a specific coordinate reference system (for example: EPSG: 4326) instead of the default, arbitrary one?

I thought that this would be a very common problem with a very straightforward solution.

I am quite new to Three.js. Any resources to read or any examples are more than welcome!

Thank you in advance!

I had to deal with this for WGS84 coords before - I think that’s the same as EPSG: 4326?

The position is easy - you can map the center of your scene to any lat/long you choose, and you can pick Y=0 to be sea level or any other height you like.

Scale is also easy - three.js units are assumed to be meters, usually, but you can choose any scale you like. Just make sure it matches any models you are using and then you might need to scale your lat lon to match. But if possible just use meters, or possibly kilometers for large scenes.

The problem is rotation. I could never find a conversion formula but I did ask over on GIS Stackexchange and got a reply which I used to muddle through to a solution. But I don’t have any immediate formula to give you, sorry.

If you’re not tied to three.js you could try using Cesium instead, I assume they already have systems for converting geospatial coords to 3d.

1 Like

Also possibly related:

1 Like

It all depends on the precision you expect.

For a quick and rough solution, you could assume the shape of the earth to be a perfect sphere (which it isn’t, but nevertheless). The formulas in this case are very simple and straightforward:

Knowing that the circumference of the earth at the equator is 40’000 km, you can compute the earth’s Radius at the equator to be

R = 40'000 / (2 * π) = 6'366.1977 km.

The radius at latitude “lat” equals to

r = R * cos( lat ).

Taking the equator (latitude = 0° and the Greenwich meridian (longitude = 0°) as reference, you can compute

X = (r * 2 * π) * (longitude / 2 * π) = r * longitude [rad]
(with the 1st bracket term being the circumference at latitude, and the 2nd bracket term being the fraction of the full circumference).

By the same reasoning, a full circumference along the 0° meridian is also 40’000 km, so the quarter circumference from equator to either of the poles is 10’000km.

So you can compute
Y = R * latitude [rad]

If you want to use this conversion to guide a cruise missile with [cm] precision into a target, obviously this method won’t be sufficient. But if you want to visualise a reasonably small patch of the earth’s surface onto a flat plane, you can expect very good results with this approximation.

It should also be obvious, that you can’t mix “datums”, that is: place markers using one datum onto a map which adheres to a different datum.

1 Like

I’m working on a project to
visualize OpenStreetMap buildings in 3d.(GitHub user Beakerboy, project OSMBuilding).

Since building footprints are so small, I convert to Cartesian-ish coordinates by first calculating the center of my object, the “home point” which the the halfway point between the object extents, min and max lat and long.

Then I rotate the object to place the home on the prime meridian. Finally I rotate to place the home at 0,0.


  /**
   * Rotate lat/lon to reposition the home point onto 0,0.
   * @param {array} latLong - [long, lat]
   * @param {array} home - [long, lat] of the point which will end up at [0, 0]
   * @return [x, y] Cartesian-ish coordinates in meters.
   */
  static repositionPoint(latLon, home) {
    const R = 6371 * 1000;   // Earth radius in m
    const circ = 2 * Math.PI * R;  // Circumference
    const phi = 90 - latLon[1];
    const theta = latLon[0] - home[0];
    const thetaPrime = home[1] / 180 * Math.PI;
    const x = R * Math.sin(theta / 180 * Math.PI) * Math.sin(phi / 180 * Math.PI);
    const y = R * Math.cos(phi / 180 * Math.PI);
    const z = R * Math.sin(phi / 180 * Math.PI) * Math.cos(theta / 180 * Math.PI);
    const abs = Math.sqrt(z**2 + y**2);
    const arg = Math.atan(y / z) - thetaPrime;

    return [x, Math.sin(arg) * abs];
  }

I’m certain there are unhandled edge conditions if the object traverses the international date line or surrounds one of the poles.

To my knowledge, there aren’t any buildings covering the very poles. So I wouldn’t worry too much about this remote possibility.

SCNR :innocent:

1 Like

My children would like to have a word with you. :santa:

2 Likes