Reads and writes PLY meshes with their colors, in meters with Z up.
How the precision is kept
On import the points go into a Float64Array in whatever type the file declares, so a file with double coordinates keeps them. On export the header declares x, y and z as 'float' and the world coordinates are written with setFloat32, although the format also allows 'double'. An exported point therefore keeps about 7 digits of its distance from the model's origin.
Open item. Declare x, y and z as 'double' in the exported header and write them with setFloat64.
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.
io/ply.jsModelCraft 0.8.1 32-bit in part5 calculationsReviewed
Tests tools/modelcraft-test/meshfiles.mjs
Reading one number
64-bit
Reads a value of the type the header names, from text or from binary.
ASCII values are converted with Number to 64-bit. Binary values are read through a DataView in their declared type, so a 'double' stays 64-bit and a 'float' is widened without loss.
io/ply.js
lines 86 to 93
ModelCraft 0.8.1
const read = (type) => {
if (format === 'ascii') return tok();
const [g, n] = TYPES[type];
if (pos + n > b.length) throw fail(t('ply.why.short'));
const v = n === 1 ? dv[g](pos) : dv[g](pos, little);
pos += n;
return v;
};
Imported positions
64-bit
Stores each vertex's x, y and z.
The values are stored unchanged in a Float64Array: no unit factor and no axis change. Their accuracy is that of the file's declared type.
io/ply.js
lines 120 to 122
ModelCraft 0.8.1
case 'x': out.positions[i * 3] = v; break;
case 'y': out.positions[i * 3 + 1] = v; break;
case 'z': out.positions[i * 3 + 2] = v; break;
Points and normals in world coordinates
64-bit
Carries a point and a normal through a placement's matrix for export.
p′ = M × p; n′ = (M × n without translation), made unit
Written out as 64-bit sums of products. The normal is turned by the matrix itself, not by its inverse transpose, so under a non-uniform scale it is not exactly square to the surface.
Writes each vertex's world position and normal into the file.
The 64-bit world coordinates are written with setFloat32 under a header that declares 'property float x'. PLY also has a 'double' type, so the 32-bit rounding is this writer's choice and not the format's limit.
Gives corners with the same position, normal, color and UV one vertex.
key = x, y, z as numbers + normal to 5 decimals + color + UV
Positions are compared as 64-bit numbers before they are rounded to 32-bit, so two points that differ only beyond 32-bit become two vertices with the same stored position.
Header-driven reader for ASCII and both binary byte orders; export of every face in world coordinates with shared vertices.
Number types
Float64Array for imported positions; Float32Array for imported normals, colors and UVs; 32-bit floats for every exported position, normal and UV.
Tolerances
An imported coordinate must be below 1e7 in size. Exported corners share a vertex when positions are exactly equal and normals agree to 5 decimals.
Limits
Exported coordinates are 32-bit: at 100 m from the origin the spacing between representable values is about 0.008 mm.
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.