Resources Numerical accuracy Calculation policy

Measure tool

The lengths, bearings, grades, total length, ground length and area of what the person measures in plan, and the difference between two points on a profile.

How the precision is kept

Each value is one 64-bit expression on the picked coordinates: hypot for lengths, atan2 for bearings, a quotient for grades, a plain sum for totals and the shoelace formula for area. The area is summed from absolute project coordinates.

Open item. Subtract the first point from every point before the area sum, so the area keeps its digits at large coordinates.

Calculations under this policy

2 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.

measure.js CivilCraft 0.8.1 64-bit 2 calculations Reviewed

Tests None found by the review

Lengths, bearings, grades and area

64-bit

Every number the Measure tool shows for a picked line or shape.

L = hypot(Δx, Δy); bearing = atan2(Δy, Δx); grade % = Δz ÷ L × 100; L₃ = hypot(L, Δz); area = |Σ (x_i·y_j − x_j·y_i)| ÷ 2

Lengths and bearings use differences of the picked points, so they keep their digits. The area sum multiplies absolute coordinates: with coordinates near 2,000,000 each product is about 4e12, where 64-bit numbers are about 0.001 apart, so the area is resolved to about 0.001 square units per corner instead of 15 digits. Totals are plain sums.

  • measure.js
  • lines 19 to 41
  • CivilCraft 0.8.1
export function measure(pts, { closed = false, zAt = null } = {}) {
  const P = (Array.isArray(pts) ? pts : []).filter((p) => p && fin(p.x) && fin(p.y));
  const z = (p) => { if (fin(p.z)) return p.z; try { const v = zAt ? zAt(p.x, p.y) : null; return fin(v) ? v : null; } catch { return null; } };
  const Z = P.map(z);
  const shut = closed && P.length >= 3;
  const segs = [];
  const seg = (i, j) => {
    const a = P[i], b = P[j], L = Math.hypot(b.x - a.x, b.y - a.y);
    const dz = Z[i] != null && Z[j] != null ? Z[j] - Z[i] : null;
    return { L, bearing: Math.atan2(b.y - a.y, b.x - a.x), dz, grade_pct: dz != null && L > 1e-12 ? (dz / L) * 100 : null, L3d: dz != null ? Math.hypot(L, dz) : null };
  };
  for (let i = 1; i < P.length; i++) segs.push(seg(i - 1, i));
  if (shut) segs.push(seg(P.length - 1, 0));
  const total = segs.reduce((s, x) => s + x.L, 0);
  const total3d = segs.length && segs.every((x) => x.L3d != null) ? segs.reduce((s, x) => s + x.L3d, 0) : null;
  let area = null;
  if (shut) {
    let a2 = 0;
    for (let i = 0; i < P.length; i++) { const p = P[i], q = P[(i + 1) % P.length]; a2 += p.x * q.y - q.x * p.y; }
    area = Math.abs(a2) / 2;
  }
  return { n: P.length, closed: shut, segs, total, total3d, area, last: segs.length ? segs[shut ? segs.length - 2 : segs.length - 1] || null : null };
}

Between two points on a profile

64-bit

The horizontal distance, height difference, straight-line distance and grade between two profile points.

dx = |ch_b − ch_a|; dz = z_b − z_a; slope distance = hypot(dx, dz); grade % = dz ÷ dx × 100

One 64-bit expression each. The grade is given only when dx is over 1e-12 and takes its sign from the direction of travel.

  • measure.js
  • lines 43 to 47
  • CivilCraft 0.8.1
export function between(a, b) {
  if (!a || !b || !fin(a.ch) || !fin(a.z) || !fin(b.ch) || !fin(b.z)) return null;
  const dx = Math.abs(b.ch - a.ch), dz = b.z - a.z;
  return { dx, dz, slope: Math.hypot(dx, dz), grade_pct: dx > 1e-12 ? (dz / dx) * 100 * Math.sign(b.ch - a.ch || 1) : null };
}

In detail

Method
Segment length by hypot; bearing by atan2; grade = Δz ÷ L × 100; area by the shoelace formula.
Number types
64-bit numbers.
Tolerances
A grade is given only when the plan length is over 1e-12.
Limits
The ground length is taken straight between the picked points' elevations, not along the surface in between. The area sum is not shifted to a local origin.

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.

Every policy that takes this approach