Typos and clarification to docs

This commit is contained in:
Roger Maitland 2022-09-16 12:20:39 -04:00
parent 5027dac7bc
commit cd6f8f0f13
3 changed files with 96 additions and 54 deletions

View file

@ -2,20 +2,20 @@
Tutorial
########
This tutorial provides a step by step guild to creating a script to build a parametric
This tutorial provides a step by step guide to creating a script to build a parametric
Lego block.
*************
Step 1: Setup
*************
Before getting to the CAD operations, this lego script needs to import the build123d
Before getting to the CAD operations, this Lego script needs to import the build123d
environment. There are over 100 python classes in build123d so we'll just import them
all with an `from build123d import *` but there are other options that we won't explore
here. In addition, the `Plane` object from `cadquery` will be used so we'll import
all with a ``from build123d import *`` but there are other options that we won't explore
here. In addition, the ``Plane`` object from ``cadquery`` will be used so we'll import
that class as well.
The dimensions of the lego block follow. A key parameter is `pip_count`, the length
The dimensions of the Lego block follow. A key parameter is ``pip_count``, the length
of the Lego blocks in pips. This parameter must be at least 2.
.. code-block:: python
@ -43,8 +43,8 @@ of the Lego blocks in pips. This parameter must be at least 2.
Step 2: Part Builder
********************
The Lego block will be created by the `BuildPart` builder as it's a discrete three
dimensional part; therefore, we'll instantiate a `BuildPart` with the name `lego`.
The Lego block will be created by the ``BuildPart`` builder as it's a discrete three
dimensional part; therefore, we'll instantiate a ``BuildPart`` with the name ``lego``.
.. code-block:: python
@ -60,27 +60,30 @@ object. As this sketch will be part of the lego part, we'll create a sketch bui
in the context of the part builder as follows:
.. code-block:: python
:emphasize-lines: 2
with BuildPart() as lego:
with BuildSketch() as plan:
Note that builder instance names are optional - we'll use `plan` to reference the sketch.
Note that builder instance names are optional - we'll use ``plan`` to reference the sketch.
Also note that all sketch objects are filled or 2D faces not just perimeter lines.
***************************
Step 4: Perimeter Rectangle
***************************
The first object in the sketch is going to be a rectangle the dimensions of the outside
of the lego block. The following step is going to refer to this rectangle, so it will
be assigned the identifier `perimeter`.
The first object in the sketch is going to be a rectangle with the dimensions of the outside
of the Lego block. The following step is going to refer to this rectangle, so it will
be assigned the identifier ``perimeter``.
.. code-block:: python
:emphasize-lines: 3
with BuildPart() as lego:
with BuildSketch() as plan:
perimeter = Rectangle(width=block_length, height=block_width)
Once the `Rectangle` object is created the sketch appears as follows:
Once the ``Rectangle`` object is created the sketch appears as follows:
.. image:: tutorial_step4.svg
:align: center
@ -90,10 +93,11 @@ Step 5: Offset to Create Walls
******************************
To create the walls of the block the rectangle that we've created needs to be
hollowed out. This will be done with the `Offset` operation which is going to
create a new object from `perimeter`.
hollowed out. This will be done with the ``Offset`` operation which is going to
create a new object from ``perimeter``.
.. code-block:: python
:emphasize-lines: 4-9
with BuildPart() as lego:
with BuildSketch() as plan:
@ -105,10 +109,10 @@ create a new object from `perimeter`.
mode=Mode.SUBTRACT,
)
The first parameter to `Offset` is the reference object. The `amount` is a
negative value to indicate that the offset should be internal. The `kind`
parameter controls the shape of the corners - `Kind.INTERSECTION` will create
square corners. Finally, the `mode` parameter controls how this object will
The first parameter to ``Offset`` is the reference object. The ``amount`` is a
negative value to indicate that the offset should be internal. The ``kind``
parameter controls the shape of the corners - ``Kind.INTERSECTION`` will create
square corners. Finally, the ``mode`` parameter controls how this object will
be placed in the sketch - in this case subtracted from the existing sketch.
The result is shown here:
@ -122,12 +126,15 @@ Step 6: Create Internal Grid
****************************
The interior of the Lego block has small ridges on all four internal walls.
These ridges will be created as a double row and column of thin rectangles. To
space this grid a pair of `GridLocations` location contexts will be used which
provide one or more positions to all of the objects within their scope - in
this case a single `Rectangle`.
These ridges will be created as a grid of thin rectangles so the positions
of the centers of these rectangles need to be defined. A pair of
``GridLocations`` location contexts will define these positions, one for
the horizontal bars and one for the vertical bars. As the ``Rectangle``
objects are in the scope of generators (``GridLocations`` in this case)
that defined multiple points, multiple rectangles are created.
.. code-block:: python
:emphasize-lines: 10-13
with BuildPart() as lego:
with BuildSketch() as plan:
@ -143,9 +150,9 @@ this case a single `Rectangle`.
with GridLocations(lego_unit_size, 0, pip_count, 1):
Rectangle(width=ridge_width, height=block_width)
Here we can see that the first `GridLocations` create two positions which causes
two horizontal rectangles to be created. The second `GridLocations` works in the same way
but creates `pip_count` positions and therefore vertical rectangles. Note that keyword
Here we can see that the first ``GridLocations`` creates two positions which causes
two horizontal rectangles to be created. The second ``GridLocations`` works in the same way
but creates ``pip_count`` positions and therefore ``pip_count`` rectangles. Note that keyword
parameter are optional in this case.
The result looks like this:
@ -158,9 +165,10 @@ Step 7: Create Ridges
*********************
To convert the internal grid to ridges, the center needs to be removed. This will be done
with another `Rectangle`.
with another ``Rectangle``.
.. code-block:: python
:emphasize-lines: 14-18
with BuildPart() as lego:
with BuildSketch() as plan:
@ -181,7 +189,7 @@ with another `Rectangle`.
mode=Mode.SUBTRACT,
)
The `Rectangle` is subtracted from the sketch to leave the ridges as follows:
The ``Rectangle`` is subtracted from the sketch to leave the ridges as follows:
.. image:: tutorial_step7.svg
:align: center
@ -192,9 +200,10 @@ Step 8: Hollow Circles
**********************
Lego blocks use a set of internal hollow cylinders that the pips push against
to hold two blocks together. These will be created with `Circle`.
to hold two blocks together. These will be created with ``Circle``.
.. code-block:: python
:emphasize-lines: 19-23
with BuildPart() as lego:
with BuildSketch() as plan:
@ -220,8 +229,8 @@ to hold two blocks together. These will be created with `Circle`.
Circle(radius=support_outer_diameter / 2)
Circle(radius=support_inner_diameter / 2, mode=Mode.SUBTRACT)
Here another `GridLocations` is used to position the centers of the circles. Note
that since both `Circle` objects are in the scope of the location context, both
Here another ``GridLocations`` is used to position the centers of the circles. Note
that since both ``Circle`` objects are in the scope of the location context, both
Circles will be positioned at these locations.
Once the Circles are added, the sketch is complete and looks as follows:
@ -237,6 +246,7 @@ Now that the sketch is complete it needs to be extruded into the three dimension
wall object.
.. code-block:: python
:emphasize-lines: 24
with BuildPart() as lego:
with BuildSketch() as plan:
@ -261,11 +271,11 @@ wall object.
):
Circle(radius=support_outer_diameter / 2)
Circle(radius=support_inner_diameter / 2, mode=Mode.SUBTRACT)
Extrude(base_height - wall_thickness)
Extrude(amount=base_height - wall_thickness)
Note how the `Extrude` operation is no longer in the `BuildSketch` scope and back into
the `BuildPart` scope. This causes `BuildSketch` to exit and transfer the sketch that
we've created to `BuildPart` for further processing by `Extrude`.
Note how the ``Extrude`` operation is no longer in the ``BuildSketch`` scope and has returned
back into the ``BuildPart`` scope. This causes ``BuildSketch`` to exit and transfer the
sketch that we've created to ``BuildPart`` for further processing by ``Extrude``.
The result is:
@ -281,6 +291,7 @@ Now that the walls are complete, the top of the block needs to be added. Althoug
could be done with another sketch, we'll add a box to the top of the walls.
.. code-block:: python
:emphasize-lines: 25-31
with BuildPart() as lego:
with BuildSketch() as plan:
@ -305,7 +316,7 @@ could be done with another sketch, we'll add a box to the top of the walls.
):
Circle(radius=support_outer_diameter / 2)
Circle(radius=support_inner_diameter / 2, mode=Mode.SUBTRACT)
Extrude(base_height - wall_thickness)
Extrude(amount=base_height - wall_thickness)
with Locations((0, 0, lego.vertices().sort_by(SortBy.Z)[-1].z)):
Box(
length=block_length,
@ -314,15 +325,15 @@ could be done with another sketch, we'll add a box to the top of the walls.
centered=(True, True, False),
)
To position the top, we'll create a new location context `Locations` at the center
and at the height of the walls. To determine the height we'll exact that from the
`lego.part` by using the `vertices()` method which returns a list of the positions
of all of the vertices of the lego block so far. Since we're interested in the top,
To position the top, we'll create a new location context ``Locations`` at the center
and at the height of the walls. To determine the height we'll extract that from the
``lego.part`` by using the ``vertices()`` method which returns a list of the positions
of all of the vertices of the Lego block so far. Since we're interested in the top,
we'll sort by the vertical (Z) axis and take the top of the list (index -1). Finally,
the `z` property of this vertex will return just the height of the top.
the ``z`` property of this vertex will return just the height of the top.
Within the scope of this `Locations` context, a `Box` is created, centered in over
the x and y axis but not in the z thus aligning with the top of the walls.
Within the scope of this ``Locations`` context, a ``Box`` is created, centered at
the intersection of the x and y axis but not in the z thus aligning with the top of the walls.
The base is closed now as shown here:
@ -337,6 +348,7 @@ The final step is to add the pips to the top of the Lego block. To do this we'll
a new workplane on top of the block where we can position the pips.
.. code-block:: python
:emphasize-lines: 32-36
with BuildPart() as lego:
with BuildSketch() as plan:
@ -361,7 +373,7 @@ a new workplane on top of the block where we can position the pips.
):
Circle(radius=support_outer_diameter / 2)
Circle(radius=support_inner_diameter / 2, mode=Mode.SUBTRACT)
Extrude(base_height - wall_thickness)
Extrude(amount=base_height - wall_thickness)
with Locations((0, 0, lego.vertices().sort_by(SortBy.Z)[-1].z)):
Box(
length=block_length,
@ -375,13 +387,30 @@ a new workplane on top of the block where we can position the pips.
radius=pip_diameter / 2, height=pip_height, centered=(True, True, False)
)
Much like the location contexts, the `Workplanes` context creates one or more planes that
Much like the location contexts, the ``Workplanes`` context creates one or more planes that
can be used to position further features. In this case, the workplane is created from the
top Face of the Lego block by using the `faces` method and then sorted as previously discussed.
top Face of the Lego block by using the ``faces`` method and then sorted vertically.
On the new workplane, a grid of locations is created and a number of `Cylinder` are positioned there.
This completes the Lego block which would now be displayed or exported as a STL or STEP file.
On the new workplane, a grid of locations is created and a number of ``Cylinder``'s are positioned
at each location.
.. image:: tutorial_step11.svg
:align: center
This completes the Lego block. To access the finished product, refer to the builder's internal
object as shown here:
+-------------+--------+
| Builder | Object |
+=============+========+
| BuildLine | line |
+-------------+--------+
| BuildSketch | sketch |
+-------------+--------+
| BuildPart | part |
+-------------+--------+
so in this case the Lego block is ``lego.part``. To display the part use ``show_object(lego.part)``
or ``show(lego.part)`` depending on the viewer. The part could also be exported to a STL or STEP
file by referencing ``lego.part``.

View file

@ -71,7 +71,7 @@ with BuildPart() as lego:
Circle(support_outer_diameter / 2)
Circle(support_inner_diameter / 2, mode=Mode.SUBTRACT)
# Extrude this base sketch to the height of the walls
Extrude(base_height - wall_thickness)
Extrude(amount=base_height - wall_thickness)
# Create a workplane on the top of the walls
with Workplanes(
Plane(origin=(0, 0, base_height - wall_thickness), normal=(0, 0, 1))

View file

@ -372,7 +372,11 @@ class Extrude(Compound):
Extrude a sketch/face and combine with part.
Args:
until (Union[float, Until, Face]): depth of extrude or extrude limit
faces (Face): sequence of faces, if not provided use pending_faces.
Defaults to None.
amount (float): distance to extrude, sign controls direction
Defaults to None.
until (Union[Until, Face]): depth of extrude or extrude limit
both (bool, optional): extrude in both directions. Defaults to False.
taper (float, optional): taper during extrusion. Defaults to None.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
@ -380,18 +384,27 @@ class Extrude(Compound):
def __init__(
self,
until: Union[float, Until, Face],
*faces: Face,
amount: float = None,
until: Union[Until, Face] = None,
both: bool = False,
taper: float = None,
mode: Mode = Mode.ADD,
):
new_solids: list[Solid] = []
context: BuildPart = BuildPart._get_context()
for face in context.pending_faces:
# TODO: add until and taper functionality
if not faces:
faces = context.pending_faces
context.pending_faces = []
for face in faces:
new_solids.append(
Solid.extrudeLinear(
face,
face.normalAt(face.Center()) * until,
face.normalAt(face.Center()) * amount,
0,
)
)
@ -399,7 +412,7 @@ class Extrude(Compound):
new_solids.append(
Solid.extrudeLinear(
face,
face.normalAt(face.Center()) * until * -1.0,
face.normalAt(face.Center()) * amount * -1.0,
0,
)
)