Writes BimCraft's pipe runs as piping components with end points, bores, bend angles and corner points, and turns the components of a piping file back into runs.
How the precision is kept
Coordinates pass through in 64-bit millimeters. A bend's corner is computed from its start point, direction, radius and angle in closed form. Three values are rounded when kept: a bend angle to 0.01 degree, a bore that is not a nominal size to 0.1 mm, and a valve's position along its run to 0.1 mm.
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.
The corner point and turn angle written for an elbow or bend.
corner = p₀ + d₁ × R tan(θ ÷ 2); angle = θ × 180 ÷ π to 2 decimals
The corner is one 64-bit expression from the bend's start point, incoming direction, radius and angle. The angle is rounded to 0.01 degree with toFixed(2) before it is written; the choice between elbow and bend uses the unrounded angle.
The corner of an imported elbow from the legs before and after it.
s = (b e − c d) ÷ (a c − b²), t = (a e − b d) ÷ (a c − b²); corner = midpoint of the two closest points
For unit directions the denominator is the squared sine of the angle between the legs; under 1e-9 the legs count as parallel and the file's own center point is used. The two closest points must lie within 2 mm of each other, an absolute limit.
mep/pcf-bim.js
lines 178 to 185
BimCraft 0.8.1
function lineMeet(p, d, q, e) {
// the point where line (p, d) passes nearest to line (q, e) — their meeting point for legs that lie in one plane
const w = sub(p, q), a = dot(d, d), b = dot(d, e), c = dot(e, e), dd = dot(d, w), ee = dot(e, w), den = a * c - b * b;
if (Math.abs(den) < 1e-9) return null;
const s = (b * ee - c * dd) / den, t = (a * ee - b * dd) / den;
const P1 = add(p, mul(d, s)), P2 = add(q, mul(e, t));
return len(sub(P1, P2)) < 2 ? mul(add(P1, P2), 0.5) : null;
}
Position of a valve along a run
64-bit
The distance along an imported run to the point nearest a valve.
s = Σ earlier leg lengths + clamp((p − a) · d, 0, L), rounded to 1 decimal
Leg lengths are Math.hypot values added in order. The result is rounded to 0.1 mm with toFixed(1), and that rounded value is the valve's position in the new run.
mep/pcf-bim.js
lines 186 to 195
BimCraft 0.8.1
function along(pts, p) {
let best = { off: Infinity, s: 0 }, run = 0;
for (let i = 1; i < pts.length; i++) {
const a = pts[i - 1], b = pts[i], L = len(sub(b, a)), d = unit(sub(b, a));
const t = Math.max(0, Math.min(L, dot(sub(p, a), d))), q = add(a, mul(d, t)), off = len(sub(p, q));
if (off < best.off) best = { off, s: run + t };
run += L;
}
return +best.s.toFixed(1);
}
Pipe size for an imported bore
Exact
The standard nominal diameter nearest to a bore that is not a standard size.
nearest = table value with the least |value − bore|
A search over the table's whole-number diameters that starts from 50; on a tie the value found first is kept. The differences are of whole or near-whole millimeters, so no digits are at stake.
Corner = start + direction × R tan(θ ÷ 2); on import the corner is where the two neighboring legs meet, else the file's center point; components are chained by matching end points.
Number types
64-bit numbers.
Tolerances
Ends join within 0.6 mm. Points within 0.5 mm are merged. Two legs are parallel when a c − b² is under 1e-9 for unit directions, and they meet only if they pass within 2 mm. A turn within 1 degree of 90 is an elbow. All absolute.
Limits
Bores are nominal diameters. A bore that is not a standard size takes the nearest one. Reducers and tees are not carried as components on import.
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.