Works out what the crane lifts, each pick's weight, radius, share of the load chart, hook height and time.
How the precision is kept
64-bit arithmetic on the model's part weights and the load chart the person enters. The chart is read as a step table, never interpolated: a radius between two rows gets the capacity of the farther row. Weights are gross (holes and copes not deducted), with a percentage added for rigging. The file says the result is not a lift plan.
Open item. Add each part's section offset when its center is taken for the center of gravity, so a beam hung from its top line is not weighed at the top of steel.
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.
The chart rows kept: sorted by radius, with a capacity that never rises as the radius grows.
Rows outside 0 to 500 m or 0 to 5,000,000 kg are dropped. A row with more capacity than the row before it is lowered to that row's capacity; values are otherwise kept as typed.
erection.js
lines 42 to 52
DetailCraft 0.8.1
/** A chart row list cleaned: numbers only, sorted by radius, a capacity that does not rise with radius. */
export function cleanChart(rows) {
const out = [];
for (const r of Array.isArray(rows) ? rows : []) {
const radius = Number(r?.radius), kg = Number(r?.kg);
if (Number.isFinite(radius) && Number.isFinite(kg) && radius > 0 && radius <= 500 && kg >= 0 && kg <= 5e6) out.push({ radius, kg });
}
out.sort((a, b) => a.radius - b.radius);
for (let i = 1; i < out.length; i++) if (out[i].kg > out[i - 1].kg) out[i] = { radius: out[i].radius, kg: out[i - 1].kg };
return out.slice(0, 200);
}
Capacity at a radius
Exact
The chart capacity that applies at a given radius.
capacity = kg of the first row with radius ≥ r; 0 beyond the last row
A lookup, not an interpolation: the value returned is always one the person typed, or zero. The comparison allows 1e-9 m, absolute.
erection.js
lines 54 to 59
DetailCraft 0.8.1
export function capacityAt(chart, radiusM) {
if (!chart?.length || !(radiusM >= 0)) return 0;
if (radiusM > chart[chart.length - 1].radius + 1e-9) return 0;
for (const row of chart) if (radiusM <= row.radius + 1e-9) return row.kg; // the first row at or beyond the radius
return 0;
}
Weight and center of gravity of a pick
64-bit
The weight of an assembly and the point its weight acts at.
W = Σ w_i; cg = Σ w_i·(a_i + b_i) ÷ 2 ÷ W
A running sum of part weights and a weighted mean of each part's line midpoint. The midpoint is of the part's frame line from its cut start to its end; the section's offset from that line is not added. An assembly of zero weight divides by 1.
erection.js
lines 104 to 106
DetailCraft 0.8.1
const weight = parts.reduce((t, q) => t + q.weight, 0);
// the centre of gravity of the assembly: weight-weighted centres of its parts (bolts and welds add to the rigging percentage, not here)
const cg = [0, 1, 2].map((i) => parts.reduce((t, q, k) => t + q.weight * (bx[k].a[i] + bx[k].b[i]) / 2, 0) / (weight || 1));
Storey a pick belongs to
64-bit
Which storey a pick is erected with, for the order of the sequence.
Levels are counted against the pick's lowest point (columns) or its center of gravity (others) with an absolute 50 mm allowance.
Radii are plan distances from Math.hypot divided by 1000. The share is one division, set to infinity when the capacity is zero. The hook height needed is the pick's top plus headroom plus clearance.
Times accumulate by addition from pick to pick with no rounding in the plan. The speed is limited to at least 0.5 m per minute when the setup is cleaned, so the division is safe.
The numbers quoted when a pick is over the chart, over the limit or too high.
Rounded for the message only: weights and capacity to whole kilograms, radius to 0.1 m, share to a whole percent, hook height to 0.01 m. The status was decided before on the unrounded values.
The picks, boxes and times saved into the erection movie page.
Rounded on the way out: coordinates and sizes to whole millimeters with Math.round, weights to whole kilograms, radius to 0.1 m, times to 0.01 minute. The movie page shows these rounded values.
erection.js
lines 245 to 261
DetailCraft 0.8.1
/** What the movie player draws: the phases' picks in order with their routes, the boxes, the cranes (plain JSON, mm, z up). */
export function movieData(pl, { title = '' } = {}) {
const members = [];
for (const p of pl.picks) {
for (const b of p.boxes || []) members.push({ pick: p.n, type: b.type, a: b.a.map(Math.round), b: b.b.map(Math.round), u: b.u, v: b.v, w: Math.round(b.w), d: Math.round(b.d), voff: Math.round(b.voff) });
}
return {
format: 'cadcraft-erection', version: 1, title,
cranes: pl.cranes.map((c) => ({ id: c.id, name: c.name, at: c.at, hookHeight: c.hookHeight, chart: c.chart })),
picks: pl.picks.map((p) => ({
n: p.n, mark: p.mark, type: p.type, profile: p.profile, phase: p.phase, kg: Math.round(p.weight), crane: p.crane, from: p.pickAt.map(Math.round), to: p.setAt.map(Math.round),
top: Math.round(p.top), radius: r1(p.radius), cap: Math.round(p.capacity), pct: Number.isFinite(p.util) ? Math.round(p.util * 100) : null, status: p.status,
t0: Math.round(p.start * 100) / 100, t1: Math.round(p.end * 100) / 100, h: r2(p.hookMin), tr: r2(p.travelMin), cg: p.cg.map(Math.round),
})),
members, minutes: pl.summary.minutes,
};
}
In detail
Method
Sum of part weights per assembly; plan distance from the crane; table lookup; time = fixed minutes + travel ÷ speed.
Number types
64-bit numbers. The movie data is rounded (millimeters to whole numbers, times to 0.01 minute).
Tolerances
Chart lookup 1e-9 m on the radius. Storey grouping 50 mm. Splice order 1 mm.
Limits
The radius is the larger of the pick-up and the set radius, measured in plan to the assembly's center of gravity. Travel is a straight carry plus the height of the pick's top.
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.