cadquery-freecad-module/doc/examples.rst
2013-04-23 20:33:39 -04:00

688 lines
22 KiB
ReStructuredText

.. _examples:
*********************************
CadQuery Examples
*********************************
.. automodule:: cadquery
The examples on this page can help you learn how to build objects with CadQuery.
They are organized from simple to complex, so working through them in order is the best way to absorb them.
Each example lists the api elements used in the example for easy reference.
Items introduced in the example are marked with a **!**
.. note::
You may want to work through these examples by pasting the text into a scratchpad on the live website.
If you do, make sure to take these steps so that they work:
1. paste the content into the build() method, properly intented, and
2. add the line 'return result' at the end. The samples below are autogenerated, but they use a different
syntax than the models on the website need to be.
.. warning::
* You have to have an svg capable browser to view these!
* For brevity, these examples do not include the MetaData and Header sections required for a
fully functional parametric part. See the :ref:`quickstart` for a guide that includes those portions
.. contents:: List of Examples
:backlinks: entry
Simple Rectangular Plate
------------------------
Just about the simplest possible example, a rectangular box
.. cq_plot::
result = Workplane("front").box(2.0,2.0,0.5)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane` **!**
* :py:meth:`Workplane.box` **!**
Plate with Hole
------------------------
A rectangular box, but with a hole added.
"\>Z" selects the top most face of the resulting box. The hole is located in the center because the default origin
of a working plane is at the center of the face. The default hole depth is through the entire part.
.. cq_plot::
result = Workplane("front").box(2.0,2.0,0.5).faces(">Z").hole(0.5)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.hole` **!**
* :py:meth:`Workplane.box`
* :py:meth:`Workplane.box`
An extruded prismatic solid
-------------------------------
Build a prismatic solid using extrusion. After a drawing operation, the center of the previous object
is placed on the stack, and is the reference for the next operation. So in this case, the rect() is drawn
centered on the previously draw circle.
By default, rectangles and circles are centered around the previous working point.
.. cq_plot::
result = Workplane("front").circle(2.0).rect(0.5,0.75).extrude(0.5)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.circle` **!**
* :py:meth:`Workplane.rect` **!**
* :py:meth:`Workplane.extrude` **!**
* :py:meth:`Workplane`
Building Profiles using lines and arcs
--------------------------------------
Sometimes you need to build complex profiles using lines and arcs. This example builds a prismatic
solid from 2-d operations.
2-d operations maintain a current point, which is initially at the origin. Use close() to finish a
closed curve.
.. cq_plot::
result = Workplane("front").lineTo(2.0,0).lineTo(2.0,1.0).threePointArc((1.0,1.5),(0.0,1.0))\
.close().extrude(0.25)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.threePointArc` **!**
* :py:meth:`Workplane.lineTo` **!**
* :py:meth:`Workplane.extrude`
* :py:meth:`Workplane`
Moving The Current working point
---------------------------------
In this example, a closed profile is required, with some interior features as well.
This example also demonstrates using multiple lines of code instead of longer chained commands,
though of course in this case it was possible to do it in one long line as well.
A new work plane center can be established at any point.
.. cq_plot::
result = Workplane("front").circle(3.0) #current point is the center of the circle, at (0,0)
result = result.center(1.5,0.0).rect(0.5,0.5) # new work center is (1.5,0.0)
result = result.center(-1.5,1.5).circle(0.25) # new work center is ( 0.0,1.5).
#the new center is specified relative to the previous center, not global coordinates!
result = result.extrude(0.25)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.center` **!**
* :py:meth:`Workplane`
* :py:meth:`Workplane.circle`
* :py:meth:`Workplane.rect`
* :py:meth:`Workplane.extrude`
Using Point Lists
---------------------------
Sometimes you need to create a number of features at various locations, and using :py:meth:`Workplane.center`
is too cumbersome.
You can use a list of points to construct multiple objects at once. Most construction methods,
like :py:meth:`Workplane.circle` and :py:meth:`Workplane.rect`, will operate on multiple points if they are on the stack
.. cq_plot::
r = Workplane("front").circle(2.0) # make base
r = r.pushPoints( [ (1.5,0),(0,1.5),(-1.5,0),(0,-1.5) ] ) # now four points are on the stack
r = r.circle( 0.25 ) # circle will operate on all four points
result = r.extrude(0.125 ) # make prism
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.points` **!**
* :py:meth:`Workplane`
* :py:meth:`Workplane.circle`
* :py:meth:`Workplane.extrude`
Polygons
-------------------------
You can create polygons for each stack point if you would like. Useful in 3d printers whos firmware does not
correct for small hole sizes.
.. cq_plot::
result = Workplane("front").box(3.0,4.0,0.25).pushPoints ( [ ( 0,0.75 ),(0,-0.75) ]) \
.polygon(6,1.0).cutThruAll()
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.polygon` **!**
* :py:meth:`Workplane.pushPoints`
* :py:meth:`Workplane.box`
Polylines
-------------------------
:py:meth:`Workplane.polyline` allows creating a shape from a large number of chained points connected by lines.
This example uses a polyline to create one half of an i-beam shape, which is mirrored to create the final profile.
.. cq_plot::
(L,H,W,t) = ( 100.0,20.0,20.0,1.0)
pts = [
(0,H/2.0),
(W/2.0,H/2.0),
(W/2.0,(H/2.0 - t)),
(t/2.0,(H/2.0-t)),
(t/2.0,(t - H/2.0)),
(W/2.0,(t -H/2.0)),
(W/2.0,H/-2.0),
(0,H/-2.0)
]
result = Workplane("front").polyline(pts).mirrorY().extrude(L)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.polyline` **!**
* :py:meth:`Workplane`
* :py:meth:`Workplane.mirrorY`
* :py:meth:`Workplane.extrude`
Defining an Edge with a Spline
------------------------------
This example defines a side using a spline curve through a collection of points. Useful when you have an edge that
needs a complex profile
.. cq_plot::
s = Workplane("XY")
sPnts = [
(2.75,1.5),
(2.5,1.75),
(2.0,1.5),
(1.5,1.0),
(1.0,1.25),
(0.5,1.0),
(0,1.0)
]
r = s.lineTo(3.0,0).lineTo(3.0,1.0).spline(sPnts).close()
result = r.extrude(0.5)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.spline` **!**
* :py:meth:`Workplane`
* :py:meth:`Workplane.close`
* :py:meth:`Workplane.lineTo`
* :py:meth:`Workplane.extrude`
Mirroring Symmetric Geometry
-----------------------------
You can mirror 2-d geometry when your shape is symmetric. In this example we also
introduce horizontal and vertical lines, which make for slightly easier coding.
.. cq_plot::
r = Workplane("front").hLine(1.0) # 1.0 is the distance, not coordinate
r = r.vLine(0.5).hLine(-0.25).vLine(-0.25).hLineTo(0.0) # hLineTo allows using xCoordinate not distance
result =r.mirrorY().extrude(0.25 ) # mirror the geometry and extrude
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.hLine` **!**
* :py:meth:`Workplane.vLine` **!**
* :py:meth:`Workplane.hLineTo` **!**
* :py:meth:`Workplane.mirrorY` **!**
* :py:meth:`Workplane.mirrorX` **!**
* :py:meth:`Workplane`
* :py:meth:`Workplane.extrude`
Creating Workplanes on Faces
-----------------------------
This example shows how to locate a new workplane on the face of a previously created feature.
.. note::
Using workplanes in this way are a key feature of CadQuery. Unlike typical 3d scripting language,
using work planes frees you from tracking the position of various features in variables, and
allows the model to adjust itself with removing redundant dimensions
The :py:meth:`Workplane.faces()` method allows you to select the faces of a resulting solid. It accepts
a selector string or object, that allows you to target a single face, and make a workplane oriented on that
face.
Keep in mind that the origin of new workplanes are located at the center of a face by default.
.. cq_plot::
result = Workplane("front").box(2,3,0.5) #make a basic prism
result = result.faces(">Z").workplane().hole(0.5) #find the top-most face and make a hole
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.faces` **!**
* :py:meth:`StringSyntaxSelector` **!**
* :ref:`selector_reference` **!**
* :py:meth:`Workplane.workplane`
* :py:meth:`Workplane.box`
* :py:meth:`Workplane`
Locating a Workplane on a vertex
---------------------------------
Normally, the :py:meth:`Workplane.workplane` method requires a face to be selected. But if a vertex is selected
**immediately after a face**, :py:meth:`Workplane.workplane` will locate the workplane on the face, with the origin at the vertex instead
of at the center of the face
The example also introduces :py:meth:`Workplane.cutThruAll`, which makes a cut through the entire part, no matter
how deep the part is
.. cq_plot::
result = Workplane("front").box(3,2,0.5) #make a basic prism
result = result.faces(">Z").vertices("<XY").workplane() #select the lower left vertex and make a workplane
result = result.circle(1.0).cutThruAll() #cut the corner out
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.cutThruAll` **!**
* :ref:`selector_reference` **!**
* :py:meth:`Workplane.vertices` **!**
* :py:meth:`Workplane.box`
* :py:meth:`Workplane`
* :py:meth:`StringSyntaxSelector` **!**
Offset Workplanes
--------------------------
Workplanes do not have to lie exactly on a face. When you make a workplane, you can define it at an offset
from an existing face.
This example uses an offset workplane to make a compound object, which is perfectly valid!
.. cq_plot::
result = Workplane("front").box(3,2,0.5) #make a basic prism
result = result.faces("<X").workplane(offset=0.75) #workplane is offset from the object surface
result = result.circle(1.0).extrude(0.5) #disc
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.extrude`
* :ref:`selector_reference` **!**
* :py:meth:`Workplane.box`
* :py:meth:`Workplane`
Rotated Workplanes
--------------------------
You can create a rotated work plane by specifying angles of rotation relative to another workplane
.. cq_plot::
result = Workplane("front").box(4.0,4.0,0.25).faces(">Z").workplane() \
.transformed(offset=Vector(0,-1.5,1.0),rotate=Vector(60,0,0)) \
.rect(1.5,1.5,forConstruction=True).vertices().hole(0.25)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.transformed` **!**
* :py:meth:`Workplane.box`
* :py:meth:`Workplane.rect`
* :py:meth:`Workplane.faces`
Using construction Geometry
---------------------------
You can draw shapes to use the vertices as points to locate other features. Features that are used to
locate other features, rather than to create them, are called ``Construction Geometry``
In the example below, a rectangle is drawn, and its vertices are used to locate a set of holes.
.. cq_plot::
result = Workplane("front").box(2,2,0.5).faces(">Z").workplane() \
.rect(1.5,1.5,forConstruction=True).vertices().hole(0.125 )
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.rect` (forConstruction=True)
* :ref:`selector_reference`
* :py:meth:`Workplane.workplane`
* :py:meth:`Workplane.box`
* :py:meth:`Workplane.hole`
* :py:meth:`Workplane`
Shelling To Create Thin features
--------------------------------
Shelling converts a solid object into a shell of uniform thickness. To shell an object, one or more faces
are removed, and then the inside of the solid is 'hollowed out' to make the shell.
.. cq_plot::
result = Workplane("front").box(2,2,2).faces("+Z").shell(0.05)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.shell` **!**
* :py:meth:`Workplane.box`
* :py:meth:`Workplane.faces`
* :py:meth:`Workplane`
Making Lofts
--------------------------------------------
A loft is a solid swept through a set of wires. This example creates lofted section between a rectangle
and a circular section.
.. cq_plot::
result = Workplane("front").box(4.0,4.0,0.25).faces(">Z").circle(1.5) \
.workplane(offset=3.0).rect(0.75,0.5).loft(combine=True)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.loft` **!**
* :py:meth:`Workplane.box`
* :py:meth:`Workplane.faces`
* :py:meth:`Workplane.circle`
* :py:meth:`Workplane.rect`
Making Counter-bored and counter-sunk holes
----------------------------------------------
Counterbored and countersunk holes are so common that CadQuery creates macros to create them in a single step.
Similar to :py:meth:`Workplane.hole` , these functions operate on a list of points as well as a single point.
.. cq_plot::
result = Workplane(Plane.XY()).box(4,2,0.5).faces(">Z").workplane().rect(3.5,1.5,forConstruction=True)\
.vertices().cboreHole(0.125, 0.25,0.125,depth=None)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.cboreHole` **!**
* :py:meth:`Workplane.cskHole` **!**
* :py:meth:`Workplane.box`
* :py:meth:`Workplane.rect`
* :py:meth:`Workplane.workplane`
* :py:meth:`Workplane.vertices`
* :py:meth:`Workplane.faces`
* :py:meth:`Workplane`
Rounding Corners with Fillet
-----------------------------
Filleting is done by selecting the edges of a solid, and using the fillet function.
Here we fillet all of the edges of a simple plate.
.. cq_plot::
result = Workplane("XY" ).box(3,3,0.5).edges("|Z").fillet(0.125)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.fillet` **!**
* :py:meth:`Workplane.box`
* :py:meth:`Workplane.edges`
* :py:meth:`Workplane`
Splitting an Object
---------------------
You can split an object using a workplane, and retain either or both halves
.. cq_plot::
c = Workplane("XY").box(1,1,1).faces(">Z").workplane().circle(0.25).cutThruAll()
#now cut it in half sideways
result = c.faces(">Y").workplane(-0.5).split(keepTop=True)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.split` **!**
* :py:meth:`Workplane.box`
* :py:meth:`Workplane.circle`
* :py:meth:`Workplane.cutThruAll`
* :py:meth:`Workplane.workplane`
* :py:meth:`Workplane`
The Classic OCC Bottle
----------------------
CadQuery is based on the OpenCascade.org (OCC) modeling Kernel. Those who are familiar with OCC know about the
famous 'bottle' example. http://www.opencascade.org/org/gettingstarted/appli/
A pythonOCC version is listed here
http://code.google.com/p/pythonocc/source/browse/trunk/src/examples/Tools/InteractiveViewer/scripts/Bottle.py?r=1046
Of course one difference between this sample and the OCC version is the length. This sample is one of the longer
ones at 13 lines, but that's very short compared to the pythonOCC version, which is 10x longer!
.. cq_plot::
(L,w,t) = (20.0,6.0,3.0)
s = Workplane("XY")
#draw half the profile of the bottle and extrude it
p = s.center(-L/2.0,0).vLine(w/2.0) \
.threePointArc((L/2.0, w/2.0 + t),(L,w/2.0)).vLine(-w/2.0) \
.mirrorX().extrude(30.0,True)
#make the neck
p.faces(">Z").workplane().circle(3.0).extrude(2.0,True)
#make a shell
result = p.faces(">Z").shell(0.3)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane.extrude`
* :py:meth:`Workplane.mirrorX`
* :py:meth:`Workplane.threePointArc`
* :py:meth:`Workplane.workplane`
* :py:meth:`Workplane.vertices`
* :py:meth:`Workplane.vLine`
* :py:meth:`Workplane.faces`
* :py:meth:`Workplane`
A Parametric Enclosure
-----------------------
.. cq_plot::
:height: 400
#parameter definitions
p_outerWidth = 100.0 #Outer width of box enclosure
p_outerLength = 150.0 #Outer length of box enclosure
p_outerHeight = 50.0 #Outer height of box enclosure
p_thickness = 3.0 #Thickness of the box walls
p_sideRadius = 10.0 #Radius for the curves around the sides of the bo
p_topAndBottomRadius = 2.0 #Radius for the curves on the top and bottom edges of the box
p_screwpostInset = 12.0 #How far in from the edges the screwposts should be place.
p_screwpostID = 4.0 #nner Diameter of the screwpost holes, should be roughly screw diameter not including threads
p_screwpostOD = 10.0 #Outer Diameter of the screwposts.\nDetermines overall thickness of the posts
p_boreDiameter = 8.0 #Diameter of the counterbore hole, if any
p_boreDepth = 1.0 #Depth of the counterbore hole, if
p_countersinkDiameter = 0.0 #Outer diameter of countersink. Should roughly match the outer diameter of the screw head
p_countersinkAngle = 90.0 #Countersink angle (complete angle between opposite sides, not from center to one side)
p_flipLid = True #Whether to place the lid with the top facing down or not.
p_lipHeight = 1.0 #Height of lip on the underside of the lid.\nSits inside the box body for a snug fit.
#outer shell
oshell = Workplane("XY").rect(p_outerWidth,p_outerLength).extrude(p_outerHeight + p_lipHeight)
#weird geometry happens if we make the fillets in the wrong order
if p_sideRadius > p_topAndBottomRadius:
oshell.edges("|Z").fillet(p_sideRadius)
oshell.edges("#Z").fillet(p_topAndBottomRadius)
else:
oshell.edges("#Z").fillet(p_topAndBottomRadius)
oshell.edges("|Z").fillet(p_sideRadius)
#inner shell
ishell = oshell.faces("<Z").workplane(p_thickness,True)\
.rect((p_outerWidth - 2.0* p_thickness),(p_outerLength - 2.0*p_thickness))\
.extrude((p_outerHeight - 2.0*p_thickness),False) #set combine false to produce just the new boss
ishell.edges("|Z").fillet(p_sideRadius - p_thickness)
#make the box outer box
box = oshell.cut(ishell)
#make the screwposts
POSTWIDTH = (p_outerWidth - 2.0*p_screwpostInset)
POSTLENGTH = (p_outerLength -2.0*p_screwpostInset)
postCenters = box.faces(">Z").workplane(-p_thickness)\
.rect(POSTWIDTH,POSTLENGTH,forConstruction=True)\
.vertices()
for v in postCenters.all():
v.circle(p_screwpostOD/2.0).circle(p_screwpostID/2.0)\
.extrude((-1.0)*(p_outerHeight + p_lipHeight -p_thickness ),True)
#split lid into top and bottom parts
(lid,bottom) = box.faces(">Z").workplane(-p_thickness -p_lipHeight ).split(keepTop=True,keepBottom=True).all() #splits into two solids
#translate the lid, and subtract the bottom from it to produce the lid inset
lowerLid = lid.translate((0,0,-p_lipHeight))
cutlip = lowerLid.cut(bottom).translate((p_outerWidth + p_thickness ,0,p_thickness - p_outerHeight + p_lipHeight))
#compute centers for counterbore/countersink or counterbore
topOfLidCenters = cutlip.faces(">Z").workplane().rect(POSTWIDTH,POSTLENGTH,forConstruction=True).vertices()
#add holes of the desired type
if p_boreDiameter > 0 and p_boreDepth > 0:
topOfLid = topOfLidCenters.cboreHole(p_screwpostID,p_boreDiameter,p_boreDepth,(2.0)*p_thickness)
elif p_countersinkDiameter > 0 and p_countersinkAngle > 0:
topOfLid = topOfLidCenters.cskHole(p_screwpostID,p_countersinkDiameter,p_countersinkAngle,(2.0)*p_thickness)
else:
topOfLid= topOfLidCenters.hole(p_screwpostID,(2.0)*p_thickness)
#flip lid upside down if desired
if p_flipLid:
topOfLid.rotateAboutCenter((1,0,0),180)
#return the combined result
result =topOfLid.combineSolids(bottom)
.. topic:: Api References
.. hlist::
:columns: 3
* :py:meth:`Workplane.circle`
* :py:meth:`Workplane.rect`
* :py:meth:`Workplane.extrude`
* :py:meth:`Workplane.box`
* :py:meth:`CQ.all`
* :py:meth:`CQ.faces`
* :py:meth:`CQ.vertices`
* :py:meth:`CQ.edges`
* :py:meth:`CQ.workplane`
* :py:meth:`Workplane.fillet`
* :py:meth:`Workplane.cut`
* :py:meth:`Workplane.combineSolids`
* :py:meth:`Workplane.rotateAboutCenter`
* :py:meth:`Workplane.cboreHole`
* :py:meth:`Workplane.cskHole`
* :py:meth:`Workplane.hole`