Drawing: path generators & renderers

Pure-Python port of BOSL2’s drawing.scad. It splits into path generators that return points – arc(), catenary(), turtle() (2-D Path) and helix() (3-D Path3D) – and path renderers that turn points into geometry, stroke() (a solid line) and dashed_stroke() (a list of dash sub-paths).

The generators return all the computed points, so they compose with every Path operation and feed straight into path_sweep / linear_extrude / stroke. stroke and dashed_stroke are also methods on Path and Region, so a built outline can be drawn directly:

arc(radius=30, angle=200).stroke(width=3)
turtle(["move", 40, "arcleft", 8, "move", 40, "arcleft", 8]).stroke(width=2, closed=True)
Region.with_holes(outline, hole).stroke(width=1)

Every generator is pinned point-for-point to the real BOSL2 output in tests/test_bosl2_reorient.py.

Coverage of BOSL2 drawing.scad

BOSL2 function

Status

Notes

arc

ported

arc() returns a Path; all 2-D forms (radius/angle, angle=[start, end], width/thickness, two-point with long/cw/ccw, three-point, corner=, and wedge=). 3-D arcs are not ported.

catenary

ported

catenary() – by droop= or endpoint angle=.

helix

ported

helix() – returns a Path3D (conical/flat spirals included).

turtle

ported

turtle() – the full command set, including repeat and the arcleft/arcright/arcleftto/arcrightto arcs.

stroke

ported

stroke() – 2-D (segment rects + joints & endcaps) and 3-D (cylinder tube + spherical joints + revolved endcaps). Every BOSL2 endcap/joint style is generated directly: round, square, butt, dot, block, diamond, chisel, line, x, cross, arrow, arrow2, arrow3, tail, tail2 (arrow caps trim the line back). Per-vertex width lists and the *_angle/*_color knobs are not ported.

dashed_stroke

ported

dashed_stroke() – the function form: a list of “on” dash Path s (stroke or extrude them to draw).

turtle3d

not ported

the 3-D turtle (separate turtle3d.scad machinery) – port on request.

debug_polygon / debug_region

not ported

annotated debugging modules (vertex/edge labels); no geometry payload.

API reference

bosl2.shapes2d.arc(count=None, radius=None, angle=None, diameter=None, center=None, points=None, corner=None, width=None, thickness=None, start=None, wedge=False, long=False, clockwise=False, counterclockwise=False, endpoint=True, fn=None, fa=None, fs=None)[source]

A 2-D arc, returned as a Path of points (BOSL2’s arc()).

All of BOSL2’s 2-D arc specifications are supported (3-D arcs, which project onto a plane, are not):

  • arc(radius=, angle=, [start=], [center=]) – radius about center, sweeping angle degrees from start (or angle=[start, end] for an explicit range).

  • arc(width=, thickness=) – a circular segment starting and ending on the X axis.

  • arc(center=, points=[P0, P1]) – around center from P0 toward the direction of P1; the short way by default, or the long/clockwise/counterclockwise way.

  • arc(points=[P0, P1, P2]) – through three points, from P0 via P1 to P2.

  • arc(corner=[P0, P1, P2], radius=) – the fillet arc of radius tangent to both legs of the corner P0-P1-P2.

Set wedge=True to prepend the centre point, giving a closed pie/sector path. When count is omitted the point count follows OpenSCAD’s $fn/$fa/$fs rules, matching BOSL2.

Parameters:
  • count (int | None) – number of points (default: from $fn/$fa/$fs)

  • radius/diameter – radius / diameter of the arc

  • angle (float | Sequence[float] | None) – degrees to sweep from start, or [start, end]

  • center (Sequence[float] | None) – centre point (default [0, 0])

  • points (Sequence[Sequence[float]] | None) – two points (with center) or three points the arc passes through

  • corner (Sequence[Sequence[float]] | None) – three points; the arc is the radius fillet tangent to both legs

  • width (float | None) – chord width for the width/thickness form

  • thickness (float | None) – height of the circular segment for the width/thickness form

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

  • wedge (bool) – prepend the centre point, producing a closed sector (default False)

  • long/clockwise/counterclockwise – for the two-point form, take the long way / a given handedness

  • endpoint (bool) – include the final point (default True)

  • radius (float | None)

  • diameter (float | None)

  • long (bool)

  • clockwise (bool)

  • counterclockwise (bool)

  • fn (int | None)

  • fa (float | None)

  • fs (float | None)

Returns:

A Path (closed when wedge is set).

Return type:

Path

bosl2.drawing.arc(count=None, radius=None, angle=None, diameter=None, center=None, points=None, corner=None, width=None, thickness=None, start=None, wedge=False, long=False, clockwise=False, counterclockwise=False, endpoint=True, fn=None, fa=None, fs=None)[source]

A 2-D arc, returned as a Path of points (BOSL2’s arc()).

All of BOSL2’s 2-D arc specifications are supported (3-D arcs, which project onto a plane, are not):

  • arc(radius=, angle=, [start=], [center=]) – radius about center, sweeping angle degrees from start (or angle=[start, end] for an explicit range).

  • arc(width=, thickness=) – a circular segment starting and ending on the X axis.

  • arc(center=, points=[P0, P1]) – around center from P0 toward the direction of P1; the short way by default, or the long/clockwise/counterclockwise way.

  • arc(points=[P0, P1, P2]) – through three points, from P0 via P1 to P2.

  • arc(corner=[P0, P1, P2], radius=) – the fillet arc of radius tangent to both legs of the corner P0-P1-P2.

Set wedge=True to prepend the centre point, giving a closed pie/sector path. When count is omitted the point count follows OpenSCAD’s $fn/$fa/$fs rules, matching BOSL2.

Parameters:
  • count (int | None) – number of points (default: from $fn/$fa/$fs)

  • radius/diameter – radius / diameter of the arc

  • angle (float | Sequence[float] | None) – degrees to sweep from start, or [start, end]

  • center (Sequence[float] | None) – centre point (default [0, 0])

  • points (Sequence[Sequence[float]] | None) – two points (with center) or three points the arc passes through

  • corner (Sequence[Sequence[float]] | None) – three points; the arc is the radius fillet tangent to both legs

  • width (float | None) – chord width for the width/thickness form

  • thickness (float | None) – height of the circular segment for the width/thickness form

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

  • wedge (bool) – prepend the centre point, producing a closed sector (default False)

  • long/clockwise/counterclockwise – for the two-point form, take the long way / a given handedness

  • endpoint (bool) – include the final point (default True)

  • radius (float | None)

  • diameter (float | None)

  • long (bool)

  • clockwise (bool)

  • counterclockwise (bool)

  • fn (int | None)

  • fa (float | None)

  • fs (float | None)

Returns:

A Path (closed when wedge is set).

Return type:

Path

bosl2.drawing.catenary(width, droop=None, sides=100, angle=None)[source]

The catenary (hanging-chain) curve of the given width, as a Path.

Give exactly one of droop (how far the middle hangs below the endpoints) or angle (the slope in degrees at the endpoints). The curve passes through [-width/2, 0] and [width/2, 0] and hangs downward (negative droop/angle flips it upward). This is BOSL2’s catenary().

Parameters:
  • width (float) – horizontal distance between the endpoints (> 0)

  • droop (float | None) – how far the midpoint hangs below the endpoints (give this or angle)

  • sides (int) – number of points along the curve (default 100)

  • angle (float | None) – endpoint slope in degrees, 0 < |angle| < 90 (give this or droop)

Return type:

Path

Examples

A hanging arch, stroked into a 2-mm ribbon and extruded into a wall:

catenary(width=80, droop=30).stroke(width=2).linear_extrude(height=6).show()

⬇ Download STL mesh

bosl2.drawing.helix(length=None, height=None, turns=None, angle=None, radius=None, radius1=None, radius2=None, diameter=None, diameter1=None, diameter2=None)[source]

A 3-D helical path on a (possibly conical) surface – BOSL2’s helix().

Returned as a Path3D (the 3-D path object), so it carries the 3-D transforms/measurements and feeds straight into stroke() or path_sweep. Give exactly two of length/height (length), turns, and angle; the third is derived. Positive turns is right-handed, negative left-handed. Start/end radii may differ for a conical helix (a flat spiral is height=0 with a turn count).

Parameters:
  • length/height – height of the helix (0 for a flat spiral)

  • turns (float | None) – number of turns (positive = right-handed)

  • angle (float | None) – helix angle in degrees (measured at the base radius)

  • radius/diameter – radius / diameter (constant helix)

  • radius1/diameter1 – bottom radius / diameter

  • radius2/diameter2 – top radius / diameter

  • length (float | None)

  • height (float | None)

  • radius (float | None)

  • radius1 (float | None)

  • radius2 (float | None)

  • diameter (float | None)

  • diameter1 (float | None)

  • diameter2 (float | None)

Return type:

Path3D

Examples

A 2.5-turn helix drawn as a tube:

stroke(helix(turns=2.5, height=100, radius=30), width=3).show()

⬇ Download STL mesh

bosl2.drawing.turtle(commands, state=None, full_state=False, repeat=1)[source]

Build a 2-D path from [turtle-graphics](https://en.wikipedia.org/wiki/Turtle_graphics) commands – BOSL2’s turtle().

commands is a flat list of command names each optionally followed by a parameter, e.g. ["move", 10, "left", 90, "move", 10]. The turtle starts at the origin pointing along +X with a step length of 1. By default the computed path is returned as a Path; set full_state to get [path, step_vector, angle, arcsteps] instead. repeat runs the whole command list that many times.

Supported commands: move/xmove/ymove/xymove, jump/xjump/yjump, untilx/untily, left/turn/right, angle, setdir, length/ scale/addlength, arcsteps, arcleft/arcright, arcleftto/arcrightto, and repeat (["repeat", count, [subcommands]]).

Examples

A rounded-corner square drawn with arcs:

path = turtle(["move", 40, "arcleft", 8, "move", 40, "arcleft", 8,
               "move", 40, "arcleft", 8, "move", 40, "arcleft", 8])
path.stroke(width=3, closed=True).linear_extrude(height=4).show()

⬇ Download STL mesh

Parameters:
  • commands (Sequence)

  • state (Sequence | None)

  • full_state (bool)

  • repeat (int)

Return type:

Path | list

bosl2.drawing.stroke(path, width=1, closed=None, endcaps=None, endcap1=None, endcap2=None, joints=None, dots=False, color=None)[source]

Render path as a solid line of the given width – BOSL2’s stroke().

Works on a 2-D or 3-D point list, a Path, a Path3D, or a Region (each of its paths is stroked closed). A 2-D stroke is a union of segment rectangles with joints and endcaps; a 3-D stroke is a tube of cylinders with spherical joints and revolved endcaps. Returns native geometry.

Every BOSL2 endcap/joint style is generated directly: "round" (default), "square", "butt"/False (flush), "dot", "block", "diamond", "chisel", "line", "x", "cross", "arrow", "arrow2", "arrow3", "tail", and "tail2". Arrow endcaps trim the line back so it doesn’t poke through the tip.

Parameters:
  • path – a point list, Path/Path3D, or

  • width (float)

  • closed (bool | None)

:param Region: :param width: line width (default 1) :param closed: close the path into a loop (default: the path’s own closed flag, or True for a Region) :param endcaps: style for both ends (endcap1/endcap2 override per end) :param joints: style for the interior corners (default "round") :param dots: mark every vertex with a round dot :param color: optional colour applied to the whole stroke

Examples

An arc drawn as a 3-mm ribbon with round ends, extruded into a curved wall:

arc(radius=30, angle=200).stroke(width=3).linear_extrude(height=5).show()

⬇ Download STL mesh

A line with a fancy endcap on each end (arrow one way, tail the other):

stroke([[0, 0], [50, 0]], width=3, endcap1='tail', endcap2='arrow')                 .linear_extrude(height=3).show()

⬇ Download STL mesh

A 3-D arrow: the endcap is a revolved cone on the tube:

stroke([[0, 0, 0], [40, 0, 0]], width=4, endcaps='arrow').show()

⬇ Download STL mesh

bosl2.drawing.dashed_stroke(path, dashpat=(3, 3), closed=False, fit=True, mindash=0.5)[source]

Break path into dashes – BOSL2’s dashed_stroke() function form.

Returns the list of “on” dash sub-paths (each a Path); stroke or extrude them to draw a dashed line. dashpat alternates dash/gap lengths. With fit (the default) the pattern is scaled slightly so a whole number of repeats fills the path exactly.

Parameters:
  • path – a point list, Path, or Region

  • dashpat (Sequence[float]) – alternating [dash, gap, …] lengths (default (3, 3))

  • closed (bool) – treat the path as a closed loop

  • fit (bool) – scale the pattern to fit a whole number of repeats (default True)

  • mindash (float) – drop a trailing dash shorter than this (default 0.5)

Return type:

list[Path | Path3D]

Examples

A dashed circle outline, the dashes unioned and extruded into little tiles:

dashes = dashed_stroke(arc(radius=30, angle=360), dashpat=[6, 4], closed=True)
ring = reduce(lambda a, b: a | b, (d.stroke(width=1.5) for d in dashes))
ring.linear_extrude(height=3).show()

⬇ Download STL mesh

class bosl2.drawing.EndcapSpec(width_mult, length_mult, extent_mult)[source]

Bases: object

The size multipliers for one stroke endcap/joint style (BOSL2 _shape_defaults()).

The realised width/length/extent are these times the stroke’s line width, then the whole shape is scaled by the line width again (as BOSL2 does).

Parameters:
  • width_mult (float)

  • length_mult (float)

  • extent_mult (float)

width_mult: float
length_mult: float
extent_mult: float