Free function API
Warning
The free function API is experimental and may change.
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.
fromcadquery.funcimport*dh=2r=1# construct edgesedge1=circle(r)edge2=circle(1.5*r).moved(z=dh)edge3=circle(r).moved(z=1.5*dh)# loft the side faceside=loft(edge1,edge2,edge3)# bottom facebottom=fill(side.edges('<Z'))# top face with continuous curvaturetop=cap(side.edges('>Z'),side,[(0,0,1.6*dh)])# assemble into a solids=solid(side,bottom,top)# construct the final resultresult=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 usingloft().
side=loft(edge1,edge2,edge3)
Once the side is there,cap() andfill() are used to define the top and bottom faces.Note thatcap() tries to maintain curvature continuity with respect to the context shape. This is not the case forfill().
# bottom facebottom=fill(side.edges('<Z'))# top face with continuous curvaturetop=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 ofmoved().
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.
fromcadquery.funcimport*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.
fromcadquery.funcimport*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))# unionr1=c2+c1r2=fuse(f1,f2)# differencer3=c1-c2r4=cut(f1,f2)# intersectionr5=c1*c2r6=intersect(f1,f2)# splittingr7=(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)fori,elinenumerate(results)])
Note that bool operations work on 2D shapes as well.
Shape construction
Constructing complex shapes from simple shapes is possible in various contexts.
fromcadquery.funcimport*e1=segment((0,0),(1,0))e2=segment((1,0),(1,1))# wire from edgesr1=wire(e1,e2)c1=circle(1)# face from a planar wirer2=face(c1)# solid from facesf1=plane(1,1)f2=f1.moved(z=1)f3=extrude(f1.wires(),(0,0,1))r3=solid(f1,f2,*f3)# compound from shapess1=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)fori,elinenumerate(results)])
Operations
Free function API currently supportsextrude(),loft(),revolve() andsweep() operations.
fromcadquery.funcimport*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)])# extrudes1=extrude(r,(0,0,2))s2=extrude(fill(r),(0,0,1))# sweeps3=sweep(r,p)s4=sweep(f,p)# lofts5=loft(r,c.moved(z=2))s6=loft(r,c.moved(z=1),cap=True)\# revolves7=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)fori,elinenumerate(results)])
Placement
Placement and creation of arrays is possible usingmove() andmoved().
fromcadquery.funcimport*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 onplanar curves and text on surfaces.
fromcadquery.funcimport*frommathimportpi# parametersD=5H=2*DS=H/10TH=S/10TXT="CadQuery"# base and spinec=cylinder(D,H).moved(rz=-135)cf=c.faces("%CYLINDER")spine=(c*plane().moved(z=D)).edges().trim(pi/2,pi)# planarr1=text(TXT,1,spine,planar=True).moved(z=-S)# normalr2=text(TXT,1,spine)# projectedr3=text(TXT,1,spine,cf).moved(z=S)# projected and thickenedr4=offset(r3,TH).moved(z=S)result=compound(r1,r2,r3,r4)
Adding features manually
In certain cases it is desirable to add features such as holes or protrusions manually.E.g., for complicated shapes it might be beneficial performance-wise because itavoids boolean operations. One can add or remove faces, add holes to existing facesand last but not least reconstruct existing solids.
fromcadquery.funcimport*w=1r=0.9*w/2# boxb=box(w,w,w)# bottom faceb_bot=b.faces('<Z')# top facesb_top=b.faces('>Z')# inner faceinner=extrude(circle(r),(0,0,w))# add holes to the bottom and top faceb_bot_hole=b_bot.addHole(inner.edges('<Z'))b_top_hole=b_top.addHole(inner.edges('>Z'))# construct the final solidresult=solid(b.remove(b_top,b_bot).faces(),#side facesb_bot_hole,# bottom with a holeinner,# inner cylinder faceb_top_hole,# top with a hole)
If the base shape is more complicated, it is possible to use local sewing thattakes into account on indicated elements of the context shape. This, however,necessitates a two step approach - first a shell needs to be explicitly sewnand only then the final solid can be constructed.
fromcadquery.funcimport*w=1h=0.1r=0.9*w/2# boxb=box(w,w,w)# top faceb_top=b.faces('>Z')# protrusionfeat_side=extrude(circle(r).moved(b_top.Center()),(0,0,h))feat_top=face(feat_side.edges('>Z'))feat=shell(feat_side,feat_top)# sew into a shell# add hole to the boxb_top_hole=b_top.addHole(feat.edges('<Z'))b=b.replace(b_top,b_top_hole)# local sewing - only two faces are taken into accountsh=shell(b_top_hole,feat.faces('<Z'),ctx=(b,feat))# construct the final solidresult=solid(sh)
Mapping onto parametric space
To complement functionalities described, it is possible to trim edges and faces explicitly using simple rectangulartrims, polygons, splines or arbitrary wires.
frommathimportpifromcadquery.funcimportcylinder,edgeOn,compound,wire# parametersd=1.5h=3du=piNturns=2# construct the base surfacebase=cylinder(d,h).faces("%CYLINDER")# rectangular trimr1=base.trim(-pi/2,0,0,h/3)# polyline trimr2=base.trim((0,0),(pi,0),(pi/2,h/2))# construct a pcurvepcurve=edgeOn(base,[(pi/2,h/4),(pi,h/4),(pi,h/2),(pi/2,h/2)],periodic=True)# pcurve trimr3=base.trim(wire(pcurve))result=compound(r1,r2.moved(x=2),r3.moved(x=4))
This in principle allows to model arbitrary shapes in the parametric domain, but often it is more desirableto work with higher level objects like wires.
fromcadquery.funcimportcylinder,loft,wireOn,segmentfrommathimportpi# parametersd=1.5h=3du=piNturns=2# construct the base surfacebase=cylinder(d,h).faces("%CYLINDER")# construct a planar 2D patch for u,v trimminguv_patch=loft(segment((0,0),(du,0)),segment((Nturns*2*pi,h),(Nturns*2*pi+du,h)))# map it onto the cylinderw=wireOn(base,uv_patch)# check that the pcurves were createdforeinw:asserte.hasPCurve(base),"No p-curve on base present"# trim the base surfaceresult=base.trim(w)
Note that trimming of periodic faces requires manual seam construction and an additional sewingstep to ensure correctness.
fromcadquery.funcimportcircle,extrude,spline,edgeOn,segment,wire,shellfrommathimportpi# baser=5h=5f=extrude(circle(r),(0,0,-h))# trimming edgesspl=spline([(0,h),(pi,h/2.5),(2*pi,h)],tgts=[(0.1,0),(0.1,0)])top=edgeOn(f,spl)bot=edgeOn(f,segment((2*pi,0),(0,0)))side1=edgeOn(f,segment((0,0),(0,h)))side2=edgeOn(f,segment((2*pi,h),(2*pi,0)))# trimming wiretrim_wire=wire(top,side1,bot,side2)# trim and sewresult=shell(f.trim(trim_wire))
Finally, it is also possible to map complete faces.
fromcadquery.funcimportsphere,text,faceOnbase=sphere(5).faces()result=faceOn(base,text("CadQuery",1))