Resources Numerical accuracy Calculation policy

Values stored from picks in the workspace

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.

partcraft.js PartCraft 0.8.1 64-bit 4 calculations Reviewed

Tests None found by the review

Sketch plane from a picked flat face

64-bit

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.

  • partcraft.js
  • lines 603 to 606
  • PartCraft 0.8.1
  ref = flat ? (f?.name ? refForName(f.name) : { kind: 'fixed', o: f.o.map((v) => +v.toFixed(9)), n: f.n.map((v) => +v.toFixed(12)) }) : null;
  if (flat && f) h = { ...h, normal: f.n };
} else ref = flat && h.feature ? faceRefAt(regen, h.feature, h.normal, h.point) : flat ? { kind: 'fixed', o: h.point, n: h.normal } : null;
pick = { kind: 'face', ...h, flat, ref, info: named() && h.face !== undefined ? regen.faces[h.face] : null };

Mate plane from a picked face of an instance

64-bit

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.

Every policy that takes this approach