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

from_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

ported — resample a transform list along its screw motion, with rot_decode / rot_inverse in pybosl2.transforms

subdivide_and_slice / slice_profiles

ported

sweep()

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

Surface generators: sweep, path_sweep, skin, linear_sweep, rotate_sweep, spiral_sweep (BOSL2 skin.scad).

class pybosl2.skin.Sweepable[source]

Bases: object

Mixin adding sweep methods to Path2D and Path3D.

path_sweep(shape, method=SweepMethod.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=CapType.BUTT, style=VNFStyle.MIN_EDGE, transforms=False)[source]

Sweep shape along this path (BOSL2 path_sweep()).

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:

import math
import numpy as np
from pybosl2 import Path3D

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)]
Path3D(helix).path_sweep(square).polyhedron().show()
Loading 3-D preview…

⬇ Download STL mesh

Parameters:
shape : Path2D

method : SweepMethod

normal : Sequence[float] | Sequence[Sequence[float]] | None

closed : bool

twist : float

twist_by_length : bool

scale : Any

scale_by_length : bool

symmetry : int

last_normal : Sequence[float] | None

tangent : Sequence[Sequence[float]] | None

uniform : bool

relaxed : bool

caps : CapsSpec

style : VNFStyle

transforms : bool

Return type:

VNF | Bosl2Solid | list[list[list[float]]]

path_sweep2d(shape, closed=False, caps=CapType.BUTT, style=VNFStyle.MIN_EDGE)[source]

Sweep 2-D shape along this 2-D path (BOSL2 path_sweep2d()).

For each point on the profile, the path is offset by its X coordinate and lifted to Z = Y, producing a stack of profiles that are skinned into the final surface. Closed paths are reversed automatically to maintain the same winding.

Examples

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

import math
from pybosl2 import Path2D

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

⬇ Download STL mesh

Parameters:
shape : Path2D

closed : bool

caps : CapsSpec

style : VNFStyle

Return type:

VNF | Bosl2Solid

linear_sweep(height=None, twist=0.0, scale=1, shift=(0.0, 0.0), slices=None, center=False, caps=CapType.BUTT, style=VNFStyle.MIN_EDGE)[source]

Extrude this 2-D profile linearly with optional twist/scale/shift (BOSL2 linear_sweep()).

The profile is duplicated at slices positions along the Z axis; at each level the points are twisted (rotation around Z, degrees) and scaled (uniform scalar or 2-vector), then shifted in XY. The slices are skinned into a VNF.

Examples

A twisting, tapering square column:

from pybosl2 import Path2D

square = [[-10, -10], [10, -10], [10, 10], [-10, 10]]
Path2D(square).linear_sweep(height=40, twist=120, scale=0.4).polyhedron().show()
Loading 3-D preview…

⬇ Download STL mesh

Parameters:
height : float | None

twist : float

scale : Any

shift : Sequence[float]

slices : int | None

center : bool

caps : CapsSpec

style : VNFStyle

Return type:

VNF | Bosl2Solid

rotate_sweep(angle=360.0, caps=CapType.BUTT, _closed=None, style=VNFStyle.MIN_EDGE, start=0.0)[source]

Revolve this 2-D profile around the Z axis (BOSL2 rotate_sweep()).

The profile is swept through angle degrees (default 360) around Z, starting at start degrees. When angle < 360 the profile is capped at both ends.

Examples

Revolving a rounded profile into a spool:

from pybosl2 import Path2D

profile = [[4, -10], [12, -10], [12, -6], [7, -2], [7, 2], [12, 6], [12, 10], [4, 10]]
Path2D(profile).rotate_sweep(angle=360).polyhedron().show()
Loading 3-D preview…

⬇ Download STL mesh

Parameters:
angle : float

caps : CapsSpec

_closed : bool | None

style : VNFStyle

start : float

Return type:

VNF | Bosl2Solid

spiral_sweep(height, radius=None, turns=1.0, radius1=None, radius2=None, diameter=None, diameter1=None, diameter2=None, center=True, style=VNFStyle.MIN_EDGE)[source]

Sweep this 2-D profile along a helix (BOSL2 spiral_sweep()).

The profile follows a helical path of height and radius (or separate start/end radii) over turns revolutions. Unlike rotate_sweep, the profile also gains height, producing a coil.

Examples

A rectangular-section coil spring:

from pybosl2 import Path2D

section = [[-1.2, -1.2], [1.2, -1.2], [1.2, 1.2], [-1.2, 1.2]]
Path2D(section).spiral_sweep(height=40, radius=12, turns=5).polyhedron().show()
Loading 3-D preview…

⬇ Download STL mesh

Parameters:
height : float

radius : float | None

turns : float

radius1 : float | None

radius2 : float | None

diameter : float | None

diameter1 : float | None

diameter2 : float | None

center : bool

style : VNFStyle

Return type:

VNF | Bosl2Solid

sweep(transforms, closed=False, caps=CapType.BUTT, style=VNFStyle.MIN_EDGE)[source]

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

or Bosl2Solid (BOSL2 sweep()).

Parameters:
transforms : Sequence[Sequence[Sequence[float]]]

closed : bool

caps : CapsSpec

style : VNFStyle

Return type:

VNF | Bosl2Solid

pybosl2.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 pybosl2/paths.py).

Parameters:
path : Sequence[Sequence[float]] | Path | np.ndarray | Sequence[np.ndarray]

Return type:

list[list[float]]

pybosl2.skin.clockwise_polygon(poly)[source]

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

Parameters:
poly : Sequence[Sequence[float]] | Path2D

Return type:

list[Sequence[float]]

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

Return 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

pybosl2.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[Sequence[float]]]

slices : int

closed : bool

Return type:

list[list[list[float]]]

pybosl2.skin.subdivide_and_slice(profiles, slices, numpoints=None, method=ResampleMethod.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[Sequence[float]]]

slices : int

numpoints : int | str | None

method : ResampleMethod

closed : bool

Return type:

list[list[list[float]]]

class pybosl2.skin.OSType(*values)[source]

Bases: StrEnum

Offset sweep profile type.

CIRCLE = 'circle'
SMOOTH = 'smooth'
TEARDROP = 'teardrop'
CHAMFER = 'chamfer'
FLAT = 'flat'
PROFILE = 'profile'
pybosl2.skin.os_circle(radius=None, height=None, extra=0.0)[source]

Circular roundover/flare profile for offset_sweep() (BOSL2 os_circle()).

Describes the treatment applied to one rim of the extruded shape:

  • radius > 0 — inward roundover: the rim is eased in (material is removed from the corner, yielding a convex fillet).

  • radius < 0 — outward flare: extra material is added outside the wall at the rim (a concave cove).

  • radius == 0 — square / no treatment (same as passing None to offset_sweep()).

Parameters:
radius : float | None

Roundover radius (positive = roundover, negative = flare).

height : float | None

Height of the rim treatment; defaults to abs(radius). Should be less than half the extrusion height.

extra : float

Extra extension beyond the nominal arc (useful to close tiny gaps from floating-point rounding; default 0).

Returns:

A descriptor OSProfile consumed by offset_sweep().

Return type:

OSProfile

pybosl2.skin.os_smooth(cut=None, radius=None, curvature=0.5, extra=0.0)[source]

Continuous curvature (Bézier) profile for offset_sweep() (BOSL2 os_smooth()).

Uses a 4th-order Bézier curve to ease the transition between flat and curved edges, avoiding sudden changes in curvature.

Parameters:
cut : float | None

Depth of the roundover/flare.

radius : float | None

Alternative to cut (aliases it).

curvature : float

Smoothness/curvature match parameter between 0 and 1 (default 0.5).

extra : float

Extra extension beyond the nominal curve (default 0).

Returns:

A descriptor OSProfile consumed by offset_sweep().

Return type:

OSProfile

pybosl2.skin.os_teardrop(radius=None, height=None, cut=None, max_angle=45.0, extra=0.0)[source]

Teardrop profile for offset_sweep() to avoid overhangs in 3D printing (BOSL2 os_teardrop()).

Transitions from a 1/8th circle into a straight line at max_angle degrees relative to the vertical wall, allowing support-free printing.

Parameters:
radius : float | None

Radius of the circular portion.

height : float | None

Total height of the treatment (defaults to abs(radius)).

cut : float | None

Alternative to radius (aliases it).

max_angle : float

Curvature transition angle relative to the wall (default 45.0).

extra : float

Extra extension beyond the nominal curve (default 0).

Returns:

A descriptor OSProfile consumed by offset_sweep().

Return type:

OSProfile

pybosl2.skin.os_chamfer(width=None, height=None, angle=None, cut=None, extra=0.0)[source]

Chamfer/bevel profile for offset_sweep() (BOSL2 os_chamfer()).

Creates a flat bevel transition.

Parameters:
width : float | None

Horizontal width of the chamfer.

height : float | None

Vertical height of the chamfer (defaults to width).

angle : float | None

Bevel angle in degrees. If given, overrides width.

cut : float | None

Bevel size (aliases both width and height).

extra : float

Extra extension beyond the nominal bevel (default 0).

Returns:

A descriptor OSProfile consumed by offset_sweep().

Return type:

OSProfile

pybosl2.skin.os_flat()[source]

Flat end cap profile descriptor representing no treatment (BOSL2 os_flat()).

Return type:

OSProfile

pybosl2.skin.os_profile(profile, extra=0.0)[source]

Return a custom offset sweep profile descriptor (BOSL2 os_profile()).

Accepts a list of 2D points [[x, y], …] defining the profile: - x is the inward radial offset (meaning delta = -x). - y is the height z.

Parameters:
profile : Sequence[Sequence[float]]

Sequence of [x, y] points. The first must be [0, 0].

extra : float

Extra extension (default 0).

Returns:

A descriptor OSProfile consumed by offset_sweep().

Return type:

OSProfile

pybosl2.skin.rot_resample(rotlist, num_copies, twist=None, scale=None, smoothlen=1, long=False, turns=0, closed=False, method=ResampleMethod.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

num_copies : int | Sequence[int]

number of output samples (method=”length”) or samples per gap (method=”count”)

twist : float | Sequence[float] | None

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

scale : float | Sequence[float] | None

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

smoothlen : int

odd window length for smoothing the twist/scale (default 1 = none)

long : bool

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 : ResampleMethod

“length” (uniform screw-distance) or “count” (fixed samples per gap)

Return type:

list[list[list[float]]]