Moves points, and a model's position on the map, between coordinate systems.
How the precision is kept
Coordinates travel as 64-bit arrays through proj4 2.22.0. The limit is the datum shift, not the arithmetic: without a loaded shift grid the result is approximate to the accuracy EPSG states for that shift, and the app raises a warning that says so. A map origin is rounded to 6 decimal places of the map unit.
Calculations under this policy
3 calculations in 2 source files. 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.
Eastings and northings of a typed latitude and longitude.
(lon, lat) → (E, N), rounded to 0.000001 of the map unit
The rounding is one micrometer when the map unit is the meter: far below any survey accuracy, and it keeps the saved origin a short, stable number.
crs-georef.js
lines 111 to 119
BimCraft 0.8.1
/** Eastings / northings (in the system's unit) of a latitude and longitude through the chosen system. */
export function originFromLonLat(crs, lon, lat) {
if (!crs || crs.unit === 'deg') return { error: fail('projected'), problems: [] };
if (!fin(lon) || !fin(lat) || Math.abs(lat) > 90 || Math.abs(lon) > 180) return { error: fail('latlon'), problems: [] };
let q;
try { q = gridOf(crs, lon, lat); } catch { q = null; }
if (!q || !q.every(fin)) return { error: fail('outside', { name: crs.name }), problems: [] };
return { eastings: r6(q[0]), northings: r6(q[1]), problems: [...areaProblems(crs, lon, lat, 'model'), ...shiftProblems({ proj4: '+datum=WGS84', name: 'WGS 84' }, crs)] };
}
Model to map conversion
64-bit
Where a model sits on the map: origin, rotation and scale.
X axis = (cos a, sin a) rounded to 1e-12; scale = model unit ÷ map unit
The axis direction is rounded at the twelfth decimal, which turns a model 1 km long by a thousandth of a micrometer at its far end.
crs-georef.js
lines 121 to 139
BimCraft 0.8.1
/**
* The IfcMapConversion for a model placed at (eastings, northings) in `crs`'s unit, with its X axis `rotationDeg` degrees counter-clockwise from grid
* east (0 = the model's Y axis points to grid north), and `scale` (default: the model's length unit over the map's, i.e. the unit difference only).
*/
export function makeConversion({ crs, eastings, northings, height = 0, rotationDeg = 0, scale, fileUnitM = 1 }) {
if (!crs || crs.unit === 'deg') return { error: fail('projected'), problems: [] };
const unitScale = fileUnitM / (METRES_PER[crs.unit] || 1);
const s = scale === undefined || scale === null || scale === '' ? unitScale : Number(scale);
const nums6 = [eastings, northings, height, rotationDeg].map(Number);
if (!nums6.every(fin)) return { error: fail('numbers'), problems: [] };
if (!fin(s) || s <= 0 || s / unitScale > 1000 || s / unitScale < 0.001) return { error: fail('scale', { scale: s }), problems: [] };
if (Math.abs(nums6[0]) > 1e9 || Math.abs(nums6[1]) > 1e9) return { error: fail('numbers'), problems: [] };
const a = nums6[3] * D2R;
const conv = { Eastings: r6(nums6[0]), Northings: r6(nums6[1]), OrthogonalHeight: r6(nums6[2]), XAxisAbscissa: r12(Math.cos(a)), XAxisOrdinate: r12(Math.sin(a)), Scale: s };
let ll;
try { ll = lonLatOf(crs, conv.Eastings, conv.Northings); } catch { ll = null; }
if (!ll || !ll.every(fin) || Math.abs(ll[1]) > 90) return { error: fail('outside', { name: crs.name }), problems: [] };
return { conv, lonlat: ll, problems: areaProblems(crs, ll[0], ll[1], 'model') };
}
In detail
Method
Each coordinate system is a proj4 definition from the catalog. Large batches run in a background worker, or in slices that hand the page back between them.
Number types
A 64-bit array of x and y pairs. Points that do not project come back as not-a-number and are counted.
Tolerances
A map origin is rounded to 6 decimal places of the map unit. The direction of the model's X axis on the map is rounded to 12.
Checked by
The georeferencing test in the BimCraft test tools.
Limits
Grid-based datum shifts (NADCON, NTv2, OSTN15) need a loaded grid. Without one the shift is the grid-free one, approximate to the accuracy EPSG states. One run handles up to 25 million points.
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.