mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-15 15:20:37 -08:00
311 lines
11 KiB
ReStructuredText
311 lines
11 KiB
ReStructuredText
############
|
|
Key Concepts
|
|
############
|
|
|
|
The following key concepts will help new users understand build123d quickly.
|
|
|
|
********
|
|
Builders
|
|
********
|
|
|
|
The three builders, `BuildLine`, `BuildSketch`, and `BuildPart` are tools to create
|
|
new objects - not the objects themselves. Each of the objects and operations applicable
|
|
to these builders create objects of the standard CadQuery Direct API, most commonly
|
|
`Compound` objects. This is opposed to CadQuery's Fluent API which creates objects
|
|
of the `Workplane` class which frequently needed to be converted back to base
|
|
class for further processing.
|
|
|
|
One can access the objects created by these builders by referencing the appropriate
|
|
instance variable. For example:
|
|
|
|
.. code-block:: python
|
|
|
|
with BuildPart() as my_part:
|
|
...
|
|
|
|
show_object(my_part.part)
|
|
|
|
.. code-block:: python
|
|
|
|
with BuildSketch() as my_sketch:
|
|
...
|
|
|
|
show_object(my_sketch.sketch)
|
|
|
|
.. code-block:: python
|
|
|
|
with BuildLine() as my_line:
|
|
...
|
|
|
|
show_object(my_line.line)
|
|
|
|
*******************
|
|
Workplane Generator
|
|
*******************
|
|
|
|
As build123d is a 3D CAD package one must be able to position objects anywhere. As one
|
|
frequently will work in the same plane for a sequence of operations, a workplane is used
|
|
to aid in the location of features. The default workplane in most cases is the XY plane
|
|
where a tuple of numbers represent positions on the x and y axes. However workplanes can
|
|
be generated on any plane which allows users to put a workplane where they are working
|
|
and then work in local 2D coordinate space.
|
|
|
|
To facilitate this a `Workplanes` generator is used to create a context where a given
|
|
workplane will apply. For example:
|
|
|
|
.. code-block:: python
|
|
|
|
with BuildPart(workplane="XY") example:
|
|
with BuildSketch() as bottom:
|
|
...
|
|
with Workplanes("XZ") as vertical:
|
|
with BuildSketch() as side:
|
|
...
|
|
with Workplanes(example.faces().sort_by(SortBy.Z)[-1]):
|
|
with BuildSketch() as top:
|
|
...
|
|
|
|
When `BuildPart` is invoked it creates the workplane provided as a parameter (which has a
|
|
default of the XY plane). The `bottom` sketch is therefore created on the XY plane. Subsequently
|
|
the user has created the `vertical` plane (XZ) on which the `side` sketch is created. All
|
|
objects or operations within the scope of a workplane will automatically be orientated with
|
|
respect to this plane so the user only has to work with local coordinates.
|
|
|
|
Workplanes can be created from faces as well. The `top` sketch is positioned on top
|
|
of `example` by selecting its faces and finding the one with the greatest z value.
|
|
|
|
One is not limited to a single workplane at a time. In the following example all six
|
|
faces of the first box is used to define workplanes which are then used to position
|
|
rotated boxes.
|
|
|
|
.. code-block:: python
|
|
|
|
import build123d as bd
|
|
|
|
with bd.BuildPart() as bp:
|
|
bd.Box(3, 3, 3)
|
|
with bd.Workplanes(*bp.faces()):
|
|
bd.Box(1, 2, 0.1, rotation=(0, 0, 45))
|
|
|
|
This is the result:
|
|
|
|
.. image:: boxes_on_faces.svg
|
|
:align: center
|
|
|
|
A detailed description of `Workplanes` follows:
|
|
|
|
.. py:module:: build_common
|
|
|
|
.. autoclass:: Workplanes
|
|
|
|
*******************
|
|
Location Generators
|
|
*******************
|
|
|
|
When positioning objects or operations within a builder Location Generators are used. These
|
|
function in a very similar was to the builders in that they create a context where one or
|
|
more locations are active within a scope. For example:
|
|
|
|
.. code-block:: python
|
|
|
|
with BuildPart():
|
|
with Locations((0,10),(0,-10)):
|
|
Box(1,1,1)
|
|
with GridLocations(x_spacing=5, y_spacing=5, x_count=2, y_count=2)
|
|
Sphere(1)
|
|
Cylinder(1,1)
|
|
|
|
In this example `Locations` creates two positions on the current workplane at (0,10) and (0,-10).
|
|
Since `Box` is within the scope of `Locations`, two boxes are created at these locations. The
|
|
`GridLocations` generator creates four positions which apply to the `Sphere`. The `Cylinder` is
|
|
out of the scope of `GridLocations` but in the scope of `Locations` so two cylinders are created.
|
|
|
|
Note that these generators are creating Location objects not just simple points. The difference
|
|
isn't obvious until the `PolarLocations` generator is used which can also rotate objects within
|
|
its scope - much as the hour and minute indicator on an analogue clock.
|
|
|
|
Each of the generators are described in detail below:
|
|
|
|
.. autoclass:: Locations
|
|
.. autoclass:: GridLocations
|
|
.. autoclass:: HexLocations
|
|
.. autoclass:: PolarLocations
|
|
|
|
****************
|
|
Operation Inputs
|
|
****************
|
|
|
|
When one is operating on an existing object, e.g. adding a fillet to a part,
|
|
a sequence of objects is often required. A python sequence of objects is
|
|
simply either a single object or a string of objects separated by commas.
|
|
To pass an array into a sequence, precede it with a `*` operator.
|
|
When a sequence is followed by another parameter, that parameter must be
|
|
entered as a keyword parameter (e.g. radius=1) to separate this parameter
|
|
from the preceding sequence.
|
|
|
|
Here is the definition of `Fillet` to help illustrate:
|
|
|
|
.. code-block:: python
|
|
|
|
class Fillet(Compound):
|
|
def __init__(self, *objects: Union[Edge, Vertex], radius: float):
|
|
|
|
To use this fillet operation, a sequence of edges or vertices must be provided
|
|
followed by a fillet radius as follows:
|
|
|
|
.. code-block:: python
|
|
|
|
with BuildPart() as pipes:
|
|
Box(10, 10, 10, rotation=(10, 20, 30))
|
|
...
|
|
Fillet(*pipes.edges(Select.LAST), radius=0.2)
|
|
|
|
Here the list of edges from the last operation of the `pipes` builder are converted
|
|
to a sequence and a radius is provided as a keyword argument.
|
|
|
|
*****************
|
|
Combination Modes
|
|
*****************
|
|
Almost all objects or operations have a `mode` parameter which is defined by the
|
|
`Mode` Enum class as follows:
|
|
|
|
.. code-block:: python
|
|
|
|
class Mode(Enum):
|
|
ADD = auto()
|
|
SUBTRACT = auto()
|
|
INTERSECT = auto()
|
|
REPLACE = auto()
|
|
PRIVATE = auto()
|
|
|
|
The `mode` parameter describes how the user would like the object or operation to
|
|
interact with the object within the builder. For example, `Mode.ADD` will
|
|
integrate a new object(s) in with an existing `part`. Note that a part doesn't
|
|
necessarily have to be a single object so multiple distinct objects could be added
|
|
resulting is multiple objects stored as a `Compound` object. As one might expect
|
|
`Mode.SUBTRACT`, `Mode.INTERSECT`, and `Mode.REPLACE` subtract, intersect, or replace
|
|
(from) the builder's object. `Mode.PRIVATE` instructs the builder that this object
|
|
should not be combined with the builder's object in any way.
|
|
|
|
Most commonly, the default `mode` is `Mode.ADD` but this isn't always true.
|
|
For example, the `Hole` classes use a default `Mode.SUBTRACT` as they remove
|
|
a volume from the part under normal circumstances. However, the `mode` used in
|
|
the `Hole` classes can be specified as `Mode.ADD` or `Mode.INTERSECT` to
|
|
help in inspection or debugging.
|
|
|
|
*********************************
|
|
Pushing Points & Rotating Objects
|
|
*********************************
|
|
|
|
build123d stores points (to be specific `Locations`) internally to be used as
|
|
positions for the placement of new objects. By default, a single location
|
|
will be created at the origin of the given workplane such that:
|
|
|
|
.. code-block:: python
|
|
|
|
with BuildPart() as pipes:
|
|
Box(10, 10, 10, rotation=(10, 20, 30))
|
|
|
|
will create a single 10x10x10 box centered at (0,0,0) - by default objects are
|
|
centered. One can create multiple objects by pushing points prior to creating
|
|
objects as follows:
|
|
|
|
.. code-block:: python
|
|
|
|
with BuildPart() as pipes:
|
|
PushPoints((-10, -10, -10), (10, 10, 10))
|
|
Box(10, 10, 10, rotation=(10, 20, 30))
|
|
|
|
which will create two boxes. Note that whenever points are pushed, previous
|
|
points are replaced.
|
|
|
|
To orient a part, a `rotation` parameter is available on `BuildSketch`` and
|
|
`BuildPart` APIs. When working in a sketch, the rotation is a single angle in
|
|
degrees so the parameter is a float. When working on a part, the rotation is
|
|
a three dimensional `Rotation` object of the form
|
|
`Rotation(<about x>, <about y>, <about z>)` although a simple three tuple of
|
|
floats can be used as input. As 3D rotations are not cumulative, one can
|
|
combine rotations with the `*` operator like this:
|
|
`Rotation(10, 20, 30) * Rotation(0, 90, 0)` to generate any desired rotation.
|
|
|
|
.. hint::
|
|
Experts Only
|
|
|
|
`PushPoints` will accept `Location` objects for input which allows one
|
|
to specify both the position and orientation. However, the orientation
|
|
is often determined by the `Plane` that an object was created on.
|
|
`Rotation` is a subclass of `Location` and therefore will also accept
|
|
a position component.
|
|
|
|
*************************
|
|
Builder's Pending Objects
|
|
*************************
|
|
|
|
When a builder exits, it will push the object created back to its parent if
|
|
there was one. Here is an example:
|
|
|
|
.. code-block:: python
|
|
|
|
with BuildPart() as pillow_block:
|
|
with BuildSketch() as plan:
|
|
Rectangle(width, height)
|
|
Fillet(*plan.vertices(), radius=fillet)
|
|
Extrude(thickness)
|
|
|
|
`BuildSketch` exits after the `FilletSketch` operation and when doing so it transfers
|
|
the sketch to the `pillow_block` instance of `BuildPart` as the internal instance variable
|
|
`pending_faces`. This allows the `Extrude` operation to be immediately invoked as it
|
|
extrudes these pending faces into `Solid` objects. Likewise, `Loft` will take all of the
|
|
`pending_faces` and attempt to create a single `Solid` object from them.
|
|
|
|
Normally the user will not need to interact directly with pending objects.
|
|
|
|
***********
|
|
Shape Lists
|
|
***********
|
|
|
|
The builders include methods to extract Edges, Faces, Solids, or Vertices from the objects
|
|
they are building. These methods are as follows:
|
|
|
|
+-------------+---------+---------+----------+------------+
|
|
| Size | Edges | Faces | Solids | Vertices |
|
|
+=============+=========+=========+==========+============+
|
|
| BuildLine | edges() | | | vertices() |
|
|
+-------------+---------+---------+----------+------------+
|
|
| BuildSketch | edges() | faces() | | vertices() |
|
|
+-------------+---------+---------+----------+------------+
|
|
| BuildPart | edges() | edges() | solids() | vertices() |
|
|
+-------------+---------+---------+----------+------------+
|
|
|
|
All of these methods return objects in a subclass of `list`, a `ShapeList` with some custom
|
|
filtering and sorting methods predefined described as follows.
|
|
|
|
.. autoclass:: build_common.ShapeList
|
|
:members:
|
|
:exclude-members: axis_map
|
|
|
|
The filter and sort parameters use the following Enums (numeric values are meaningless):
|
|
|
|
.. autoclass:: build_common.Axis
|
|
:members:
|
|
|
|
.. autoclass:: build_common.SortBy
|
|
:members:
|
|
|
|
.. autoclass:: build_common.Type
|
|
:members:
|
|
|
|
|
|
It is important to note that standard list methods such as `sorted` or `filtered` can
|
|
be used to easily build complex selectors beyond what is available with the predefined
|
|
sorts and filters. Here is an example of a custom filters:
|
|
|
|
.. code-block:: python
|
|
|
|
with BuildSketch() as din:
|
|
...
|
|
outside_vertices = filter(
|
|
lambda v: (v.Y == 0.0 or v.Y == height)
|
|
and -overall_width / 2 < v.X < overall_width / 2,
|
|
din.vertices(),
|
|
)
|