Writes where the drawing sits on its map grid (design point, reference point, north direction) into the file's GEODATA object, and reads another program's back.
How the precision is kept
The design point and the grid reference point are copied as 64-bit numbers without change. The rotation is the part that is limited: the north vector is rounded to 9 decimals when written, and the rotation read back from a file is rounded to 9 decimals of a degree.
Open item. Write the north vector's sine and cosine unrounded, and keep the rotation read from a file unrounded.
Calculations under this policy
3 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.
The design point and reference point are copied unchanged. Both components of the north vector are rounded to 9 decimals (Math.round(v × 1e9) ÷ 1e9) before they are stored, so the written direction is held to about 1 × 10⁻⁹ and not to 15 digits. The projection radius is the constant 6378137.
geodwg.js
lines 178 to 193
CadCraft 0.8.2
/** The GEODATA a drawing's geo record writes (lib/dwg model fields, host left to the caller), or null (nothing to place). */
export function geodataFields(geo, units) {
const g = cleanGeo(geo);
if (!g) return null;
if (g.src && sameCrs(g.crs, g.src.crs)) return { ...g.src.fields }; // as read, while unchanged (another program's own definition)
const c = g.crs;
if (!c || c.place.e === undefined) return null;
const rot = (c.place.rot * Math.PI) / 180;
const u = GEO_UNIT[units] || GEO_UNIT[c.units] || CS_UNIT[c.unit] || 6;
return {
coordType: 2, designPoint: { x: c.place.x, y: c.place.y, z: 0 }, referencePoint: { x: c.place.e, y: c.place.n, z: 0 },
unitScaleH: 1, unitsH: u, unitScaleV: 1, unitsV: u, up: { x: 0, y: 0, z: 1 },
north: { x: r9(Math.sin(rot)), y: r9(Math.cos(rot)) }, scaleMethod: 1, userScale: 1, seaLevel: false, seaElevation: 0, projRadius: 6378137,
csDef: csXml(c.code, c.unit || 'm'), geoRss: '', obsFrom: '', obsTo: '', obsCoverage: '', meshPoints: [], meshFaces: [],
};
}
Location from another program's GEODATA
64-bit
Turns a file's GEODATA into the drawing's coordinate system, placement point and rotation.
rot = round₉(atan2(north.x, north.y) × 180 ÷ π)
The rotation in degrees is rounded to 9 decimals before it is kept. The scale and up-vector tests use an absolute tolerance of 1e-9. Design and reference point coordinates are copied unchanged.
geodwg.js
lines 195 to 212
CadCraft 0.8.2
/**
* Another program's GEODATA → { crs, src, why }. CadCraft places the drawing when the definition names an EPSG code and the
* location is a projected grid (or latitude / longitude) at scale 1 with up = +Z; otherwise crs is null and `why` says
* which ('code' | 'kind' | 'scale'), and the fields are still kept to write back.
*/
export function fromGeodata(fields, { units = '' } = {}) {
const f = cleanFields(fields);
if (!f) return null;
const why = !epsgOf(f.csDef) ? 'code' : (f.coordType !== 2 && f.coordType !== 3) || Math.abs(f.up.z - 1) > 1e-9 ? 'kind' : Math.abs(f.unitScaleH - 1) > 1e-9 ? 'scale' : '';
let crs = null;
if (!why) {
const rot = r9((Math.atan2(f.north.x, f.north.y) * 180) / Math.PI);
const place = f.coordType === 2 ? { x: f.designPoint.x, y: f.designPoint.y, e: f.referencePoint.x, n: f.referencePoint.y, rot }
: { x: f.designPoint.x, y: f.designPoint.y, lon: f.referencePoint.x, lat: f.referencePoint.y, rot };
crs = cleanCrs({ code: epsgOf(f.csDef), name: csLabel(f.csDef), place, ...(!units && UNIT_NAME[f.unitsH] ? { units: UNIT_NAME[f.unitsH] } : {}) });
}
return { crs, src: { fields: f, crs }, why: crs ? '' : why || 'kind', label: csLabel(f.csDef) };
}
Fingerprint of the written location
64-bit
Decides whether the GEODATA in a file is still the one CadCraft wrote or another program moved the location since.
Every point and vector component is rounded to 9 decimals before the comparison, so a change of the design or reference point smaller than about 5 × 10⁻¹⁰ drawing units is not seen as a change. The definition text is compared by its length only.
geodwg.js
lines 174 to 176
CadCraft 0.8.2
const r9 = (v) => Math.round(v * 1e9) / 1e9;
/** A fingerprint of the GEODATA fields that place the drawing (to tell whether another program changed them). */
export const geoKey = (f) => JSON.stringify([f.coordType, f.designPoint, f.referencePoint, f.north, f.unitsH, f.unitScaleH].map((v) => (v && typeof v === 'object' ? Object.values(v).map(r9) : v)).concat(String(f.csDef).length));
In detail
Method
North vector = (sin rot, cos rot) with rot in radians from degrees; on reading, rot = atan2(north.x, north.y) in degrees.
Number types
64-bit numbers. DXF group values are read with parseFloat.
Tolerances
1e-9 absolute on the unit scale (|scale − 1|) and on the up vector's z (|z − 1|) to decide whether CadCraft can place the drawing. The fingerprint that detects a location changed by another program compares values rounded to 9 decimals.
Limits
Place values (x, y, rotation, easting, northing) of 1e10 or more in size are refused. A GEODATA with a unit scale other than 1 or a coordinate type other than projected grid or latitude and longitude is kept to write back but not used to place the drawing.
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.