NURBS: curves & surfaces

Pure-Python port of the NURBS evaluation API from BOSL2’s nurbs.scad: evaluate a NURBS curve, sample a NURBS surface patch, mesh a patch into a VNF, and elevate a curve’s degree. All three flavours – "clamped", "open" and "closed" – are supported, with weights (rational NURBS), knot multiplicities, and explicit knot vectors.

nurbs_curve() returns a Path (2-D control points) or Path3D (3-D), so the result carries the full path/extrude/stroke API; nurbs_vnf() returns a VNF. Every case is pinned point-for-point to the real BOSL2 output in tests/test_bosl2_reorient.py – including the classic rational-NURBS sphere.

The first argument to any of these may be a NURBS parameter list [type, degree, control, knots, mult, weights] instead of separate arguments.

Coverage of BOSL2 nurbs.scad

BOSL2 function

Status

Notes

nurbs_curve

ported

nurbs_curve() – clamped/open/closed, weights, mult, explicit knots, splinesteps or u. Returns a Path / Path3D (a scalar u returns one point).

nurbs_patch_points

ported

nurbs_patch_points() – sample a surface on a grid (splinesteps or u/v); per-direction degree/type/mult/knots.

nurbs_vnf

ported

nurbs_vnf() – mesh a patch (built on vnf_vertex_array), with style / reverse / caps.

nurbs_elevate_degree

ported

nurbs_elevate_degree() – raise a clamped/open curve’s degree (collocation at Greville points).

is_nurbs_patch

ported

is_nurbs_patch().

nurbs_interp / nurbs_interp_surface

not ported

the constrained least-squares interpolation solvers (fit a NURBS through given points with derivative/curvature/corner constraints) – thousands of lines of custom linear algebra; a large follow-up.

debug_nurbs / debug_nurbs_interp

not ported

preview/annotation display modules.

Examples

A cubic clamped NURBS curve, swept into a tube:

ctrl = [[0, 0, 0], [10, 20, 5], [30, -10, 10], [50, 20, 0], [60, 0, 15]]
nurbs_curve(ctrl, 3, splinesteps=12).stroke(width=3).show()

⬇ Download STL mesh

A cubic B-spline surface patch meshed into a sheet:

patch = [
    [[-50, 50, 0], [-16, 50, 20], [16, 50, 20], [50, 50, 0]],
    [[-50, 16, 20], [-16, 16, 40], [16, 16, 40], [50, 16, 20]],
    [[-50, -16, 20], [-16, -16, 40], [16, -16, 40], [50, -16, 20]],
    [[-50, -50, 0], [-16, -50, 20], [16, -50, 20], [50, -50, 0]],
]
nurbs_vnf(patch, 3, splinesteps=10).polyhedron().show()

⬇ Download STL mesh

A sphere as a rational NURBS surface (weights + repeated knots):

patch = [[[0, 0, 1]] * 7,
         [[2, 0, 1], [2, 4, 1], [-2, 4, 1], [-2, 0, 1], [-2, -4, 1], [2, -4, 1], [2, 0, 1]],
         [[2, 0, -1], [2, 4, -1], [-2, 4, -1], [-2, 0, -1], [-2, -4, -1], [2, -4, -1], [2, 0, -1]],
         [[0, 0, -1]] * 7]
weights = [[w / 9 for w in row] for row in
           [[9, 3, 3, 9, 3, 3, 9], [3, 1, 1, 3, 1, 1, 3], [3, 1, 1, 3, 1, 1, 3], [9, 3, 3, 9, 3, 3, 9]]]
nurbs_vnf(patch, 3, weights=weights, knots=[None, [0, 0.5, 0.5, 0.5, 1]], splinesteps=12).polyhedron().show()

⬇ Download STL mesh

API reference

bosl2.nurbs.nurbs_curve(control, degree=None, splinesteps=None, u=None, mult=None, weights=None, type='clamped', knots=None)[source]

Evaluate a NURBS curve, returning its points (BOSL2 nurbs_curve()).

Give either splinesteps (uniform samples between knots, with a sample at every knot) or u (parameter values in [0, 1]). weights makes it a rational NURBS; mult / knots give knot multiplicities / an explicit knot vector; type is "clamped" (default), "open" or "closed". The first argument may instead be a NURBS parameter list [type, degree, control, knots, mult, weights].

Returns:

A Path (2-D control points) or Path3D (3-D). A single scalar u returns just that point as a plain list.

Parameters:
  • degree (int | None)

  • splinesteps (int | None)

  • type (str)

Examples

A cubic clamped NURBS curve through five control points, swept into a tube:

ctrl = [[0, 0, 0], [10, 20, 5], [30, -10, 10], [50, 20, 0], [60, 0, 15]]
nurbs_curve(ctrl, 3, splinesteps=12).stroke(width=3).show()

⬇ Download STL mesh

bosl2.nurbs.nurbs_patch_points(patch, degree=None, splinesteps=None, u=None, v=None, weights=None, type=('clamped', 'clamped'), mult=(None, None), knots=(None, None))[source]

Sample a NURBS surface patch on a grid of points (BOSL2 nurbs_patch_points()).

patch is a rectangular array of control points (or a NURBS parameter list). degree, splinesteps, type, mult and knots are scalars applied to both directions or 2-lists [u_dir, v_dir]. Give splinesteps, or u and v parameter lists. weights is a matrix the size of patch.

Returns:

A grid (list of rows) of [x, y, z] points.

Parameters:
  • degree (int | None)

  • splinesteps (int | None)

  • type (str)

bosl2.nurbs.nurbs_vnf(patch, degree=None, splinesteps=16, weights=None, type='clamped', mult=None, knots=None, style='default', reverse=False, caps=None, cap1=None, cap2=None)[source]

Mesh a NURBS surface patch into a VNF (BOSL2 nurbs_vnf()).

Samples the patch with nurbs_patch_points() and builds the mesh with vertex_array(), wrapping the rows/columns for "closed" directions.

Parameters:
  • patch – control-point grid or a NURBS parameter list

  • degree (int | None) – scalar or [u, v] degree

  • splinesteps (int) – scalar or [u, v] samples per knot span (default 16)

  • weights/type/mult/knots – as for nurbs_patch_points()

  • style (str) – vertex_array() triangulation style

  • reverse (bool) – flip every face normal

  • caps/cap1/cap2 – cap a ["clamped","closed"] / ["closed","clamped"] surface

  • type (str)

Examples

A cubic B-spline surface patch meshed into a solid:

patch = [
    [[-50, 50, 0], [-16, 50, 20], [16, 50, 20], [50, 50, 0]],
    [[-50, 16, 20], [-16, 16, 40], [16, 16, 40], [50, 16, 20]],
    [[-50, -16, 20], [-16, -16, 40], [16, -16, 40], [50, -16, 20]],
    [[-50, -50, 0], [-16, -50, 20], [16, -50, 20], [50, -50, 0]],
]
nurbs_vnf(patch, 3).polyhedron().show()

⬇ Download STL mesh

bosl2.nurbs.nurbs_elevate_degree(control, degree=None, knots=None, type='clamped', times=1, weights=None, mult=None)[source]

Raise a NURBS/B-spline curve’s degree by times, returning a parameter list (BOSL2 nurbs_elevate_degree()).

Returns [type, new_degree, new_control, new_knots, None, new_weights]. Only "clamped" and "open" splines are supported (as in BOSL2). Rational curves are elevated in homogeneous space and de-homogenised.

Parameters:
  • degree (int | None)

  • type (str)

  • times (int)

bosl2.nurbs.is_nurbs_patch(x)[source]

True if x looks like a NURBS patch: a rectangular 2-D array of points (BOSL2 is_nurbs_patch()).

Return type:

bool