Script workspace: the part handed to scripts and picked values
Hands the open part's mesh to scripts, and reports the point, node and field values under a click on what a script showed.
How the precision is kept
The part reaches a script as the display mesh, whose corner coordinates kernel.js keeps in a Float32Array; widening them to a Float64Array does not bring digits back. The picked point comes from a ray cast on the drawn surface, which cs-ui.js surfaceOf also stores as a Float32Array. Field values under the click are read from the field's own data array without interpolation.
Open item. Hand scripts the part's geometry from the 64-bit solid instead of the 32-bit display mesh, and state the picked point from the mesh's own node coordinates.
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.
ws-script.jsPartCraft 0.8.1 32-bit in part4 calculationsReviewed
Tests tools/partcraft-test/test-script.mjs
Part mesh for scripts
32-bit in part
The open part as a triangle mesh a script can compute on through part().
The source is the part's display mesh (the comment says so); kernel.js fills its positions as a Float32Array. Float64Array.from widens those 32-bit values, so every length, area or volume a script works out from part() starts from about 7 significant digits.
ws-script.js
lines 232 to 237
PartCraft 0.8.1
/** The open part as a model value for the script's part() (its display mesh; only sent when the script names it). */
function partModel(host) {
const m = host.regen && host.regen.mesh;
if (!m || !m.positions || !m.indices) return null;
return { t: 'model', source: 'part', ref: String(host.part.name || 'Part').slice(0, 120) /* i18n-ignore: a data reference */, mesh: { t: 'mesh', kind: 'tri', nodes: Float64Array.from(m.positions), elems: Int32Array.from(m.indices) } };
}
Picked point and nearest node
32-bit in part
The coordinates of the clicked point and the mesh node closest to it.
node = the hit triangle's corner with the least √(Δx² + Δy² + Δz²) to the hit point
The hit point comes from a ray cast on the drawn geometry, whose positions are a Float32Array; when the item is shown deformed these are the displaced, scaled positions. The point is rounded with toFixed(4) before it is shown.
ws-script.js
lines 463 to 472
PartCraft 0.8.1
const rows = [[t('script.ws.pick.item'), `${it.name} (${it.kind})`], [t('script.ws.pick.point'), h.point.toArray().map((v) => fmtNum(+v.toFixed(4))).join(', ')]];
let node = -1;
if (idx) {
const pos = h.object.geometry.attributes.position;
let best = Infinity;
for (const v of idx) { const d = Math.hypot(pos.getX(v) - h.point.x, pos.getY(v) - h.point.y, pos.getZ(v) - h.point.z); if (d < best) { best = d; node = s.vertNode[v]; } }
} else {
const v0 = s.indices[3 * tri];
node = s.vertNode[v0];
}
Field values at the picked node or element
64-bit
The value of each shown field at the picked node or element.
Each component is read from the field's own data array at the node or element index, with no interpolation. sig prints it to 4 significant figures; the stored data is not changed.
ws-script.js
lines 475 to 480
PartCraft 0.8.1
for (const f of S.shown.filter((x) => x.kind === 'field' && x.visible && x.mesh === it.mesh)) {
const c = f.value.comps || 1, at = f.value.at === 'elem' ? elem : node;
if (at < 0) continue;
const vals = Array.from(f.value.data.subarray ? f.value.data.subarray(at * c, at * c + c) : f.value.data.slice(at * c, at * c + c), (x) => sig(x));
rows.push([f.value.at === 'elem' ? t('script.ws.pick.at_element', { name: f.name }) : t('script.ws.pick.at_node', { name: f.name }), vals.join(', ') + (f.value.unit ? ' ' + f.value.unit : '')]);
}
Deformed shape for drawing
32-bit, display only
The drawn position of each surface corner when a displacement field deforms the shape.
drawn position = position + scale × displacement
Written into a Float32Array that only feeds the drawn geometry. The scale is the automatic one from cs-ui.js unless the script or the person set it.
ws-script.js
lines 353 to 358
PartCraft 0.8.1
if (it.deform) {
if (it.scale === null) it.scale = C.autoScale(s.positions, it.deform.data, s.vertNode);
pos = new Float32Array(s.positions.length);
const u = it.deform.data;
for (let v = 0; v < s.vertNode.length; v++) { const n = s.vertNode[v]; for (let c = 0; c < 3; c++) pos[3 * v + c] = s.positions[3 * v + c] + it.scale * u[3 * n + c]; }
}
In detail
Method
partModel copies the display mesh into the script's model value. pick casts a ray on the shown overlays, takes the nearest of the hit triangle's three corners as the node, and lists each visible field's value at that node or element.
Number types
Float32Array (display mesh and drawn surface), widened to Float64Array for the script; field data in the typed array the script produced; 64-bit arithmetic.
Limits
The picked point is printed to 4 decimals and field values to 4 significant figures (sim-ui.js sig).
Approach: 32-bit step, flagged
One step stores or exchanges 32-bit values that reach a number a person reads. It is listed here with its open item, and the step is either moved to 64-bit or the app will warn where the number is read.