Sweeps (skin)

Pure-Python port of the surface generators from BOSL2’s skin.scad — every one builds a VNF you render with .polyhedron().

Coverage of BOSL2 skin.scad

BOSL2 function

Status

Notes

sweep(shape, transforms)

ported

sweep()

path_sweep(shape, path)

ported

path_sweep() — methods incremental / manual / natural, twist, scale (scalar / [x, y] / per-point / Nx2), open & closed paths, flat caps, user tangents, and the transforms=True mode

skin(profiles, slices)

ported

skin()direct and reindex methods

linear_sweep(region, h)

ported

linear_sweep() — single outline, with twist / scale / shift / caps

rotate_sweep(shape, angle)

ported

rotate_sweep()

spiral_sweep(poly, h, r)

ported

spiral_sweep() — without the lead-in taper options

path_sweep2d(shape, path)

ported

path_sweep2d() — 2-D shape along a 2-D path (mitre offset; local creases handled up to the path’s tightest radius)

rot_resample(rotlist, n)

ported

rot_resample() — resample a transform list along its screw motion, with rot_decode / rot_inverse in bosl2.transforms

subdivide_and_slice / slice_profiles

ported

subdivide_and_slice(), slice_profiles()

skin() distance / tangent methods

not ported

use direct / reindex (they need the dynamic-programming vertex matcher)

sweep_attach(), anchors

not ported

need the BOSL2 attachment/anchor system

textures (texture(), tex_*)

not ported

the whole texturing engine

rounded / chamfered “fancy” caps

not ported

use flat caps, or a native end treatment

region shapes with holes

not ported

use a native linear_extrude / CSG for holed extrusions

rot_resample() / associate_vertices() helpers

not ported

only needed by the un-ported matching methods

API reference

bosl2.skin.path3d(path)[source]

Pad a 2-D (or 3-D) point list to 3-D with z=0.

The coordinates are converted to plain Python floats, not left as whatever the input held: a numpy row in would otherwise leak np.float64 scalars out of an annotation that promises float, and those raise SystemError/TypeError at the native FFI boundary (see the note in bosl2/paths.py).

Parameters:

path (Sequence[Sequence[float]])

Return type:

list[list[float]]

bosl2.skin.clockwise_polygon(poly)[source]

poly wound clockwise (reversed if its signed area is positive/CCW).

Parameters:

poly (Sequence[Sequence[float]])

Return type:

list[Sequence[float]]

bosl2.skin.frame_map(x=None, y=None, z=None)[source]

The 4x4 rotation whose columns are the given orthonormal axes (BOSL2 frame_map()).

Give any two of x/y/z (as 3-vectors); the third is filled in by the cross product.

Parameters:
  • x (Sequence[float] | None)

  • y (Sequence[float] | None)

  • z (Sequence[float] | None)

Return type:

ndarray

bosl2.skin.CapsSpec = bool | typing.Sequence[bool] | None

one bool for both ends, a [cap1, cap2] pair for each end separately, or None to take the call’s own default. Every sweep/skin entry point accepts all three spellings, exactly as BOSL2 does – see _norm_caps().

Type:

A BOSL2 caps= argument

bosl2.skin.sweep(shape, transforms, closed=False, caps=None, style='min_edge')[source]

Apply each 4x4 transform to the 2-D shape and skin the resulting profiles into a VNF.

Parameters:
  • shape (Sequence[Sequence[float]]) – a 2-D polygon (list of [x, y] points)

  • transforms (Sequence[Sequence[Sequence[float]]]) – list of 4x4 matrices, one per cross section along the path

  • closed (bool) – the sweep loops back on itself (no caps)

  • caps (bool | Sequence[bool] | None) – cap the open ends (default: True/True open, none closed); bool or [bool, bool]

  • style (str) – vnf_vertex_array quad-subdivision style

Return type:

VNF

bosl2.skin.path_sweep(shape, path, method='incremental', normal=None, closed=False, twist=0.0, twist_by_length=True, scale=(1.0, 1.0), scale_by_length=True, symmetry=1, last_normal=None, tangent=None, uniform=True, relaxed=False, caps=None, style='min_edge', transforms=False)[source]

Sweep the 2-D shape along the 2-D/3-D path, returning a VNF (or the transform list).

method orients the cross section: “incremental” (rotation-minimizing frame), “manual” (using normal as a per-point normal list), or “natural” (the path’s own normal). twist (degrees) and scale (scalar, 2-vector, per-point vector, or Nx2) are interpolated along the path. See BOSL2 path_sweep() for the full semantics.

Examples

Sweeping a small square profile along a helical path into a solid:

square = [[-3, -3], [3, -3], [3, 3], [-3, 3]]
helix = [[10 * math.cos(t), 10 * math.sin(t), t * 3] for t in np.linspace(0, 3 * math.pi, 40)]
path_sweep(square, helix).polyhedron().show()

⬇ Download STL mesh

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

  • path (Sequence[Sequence[float]])

  • method (str)

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

  • closed (bool)

  • twist (float)

  • twist_by_length (bool)

  • scale (tuple[float, float])

  • scale_by_length (bool)

  • symmetry (int)

  • last_normal (Sequence[float] | None)

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

  • uniform (bool)

  • relaxed (bool)

  • caps (bool | Sequence[bool] | None)

  • style (str)

  • transforms (bool)

bosl2.skin.slice_profiles(profiles, slices, closed=False)[source]

Interpolate slices extra profiles between each consecutive pair (BOSL2 slice_profiles()).

slices is a count (or a per-segment list). The profiles must all be equal-length point lists; the interpolation is vertex-by-vertex.

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

  • slices (int)

  • closed (bool)

Return type:

list[list[float]]

bosl2.skin.skin(profiles, slices, refine=1.0, method='direct', sampling=None, caps=None, closed=False, style='min_edge', z=None)[source]

Blend a stack of 2-D/3-D profiles into a skinned surface, returning a VNF (BOSL2 skin()).

Consecutive profiles are connected vertex-to-vertex; slices extra interpolated profiles are inserted between each pair to smooth the transition. Profiles of differing point counts are resampled up to the largest (via Path._subdivide_path()).

Parameters:
  • profiles (Sequence[Sequence[Sequence[float]]]) – list of >= 2 closed profiles (each a list of points). If 2-D, give matching z.

  • slices (int) – number of interpolated profiles inserted between each pair (int or per-gap list)

  • refine (float) – subdivide every profile by this factor before skinning (default 1)

  • method (str) – “direct” (connect vertex i to vertex i) or “reindex” (rotate each profile to best-align with the previous). The “distance”/”tangent” vertex-matching methods are not ported.

  • sampling (str | None) – “length” or “segment” resampling (default “length”)

  • caps (bool | Sequence[bool] | None) – cap the ends (default: True for open, False for closed); bool or [bool, bool]

  • closed (bool) – the stack loops back to the first profile (default False)

  • style (str) – vnf_vertex_array quad-subdivision style

  • z (Sequence[float] | None) – per-profile Z heights, required when the profiles are 2-D

Return type:

VNF

Examples

Skinning a round profile up to a square one (a lofted transition):

circle = [[6 * math.cos(t), 6 * math.sin(t)] for t in np.linspace(0, 2 * math.pi, 24, endpoint=False)]
square = [[-8, -8], [8, -8], [8, 8], [-8, 8]]
skin([circle, square], slices=20, method="reindex", z=[0, 25]).polyhedron().show()

⬇ Download STL mesh

bosl2.skin.linear_sweep(region, height=None, twist=0.0, scale=1, shift=(0.0, 0.0), slices=None, caps=None, style='default', center=None)[source]

Extrude a 2-D outline to height with optional twist / scale / shift (BOSL2 linear_sweep()).

A single closed outline (a Path or point list) is supported – for a region with holes use a native linear_extrude instead. The bottom sits on Z=0 unless center is True.

Parameters:
  • region (Sequence[Sequence[float]]) – the 2-D outline to extrude (a closed path)

  • height (float | None) – extrusion height (aliases: height; default 1)

  • twist (float) – total twist over the height, in degrees (default 0)

  • scale – scale of the top relative to the bottom (scalar or [x, y]; default 1)

  • shift – [x, y] offset of the top relative to the bottom (default [0, 0])

  • slices (int | None) – number of intermediate layers (default: enough for ~5 deg of twist each)

  • caps (bool | Sequence[bool] | None) – cap the ends (default True); bool or [bool, bool]

  • center (bool | None) – center the extrusion on Z (default False -> base on Z=0)

  • style (str) – vnf_vertex_array quad-subdivision style

Return type:

VNF

Examples

A twisting, tapering square column:

square = [[-10, -10], [10, -10], [10, 10], [-10, 10]]
linear_sweep(square, height=40, twist=120, scale=0.4).polyhedron().show()

⬇ Download STL mesh

bosl2.skin.rotate_sweep(shape, angle=360.0, caps=None, closed=None, style='min_edge', start=0.0)[source]

Revolve a 2-D shape (in the X+ half-plane, x=radius, y=height) around the Z axis (BOSL2 rotate_sweep()).

A closed shape profile makes a solid of revolution; an open path with caps is first closed to the axis. A full 360-degree revolution loops seamlessly; a partial angle end-caps the sweep.

Parameters:
  • shape (Sequence[Sequence[float]]) – the 2-D profile to revolve (x >= 0)

  • angle (float) – revolution angle in degrees, 0 < angle <= 360 (default 360)

  • caps (bool | Sequence[bool] | None) – end-cap a partial revolution / close an open profile to the axis (default: angle < 360)

  • closed (bool | None) – legacy inverse of caps (give one or the other)

  • style (str) – vnf_vertex_array quad-subdivision style

  • start (float) – starting angle in degrees (default 0)

Return type:

VNF

Examples

Revolving a rounded profile into a spool:

profile = [[4, -10], [12, -10], [12, -6], [7, -2], [7, 2], [12, 6], [12, 10], [4, 10]]
rotate_sweep(profile, 360).polyhedron().show()

⬇ Download STL mesh

bosl2.skin.spiral_sweep(poly, height, radius=None, turns=1.0, radius1=None, radius2=None, diameter=None, diameter1=None, diameter2=None, center=True, style='min_edge')[source]

Sweep a 2-D cross-section poly along a helix (BOSL2 spiral_sweep(), without lead-in tapers).

poly’s X is the radial offset from the helix radius and its Y is the vertical offset, so a small wire cross-section becomes a spring/thread. The lead-in taper options are not ported.

Parameters:
  • poly (Sequence[Sequence[float]]) – the 2-D wire cross-section (closed path)

  • height (float) – total height of the spiral

  • radius/diameter – helix radius/diameter (or per-end radius1/radius2 / diameter1/diameter2 for a conical spiral)

  • turns (float) – number of turns (default 1)

  • center (bool) – center the spiral on Z (default True)

  • style (str) – vnf_vertex_array quad-subdivision style

  • radius (float | None)

  • radius1 (float | None)

  • radius2 (float | None)

  • diameter (float | None)

  • diameter1 (float | None)

  • diameter2 (float | None)

Return type:

VNF

Examples

A rectangular-section coil spring:

section = [[-1.2, -1.2], [1.2, -1.2], [1.2, 1.2], [-1.2, 1.2]]
spiral_sweep(section, height=40, radius=12, turns=5).polyhedron().show()

⬇ Download STL mesh

bosl2.skin.subdivide_and_slice(profiles, slices, numpoints=None, method='length', closed=False)[source]

Resample every profile up to numpoints then interpolate slices between them (BOSL2 subdivide_and_slice()).

numpoints defaults to the largest profile’s length; “lcm” uses the least common multiple of the profile lengths. Returns the stacked list of (equal-length) profiles.

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

  • slices (int)

  • method (str)

  • closed (bool)

Return type:

list[list[float]]

bosl2.skin.path_sweep2d(shape, path, closed=False, caps=None, quality=1, style='min_edge')[source]

Sweep a 2-D shape along a 2-D path, mapping the shape’s Y to Z (BOSL2 path_sweep2d()).

Both shape and path are 2-D Path objects (coerced from point lists). Each shape point offsets the path by its X and lifts it to its Y, so a shape with a wide X range becomes a wall of varying width along the path. Unlike path_sweep(), moderate local concavity is handled by the offset (mitre joins); an offset large enough to collapse a feature of the path will still fold, so keep the shape’s X extent below the path’s tightest radius.

Parameters:
  • shape (Sequence[Sequence[float]]) – the 2-D cross-section (a closed path); its X is the offset from the path, its Y the height

  • path (Sequence[Sequence[float]]) – the 2-D path to sweep along

  • closed (bool) – the path is a closed loop (default False)

  • caps (bool | Sequence[bool] | None) – cap the open ends (default: True for open, False for closed)

  • quality (int) – accepted for signature parity (unused – the mitre offset needs no quality knob)

  • style (str) – vnf_vertex_array quad-subdivision style

Return type:

VNF

Examples

A rounded bar swept along a wavy 2-D path:

shape = [[-2, -2], [2, -2], [2, 2], [-2, 2]]
path = [[t, 8 * math.sin(t / 12)] for t in range(0, 90, 3)]
path_sweep2d(shape, path).polyhedron().show()

⬇ Download STL mesh

bosl2.skin.rot_resample(rotlist, sides, twist=None, scale=None, smoothlen=1, long=False, turns=0, closed=False, method='length')[source]

Resample a list of 4x4 transforms to uniform screw-motion spacing (BOSL2 rot_resample()).

Interpolates between successive transforms along their screw motion (via rot_decode()), optionally adding twist and scale (smoothed over smoothlen). Handy for regularizing the transform list from path_sweep(..., transforms=True) before handing it to sweep().

Parameters:
  • rotlist (Sequence[Sequence[float]]) – list of 4x4 transform matrices

  • sides (int) – number of output samples (method=”length”) or samples per gap (method=”count”)

  • twist – extra twist in degrees (scalar or per-gap list)

  • scale – extra scale (scalar or per-gap list, multiplied cumulatively)

  • smoothlen (int) – odd window length for smoothing the twist/scale (default 1 = none)

  • long – take the >180-degree rotation at a gap (scalar or per-gap list)

  • turns (float) – extra full turns to add at a gap (scalar or per-gap list)

  • closed (bool) – the transform list forms a loop (default False)

  • method (str) – “length” (uniform screw-distance) or “count” (fixed samples per gap)

Return type:

list