Resources Numerical accuracy Calculation policy

Rib feature

Builds the region a rib fills from an open sketch line: the line extended past the body, swept to one side, and trimmed by the body.

How the precision is kept

The slab's corner points are 64-bit sums of sketch points and an extension length several times the body's size; the Boolean cut and the choice of piece are done by OpenCascade. The rib's final faces are where the slab meets the body, so the extension length does not set the result's accuracy.

Calculations under this policy

2 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.

brep-rib.js PartCraft 0.8.1 64-bit 2 calculations Reviewed

Tests tools/partcraft-test/test-rib.mjs

Rib slab outline

64-bit

The flat region the rib is cut from: the sketch chain carried past both ends and offset to one side.

E = 4 × max(1, diagonal + |box center − sketch origin|); ends ± E along the end directions; far side = + E × D

End directions and the chord are normalized with Math.hypot. The far corners are sums of a sketch coordinate and a length of several body sizes, so they carry rounding at that larger scale; they lie outside the body and are removed by the cut.

  • brep-rib.js
  • lines 28 to 44
  • PartCraft 0.8.1
const E = 4 * Math.max(1, V.len(V.sub(bb.max, bb.min)) + V.len(V.sub(V.mul(V.add(bb.max, bb.min), 0.5), frame.o)));
const sub = (a, b) => [a[0] - b[0], a[1] - b[1]], len = (a) => Math.hypot(a[0], a[1]);
const unit = (a) => [a[0] / len(a), a[1] / len(a)];
const n = pts.length;
const d0 = unit(sub(pts[1], pts[0])), d1 = unit(sub(pts[n - 1], pts[n - 2]));
const chord = unit(sub(pts[n - 1], pts[0]));
// the side the rib fills: toward the body's centre of mass (a bracket's inside corner), flip: away — whichever end was drawn first
const gp = T(new oc.GProp_GProps());
oc.BRepGProp.VolumeProperties(ctx.body, gp, false, false, false);
const cm = V.toPlane(frame, H.xyz(T(gp.CentreOfMass())));
const left = [-chord[1], chord[0]], mid0 = [(pts[0][0] + pts[n - 1][0]) / 2, (pts[0][1] + pts[n - 1][1]) / 2];
const toward = (cm[0] - mid0[0]) * left[0] + (cm[1] - mid0[1]) * left[1] >= 0 ? 1 : -1;
const side = toward * (f.flip ? -1 : 1);
const D = [left[0] * side, left[1] * side];
const ext = [[pts[0][0] - d0[0] * E, pts[0][1] - d0[1] * E], ...pts.slice(1, -1), [pts[n - 1][0] + d1[0] * E, pts[n - 1][1] + d1[1] * E]];
const far = ext.map((p) => [p[0] + D[0] * E, p[1] + D[1] * E]).reverse();
const poly = [...ext, ...far];

Choosing the rib piece

64-bit

Picks the piece of the trimmed slab that lies beside the sketch line and checks it is closed off by the body.

distance(probe, piece) < 1e-6 × max(1, t); open when reach > 0.5 × E

The distance comes from OpenCascade's extrema with its own tolerance argument of 1e-9. The open test uses the piece's bounding-box corners projected into the sketch plane.

  • brep-rib.js
  • lines 66 to 77
  • PartCraft 0.8.1
const probe = V.add(V.toWorld(frame, mid2[0], mid2[1]), V.mul(frame.n, lift + f.t / 2));
const vx = T(T(new oc.BRepBuilderAPI_MakeVertex(H.pnt(probe))).Vertex());
const dist = (s) => { const dd = T(new oc.BRepExtrema_DistShapeShape(vx, s, 1e-9, undefined, undefined, T(new oc.Message_ProgressRange()))); return dd.IsDone() ? dd.Value() : Infinity; };
const rib = pieces.find((s) => dist(s) < 1e-6 * Math.max(1, f.t));
if (!rib) fail(t('rib.err.inside'));
// open: the piece runs out to the far side of the slab, so the edge never meets the body on that side
const rb = ctx.bbox(rib);
const corners = [];
for (const x of [rb.min[0], rb.max[0]]) for (const y of [rb.min[1], rb.max[1]]) for (const z of [rb.min[2], rb.max[2]]) corners.push(V.toPlane(frame, [x, y, z]));
const reach = Math.max(...corners.map((c) => (c[0] - mid2[0]) * D[0] + (c[1] - mid2[1]) * D[1]));
const along = Math.max(...corners.map((c) => Math.abs((c[0] - mid2[0]) * chord[0] + (c[1] - mid2[1]) * chord[1])));
if (reach > 0.5 * E || along > 0.5 * E) fail(t('rib.err.open'));

In detail

Method
Extension E = 4 × max(1, body box diagonal + distance from box center to the sketch origin). Side chosen toward the body's center of mass. The rib is the piece of slab-minus-body touching a probe point at the chain's middle.
Number types
64-bit numbers.
Tolerances
Slab edges shorter than 1e-9 are skipped. The probe must be within 1e-6 × max(1, thickness) of the piece. A piece reaching more than 0.5 × E is refused as open.
Limits
The side test uses the sign of a 2D dot product; a center of mass exactly on the chord's line falls to the left side.

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.

Every policy that takes this approach