Lays out the assembly drawing (view scale, positions on the sheet, bill of materials masses) and writes the placed assembly as one mesh for STL or as a 3MF file.
How the precision is kept
Sheet coordinates are 64-bit. The mesh exports start from each part's Float32Array positions; the STL mesh is transformed in 64-bit and stored back in a Float32Array. The 3MF writer prints every number, including each instance's placement matrix, with 9 significant digits.
Open item. Write the 3MF item transform with 17 significant digits; only the vertex coordinates are limited to 32-bit by their source.
Calculations under this policy
5 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.
asm-drawing.jsPartCraft 0.8.1 32-bit in part5 calculationsReviewed
Picks the drawing scale and maps view coordinates to sheet millimeters.
scale = first s with w × s ≤ 0.78 × frame width and h × s ≤ 0.78 × frame height; sheet = origin + (u − u₀) × scale
The scale is one of the fixed values in drawing.js (10 down to 1/1000); when none fits, the smallest is used even though the view then overflows the frame. The mapping subtracts the view's minimum before scaling, in 64-bit.
Moves every part's mesh to its place in the assembly and joins them, for STL export and the 3D-printing check.
p′ = M × p for each vertex
Reads each vertex from the part mesh's Float32Array, applies the 64-bit placement matrix, and stores the result in a new Float32Array. A coordinate far from the origin keeps about 7 significant digits.
asm-drawing.js
lines 132 to 144
PartCraft 0.8.1
/** items: [{ mesh, matrix }] → { positions, indices } in world coordinates. */
export function assemblyMesh(items) {
let nv = 0, ni = 0;
for (const it of items) { nv += it.mesh.positions.length; ni += it.mesh.indices.length; }
const positions = new Float32Array(nv), indices = new Uint32Array(ni);
let pv = 0, pi = 0;
for (const it of items) {
const P = it.mesh.positions, base = pv / 3;
for (let i = 0; i < P.length; i += 3) { const q = V.applyMat(it.matrix, [P[i], P[i + 1], P[i + 2]]); positions[pv++] = q[0]; positions[pv++] = q[1]; positions[pv++] = q[2]; }
for (const k of it.mesh.indices) indices[pi++] = base + k;
}
return { positions, indices };
}
Numbers written to 3MF
64-bit
Turns a coordinate or a matrix entry into the text stored in the 3MF file.
text = toPrecision(9) of v; |v| < 1e-12 → 0
Every number is rounded to 9 significant digits. That is enough to round-trip a 32-bit vertex coordinate, but it also rounds the 64-bit placement matrix. Values smaller than 1e-12 in absolute size are written as 0.
asm-drawing.js
line 147
PartCraft 0.8.1
const num = (v) => { const r = Math.abs(v) < 1e-12 ? 0 : v; return Number(r.toPrecision(9)).toString(); };
Instance placement in 3MF
64-bit
Converts each instance's placement from Y-up to Z-up and writes it as the item transform.
T = Y_TO_Z × M × Z_TO_Y; 12 entries written row by row
The axis-swap matrices hold only 0, 1 and −1, so the two products add no rounding beyond sign changes. The 12 entries then pass through the 9-digit text conversion.
asm-drawing.js
lines 171 to 174
PartCraft 0.8.1
// Z-up placement: Y_TO_Z · M · Z_TO_Y; 3MF writes the 3×4 as m00 m01 m02 m10 … m30 m31 m32 (row vectors)
const m = V.matMul(Y_TO_Z, V.matMul(it.matrix, Z_TO_Y));
const t = [m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10], m[12], m[13], m[14]].map(num).join(' ');
out.push(` <item objectid="${ids.get(it.pid)}" transform="${t}"/>\n`);
In detail
Method
The view scale is the first of the fixed scales in drawing.js at which the view fits in 78 % of the frame. 3MF placement is Y_TO_Z × M × Z_TO_Y written as a 3 × 4 transform.
Number types
64-bit numbers for the sheet; Float32Array for mesh positions in and out; decimal text with 9 significant digits in the 3MF file.
Tolerances
In the 3MF text a value with absolute size below 1e-12 is written as 0.
Limits
STL coordinates are 32-bit. The 3MF placement transform is rounded to 9 significant digits although the placement itself is 64-bit.
Approach: 32-bit step, flagged
One step stores or exchanges 32-bit values that reach a number a person reads. It is listed here with its open item, and the step is either moved to 64-bit or the app will warn where the number is read.