Forge: fit and connect

A forged model is many parts placed by coordinates. Placed by hand, a wing ends up a few centimetres off its pod, a light hovers in front of the hull, a frame pokes through the canopy. Fit & connect attaches parts to each other by their faces and surfaces instead, and checks every build for gaps, sunk parts and floating groups.

The fit check in every build

Every native forge_model build ends with a fit report (2 mm tolerance) in its result:

  • floating: a group of parts touching nothing that leads to the main body (the biggest group), with its gap.
  • gap: two parts within 20 mm of each other that leave a visible slit over 2 mm.
  • sunk: a part pushed more than 2 mm into another (measured from its corners and edge points); structural overlaps a modeller makes on purpose (a pylon in a hull) show here too, deepest first.
  • crosses: two surfaces cut through each other with no point inside either (a sheet through a sheet).
  • parts poking out through glass (mostly inside the glass, reaching out where it shows).

Joining parts in a recipe

const pod = f.loft("EnginePod", sections, {at: [1.42, 0, 0.75], material: gun})
const fin = f.box("Fin", {size: [1.5, 1.1, 0.06], material: white})
// A socket is a named face: where it is, which way it points out, and which way is up on it.
f.socket(fin, "root", [-0.75, 0, 0], {normal: [-1, 0, 0], up: [0, 0, 1]})
f.socket(pod, "fin", [1.95, 2.3, 0.6], {normal: [1, 0, -0.3]})
f.attach(fin, "root", pod, "fin", {spin: 10})          // face to face: normals opposite, ups matched, then turned
f.attach(fin, "root", pod)                              // no parent socket: onto the pod's nearest surface
// Slide a part along a direction until it rests on another's surface, sink metres into it (gap: stand off).
f.mount(f.box("CheekLight", {size: [0.05, 0.3, 0.035], at: [1.2, -2.2, 0.82], material: red}), hull, {direction: [-1, 0, 0], sink: 0.01})
f.mount(light, hull)                                    // no direction: straight at the hull's nearest surface
const r = f.fit({snap: true})                           // report; snap moves floating groups onto the body
log(r.floating_parts, r.summary)
  • f.mount casts from the part's corners and edge points (and back from the target's) along the direction, so a lamp dropped on a ramp rests on its highest point. align: [0, 0, -1] first turns the part so that axis faces the surface.
  • f.fit({snap: true}) moves each floating group straight toward the nearest point of the body until it touches, sink (1 mm) in, nearest group first (a fin and its tip light move together).
  • Sockets move with their part through mount, attach and fit.

Two models in one frame

The engine's glow lights a whole model, so glowing lights are often a second model in the same frame as the body (hb_racer_lights on hb_racer). f.fit({against: "hb_racer.js"}) runs that recipe as context: its parts are the main body for the check and for snapping, they never move, and they are not exported. The final build report keeps the same context.

The fit_check tool

fit_check {name} reports a recipe's fit without building it (every pair, as text and JSON); snap: true adds f.fit({snap: true}) to the recipe, rebuilds the model and reports again; against checks a second model sitting on another. Lab/fit/fit-survey.py runs the same check over a whole Forge folder.

Arcwright Beta 2 (0.4.0) · generated from the engine source (25e375c86)Something wrong or missing? Tell us
Download Arcwright free