mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-06 02:30:55 -08:00
Adding a design tutorial
This commit is contained in:
parent
19b15f3d13
commit
a66b8c76f4
6 changed files with 317 additions and 0 deletions
316
docs/tutorial_design.rst
Normal file
316
docs/tutorial_design.rst
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
.. _design_tutorial:
|
||||
|
||||
#############################
|
||||
Designing a Part in build123d
|
||||
#############################
|
||||
|
||||
Designing a part with build123d involves a systematic approach that leverages the power
|
||||
of 2D profiles, extrusions, and revolutions. Where possible, always work in the lowest
|
||||
possible dimension, 1D lines before 2D sketches before 3D parts. The following guide will
|
||||
get you started:
|
||||
|
||||
*As an example, we'll go through the design process for this bracket:*
|
||||
|
||||
.. image:: assets/bracket.png
|
||||
:align: center
|
||||
|
||||
Step 1. Examine the Part in All Three Orientations
|
||||
**************************************************
|
||||
|
||||
Start by visualizing the part from the front, top, and side views. Identify any symmetries
|
||||
in these orientations, as symmetries can simplify the design by reducing the number of
|
||||
unique features you need to model.
|
||||
|
||||
*In the following view of the bracket one can see the plane of symmetry in its middle
|
||||
so we'll only need to design half of it.*
|
||||
|
||||
.. image:: assets/bracket_with_symmetry.png
|
||||
:align: center
|
||||
|
||||
Step 2. Identify Rotational Symmetries
|
||||
**************************************
|
||||
|
||||
Look for structures that could be created through the rotation of a 2D shape. For instance,
|
||||
cylindrical or spherical features are often the result of revolving a profile around an axis.
|
||||
Identify the axis of rotation and make a note of it.
|
||||
|
||||
*There are no rotational structures in the example bracket.*
|
||||
|
||||
Step 3. Select a Convenient Origin
|
||||
**********************************
|
||||
|
||||
Choose an origin point that minimizes the need to move or transform components later in the
|
||||
design process. Ideally, the origin should be placed at a natural center of symmetry or a
|
||||
critical reference point on the part.
|
||||
|
||||
*The plane of symmetry for the bracket was identified in step 1, making it logical to
|
||||
place the origin on this plane at the bottom of the bracket's front face. Additionally,
|
||||
we'll define the coordinate system we'll be working in: Plane.XY (the default), where
|
||||
the origin is set at the global (0,0,0) position. In this system, the x-axis aligns with
|
||||
the front of the bracket, and the z-axis corresponds to its width. It’s important to note
|
||||
that all coordinate systems/planes in build123d adhere to the*
|
||||
`right-hand rule <https://en.wikipedia.org/wiki/Right-hand_rule>`_ *meaning the y-axis is
|
||||
automatically determined by this convention.*
|
||||
|
||||
.. image:: assets/bracket_with_origin.png
|
||||
:align: center
|
||||
|
||||
Step 4. Create 2D Profiles
|
||||
**************************
|
||||
Design the 2D profiles of your part in the appropriate orientation(s). These profiles are
|
||||
the foundation of the part's geometry and can often represent cross-sections of the part.
|
||||
Mirror parts of profiles across any axes of symmetry identified earlier.
|
||||
|
||||
*The 2D profile of the bracket is as follows:*
|
||||
|
||||
.. image:: assets/bracket_sketch.png
|
||||
:align: center
|
||||
|
||||
*The build123d code to generate this profile is as follows:*
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with BuildSketch() as sketch:
|
||||
with BuildLine() as profile:
|
||||
FilletPolyline(
|
||||
(0, 0), (length / 2, 0), (length / 2, height), radius=bend_radius
|
||||
)
|
||||
offset(amount=thickness, side=Side.LEFT)
|
||||
make_face()
|
||||
mirror(about=Plane.YZ)
|
||||
|
||||
*This code creates a 2D sketch of a mirrored profile in the build123d CAD system. Here's a step-by-step explanation of what it does:*
|
||||
|
||||
with BuildSketch() as sketch:
|
||||
*This starts a context for creating a 2D sketch, which defines the overall boundary and geometric features. The sketch will be stored in the variable sketch.*
|
||||
|
||||
with BuildLine() as profile:
|
||||
*This starts another context, this time for drawing lines (or profiles) within the sketch. The profile consists of connected line segments, arcs, or polylines.*
|
||||
|
||||
FilletPolyline((0, 0), (length / 2, 0), (length / 2, height), radius=bend_radius)
|
||||
*This object draws a polyline with three points: (0,0), (length/2, 0), and (length/2, height). A fillet (curved corner) with a radius of bend_radius is added where applicable between the segments of the polyline.*
|
||||
|
||||
offset(amount=thickness, side=Side.LEFT)
|
||||
*This applies an offset to the polyline created earlier. The offset creates a parallel line at a distance of thickness to the left side of the original polyline. This operation essentially thickens the profile by a given amount.*
|
||||
|
||||
make_face()
|
||||
*This command creates a 2D face from the closed profile. The offset operation ensures that the profile is closed, allowing the creation of a solid face from the boundary defined.*
|
||||
|
||||
mirror(about=Plane.YZ)
|
||||
*This mirrors the entire face about the YZ plane (which runs along the center of the sketch), creating a symmetrical counterpart of the face. The mirrored geometry will complete the final shape.*
|
||||
|
||||
Step 5. Use Extrusion for Prismatic Features
|
||||
********************************************
|
||||
For solid or prismatic shapes, extrude the 2D profiles along the necessary axis. You can
|
||||
also combine multiple extrusions by intersecting or unionizing them to form complex shapes.
|
||||
Use the resulting geometry as sub-parts if needed.
|
||||
|
||||
*The next step in implmenting our design in build123d is to convert the above sketch into
|
||||
a part by extruding it as shown in this code:*
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with BuildPart() as bracket:
|
||||
with BuildSketch() as sketch:
|
||||
with BuildLine() as profile:
|
||||
FilletPolyline(
|
||||
(0, 0), (length / 2, 0), (length / 2, height), radius=bend_radius
|
||||
)
|
||||
offset(amount=thickness, side=Side.LEFT)
|
||||
make_face()
|
||||
mirror(about=Plane.YZ)
|
||||
extrude(amount=width)
|
||||
|
||||
*Here we've wrapped the sketch in a BuildPart context - used to create 3D parts - and
|
||||
the extrude function with draws the sketch out into a solid object.*
|
||||
|
||||
Step 6. Generate Revolved Features
|
||||
**********************************
|
||||
If any part of the geometry can be created by revolving a 2D profile around an axis, use
|
||||
the revolve operation. This is particularly useful for parts that include cylindrical,
|
||||
conical, or spherical features. Combine these revolved sub-parts with existing features
|
||||
using additive, subtractive, or intersecting operations.
|
||||
|
||||
*Our example has no revolved features.*
|
||||
|
||||
Step 7. Combine Sub-parts Intelligently
|
||||
***************************************
|
||||
When combining multiple sub-parts, keep in mind whether they need to be added, subtracted,
|
||||
or intersected. Subtracting or intersecting can create more refined details, while addition
|
||||
is useful for creating complex assemblies.
|
||||
|
||||
*Out example only has one sub-part but further sub-parts could be created in the
|
||||
BuildPart context by defining more sketches and extruding or revolving them.*
|
||||
|
||||
Step 8. Apply Chamfers and Fillets
|
||||
**********************************
|
||||
Identify critical edges or vertices that need chamfering or filleting. Use build123d’s
|
||||
selectors to apply these operations accurately. Always visually inspect the results to
|
||||
ensure the correct edges have been modified.
|
||||
|
||||
*The back corners of the bracket need to be rounded off or filleted so the edges that
|
||||
define these corners need to be isolated. The following code, placed to follow the previous
|
||||
code block, captures just these edges:*
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
corners = bracket.edges().filter_by(Axis.X).group_by(Axis.Y)[-1]
|
||||
fillet(corners, fillet_radius)
|
||||
|
||||
*These lines isolates specific corner edges that are then filleted.*
|
||||
|
||||
corners = bracket.edges().filter_by(Axis.X).group_by(Axis.Y)[-1]
|
||||
*This line is used to select specific edges from the 3D part (bracket) that was
|
||||
created by the extrusion.*
|
||||
|
||||
- bracket.edges() *retrieves all the edges of the bracket part.*
|
||||
- filter_by(Axis.X) *filters the edges to only those that are aligned along the
|
||||
X-axis.*
|
||||
- group_by(Axis.Y) *groups the edges by their positions along the Y-axis. This
|
||||
operation essentially organizes the filtered X-axis edges into groups based on
|
||||
their Y-coordinate positions.*
|
||||
- [-1] *selects the last group of edges along the Y-axis, which corresponds
|
||||
to the back of the part - the edges we are looking for.*
|
||||
|
||||
|
||||
fillet(corners, fillet_radius)
|
||||
*This function applies a fillet (a rounded edge) to the selected corners, with a
|
||||
specified radius (fillet_radius). The fillet smooths the sharp edges at the corners,
|
||||
giving the part a more refined shape.*
|
||||
|
||||
Step 9. Design for Assembly
|
||||
***************************
|
||||
If the part is intended to connect with others, add features like joints, holes, or other
|
||||
attachment points. Ensure that these features are precisely located to ensure proper fitment
|
||||
and functionality in the final assembly.
|
||||
|
||||
*Our example has two circular holes and a slot that need to be created. First we'll create
|
||||
the two circular holes:*
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with Locations(bracket.faces().sort_by(Axis.X)[-1]):
|
||||
Hole(hole_diameter / 2)
|
||||
|
||||
*This code creates a hole in a specific face of the bracket part.*
|
||||
|
||||
with Locations(bracket.faces().sort_by(Axis.X)[-1]):
|
||||
*This context sets a location(s) for subsequent operations.*
|
||||
|
||||
- bracket.faces() *retrieves all the faces of the bracket part.*
|
||||
- sort_by(Axis.X) *sorts these faces based on their position along the X-axis (from
|
||||
one side of the bracket to the other).*
|
||||
- [-1] *selects the last face in this sorted list, which would be the face farthest
|
||||
along the X-axis, the extreme right side of the part.*
|
||||
- Locations() *creates a new local context or coordinate system at the selected face,
|
||||
effectively setting this face as the working location for any subsequent operations
|
||||
inside the with block.*
|
||||
|
||||
Hole(hole_diameter / 2)
|
||||
*This creates a hole in the selected face. The radius of the hole is specified as
|
||||
hole_diameter / 2. The hole is placed at the origin of the selected face, based on
|
||||
the local coordinate system created by Locations(). As the depth of the hole is
|
||||
not provided it is assumed to go entirely through the part.*
|
||||
|
||||
*Next the slot needs to be created in the bracket with will be done by sketching a slot on
|
||||
the front of the bracket and extruding the sketch through the part.*
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with BuildSketch(bracket.faces().sort_by(Axis.Y)[0]):
|
||||
SlotOverall(20 * MM, hole_diameter)
|
||||
extrude(amount=-thickness, mode=Mode.SUBTRACT)
|
||||
|
||||
*Here’s a detailed explanation of what each part does:*
|
||||
|
||||
with BuildSketch(bracket.faces().sort_by(Axis.Y)[0]):
|
||||
*This line sets up a sketching context.*
|
||||
|
||||
- bracket.faces() *retrieves all the faces of the bracket part.*
|
||||
- sort_by(Axis.Y) *sorts the faces along the Y-axis, arranging them from the lowest
|
||||
Y-coordinate to the highest.*
|
||||
- [0] *selects the first face in this sorted list, which is the one located at the
|
||||
lowest Y-coordinate, the nearest face of the part.*
|
||||
- BuildSketch() *creates a new sketching context on this selected face, where 2D
|
||||
geometry will be drawn.*
|
||||
|
||||
SlotOverall(20, hole_diameter)
|
||||
*This command draws a slot (a rounded rectangle or elongated hole) on the selected
|
||||
face. The slot has a total length of 20 mm and a width equal to hole_diameter.
|
||||
The slot is defined within the 2D sketch on the selected face of the bracket.*
|
||||
|
||||
extrude(amount=-thickness, mode=Mode.SUBTRACT)
|
||||
extrude() *takes the 2D sketch (the slot) and extends it into the 3D space by a
|
||||
distance equal to -thickness, creating a cut into the part. The negative value
|
||||
(-thickness) indicates that the extrusion is directed inward into the part (a cut).*
|
||||
mode=Mode.SUBTRACT *specifies that the extrusion is a subtractive operation,
|
||||
meaning it removes material from the bracket, effectively cutting the slot through
|
||||
the face of the part.*
|
||||
|
||||
*Although beyond the scope of this tutorial, joints could be defined for each of the
|
||||
holes to allow programmatic connection to other parts.*
|
||||
|
||||
Step 10. Plan for Parametric Flexibility
|
||||
****************************************
|
||||
Wherever possible, make your design parametric, allowing dimensions and features to be
|
||||
easily adjusted later. This flexibility can be crucial if the design needs modifications
|
||||
or if variations of the part are needed.
|
||||
|
||||
*The dimensions of the bracket are defined as follows:*
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
thickness = 3 * MM
|
||||
width = 25 * MM
|
||||
length = 50 * MM
|
||||
height = 25 * MM
|
||||
hole_diameter = 5 * MM
|
||||
bend_radius = 5 * MM
|
||||
fillet_radius = 2 * MM
|
||||
|
||||
Step 11. Test Fit and Tolerances
|
||||
********************************
|
||||
Visualize the fit of the part within its intended assembly. Consider tolerances for
|
||||
manufacturing, such as clearance between moving parts or shrinkage for 3D-printed parts.
|
||||
Adjust the design as needed to ensure real-world functionality.
|
||||
|
||||
Summary
|
||||
*******
|
||||
These steps should guide you through a logical and efficient workflow in build123d
|
||||
(or any CAD tool), helping you to design parts with accuracy and ease.
|
||||
|
||||
*The entire code block for the bracket example is shown here:*
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from build123d import *
|
||||
from ocp_vscode import show_all
|
||||
|
||||
thickness = 3 * MM
|
||||
width = 25 * MM
|
||||
length = 50 * MM
|
||||
height = 25 * MM
|
||||
hole_diameter = 5 * MM
|
||||
bend_radius = 5 * MM
|
||||
fillet_radius = 2 * MM
|
||||
|
||||
with BuildPart() as bracket:
|
||||
with BuildSketch() as sketch:
|
||||
with BuildLine() as profile:
|
||||
FilletPolyline(
|
||||
(0, 0), (length / 2, 0), (length / 2, height), radius=bend_radius
|
||||
)
|
||||
offset(amount=thickness, side=Side.LEFT)
|
||||
make_face()
|
||||
mirror(about=Plane.YZ)
|
||||
extrude(amount=width)
|
||||
corners = bracket.edges().filter_by(Axis.X).group_by(Axis.Y)[-1]
|
||||
fillet(corners, fillet_radius)
|
||||
with Locations(bracket.faces().sort_by(Axis.X)[-1]):
|
||||
Hole(hole_diameter / 2)
|
||||
with BuildSketch(bracket.faces().sort_by(Axis.Y)[0]):
|
||||
SlotOverall(20 * MM, hole_diameter)
|
||||
extrude(amount=-thickness, mode=Mode.SUBTRACT)
|
||||
|
||||
show_all()
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue