Turns a picked flat face, a click on a drawing view or a new section into the plane, point or offset that is saved in the part or assembly.
How the precision is kept
partcraft.js is the page controller; its own arithmetic is small. Where it stores a value taken from a pick it rounds it with toFixed first: a fixed plane's origin to 9 decimals and its normal to 12, a drawing anchor and a section offset to 4 decimals. The rounding is of the value that is kept in the file, not only of what is shown.
Calculations under this policy
4 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 plane reference stored when a sketch is put on a picked flat face that has no stable name.
o = each coordinate rounded to 9 decimals; n = each component rounded to 12 decimals
A named face is stored by its name and follows the feature. A face without a name is stored as a fixed plane whose origin and normal pass through toFixed(9) and toFixed(12), so the saved plane is the rounded one.
The plane stored in an assembly mate when a flat face of a placed part is picked.
o rounded to 9 decimals, n to 12 decimals, when the face has no stable name
The same rounding as for a sketch plane: toFixed(9) on the origin and toFixed(12) on the normal before the mate is saved. On a build without a face table the face counts as flat when no neighboring facet group is within 20° of it, and its plane comes from faceRefAt or is stored with the picked point and normal as they are.
partcraft.js
lines 2217 to 2239
PartCraft 0.8.1
/** A flat face picked on an instance → its mate plane in the part (stable when the face was made by a sketch edge). */
function mateFromHit(h) {
const inst = instById(h.inst), build = asmBuilds.get(inst.part);
if ((build?.exact || build?.named) && h.face !== undefined) {
const f = build.faces[h.face];
if (!f || f.type !== 'plane') return null;
return { inst: h.inst, plane: f.name ? refForName(f.name) : { kind: 'fixed', o: f.o.map((v) => +v.toFixed(9)), n: f.n.map((v) => +v.toFixed(12)) } };
}
const grp = view.instances.find((o) => o.id === h.inst).groups;
const g = grp.groups[h.group];
const I = h.data.indices;
const key = (a, b) => (a < b ? a + ',' + b : b + ',' + a);
const inG = new Set(g.tris);
const edgeTri = new Map();
for (let t = 0; t < I.length / 3; t++) for (let k = 0; k < 3; k++) { const kk = key(I[t * 3 + k], I[t * 3 + (k + 1) % 3]); if (!edgeTri.has(kk)) edgeTri.set(kk, []); edgeTri.get(kk).push(t); }
let flat = true;
for (const t of g.tris) for (let k = 0; k < 3 && flat; k++) for (const o of edgeTri.get(key(I[t * 3 + k], I[t * 3 + (k + 1) % 3])) || []) {
if (!inG.has(o) && V.dot(grp.groups[grp.faceOf[o]].n, g.n) > Math.cos(20 * Math.PI / 180)) flat = false;
}
if (!flat) return null;
const plane = h.feature ? faceRefAt(build, h.feature, g.n, h.point) : { kind: 'fixed', o: h.point, n: g.n };
return { inst: h.inst, plane };
}
Anchor point on a drawing view
64-bit
The point in a view's own coordinates where a note, dimension or detail view is attached.
u = u₀ + (x − x_view) ÷ scale, snapped to the nearest drawn line within 2.5 ÷ scale, then rounded to 4 decimals
The click is converted from sheet to view coordinates by one subtraction and one division, snapped to the closest point of a visible line when one is near, and stored after toFixed(4).
partcraft.js
lines 2696 to 2717
PartCraft 0.8.1
/** Which view a sheet point is on, and its view coordinates (snapped to the nearest drawn line within 2.5 mm). */
function viewAt(x, y) {
const sh = drawingState.sheet;
for (const [k, p] of Object.entries(sh.place)) {
const w = (p.box.u1 - p.box.u0) * p.s, h = (p.box.v1 - p.box.v0) * p.s;
if (x < p.x - 3 || x > p.x + w + 3 || y < p.y - 3 || y > p.y + h + 3) continue;
let u = p.box.u0 + (x - p.x) / p.s, v = p.box.v0 + (y - p.y) / p.s;
const src = k === 'detail' ? null : drawingState.data.views[k];
if (src) {
let best = 2.5 / p.s, at = null;
for (const g of [...src.visible, ...(src.cut || [])]) {
const dx = g[2] - g[0], dy = g[3] - g[1], L = dx * dx + dy * dy;
const t = L > 0 ? Math.max(0, Math.min(1, ((u - g[0]) * dx + (v - g[1]) * dy) / L)) : 0;
const qx = g[0] + dx * t, qy = g[1] + dy * t, dd = Math.hypot(u - qx, v - qy);
if (dd < best) { best = dd; at = [qx, qy]; }
}
if (at) [u, v] = at;
}
return { view: k, at: [+u.toFixed(4), +v.toFixed(4)] };
}
return null;
}
Default section plane offset
64-bit
The offset of a new section view's cutting plane: the middle of the part's bounding box along the view direction.
offset = dir · (min + max) ÷ 2, rounded to 4 decimals
The bounding box is the kernel's 64-bit statistic; the offset that is stored passes through toFixed(4).
partcraft.js
lines 2860 to 2864
PartCraft 0.8.1
function sectionCentre(of) {
const b = regen?.stats?.bbox; if (!b) return 0;
const dir = { front: [0, 0, 1], top: [0, 1, 0], right: [1, 0, 0] }[of];
return +V.dot(dir, b.min.map((v, i) => (v + b.max[i]) / 2)).toFixed(4);
}
In detail
Method
Values copied from the face table or computed by one projection, then rounded with toFixed before they are stored.
Number types
64-bit numbers, rounded to a fixed number of decimals when stored.
Limits
A stored normal rounded to 12 decimals is no longer exactly unit length. A drawing anchor keeps 0.0001 of a model unit.
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.