Lays out the process flow diagram, node boundaries and live value labels that the P&ID add-on and the Plant tab add to a drawing.
How the precision is kept
The layout is simple 64-bit arithmetic on fixed box sizes and gaps. Line, circle and text coordinates are rounded to 3 decimals of a drawing unit before they are handed to the host; polygon corners are not. Stream labels show temperature and pressure rounded to 3 decimals. The diagram is schematic, so the rounding does not affect any engineering value.
Calculations under this policy
4 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.
A coordinate or label value rounded for the drawing.
f(v) = +v.toFixed(3); 0 when v is not finite
Three decimals of a drawing unit. A value that is not finite becomes 0 without a flag.
process/draw.js
lines 2 to 14
CadCraft 0.8.2
/**
* draw.js — what the P&ID add-on and the Plant tab draw from the process engines (0.8 chem-draw_PART_4; DOM-free, no imports). Everything returns plain entities
* ({ type: 'line'|'circle'|'poly'|'text', layer, … } in the units asked for) and plain tables, so the hosts only have to add them.
*
* pfdEntities(def, res?, opts) CH.2 the block flow / process flow diagram of a flowsheet: units in columns by flow, streams as arrows with their names, recycles over the top
* nodeInside(node-rect, items) CH.14 which tags and line numbers lie inside a hazop node's region
* regionEntities(node, opts) CH.14 the node boundary and its label as entities on layer HAZOP-NODE
* markerEntities(markers, at, opts) CH.27 / XE.9 value labels beside tagged symbols, coloured by state
* markerLevels(markers) XE.9 0..1 level per tag for tinting 3D elements
* loopTable(loops, bindings, spec) CH.5 the loop binding screen's rows and what is unbound
* faceplate(ctrl, trend) CH.5 the numbers a controller faceplate shows from a simulation
*/
const f = (v) => (Number.isFinite(v) ? +Number(v).toFixed(3) : 0);
Stream label
64-bit
The text under a stream arrow: its name, temperature in degrees Celsius and pressure in bar.
T (°C) = T − 273.15; P (bar) = P ÷ 1e5; both to 3 decimals
The subtraction and division are done on the solved values and only the label text is rounded.
process/draw.js
lines 40 to 41
CadCraft 0.8.2
const streamLabel = (id) => { const s = res && res.streams && res.streams[id]; return s && Number.isFinite(s.T) ? `${id} ${f(s.T - 273.15)} C ${f(s.P / 1e5)} bar` : id; };
const consumed = new Set();
Point inside a node boundary
64-bit
Whether a tag or line label lies inside a hazard study node's region.
count the sides whose ends straddle the point's height and cross to its right; inside when the count is odd
One division per straddling side and no tolerance, so a point exactly on the boundary can fall either way.
process/draw.js
line 71
CadCraft 0.8.2
const inPoly = (p, poly) => { let c = false; for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) { const a = poly[i], b = poly[j]; if ((a[1] > p.y) !== (b[1] > p.y) && p.x < ((b[0] - a[0]) * (p.y - a[1])) / (b[1] - a[1]) + a[0]) c = !c; } return c; };
Controller faceplate numbers
64-bit
The set point, measurement, output and error a controller faceplate shows from a simulation.
error = set point − last measurement
The last values of the trend are passed on unrounded and the error is one subtraction.
process/draw.js
lines 107 to 113
CadCraft 0.8.2
/** A faceplate from a simulation result: the controller record, the trend of its pv and output, and the numbers the plate shows. */
export function faceplate(ctrl, trend = null) {
const last = (a) => (Array.isArray(a) && a.length ? a[a.length - 1] : null);
const pv = trend && trend.pv, out = trend && trend.out;
return { tag: ctrl.id, mode: ctrl.auto === false ? 'MAN' : 'AUTO', sp: ctrl.sp, pv: last(pv), out: ctrl.auto === false ? ctrl.out ?? null : last(out), action: ctrl.action, Kc: ctrl.Kc, Ti: ctrl.Ti ?? null, Td: ctrl.Td ?? null, span: ctrl.span || null,
error: Number.isFinite(last(pv)) && Number.isFinite(ctrl.sp) ? ctrl.sp - last(pv) : null };
}
In detail
Method
Units in columns by flow order, streams as polylines with arrow heads; a point-in-polygon test for what lies inside a hazard study node.
Number types
64-bit numbers; coordinates rounded with toFixed(3).
Tolerances
Two heights closer than 1e-6 draw as one straight arrow.
Limits
The point-in-polygon test has no tolerance on the boundary.
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.