Distributors: copiers & reflected copies

Pure-Python port of BOSL2’s distributors.scad – the “copiers” that duplicate a shape into a line, grid, ring, arc, sphere, or path pattern, plus the reflected-copy helpers. Each copier is a module-level function returning a list of 4x4 transformation matrices (BOSL2’s function form), and a matching method on every geometry object via the Distributable mixin.

What a copier returns depends on the object it is called on:

  • Bosl2Solid – the union of the transformed geometry copies (a new solid), matching BOSL2’s module form:

    cuboid([10, 10, 10]).grid_copies(n=[3, 3], spacing=30)   # 9 cubes, unioned
    cuboid([6, 6, 6]).zrot_copies(sides=6, radius=30)                 # a ring of 6 cubes
    part.right(20).xflip_copy()                              # part + its mirror image
    
  • Path / Path3D – a plain list of the transformed path copies (BOSL2’s function form). A 2-D Path only supports the in-plane copiers; one that would lift it out of the XY plane (zcopies, xrot_copies, sphere_copies, …) raises, directing you to Path3D.

Every copier’s matrices are pinned to the real BOSL2 output in tests/test_bosl2_reorient.py.

Coverage of BOSL2 distributors.scad

BOSL2 function

Status

Notes

move_copies

ported

move_copies() – a copy at each given offset.

xcopies / ycopies / zcopies

ported

spacing/n/l/sp and the explicit-position-list form.

line_copies

ported

line_copies() – along a line by spacing, length, or p1/p2.

grid_copies

ported

square and staggered (hex) grids, size/n/spacing, axes=, and an inside= polygon mask (grid2d is the deprecated alias, not ported).

rot_copies

ported

rotated copies about any axis, with cp/sa/delta/subrot.

xrot_copies / yrot_copies / zrot_copies

ported

rings about the X/Y/Z axes (r/d, sa, subrot).

arc_copies

ported

along a circular or elliptical arc in the XY plane (arc_of alias not ported).

sphere_copies

ported

golden-spiral spread over a sphere/ellipsoid (ovoid_spread alias not ported).

path_copies

ported

path_copies() – along a 2-D/3-D path, oriented to it (path_spread alias not ported).

mirror_copy / xflip_copy / yflip_copy / zflip_copy

ported

the original plus one reflected copy.

distribute / xdistribute / ydistribute / zdistribute

ported

distribute() – lay a list of distinct solids out so they don’t overlap (sizes taken from each child’s bounding box if not given).

$pos / $idx / $ang / $row / $col side-effect variables

not ported

OpenSCAD special variables for per-copy customization have no Python equivalent; build the variants yourself and use move_copies with explicit matrices.

Examples

A grid of rounded pillars, unioned into one solid:

s3.cyl(height=12, radius=4, rounding=1).grid_copies(n=[4, 3], spacing=14).show()
_images/4c407a59a1b83955.png

A ring of wedges facing the centre:

s3.prismoid([6, 10], [2, 10], height=12).zrot_copies(sides=8, radius=24).show()

⬇ Download STL mesh

Copies of a 2-D outline along an arc, extruded together:

tile = Path([[-3, -3], [3, -3], [3, 3], [-3, 3]])
reduce(lambda a, b: a | b, (c.polygon() for c in tile.arc_copies(sides=10, radius=30, ea=180))) \
    .linear_extrude(height=3).show()

⬇ Download STL mesh

API reference

bosl2.distributors.move_copies(a=([0, 0, 0],))[source]

One translation matrix per offset in a (BOSL2 move_copies()).

Return type:

list[ndarray]

bosl2.distributors.xcopies(spacing=None, sides=None, length=None, sp=None)[source]

Copies spread along the X axis (BOSL2 xcopies()).

Parameters:

length (float | None)

Return type:

list[ndarray]

bosl2.distributors.ycopies(spacing=None, sides=None, length=None, sp=None)[source]

Copies spread along the Y axis (BOSL2 ycopies()).

Parameters:

length (float | None)

Return type:

list[ndarray]

bosl2.distributors.zcopies(spacing=None, sides=None, length=None, sp=None)[source]

Copies spread along the Z axis (BOSL2 zcopies()).

Parameters:

length (float | None)

Return type:

list[ndarray]

bosl2.distributors.line_copies(spacing=None, sides=None, length=None, p1=None, p2=None)[source]

Translation matrices evenly spread along a line (BOSL2 line_copies()).

Parameters:

length (float | None)

Return type:

list[ndarray]

bosl2.distributors.grid_copies(spacing=None, sides=None, size=None, stagger=False, inside=None, nonzero=None, axes='xy')[source]

Copies laid out in a square or staggered (hex) grid (BOSL2 grid_copies()).

Parameters:
  • stagger (bool)

  • nonzero (bool | None)

Return type:

list[ndarray]

bosl2.distributors.rot_copies(rots=None, v=None, center=(0, 0, 0), sides=None, sa=0, offset=0, delta=(0, 0, 0), subrot=True)[source]

Rotated copies about an axis, optionally offset into a ring (BOSL2 rot_copies()).

Parameters:
  • center (bool | Sequence[float])

  • sa (float)

  • delta (Sequence[float])

  • subrot (bool)

Return type:

list[ndarray]

bosl2.distributors.xrot_copies(rots=None, center=(0, 0, 0), sides=None, sa=0, radius=None, diameter=None, subrot=True)[source]

Rotated copies around the X axis, optionally into a ring of radius radius (BOSL2 xrot_copies()).

Parameters:
  • center (bool | Sequence[float])

  • sa (float)

  • radius (float | None)

  • diameter (float | None)

  • subrot (bool)

Return type:

list[ndarray]

bosl2.distributors.yrot_copies(rots=None, center=(0, 0, 0), sides=None, sa=0, radius=None, diameter=None, subrot=True)[source]

Rotated copies around the Y axis, optionally into a ring of radius radius (BOSL2 yrot_copies()).

Parameters:
  • center (bool | Sequence[float])

  • sa (float)

  • radius (float | None)

  • diameter (float | None)

  • subrot (bool)

Return type:

list[ndarray]

bosl2.distributors.zrot_copies(rots=None, center=(0, 0, 0), sides=None, sa=0, radius=None, diameter=None, subrot=True)[source]

Rotated copies around the Z axis, optionally into a ring of radius radius (BOSL2 zrot_copies()).

Parameters:
  • center (bool | Sequence[float])

  • sa (float)

  • radius (float | None)

  • diameter (float | None)

  • subrot (bool)

Return type:

list[ndarray]

bosl2.distributors.arc_copies(sides=6, radius=None, radius_x=None, radius_y=None, diameter=None, diameter_x=None, diameter_y=None, sa=0, ea=360, rot=True)[source]

Copies spread along an (elliptical) arc in the XY plane (BOSL2 arc_copies()).

Parameters:
  • radius (float | None)

  • radius_x (float | None)

  • radius_y (float | None)

  • diameter (float | None)

  • diameter_x (float | None)

  • diameter_y (float | None)

  • sa (float)

  • ea (float)

Return type:

list[ndarray]

bosl2.distributors.sphere_copies(sides=100, radius=None, diameter=None, cone_ang=90, scale=(1, 1, 1), perp=True)[source]

Copies spread over a sphere/ellipsoid by the golden-spiral method (BOSL2 sphere_copies()).

Parameters:
  • radius (float | None)

  • diameter (float | None)

  • perp (bool)

Return type:

list[ndarray]

bosl2.distributors.path_copies(path, sides=None, spacing=None, sp=None, dist=None, rotate_children=True, closed=None)[source]

Copies placed along path, oriented to it (BOSL2 path_copies()).

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

  • rotate_children (bool)

  • closed (bool | None)

Return type:

list[ndarray]

bosl2.distributors.mirror_copy(v=(0, 0, 1), offset=0, center=None)[source]

The original plus a mirrored copy across the plane with normal v (BOSL2 mirror_copy()).

Parameters:

center (bool | list[float] | None)

Return type:

list[ndarray]

bosl2.distributors.xflip_copy(offset=0, x=0)[source]

The original plus a copy mirrored across the X=*x* plane (BOSL2 xflip_copy()).

Return type:

list[ndarray]

bosl2.distributors.yflip_copy(offset=0, y=0)[source]

The original plus a copy mirrored across the Y=*y* plane (BOSL2 yflip_copy()).

Return type:

list[ndarray]

bosl2.distributors.zflip_copy(offset=0, z=0)[source]

The original plus a copy mirrored across the Z=*z* plane (BOSL2 zflip_copy()).

Return type:

list[ndarray]

bosl2.distributors.distribute(children, spacing=None, sizes=None, dir=[1, 0, 0], length=None)[source]

Space a LIST of distinct solids out along dir so they don’t overlap (BOSL2 distribute()).

Unlike the copiers (which duplicate one shape), this lays out several different children in order. sizes gives each child’s extent along dir; if omitted it is read from each child’s bounding box. Give spacing (gap between children) or length (total length to fill). Returns the union of the positioned children.

Parameters:

length (float | None)

bosl2.distributors.xdistribute(children, spacing=None, sizes=None, length=None)[source]

Distribute distinct children along the X axis (BOSL2 xdistribute()).

Parameters:

length (float | None)

bosl2.distributors.ydistribute(children, spacing=None, sizes=None, length=None)[source]

Distribute distinct children along the Y axis (BOSL2 ydistribute()).

Parameters:

length (float | None)

bosl2.distributors.zdistribute(children, spacing=None, sizes=None, length=None)[source]

Distribute distinct children along the Z axis (BOSL2 zdistribute()).

Parameters:

length (float | None)

class bosl2.distributors.Distributable[source]

Bases: ABC

Mixin adding the distributors.scad copiers as methods.

Inherited by Bosl2Solid, Path, and Path3D. Each copier builds a list of transformation matrices and hands them to _distribute, which every host class implements: a Bosl2Solid unions the geometry copies into a new solid; a Path / Path3D returns a plain list of the copied paths.

move_copies(a=([0, 0, 0],))[source]

Copy to each offset in a.

xcopies(spacing=None, sides=None, length=None, sp=None)[source]

Copies spread along the X axis.

Parameters:

length (float | None)

ycopies(spacing=None, sides=None, length=None, sp=None)[source]

Copies spread along the Y axis.

Parameters:

length (float | None)

zcopies(spacing=None, sides=None, length=None, sp=None)[source]

Copies spread along the Z axis.

Parameters:

length (float | None)

line_copies(spacing=None, sides=None, length=None, p1=None, p2=None)[source]

Copies spread along a line.

Parameters:

length (float | None)

grid_copies(spacing=None, sides=None, size=None, stagger=False, inside=None, nonzero=None, axes='xy')[source]

Copies in a square or staggered (hex) grid.

Parameters:
  • stagger (bool)

  • nonzero (bool | None)

rot_copies(rots=None, v=None, center=(0, 0, 0), sides=None, sa=0, offset=0, delta=(0, 0, 0), subrot=True)[source]

Rotated copies about an axis (optionally into a ring via delta).

Parameters:
  • center (bool | Sequence[float])

  • sa (float)

  • delta (Sequence[float])

  • subrot (bool)

xrot_copies(rots=None, center=(0, 0, 0), sides=None, sa=0, radius=None, diameter=None, subrot=True)[source]

Rotated copies around the X axis.

Parameters:
  • center (bool | Sequence[float])

  • sa (float)

  • radius (float | None)

  • diameter (float | None)

  • subrot (bool)

yrot_copies(rots=None, center=(0, 0, 0), sides=None, sa=0, radius=None, diameter=None, subrot=True)[source]

Rotated copies around the Y axis.

Parameters:
  • center (bool | Sequence[float])

  • sa (float)

  • radius (float | None)

  • diameter (float | None)

  • subrot (bool)

zrot_copies(rots=None, center=(0, 0, 0), sides=None, sa=0, radius=None, diameter=None, subrot=True)[source]

Rotated copies around the Z axis.

Parameters:
  • center (bool | Sequence[float])

  • sa (float)

  • radius (float | None)

  • diameter (float | None)

  • subrot (bool)

arc_copies(sides=6, radius=None, radius_x=None, radius_y=None, diameter=None, diameter_x=None, diameter_y=None, sa=0, ea=360, rot=True)[source]

Copies spread along an (elliptical) arc in the XY plane.

Parameters:
  • radius (float | None)

  • radius_x (float | None)

  • radius_y (float | None)

  • diameter (float | None)

  • diameter_x (float | None)

  • diameter_y (float | None)

  • sa (float)

  • ea (float)

sphere_copies(sides=100, radius=None, diameter=None, cone_ang=90, scale=(1, 1, 1), perp=True)[source]

Copies spread over a sphere/ellipsoid surface.

Parameters:
  • radius (float | None)

  • diameter (float | None)

  • perp (bool)

path_copies(path, sides=None, spacing=None, sp=None, dist=None, rotate_children=True, closed=None)[source]

Copies placed along path, oriented to it.

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

  • rotate_children (bool)

  • closed (bool | None)

mirror_copy(v=(0, 0, 1), offset=0, center=None)[source]

This object plus a copy mirrored across the plane with normal v.

Parameters:

center (bool | None)

xflip_copy(offset=0, x=0)[source]

This object plus a copy mirrored across the X=*x* plane.

yflip_copy(offset=0, y=0)[source]

This object plus a copy mirrored across the Y=*y* plane.

zflip_copy(offset=0, z=0)[source]

This object plus a copy mirrored across the Z=*z* plane.