Rounding: round_corners & smooth_path

Pure-Python port of the path-rounding core of BOSL2’s rounding.scad: round_corners() rounds every corner of a path, and smooth_path() fits a continuous-curvature curve through a path. Both work on 2-D and 3-D paths and are methods on paths and path3d:

Path([[0, 0], [40, 0], [40, 30], [0, 30]]).round_corners(radius=5)
Path([[0, 0], [40, 0], [40, 30], [0, 30]]).round_corners(method="smooth", joint=8)
Path([[0, 0], [10, 30], [30, -10], [50, 20]], closed=False).smooth_path(relsize=0.4)

round_corners supports three corner styles – "circle" (a constant-radius arc), "smooth" (a continuous-curvature bezier, so no curvature discontinuity where the round meets the edge), and "chamfer" (a straight bevel) – sized by exactly one of radius/r (circle only), cut (depth toward the corner), joint (distance back along each edge), or width (chamfer only). k (smooth only) tunes the curvature match. Both functions are pinned point-for-point to the real BOSL2 output in tests/test_pybosl2_reorient.py; the circle case is bit-identical to the toolkit’s original round_corners.

Coverage of BOSL2 rounding.scad

BOSL2 function

Status

Notes

round_corners

ported

round_corners() – all three methods, all four size measures, open/closed, 2-D and 3-D. The roundover-overflow (scale-factor) check is included.

smooth_path

ported (method="edges")

smooth_path() – a bezier fit through the points; the method="corners" variant is not ported.

path_join

not ported

join paths end-to-end with rounded joints – a follow-up.

offset_stroke / offset_sweep (+ os_*) / convex_offset_extrude

not ported

variable-width strokes and rounded-edge extrusions – a large follow-up.

rounded_prism / join_prism / prism_connector / attach_prism / bent_cutout_mask

not ported

the continuous-curvature 3-D prism generators (thousands of lines) – a large follow-up.

Examples

A square rounded three ways (circle, smooth, chamfer), extruded:

from pybosl2 import Path2D

sq = [[0, 0], [40, 0], [40, 30], [0, 30]]
a = Path2D(sq).round_corners(method="circle", radius=6).polygon().linear_extrude(height=4)
b = Path2D(sq).round_corners(method="smooth", joint=10).polygon().linear_extrude(height=4).right(50)
c = Path2D(sq).round_corners(method="chamfer", joint=8).polygon().linear_extrude(height=4).right(100)
(a | b | c).show()
Loading 3-D preview…

⬇ Download STL mesh

A wiggly path smoothed into a flowing ribbon:

from pybosl2 import Path2D

pts = [[0, 0], [10, 30], [30, -10], [50, 20], [70, 0]]
Path2D(pts).smooth_path(relsize=0.4).stroke(width=2).linear_extrude(height=3).show()
Loading 3-D preview…

⬇ Download STL mesh

API reference

Path-rounding core: round_corners and smooth_path (BOSL2 rounding.scad).

class pybosl2.rounding.Roundable[source]

Bases: object

Mixin adding the rounding.scad path operators as methods on Path2D and.

Path3D.

round_corners(radius=None, method=RoundingMethod.CIRCLE, cut=None, joint=None, width=None, curvature=None, closed=None, fn=None, fa=None, fs=None, k=None)[source]

Round every corner of this path (BOSL2 round_corners()).

method is "circle" (a constant-radius arc), "smooth" (a continuous-curvature bezier), or "chamfer" (a straight bevel). Size the roundover with exactly one of radius (circle only), cut (depth toward the corner), joint (distance back from the corner along each edge), or width (chamfer only) – each a scalar or a per-corner list. curvature (smooth only, 0..1) tunes how tight the curvature match is. Works on 2-D and 3-D paths.

Returns:

A Path2D (2-D) or Path3D (3-D).

Parameters:
radius : float | None

method : RoundingMethod

cut : float | Sequence[float] | None

joint : float | Sequence[float] | None

width : float | None

curvature : float | None

closed : bool | None

fn : int | None

fa : float | None

fs : float | None

k : float | None

Return type:

object

Examples

A rounded, smoothed and chamfered square (three copies):

from pybosl2 import Path2D, Path3D
from pybosl2.enums import RoundingMethod

sq = [[0, 0], [40, 0], [40, 40], [0, 40]]
Path2D(sq).round_corners(method=RoundingMethod.SMOOTH, joint=10).polygon().linear_extrude(
    height=4
).show()
Loading 3-D preview…

⬇ Download STL mesh

A 2-D path with circle-rounded corners:

from pybosl2 import Path2D, Path3D
from pybosl2.enums import RoundingMethod

path = Path2D([[0, 0], [20, 0], [20, 10], [10, 15], [0, 10]])
path.round_corners(method=RoundingMethod.CIRCLE, radius=3).polygon().linear_extrude(height=5).show()
Loading 3-D preview…

⬇ Download STL mesh

smooth_path(tangents=None, size=None, relsize=None, splinesteps=10, uniform=False, closed=None)[source]

Fit a smooth continuous-curvature curve through this path (BOSL2 smooth_path(), method=”edges”).

Runs a cubic bezier through every point, matching the path’s tangents, and samples it with splinesteps points per segment. size / relsize bound how far the curve may bow away from the straight path (relsize is a fraction of each segment, default 0.1). The BOSL2 method="corners" variant is not ported.

Returns:

A Path2D (2-D) or Path3D (3-D).

Parameters:
tangents : Sequence[Sequence[float]] | None

size : float | Sequence[float] | None

relsize : float | None

splinesteps : int

uniform : bool

closed : bool | None

Return type:

object

Examples

A wiggly control path smoothed into a flowing curve:

from pybosl2 import Path2D, Path3D

pts = [[0, 0], [10, 30], [30, -10], [50, 20], [70, 0]]
Path2D(pts).smooth_path(relsize=0.4).stroke(width=2).linear_extrude(height=3).show()
Loading 3-D preview…

⬇ Download STL mesh

A sawtooth path smoothed with explicit size and relsize:

from pybosl2 import Path2D, Path3D

path = Path2D([[0, 0], [10, 5], [20, 0], [30, 10]])
path.smooth_path(relsize=0.1).stroke(width=1).linear_extrude(height=3).show()
Loading 3-D preview…

⬇ Download STL mesh

offset_stroke(width=1.0, closed=None, endcap=CapType.ROUND, joint=CapType.ROUND)[source]

Offset this 2-D path to create a thickened outline Region (BOSL2 offset_stroke()).

Parameters:
width : float

closed : bool | None

endcap : CapType

joint : CapType

Return type:

object

offset_sweep(height, bottom=None, top=None, steps=16, caps=CapType.BUTT, style=VNFStyle.MIN_EDGE)[source]

Offset sweep/extrusion of this 2-D shape (BOSL2 offset_sweep()).

Parameters:
height : float

bottom : object

top : object

steps : int

caps : CapsSpec

style : VNFStyle

Return type:

object

convex_offset_extrude(height, bottom=None, top=None, steps=16, caps=CapType.BUTT, style=VNFStyle.MIN_EDGE)[source]

Offset sweep/extrusion of this 2-D shape (BOSL2 convex_offset_extrude()).

Parameters:
height : float

bottom : object

top : object

steps : int

caps : CapsSpec

style : VNFStyle

Return type:

object

rounded_prism(top=None, height=None, joint_top=None, joint_bottom=None, joint_sides=None, curvature_sides=None, steps=16, caps=CapType.BUTT, style=VNFStyle.MIN_EDGE, joint_bot=None, k_sides=None)[source]

Return the rounded prism between this path and a top path (BOSL2 rounded_prism()).

Parameters:
top : Sequence[Sequence[float]] | None

height : float | None

joint_top : float | dict[str, object] | None

joint_bottom : float | dict[str, object] | None

joint_sides : float | list[float] | None

curvature_sides : float | list[float] | None

steps : int

caps : CapsSpec

style : VNFStyle

joint_bot : float | dict[str, object] | None

k_sides : float | list[float] | None

Return type:

object

join_prism(height, fillet=0.0, steps=16, caps=CapType.BUTT, style=VNFStyle.MIN_EDGE)[source]

Join this prism to a base plane with a filleted transition (BOSL2 join_prism()).

Parameters:
height : float

fillet : float

steps : int

caps : CapsSpec

style : VNFStyle

Return type:

object

prism_connector(length, fillet=0.0, fillet1=None, fillet2=None, steps=16, caps=CapType.BUTT, style=VNFStyle.MIN_EDGE)[source]

Construct a filleted prism connecting two objects (BOSL2 prism_connector()).

Parameters:
length : float

fillet : float

fillet1 : float | None

fillet2 : float | None

steps : int

caps : CapsSpec

style : VNFStyle

Return type:

object

attach_prism(length, fillet=0.0, rounding=0.0, steps=16, caps=CapType.BUTT, style=VNFStyle.MIN_EDGE)[source]

Attach a filleted prism with optional rounded end (BOSL2 attach_prism()).

Parameters:
length : float

fillet : float

rounding : float

steps : int

caps : CapsSpec

style : VNFStyle

Return type:

object

bent_cutout_mask(radius, thickness, style=VNFStyle.MIN_EDGE)[source]

Create a mask to generate a round-edged cutout in a cylindrical shell (BOSL2 bent_cutout_mask()).

Parameters:
radius : float

thickness : float

style : VNFStyle

Return type:

object

path_join(other_paths, radius=None, cut=None, joint=None, curvature=None, relocate=True, closed=None, k=None)[source]

Join multiple paths to this path end-to-end (see path_join()).

Parameters:
other_paths : Sequence[Sequence[Sequence[float]]]

radius : float | list[float] | None

cut : float | list[float] | None

joint : float | list[float] | None

curvature : float | list[float] | None

relocate : bool

closed : bool | None

k : float | list[float] | None

Return type:

object