Turns an opening, a layout of panes and a profile system into the profile pieces to cut with their angles, the glass sizes and the hardware and gasket quantities.
How the precision is kept
All sizes are millimeters in 64-bit numbers, built from short sums and differences of the opening and the profile system's face widths, overlaps and gaps. Stored piece lengths, cell positions and glass sizes are rounded to 0.001 mm. Hardware quantities are rounded to 0.001 after every addition.
Calculations under this policy
9 calculations in 2 source files. 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.
Shares the inner opening between columns or rows: typed sizes keep theirs, the others split what is left equally.
each free size = (avail − Σ typed) ÷ free count
If the typed sizes exceed the space by more than 1e-9 mm, or leave less than 1 mm for the free ones, every size becomes an equal share and the result is flagged. If all sizes are typed and miss the space by more than 1e-6 mm they are scaled by avail ÷ Σ typed.
addons/windows/lib/model.js
lines 70 to 78
CadCraft 0.8.2
/** Share `avail` between sizes: given ones keep theirs, the others split what is left. null sizes → equal. Returns { sizes, ok }. */
function split(given, avail) {
const fixed = given.reduce((a, g) => a + (g || 0), 0), free = given.filter((g) => !g).length;
if (fixed > avail + 1e-9 || (free && avail - fixed < 1)) { const e = avail / given.length; return { sizes: given.map(() => e), ok: false }; }
const each = free ? (avail - fixed) / free : 0;
const sizes = given.map((g) => g || each);
if (!free && Math.abs(fixed - avail) > 1e-6) { const k = avail / fixed; return { sizes: sizes.map((s) => s * k), ok: false }; }
return { sizes, ok: true };
}
Inner opening
64-bit
The opening inside the frame, and the space left for the columns after the mullions.
inner w = W − 2f; inner h = H − f − tf; columns share inner w − (n − 1) × m
Subtractions of the frame and mullion face widths from the opening; for a door the bottom is the threshold's face instead of the frame's.
The length a piece is sawn to, with the welding allowance, and the merging of equal pieces into one row.
cut = outer + (mitred ends) × weld ÷ 2
The outer length is rounded to 0.001 mm first, then the allowance is added and the sum rounded again. Pieces are merged when role, rounded cut length, angles and note are equal. Clipped beads get no allowance.
Frame and sash profiles get steel only when longer than the system's limit; mullions and transoms always. The section is written as 28 × 22 mm in the code for every system.
The size of an opening sash and of the glass in a sash or in the frame.
sash = cell + 2 (overlap − gap); glass in a sash = sash − 2 × face + 2 (seat − glass gap); glass in the frame = cell + 2 (frame seat − glass gap)
Computed from the unrounded cell size; the sash and glass sizes are rounded to 0.001 mm only where they are stored. The heavy-sash warning compares the sash width with 1400 mm and its area with 2.2e6 mm².
One row per glass size with its quantity and the area of one pane.
area = round(gw × gh) ÷ 10⁶ m²
The area is rounded to a whole square millimeter before it is divided into square meters, from the unrounded width and height. Panes are merged by their sizes rounded to 0.001 mm; the row's area stays that of one pane.
Handles, hinges, locking points, strikers, packers, connectors and the meters of each gasket for a set of windows.
locks = max(2, ⌈perimeter ÷ lock pitch⌉); sash gasket = 2 (w + h) ÷ 1000 m; glass gasket = 4 (gw + gh) ÷ 1000 m
The running total of each item is rounded to 0.001 after every addition (a millimeter of gasket), so the rounding can add up over many panes. Perimeters use the sash and glass sizes already rounded to 0.001 mm. No waste allowance is added.
addons/windows/lib/model.js
lines 198 to 223
CadCraft 0.8.2
export function hardwareList(models) {
const rows = new Map();
const add = (key, item, spec, qty) => { if (!(qty > 0)) return; const k = key + '|' + spec; const r = rows.get(k) || { key, item, spec, qty: 0 }; r.qty = Math.round((r.qty + qty) * 1000) / 1000; rows.set(k, r); };
for (const mod of models) {
const sys = mod.system, hw = sys.hardware;
for (const col of mod.cols) for (const c of col.cells) {
if (c.sash) {
const per = 2 * (c.sash.w + c.sash.h);
add('handle', 'hw.handle', '', 1);
const locks = Math.max(2, Math.ceil(per / hw.lockPitch));
if (c.op === 'TL' || c.op === 'TR') add('tt-set', 'hw.tt-set', c.op === 'TL' ? 'L' : 'R', 1);
else if (c.op === 'T') add('tilt-set', 'hw.tilt-set', '', 1);
else add('hinge', 'hw.hinge', '', c.sash.h > hw.hingeOver ? 3 : 2);
add('lock', 'hw.lock', '', locks);
add('striker', 'hw.striker', '', locks);
add('gasket-sash', 'hw.gasket-sash', 'm', per / 1000);
}
add('packer', 'hw.packer', '', hw.packers);
add('gasket-glass', 'hw.gasket-glass', 'm', 2 * 2 * (c.glass.w + c.glass.h) / 1000);
}
add('gasket-frame', 'hw.gasket-frame', 'm', 2 * (mod.inner.w + mod.inner.h) / 1000);
add('connector', 'hw.connector', '', 2 * (mod.cols.length - 1) + 2 * mod.cols.reduce((a, c) => a + c.cells.length - 1, 0));
}
const ORDER = ['handle', 'tt-set', 'tilt-set', 'hinge', 'lock', 'striker', 'connector', 'packer', 'gasket-frame', 'gasket-sash', 'gasket-glass'];
return [...rows.values()].sort((a, b) => ORDER.indexOf(a.key) - ORDER.indexOf(b.key) || a.spec.localeCompare(b.spec));
}
The factor between the drawing's units and the builder's millimeters, and its reciprocal stored with each window.
mm per drawing unit = per × 25.4 (inch rules) or per × 1; kmm = 1 ÷ that
25.4 is exact. The stored kmm is a reciprocal, 1 ÷ (per × 25.4) in an inch drawing, which a binary number cannot hold exactly; it is the factor the elevation drawing multiplies every millimeter size by.
addons/windows/main.js
line 64
CadCraft 0.8.2
const unitFacts = (doc) => { const u = ruleUnitOf(doc), per = perUnit(doc, u), mmPerRule = u === 'in' ? MM_IN : 1; return { u, mmPerDrawing: per * mmPerRule, kmm: 1 / (per * mmPerRule) }; };
Typed opening size
64-bit
A size typed as width x height in drawing units, as millimeters.
w = typed w × mm per drawing unit
The text is read as plain decimals (no fractions, no unit marks) and multiplied by the factor; nothing is rounded.
The file's header comment gives each formula: inner opening, columns and rows shared after the mullions, sash = cell + 2 (overlap − gap), glass from the sight size plus the seats, beads from the glass, half the weld allowance on every mitred end of a welded frame.
Number types
64-bit numbers.
Tolerances
Lengths rounded to 0.001 mm. An end counts as mitred when its angle differs from 90° by more than 1e-9. Typed column or row sizes are refused when they exceed the space by more than 1e-9 mm, and rescaled when they miss it by more than 1e-6 mm.
Limits
The steel reinforcement section is fixed at 28 × 22 mm in the code. The heavy-sash warning uses fixed limits of 1400 mm width and 2.2 m².
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.