Resources Numerical accuracy Calculation policy

Site surroundings in local meters

Converts the buildings, parcels and zones found around an address from longitude and latitude to meters east and north of the address point, as suggestions a person can add to the model.

How the precision is kept

The conversion is a flat approximation: 111,320 m per degree of latitude, and that times the cosine of the origin's latitude per degree of longitude. The file's own header says it is good to a few meters within a few kilometers. Outlines are rounded to 0.01 m when the file is built, and a building with only a number of levels is given 3 m per level.

Calculations under this policy

4 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.

site-context.js BimCraft 0.8.1 64-bit 4 calculations Reviewed

Tests tools/bimcraft-test/site-ctx-test.mjs, bin/test-site-context.mjs

Longitude and latitude to local meters

64-bit

The position of a point in meters east and north of the address point.

x = (lon − lon₀) × 111320 × cos(lat₀); y = (lat − lat₀) × 111320

The constant 111320 m per degree is used for both directions and the cosine is taken at the origin's latitude only. The method, not the arithmetic, sets the accuracy: the header states a few meters within a few kilometers.

  • site-context.js
  • line 30
  • BimCraft 0.8.1
export const toLocal = (o, lon, lat) => [(lon - o.lon) * M_PER_DEG * Math.cos((o.lat * Math.PI) / 180), (lat - o.lat) * M_PER_DEG];

Local meters back to longitude and latitude

64-bit

The longitude and latitude of a local point.

lon = lon₀ + x ÷ (111320 × cos(lat₀)); lat = lat₀ + y ÷ 111320

The exact inverse of toLocal's formula. The division by cos(lat₀) is not guarded for an origin at a pole.

  • site-context.js
  • line 31
  • BimCraft 0.8.1
export const fromLocal = (o, x, y) => [o.lon + x / (M_PER_DEG * Math.cos((o.lat * Math.PI) / 180)), o.lat + y / M_PER_DEG];

Outlines and heights kept in the site file

64-bit

Converts each outline to local meters, thins and rounds it, and sets the item's height.

ring = round(x × 100) ÷ 100, round(y × 100) ÷ 100; height = source height, else levels × 3

Outline coordinates are rounded to 0.01 m before they are stored. A height is taken from the source when it is between 0 and 2000 m; otherwise the number of levels times 3 m, marked as from levels.

  • site-context.js
  • lines 46 to 52
  • BimCraft 0.8.1
const local = thin(clean(ring.map((p) => toLocal(origin, p[0], p[1]))));
if (local.length < 3) continue;
if (!local.some((p) => Math.hypot(p[0], p[1]) <= radius * 1.5)) continue;   // nowhere near the point
if (out.length >= MAX_ITEMS) break;
const h = fin(it.height) && it.height > 0 && it.height < 2000 ? it.height : null, lv = fin(it.levels) && it.levels > 0 && it.levels < 300 ? it.levels : null;
out.push({ id: it.kind[0] + (++n), kind: it.kind, name: S(it.name, 80), ring: local.map((p) => [Math.round(p[0] * 100) / 100, Math.round(p[1] * 100) / 100]),
  height: h !== null ? h : lv !== null ? lv * LEVEL_HEIGHT : null, heightFrom: h !== null ? 'source' : lv !== null ? 'levels' : null, label: S(it.label, 120) });

Thinning a long outline

64-bit

Reduces an outline of more than 400 points by keeping every n-th point.

step = ⌈points ÷ 400⌉; keep indexes divisible by step

The kept points are unchanged; the dropped ones are chosen by index, not by how much shape they carry, so corners can be cut.

  • site-context.js
  • lines 33 to 37
  • BimCraft 0.8.1
function thin(ring) {
  if (ring.length <= MAX_RING) return ring;
  const step = Math.ceil(ring.length / MAX_RING);
  return ring.filter((_, i) => i % step === 0);
}

In detail

Method
Equirectangular: x = Δlon × 111320 × cos(lat₀), y = Δlat × 111320.
Number types
64-bit numbers. 111320 is a rounded constant, not an ellipsoid formula.
Tolerances
Outlines are kept when any point is within 1.5 times the radius. Outline coordinates beyond 1e6 m are dropped when a file is read.
Limits
Outlines of more than 400 points keep every n-th point. Heights from a level count are an assumption of 3 m per level, and a building with no height is proposed at 6 m.

Approach: 64-bit, stated limit

The arithmetic is 64-bit, but the method or the data sets the accuracy: a solver tolerance, a mesh, a step size, a datum shift, a table. The limit is stated where the result is shown.

Every policy that takes this approach