Chooses the scale a level's plan prints at and turns plan millimeters into positions on the sheet.
How the precision is kept
Plan coordinates are divided by the scale ratio, offset to center the drawing and multiplied by 72 ÷ 25.4 to PDF points, in 64-bit. Each coordinate is then written with 6 decimals of a point. Door swings and other arcs are written as short straight lines.
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 paper size, the drawing's extent and the scale it prints at.
fits when W ÷ r ≤ room width and H ÷ r ≤ room height
The extent is a difference of bounds, floored at 1 mm. The first standard scale at which width ÷ ratio and height ÷ ratio fit the sheet is taken; when none fits, the ratio is the ceiling of the larger of the two quotients.
model-pdf.js
lines 60 to 71
BimCraft 0.8.1
/** The sheet and the scale a plan prints at: { PW, PH, margin, strip, bb, W, H, room, sc: [ratio, label] }. */
export function sheetFor(scene, { paper = 'letter', units = 'ftin', scale = null } = {}) {
const [PW, PH] = PAPER[paper] || PAPER.letter;
const margin = 12, strip = 16;
const bb = bounds(scene);
const W = Math.max(1, bb.x1 - bb.x0), H = Math.max(1, bb.y1 - bb.y0);
const room = [PW - 2 * margin, PH - 2 * margin - strip];
const list = SCALES[isMetric(units) ? 'mm' : 'ftin'];
let sc = scale ? list.find((x) => x[0] === scale) || [scale, '1:' + scale] : list.find(([r]) => W / r <= room[0] && H / r <= room[1]); // i18n-ignore: a scale ratio
if (!sc) { const r = Math.ceil(Math.max(W / room[0], H / room[1])); sc = [r, '1:' + r]; } // i18n-ignore: a scale ratio
return { PW, PH, margin, strip, bb, W, H, room, sc };
}
Plan millimeters to the sheet
64-bit
The scale factor and offsets that place the plan on the page.
k = 1 ÷ ratio; paper = offset + plan × k; points = paper × 72 ÷ 25.4
k = 1 ÷ ratio is computed once and multiplied in, instead of dividing each coordinate by the ratio, so a ratio that is not a power of two adds one rounding. The points factor 72 ÷ 25.4 is the exact definition, rounded once to 64-bit.
model-pdf.js
lines 75 to 77
BimCraft 0.8.1
const k = 1 / sc[0]; // plan mm → paper mm
const ox = margin + (room[0] - W * k) / 2 - bb.x0 * k, oy = margin + strip + (room[1] - H * k) / 2 - bb.y0 * k;
const P = ([x, y]) => [ox + x * k, oy + y * k];
Coordinate written to the PDF
64-bit
How a path coordinate in points is turned into text.
text = Number(v.toFixed(6))
toFixed(6) keeps 6 decimals of a point, which is 3.5e-7 mm on paper. The code's comment says this keeps model precision under 0.005 mm at the supported scales.
model-pdf.js
lines 51 to 52
BimCraft 0.8.1
// Vector coordinates retain sub-0.005 mm model precision at supported drawing scales.
const coord = v => String(Number(v.toFixed(6)));
Arcs as short lines
64-bit
Door swings and other arcs written as polylines.
steps = max(8, ⌈|a₁ − a₀| ÷ (π ÷ 32)⌉)
An arc is cut into max(8, ⌈|sweep| ÷ (π ÷ 32)⌉) equal steps and each point is the center plus r at that angle, so the points lie on the arc and the chords inside it.
model-pdf.js
line 155
BimCraft 0.8.1
for (const a of s.arcs || []) { const steps = Math.max(8, Math.ceil(Math.abs(a.a1 - a.a0) / (Math.PI / 32))); const pts = []; for (let i = 0; i <= steps; i++) { const t = a.a0 + (a.a1 - a.a0) * i / steps; pts.push([a.c[0] + a.r * Math.cos(t), a.c[1] + a.r * Math.sin(t)]); } path(pts); }
In detail
Method
paper mm = offset + plan mm ÷ ratio; points = mm × 72 ÷ 25.4. The scale is the largest standard scale at which the drawing fits the sheet.
Number types
64-bit numbers; text in the PDF.
Tolerances
Path coordinates written with 6 decimals of a point; pen widths, text positions and the page size with 3. A value under 5e-5 is written as 0 by the 3-decimal formatter. Arcs in steps of at most π ÷ 32 (5.625°), at least 8 steps.
Checked by
tools/bimcraft-test/model-test.mjs and tools/bimcraft-test/wall-precision.test.mjs call planPdf in Node.
Limits
0.000001 point is 0.00000035 mm on paper, which at 1:1000 is 0.00035 mm in the model. Arcs are polylines.
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.