This is the complete source code listing for openscad.py. Feel free to copy and paste into a file
of that name, and import it into your projects as described in detail in
my book, "Python for 3D Printing", by John Clark Craig...
Amazon listing
# openscad.py
import os
import math
import inspect
# Global commands accumulator
_cmds = ""
_use = ""
# Function modifying parameters
fragments = 31
# Constants
tiny = 1e-99
# Functions for driving Openscad
def startup(s):
global _use
_use += f"""{s}\n"""
def literally(s):
global _cmds
_cmds += f"""{s}\n"""
def cyl(diameter, height):
global _cmds, fragments
radius = diameter / 2
_cmds = (
f"cylinder(h={height},"
f"r1={radius},r2={radius},"
f"center=false,$fn={fragments});\n\n"
) + _cmds
def cylinder(diameter, height):
global _cmds, fragments
radius = diameter / 2
_cmds = (
f"cylinder(h={height},"
f"r1={radius},r2={radius},"
f"center=false,$fn={fragments});\n\n"
) + _cmds
def cone(diameter, height):
global _cmds, fragments
radius = diameter / 2
_cmds = (
f"cylinder(h={height},"
f"r1={radius},r2={0},"
f"center=false,"
f"$fn={fragments});\n\n"
) + _cmds
def cone_truncated(diameter1, diameter2, height):
global _cmds, fragments
radius = diameter1 / 2
radius2 = diameter2 / 2
_cmds = (
f"cylinder(h={height},r1={radius},"
f"r2={radius2},center=false,"
f"$fn={fragments});\n\n"
) + _cmds
def sphere(diameter):
global _cmds, fragments
radius = diameter / 2
_cmds = (f"sphere({radius},"
f"$fn={fragments});\n\n" ) + _cmds
def box(x, y, z):
global _cmds
_cmds = (f"cube({[x,y,z]},"
f"center=false);\n\n") + _cmds
def polygon(points_list, height):
global _cmds, fragments
_cmds = (
f"linear_extrude({height})\n"
f"polygon({points_list},"
f"convexity=20,$fn={fragments});\n\n"
) + _cmds
def triangle(point1, point2, point3, height):
polygon([point1, point2, point3], height)
def regular_polygon(sides, radius, height):
global _cmds
_cmds = "}\n\n" + _cmds
for wedge in range(sides):
p1 = _cart(radius,wedge*360/sides)
p2 = _cart(radius,(wedge+1)*360/sides)
triangle([0, 0], p1, p2, height)
_cmds = "union(){\n" + _cmds
def tube(outside_diam, inside_diam, height):
global _cmds, fragments
r1 = outside_diam / 2
r2 = inside_diam / 2
_cmds = (
"difference(){\n"
f"cylinder(h={height},r1={r1},r2={r1},"
f"center=false,$fn={fragments});\n"
f"cylinder(h={height*3},r1={r2},r2={r2},"
f"center=true,$fn={fragments});\n"
"}\n" ) + _cmds
def polyhedron(points_list, faces_list):
global _cmds
_cmds = (f"polyhedron({points_list},"
f"{faces_list},convexity=20);\n\n"
) + _cmds
def text(
text="",
size=10,
font="Liberation Sans",
halign="left",
valign="baseline",
spacing=1,
direction="ltr",
language="en",
script="latin",
height=1,
):
global _cmds, fragments
_cmds = (
f'linear_extrude({height})\n'
f'text(text="{text}",size={size},'
f'font="{font}",halign="{halign}",'
f'valign="{valign}",spacing={spacing},'
f'direction="{direction}",'
f'language="{language}",'
f'script="{script}",'
f'$fn={fragments});\n\n'
) + _cmds
def translate(x, y, z):
global _cmds
_cmds = f"translate([{x},{y},{z}])\n" + _cmds
def rotate(x, y, z):
global _cmds
_cmds = f"rotate([{x},{y},{z}])\n" + _cmds
def scale(x, y, z):
global _cmds
_cmds = f"scale([{x},{y},{z}])\n" + _cmds
def resize(x, y, z):
global _cmds
_cmds = f"resize([{x},{y},{z}])\n" + _cmds
def mirror(x, y, z):
global _cmds
_cmds = f"mirror([{x},{y},{z}])\n" + _cmds
def color(color_name, alpha=1.0):
global _cmds
_cmds = (f'color("{color_name}",'
f'{alpha})\n') + _cmds
def rgb(r, g, b, alpha=1.0):
global _cmds
_cmds = (f"color([{r/255},{g/255},"
f"{b/255},{alpha}])\n") + _cmds
def offset_round(distance, height):
global _cmds, fragments
_cmds = (
f"linear_extrude({height})\n"
f"offset(r={distance},chamfer=false,"
f"$fn={fragments})\n"
f"projection()\n" ) + _cmds
def offset_straight(distance, height):
global _cmds
_cmds = (
f"linear_extrude({height})\n"
f"offset(delta={distance},"
f"chamfer=false)\n"
f"projection()\n"
) + _cmds
def offset_chamfer(distance, height):
global _cmds
_cmds = (
f"linear_extrude({height})\n"
f"offset(delta={distance},"
f"chamfer=true)\n"
f"projection()\n"
) + _cmds
def projection(height):
global _cmds
_cmds = (f"linear_extrude({height})"
f"\nprojection()\n") + _cmds
def slice(height):
global _cmds
_cmds = (f"linear_extrude({height})\n"
f"projection(cut=true)\n") + _cmds
def spiral(turns, height, scale=1):
global _cmds, fragments
_cmds = (
f"linear_extrude(height={height},"
f"twist=-{360*turns},"
f"scale={scale},"
f"slices={fragments},"
f"center=false,"
f"convexity=20,"
f"$fn={fragments})\n"
f"projection()\n"
) + _cmds
def rotate_extrude(angle=360):
global _cmds, fragments
_cmds = (
f"rotate_extrude(angle={angle},"
f"convexity=20,$fn={fragments})\n"
f"projection()\n"
) + _cmds
def union(obj_list):
global _cmds
cmd = "union(){\n"
for obj in obj_list:
cmd += obj
cmd += "}\n"
_cmds = cmd + _cmds
def difference(obj_list):
global _cmds
cmd = "difference(){\n"
for obj in obj_list:
cmd += obj
cmd += "}\n"
_cmds = cmd + _cmds
def intersection(obj_list):
global _cmds
cmd = "intersection(){\n"
for obj in obj_list:
cmd += obj
cmd += "}\n"
_cmds = cmd + _cmds
def hull(obj_list):
global _cmds
cmd = "hull(){\n"
for obj in obj_list:
cmd += obj
cmd += "}\n"
_cmds = cmd + _cmds
def minkowski(obj_list):
global _cmds
cmd = "minkowski(){\n"
for obj in obj_list:
cmd += obj
cmd += "}\n"
_cmds = cmd + _cmds
def surface(filename,invert="false"):
global _cmds
_cmds = (f'surface(file=\"{filename}\",'
f'convexity=5,'
f'invert={invert});\n') + _cmds
def result():
global _cmds
res = _cmds
_cmds = ""
return res
def output(cmds_list=""):
global _use
calling_file = inspect.stack()[1].filename
srcfile = calling_file.split("\\")[-1]
dstfile = srcfile.replace(".py", ".scad")
f = open(dstfile, "w")
if _use:
f.write(_use)
_use = ""
for cmd in cmds_list:
f.write(cmd)
f.close()
def platonic_cube(n):
box(n, n, n)
translate(-n / 2, -n / 2, -n / 2)
def platonic_tetrahedron(n):
n0 = n * (8 / 3) ** -0.5
n1 = ((8 / 9) ** 0.5) * n0
n2 = ((2 / 9) ** 0.5) * n0
n3 = ((2 / 3) ** 0.5) * n0
n4 = -n0 / 3
v0 = [n1, 0, n4]
v1 = [-n2, n3, n4]
v2 = [-n2, -n3, n4]
v3 = [0, 0, n0]
points = [v0, v1, v2, v3]
faces = [[0, 1, 2], [0, 3, 1],
[1, 3, 2], [2, 3, 0]]
polyhedron(points, faces)
def platonic_octahedron(n):
n0 = n * 2 ** -0.5
v0 = [n0, 0, 0]
v1 = [-n0, 0, 0]
v2 = [0, n0, 0]
v3 = [0, -n0, 0]
v4 = [0, 0, n0]
v5 = [0, 0, -n0]
points = [v0, v1, v2, v3, v4, v5]
faces = [
[0, 4, 2],
[2, 4, 1],
[1, 4, 3],
[3, 4, 0],
[2, 5, 0],
[1, 5, 2],
[3, 5, 1],
[0, 5, 3],
]
polyhedron(points, faces)
def platonic_dodecahedron(n):
phi = (1 + 5 ** 0.5) / 2
fac = n * phi / 2
n0 = phi * fac
n1 = fac / phi
v0 = [fac, fac, fac]
v1 = [-fac, fac, fac]
v2 = [fac, -fac, fac]
v3 = [-fac, -fac, fac]
v4 = [fac, fac, -fac]
v5 = [-fac, fac, -fac]
v6 = [fac, -fac, -fac]
v7 = [-fac, -fac, -fac]
v8 = [0, n0, n1]
v9 = [0, -n0, n1]
v10 = [0, n0, -n1]
v11 = [0, -n0, -n1]
v12 = [n1, 0, n0]
v13 = [n1, 0, -n0]
v14 = [-n1, 0, n0]
v15 = [-n1, 0, -n0]
v16 = [n0, n1, 0]
v17 = [-n0, n1, 0]
v18 = [n0, -n1, 0]
v19 = [-n0, -n1, 0]
points = [
v0,
v1,
v2,
v3,
v4,
v5,
v6,
v7,
v8,
v9,
v10,
v11,
v12,
v13,
v14,
v15,
v16,
v17,
v18,
v19,
]
f1 = [0, 16, 18, 2, 12]
f2 = [14, 12, 2, 9, 3]
f3 = [19, 3, 9, 11, 7]
f4 = [15, 7, 11, 6, 13]
f5 = [4, 13, 6, 18, 16]
f6 = [2, 18, 6, 11, 9]
f7 = [12, 14, 1, 8, 0]
f8 = [3, 19, 17, 1, 14]
f9 = [7, 15, 5, 17, 19]
f10 = [13, 4, 10, 5, 15]
f11 = [16, 0, 8, 10, 4]
f12 = [1, 17, 5, 10, 8]
faces = [f1, f2, f3, f4, f5, f6,
f7, f8, f9, f10, f11, f12]
polyhedron(points, faces)
def platonic_icosahedron(n):
phi = (1 + 5 ** 0.5) / 2
fac = n / 2
n0 = phi * fac
v0 = [0, fac, n0]
v1 = [0, fac, -n0]
v2 = [0, -fac, n0]
v3 = [0, -fac, -n0]
v4 = [fac, n0, 0]
v5 = [fac, -n0, 0]
v6 = [-fac, n0, 0]
v7 = [-fac, -n0, 0]
v8 = [n0, 0, fac]
v9 = [-n0, 0, fac]
v10 = [n0, 0, -fac]
v11 = [-n0, 0, -fac]
points = [v0, v1, v2, v3, v4, v5, v6,
v7, v8, v9, v10, v11]
f1 = [2, 9, 0]
f2 = [2, 7, 9]
f3 = [2, 5, 7]
f4 = [2, 8, 5]
f5 = [2, 0, 8]
f6 = [1, 4, 6]
f7 = [1, 6, 11]
f8 = [1, 11, 3]
f9 = [1, 3, 10]
f10 = [1, 10, 4]
f11 = [0, 6, 4]
f12 = [6, 0, 9]
f13 = [9, 11, 6]
f14 = [11, 9, 7]
f15 = [7, 3, 11]
f16 = [3, 7, 5]
f17 = [5, 10, 3]
f18 = [10, 8, 5]
f19 = [8, 4, 10]
f20 = [4, 8, 0]
faces = [
f1,
f2,
f3,
f4,
f5,
f6,
f7,
f8,
f9,
f10,
f11,
f12,
f13,
f14,
f15,
f16,
f17,
f18,
f19,
f20,
]
polyhedron(points, faces)
# Local utility functions
def _cart(radius, angle):
rad = math.radians(angle)
x = radius * math.cos(rad)
y = radius * math.sin(rad)
return [x, y]