Resources Numerical accuracy Calculation policy

Sheet and path of a point on a schematic

Finds which numbered path column of a sheet frame a device or wire sits in, for the place printed in cross-references and lists.

How the precision is kept

A frame is a block reference; its placement is a 2 by 3 matrix. The point is taken back into the frame's own millimeters with the inverse matrix and the column is found by one division and a floor. All 64-bit; there is no tolerance, so a point within rounding of a column line can fall on either side.

Calculations under this policy

2 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/electrical/lib/project.js CadCraft 0.8.2 64-bit 2 calculations Reviewed

Tests None found by the review

Frame grid in drawing coordinates

64-bit

The frame's matrix, its inverse and the box of the whole paper in the drawing.

det = m₀·m₃ − m₁·m₂; inverse = adjugate ÷ det

The inverse is the closed form for a 2 by 3 matrix. Only a determinant of exactly zero is rejected, so a frame scaled to almost nothing is inverted with large factors. The paper box is the minimum and maximum of the four transformed corners.

  • addons/electrical/lib/project.js
  • lines 72 to 84
  • CadCraft 0.8.2
/** A frame insert's grid in world coordinates: {cols, x0, x1, y0, y1, box: [x0,y0,x1,y1] (the whole paper), m, inv}. */
export function frameGrid(e, blk, meta = readMeta(blk)) {
  if (!meta || meta.role !== 'frame') return null;
  const n = (k, d) => (Number.isFinite(+meta[k]) ? +meta[k] : d);
  const cols = Math.max(1, Math.min(100, Math.round(n('cols', 10))));
  const m = insertM(e, blk);
  const det = m[0] * m[3] - m[1] * m[2];
  if (!det) return null;
  const inv = [m[3] / det, -m[1] / det, -m[2] / det, m[0] / det, (m[2] * m[5] - m[3] * m[4]) / det, (m[1] * m[4] - m[0] * m[5]) / det];
  const corners = [[0, 0], [n('w', 420), 0], [n('w', 420), n('h', 297)], [0, n('h', 297)]].map(([x, y]) => apply(m, x, y));
  const xs = corners.map((p) => p.x), ys = corners.map((p) => p.y);
  return { cols, gx0: n('gx0', 20), gx1: n('gx1', 410), gy0: n('gy0', 45), gy1: n('gy1', 282), m, inv, box: [Math.min(...xs), Math.min(...ys), Math.max(...xs), Math.max(...ys)] };
}

Path column of a point

64-bit

The column number, 1 to the column count, of a point inside a frame; 0 when it is left or right of the grid.

path = min(cols, ⌊(x − gx0) ÷ ((gx1 − gx0) ÷ cols)⌋ + 1)

One subtraction, one division and a floor on the point taken into frame coordinates. No tolerance is applied at column lines.

  • addons/electrical/lib/project.js
  • lines 86 to 92
  • CadCraft 0.8.2
/** The path column (1…cols) of a world point inside a frame; 0 when it is left or right of the grid. */
export function pathAt(grid, p) {
  const q = apply(grid.inv, p.x, p.y);
  if (q.x < grid.gx0 || q.x > grid.gx1) return 0;
  const colw = (grid.gx1 - grid.gx0) / grid.cols;
  return Math.min(grid.cols, Math.floor((q.x - grid.gx0) / colw) + 1);
}

In detail

Method
Inverse of the insert matrix by its determinant; column = ⌊(x − gx0) ÷ column width⌋ + 1.
Number types
64-bit numbers; the column count is a whole number from 1 to 100.
Tolerances
None. A frame whose matrix has a determinant of exactly zero is refused.
Limits
A point exactly on a column line belongs to the column on its right; the right edge of the grid belongs to the last column.

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