New Project

Curved Members#

A swept bend along a member's own length

Names: bend arc spline

When to use#

  • A member that curves along its own length, not its cross-section: a chair crest rail that bows in plan or in elevation, a splat that follows a lumbar curve — RFC-0040's own two motivating cases.
  • You want the cut list to say "follows spine," and the card to dimension the curve itself (an arc's radius, or a spline's keyframes), not the swept solid's bounding box.

Not for a cross-section that varies along a straight length (that is section's own rect/interp=spline job — turning-and-sections), a doubly curved surface such as a saddled seat (not built, RFC-0021), or a true 3D (non-planar) spine (not built: plane= is always one coordinate plane).

Syntax#

bend axis=z plane=<xz|yz> [tolerance=<expr> | samples=<expr>] {
    arc radius=<expr>
}
bend axis=z plane=<xz|yz> [tolerance=<expr> | samples=<expr>] {
    spline {
        point z=<expr> <x|y>=<expr>   // two or more, z running the whole part
    }
}
  • axis= — only "z". A bent member's own length is always its local z; place it with rot like any other component whose length is not world z.
  • plane= — "xz" (bows local x, holds local y fixed) or "yz" (bows local y, holds local x fixed). The spine stays planar.
  • tolerance= or samples=, mutually exclusive, same meaning as the rect-section family's own knobs.
  • Exactly one of arc (closed-form, tangent at z=0 only, asymmetric end to end) or spline (two or more (z, offset) control points, resampled through ww_geom::spline::sample — symmetric when both ends hold offset=0). A spline's points must run the whole part, z=0 to z = 0 - size.z.
  • A radius (or local curvature) tighter than the cross-section's own half-depth is refused before any kernel call — it would self-intersect the sweep.

Available faces. Only the two end FaceFrames (and their standard anchors — top_sw, …, top_center, bottom_center, center) exist; the swept lateral surface is not a face. A mark with an end-facing normal= (pos_z/neg_z) resolves off the real, curved end frame; one with a lateral normal= is refused by name. mortise_and_tenon needs a mark with normal= (a standard anchor has no facing, D6) — a mark at the end face's own centre is exact whenever the curve holds offset=0 at that end.

Example#

bend axis=z plane=xz {
    spline {
        point z=0.0          x=0.0
        point z="0.0 - 300.0" x="0.0 - 18.0"
        point z="0.0 - 600.0" x=0.0
    }
}

mark CrestTenon_Start x=50.0 y=50.0 z=0.0            normal=pos_z
mark CrestTenon_End   x=50.0 y=50.0 z="0.0 - 600.0"  normal=neg_z

examples/arched_crest_side_chair.kdl is the worked case: a steam-bent ash crest rail, mortise-and-tenoned into its two back posts' own end faces — the same "square tenon against a resolved FaceFrame" path a straight member's own end joinery uses, no synthesizer change. crates/ww-build/tests/bend_joinery.rs's own fixture is the arc-bodied, tangent-at-one-end case.

Pitfalls and diagnostics#

  • axis=x/axis=y, a varying cross-section along the bend, a mid-curve feature or mark, a curved CNC toolpath, and turning a bend (round stock plus a curved spine) are all not built.
  • A spline whose points do not run the whole part (z=0 to z = 0 - size.z) is refused: "a bend's spline must run the whole part, from its top face (z=0) to its foot ...".
  • A join naming a lateral mark on a bent component is refused, naming the two valid end faces (top_sw/bottom_sw's own families).
  • mortise_and_tenon against a standard anchor (top_center, …) is refused: "is a standard anchor, which has a point but no facing (D6)" — use a mark with normal= instead.
  • The built solid's real boundary can stand a millimetre or two past the exact plane the end FaceFrame reports, at a member's own free ends (an existing, documented margin, crates/ww-build/tests/bend_joinery.rs's own header) — a mating part placed flush against that reported plane can show a small, bounded clash there; not a placement bug.

See also#

docs/KDL_AUTHORING.md §6 ("bend"), RFC-0040, ADR-0016 (arc/path2d tessellation), ADR-0032 (ww_geom::spline), ADR-0012 (native/wasm determinism — a bend's own rotation uses libm::atan2/libm::sincos, never the inherent f64 methods), ADR-0028 (grain axis — "follows spine"), turning-and-sections (the sibling cross-section-along-a-straight-length family), joinery-tenons.

Names#

Every name this page declares, how the example library uses it, and the shortest real use.

bend#

feature; node in 1 of 116 examples (1 uses).

Shortest real use, from arched_crest_side_chair.kdl:

bend axis=z plane=xz {
    // A `bend`'s spline must run the whole part from its own top face (z=0) to its
    // foot (z = 0 - open_w, D4's top-down local convention) — the same direction
    // `crates/ww-build/tests/bend.rs`'s own spline fixture uses, not the ascending
    // z this file's own first draft tried (kdl-check's own diagnostic caught it).
    spline {
        point z=0.0                     x=0.0
        point z="0.0 - (open_w / 2.0)"  x="0.0 - crest_arch_rise"
        point z="0.0 - open_w"          x=0.0
    }
}

arc#

node in 19 of 116 examples (65 uses).

Shortest real use, from windsor_fan_back_side_chair.kdl:

arc center_x=rf center_y=cy radius=rf start_angle=0.0 end_angle=180.0

spline#

node in 26 of 116 examples (110 uses); value in 28 of 116 examples (42 uses).

Shortest real use, from adirondack_plank_chair.kdl:

spline { point x=0.0 y=60.0; point x="arm_w * 0.12" y=18.0; point x="arm_w * 0.5" y=0.0; point x="arm_w * 0.88" y=18.0; point x=arm_w y=60.0 }

Settings

Region

A region picks sensible defaults; change any of these separately.

Units

In inches, type lengths the way you say them: 34 1/2, 3/4", 1'-2" or 12.7mm. A length that can't be read is flagged, never rounded to something else.

Paper
Date order
Clock