Resources Numerical accuracy Calculation policy

Export of the 3D model to DXF and DWG

The coordinates, block placements and rotation angles written when the 3D model is exported to DXF R12 or handed to the DWG writer.

How the precision is kept

Coordinates are multiplied by one unit factor (meters to inches, millimeters, centimeters or meters) in 64-bit. DXF text is written with 15 significant digits. The DWG path passes the same numbers on as 64-bit values without formatting them.

Open item. Write DXF numbers with 17 significant digits and convert to inches by dividing by 0.0254.

Calculations under this policy

6 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.

m3d/io.js CadCraft 0.8.2 64-bit 6 calculations Reviewed

Tests None found by the review

Unit factor for DXF and DWG

64-bit

The factor that turns the model's meters into the drawing unit of the export.

inches: 1 ÷ 0.0254; mm: 1000; cm: 100; m: 1

The metric factors are whole numbers. The inch factor is computed once as 1 ÷ 0.0254, which is rounded, and coordinates are then multiplied by it: two roundings where a division by 0.0254 would make one.

  • m3d/io.js
  • line 1210
  • CadCraft 0.8.2
const CAD_UNITS = { 'ft-in': ['inches', 1 / 0.0254, 1], in: ['inches', 1 / 0.0254, 1], mm: ['millimeters', 1000, 4], cm: ['centimeters', 100, 5], m: ['meters', 1, 6] };

Exported point

64-bit

A vertex of the model in the export's unit.

p′ = (M · p) × k

The vertex is multiplied by the extra placement matrix (the identity inside a block) and then by the unit factor, component by component.

  • m3d/io.js
  • line 1264
  • CadCraft 0.8.2
const P = (v) => { const p = apply(m, def.verts.get(v)); return [p[0] * k, p[1] * k, p[2] * k]; };

Placement as a block insert

64-bit

The insertion point, scale, rotation and extrusion direction that stand for a placement matrix.

scale = column lengths; n = third unit column; rot = atan2(r₀ · a_y, r₀ · a_x); insertion = (T · a_x, T · a_y, T · n)

The matrix columns are normalized by their lengths; the placement is written as an insert only when the unit columns are square to each other within 1e-9 in their dot products, otherwise it is written out as plain geometry. The rotation comes from atan2 and the insertion point is the translation, times the unit factor, projected on the insert's own axes.

  • m3d/io.js
  • lines 1233 to 1247
  • CadCraft 0.8.2
/** A placement as an INSERT: {ins (OCS), scale [x, y, z], rot (radians), n (extrusion)}, or null when it is not a turn + scale. */
export function insertOf(m, k) {
  const c = [[m[0], m[1], m[2]], [m[4], m[5], m[6]], [m[8], m[9], m[10]]];
  const s = c.map(len);
  if (s.some((x) => !(x > 1e-12))) return null;
  const r = c.map((v, i) => mul(v, 1 / s[i]));
  if (Math.abs(dot(r[0], r[1])) > 1e-9 || Math.abs(dot(r[0], r[2])) > 1e-9 || Math.abs(dot(r[1], r[2])) > 1e-9) return null;
  if (dot(cross(r[0], r[1]), r[2]) < 0) { s[2] = -s[2]; r[2] = mul(r[2], -1); }
  const n = r[2];
  // the arbitrary axis algorithm (DXF reference): the OCS of this extrusion direction
  const ax = norm(Math.abs(n[0]) < 1 / 64 && Math.abs(n[1]) < 1 / 64 ? cross([0, 1, 0], n) : cross([0, 0, 1], n));
  const ay = cross(n, ax);
  const T = [m[12] * k, m[13] * k, m[14] * k];
  return { ins: [dot(T, ax), dot(T, ay), dot(T, n)], scale: s, rot: Math.atan2(dot(r[0], ay), dot(r[0], ax)), n };
}

DXF number format

64-bit

How every coordinate, scale and angle is written in the DXF text.

text = x rounded to 15 significant digits

toPrecision(15) keeps 15 significant digits; a value below 1e-12 in size, in the drawing's unit, is written as 0.

  • m3d/io.js
  • line 1304
  • CadCraft 0.8.2
const df = (x) => { let v = +(+x).toPrecision(15); if (Object.is(v, -0) || Math.abs(v) < 1e-12) v = 0; return String(v); };

DXF insert record

64-bit

The numbers of one block placement in the DXF text.

rotation in degrees = rot × 180 ÷ π

The rotation is converted from radians to degrees in one expression and written, like the point, scale and extrusion direction, with 15 significant digits.

  • m3d/io.js
  • lines 1318 to 1320
  • CadCraft 0.8.2
w(0, 'INSERT'); w(8, '0'); w(2, e.block); w(10, df(e.ins[0])); w(20, df(e.ins[1])); w(30, df(e.ins[2]));
w(41, df(e.scale[0])); w(42, df(e.scale[1])); w(43, df(e.scale[2])); w(50, df((e.rot * 180) / Math.PI));
w(210, df(e.n[0])); w(220, df(e.n[1])); w(230, df(e.n[2]));

Numbers handed to the DWG writer

64-bit

The same faces, lines and inserts as objects for the DWG writer.

Points, scales, the rotation (in radians) and the extrusion direction are passed on as the 64-bit numbers they are; nothing is rounded here.

  • m3d/io.js
  • lines 1344 to 1346
  • CadCraft 0.8.2
const conv = (e) => (e.t === 'face' ? { type: '3DFACE', layer: '0', color: color(e.color), points: e.pts.map(P), invisibleEdges: e.inv }
  : e.t === 'line' ? { type: 'LINE', layer: '0', color: { index: 256 }, start: P(e.a), end: P(e.b) }
    : { type: 'INSERT', layer: '0', color: { index: 256 }, block: e.block, insert: P(e.ins), scale: { x: e.scale[0], y: e.scale[1], z: e.scale[2] }, rotation: e.rot, extrusion: P(e.n) });

In detail

Method
Each definition becomes a block and each placement an INSERT whose insertion point, scale, rotation and extrusion direction come from the placement matrix by the arbitrary axis algorithm (the code cites the DXF reference). A placement that is not a turn and scale is written out in place.
Number types
64-bit numbers; DXF text via toPrecision(15).
Tolerances
A placement is a turn and scale when its unit columns' dot products are within 1e-9 and no column is shorter than 1e-12. DXF: a value below 1e-12 in size is written as 0. Arbitrary axis switch at 1/64, as the format defines.
Limits
15 significant digits are written, not the 17 needed to read back the same 64-bit value. The inch factor is the rounded value of 1 ÷ 0.0254.

Approach: 64-bit, direct

Every value is a 64-bit number from input to result. Formulas are closed form or a direct solve, and every comparison uses a stated tolerance.

Every policy that takes this approach