Resources Numerical accuracy Calculation policy

USD export of a part or assembly

Writes the part's mesh, its placement in an assembly, and its volume and mass to an OpenUSD file in meters with Z up.

How the precision is kept

Mesh points are divided by 1000 and written as point3f[], the 32-bit point type of a USD mesh, so they carry about 7 significant digits in meters. Placement matrices, volume, mass and density are written as 64-bit values.

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.

usd-partcraft.js PartCraft 0.8.1 64-bit 3 calculations Reviewed

Tests tools/usd/test-apps.mjs

Mesh points in meters, Z up

64-bit

Converts the part's mesh vertices for the USD file.

(x, y, z) mm → (x, −z, y) ÷ 1000 m

Each coordinate is divided by 1000 in 64-bit and stored in a Float32Array, because the mesh is written as point3f[]. That 32-bit store is the file format's point type. A point 10 m from the origin keeps a resolution of about 1 µm.

  • usd-partcraft.js
  • lines 30 to 36
  • PartCraft 0.8.1
function body(b, prim, mesh, mat) {
  const P = mesh.positions, n = P.length / 3;
  const pts = new Float32Array(P.length);
  for (let i = 0; i < n; i++) { pts[i * 3] = P[i * 3] / 1000; pts[i * 3 + 1] = -P[i * 3 + 2] / 1000; pts[i * 3 + 2] = P[i * 3 + 1] / 1000; }
  const nt = mesh.indices.length / 3;
  b.mesh(prim, 'Body', { points: pts, counts: new Int32Array(nt).fill(3), indices: Int32Array.from(mesh.indices) }, { material: mat });
}

Instance placement

64-bit

Turns an assembly instance's placement matrix from millimeters, Y up, to meters, Z up.

M′ = A · M · A⁻¹; translation ÷ 1000

A and its inverse hold only 0, 1 and −1, so the two products move and negate entries without rounding. Only the three translation entries are divided by 1000. The matrix is passed on as 64-bit numbers.

  • usd-partcraft.js
  • lines 26 to 27
  • PartCraft 0.8.1
/** A placement (mm, Y up) → metres, Z up: A·M·A⁻¹ with the translation in metres. */
function place(M) { const m = mmul(A, mmul(M, AI)); m[12] /= 1000; m[13] /= 1000; m[14] /= 1000; return m; }

Volume and mass attributes

64-bit

The volume in cubic meters and the mass in kilograms written on each part.

volume m³ = V mm³ × 10⁻⁹; mass kg = V mm³ × ρ g/cm³ × 10⁻⁶

Both are 64-bit products written as double attributes. The volume itself comes from the build's statistics. Mass is written only when the part has a material with a finite density.

  • usd-partcraft.js
  • lines 37 to 48
  • PartCraft 0.8.1
function partData(b, prim, part, stats) {
  const S = (n, v) => { if (v !== null && v !== undefined && v !== '') b.attr(prim, n, 'string', String(v), { custom: true, uniform: true }); };
  S('cadcraft:partNumber', part.number || part.drawing?.title?.number || null);
  if (part.material) {
    S('cadcraft:material', part.material.name);
    if (Number.isFinite(part.material.density)) b.attr(prim, 'cadcraft:density', 'double', part.material.density, { custom: true, uniform: true, meta: unit('g/cm3') });
  }
  if (stats && Number.isFinite(stats.volume)) {
    b.attr(prim, 'cadcraft:volume', 'double', stats.volume * 1e-9, { custom: true, uniform: true, meta: unit('m3') });
    if (part.material && Number.isFinite(part.material.density)) b.attr(prim, 'cadcraft:mass', 'double', stats.volume * part.material.density * 1e-6, { custom: true, uniform: true, meta: unit('kg') });
  }
}

In detail

Method
Axis change (x, y, z) → (x, −z, y) and millimeters to meters; placements as A · M · A⁻¹ with the translation divided by 1000.
Number types
Float32Array for mesh points (point3f[]); 64-bit numbers for matrices and the custom attributes.
Limits
Mesh points are 32-bit in the file. The factors 1e-9 and 1e-6 are not exact in binary, so each product with them is rounded once.

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