1126 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			1126 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
.. _examples:
 | 
						||
 | 
						||
*********************************
 | 
						||
CadQuery Examples
 | 
						||
*********************************
 | 
						||
 | 
						||
 | 
						||
 | 
						||
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 code editor in a CadQuery .
 | 
						||
    If you do, make sure to take these steps so that they work:
 | 
						||
 | 
						||
       1. paste the content into the build() method, properly indented, 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.
 | 
						||
 | 
						||
.. note::
 | 
						||
 | 
						||
    We strongly recommend installing `CQ-editor <https://github.com/CadQuery/CQ-editor>`_,
 | 
						||
    so that you can work along with these examples interactively. See :ref:`installation` for more info.
 | 
						||
 | 
						||
.. warning::
 | 
						||
 | 
						||
    * You have to have an svg capable browser to view these!
 | 
						||
 | 
						||
.. contents:: List of Examples
 | 
						||
    :backlinks: entry
 | 
						||
 | 
						||
 | 
						||
Simple Rectangular Plate
 | 
						||
------------------------
 | 
						||
 | 
						||
Just about the simplest possible example, a rectangular box
 | 
						||
 | 
						||
.. cq_plot::
 | 
						||
 | 
						||
    result = cadquery.Workplane("front").box(2.0, 2.0, 0.5)
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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::
 | 
						||
 | 
						||
        # The dimensions of the box. These can be modified rather than changing the
 | 
						||
        # object's code directly.
 | 
						||
        length = 80.0
 | 
						||
        height = 60.0
 | 
						||
        thickness = 10.0
 | 
						||
        center_hole_dia = 22.0
 | 
						||
 | 
						||
        # Create a box based on the dimensions above and add a 22mm center hole
 | 
						||
        result = cq.Workplane("XY").box(length, height, thickness) \
 | 
						||
            .faces(">Z").workplane().hole(center_hole_dia)
 | 
						||
 | 
						||
        show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.Workplane("front").circle(2.0).rect(0.5, 0.75).extrude(0.5)
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.Workplane("front").lineTo(2.0, 0).lineTo(2.0, 1.0).threePointArc((1.0, 1.5),(0.0, 1.0))\
 | 
						||
        .close().extrude(0.25)
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
 | 
						||
.. 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 = cq.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)
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
 | 
						||
.. 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 = cq.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
 | 
						||
   show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.Workplane("front").box(3.0, 4.0, 0.25).pushPoints ( [ ( 0,0.75 ),(0, -0.75) ]) \
 | 
						||
        .polygon(6, 1.0).cutThruAll()
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.Workplane("front").moveTo(*pts[0]).polyline(pts[1:]).mirrorY().extrude(L)
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.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)
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.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
 | 
						||
   show_object(result)
 | 
						||
 | 
						||
.. 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`
 | 
						||
 | 
						||
Mirroring 3D Objects
 | 
						||
-----------------------------
 | 
						||
 | 
						||
.. cq_plot::
 | 
						||
 | 
						||
    result0 = (cadquery.Workplane("XY")
 | 
						||
               .moveTo(10,0)
 | 
						||
               .lineTo(5,0)
 | 
						||
               .threePointArc((3.9393,0.4393),(3.5,1.5))
 | 
						||
               .threePointArc((3.0607,2.5607),(2,3))
 | 
						||
               .lineTo(1.5,3)
 | 
						||
               .threePointArc((0.4393,3.4393),(0,4.5))
 | 
						||
               .lineTo(0,13.5)
 | 
						||
               .threePointArc((0.4393,14.5607),(1.5,15))
 | 
						||
               .lineTo(28,15)
 | 
						||
               .lineTo(28,13.5)
 | 
						||
               .lineTo(24,13.5)
 | 
						||
               .lineTo(24,11.5)
 | 
						||
               .lineTo(27,11.5)
 | 
						||
               .lineTo(27,10)
 | 
						||
               .lineTo(22,10)
 | 
						||
               .lineTo(22,13.2)
 | 
						||
               .lineTo(14.5,13.2)
 | 
						||
               .lineTo(14.5,10)
 | 
						||
               .lineTo(12.5,10 )
 | 
						||
               .lineTo(12.5,13.2)
 | 
						||
               .lineTo(5.5,13.2)
 | 
						||
               .lineTo(5.5,2)
 | 
						||
               .threePointArc((5.793,1.293),(6.5,1))
 | 
						||
               .lineTo(10,1)
 | 
						||
               .close())
 | 
						||
    result = result0.extrude(100)
 | 
						||
 | 
						||
    result = result.rotate((0, 0, 0),(1, 0, 0), 90)
 | 
						||
 | 
						||
    result = result.translate(result.val().BoundingBox().center.multiply(-1))
 | 
						||
 | 
						||
    mirXY_neg = result.mirror(mirrorPlane="XY", basePointVector=(0, 0, -30))
 | 
						||
    mirXY_pos = result.mirror(mirrorPlane="XY", basePointVector=(0, 0, 30))
 | 
						||
    mirZY_neg = result.mirror(mirrorPlane="ZY", basePointVector=(-30,0,0))
 | 
						||
    mirZY_pos = result.mirror(mirrorPlane="ZY", basePointVector=(30,0,0))
 | 
						||
 | 
						||
    result = result.union(mirXY_neg).union(mirXY_pos).union(mirZY_neg).union(mirZY_pos)
 | 
						||
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. topic:: Api References
 | 
						||
 | 
						||
    .. hlist::
 | 
						||
        :columns: 2
 | 
						||
 | 
						||
        * :py:meth:`Workplane.moveTo`
 | 
						||
        * :py:meth:`Workplane.lineTo`
 | 
						||
        * :py:meth:`Workplane.threePointArc`
 | 
						||
        * :py:meth:`Workplane.extrude`
 | 
						||
        * :py:meth:`Workplane.mirror`
 | 
						||
        * :py:meth:`Workplane.union`
 | 
						||
        * :py:meth:`CQ.rotate`
 | 
						||
 | 
						||
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 = cq.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
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.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
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.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
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.Workplane("front").box(4.0, 4.0, 0.25).faces(">Z").workplane()  \
 | 
						||
         .transformed(offset=cq.Vector(0, -1.5, 1.0),rotate=cq.Vector(60, 0, 0)) \
 | 
						||
         .rect(1.5,1.5,forConstruction=True).vertices().hole(0.25)
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.Workplane("front").box(2, 2, 0.5).faces(">Z").workplane() \
 | 
						||
        .rect(1.5, 1.5, forConstruction=True).vertices().hole(0.125 )
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.Workplane("front").box(2, 2, 2).faces("+Z").shell(0.05)
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.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)
 | 
						||
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.Workplane(cq.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)
 | 
						||
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.Workplane("XY" ).box(3, 3, 0.5).edges("|Z").fillet(0.125)
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. topic:: Api References
 | 
						||
 | 
						||
    .. hlist::
 | 
						||
        :columns: 2
 | 
						||
 | 
						||
        * :py:meth:`Workplane.fillet` **!**
 | 
						||
        * :py:meth:`Workplane.box`
 | 
						||
        * :py:meth:`Workplane.edges`
 | 
						||
        * :py:meth:`Workplane`
 | 
						||
 | 
						||
A Parametric Bearing Pillow Block
 | 
						||
------------------------------------
 | 
						||
 | 
						||
Combining a few basic functions, its possible to make a very good parametric bearing pillow block,
 | 
						||
with just a few lines of code.
 | 
						||
 | 
						||
.. cq_plot::
 | 
						||
 | 
						||
        (length,height,bearing_diam, thickness,padding) = ( 30.0, 40.0, 22.0, 10.0, 8.0)
 | 
						||
 | 
						||
        result = cq.Workplane("XY").box(length,height,thickness).faces(">Z").workplane().hole(bearing_diam) \
 | 
						||
                .faces(">Z").workplane() \
 | 
						||
                .rect(length-padding,height-padding,forConstruction=True) \
 | 
						||
                .vertices().cboreHole(2.4, 4.4, 2.1)
 | 
						||
 | 
						||
        show_object(result)
 | 
						||
 | 
						||
 | 
						||
Splitting an Object
 | 
						||
---------------------
 | 
						||
 | 
						||
You can split an object using a workplane, and retain either or both halves
 | 
						||
 | 
						||
.. cq_plot::
 | 
						||
 | 
						||
        c = cq.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)
 | 
						||
        show_object(result)
 | 
						||
 | 
						||
.. 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 = cq.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 = p.faces(">Z").workplane().circle(3.0).extrude(2.0,True)
 | 
						||
 | 
						||
    #make a shell
 | 
						||
    result = p.faces(">Z").shell(0.3)
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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 box
 | 
						||
    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 screw posts should be place.
 | 
						||
    p_screwpostID = 4.0 #Inner Diameter of the screw post holes, should be roughly screw diameter not including threads
 | 
						||
    p_screwpostOD = 10.0 #Outer Diameter of the screw posts.\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 = cq.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 = oshell.edges("|Z").fillet(p_sideRadius)
 | 
						||
        oshell = oshell.edges("#Z").fillet(p_topAndBottomRadius)
 | 
						||
    else:
 | 
						||
        oshell = oshell.edges("#Z").fillet(p_topAndBottomRadius)
 | 
						||
        oshell = 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 = ishell.edges("|Z").fillet(p_sideRadius - p_thickness)
 | 
						||
 | 
						||
    #make the box outer box
 | 
						||
    box = oshell.cut(ishell)
 | 
						||
 | 
						||
    #make the screw posts
 | 
						||
    POSTWIDTH = (p_outerWidth - 2.0*p_screwpostInset)
 | 
						||
    POSTLENGTH = (p_outerLength  -2.0*p_screwpostInset)
 | 
						||
 | 
						||
    box = box.faces(">Z").workplane(-p_thickness)\
 | 
						||
        .rect(POSTWIDTH,POSTLENGTH,forConstruction=True)\
 | 
						||
        .vertices().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 = topOfLid.rotateAboutCenter((1,0,0),180)
 | 
						||
 | 
						||
    #return the combined result
 | 
						||
    result =topOfLid.combineSolids(bottom)
 | 
						||
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
.. 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`
 | 
						||
 | 
						||
Lego Brick
 | 
						||
-------------------
 | 
						||
 | 
						||
This script will produce any size regular rectangular Lego(TM) brick. Its only tricky because of the logic
 | 
						||
regarding the underside of the brick.
 | 
						||
 | 
						||
.. cq_plot::
 | 
						||
    :height: 400
 | 
						||
 | 
						||
    #####
 | 
						||
    # Inputs
 | 
						||
    ######
 | 
						||
    lbumps = 6       # number of bumps long
 | 
						||
    wbumps = 2       # number of bumps wide
 | 
						||
    thin = True      # True for thin, False for thick
 | 
						||
 | 
						||
    #
 | 
						||
    # Lego Brick Constants-- these make a Lego brick a Lego :)
 | 
						||
    #
 | 
						||
    pitch = 8.0
 | 
						||
    clearance = 0.1
 | 
						||
    bumpDiam = 4.8
 | 
						||
    bumpHeight = 1.8
 | 
						||
    if thin:
 | 
						||
        height = 3.2
 | 
						||
    else:
 | 
						||
        height = 9.6
 | 
						||
 | 
						||
    t = (pitch - (2 * clearance) - bumpDiam) / 2.0
 | 
						||
    postDiam = pitch - t  # works out to 6.5
 | 
						||
    total_length = lbumps*pitch - 2.0*clearance
 | 
						||
    total_width = wbumps*pitch - 2.0*clearance
 | 
						||
 | 
						||
    # make the base
 | 
						||
    s = cq.Workplane("XY").box(total_length, total_width, height)
 | 
						||
 | 
						||
    # shell inwards not outwards
 | 
						||
    s = s.faces("<Z").shell(-1.0 * t)
 | 
						||
 | 
						||
    # make the bumps on the top
 | 
						||
    s = s.faces(">Z").workplane(). \
 | 
						||
        rarray(pitch, pitch, lbumps, wbumps, True).circle(bumpDiam / 2.0) \
 | 
						||
        .extrude(bumpHeight)
 | 
						||
 | 
						||
    # add posts on the bottom. posts are different diameter depending on geometry
 | 
						||
    # solid studs for 1 bump, tubes for multiple, none for 1x1
 | 
						||
    tmp = s.faces("<Z").workplane(invert=True)
 | 
						||
 | 
						||
    if lbumps > 1 and wbumps > 1:
 | 
						||
        tmp = tmp.rarray(pitch, pitch, lbumps - 1, wbumps - 1, center=True). \
 | 
						||
            circle(postDiam / 2.0).circle(bumpDiam / 2.0).extrude(height - t)
 | 
						||
    elif lbumps > 1:
 | 
						||
        tmp = tmp.rarray(pitch, pitch, lbumps - 1, 1, center=True). \
 | 
						||
            circle(t).extrude(height - t)
 | 
						||
    elif wbumps > 1:
 | 
						||
        tmp = tmp.rarray(pitch, pitch, 1, wbumps - 1, center=True). \
 | 
						||
            circle(t).extrude(height - t)
 | 
						||
    else:
 | 
						||
        tmp = s
 | 
						||
 | 
						||
    # Render the solid
 | 
						||
    show_object(tmp)
 | 
						||
 | 
						||
 | 
						||
Braille Example
 | 
						||
---------------------
 | 
						||
 | 
						||
.. cq_plot::
 | 
						||
    :height: 400
 | 
						||
 | 
						||
    from __future__ import unicode_literals, division
 | 
						||
    from collections import namedtuple
 | 
						||
 | 
						||
 | 
						||
    # text_lines is a list of text lines.
 | 
						||
    # Braille (converted with braille-converter:
 | 
						||
    # https://github.com/jpaugh/braille-converter.git).
 | 
						||
    text_lines = ['⠠ ⠋ ⠗ ⠑ ⠑ ⠠ ⠉ ⠠ ⠁ ⠠ ⠙']
 | 
						||
    # See http://www.tiresias.org/research/reports/braille_cell.htm for examples
 | 
						||
    # of braille cell geometry.
 | 
						||
    horizontal_interdot = 2.5
 | 
						||
    vertical_interdot = 2.5
 | 
						||
    horizontal_intercell = 6
 | 
						||
    vertical_interline = 10
 | 
						||
    dot_height = 0.5
 | 
						||
    dot_diameter = 1.3
 | 
						||
 | 
						||
    base_thickness = 1.5
 | 
						||
 | 
						||
    # End of configuration.
 | 
						||
    BrailleCellGeometry = namedtuple('BrailleCellGeometry',
 | 
						||
                                     ('horizontal_interdot',
 | 
						||
                                      'vertical_interdot',
 | 
						||
                                      'intercell',
 | 
						||
                                      'interline',
 | 
						||
                                      'dot_height',
 | 
						||
                                      'dot_diameter'))
 | 
						||
 | 
						||
 | 
						||
    class Point(object):
 | 
						||
        def __init__(self, x, y):
 | 
						||
            self.x = x
 | 
						||
            self.y = y
 | 
						||
 | 
						||
        def __add__(self, other):
 | 
						||
            return Point(self.x + other.x, self.y + other.y)
 | 
						||
 | 
						||
        def __len__(self):
 | 
						||
            return 2
 | 
						||
 | 
						||
        def __getitem__(self, index):
 | 
						||
            return (self.x, self.y)[index]
 | 
						||
 | 
						||
        def __str__(self):
 | 
						||
            return '({}, {})'.format(self.x, self.y)
 | 
						||
 | 
						||
 | 
						||
    def brailleToPoints(text, cell_geometry):
 | 
						||
        # Unicode bit pattern (cf. https://en.wikipedia.org/wiki/Braille_Patterns).
 | 
						||
        mask1 = 0b00000001
 | 
						||
        mask2 = 0b00000010
 | 
						||
        mask3 = 0b00000100
 | 
						||
        mask4 = 0b00001000
 | 
						||
        mask5 = 0b00010000
 | 
						||
        mask6 = 0b00100000
 | 
						||
        mask7 = 0b01000000
 | 
						||
        mask8 = 0b10000000
 | 
						||
        masks = (mask1, mask2, mask3, mask4, mask5, mask6, mask7, mask8)
 | 
						||
 | 
						||
        # Corresponding dot position
 | 
						||
        w = cell_geometry.horizontal_interdot
 | 
						||
        h = cell_geometry.vertical_interdot
 | 
						||
        pos1 = Point(0, 2 * h)
 | 
						||
        pos2 = Point(0, h)
 | 
						||
        pos3 = Point(0, 0)
 | 
						||
        pos4 = Point(w, 2 * h)
 | 
						||
        pos5 = Point(w, h)
 | 
						||
        pos6 = Point(w, 0)
 | 
						||
        pos7 = Point(0, -h)
 | 
						||
        pos8 = Point(w, -h)
 | 
						||
        pos = (pos1, pos2, pos3, pos4, pos5, pos6, pos7, pos8)
 | 
						||
 | 
						||
        # Braille blank pattern (u'\u2800').
 | 
						||
        blank = '⠀'
 | 
						||
        points = []
 | 
						||
        # Position of dot1 along the x-axis (horizontal).
 | 
						||
        character_origin = 0
 | 
						||
        for c in text:
 | 
						||
            for m, p in zip(masks, pos):
 | 
						||
                delta_to_blank = ord(c) - ord(blank)
 | 
						||
                if (m & delta_to_blank):
 | 
						||
                    points.append(p + Point(character_origin, 0))
 | 
						||
            character_origin += cell_geometry.intercell
 | 
						||
        return points
 | 
						||
 | 
						||
 | 
						||
    def get_plate_height(text_lines, cell_geometry):
 | 
						||
        # cell_geometry.vertical_interdot is also used as space between base
 | 
						||
        # borders and characters.
 | 
						||
        return (2 * cell_geometry.vertical_interdot +
 | 
						||
                2 * cell_geometry.vertical_interdot +
 | 
						||
                (len(text_lines) - 1) * cell_geometry.interline)
 | 
						||
 | 
						||
 | 
						||
    def get_plate_width(text_lines, cell_geometry):
 | 
						||
        # cell_geometry.horizontal_interdot is also used as space between base
 | 
						||
        # borders and characters.
 | 
						||
        max_len = max([len(t) for t in text_lines])
 | 
						||
        return (2 * cell_geometry.horizontal_interdot +
 | 
						||
                cell_geometry.horizontal_interdot +
 | 
						||
                (max_len - 1) * cell_geometry.intercell)
 | 
						||
 | 
						||
 | 
						||
    def get_cylinder_radius(cell_geometry):
 | 
						||
        """Return the radius the cylinder should have
 | 
						||
        The cylinder have the same radius as the half-sphere make the dots (the
 | 
						||
        hidden and the shown part of the dots).
 | 
						||
        The radius is such that the spherical cap with diameter
 | 
						||
        cell_geometry.dot_diameter has a height of cell_geometry.dot_height.
 | 
						||
        """
 | 
						||
        h = cell_geometry.dot_height
 | 
						||
        r = cell_geometry.dot_diameter / 2
 | 
						||
        return (r ** 2 + h ** 2) / 2 / h
 | 
						||
 | 
						||
 | 
						||
    def get_base_plate_thickness(plate_thickness, cell_geometry):
 | 
						||
        """Return the height on which the half spheres will sit"""
 | 
						||
        return (plate_thickness +
 | 
						||
                get_cylinder_radius(cell_geometry) -
 | 
						||
                cell_geometry.dot_height)
 | 
						||
 | 
						||
 | 
						||
    def make_base(text_lines, cell_geometry, plate_thickness):
 | 
						||
        base_width = get_plate_width(text_lines, cell_geometry)
 | 
						||
        base_height = get_plate_height(text_lines, cell_geometry)
 | 
						||
        base_thickness = get_base_plate_thickness(plate_thickness, cell_geometry)
 | 
						||
        base = cq.Workplane('XY').box(base_width, base_height, base_thickness,
 | 
						||
                                      centered=(False, False, False))
 | 
						||
        return base
 | 
						||
 | 
						||
 | 
						||
    def make_embossed_plate(text_lines, cell_geometry):
 | 
						||
        """Make an embossed plate with dots as spherical caps
 | 
						||
        Method:
 | 
						||
            - make a thin plate on which sit cylinders
 | 
						||
            - fillet the upper edge of the cylinders so to get pseudo half-spheres
 | 
						||
            - make the union with a thicker plate so that only the sphere caps stay
 | 
						||
              "visible".
 | 
						||
        """
 | 
						||
        base = make_base(text_lines, cell_geometry, base_thickness)
 | 
						||
 | 
						||
        dot_pos = []
 | 
						||
        base_width = get_plate_width(text_lines, cell_geometry)
 | 
						||
        base_height = get_plate_height(text_lines, cell_geometry)
 | 
						||
        y = base_height - 3 * cell_geometry.vertical_interdot
 | 
						||
        line_start_pos = Point(cell_geometry.horizontal_interdot, y)
 | 
						||
        for text in text_lines:
 | 
						||
            dots = brailleToPoints(text, cell_geometry)
 | 
						||
            dots = [p + line_start_pos for p in dots]
 | 
						||
            dot_pos += dots
 | 
						||
            line_start_pos += Point(0, -cell_geometry.interline)
 | 
						||
 | 
						||
        r = get_cylinder_radius(cell_geometry)
 | 
						||
        base = base.faces('>Z').vertices('<XY').workplane() \
 | 
						||
            .pushPoints(dot_pos).circle(r) \
 | 
						||
            .extrude(r)
 | 
						||
        # Make a fillet almost the same radius to get a pseudo spherical cap.
 | 
						||
        base = base.faces('>Z').edges() \
 | 
						||
            .fillet(r - 0.001)
 | 
						||
        hidding_box = cq.Workplane('XY').box(
 | 
						||
            base_width, base_height, base_thickness, centered=(False, False, False))
 | 
						||
        result = hidding_box.union(base)
 | 
						||
        return result
 | 
						||
 | 
						||
    _cell_geometry = BrailleCellGeometry(
 | 
						||
        horizontal_interdot,
 | 
						||
        vertical_interdot,
 | 
						||
        horizontal_intercell,
 | 
						||
        vertical_interline,
 | 
						||
        dot_height,
 | 
						||
        dot_diameter)
 | 
						||
 | 
						||
    if base_thickness < get_cylinder_radius(_cell_geometry):
 | 
						||
        raise ValueError('Base thickness should be at least {}'.format(dot_height))
 | 
						||
 | 
						||
    show_object(make_embossed_plate(text_lines, _cell_geometry))
 | 
						||
 | 
						||
Panel With Various Connector Holes
 | 
						||
-----------------------------------
 | 
						||
 | 
						||
.. cq_plot::
 | 
						||
    :height: 400
 | 
						||
 | 
						||
    # The dimensions of the model. These can be modified rather than changing the
 | 
						||
    # object's code directly.
 | 
						||
    width = 400
 | 
						||
    height = 500
 | 
						||
    thickness = 2
 | 
						||
 | 
						||
    # Create a plate with two polygons cut through it
 | 
						||
    result = cq.Workplane("front").box(width, height, thickness)
 | 
						||
 | 
						||
    h_sep = 60
 | 
						||
    for idx in range(4):
 | 
						||
        result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(157,210-idx*h_sep).moveTo(-23.5,0).circle(1.6).moveTo(23.5,0).circle(1.6).moveTo(-17.038896,-5.7).threePointArc((-19.44306,-4.70416),(-20.438896,-2.3)).lineTo(-21.25,2.3).threePointArc((-20.25416,4.70416),(-17.85,5.7)).lineTo(17.85,5.7).threePointArc((20.25416,4.70416),(21.25,2.3)).lineTo(20.438896,-2.3).threePointArc((19.44306,-4.70416),(17.038896,-5.7)).close().cutThruAll()
 | 
						||
 | 
						||
    for idx in range(4):
 | 
						||
        result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(157,-30-idx*h_sep).moveTo(-16.65,0).circle(1.6).moveTo(16.65,0).circle(1.6).moveTo(-10.1889,-5.7).threePointArc((-12.59306,-4.70416),(-13.5889,-2.3)).lineTo(-14.4,2.3).threePointArc((-13.40416,4.70416),(-11,5.7)).lineTo(11,5.7).threePointArc((13.40416,4.70416),(14.4,2.3)).lineTo(13.5889,-2.3).threePointArc((12.59306,-4.70416),(10.1889,-5.7)).close().cutThruAll()
 | 
						||
 | 
						||
    h_sep4DB9 = 30
 | 
						||
    for idx in range(8):
 | 
						||
        result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(91,225-idx*h_sep4DB9).moveTo(-12.5,0).circle(1.6).moveTo(12.5,0).circle(1.6).moveTo(-6.038896,-5.7).threePointArc((-8.44306,-4.70416),(-9.438896,-2.3)).lineTo(-10.25,2.3).threePointArc((-9.25416,4.70416),(-6.85,5.7)).lineTo(6.85,5.7).threePointArc((9.25416,4.70416),(10.25,2.3)).lineTo(9.438896,-2.3).threePointArc((8.44306,-4.70416),(6.038896,-5.7)).close().cutThruAll()
 | 
						||
 | 
						||
    for idx in range(4):
 | 
						||
        result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(25,210-idx*h_sep).moveTo(-23.5,0).circle(1.6).moveTo(23.5,0).circle(1.6).moveTo(-17.038896,-5.7).threePointArc((-19.44306,-4.70416),(-20.438896,-2.3)).lineTo(-21.25,2.3).threePointArc((-20.25416,4.70416),(-17.85,5.7)).lineTo(17.85,5.7).threePointArc((20.25416,4.70416),(21.25,2.3)).lineTo(20.438896,-2.3).threePointArc((19.44306,-4.70416),(17.038896,-5.7)).close().cutThruAll()
 | 
						||
 | 
						||
    for idx in range(4):
 | 
						||
        result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(25,-30-idx*h_sep).moveTo(-16.65,0).circle(1.6).moveTo(16.65,0).circle(1.6).moveTo(-10.1889,-5.7).threePointArc((-12.59306,-4.70416),(-13.5889,-2.3)).lineTo(-14.4,2.3).threePointArc((-13.40416,4.70416),(-11,5.7)).lineTo(11,5.7).threePointArc((13.40416,4.70416),(14.4,2.3)).lineTo(13.5889,-2.3).threePointArc((12.59306,-4.70416),(10.1889,-5.7)).close().cutThruAll()
 | 
						||
 | 
						||
    for idx in range(8):
 | 
						||
        result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-41,225-idx*h_sep4DB9).moveTo(-12.5,0).circle(1.6).moveTo(12.5,0).circle(1.6).moveTo(-6.038896,-5.7).threePointArc((-8.44306,-4.70416),(-9.438896,-2.3)).lineTo(-10.25,2.3).threePointArc((-9.25416,4.70416),(-6.85,5.7)).lineTo(6.85,5.7).threePointArc((9.25416,4.70416),(10.25,2.3)).lineTo(9.438896,-2.3).threePointArc((8.44306,-4.70416),(6.038896,-5.7)).close().cutThruAll()
 | 
						||
 | 
						||
    for idx in range(4):
 | 
						||
        result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-107,210-idx*h_sep).moveTo(-23.5,0).circle(1.6).moveTo(23.5,0).circle(1.6).moveTo(-17.038896,-5.7).threePointArc((-19.44306,-4.70416),(-20.438896,-2.3)).lineTo(-21.25,2.3).threePointArc((-20.25416,4.70416),(-17.85,5.7)).lineTo(17.85,5.7).threePointArc((20.25416,4.70416),(21.25,2.3)).lineTo(20.438896,-2.3).threePointArc((19.44306,-4.70416),(17.038896,-5.7)).close().cutThruAll()
 | 
						||
 | 
						||
    for idx in range(4):
 | 
						||
        result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-107,-30-idx*h_sep).circle(14).rect(24.7487,24.7487, forConstruction=True).vertices().hole(3.2).cutThruAll()
 | 
						||
 | 
						||
    for idx in range(8):
 | 
						||
        result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-173,225-idx*h_sep4DB9).moveTo(-12.5,0).circle(1.6).moveTo(12.5,0).circle(1.6).moveTo(-6.038896,-5.7).threePointArc((-8.44306,-4.70416),(-9.438896,-2.3)).lineTo(-10.25,2.3).threePointArc((-9.25416,4.70416),(-6.85,5.7)).lineTo(6.85,5.7).threePointArc((9.25416,4.70416),(10.25,2.3)).lineTo(9.438896,-2.3).threePointArc((8.44306,-4.70416),(6.038896,-5.7)).close().cutThruAll()
 | 
						||
 | 
						||
    for idx in range(4):
 | 
						||
        result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-173,-30-idx*h_sep).moveTo(-2.9176,-5.3).threePointArc((-6.05,0),(-2.9176,5.3)).lineTo(2.9176,5.3).threePointArc((6.05,0),(2.9176,-5.3)).close().cutThruAll()
 | 
						||
 | 
						||
    # Render the solid
 | 
						||
    show_object(result)
 | 
						||
 | 
						||
 | 
						||
Cycloidal gear
 | 
						||
--------------
 | 
						||
 | 
						||
You can define complex geometries using the parametricCurve functionality.
 | 
						||
This specific examples generates a helical cycloidal gear.
 | 
						||
 | 
						||
.. cq_plot::
 | 
						||
    :height: 400
 | 
						||
 | 
						||
    import cadquery as cq
 | 
						||
    from math import sin, cos,pi,floor
 | 
						||
 | 
						||
    # define the generating function
 | 
						||
    def hypocycloid(t,r1,r2):
 | 
						||
        return ((r1-r2)*cos(t)+r2*cos(r1/r2*t-t),(r1-r2)*sin(t)+r2*sin(-(r1/r2*t-t)))
 | 
						||
 | 
						||
    def epicycloid(t,r1,r2):
 | 
						||
        return ((r1+r2)*cos(t)-r2*cos(r1/r2*t+t),(r1+r2)*sin(t)-r2*sin(r1/r2*t+t))
 | 
						||
 | 
						||
    def gear(t,r1=4,r2=1):
 | 
						||
        if (-1)**(1+floor(t/2/pi*(r1/r2))) < 0:
 | 
						||
            return epicycloid(t,r1,r2)
 | 
						||
        else:
 | 
						||
            return hypocycloid(t,r1,r2)
 | 
						||
 | 
						||
    # create the gear profile and extrude it
 | 
						||
    result = cq.Workplane('XY').parametricCurve(lambda t: gear(t*2*pi,6,1))\
 | 
						||
        .twistExtrude(15,90).faces('>Z').workplane().circle(2).cutThruAll()
 | 
						||
 | 
						||
    show_object(result)
 |