← cad viewer

CAD viewer · #6

Measurements: two clicks, one distance

Face picking gave us the hard part for free: a raycast that returns exact world-space intersection points on the model. Measuring a distance is what you get when you stop throwing those points away.

The interaction

Check measure in /viewer's panel and clicks switch modes — instead of selecting a B-rep face, each click drops a marker at hit.point, the precise spot the ray pierced the surface. Second click draws the segment and reports the distance. Third click starts a fresh measurement. Uncheck and it all clears.

The distance itself is a.distanceTo(b) — the interesting parts are everything around it.

Marker scale is model scale

A marker sphere needs a radius, and "1 unit" means nothing when models range from a 10 mm cube to a 2 m assembly. So markers derive from the model's bounding sphere at load time: radius * 0.008. Same visual size on every model, no fiddling.

The floating label

The distance tag isn't in the 3D scene — it's a plain DOM element. Each frame, the segment's midpoint goes through Vector3.project(camera) into normalized device coordinates, then converts to pixels:

_mid.addVectors(measurePoints[0], measurePoints[1]).multiplyScalar(0.5);
_mid.project(camera);
measureLabel.style.left = `${((_mid.x + 1) / 2) * rect.width}px`;
measureLabel.style.top = `${((-_mid.y + 1) / 2) * rect.height}px`;

That's the standard trick for annotations: the label stays crisp, selectable size, immune to perspective — and it costs one matrix multiply per frame.

Units are a convention, not a fact

STEP files carry their own units and OCCT tessellates in them — in practice, millimeters. The readout auto-scales like the face areas do: under 100 mm it shows 42.3 mm, beyond that 14.2 cm. If a model arrives in inches the numbers will be off by 25.4× — a real fix means reading SI_UNIT from the STEP header, which is on the list.

One detail worth keeping: markers and the measure line carry the same clippingPlanes as the model, so measurements on a sectioned surface clip exactly like the geometry they sit on.

What this unlocks

Distance-between-points is the smallest useful measurement. The same infrastructure extends naturally: edge lengths once true B-rep edges land, face-to-face distances, maybe a tape along a surface. The pick pipeline is done — the rest is choosing which answer to compute.

Six milestones in: parse, parts, edges, sections, face data, measurements. The remaining roadmap is honest — true B-rep edges, then WebGPU when a workload earns it.