Paths & Splines#
Spline segments, named compound paths, and derived circle paths
Names: path cut_path spline circle line arc polyline
When to use#
A shaped edge or a pierced cut-out that is not a straight line or a round: a cloud lift on
an apron, a serpentine rail, a vase-shaped splat, a scalloped edge, a freeform window. Use
spline for a smooth curve through points you choose, line/arc/polyline for the
straight and circular parts, and chain them in one cut_path (a compound path). Name a
compound path once with path <Name> { ... } when several cut_paths reuse it. Use circle
for a plain round hole of any size (a hole is simpler for a drilled one).
Syntax#
cut_path depth= [face=] [keep="outside"|"inside"] [path=Name] { <segment> ... }
path Name <kind> <props> // one named segment
path Name { <segment> ... } // a named compound path
line from_x= from_y= to_x= to_y=
arc center_x= center_y= radius= start_angle= end_angle=
polyline { point x= y= ; ... }
spline [closed=#true] [tolerance=<mm> | samples=<n>] { point x= y= ; ... }
circle center_x= center_y= radius=
splinepasses through everypoint.tolerance=(default0.01length units) is the largest gap between the cut edge and the true curve;samples=instead fixes the chords per span (whole number, at most 1024). Give one, not both. The curve is flattened to chords once, the same way every time, so the result is deterministic and native/wasm identical.- An open spline closes along its chord, like a lone
arc; in a compound path it chains end to start (each segment's end must meet the next one's start).closed=#trueis a whole loop and cannot chain. Acircleis a whole loop too. - A
cut_pathremoves the closed region (keep="outside", the default);keep="inside"keeps only the region, making it the part's new footprint.
Example#
// A cloud lift cut into the lower edge of an apron: straight sides, a spline between them.
project name="Cloud lift" units=mm schema_version=1 {
materials { material Oak type=hardwood }
component Apron {
stock Oak 190.0 22.0 90.0
// Named once as a compound path, then cut.
path Cloud {
line from_x=30.0 from_y=-10.0 to_x=30.0 to_y=0.0
spline {
point x=30.0 y=0.0
point x=75.0 y=34.0
point x=115.0 y=34.0
point x=160.0 y=0.0
}
line from_x=160.0 from_y=0.0 to_x=160.0 to_y=-10.0
}
cut_path depth=0.0 face=neg_y path=Cloud
// A closed spline: a pierced, smooth-edged window, finer than the default.
cut_path depth=0.0 face=neg_y {
spline closed=#true tolerance=0.05 {
point x=60.0 y=45.0
point x=80.0 y=65.0
point x=100.0 y=45.0
point x=80.0 y=25.0
}
}
// A round hole by centre and radius.
cut_path depth=0.0 face=neg_y { circle center_x=20.0 center_y=65.0 radius=8.0 }
}
assembly Rail {
part Apron instance=Apron { pos x=0.0 y=0.0 z=0.0 }
}
}
Pitfalls and diagnostics#
- The region must have an enclosed area and not cross itself. A wave that dips below its own
chord is reported as a skip ("the closed path crosses itself"); lift the end points or close
the loop yourself with a
line. - Cut corners must lie outside the stock so the cut breaks cleanly through the edge: the
cloud lift's low corners are at
y=-10, below the true edge aty=0. - Consecutive spline points that coincide are refused. A curve of
closed=#trueneeds at least three points, an open one at least two. - A spline is drawn through the points you give, so overshoot comes from the points, not the maths: space them evenly, and add a point where the curve bends sharply.
closed=#truecombined with other segments,tolerance=together withsamples=, a non-wholesamples=, and a tolerance so fine that a span would need more than 1024 chords are all refused with the cause named.splineandcircleare path segments, not features: written outside acut_path/paththey are reported as such.kdl-checkpassing says only that the file is well formed; it cannot see whether a path closes or is sensible. Runww check.- Not built: a bent or curved part (RFC-0040), G02/G03 toolpath arcs, features placed along a path.
See also#
docs/KDL_AUTHORING.md§7,cut_pathdocs/adr/0032-spline-and-compound-paths.md,docs/adr/0016-path-geometry.mddocs/rfc/0120-curved-path-geometry.mddocs/agent-reference/nodes.md(cut_path),tasks.md("cut a curved outline")
Names#
Every name this page declares, how the example library uses it, and the shortest real use.
path#
feature, word-valued property; node in 9 of 116 examples (15 uses); property in 9 of 116 examples (19 uses).
Shortest real use, from jacobean_joint_stool.kdl:
path ArchLong {
line from_x="span_w * 0.10" from_y=-5.0 to_x="span_w * 0.10" to_y=0.0
spline {
point x="span_w * 0.10" y=0.0
point x="span_w * 0.30" y="arch_rise * 0.80"
point x="span_w * 0.50" y=arch_rise
point x="span_w * 0.70" y="arch_rise * 0.80"
point x="span_w * 0.90" y=0.0
}
line from_x="span_w * 0.90" from_y=0.0 to_x="span_w * 0.90" to_y=-5.0
}
cut_path#
feature; node in 50 of 116 examples (239 uses).
Shortest real use, from ming_waisted_corner_leg_table.kdl:
cut_path depth=0.0 face=neg_y path=Hoof
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 }
circle#
node in 40 of 116 examples (933 uses).
Shortest real use, from windsor_round_stool.kdl:
circle r=rf
line#
node in 33 of 116 examples (256 uses).
Shortest real use, from postmodern_flat_silhouette_chair.kdl:
line from_x=w from_y=0.0 to_x=w to_y=seat_h
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
polyline#
node in 21 of 116 examples (91 uses).
Shortest real use, from incised_walnut_washstand.kdl:
polyline { point x="9.0 + (0.0000)" y="9.0 + (1.0000)"; point x="face_w - 9.0 + (0.0000)" y="9.0 + (1.0000)"; point x="face_w - 9.0 - (0.0000)" y="9.0 - (1.0000)"; point x="9.0 - (0.0000)" y="9.0 - (1.0000)" }