Turns a scale 1:n and the drawing's units into a viewport scale, picks the standard scale at which a view fits, and sizes the space a new sheet leaves for views.
How the precision is kept
All values are 64-bit numbers. Unit factors are millimeters per unit, written as their defined values (25.4, 304.8, 914.4, 1609344). Sheet borders and margins are designed in millimeters and converted with the reciprocal 1 ÷ (millimeters per unit), which is a rounded number for inch paper. Standard scales are matched with relative tolerances; the viewport scale that is stored is never rounded.
Calculations under this policy
10 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.
Paper units per model unit for a drawing scale 1:n.
s = mm per model unit ÷ mm per paper unit ÷ n
Two 64-bit divisions, nothing rounded. The unit table holds millimeters per unit as the defined values (inch 25.4, foot 304.8, yard 914.4, mile 1609344); a drawing with no known unit uses the paper's unit.
sheets.js
lines 49 to 50
CadCraft 0.8.2
/** Paper units per model unit for a scale 1:n. */
export const sOf = (doc, paperUnit, n) => modelMm(doc, paperUnit) / UNIT_MM[paperUnit] / n;
Scale 1:n from a viewport scale
64-bit
The n of 1:n that a viewport's stored scale stands for.
n = mm per model unit ÷ mm per paper unit ÷ s
The same two 64-bit divisions with s in place of n. No guard for s = 0 in this function.
sheets.js
lines 51 to 52
CadCraft 0.8.2
/** The n of 1:n for a viewport scale s. */
export const nOf = (doc, paperUnit, s) => modelMm(doc, paperUnit) / UNIT_MM[paperUnit] / s;
List of standard and custom scales
64-bit
The scales offered for a drawing: the standard ones and the drawing's own that the standard list lacks.
custom n = drawing ÷ paper; kept when |n − listed n| ≥ 1e-6 × n for every listed scale
A custom scale's n is one 64-bit division of the two numbers in the file's scale list. It is dropped as a duplicate when within 1e-6 × n of a listed scale, a relative tolerance. Enlargements are held as n = 1/10, 1/5 and 1/2.
sheets.js
lines 63 to 73
CadCraft 0.8.2
/** Standard scales for this drawing: architectural and engineering ones for imperial drawings. */
export function scaleList(doc) {
const metric = METRIC.map((n) => ({ n, label: ratioLabel(n) }));
const std = isImperial(doc) ? [...ARCH.map(([label, n]) => ({ n, label })).sort((a, b) => a.n - b.n), ...metric] : metric;
// the drawing's own scales (its file's list, SCALELISTEDIT: scales.js) that the standard list lacks, after it
const own = (Array.isArray(doc.meta.scales) ? doc.meta.scales : []).map((x) => ({ n: x.drawing / x.paper, label: x.name, custom: true }))
.filter((x) => x.n > 0 && Number.isFinite(x.n)).sort((a, b) => a.n - b.n);
const extra = [];
for (const x of own) if (![...std, ...extra].some((y) => Math.abs(y.n - x.n) < 1e-6 * x.n)) extra.push(x);
return extra.length ? [...std, ...extra] : std;
}
Name of a viewport scale
64-bit
The text a viewport scale reads as: a standard name when it is one, else 1:n.
A listed scale is recognized when its n is within 1e-6 × n of the viewport's, a relative tolerance. The result is text only; the viewport's stored scale is not changed.
sheets.js
lines 75 to 80
CadCraft 0.8.2
/** How a viewport scale reads: a standard name when it is one, else 1:n. */
export function scaleLabel(doc, paperUnit, s) {
const n = nOf(doc, paperUnit, s);
const std = scaleList(doc).find((x) => Math.abs(x.n - n) < 1e-6 * n);
return std ? std.label : ratioLabel(n);
}
Ratio text for a scale that is not listed
64-bit
Writes 1:n or n:1 for a scale with no standard name.
n ≥ 1: "1:n"; n < 1: "(1 ÷ n):1"
toPrecision(6) keeps 6 significant digits of n in the text. This text is what the title block's SCALE field and a viewport caption show for a scale that is not in the list.
Picks the largest listed scale at which the window still fits the viewport.
largest s with s ≤ sFit × (1 + 1e-9)
Each listed scale is converted to s and compared with the fitting scale with a relative allowance of 1e-9. When no listed scale fits, the fitting scale itself is returned unrounded.
sheets.js
lines 82 to 90
CadCraft 0.8.2
/** The largest standard scale whose s is at most sFit (so the drawing still fits). */
export function bestScale(doc, paperUnit, sFit) {
let best = null;
for (const x of scaleList(doc)) {
const s = sOf(doc, paperUnit, x.n);
if (s <= sFit * (1 + 1e-9) && (!best || s > best.s)) best = { ...x, s };
}
return best || { n: nOf(doc, paperUnit, sFit), label: ratioLabel(nOf(doc, paperUnit, sFit)), s: sFit };
}
Viewport center and scale for a model window
64-bit
The model point a viewport looks at and the scale at which a model window fits it.
sFit = min(w ÷ Δx, h ÷ Δy); center = ((minX + maxX) ÷ 2, (minY + maxY) ÷ 2)
The window's width and height are floored at 1e-9 drawing units before the divisions, an absolute floor that guards a zero-size window. The center is the mean of the window's limits.
sheets.js
lines 103 to 109
CadCraft 0.8.2
/** Aim a viewport of w × h paper units at a model window (bounds): centre and a standard scale. */
export function aimViewport(doc, paperUnit, w, h, win, { exact = false } = {}) {
if (!validBounds(win)) return { cx: 0, cy: 0, s: sOf(doc, paperUnit, 1) };
const bw = Math.max(win.maxX - win.minX, 1e-9), bh = Math.max(win.maxY - win.minY, 1e-9);
const sFit = Math.min(w / bw, h / bh);
return { cx: (win.minX + win.maxX) / 2, cy: (win.minY + win.maxY) / 2, s: exact ? sFit : bestScale(doc, paperUnit, sFit).s };
}
Standard paper for a sheet size
64-bit
Finds the standard paper a sheet of w × h is, either way round.
|standard side − side| ≤ 0.005 × side, both sides in mm
Both sides are converted to millimeters by one multiplication and compared with each standard size within 0.5 % of the side, a relative tolerance.
sheets.js
lines 32 to 37
CadCraft 0.8.2
/** The standard paper a sheet of w × h (in its unit) is, either way round, within 0.5 %; else null. */
export function matchPaper(w, h, unit) {
const k = UNIT_MM[unit] || 1;
const [a, b] = [Math.max(w, h) * k, Math.min(w, h) * k];
return PAPERS.find((p) => { const pk = UNIT_MM[p.unit]; return Math.abs(p.w * pk - a) <= a * 0.005 && Math.abs(p.h * pk - b) <= b * 0.005; }) || null;
}
Space for viewports on a sheet
64-bit
The rectangle inside the border and above the title block, in paper units.
x0 = sheet x0 + 15 mm × k; y0 = sheet y0 + 47 mm × k; x1 = sheet x0 + (W − 15 mm) × k; y1 = sheet y0 + (H − 15 mm) × k; k = 1 ÷ mm per paper unit
The sheet's width and height are converted to millimeters by dividing by k = 1 ÷ (mm per unit), and the corners are converted back by multiplying by k. For inch paper k = 1 ÷ 25.4 is a rounded number, so each far corner goes through a division and a multiplication by a rounded factor.
sheets.js
lines 122 to 126
CadCraft 0.8.2
/** The space a sheet leaves for viewports (inside the border, above the title block), in paper units: { x0, y0, x1, y1 }. Matches sheetContents. */
export function viewZone(paper) {
const k = 1 / UNIT_MM[paper.unit], W = paper.w / k, H = paper.h / k, m = 10, th = 32;
return { x0: paper.x0 + (m + 5) * k, y0: paper.y0 + (m + th + 5) * k, x1: paper.x0 + (W - m - 5) * k, y1: paper.y0 + (H - m - 5) * k };
}
Viewport of a new sheet
64-bit
The size, paper position, model center and scale of the viewport a new sheet starts with.
The viewport's size and paper center use the same millimeter margins and factor k as the border. Its model center and scale come from aimViewport over the extents of the visible model, and are stored unrounded.
s = (model millimeters per unit) ÷ (paper millimeters per unit) ÷ n for a scale 1:n. The chosen scale is the largest listed scale whose s does not exceed the scale at which the window just fits.
Number types
64-bit numbers.
Tolerances
Listed scale match: 1e-6 × n (relative). Scale fits: s ≤ sFit × (1 + 1e-9) (relative). Standard paper match: 0.5 % of each side (relative). Model window sides are floored at 1e-9 drawing units (absolute).
Limits
The text of a scale that is not in the list is written with 6 significant digits. A drawing without a known unit is taken to be in the paper's 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.