Lists stakes along an alignment at stations and offsets, or survey points measured against it, each with its coordinates, design and ground elevations and cut or fill.
How the precision is kept
Each stake is placed in 64-bit from the alignment point at its station and one sine and cosine of the direction. Cut or fill is one subtraction of the design from the ground. The rows keep full precision; the CSV writes coordinates, elevations and cut or fill to 3 decimals, and the PDF table writes elevations to 2.
Calculations under this policy
5 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.
Every multiple of the step between two stations, both ends, and the alignment's own curve points in between.
sta = k × step for whole k; neighbors closer than 1e-6 merged
Each station is k × step, one multiplication, clamped to the range, and is not rounded. The first k uses ceil((a − 1e-9) ÷ step) so a start on a multiple of the step is kept.
staking.js
lines 28 to 34
CivilCraft 0.8.1
export function stakeStations(al, { from = al.start, to = al.end, step = 50, keys = true } = {}) {
const a = Math.max(al.start, Math.min(from, to)), b = Math.min(al.end, Math.max(from, to));
const set = new Set([a, b]);
if (step > 0) for (let k = Math.ceil((a - EPS) / step); k * step <= b + EPS; k++) set.add(Math.min(b, Math.max(a, k * step)));
if (keys) for (const e of al.elements || []) for (const s of [e.sta, e.sta + e.len]) if (s > a + EPS && s < b - EPS) set.add(s);
return [...set].sort((x, y) => x - y).filter((s, i, arr) => i === 0 || s - arr[i - 1] > 1e-6);
}
Stake position
64-bit
The coordinates of a stake at a station and an offset to the right or left.
x = xₚ + off × sin(dir); y = yₚ − off × cos(dir)
One 64-bit sine and cosine of the alignment's direction at the station and one multiply and add per coordinate.
staking.js
lines 36 to 40
CivilCraft 0.8.1
function place(al, sta, off) {
const p = al.pointAt(sta);
// right of the alignment = + : the right-hand normal of the forward direction
return { x: p.x + off * Math.sin(p.dir), y: p.y - off * Math.cos(p.dir) };
}
Stake rows with cut or fill
64-bit
One row per station and offset with design elevation, ground elevation and cut or fill.
cf = ground − design (positive = cut)
A single 64-bit subtraction of two elevations supplied by the caller; the row keeps the unrounded value.
staking.js
lines 41 to 50
CivilCraft 0.8.1
export function stakeRows(al, { stations, offsets = [0], design = () => null, ground = () => null, first = 1, prefix = '' }) {
const rows = [];
let n = first;
for (const sta of stations) for (const off of offsets) {
const { x, y } = place(al, sta, off);
const d = design(sta, off, x, y), g = ground(x, y);
rows.push({ id: prefix + n++, sta, off, x, y, design: fin(d) ? d : null, ground: fin(g) ? g : null, cf: fin(d) && fin(g) ? g - d : null });
}
return rows;
}
Survey points against the alignment
64-bit
Each survey point's station and offset on the alignment, the design there and the cut or fill to the point's own elevation.
cf = point elevation − design
Station and offset come from the alignment's own stationOffset; the cut or fill is one 64-bit subtraction. Points beyond the alignment's ends are counted and left out.
staking.js
lines 51 to 62
CivilCraft 0.8.1
export function pointRows(al, points, { design = () => null, ground = null } = {}) {
const rows = [];
let outside = 0;
for (const p of points) {
const so = al.stationOffset(p.x, p.y);
if (!so || so.outside) { outside++; continue; }
const d = design(so.sta, so.off, p.x, p.y), g = fin(p.z) ? p.z : ground ? ground(p.x, p.y) : null;
rows.push({ id: p.n, sta: so.sta, off: so.off, x: p.x, y: p.y, design: fin(d) ? d : null, ground: fin(g) ? g : null, cf: fin(d) && fin(g) ? g - d : null });
}
rows.sort((a, b) => a.sta - b.sta || a.off - b.off);
return { rows, outside };
}
Staking table as CSV
64-bit
Writes the stake rows to a CSV file.
northing, easting, design, ground and cut or fill to 3 decimals; offset and the C/F column to 2 decimals
The exported numbers are rounded with toFixed: 3 decimals for coordinates, elevations and the signed cut or fill, 2 for the offset and the C or F text. A cut or fill smaller than 0.005 is written as 0.00 in the text column.
staking.js
lines 90 to 99
CivilCraft 0.8.1
export function stakingCsv(rows, { units = 'ft', title = '' } = {}) {
const u = units === 'm' ? 'm' : 'ft';
const q = (v) => { const s = String(v); return /^-?\d/.test(s) || s === '' ? s : /^[=+\-@\t\r]/.test(s) ? "'" + s : s; };
const c = (v) => (/[",\r\n]/.test(v) ? '"' + v.replace(/"/g, '""') + '"' : v);
const out = [];
if (title) out.push([title]);
out.push([t('sk.c.point'), t('sk.c.sta'), t('sk.c.off', { u }), t('sk.c.n'), t('sk.c.e'), t('sk.c.design'), t('sk.c.ground'), t('sk.c.cf', { u }), t('sk.c.cfn')]);
for (const r of rows) out.push([r.id, formatStation(r.sta, units), offsetText(r.off), num(r.y, 3), num(r.x, 3), num(r.design, 3), num(r.ground, 3), cutFillText(r.cf), num(r.cf, 3)]);
return out.map((r) => r.map((v) => c(q(v))).join(',')).join('\r\n') + '\r\n';
}
In detail
Method
Stake = alignment point + offset × right-hand normal; cut or fill = ground − design.
Number types
64-bit numbers.
Tolerances
Station steps and key stations compared with 1e-9; stations closer than 1e-6 merged; offsets closer than 1e-9 treated as repeats; a cut, fill or offset below 0.005 prints as 0.00.
Limits
The exported text is rounded: 3 decimals in the CSV, 2 or 3 in the PDF table.
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.