Docs

Draw a place from a map

Turn building footprints, roads and zones into Scene Objects with the plan geometry kinds.

A twin of a real place starts from a map: building footprints, road centre lines, the outline of a zone. Three geometry kinds take them as they are.

KindWhat you haveWhat it draws
extrusionA footprint and a heightA building block
polygonAn outlineA flat area: a square, a zone, water
polylineA centre line and a widthA road, a pipe, a route

Their points are [east, north] pairs in metres around the object's position. The object is still one position on Earth; the shape is drawn around it. A footprint may run clockwise or counter clockwise and may repeat its first point at the end, as GeoJSON rings do.

plan-geometry.ts
import { createScene, type PlanPoint } from "@klorad/api/world";

const scene = createScene({ coordinateSystem: { origin: { lat: 40.62637, lon: 22.94838 } } });
const cs = scene.coordinateSystem;

/** A ring of [longitude, latitude] pairs, as GeoJSON gives it, in metres around a position. */
function around(position: { lat: number; lon: number }, ring: [number, number][]): PlanPoint[] {
  const centre = cs.toLocal({ ...position, height: 0 });
  return ring.map(([lon, lat]) => {
    const point = cs.toLocal({ lat, lon, height: 0 });
    return [point.east - centre.east, point.north - centre.north];
  });
}

// A building: its footprint from a map, raised to its height.
const footprint: [number, number][] = [[22.9482, 40.6266], [22.9486, 40.6266], [22.9486, 40.62685], [22.9482, 40.62685], [22.9482, 40.6266]];
const hall = { lat: 40.62672, lon: 22.9484 };
scene.add({ name: "Hall", position: hall, geometry: { kind: "extrusion", footprint: around(hall, footprint), height: 9 } });

// An area and a line, laid out by hand in metres east and north of their position.
scene.add({ name: "Forecourt", position: { east: 0, north: 0 }, geometry: { kind: "polygon", footprint: [[-30, -20], [30, -20], [30, 10], [-30, 10]] } });
scene.add({ name: "Access road", position: { east: 0, north: -40 }, geometry: { kind: "polyline", path: [[-60, 0], [0, 0], [40, 25]], width: 7 } });

export { scene };

From latitude and longitude

Map data comes in degrees. The scene's coordinate system converts it: toLocal gives metres from the scene's origin, and subtracting the object's own position gives metres around the object. The around function above does exactly that.

A whole town

Nothing more is needed for a town than a loop: one extrusion per building. The Space sandbox draws Thessaloniki's waterfront this way, with the sea, a park and a square as areas, its main streets as lines and the landmarks as glTF models; its Code tab shows the file.

What it does not do

A footprint has no holes, so a building with a courtyard is drawn as its outer ring. Lines are straight between their points.

Run it liveSandbox: SpaceThessaloniki's waterfront, where every point of the scene is a real place on Earth.

Something wrong or unclear? Tell us.