Skip to content

Instantly share code, notes, and snippets.

@aavogt
Last active March 13, 2024 18:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aavogt/8fb7162e572d72049748e1e42b12bbd2 to your computer and use it in GitHub Desktop.
Save aavogt/8fb7162e572d72049748e1e42b12bbd2 to your computer and use it in GitHub Desktop.
cadquery 3d strip
import cadquery as cq
from copy import copy
class Ribbon3:
""" A ribbon is a way to make a sequence of Workplane.box
end-to-end without repeating dimensions.
I like the offset2D approach:
cq.Workplane().hLine(5).vLine(6).offset2D(2).extrude(3)
The near equivalent is:
Ribbon3(cq.Workplane(), w=2, h=3).x(5).y(6).end()
unlike offset2D, corners are not rounded, but you can go up with z()
offset2D does lengths for the midplane. Ribbon3 x(1).z(10).y(1) should
put the two bottom XY planes 10 mm apart.
"""
def __init__(self, cq=cq.Workplane(), w=5, h=2):
self.cq = cq
self.axis = 2
self.d = [w, h, 0]
self.p = [0, 0, 0]
# states for push/pop
self.ds = []
self.axes = []
self.ps = []
self.planes = []
def go(self, naxis, length):
self.d[naxis], self.d[self.axis] = abs(length), self.d[naxis]
if (length < 0):
self.p[naxis] = length
self.d[naxis] += self.d[self.axis]
self.cq = self.cq.transformed(offset=self.p).box(self.d[0], self.d[1], self.d[2], False)
self.p[self.axis] = 0
if (length < 0):
self.p[naxis] = 0
else:
self.p[naxis] = length
self.axis = naxis
return self
def x(self, length):
return self.go(0, length)
def y(self, length):
return self.go(1, length)
def z(self, length):
return self.go(2, length)
def end(self):
return self.cq
def push(self):
""" Save the current state """
self.ps.append(self.p.copy())
self.ds.append(self.d.copy())
self.axes.append(self.axis)
self.planes.append(copy(self.cq.plane))
print("pushed", self.ps, self.ds, self.axes)
return self
def pop(self):
""" Restore the previous state """
self.p = self.ps.pop()
self.axis = self.axes.pop()
self.d = self.ds.pop()
self.cq.plane = self.planes.pop()
print("restored", self.p, self.d, self.axis)
return self
def branch(self, f):
""" Save the current state, call f, restore the previous state
ribbon.branch(lambda c: c.x(4).y(5)).x(-5).y(5).end()
Ideally the syntax would be lighter, perhaps
ribbon.branch(_.x(4).y(5)).x(-5).y(5).end()
fn.py defines an underscore, but when I try to use it I get
'int' object has no attribute 'x'
from fn import _
ribbon.branch(_.x(4).y(5)).x(-5).y(5).end()
I could add x,y,z etc. attributes to _, but could they
have written it such that _ has every method which
just stores the syntax tree for later use (when the _
is defined).
"""
return f(self.push()).pop()
def __call__(self, f):
""" for now this is branch, but it should be something else? """
return self.branch(f)
ribbon_test = Ribbon3().x(10).y(20).z(20).x(-10).y(30).z(-5).end()
show_object(ribbon_test) # https://i.ibb.co/sW0tBDW/ribbon.png
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment