Bezier curves, paths and surfaces

class bosl2.beziers.Bezier(control_points=())[source]

Bases: list

A Bezier curve or path: a list of control points, with every bezier operation as a method.

Subclasses list (the same trick as bosl2.paths.Path), so it is a drop-in for the raw control-point lists the toolkit passes around, while giving the chained object form:

Bezier([[44, 5], [48, 6], [64, -15]]).points([0.2 * i for i in range(6)])
Bezier.flatten([Bezier.begin([0, 0], -20, 0.4), Bezier.end([1, 0], 230, 1)]).curve(20)

A curve is one set of control points (degree len - 1). A path is a flat list of degree-N curves sharing endpoints (len % N == 1); the path_* methods interpret the Bezier that way. The point-valued methods return numpy ndarrays; the control-point builders (begin/tang/joint/end) are staticmethods returning raw ndarray groups that flatten concatenates into a new Bezier.

Parameters:

control_points – the control points (anything array-like; 2-D or 3-D points)

Examples

Sweeping a circular profile along a 3-D bezier curve into a solid tube:

circle = [[2 * math.cos(t), 2 * math.sin(t)] for t in np.linspace(0, 2 * math.pi, 24, endpoint=False)]
tube = Bezier([[0, 0, 5], [0, 0, 20], [25, 12, 15], [30, 4, 6]]).sweep(circle, splinesteps=24)
tube.polyhedron().show()

⬇ Download STL mesh

property array: ndarray

The control points as an (N, dim) numpy array.

points(u)[source]

Evaluate this curve’s control points at parameter(s) u (each in [0, 1]).

Returns an ndarray of points (or a length-dim ndarray for a scalar u).

curve(splinesteps=16, endpoint=True)[source]

Sample splinesteps segments (splinesteps+1 points) uniformly along the curve.

Parameters:
  • splinesteps (int)

  • endpoint (bool)

Return type:

ndarray

derivative(u, order=1)[source]

The order-th derivative of the curve at parameter(s) u, as an ndarray.

Parameters:

order (int)

tangent(u)[source]

Unit tangent vector(s) at parameter(s) u, as an ndarray.

curvature(u)[source]

Curvature value(s) at parameter(s) u (inverse tangent-circle radius).

closest_point(pt, max_err=0.01, u=0.0, end_u=1.0)[source]

The parameter u of the point on this curve closest to pt (approximate).

Parameters:
  • max_err (float)

  • u (float)

  • end_u (float)

Return type:

float

length(start_u=0.0, end_u=1.0, max_deflect=0.01)[source]

Approximate arc length of the curve between start_u and end_u.

Parameters:
  • start_u (float)

  • end_u (float)

  • max_deflect (float)

Return type:

float

line_intersection(line)[source]

The u values where this 2-D curve crosses line (two points), each in [0, 1].

Return type:

list

path_points(curveind, u, N=3)[source]

Evaluate curve number curveind of this bezier PATH at parameter(s) u.

Parameters:
  • curveind (int)

  • N (int)

path_curve(splinesteps=16, N=3, endpoint=True)[source]

Sample this bezier PATH (degree-N curves sharing endpoints, len % N == 1) into points.

Kept as the plain concatenation of each segment’s samples (unlike BOSL2’s bezpath_curve, which additionally merges collinear/duplicate points and can emit derivatives) so the point set the toolkit’s existing outlines are built from does not change.

Parameters:
  • splinesteps (int)

  • N (int)

  • endpoint (bool)

Return type:

ndarray

path_closest_point(pt, N=3, max_err=0.01)[source]

[segnum, u] for the closest position on this bezier PATH to pt (approximate).

Parameters:
  • pt (Sequence[float])

  • N (int)

  • max_err (float)

Return type:

tuple[int, float]

path_length(N=3, max_deflect=0.001)[source]

Approximate arc length of this bezier PATH.

Parameters:
  • N (int)

  • max_deflect (float)

Return type:

float

close_to_axis(axis='X', N=3)[source]

Close this 2-D bezier PATH down to the given axis (“X” or “Y”), returning a new Bezier.

Parameters:
  • axis (str)

  • N (int)

Return type:

Bezier

path_offset(offset, N=3)[source]

Close this 2-D bezier PATH with a reversed copy offset by offset [x, y], returning a Bezier.

Parameters:
  • offset (Sequence[float])

  • N (int)

Return type:

Bezier

classmethod from_path(path, closed=False, tangents=None, uniform=False, size=None, relsize=None)[source]

Cubic bezier PATH through every point of path, matching its tangents (BOSL2 path_to_bezpath).

size/relsize control how far the curve may deviate from the input path (relsize is a fraction of the segment length, default 0.1). Tangents default to Path tangents.

Parameters:
  • path (Sequence[Sequence[float]])

  • closed (bool)

  • tangents (Sequence[Sequence[float]] | None)

  • uniform (bool)

  • size (float | None)

  • relsize (float | None)

Return type:

Bezier

sweep(shape, splinesteps=16, N=3, method='incremental', endpoint=True, normal=None, closed=False, twist=0.0, twist_by_length=True, scale=1.0, scale_by_length=True, symmetry=1, last_normal=None, caps=None, style='min_edge', transforms=False)[source]

Sweep the 2-D shape along this bezier CURVE into a VNF (BOSL2 bezier_sweep()).

Uses the curve’s exact derivatives as tangents (better end joints than path_sweep’s approximation). N is ignored (present for signature parity with bezpath_sweep()).

Parameters:
  • shape (ndarray)

  • splinesteps (int)

  • N (int)

  • method (str)

  • endpoint (bool)

  • normal (Sequence[float] | None)

  • closed (bool)

  • twist (float)

  • twist_by_length (bool)

  • scale (float)

  • scale_by_length (bool)

  • symmetry (int)

  • style (str)

  • transforms (bool)

bezpath_sweep(shape, splinesteps=16, N=3, method='incremental', endpoint=True, normal=None, closed=False, twist=0.0, twist_by_length=True, scale=1, scale_by_length=True, symmetry=1, last_normal=None, caps=None, style='min_edge', transforms=False)[source]

Sweep the 2-D shape along this bezier PATH into a VNF (BOSL2 bezpath_sweep()).

Parameters:
  • splinesteps (int)

  • N (int)

  • method (str)

  • endpoint (bool)

  • closed (bool)

  • twist (float)

  • twist_by_length (bool)

  • scale_by_length (bool)

  • symmetry (int)

  • style (str)

  • transforms (bool)

static begin(pt, a, radius=None, p=None)[source]

The starting endpoint and control point of a cubic bezier path, as a (2, dim) ndarray.

Parameters:
  • radius (float | None)

  • p (float | None)

Return type:

ndarray

static tang(pt, a, radius1=None, radius2=None, p=None)[source]

A smooth joint (approaching center, fixed point, departing center) – the two cps collinear with the fixed point – in a cubic bezier path, as a (3, dim) ndarray.

Parameters:
  • radius1 (float | None)

  • radius2 (float | None)

  • p (float | None)

Return type:

ndarray

static joint(pt, a1, a2, radius1=None, radius2=None, p1=None, p2=None)[source]

A disjoint corner joint (approaching center, fixed point, departing center) with the two cps in independent directions, in a cubic bezier path, as a (3, dim) ndarray.

Parameters:
  • radius1 (float | None)

  • radius2 (float | None)

  • p1 (float | None)

  • p2 (float | None)

Return type:

ndarray

static end(pt, a, radius=None, p=None)[source]

The approaching control point and endpoint of a cubic bezier path, as a (2, dim) ndarray.

Parameters:
  • radius (float | None)

  • p (float | None)

Return type:

ndarray

debug(width=1.0, N=3)[source]

Native geometry visualizing this bezier PATH: the swept curve, control net and control points (a functional port of BOSL2’s debug_bezier() module; requires the real app).

Parameters:
  • width (float)

  • N (int)

static flatten(groups)[source]

Concatenate a list of control-point groups (from begin/tang/joint/end) into one Bezier.

Return type:

Bezier

class bosl2.beziers.BezierPatch(rows=())[source]

Bases: list

A rectangular Bezier surface patch: a 2-D array (rows x cols) of 3-D control points.

Evaluate it with points(), get surface normals with normals(), and mesh it into a VNF with vnf() (which renders via polyhedron()). Build several patches into one VNF with to_vnf() (BOSL2 bezier_vnf), and make a flat patch with flat() (BOSL2 bezier_patch_flat):

BezierPatch.flat([100, 100]).vnf(splinesteps=8).polyhedron()

Ported from beziers.scad’s Bezier SURFACE section: bezier_patch_points/_normals/_reverse/ _flat, is_bezier_patch, and bezier_vnf. NOT ported: bezier_vnf_degenerate_patch (handles collapsed-edge patches), bezier_sheet (offset-shell), and bezier_sweep/bezpath_sweep (need BOSL2’s un-ported path_sweep), plus the debug_* visualization modules.

Parameters:

rows – a list of rows, each a list of [x, y, z] control points

Examples

A bezier surface patch, thickened into a solid sheet:

patch = [
    [[-50, -50, 0], [-16, -50, 20], [16, -50, -20], [50, -50, 0]],
    [[-50, -16, 20], [-16, -16, 20], [16, -16, -20], [50, -16, 20]],
    [[-50, 16, 20], [-16, 16, -20], [16, 16, 20], [50, 16, 20]],
    [[-50, 50, 0], [-16, 50, -20], [16, 50, 20], [50, 50, 0]],
]
BezierPatch(patch).sheet([0, -6], splinesteps=16).polyhedron().show()

⬇ Download STL mesh

property array: ndarray

The control points as an (rows, cols, dim) numpy array.

static is_patch(x)[source]

True if x looks like a bezier patch: a rectangular 2-D array of point vectors.

Return type:

bool

points(u, v)[source]

Sample the patch at parameter(s) u (inner/column axis) and v (outer/row axis).

Scalar u and v give one point; lists/ranges give a rectangular (len(u) x len(v)) grid.

normals(u, v)[source]

Unit surface normal(s) at parameter(s) u, v (same shape rules as points()).

reverse()[source]

The patch with each row reversed (flips the surface orientation).

Return type:

BezierPatch

vnf(splinesteps=16, style='default')[source]

Mesh this patch into a VNF. splinesteps is a scalar or [u, v].

Parameters:
  • splinesteps (int)

  • style (str)

Return type:

VNF

static to_vnf(patches, splinesteps=16, style='default')[source]

One patch or a list of patches into a single VNF (BOSL2 bezier_vnf()).

Parameters:
  • splinesteps (int)

  • style (str)

Return type:

VNF

static flat(size, N=1, spin=0.0, orient=[0.0, 0.0, 1.0], trans=(0.0, 0.0, 0.0))[source]

A flat rectangular degree-N patch of the given size, centered on XY, then reoriented.

Parameters:
  • N (int)

  • spin (float)

Return type:

BezierPatch

sheet(delta, splinesteps=16, style='default')[source]

A thin sheet from this patch, offsetting along the surface normals by delta (BOSL2 bezier_sheet()).

delta is a 2-vector [d0, diameter1] of the two offset distances (a scalar d means [0, -d]).

Parameters:
  • delta (float)

  • splinesteps (int)

  • style (str)

Return type:

VNF

vnf_degenerate(splinesteps=16, reverse=False, return_edges=False)[source]

VNF for a degenerate patch (some corners/edges collapsed), avoiding excess triangles.

BOSL2 bezier_vnf_degenerate_patch(). With return_edges returns [vnf, edges] where edges is [left, right, top, bottom] point lists.

Parameters:
  • splinesteps (int)

  • reverse (bool)

  • return_edges (bool)

debug(splinesteps=16, showcps=True, showdots=False, showpatch=True, size=None, style='default')[source]

Native geometry visualizing this patch: the surface plus control points/lines (BOSL2 debug_bezier_patches()).

Parameters:
  • splinesteps (int)

  • showcps (bool)

  • showdots (bool)

  • showpatch (bool)

  • style (str)

bosl2.beziers.debug_bezier_patches(patches, size=None, splinesteps=16, showcps=True, showdots=False, showpatch=True, style='default')[source]

Native geometry showing bezier patches: surfaces, control points and control-net lines.

A functional port of BOSL2’s debug_bezier_patches() module – returns a combined native solid (requires the real app; builds on VNF.polyhedron() and the ported path_sweep tube).

Parameters:
  • splinesteps (int)

  • showcps (bool)

  • showdots (bool)

  • showpatch (bool)

  • style (str)