Free function API

For situations when more freedom in crafting individual objects is required, a free function API is provided. This API has no hidden state, but may result in more verbose code. One can still use selectors as methods, but all other operations are implemented as free functions. Placement of objects and creation of patterns can be achieved using the various overloads of the moved method.

Currently this documentation is incomplete, more examples can be found in the tests.

Tutorial

The purpose of this section is to demonstrate how to construct Shape objects using the free function API.

from cadquery.func import *

dh = 2
r = 1

# construct edges
edge1 = circle(r)
edge2 = circle(1.5*r).moved(z=dh)
edge3 = circle(r).moved(z=1.5*dh)

# loft the side face
side = loft(edge1, edge2, edge3)

# bottom face
bottom = fill(side.edges('<Z'))

# top face with continuous curvature
top = cap(side.edges('>Z'), side, [(0,0,1.6*dh)])

# assemble into a solid
s = solid(side, bottom, top)

# construct the final result
result = s.moved((-3*r, 0, 0), (3*r, 0, 0))

The code above builds a non-trivial object by sequentially constructing individual faces, assembling them into a solid and finally generating a pattern.

It begins with defining few edges.

edge1 = circle(r)
edge2 = circle(2*r).moved(z=dh)
edge3 = circle(r).moved(z=1.5*dh)

Those edges are used to create the side faces of the final solid using loft().

side = loft(edge1, edge2, edge3)

Once the side is there, cap() and fill() are used to define the top and bottom faces. Note that cap() tries to maintain curvature continuity with respect to the context shape. This is not the case for fill().

# bottom face
bottom = fill(side.edges('<Z'))

# top face with continuous curvature
top = cap(side.edges('>Z'), side, [(0,0,1.75*dh)])

Next, all the faces are assembled into a solid.

s = solid(side, bottom, top)

Finally, the solid is duplicated and placed in the desired locations creating the final compound object. Note various usages of moved().

result = s.moved((-3*r, 0, 0), (3*r, 0, 0))

In general all the operations are implemented as free functions, with the exception of placement and selection which are strictly related to a specific shape.

Primitives

Various 1D, 2D and 3D primitives are supported.

from cadquery.func import *

e = segment((0,0), (0,1))

c = circle(1)

f = plane(1, 1.5)

b = box(1, 1, 1)

result = compound(e, c.move(2), f.move(4), b.move(6))

Boolean operations

Boolean operations are supported and implemented as operators and free functions. In general boolean operations are slow and it is advised to avoid them and not to perform the in a loop. One can for example union multiple solids at once by first combining them into a compound.

from cadquery.func import *

c1 = cylinder(1, 2)
c2 = cylinder(0.5, 3)

f1 = plane(2, 2).move(z=1)
f2 = plane(1, 1).move(z=1)

e1 = segment((0,-2.5, 1), (0,2.5,1))

# union
r1 = c2 + c1
r2 = fuse(f1, f2)

# difference
r3 = c1 - c2
r4 = cut(f1, f2)

# intersection
r5 = c1*c2
r6 = intersect(f1, f2)

# splitting
r7 = (c1 / f1).solids('<Z')
r8 = split(f2, e1).faces('<X')

results = (r1, r2, r3, r4, r5, r6, r7, r8)
result = compound([el.moved(2*i) for i,el in enumerate(results)])

Note that bool operations work on 2D shapes as well.

Boolean operations support optionally history that allows to refer to generated, modified or deleted shapes. In order to use it one has to instantiate the cadquery.occ_impl.shapes.History class and pass it to the operations of interest. The individual boolean operations entries (i.e. instances of cadquery.occ_impl.shapes.Op) can be accessed using indexing or name-based queries. In order to support names, one need to specify the name parameter when invoking an operation.

Warning

The history tracking feature of the free function API is experimental and may change.

Shape selection

Shape selection can be performed using the usual vertices(), edges(), wires(), faces(), shells(), solids() methods. Those methods return a shape or a compound. Alternatively, one can use vertex(), edge(), wire(), face(), shell(), solid() methods. Those methods either return a single shape or throw. Additionally, selection can be performed using siblings(), ancestors(), special selectors. Last but not least, selections can be combined using set operations implemented via convenient operator syntax __and__(), __or__(), __mod__(). The last operator implements a set difference operation.

Shape construction

Constructing complex shapes from simple shapes is possible in various contexts.

from cadquery.func import *

e1 = segment((0,0), (1,0))
e2 = segment((1,0), (1,1))

# wire from edges
r1 = wire(e1, e2)

c1 = circle(1)

# face from a planar wire
r2 = face(c1)

# solid from faces
f1 = plane(1,1)
f2 = f1.moved(z=1)
f3 = extrude(f1.wires(), (0,0,1))

r3 = solid(f1,f2,*f3)

# compound from shapes
s1 = circle(1).moved(ry=90)
s2 = plane(1,1).move(rx=90).move(y=2)
s3 = cone(1,1.5).move(y=4)

r4 = compound(s1, s2, s3)

results = (r1, r2, r3, r4,)
result = compound([el.moved(2*i) for i,el in enumerate(results)])

Operations

Free function API currently supports extrude(), loft(), revolve(), sweep(), hollow(), draft(), prism(), chamfer() and fillet() operations.

from cadquery.func import *

r = rect(1,0.5)
f = face(r, circle(0.2).moved(0.2), rect(0.2, 0.4).moved(-0.2))
c = circle(0.2)
p = spline([(0,0,0), (0,-1,2)], [(0,0,1), (0,-1,1)])

# extrude
s1 = extrude(r, (0,0,2))
s2 = extrude(fill(r), (0,0,1))

# sweep
s3 = sweep(r, p)
s4 = sweep(f, p)

# loft
s5 = loft(r, c.moved(z=2))
s6 = loft(r, c.moved(z=1), cap=True)\

# revolve
s7 = revolve(fill(r), (0.5, 0, 0), (0, 1, 0), 90)

results = (s1, s2, s3, s4, s5, s6, s7)
result = compound([el.moved(2*i) for i,el in enumerate(results)])

Most operations support optionally history that allows to refer to generated, modified or deleted shapes. In order to use it one has to instantiate the cadquery.occ_impl.shapes.History class and pass it to the operations of interest. The individual modeling steps (i.e. instances of cadquery.occ_impl.shapes.Op) can be accessed using indexing or name-based queries. In order to support names, one need to specify the name parameter when invoking an operation. Here is an usage example of this feature.

from cadquery.func import *

dx = 5
dy = 3
dz = 1.5

hist = History()

# make a hollow base
base_face = plane(dx, dy)
base = extrude(base_face, (0, 0, dz))
res = fillet(base, base.edges("|Z"), 0.5)
ftop = res.face(">Z")
resh = hollow(res, ftop, -0.2, history=hist, name="hollow")

# add mounting points
mid = resh.face(">Z[-2]")
f = (
    face(circle(0.1), circle(0.05))
    .moved(offset2D(base_face.wire(), -0.5).vertices())
    .moved(mid)
    .moved(z=0)
)
res = prism(resh, mid, f, base.face(">Z"), history=hist, name="mounts")

# add fillet
res = fillet(
    res,
    hist["hollow"].generated().edges("<Z") | hist["mounts"].generated().edges("<Z"),
    0.04,
)

# add a lip
top = hist["hollow"].modified().face(">Z")
top_ow = top.outerWire()

res = prism(
    res,
    top,
    face(top_ow, offset2D(top_ow, -0.1)),
    0.2,
    additive=False,
    history=hist,
    name="lip",
)

# apply chamfers
res = chamfer(res, hist["lip"].modified(top).face().outerWire(), 0.05)
result = chamfer(
    res, compound([f.face().outerWire() for f in hist["mounts"].last()]), 0.02
)

Some operations like e.g. extrude() or prism() support referring to the first() and last() shape as well.

Warning

The history tracking feature of the free function API is experimental and may change.

Placement

Placement and creation of arrays is possible using move() and moved().

from cadquery.func import *

locs = [(0,-1,0), (0,1,0)]

s = sphere(1).moved(locs)
c = cylinder(1,2).move(rx=15).moved(*locs)

result = compound(s, c.moved(2))

Text

The free function API has extensive text creation capabilities including text on planar curves and text on surfaces.