Resources Numerical accuracy Calculation policy

Apparel commands: piece table, marks and marker output

The Apparel add-on's commands that put numbers into the drawing or a file: the piece table, grain lines and buttonholes, automatic nesting on a marker and the marker's PDF.

How the precision is kept

The commands call the library files for the geometry and add unit factors and rounding of their own. The piece table rounds perimeters and areas to 2 decimals before they are printed or written to CSV. Marks picked in the drawing are stored at 6 decimals. Automatic nesting is run on a raster of the fabric width ÷ 750 with a time limit.

Open item. Write the piece table's CSV with the unrounded values and round only what is printed on the command line.

Calculations under this policy

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

addons/apparel/main.js CadCraft 0.8.2 64-bit 11 calculations Reviewed

Tests None found by the review

Picked point into the piece's frame

64-bit

A point picked in the drawing as a point in the piece's own coordinates.

local = (insert matrix)⁻¹ · p

The matrix and its inverse come from geom.js. When the matrix has no inverse the point is used unchanged.

  • addons/apparel/main.js
  • line 66
  • CadCraft 0.8.2
const toLocal = (doc, e, p) => { const inv = mInverse(insertMatrix(e, doc.blocks.get(e.block) || { base: { x: 0, y: 0 } })); return inv ? mApply(inv, p) : { x: p.x, y: p.y }; };

Piece table

64-bit

Sew and cut perimeter and area of every piece in every size, as printed and as exported to CSV.

perimeter → toFixed(2); area ÷ k → toFixed(2), k = 100 for mm² to cm², 1 for in²

The values are rounded to 2 decimals in this function, before both the command line and the CSV export, so the exported file carries the rounded numbers. 100 mm² per cm² is exact.

  • addons/apparel/main.js
  • lines 502 to 515
  • CadCraft 0.8.2
/** Every piece (or the selected ones) × its sizes. */
function tableRows(doc, only = null) {
  const rows = [];
  let u = 'mm';
  for (const e of doc.all()) {
    if (!isPiece(e) || (only && !only.has(e.id))) continue;
    const d = api.objects.dataOf(e);
    if (!d) continue;
    u = d.u;
    const k = d.u === 'in' ? 1 : 100;   // mm² → cm²
    for (const r of pieceRows(d)) rows.push({ style: d.style, piece: d.name, size: r.size, qty: d.qty ?? 1, sewPerimeter: +r.sewPerimeter.toFixed(2), cutPerimeter: +r.cutPerimeter.toFixed(2), sewArea: +(r.sewArea / k).toFixed(2), cutArea: +(r.cutArea / k).toFixed(2) });
  }
  return { rows, u };
}

Default grain line

64-bit

The grain line a new piece gets: through its centroid, up the page.

h = 0.3 × (maxY − minY); a = (cₓ, cᵧ − h); b = (cₓ, cᵧ + h); each → toFixed(6)

The centroid and box are those of the sampled outline. The two end points are rounded to 6 decimals when stored.

  • addons/apparel/main.js
  • lines 122 to 127
  • CadCraft 0.8.2
/** A grain line through the middle of the piece, up the page, 60 % of its height. */
function autoGrain(data, style = 'both') {
  const { path } = sampled(ptsOf(data.pts), true);
  const b = bounds(path), m = centroid(path), h = (b.maxY - b.minY) * 0.3;
  return { a: [+m.x.toFixed(6), +(m.y - h).toFixed(6)], b: [+m.x.toFixed(6), +(m.y + h).toFixed(6)], s: ARROWS.includes(style) ? style : 'both' };
}

Buttonhole from two picked points

64-bit

The center, length and angle stored for a buttonhole.

center = (q + b) ÷ 2; L = |b − q|; angle = atan2(Δy, Δx) × 180 ÷ π

Center and length are rounded to 6 decimals and the angle to 4 decimals of a degree before they are stored. A length below 1e-9 is refused.

  • addons/apparel/main.js
  • lines 238 to 241
  • CadCraft 0.8.2
const lb = toLocal(cc.doc, e, b);
const L = Math.hypot(lb.x - q.x, lb.y - q.y);
if (L < 1e-9) return null;
return [+((q.x + lb.x) / 2).toFixed(6), +((q.y + lb.y) / 2).toFixed(6), +L.toFixed(6), +((Math.atan2(lb.y - q.y, lb.x - q.x) * 180) / Math.PI).toFixed(4)];

Do the notches of two seams match

64-bit

The line printed for each notch pair when two edges are walked along each other.

match when |offset| < 0.5 × (1 mm or 0.0625 in)

The offset comes from measure.js; here it is only compared with a fixed limit of 0.5 mm or 1/32 in and printed.

  • addons/apparel/main.js
  • line 472
  • CadCraft 0.8.2
w.pairs.forEach((p, k) => c.print('  ' + t(Math.abs(p.off) < 0.5 * (u === 'in' ? 0.0625 : 1) ? 'done.walk.notch.ok' : 'done.walk.notch', { n: k + 1, a: fmtLen(p.a, u), off: (p.off >= 0 ? '+' : '') + fmtLen(p.off, u) })));

Tile overlap typed in inches

Exact

The overlap between printed tiles, in millimeters.

overlap = typed value × 25.4 in inch drawings

25.4 is the exact number of millimeters in an inch. The default is 10 mm, or 0.5 in in inch drawings.

  • addons/apparel/main.js
  • lines 572 to 573
  • CadCraft 0.8.2
const o = await c.distance(t('ask.print.overlap'), { default: u === 'in' ? 0.5 : 10 });
if (Number(o) >= 0) overlap = Number(o) * (u === 'in' ? 25.4 : 1);

Drawing point into the marker's frame

64-bit

A drawing point as a point measured from the fabric's lower-left corner, along and across the fabric.

x′ = cos(−rot)·(x − mₓ) − sin(−rot)·(y − mᵧ); y′ = sin(−rot)·(x − mₓ) + cos(−rot)·(y − mᵧ)

The marker's position is subtracted first and the difference is turned, so a marker far from the drawing origin does not cost digits in the turned values.

  • addons/apparel/main.js
  • line 741
  • CadCraft 0.8.2
const toMarker = (mIns) => { const c = Math.cos(-(mIns.rot || 0)), s2 = Math.sin(-(mIns.rot || 0)); return (p) => ({ x: c * (p.x - mIns.x) - s2 * (p.y - mIns.y), y: s2 * (p.x - mIns.x) + c * (p.y - mIns.y) }); };

Marker numbers after a change

64-bit

The length, used area, efficiency and piece count kept with a marker after every change to the drawing.

Only pieces that lie wholly on the fabric are counted. The numbers come from stats in marker.js and are stored with the marker when any of them changed.

  • addons/apparel/main.js
  • lines 788 to 789
  • CadCraft 0.8.2
const st2 = stats(m, on);
const next = { ...m, ...st2, total: Math.max(all.length, on.length) };

Automatic nesting on a marker

64-bit

Lays the marker's pieces on the fabric and writes their new positions to the drawing.

raster cell = width ÷ 750; time limit 3000 ms; x = mₓ + cos(rot)·pₓ − sin(rot)·pᵧ; y = mᵧ + sin(rot)·pₓ + cos(rot)·pᵧ; rotation = marker rotation + piece rotation

The nesting engine (lib/nest/nest.js, not part of this review) is called with a raster cell of the fabric width ÷ 750 and a time limit of 3000 ms. The positions it returns are turned into the drawing with one 64-bit expression per coordinate and stored unrounded.

  • addons/apparel/main.js
  • lines 888 to 894
  • CadCraft 0.8.2
const r = nest(parts, { h: m.w, obstacles }, { spacing: Number(gap), grainTol: m.tol || 0, step: 0, res: m.w / 750, timeLimit: 3000 });
const cr = Math.cos(mk.rot || 0), sr = Math.sin(mk.rot || 0);
doc.change('MARKERNEST', () => {
  for (const pl of r.placed) {
    const x = doc.get(pl.id);
    if (!x) continue;
    doc.update(x.id, { ...x, rot: (mk.rot || 0) + pl.rot, sx: pl.mirror ? -1 : 1, sy: 1, x: mk.x + cr * pl.x - sr * pl.y, y: mk.y + sr * pl.x + cr * pl.y });

Marker PDF page

64-bit

The size of the marker's PDF page and the placement of the fabric on it at 1:1.

k = 25.4 (inch) or 1; W = (x₁ − x₀)·k + 20; H = (y₁ − y₀)·k + 20 + pad; matrix = [k, 0, 0, k, 10 − x₀·k, 10 + pad − y₀·k]

Page units are millimeters and the scale is k itself. The pad is 40 mm, or 1.5 in × 25.4 = 38.1 mm.

  • addons/apparel/main.js
  • lines 951 to 966
  • CadCraft 0.8.2
/** The marker at 1:1 on one page: the fabric, the pieces on it, the numbers. */
async function markerPdf(doc, mk, items, fabric, m) {
  const k = m.u === 'in' ? 25.4 : 1;
  const pd = new Doc();
  const ents = [];
  pd.blocks.set('*M', { name: '*M', base: { x: 0, y: 0 }, entities: drawMarker(m, t).map(strip) });
  ents.push({ type: 'insert', block: '*M', x: mk.x, y: mk.y, rot: mk.rot || 0, sx: 1, sy: 1, layer: '0', id: 1 });
  items.forEach((it, i) => { const name = '*P' + i; pd.blocks.set(name, { name, base: { x: 0, y: 0 }, entities: drawPlaced(it.p, t).map(strip) }); ents.push({ type: 'insert', block: name, x: it.e.x, y: it.e.y, rot: it.e.rot || 0, sx: it.e.sx ?? 1, sy: it.e.sy ?? 1, layer: '0', id: i + 2 }); });
  let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
  for (const q of fabric) { x0 = Math.min(x0, q.x); y0 = Math.min(y0, q.y); x1 = Math.max(x1, q.x); y1 = Math.max(y1, q.y); }
  const margin = 10, pad = (m.u === 'in' ? 1.5 : 40) * k;
  const W = (x1 - x0) * k + 2 * margin, H = (y1 - y0) * k + 2 * margin + pad;
  const list = displayList(pd, { w: W, h: H, name: m.name, views: [{ clip: null, m: [k, 0, 0, k, margin - x0 * k, margin + pad - y0 * k], entities: ents }] }, { mono: true });
  const r = await toPdfPages([list], { title: m.name, names: [m.name], pen: 0.35 });
  return r.bytes;
}

A measured length as text

64-bit

The text of a seam length or walk difference on the command line.

mm: 1 decimal, 0 below 0.05; inches: fractions to 1/16

Display rounding only: the measured value is not changed. A length is therefore shown no finer than 0.1 mm or 1/16 in.

  • addons/apparel/main.js
  • lines 1162 to 1163
  • CadCraft 0.8.2
/** A measured length: millimetres to one decimal, inches in fractions to 1/16 (CadCraft's units.js). */
export function fmtLen(v, u) { return u === 'in' ? formatLength(v, { lunits: 5, prec: 4 }) + ' in' : (Math.abs(v) < 0.05 ? '0' : Number(v).toFixed(1)) + ' mm'; }

In detail

Method
Inverse of the block reference's matrix for picked points; unit factors 100 (mm² to cm²) and 25.4 (inches to mm); rotation and translation of nested pieces into the drawing.
Number types
64-bit numbers.
Tolerances
Table values: 2 decimals. Stored marks: 6 decimals; buttonhole angle: 4 decimals of a degree. A buttonhole shorter than 1e-9 is refused. A walked notch counts as matching within 0.5 mm (1/32 in). Lengths shown: 0.1 mm or 1/16 in.
Limits
The nesting call is given a time limit of 3 seconds and a raster cell of the fabric width ÷ 750.

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