Skip to content

New Functions in PythonSCAD

OpenSCAD already got a rich set of functions, however, there could be some more ...

A note on imports

Previously Python designs used from openscad import *, but now the recommended import is from pythonscad import *, which is a strict superset of openscad and will host PythonSCAD-only features going forward:

# Recommended for new PythonSCAD designs
from pythonscad import *

Both forms call the same underlying C extension. See doc/python-modules.md for the layered module layout.

divmatrix

Sometimes its helpful to use multmatrix with the inverse of a matrix. Why don't use divmatrix right from the beginning ?

from pythonscad import *
mat=[[1,0,0,10],[0,1,0,0],[0,0,1,0],[0,0,0,1]] # Move to the right by 10

a=cube([1,1,1])
b=a.multmatrix(mat) # move to right
c=b.divmatrix(mat) # move back left
c.show()

mesh

With mesh function you can convert solid to a set of vertices and triangles like so:

from pythonscad import *

u=cube([1,1,1]) | cylinder(d=1,h=10)

pts, tris = u.mesh()
# Now you could use the pts for further processing or even manipulate them and do this ...

v = polyhedron(pts, tris)
v.show()

path_extrude

OpenSCAD has linear_extrude to move along a straight line and rotate_extrude to extrude along an arc. But there is nothing which can extrude along an arbritary line. This is reason to create path_extrude. With path_extrude you can extrude any shape along a path given by points. A 4th parameter in a vertex means the radius in this corner

from pythonscad import *
p=path_extrude(square(1),[[0,0,0],[0,0,10,3], [10,0,10,3],[10,10,10]]);
show(p);

quick transformations

Sometime translate or rotate is quite a burden to write when you just want to change one coordinate and still have to specify 3 values in the transformation
from pythonscad import *
# these are easier to write instead specifying full translate or rotate
obj=cube(2)
part1 = obj.right(2.5)
part2 = obj.left(2.5)
part3 = obj.up(2.5)
part4 = obj.down(2.5)
part5 = obj.front(2.5)
part6 = obj.back(2.5)
part7 = obj.rotx(90)
part8 = obj.roty(135)
part9 = obj.rotz(-45)
part5.show()

pulling objects apart

Sometimes its helpful to alter an existings STL and just adjust dimensions, whowever scale is not the right approach because you only want the new dimension just on one place, not all over the object. This is where pull can be helpful pull defines one point one direction where it inserts "void" right into the spanned area. Best use this to work on STL's

from pythonscad import *
# One Cube
c=cube([2,2,5])

p=c.pull([1,1,3],[4,-2,5])  # Attach Point , Pull amount
p.show()

Flower

Signed distance Functions within OpenSCAD

No need to create SDF objects in other tools and import into OpenSCAD after. Thanks to embedded libfive this can be done online. Watch this small sample to get an idea, how easy it is:

from pythonscad import *
from pylibfive import *

# Just assemble you libfive object first
c=lv_coord()
s1=lv_sphere(lv_trans(c,[2,2,2]),2)
b1=lv_box(c,[2,2,2])
sdf=lv_union_stairs(s1,b1,1,3)

# And mesh it finally to get something, that PythonSCAD can display
fobj=frep(sdf,[-4,-4,-4],[4,4,4],20)
show(fobj)
Flower

On a lower level, SDF used a formula and creates surfaces in the area, where this function hits zero. All functions, which are provided by libfive are also available in openSCAD. These are

import libfivew as lv
lv.x() # returns x coodinate
lv.y() # returns y coodinate
lv.z() # returns z coodinate
lv.sqrt(x)
lv.square(x)
lv.abs(x)
lv.max(x,y)
lv.min(x,y)
lv.sin(x)
lv.cos(x)
lv.tan(x)
lv.asin(x)
lv.acos(x)
lv.atan(x)
lv.exp(x)
lv.log(x)
lv.pow(x)
lv.comp(a,b)
lv.atan2(x,y)
lv.print(formula) # print tree of formula
A great introduction to the world of SDF can be found in here

align

Align can be used to combine combjects together without difficult transformations

from pythonscad import *
c = cube()
c1 = c
# scale with -1 will also invert the directions of all handles, so the objects will be abutting instead of coincident
c2 = c.align(scale(c1.origin,-1), c.origin)

show(c1 | c2)

edge

PythonSCAD has a new primitive called "edge" which just has a length

from pythonscad import *
e = edge(size=10, center=True)

# and of course you can extrude it
square = linear_extrude(e, height=10)
square.show()

# or get back the edges in a python list
all_e = square.edges()

fillet

You can use fillet to add roundings and chamfers to your existing object an easy cases, so dont challenge the algorithmus. Usually if you have an idea, how to fillet, the tool can do it, too

from pythonscad import *

c=cube(10);

mask=cube([30,1,30],center=True)

demo = [
    c.fillet(1), # Normal fillet with r=1, fn=2, thus bevel
    c.fillet(2,fn=5).right(15), #fillet with r=2 and more points
    c.fillet(3,mask,fn=20).right(30), # really round, but just with masked edges(which are front)
]
show(demo)
Flower

faces

You can retrieve a list of faces for any solid in a python list

from pythonscad import *

core=sphere(r=2)
faces = core.faces()

flower = core
for f in faces:
    flower |= f.linear_extrude(height=4)
flower.show()
Flower note that objects returned by faces (and edges) have a property called 'matrix' which is a 4x4 eigen matrix which shows their orientation in space. it can be used to filter them

export

You can use this to export your data to disk programmatically like so:

from pythonscad import *
c = cube(10)
cyl = cylinder(r=4,h=4)

c.export("mycube.stl")

# with 3mf format you can even store many objects at once

export( {
    "cube" : c,
    "cylinder" : cyl
},"myfile.3mf")

MultiToolExporter

When working with multi-tool / multi-color 3D printers, a single model is often split into one part per filament. MultiToolExporter is a PythonSCAD-only list subclass that automates that split: it stores (name, object) pairs (the same shape as dict.items()) and, on export, writes each part as f"{prefix}{name}{suffix}", where each part has all later objects subtracted from it. That cumulative-difference rule guarantees overlapping volume is claimed by exactly one part.

from pythonscad import *

# Two-color flag: red star punched out of a blue background.
background = cube([200, 100, 1]).color("blue")
star       = cylinder(r=20, h=2, fn=5).translate([100, 50, -0.5]).color("red")

exporter = MultiToolExporter("out/flag-", ".stl", mkdir=True)
exporter.append(("blue", background))  # blue: rectangle minus the star area
exporter.append(("red",  star))        # red: the star itself (later wins)
exporter.export()
# writes out/flag-blue.stl and out/flag-red.stl

exporter.show() previews the same split inside the GUI without writing files, and items can also be seeded directly via the constructor's items=[...] argument. See Multi-tool Export for the full reference.

spline

Spline is like 'polygon' just with the difference, that the resulting object is very round and will meet the given points

from pythonscad import *

pts=[[0,6],[10,-5],[20,10],[0,19]]
s = spline(pts,fn=20).linear_extrude(height=1)
for pt in pts:
    s |= (cylinder(r=0.3,h=10,fn=20)+pt)
s.show()
Spline

polyline

Polyline is a set of vertices which are connected with a line in between. It's not neccessarily closed. It can carry color but has not area and it's ignored in CSG operations. Its very useful to define cut lines in laser cutting.

from pythonscad import *

for i in range(10):
    polyline([[0,i], [20,i]]).show()

skin

Thanks to scrameta, pythonscad got wonderful skin. skin is like you put arbritary 2d objects in space and skin will cover all of them tightly

This is basically morphing a square into a circle

from pythonscad import *
a=square(4,center=True).roty(40)
b=circle(r=2,fn=20).rotx(40).up(10)
s=skin(a,b)
s.show()
Skin

add_parameter

This is how PythonSCAD can interact with the customizer. The customizer allows users to modify parameters through a GUI without editing code.

Basic Usage

from pythonscad import *

# Simple parameter with default value
width = add_parameter("width", 10)
name = add_parameter("name", "default")
enabled = add_parameter("enabled", True)

cube([width, width, width]).show()

Parameter Options

Option Type Description
description str Help text shown in customizer
group str Tab name (default: "Parameters")
range range/tuple Min/max for slider (numbers/vectors)
step float Step increment for spinbox
max_length int Maximum length (strings only)
options list/dict Dropdown options

Sliders (Numbers)

from pythonscad import *

# Integer slider using range() - note: range is exclusive, use 101 for max 100
quality = add_parameter("quality", 50, range=range(0, 101, 5))

# Float slider using tuple (min, max) or (min, max, step)
scale = add_parameter("scale", 1.0, range=(0.1, 10.0, 0.1))

# Spinbox with step (no slider)
angle = add_parameter("angle", 45.0, step=0.5)
from pythonscad import *

# Simple options list
color = add_parameter("color", "red", options=["red", "green", "blue"])

# Labeled options (value: label)
quality = add_parameter("quality", 10, options={10: "Low", 20: "Medium", 30: "High"})

Vectors

from pythonscad import *

# Vector with constraints (applied to all elements, max 4 elements)
size = add_parameter("size", [10, 20, 30], range=(1, 100, 1))

Groups and Organization

from pythonscad import *

# Organize parameters into tabs
width = add_parameter("width", 10, group="Dimensions")
height = add_parameter("height", 20, group="Dimensions")
color = add_parameter("color", "red", group="Appearance")

# Special groups
debug = add_parameter("debug", False, group="Hidden")    # Not shown in UI
units = add_parameter("units", "mm", group="Global")     # Appears on all tabs

Descriptions

from pythonscad import *

# Add help text
width = add_parameter("width", 10,
    description="Width of the model in mm",
    group="Dimensions")

rendervars

With rendervars you can control the camera / viewport settings directly from your Python script. This is useful for setting up specific viewing angles when sharing scripts or creating presentations of your models.

from pythonscad import *

c = cube(10, center=True)
c.show()

rendervars(vpd=150, vpr=[55, 0, 25], vpt=[0, 0, 5])

Parameters

Parameter Type Description
vpd float Viewer distance – how far the camera is from the object
vpf float Field of view angle in degrees
vpr [x, y, z] Viewport rotation in degrees
vpt [x, y, z] Viewport translation – the point the camera looks at

All parameters are optional. Only the parameters you provide will be changed; the rest keep their current values.

concat

Concat concatenates the triangles and vertices of serveral objects without actually createing an Union operation on them. This is useful when the sub-parts are not yet water-tight and CSG would fail on them.

from pythonscad import *

alltogether = concat(part1, part2, part3)

existing functions are improved

Some of the existing functions got additional useful parameters

union, difference

Specify r or fn as an additional parameter and the new created common edges get nice roundings

circle gets an angle parameter

from pythonscad import *

pie = circle(r=5,angle=70)
pie.show()
Circle Pie

same for cylinder, why should it be missing

from pythonscad import *

pie = cylinder(r=5,h=6, angle=90)
pie.show()
Cylinder Pie

sphere can accept a function which receives a 3d vector and will output a radius

from pythonscad import *

def rfunc(v):
  cf = abs(v[0])+abs(v[1])+abs(v[2])+3
  return 10/cf
sphere(rfunc,fs=0.5,fn=10).show()
Sphere with custom radius

linear_extrude can also extrude a python function. this will get a height and shall return a 2d polygon

from pythonscad import *
from math import *
def xsection(h):
    v =5+sin(h)
    return [[-v,-v],[v,-v],[v,v],[-v,v]]

prisma = linear_extrude(xsection, height=10, slices=20)
prisma.show()
Linear Extrude with custom xsection

rotate_extrude can also extrude a python function. this will get a height and shall return a 2d polygon

from pythonscad import *
from math import *
def xsection(h):
    v =2*sin(4*pi*h)
    res=[[10+v,-v],[15-v,-v],[15-v,5+v],[10+v,5+v]]
    return res
rotate_extrude(xsection,fn=50).show()
Rotate Extrude with custom xsection

rotate_extrude has a v parameter , when not [0,0,0] it will do nice helix

from pythonscad import *

circle(3).right(10).rotate_extrude(v=[0,0,20],angle=600).show()
Sphere with custom radius