Working with geographic data
Quick answer
This tutorial confronts the fact that three.js has no concept of longitude or latitude. It compares a spherical globe, a local planar offset and tile streaming, then implements lonLatToVector3 and a toLocalMeters helper that subtracts an origin and rescales metres. It converts GeoJSON longitude and latitude pairs into BufferGeometry lines and discusses DEM terrain, vertical exaggeration and Float32 precision limits. Readers can place real survey data in a scene at a chosen scale.
Key points
- Map longitude and latitude onto a sphere with altitude and radius in the same unit.
- Subtract a local origin and scale metres before writing any vertex positions.
- Read GeoJSON as longitude then latitude, and map north to negative Z.
Example
function lonLatToVector3(lon, lat, altitude, radius) {
const phi = (90 - lat) * Math.PI / 180; // 极角
const theta = (lon + 180) * Math.PI / 180; // 方位角
const r = radius + altitude; // altitude 与 radius 同单位
return new THREE.Vector3(
-r * Math.sin(phi) * Math.cos(theta),
r * Math.cos(phi),
r * Math.sin(phi) * Math.sin(theta)
);
}
const beijing = lonLatToVector3(116.39, 39.91, 0.02, 1.0);const ORIGIN = { lon: 116.391, lat: 39.907 };
function toLocalMeters(lon, lat, height) {
const dx = (lon - ORIGIN.lon) * Math.cos(ORIGIN.lat * Math.PI / 180) * 111320;
const dz = (lat - ORIGIN.lat) * 110540;
return {
east: dx,
north: dz,
up: height
};
}
const SCALE = 100;
const p = toLocalMeters(116.404, 39.915, 12);
const v = new THREE.Vector3(p.east / SCALE, p.up / SCALE, -p.north / SCALE);
Notes
- Float32 resolves only about 0.5 metres at Earth radius, so absolute coordinates jitter.
- Degree-to-metre approximations drift badly beyond a few tens of kilometres.
English edition written for Atlaslog. Code is taken from the original Chinese page and runs unchanged.
Atlaslog (2026). Working with geographic data. https://www.jingweizhi.com/en/three/tutorials/geo-data.html (accessed 2026-11-03).