Build123d Readthedocs Io en Latest
Build123d Readthedocs Io en Latest
Release 0.9.2.dev67+gbde03f4
Gumyr
1 Table Of Contents 3
1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.3 Key Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.4 Key Concepts (builder mode) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.5 Key Concepts (algebra mode) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.6 Moving Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.7 Transitioning from OpenSCAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.8 Introductory Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.9 Tutorials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
1.10 Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
1.11 Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
1.12 Builders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
1.13 Joints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
1.14 Assemblies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
1.15 Tips, Best Practices and FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
1.16 Import/Export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
1.17 Advanced Topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
1.18 Cheat Sheet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
1.19 External Tools and Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
1.20 Builder Common API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
1.21 Direct API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
1.22 Indices and tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
Index 381
i
ii
build123d, Release 0.9.2.dev67+gbde03f4
Build123d is a python-based, parametric, boundary representation (BREP) modeling framework for 2D and 3D CAD.
It’s built on the Open Cascade geometric kernel and allows for the creation of complex models using a simple and
intuitive python syntax. Build123d can be used to create models for 3D printing, CNC machining, laser cutting, and
other manufacturing processes. Models can be exported to a wide variety of popular CAD tools such as FreeCAD and
SolidWorks.
Build123d could be considered as an evolution of CadQuery where the somewhat restrictive Fluent API (method chain-
ing) is replaced with stateful context managers - i.e. with blocks - thus enabling the full python toolbox: for loops,
references to objects, object sorting and filtering, etc.
Note that this documentation is available in pdf and epub formats for reference while offline.
build123d uses the standard python context manager - i.e. the with statement often used when working with files - as
a builder of the object under construction. Once the object is complete it can be extracted from the builders and used
in other ways: for example exported as a STEP file or used in an Assembly. There are three builders available:
• BuildLine: a builder of one dimensional objects - those with the property of length but not of area or volume -
typically used to create complex lines used in sketches or paths.
• BuildSketch: a builder of planar two dimensional objects - those with the property of area but not of volume -
typically used to create 2D drawings that are extruded into 3D parts.
• BuildPart: a builder of three dimensional objects - those with the property of volume - used to create individual
parts.
The three builders work together in a hierarchy as follows:
where my_line will be added to my_sketch once the line is complete and my_sketch will be added to my_part once
the sketch is complete.
As an example, consider the design of a tea cup:
wall_thickness = 3 * MM
fillet_radius = wall_thickness * 0.49
CONTENTS 1
build123d, Release 0.9.2.dev67+gbde03f4
ò Note
There is a Discord server (shared with CadQuery) where you can ask for help in the build123d channel.
2 CONTENTS
CHAPTER
ONE
TABLE OF CONTENTS
1.1 Introduction
1.1.1 Key Aspects
The following sections describe some of the key aspects of build123d and illustrate why one might choose this open
source system over proprietary options like SolidWorks, OnShape, Fusion 360, or even other open source systems like
Blender, or OpenSCAD.
3
build123d, Release 0.9.2.dev67+gbde03f4
Parameterized Models
Parametrized CAD systems are more effective than non-parametric CAD systems in several ways:
• Reusability: Parametrized CAD models can be easily modified by changing a set of parameters, such as the length
or width of an object, rather than having to manually edit the geometry. This makes it easy to create variations
of a design without having to start from scratch.
• Design exploration: Parametrized CAD systems allow for easy exploration of different design options by chang-
ing the parameters and quickly visualizing the results. This can save a lot of time and effort during the design
process.
• Constraints and relationships: Parametrized CAD systems allow for the definition of constraints and relationships
between different parameters. This ensures that the model remains valid and functional even when parameters
are changed.
• Automation: Parametrized CAD systems can be automated to perform repetitive tasks, such as generating de-
tailed drawings or creating parts lists. This can save a lot of time and effort and reduce the risk of errors.
• Collaboration: Parametrized CAD systems allow different team members to work on different aspects of a design
simultaneously and ensure that the model remains consistent across different stages of the development process.
• Document management: Parametrized CAD systems can generate engineering drawings, BOMs, and other doc-
uments automatically, which makes it easier to manage and track the design history.
In summary, parametrized CAD systems are more effective than non-parametric CAD systems because they provide a
more efficient and flexible way to create and modify designs, and can be easily integrated into the design, manufacturing,
and documentation process.
1.1. Introduction 5
build123d, Release 0.9.2.dev67+gbde03f4
In summary, GUI version control systems are generally more user-friendly and easier to use, while source code control
systems like Git offer more flexibility and control over the code. Both can be used to achieve the same goal, but they
cater to different types of users and use cases.
Automated Testing
Users of source based CAD systems can benefit from automated testing which improves their source code by:
• Finding bugs: Automated tests can detect bugs in the code, which can then be fixed before the code is released.
This helps to ensure that the code is of higher quality and less likely to cause issues when used.
• Regression testing: Automated tests can be used to detect regressions, which are bugs that are introduced by
changes to the codebase. This helps to ensure that changes to the code do not break existing functionality.
• Documenting code behavior: Automated tests can serve as documentation for how the code is supposed to behave.
This makes it easier for developers to understand the code and make changes without breaking it.
• Improving code design: Writing automated tests often requires a good understanding of the code and how it is
supposed to behave. This can lead to a better design of the code, as developers will have a better understanding
of the requirements and constraints.
• Saving time and cost: Automated testing can save time and cost by reducing the need for manual testing. Auto-
mated tests can be run quickly and often, which means that bugs can be found and fixed early in the development
process, which is less expensive than finding them later.
• Continuous integration and delivery: Automated testing can be integrated into a continuous integration and
delivery (CI/CD) pipeline. This means that tests are run automatically every time code is committed and can be
integrated with other tools such as code coverage, static analysis and more.
• Improving maintainability: Automated tests can improve the maintainability of the code by making it easier to
refactor and change the codebase. This is because automated tests provide a safety net that ensures that changes
to the code do not introduce new bugs.
Overall, automated testing is an essential part of the software development process, it helps to improve the quality of
the code by detecting bugs early, documenting code behavior, and reducing the cost of maintaining and updating the
code.
Automated Documentation
The Sphinx automated documentation system was used to create the page you are reading now and can be used for user
design documentation as well. Such systems are used for several reasons:
• Consistency: Sphinx and other automated documentation systems can generate documentation in a consistent
format and style, which makes it easier to understand and use.
• Automation: Sphinx can automatically generate documentation from source code and comments, which saves
time and effort compared to manually writing documentation.
• Up-to-date documentation: Automated documentation systems like Sphinx can update the documentation auto-
matically when the code changes, ensuring that the documentation stays up-to-date with the code.
• Searchability: Sphinx and other automated documentation systems can include search functionality, which makes
it easy to find the information you need.
• Cross-referencing: Sphinx can automatically create links between different parts of the documentation, making
it easy to navigate and understand the relationships between different parts of the code.
• Customizable: Sphinx and other automated documentation systems can be customized to match the look and
feel of your company’s documentation.
• Multiple output formats: Sphinx can generate documentation in multiple formats such as HTML, PDF, ePub,
and more.
• Support for multiple languages: Sphinx can generate documentation in multiple languages, which can make it
easier to support international users.
• Integration with code management: Sphinx can be integrated with code management tools like Git, which allows
documentation to be versioned along with the code.
In summary, automated documentation systems like Sphinx are used to generate consistent, up-to-date, and searchable
documentation from source code and comments. They save time and effort compared to manual documentation, and
can be customized to match the look and feel of your company’s documentation. They also provide multiple output
formats, support for multiple languages and can be integrated with code management tools.
# build123d API
with BuildPart() as pillow_block:
with BuildSketch() as plan:
Rectangle(width, height)
fillet(plan.vertices(), radius=fillet)
extrude(thickness)
...
The use of the standard with block allows standard python instructions to be inserted anyway in the code flow. One can
insert a CQ-editor debug or standard print statement anywhere in the code without impacting functionality. Simple
python for loops can be used to repetitively create objects instead of forcing users into using more complex lambda
and iter operations.
Instantiated Objects
Each object and operation is now a class instantiation that interacts with the active context implicitly for the user. These
instantiations can be assigned to an instance variable as with standard python programming for direct use.
1.1. Introduction 7
build123d, Release 0.9.2.dev67+gbde03f4
Operators
New operators have been created to extract information from objects created previously in the code. The @ operator
extracts the position along an Edge or Wire while the % operator extracts the tangent along an Edge or Wire. The
position parameter are float values between 0.0 and 1.0 which represent the beginning and end of the line. In the
following example, a spline is created from the end of l5 (l5 @ 1) to the beginning of l6 (l6 @ 0) with tangents equal
to the tangents of l5 and l6 at their end and beginning respectively. Being able to extract information from existing
features allows the user to “snap” new features to these points without knowing their numeric values.
Extensions
Extending build123d is relatively simple in that custom objects or operations can be created as new classes without the
need to monkey patch any of the core functionality. These new classes will be seen in IDEs which is not possible with
monkey patching the core CadQuery classes.
Enums
All Literal strings have been replaced with Enum which allows IDEs to prompt users for valid options without having
to refer to documentation.
top = rail.faces().filter_by(Axis.Z)[-1]
...
(continues on next page)
1.2 Installation
The recommended method for most users to install build123d is:
ò Note
If you receive errors about conflicting dependencies, you can retry the installation after having upgraded pip to the
latest version with the following command:
However, if you want the latest commit from GitHub you might need to specify the branch that is used for git-based
installs; until quite recently, poetry used to checkout the master branch when none was specified, and this fails on
build123d that uses a dev branch.
Pip does not suffer from this issue because it correctly fetches the repository default branch.
If you are a poetry user, you can work around this issue by installing build123d in the following way:
Please note that always suffixing the URL with @dev is safe and will work with both older and recent versions of poetry.
1.2. Installation 9
build123d, Release 0.9.2.dev67+gbde03f4
Once pip is up-to-date, you can install build123d in development mode with the following commands:
Please substitute python3 with python in the lines above if you are using Windows.
If you’re working directly with the OpenCascade OCP layer you will likely want to install the OCP stubs as follows:
>>> python
>>> from build123d import *
>>> print(Solid.make_box(1,2,3).show_topology(limit_class="Face"))
1.3.1 Topology
Topology, in the context of 3D modeling and computational geometry, is the branch of mathematics that deals with
the properties and relationships of geometric objects that are preserved under continuous deformations. In the context
of CAD and modeling software like build123d, topology refers to the hierarchical structure of geometric elements
(vertices, edges, faces, etc.) and their relationships in a 3D model. This structure defines how the components of a
model are connected, enabling operations like Boolean operations, transformations, and analysis of complex shapes.
Topology provides a formal framework for understanding and manipulating geometric data in a consistent and reliable
manner.
The following are the topological objects that compose build123d objects:
Vertex
A Vertex is a data structure representing a 0D topological element. It defines a precise point in 3D space, often
at the endpoints or intersections of edges in a 3D model. These vertices are part of the topological structure used
to represent complex shapes in build123d.
Edge
An Edge in build123d is a fundamental geometric entity representing a 1D element in a 3D model. It defines the
shape and position of a 1D curve within the model. Edges play a crucial role in defining the boundaries of faces
and in constructing complex 3D shapes.
Wire
A Wire in build123d is a topological construct that represents a connected sequence of Edges, forming a 1D
closed or open loop within a 3D model. Wires define the boundaries of faces and can be used to create complex
shapes, making them essential for modeling in build123d.
Face
A Face in build123d represents a 2D surface in a 3D model. It defines the boundary of a region and can have
associated geometric and topological data. Faces are vital for shaping solids, providing surfaces where other
elements like edges and wires are connected to form complex structures.
Shell
A Shell in build123d represents a collection of Faces, defining a closed, connected volume in 3D space. It acts
as a container for organizing and grouping faces into a single shell, essential for defining complex 3D shapes like
solids or assemblies within the build123d modeling framework.
Solid
A Solid in build123d is a 3D geometric entity that represents a bounded volume with well-defined interior and
exterior surfaces. It encapsulates a closed and watertight shape, making it suitable for modeling solid objects
and enabling various Boolean operations such as union, intersection, and subtraction.
Compound
A Compound in build123d is a container for grouping multiple geometric shapes. It can hold various types of
entities, such as vertices, edges, wires, faces, shells, or solids, into a single structure. This makes it a versatile
tool for managing and organizing complex assemblies or collections of shapes within a single container.
Shape
A Shape in build123d represents a fundamental building block in 3D modeling. It encompasses various topo-
logical elements like vertices, edges, wires, faces, shells, solids, and compounds. The Shape class is the base
class for all of the above topological classes.
One can use the show_topology() method to display the topology of a shape as shown here for a unit cube:
Users of build123d will often reference topological objects as part of the process of creating the object as described
below.
1.3.2 Location
A Location represents a combination of translation and rotation applied to a topological or geometric object. It
encapsulates information about the spatial orientation and position of a shape within its reference coordinate system.
This allows for efficient manipulation of shapes within complex assemblies or transformations. The location is typically
used to position shapes accurately within a 3D scene, enabling operations like assembly, and boolean operations. It’s an
essential component in build123d for managing the spatial relationships of geometric entities, providing a foundation
for precise 3D modeling and engineering applications.
The topological classes (sub-classes of Shape) and the geometric classes Axis and Plane all have a location prop-
erty. The Location class itself has position and orientation properties that have setters and getters as shown
below:
There are also four methods that are used to change the location of objects:
• locate() - absolute change of this object
• located() - absolute change of copy of this object
• move() - relative change of this object
• moved() - relative change of copy of this object
Locations can be combined with the * operator and have their direction flipped with the - operator.
1.3.3 Selectors
When using a GUI based CAD system the user will often click on a feature to select it for some operation. How does a
user “click” when CAD is done entirely in code? Selectors are recipes for how to isolate a feature from a design using
python filter and sorting methods typically implemented as a set of custom python operations.
Quick Reference
The following tables describes the build123d selectors:
The operand types are: Axis, Plane, SortBy, and GeomType. An Axis is a base object with an origin and a direction
with several predefined values such as Axis.X, Axis.Y, and Axis.Z; however, any Axis could be used as an operand
(e.g. Axis((1,2,3),(0.5,0,-0.5)) is valid) - see Axis for a complete description. A Plane is a coordinate system
defined by an origin, x_dir (X direction), y_dir (Y direction), and z_dir (Z direction). See Plane for a complete
description. Filtering by a Plane will return faces/edges parallel to it. SortBy and GeomType are python Enum class
described here:
GeomType
BEZIER, BSPLINE, CIRCLE, CONE, CYLINDER, ELLIPSE, EXTRUSION, HYPERBOLA, LINE, OFFSET,
OTHER, PARABOLA, PLANE, REVOLUTION, SPHERE, TORUS
SortBy
LENGTH, RADIUS, AREA, VOLUME, DISTANCE
ShapeList Class
The builders include methods to extract Edges, Faces, Solids, Vertices, or Wires from the objects they are building.
All of these methods return objects of a subclass of list, a ShapeList with custom filtering and sorting methods and
operations as follows.
The filter_by() method can take lambda expressions as part of a fluent chain of operations which enables integration
of custom filters into a larger change of selectors as shown in this example:
Here the two faces with “inner_wires” (i.e. holes) have been selected independent of orientation.
Example Workflow
Here is an example of using a Builder to create a simple part:
Key Concepts
• Incremental Construction: Builders allow you to build objects step-by-step, maintaining clarity and modularity.
• Dynamic Mode Switching: The mode parameter gives you precise control over how each operation modifies
the current total.
• Seamless Extraction: The Builder paradigm simplifies the retrieval of the final object, ensuring that you always
have access to the most up-to-date result.
1.4.2 Builders
The three builders, BuildLine, BuildSketch, and BuildPart are tools to create new objects - not the objects them-
selves. 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:
show_object(my_part.part)
show_object(my_sketch.sketch)
show_object(my_line.line)
Instead, build123d determines from the scope of the object or operation which builder it applies to thus eliminating the
need for the user to provide this information - as follows:
In this example, Box is in the scope of part_builder while Circle is in the scope of sketch_builder.
1.4.4 Workplanes
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, the first parameter(s) of the builders is a (sequence of) workplane(s) which
is (are) used to aid in the location of features. The default workplane in most cases is the Plane.XY 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.
When BuildPart is invoked it creates the workplane provided as a parameter (which has a default of the Plane.XY).
The bottom sketch is therefore created on the Plane.XY but with the normal reversed to point down. Subsequently
the user has created the vertical (Plane.XZ) sketch. 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.
As shown above, 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 are used to
define workplanes which are then used to position rotated boxes.
import build123d as bd
with BuildPart():
with Locations((0,10),(0,-10)):
Box(1,1,1)
(continues on next page)
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 context 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 contexts are creating Location objects not just simple points. The difference isn’t obvious until the
PolarLocations context is used which can also rotate objects within its scope - much as the hour and minute indicator
on an analogue clock.
Also note that the locations are local to the current location(s) - i.e. Locations can be nested. It’s easy for a user to
retrieve the global locations:
Location(p=(-0.50,-0.50,0.00), o=(0.00,-0.00,0.00))
Location(p=(-0.50,0.50,0.00), o=(0.00,-0.00,0.00))
Location(p=(0.50,-0.50,0.00), o=(0.00,-0.00,0.00))
Location(p=(0.50,0.50,0.00), o=(0.00,-0.00,0.00))
Location(p=(-0.50,-0.00,-0.50), o=(90.00,-0.00,0.00))
Location(p=(-0.50,0.00,0.50), o=(90.00,-0.00,0.00))
Location(p=(0.50,0.00,-0.50), o=(90.00,-0.00,0.00))
Location(p=(0.50,0.00,0.50), o=(90.00,-0.00,0.00))
def fillet(
objects: Union[Union[Edge, Vertex], Iterable[Union[Edge, Vertex]]],
radius: float,
):
To use this fillet operation, an edge or vertex or iterable of edges or vertices must be provided followed by a fillet radius
with or without the keyword as follows:
Here the fillet accepts the iterable ShapeList of edges from the last operation of the pipes builder and a radius is
provided as a keyword argument.
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.
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:
Hint
Experts Only
Locations 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.
BuildSketch exits after the fillet 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 would 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; however, one can see pending Edges and
Faces with <builder_instance>.pending_edges and <builder_instance>.pending_faces attributes. In the
above example, by adding a print(pillow_block.pending_faces) prior to the extrude(amount=thickness)
the pending Face from the BuildSketch will be displayed.
b = Box(1, 2, 3)
c = Cylinder(0.2, 5)
r = Box(1, 2, 3) + Cylinder(0.2, 5)
r = Box(1, 2, 3) - Cylinder(0.2, 5)
Notes:
• b, c and r are instances of class Compound and can be viewed with every viewer that can show build123d.
Compound objects.
• A discussion around performance can be found in Performance considerations in algebra mode.
• A mathematically formal definition of the algebra can be found in Algebraic definition.
plane * alg_compound
location * alg_compound
2. Placement on the plane and then moved relative to the plane by location (the location is relative to the local
coordinate system of the plane).
Plane.XY * Box(1, 2, 3)
Box(1, 2, 3)
Note: On the XY plane no placement is needed (mathematically Plane.XY * will not change the location of an
object).
• Box on the XY plane centered at (0, 1, 0) (all three are equivalent):
Pos(0, 1, 0) * Box(1, 2, 3)
Pos(Y=1) * Box(1, 2, 3)
Plane.XZ * Box(1, 2, 3)
• Box on plane Plane.XZ with a location (X=1, Y=2, Z=3) relative to the XZ plane, i.e., using the x-, y- and
z-axis of the XZ plane:
• Box on plane Plane.XZ moved to (X=1, Y=2, Z=3) relative to this plane and rotated there by the angles (X=0,
Y=100, Z=45) around Plane.XZ axes:
• Box on plane Plane.XZ rotated on this plane by the angles (X=0, Y=100, Z=45) (using the x-, y- and z-axis
of the XZ plane) and then moved to (X=1, Y=2, Z=3) relative to the XZ plane:
Note: In Python * binds stronger then +, -, &, hence brackets are not needed.
ò Note
The location(s) of an object must be defined prior to its creation when using builder mode.
Example:
Position
• Absolute Position: Set the position directly.
shape.position = (x, y, z)
shape.position += (x, y, z)
shape.position -= (x, y, z)
Orientation
• Absolute Orientation: Set the orientation directly.
shape.orientation = (X, Y, Z)
shape.orientation += (X, Y, Z)
shape.orientation -= (X, Y, Z)
Movement Methods
• Relative Move:
shape.move(Location)
relocated_shape = shape.moved(Location)
• Absolute Move:
shape.locate(Location)
relocated_shape = shape.located(Location)
ò Note
These methods don’t work in the same way as the previous methods in that they don’t just change the object’s
internal Location but transform the base object itself which is quite slow and potentially problematic.
relocated_shape = shape.translate(x, y, z)
Example Comparison
To illustrate the advantages of this approach, compare a simple model in OpenSCAD and build123d of a piece of angle
iron:
OpenSCAD Approach
// Dimensions
length = 100; // 10 cm long
width = 30; // 3 cm wide
thickness = 4; // 4 mm thick
fillet = 5; // 5 mm fillet radius
delta = 0.001; // a small number
}
}
build123d Approach
# Builder mode
with BuildPart() as angle_iron:
with BuildSketch() as profile:
Rectangle(3 * CM, 4 * MM, align=Align.MIN)
Rectangle(4 * MM, 3 * CM, align=Align.MIN)
extrude(amount=10 * CM)
fillet(angle_iron.edges().filter_by(lambda e: e.is_interior), 5 * MM)
# Algebra mode
profile = Rectangle(3 * CM, 4 * MM, align=Align.MIN)
profile += Rectangle(4 * MM, 3 * CM, align=Align.MIN)
angle_iron = extrude(profile, 10 * CM)
angle_iron = fillet(angle_iron.edges().filter_by(lambda e: e.is_interior), 5 * MM)
OpenSCAD and build123d offer distinct paradigms for creating 3D models, as demonstrated by the angle iron example.
OpenSCAD relies on Constructive Solid Geometry (CSG) operations, combining and subtracting 3D shapes like cubes
and cylinders. Fillets are approximated by manually adding high-resolution cylinders, making adjustments cumbersome
and less precise. This static approach can handle simple models but becomes challenging for complex or iterative
designs.
In contrast, build123d emphasizes a profile-driven workflow. It starts with a 2D sketch, defining the geometry’s outline,
which is then extruded or otherwise transformed into a 3D model. Features like fillets are applied dynamically by
querying topological elements, such as edges, using intuitive filtering methods. This approach ensures precision and
flexibility, making changes straightforward without the need for manual repositioning or realignment.
The build123d methodology is computationally efficient, leveraging mathematical precision for features like fillets.
By separating the design into manageable steps—sketching, extruding, and refining—it aligns with traditional CAD
practices and enhances readability, modularity, and maintainability. Unlike OpenSCAD, build123d’s dynamic querying
of topological features allows for easy updates and adjustments, making it better suited for modern, complex, and
iterative design workflows.
In summary, build123d’s sketch-based paradigm and topological querying capabilities provide superior precision, flex-
ibility, and efficiency compared to OpenSCAD’s static, CSG-centric approach, making it a better choice for robust and
adaptable CAD modeling.
1.7.5 Conclusion
While OpenSCAD and build123d share the goal of empowering users to create parametric 3D models, their approaches
differ significantly. Embracing build123d’s workflow of building with lower-dimensional objects and applying extru-
sion, lofting, sweeping, or revolution will unlock its full potential and lead to better design outcomes.
ò Note
Some important lines are omitted below to save space, so you will most likely need to add 1 & 2 to the provided
code below for them to work:
1. from build123d import *
List of Examples
• Introductory Examples
– 1. Simple Rectangular Plate
– 2. Plate with Hole
– 3. An extruded prismatic solid
– 4. Building Profiles using lines and arcs
– 5. Moving the current working point
– 6. Using Point Lists
– 7. Polygons
– 8. Polylines
– 9. Selectors, Fillets, and Chamfers
– 10. Select Last and Hole
– 11. Use a face as a plane for BuildSketch and introduce GridLocations
– 12. Defining an Edge with a Spline
– 13. CounterBoreHoles, CounterSinkHoles and PolarLocations
– 14. Position on a line with ‘@’, ‘%’ and introduce Sweep
– 15. Mirroring Symmetric Geometry
– 16. Mirroring 3D Objects
– 17. Mirroring From Faces
– 18. Creating Workplanes on Faces
– 19. Locating a workplane on a vertex
– 20. Offset Sketch Workplane
– 21. Create a Workplanes in the center of another shape
– 22. Rotated Workplanes
– 23. Revolve
– 24. Loft
– 25. Offset Sketch
– 26. Offset Part To Create Thin features
– 27. Splitting an Object
– 28. Locating features based on Faces
– 29. The Classic OCC Bottle
– 30. Bezier Curve
– 31. Nesting Locations
– 32. Python For-Loop
– 33. Python Function and For-Loop
– 34. Embossed and Debossed Text
– 35. Slots
– 36. Extrude Until
• Builder mode
length, width, thickness = 80.0, 60.0, 10.0
• Algebra mode
• Builder mode
In this case we are using Mode .SUBTRACT to cut the Cylinder from the Box.
length, width, thickness = 80.0, 60.0, 10.0
center_hole_dia = 22.0
• Algebra mode
In this case we are using the subtract operator - to cut the Cylinder from the Box.
• Builder mode
This time we can first create a 2D BuildSketch adding a Circle and a subtracted Rectangle` and
then use BuildPart’s extrude() feature.
• Algebra mode
This time we can first create a 2D Circle with a subtracted Rectangle` and then use the extrude()
operation for parts.
• Builder mode
BuildSketch operates on closed Faces, and the operation make_face() is used to convert the pend-
ing line segments from BuildLine into a closed Face.
• Algebra mode
We start with an empty Curve and add lines to it (note that Curve() + [line1, line2, line3]
is much more efficient than line1 + line2 + line3, see Performance considerations in algebra
mode). The operation make_face() is used to convert the line segments into a Face.
lines = Curve() + [
Line((0, 0), (length, 0)),
Line((length, 0), (length, width)),
ThreePointArc((length, width), (width, width * 1.5), (0.0, width)),
Line((0.0, width), (0, 0)),
]
sk4 = make_face(lines)
ex4 = extrude(sk4, thickness)
Note that to build a closed face it requires line segments that form a closed shape.
• Builder mode
Using Locations we can place one (or multiple) objects at one (or multiple) places.
• Algebra mode
Using the pattern Pos(x, y, z=0) * obj (with geometry.Pos) we can move an object to the pro-
vided position. Using Rot(x_angle, y_angle, z_angle) * obj (with geometry.Rot) would
rotate the object.
• Builder mode
You can use a list of points to construct multiple objects at once.
a, b, c = 80, 60, 10
• Algebra mode
You can use loops to iterate over these Locations or list comprehensions as in the example.
The algebra operations are vectorized, which means obj - [obj1, obj2, obj3] is short for obj
- obj1 - obj2 - ob3 (and more efficient, see Performance considerations in algebra mode).
a, b, c = 80, 60, 10
sk6 = [loc * Circle(c) for loc in Locations((b, 0), (0, b), (-b, 0), (0, -
˓→b))]
1.8.7 7. Polygons
• Builder mode
You can create RegularPolygon for each stack point if you would like.
a, b, c = 60, 80, 5
• Algebra mode
You can apply locations to RegularPolygon instances for each location via loops or list comprehen-
sions.
a, b, c = 60, 80, 5
polygons = [
loc * RegularPolygon(radius=2 * c, side_count=6)
for loc in Locations((0, 3 * c), (0, -3 * c))
]
sk7 = Rectangle(a, b) - polygons
ex7 = extrude(sk7, amount=c)
1.8.8 8. Polylines
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 mirror() ed to create the final profile.
• Builder mode
• Algebra mode
ln = Polyline(pts)
ln += mirror(ln, Plane.YZ)
• Builder mode
• Algebra mode
Note that group_by() (Axis.Z) returns a list of lists of edges that is grouped by their z-position. In this case we want
to use the [-1] group which, by convention, will be the highest z-dimension group.
• Builder mode
Using Select .LAST you can select the most recently modified edges. It is used to perform a
fillet() in this example. This example also makes use of Hole which automatically cuts through
the entire part.
• Algebra mode
Using the pattern snapshot = obj.edges() before and last_edges = obj.edges() -
snapshot after an operation allows to select the most recently modified edges (same for faces,
vertices, . . . ). It is used to perform a fillet() in this example. This example also makes use of
Hole. Different to the context mode, you have to add the depth of the whole.
snapshot = ex10.edges()
ex10 -= Hole(radius=width / 4, depth=thickness)
last_edges = ex10.edges() - snapshot
ex10 = fillet(last_edges.group_by(Axis.Z)[-1], 2)
1.8.11 11. Use a face as a plane for BuildSketch and introduce GridLocations
• Builder mode
BuildSketch accepts a Plane or a Face, so in this case we locate the Sketch on the top of the part.
Note that the face used as input to BuildSketch needs to be Planar or unpredictable behavior can result.
Additionally GridLocations can be used to create a grid of points that are simultaneously used to
place 4 pentagons.
Lastly, extrude() can be used with a negative amount and Mode.SUBTRACT to cut these from the
parent.
• Algebra mode
The pattern plane * obj can be used to locate an object on a plane. Furthermore, the pattern plane
* location * obj first places the object on a plane and then moves it relative to plane according
to location.
GridLocations creates a grid of points that can be used in loops or list comprehensions as described
earlier.
Lastly, extrude() can be used with a negative amount and cut (-) from the parent.
plane = Plane(ex11.faces().sort_by().last)
polygons = Sketch() + [
plane * loc * RegularPolygon(radius=5, side_count=5)
for loc in GridLocations(length / 2, width / 2, 2, 2)
]
ex11 -= extrude(polygons, -thickness)
Note that the direction implied by positive or negative inputs to amount is relative to the normal direction of the face
or plane. As a result of this, unexpected behavior can occur if the extrude direction and mode/operation (ADD / + or
SUBTRACT / -) are not correctly set.
• Builder mode
pts = [
(55, 30),
(50, 35),
(40, 30),
(30, 20),
(20, 25),
(10, 20),
(0, 20),
]
• Algebra mode
pts = [
(55, 30),
(50, 35),
(40, 30),
(30, 20),
(20, 25),
(10, 20),
(0, 20),
]
l1 = Spline(pts)
(continues on next page)
• Builder mode
We use a face to establish a location for Locations.
a, b = 40, 4
with BuildPart() as ex13:
Cylinder(radius=50, height=10)
with Locations(ex13.faces().sort_by(Axis.Z)[-1]):
with PolarLocations(radius=a, count=4):
CounterSinkHole(radius=b, counter_sink_radius=2 * b)
with PolarLocations(radius=a, count=4, start_angle=45, angular_
˓→range=360):
• Algebra mode
We use a face to establish a plane that is used later in the code for locating objects onto this plane.
a, b = 40, 4
ex13 -= (
plane
* PolarLocations(radius=a, count=4)
* CounterSinkHole(radius=b, counter_sink_radius=2 * b, depth=10)
)
ex13 -= (
plane
* PolarLocations(radius=a, count=4, start_angle=45, angular_range=360)
* CounterBoreHole(
radius=b, counter_bore_radius=2 * b, depth=10, counter_bore_depth=b
)
)
1.8.14 14. Position on a line with ‘@’, ‘%’ and introduce Sweep
build123d includes a feature for finding the position along a line segment. This is normalized between 0 and 1 and
can be accessed using the position_at() (@) operator. Similarly the tangent_at() (%) operator returns the line
direction at a given point.
These two features are very powerful for chaining line segments together without having to repeat dimensions again
and again, which is error prone, time consuming, and more difficult to maintain. The pending faces must lie on the
path, please see example 37 for a way to make this placement easier.
• Builder mode
The sweep() method takes any pending faces and sweeps them through the provided path (in this case
the path is taken from the pending edges from ex14_ln). revolve() requires a single connected
wire.
a, b = 40, 20
• Algebra mode
The sweep() method takes any faces and sweeps them through the provided path (in this case the
path is taken from ex14_ln).
a, b = 40, 20
It is also possible to use tuple or Vector addition (and other vector math operations) as seen in the l3 variable.
• Builder mode
a, b, c = 80, 40, 20
• Algebra mode
Combine lines via the pattern Curve() + [l1, l2, l3, l4, l5]
a, b, c = 80, 40, 20
sk15 = make_face(ln)
ex15 = extrude(sk15, c)
• Builder mode
extrude(amount=length)
• Algebra mode
planes = [
Plane.XY.offset(width),
Plane.YX.offset(width),
Plane.YZ.offset(width),
Plane.YZ.offset(-width),
]
objs = [mirror(ex16_single, plane) for plane in planes]
ex16 = ex16_single + objs
• Builder mode
a, b = 30, 20
• Algebra mode
a, b = 30, 20
• Builder mode
We then use Mode.SUBTRACT to cut it out from the main body.
• Algebra mode
We then use -= to cut it out from the main body.
• Builder mode
Then the X and Y positions of these vertices are selected and passed to Locations as center points
for two circles that cut through the main part. Note that if you passed the variable vtx directly to
Locations then the part would be offset from the workplane by the vertex z-position.
• Algebra mode
Then the X and Y positions of these vertices are selected and used to move two circles that cut through
the main part. Note that if you passed the variable vtx directly to Pos then the part would be offset
from the workplane by the vertex z-position.
topf = ex19.faces().sort_by().last
vtx = topf.vertices().group_by(Axis.X)[-1][0]
ex19_sk2 = Circle(radius=length / 8)
ex19_sk2 = Pos(vtx.X, vtx.Y) * ex19_sk2 + Pos(vtx2.X, vtx2.Y) * ex19_sk2
• Builder mode
• Algebra mode
• Builder mode
• Algebra mode
• Builder mode
Use the rotated() method to rotate the workplane.
• Algebra mode
Use the operator * to relocate the plane (post-multiplication!).
holes = Sketch() + [
plane * loc * Circle(thickness / 4)
for loc in GridLocations(length / 4, width / 4, 2, 2)
]
ex22 -= extrude(holes, -100, both=True)
GridLocations places 4 Circles on 4 points on this rotated workplane, and then the Circles are extruded in the “both”
(positive and negative) normal direction.
• Builder mode
pts = [
(-25, 35),
(-25, 0),
(-20, 0),
(-20, 5),
(-15, 10),
(-15, 35),
]
• Algebra mode
pts = [
(-25, 35),
(-25, 0),
(-20, 0),
(-20, 5),
(-15, 10),
(-15, 35),
(continues on next page)
l1 = Polyline(pts)
l2 = Line(l1 @ 1, l1 @ 0)
sk23 = make_face([l1, l2])
• Builder mode
• Algebra mode
faces = Sketch() + [
plane * Circle(length / 3),
plane.offset(length / 2) * Rectangle(length / 6, width / 6),
]
ex24 += loft(faces)
• Builder mode
BuildSketch faces can be transformed with a 2D offset().
• Algebra mode
Sketch faces can be transformed with a 2D offset().
They can be offset inwards or outwards, and with different techniques for extending the corners (see Kind in the Offset
docs).
• Builder mode
• Algebra mode
• Builder mode
• Algebra mode
• Builder mode
We create a triangular prism with Mode .PRIVATE and then later use the faces of this object to cut
holes in a sphere.
• Algebra mode
We create a triangular prism and then later use the faces of this object to cut holes in a sphere.
We are able to create multiple workplanes by looping over the list of faces.
• Builder mode
• Algebra mode
• Builder mode
pts = [
(0, 0),
(20, 20),
(40, 0),
(0, -40),
(-60, 0),
(0, 100),
(100, 0),
]
wts = [
1.0,
1.0,
2.0,
3.0,
4.0,
2.0,
1.0,
]
• Algebra mode
pts = [
(0, 0),
(20, 20),
(40, 0),
(0, -40),
(-60, 0),
(0, 100),
(100, 0),
]
wts = [
(continues on next page)
• Builder mode
• Algebra mode
)
ex31 = extrude(ex31, 3)
• Builder mode
Mode .PRIVATE is used in BuildSketch to avoid adding these faces until the for-loop.
• Algebra mode
• Builder mode
The function returns a BuildSketch .
• Algebra mode
The function returns a Sketch object.
ex33 = Part() + [
extrude(square(b + 2 * i, loc), c + 2 * i)
for i, loc in enumerate(PolarLocations(a / 2, 6))
]
• Builder mode
The text “Hello” is placed on top of a rectangle and embossed (raised) by placing a BuildSketch on
the top face (topf). Note that Align is used to control the text placement. We re-use the topf
variable to select the same face and deboss (indented) the text “World”. Note that if we simply ran
BuildSketch(ex34.faces().sort_by(Axis.Z)[-1]) for both ex34_sk1 & 2 it would incor-
rectly locate the 2nd “World” text on the top of the “Hello” text.
length, width, thickness, fontsz, fontht = 80.0, 60.0, 10.0, 25.0, 4.0
• Algebra mode
The text “Hello” is placed on top of a rectangle and embossed (raised) by placing a sketch on the top
face (topf). Note that Align is used to control the text placement. We re-use the topf variable to
select the same face and deboss (indented) the text “World”.
length, width, thickness, fontsz, fontht = 80.0, 60.0, 10.0, 25.0, 4.0
• Builder mode
Here we create a SlotCenterToCenter and then use a BuildLine and RadiusArc to create an arc
for two instances of SlotArc.
• Algebra mode
Here we create a SlotCenterToCenter and then use a RadiusArc to create an arc for two instances
of SlotArc.
• Builder mode
rad, rev = 6, 50
• Algebra mode
rad, rev = 6, 50
1.9 Tutorials
There are several tutorials to help guide uses through the concepts of build123d in a step by step way. Working through
these tutorials in order is recommended as later tutorials build on the concepts introduced in earlier ones.
1.9. Tutorials 55
build123d, Release 0.9.2.dev67+gbde03f4
1.9. Tutorials 57
build123d, Release 0.9.2.dev67+gbde03f4
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.
In this example, we’ve wrapped the sketch within a BuildPart context, which is used for creating 3D parts. We utilized
the extrude function to extend the 2D sketch into a solid object, turning it into a 3D part. Additionally, we applied the
mirror function to replicate the partial part across a plane of symmetry, ensuring a symmetrical design.
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.
1.9. Tutorials 59
build123d, Release 0.9.2.dev67+gbde03f4
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 essen-
tially 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 (fil-
let_radius). The fillet smooths the sharp edges at the corners, giving the part a more refined shape.
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)
• 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 connec-
tion to other parts.
thickness = 3 * MM
width = 25 * MM
length = 50 * MM
height = 25 * MM
hole_diameter = 5 * MM
bend_radius = 5 * MM
fillet_radius = 2 * MM
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:
thickness = 3 * MM
width = 25 * MM
length = 50 * MM
(continues on next page)
1.9. Tutorials 61
build123d, Release 0.9.2.dev67+gbde03f4
show_all()
ò Note
One can see any object in the following tutorial by using the ocp_vscode (or any other supported viewer) by using
the show(object_to_be_viewed) command. Alternatively, the show_all() command will display all objects
that have been assigned an identifier.
1.9. Tutorials 63
build123d, Release 0.9.2.dev67+gbde03f4
Step 1: Setup
Before getting to the CAD operations, this selector script needs to import the build123d environment.
Here we’re using selectors to find that top Face - let’s break down example.faces().sort_by(Axis.Z)[-1]:
The first sub-step is the extraction of all of the Faces from the part that we’re building. The BuildPart instance was
assigned the identifier example so example.faces() will extract all of the Faces from that part into a custom python
list - a ShapeList.
The next sub-step is to sort the ShapeList of Faces by their position with respect to the Z Axis. The sort_by method
will sort the list by relative position of the object’s center to the Axis.Z and [-1] selects the last item on that list - or
return the top Face of the example part.
We’ll create a hexagon with the use of RegularPolygon object with six sides.
To create the hole we’ll subtract a Circle from the sketch by using mode=Mode.SUBTRACT. The sketch now described
the hexagonal hole that we want to make in the Cylinder.
Note that amount=-2 indicates extruding into the part and - just like with the sketch - mode=Mode.SUBTRACT instructs
the builder to subtract this hexagonal shape from the part under construction.
At this point the part looks like:
1.9. Tutorials 65
build123d, Release 0.9.2.dev67+gbde03f4
show(example)
Here we’re using the fillet() operation which needs two things: the edge(s) to fillet and the radius of the fillet. To
provide the edge, we’ll use more selectors as described in the following sub-steps.
Much like selecting Faces in Step 3a, we’ll select all of the example part’s edges with example.edges().
Since we know that the edge we’re looking for is a circle, we can filter the edges selected in Step 6a for just those that
are of geometric type CIRCLE with example.edges().filter_by(GeomType.CIRCLE). This step removes all of
the Edges of the hexagon hole.
The perimeter are the largest circles - the central cylinder must be excluded - so we’ll sort all of the circles by their
radius with: example.edges().filter_by(GeomType.CIRCLE).sort_by(SortBy.RADIUS).
We know that the example part has two perimeter circles so we’ll select just the top two edges from the sorted circle
list with: example.edges().filter_by(GeomType.CIRCLE).sort_by(SortBy.RADIUS)[-2:]. The syntax of
this slicing operation is standard python list slicing.
The last sub-step is to select the top perimeter edge, the one with the greatest Z value which we’ll do with the
sort_by(Axis.Z)[-1] method just like Step 3b - note that these methods work on all Shape objects (Edges, Wires,
Faces, Solids, and Compounds) - with: example.edges().filter_by(GeomType.CIRCLE).sort_by(SortBy.
RADIUS)[-2:].sort_by(Axis.Z)[-1].
Conclusion
By using selectors as we have in this example we’ve used methods of identifying features that are robust to features
changing within the part. We’ve also avoided the classic CAD “Topological naming problem” by never referring to
features with names or tags that could become obsolete as the part changes.
When possible, avoid using static list indices to refer to features extracted from methods like edges() as the order
within the list is not guaranteed to remain the same.
Step 1: Setup
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 a from build123d import * but there are other
options that we won’t explore here.
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.
lego_unit_size = 8
pip_height = 1.8
pip_diameter = 4.8
block_length = lego_unit_size * pip_count
block_width = 16
base_height = 9.6
block_height = base_height + pip_height
support_outer_diameter = 6.5
support_inner_diameter = 4.8
ridge_width = 0.6
ridge_depth = 0.3
wall_thickness = 1.2
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.
1.9. Tutorials 67
build123d, Release 0.9.2.dev67+gbde03f4
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:
Here we can see that the first GridLocations creates two positions which causes two horizontal rectangles to be cre-
ated. 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 Rectangle is subtracted from the sketch to leave the ridges as follows:
1.9. Tutorials 69
build123d, Release 0.9.2.dev67+gbde03f4
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:
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:
1.9. Tutorials 71
build123d, Release 0.9.2.dev67+gbde03f4
To position the top, we’ll describe the top center of the lego walls with a Locations context. 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 sort_by(Axis.Z)[-1]. Finally, the Z property of this vertex will return just the height of the top. Note
that the X and Y values are not used from the selected vertex as there are no vertices in the center of the block.
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:
In this case, the workplane is created from the top Face of the Lego block by using the faces method and then sorted
vertically and taking the top one sort_by(Axis.Z)[-1].
On the new workplane, a grid of locations is created and a number of Cylinder’s are positioned at each location.
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.
ò Note
Viewers that don’t directly support build123d my require a raw OpenCascade object. In this case, append .wrapped
to the object (e.g.) show_object(lego.part.wrapped).
1.9. Tutorials 73
build123d, Release 0.9.2.dev67+gbde03f4
Step 1: Setup
Before getting to the CAD operations, this selector script needs to import the build123d environment.
class Hinge(Compound):
"""Hinge
Args:
width (float): width of one leaf
length (float): hinge length
barrel_diameter (float): size of hinge pin barrel
thickness (float): hinge leaf thickness
pin_diameter (float): hinge pin diameter
inner (bool, optional): inner or outer half of hinge . Defaults to True.
"""
def __init__(
self,
width: float,
length: float,
barrel_diameter: float,
thickness: float,
pin_diameter: float,
inner: bool = True,
):
# The profile of the hinge used to create the tabs
with BuildPart() as hinge_profile:
with BuildSketch():
for i, loc in enumerate(
GridLocations(0, length / 5, 1, 5, align=(Align.MIN, Align.MIN))
):
if i % 2 == inner:
with Locations(loc):
Rectangle(width, length / 5, align=(Align.MIN, Align.MIN))
Rectangle(
width - barrel_diameter,
length,
align=(Align.MIN, Align.MIN),
(continues on next page)
1.9. Tutorials 75
build123d, Release 0.9.2.dev67+gbde03f4
Once the two leaves have been created they will look as follows:
Note that the XYZ indicators and a circle around the hinge pin indicate joints that are discussed below.
The first joint to add is a RigidJoint that is used to fix the hinge leaf to the box or lid.
#
# Leaf attachment
RigidJoint(
label="leaf",
joint_location=Location(
(width - barrel_diameter, 0, length / 2), (90, 0, 0)
),
)
Each joint has a label which identifies it - here the string “leaf” is used, the to_part binds the joint to leaf_builder.
part (i.e. the part being built), and joint_location is specified as middle of the leaf along the edge of the pin. Note
that Location objects describe both a position and orientation which is why there are two tuples (the orientation listed
is rotate about the X axis 90 degrees).
The second joint to add is either a RigidJoint (on the inner leaf) or a RevoluteJoint (on the outer leaf) that describes
the hinge axis.
#
# Leaf attachment
RigidJoint(
label="leaf",
joint_location=Location(
(width - barrel_diameter, 0, length / 2), (90, 0, 0)
),
)
# [Hinge Axis] (fixed with inner)
(continues on next page)
The inner leaf just pivots around the outer leaf and therefore the simple RigidJoint is used to define the Location of
this pivot. The outer leaf contains the more complex RevoluteJoint which defines an axis of rotation and angular
limits to that rotation (90 and 270 in this example as the two leaves will interfere with each other outside of this range).
Note that the maximum angle must be greater than the minimum angle and therefore may be greater than 360°. Other
types of joints have linear ranges as well as angular ranges.
The third set of joints to add are CylindricalJoint’s that describe how the countersunk screws used to attach the
leaves move.
Much like the RevoluteJoint, a CylindricalJoint has an Axis of motion but this type of joint allows both move-
ment around and along this axis - exactly as a screw would move. Here is the Axis is setup such that a position of
0 aligns with the screw being fully set in the hole and positive numbers indicate the distance the head of the screw
is above the leaf surface. One could have reversed the direction of the Axis such that negative position values would
correspond to a screw now fully in the hole - whatever makes sense to the situation. The angular range of this joint is
set to (0°, 360°) as there is no limit to the angular rotation of the screw (one could choose to model thread pitch and
calculate position from angle or vice-versa).
To finish off, the base class for the Hinge class is initialized:
super().__init__(leaf_builder.part.wrapped, joints=leaf_builder.part.joints)
1.9. Tutorials 77
build123d, Release 0.9.2.dev67+gbde03f4
Now that the Hinge class is complete it can be used to instantiate the two hinge leaves required to attach the box and
lid together.
hinge_inner = Hinge(
width=5 * CM,
length=12 * CM,
barrel_diameter=1 * CM,
thickness=2 * MM,
pin_diameter=4 * MM,
)
hinge_outer = Hinge(
width=5 * CM,
length=12 * CM,
barrel_diameter=1 * CM,
thickness=2 * MM,
pin_diameter=4 * MM,
inner=False,
)
Since the hinge will be fixed to the box another RigidJoint is used mark where the hinge will go. Note that the
orientation of this Joint will control how the hinge leaf is attached and is independent of the orientation of the hinge
as it was constructed.
Note that the position and orientation of the box’s joints are given as a global Location when created but will be
translated to a relative Location internally to allow the Joint to “move” with the parent object. This allows users the
freedom to relocate objects without having to recreate or modify Joint’s. Here is the box is moved upwards to show
this property.
Again, the original orientation of the lid and hinge inner leaf are not important, when the joints are connected together
the parts will move into the correct position.
m6_screw = import_step("M6-1x12-countersunk-screw.step")
m6_joint = RigidJoint("head", m6_screw, Location((0, 0, 0), (0, 0, 0)))
Here a simple RigidJoint is bound to the top of the screw head such that it can be connected to the hinge’s
CylindricalJoint.
To start, the outer hinge leaf will be connected to the box, as follows:
box.joints["hinge_attachment"].connect_to(hinge_outer.joints["leaf"])
1.9. Tutorials 79
build123d, Release 0.9.2.dev67+gbde03f4
Here the hinge_attachment joint of the box is connected to the leaf joint of hinge_outer. Note that the hinge
leaf is the object to move. Once this line is executed, we get the following:
Next, the hinge inner leaf is connected to the hinge outer leaf which is attached to the box.
hinge_outer.joints["hinge_axis"].connect_to(hinge_inner.joints["hinge_axis"], angle=120)
hinge_inner.joints["leaf"].connect_to(lid.joints["hinge_attachment"])
Note how the lid is now in an open position. To close the lid just change the above angle parameter from 120° to 90°.
The last step in this example is to place a screw in one of the hinges:
As the position is a positive number the screw is still proud of the hinge face as shown here:
Try changing these position and angle values to “tighten” the screw.
Conclusion
Use a Joint to locate two objects relative to each other with some degree of motion. Keep in mind that when using
the connect_to method, self is always fixed and other will move to the appropriate Location.
ò Note
The joint symbols can be displayed as follows (your viewer may use show instead of show_object):
show_object(box.joints["hinge_attachment"].symbol, name="box attachment point")
or
show_object(m6_joint.symbol, name="m6 screw symbol")
1.9. Tutorials 81
build123d, Release 0.9.2.dev67+gbde03f4
Benchy Benchy
Canadian Flag Blowing in The Wind Canadian Flag Blowing in The Wind
1.9. Tutorials 83
build123d, Release 0.9.2.dev67+gbde03f4
1.9. Tutorials 85
build123d, Release 0.9.2.dev67+gbde03f4
Handle Handle
1.9. Tutorials 87
build123d, Release 0.9.2.dev67+gbde03f4
1.9. Tutorials 89
build123d, Release 0.9.2.dev67+gbde03f4
1.9. Tutorials 91
build123d, Release 0.9.2.dev67+gbde03f4
1.9. Tutorials 93
build123d, Release 0.9.2.dev67+gbde03f4
1.9. Tutorials 95
build123d, Release 0.9.2.dev67+gbde03f4
1.9. Tutorials 97
build123d, Release 0.9.2.dev67+gbde03f4
Benchy
The Benchy examples shows how to import a STL model as a Solid object with the class Mesher and modify it by
replacing chimney with a BREP version.
• Benchy STL model: low_poly_benchy.stl
Gallery
1.9. Tutorials 99
build123d, Release 0.9.2.dev67+gbde03f4
show(benchy)
This example creates the former build123d logo (new logo was created in the end of 2023).
Using text and lines to create the first build123d logo. The builder mode example also generates the SVG file logo.svg.
if True:
logo = Compound(
children=[
one.line,
two.sketch,
three_d.part,
extension_lines.line,
build.sketch,
]
)
# logo.export_step("logo.step")
def add_svg_shape(svg: ExportSVG, shape: Shape, color: tuple[float, float, float]):
global counter
try:
counter += 1
except:
counter = 1
svg = ExportSVG(scale=20)
add_svg_shape(svg, logo, None)
# add_svg_shape(svg, Compound(children=[one.line, extension_lines.line]), None)
# add_svg_shape(svg, Compound(children=[two.sketch, build.sketch]), (170, 204, 255))
# add_svg_shape(svg, three_d.part, (85, 153, 255))
svg.write("logo.svg")
show_object(one, name="one")
show_object(two, name="two")
show_object(three_d, name="three_d")
show_object(extension_lines, name="extension_lines")
show_object(build, name="build")
show_object(cmpd, name="compound")
A Canadian Flag blowing in the wind created by projecting planar faces onto a non-planar face (the_wind).
This example also demonstrates building complex lines that snap to existing features.
More Images
# Note that the surface to project on must be a little larger than the faces
# being projected onto it to create valid projected faces
the_wind = Face.make_surface_from_array_of_points(
[
[
Vector(
width * (v * 1.1 / 40 - 0.05),
height * (u * 1.2 / 40 - 0.1),
height * surface(wave_amplitude, u / 40, v / 40) / 2,
)
for u in range(41)
]
for v in range(41)
]
)
with BuildSketch(Plane.XY.offset(10)) as west_field_builder:
Rectangle(width / 4, height, align=(Align.MIN, Align.MIN))
west_field_planar = west_field_builder.sketch.faces()[0]
east_field_planar = west_field_planar.mirror(Plane.YZ.offset(width / 2))
# Note that the surface to project on must be a little larger than the faces
# being projected onto it to create valid projected faces
the_wind = Face.make_surface_from_array_of_points(
[
[
Vector(
width * (v * 1.1 / 40 - 0.05),
height * (u * 1.2 / 40 - 0.1),
height * surface(wave_amplitude, u / 40, v / 40) / 2,
)
for u in range(41)
]
for v in range(41)
]
)
outline = l1 + [l2, r1, l3, r2, l4, r3, l5, r4, l6, s, l7, r5]
outline += mirror(outline, Plane.YZ)
maple_leaf_planar = make_face(outline)
center_field_planar = (
Rectangle(1, 1, align=(Align.CENTER, Align.MIN)) - maple_leaf_planar
)
def scale_move(obj):
return Plane((width / 2, 0, 10)) * scale(obj, height)
def project(obj):
return obj.faces()[0].project_to_shape(the_wind, (0, 0, -1))[0]
maple_leaf_planar = scale_move(maple_leaf_planar)
center_field_planar = scale_move(center_field_planar)
west_field = project(west_field_planar)
west_field.color = Color("red")
east_field = project(east_field_planar)
east_field.color = Color("red")
center_field = project(center_field_planar)
center_field.color = Color("white")
maple_leaf = project(maple_leaf_planar)
maple_leaf.color = Color("red")
More Images
show_object(pcb.part.wrapped)
show(pcb)
Clock Face
clock_radius = 10
with BuildSketch() as minute_indicator:
with BuildLine() as outline:
l1 = CenterArc((0, 0), clock_radius * 0.975, 0.75, 4.5)
l2 = CenterArc((0, 0), clock_radius * 0.925, 0.75, 4.5)
Line(l1 @ 0, l2 @ 0)
Line(l1 @ 1, l2 @ 1)
make_face()
fillet(minute_indicator.vertices(), radius=clock_radius * 0.01)
show(clock_face)
clock_radius = 10
clock_face = Circle(clock_radius)
clock_face -= PolarLocations(0, 60) * minute_indicator
clock_face -= PolarLocations(clock_radius * 0.875, 12) * SlotOverall(
clock_radius * 0.05, clock_radius * 0.025
)
(continues on next page)
clock_face -= [
loc
* Text(
str(hour + 1),
font_size=clock_radius * 0.175,
font_style=FontStyle.BOLD,
align=Align.CENTER,
)
for hour, loc in enumerate(
PolarLocations(clock_radius * 0.75, 12, 60, -360, rotate=False)
)
]
show(clock_face)
The Python code utilizes the build123d library to create a 3D model of a clock face. It defines a minute indicator with
arcs and lines, applying fillets, and then integrates it into the clock face sketch. The clock face includes a circular outline,
hour labels, and slots at specified positions. The resulting 3D model represents a detailed and visually appealing clock
design.
PolarLocations are used to position features on the clock face.
Handle
segment_count = 6
show_object(handle_center_line.line, name="handle_center_line")
for i, section in enumerate(sections):
show_object(section, name="section" + str(i))
show_object(handle.part, name="handle", options=dict(alpha=0.6))
segment_count = 6
# Create a path for the sweep along the handle - added to pending_edges
handle_center_line = Spline(
(-10, 0, 0),
(0, 0, 5),
(10, 0, 0),
tangents=((0, 0, 1), (0, 0, -1)),
tangent_scalars=(1.5, 1.5),
)
show_object(handle_center_line, name="handle_path")
for i, circle in enumerate(sections):
show_object(circle, name="section" + str(i))
show_object(handle, name="handle", options=dict(alpha=0.6))
Heat Exchanger
exchanger_diameter = 10 * CM
exchanger_length = 30 * CM
plate_thickness = 5 * MM
# 149 tubes
tube_diameter = 5 * MM
tube_spacing = 2 * MM
tube_wall_thickness = 0.5 * MM
tube_extension = 3 * MM
bundle_diameter = exchanger_diameter - 2 * tube_diameter
fillet_radius = tube_spacing / 3
assert tube_extension > fillet_radius
show(heat_exchanger)
exchanger_diameter = 10 * CM
exchanger_length = 30 * CM
plate_thickness = 5 * MM
# 149 tubes
tube_diameter = 5 * MM
tube_spacing = 2 * MM
tube_wall_thickness = 0.5 * MM
tube_extension = 3 * MM
bundle_diameter = exchanger_diameter - 2 * tube_diameter
fillet_radius = tube_spacing / 3
assert tube_extension > fillet_radius
plate_plane = Plane(
origin=(0, 0, exchanger_length / 2 - tube_extension - plate_thickness),
z_dir=(0, 0, 1),
)
plate = Circle(radius=exchanger_diameter / 2) - tube_locations * Circle(
radius=tube_diameter / 2 - tube_wall_thickness
)
(continues on next page)
show(heat_exchanger)
This example creates a model of a parametric heat exchanger core. The positions of the tubes are defined with
HexLocations and further limited to fit within the circular end caps. The ends of the tubes are filleted to the end
plates to simulate welding.
Key Cap
show(key_cap, alphas=[0.3])
# Taper Extrude and Extrude to "next" while creating a Cherry MX key cap
# See: https://www.cherrymx.de/en/dev.html
show(key_cap, alphas=[0.3])
This example demonstrates the design of a Cherry MX key cap by using extrude with a taper and extrude until next.
Maker Coin
This example creates the maker coin as defined by Angus on the Maker’s Muse YouTube channel. There are two key
features:
1. the use of DoubleTangentArc to create a smooth transition from the central dish to the outside arc, and
2. embossing the text into the top of the coin not just as a simple extrude but from a projection which results in text
with even depth.
# Coin Parameters
diameter, thickness = 50 * MM, 10 * MM
show(maker_coin)
Multi-Sketch Loft
This example demonstrates lofting a set of sketches, selecting the top and bottom by type, and shelling.
want = 1306.3405290344635
got = art.part.volume
delta = abs(got - want)
tolerance = want * 1e-5
assert delta < tolerance, f"{delta=} is greater than {tolerance=}; {got=}, {want=}"
show(art, names=["art"])
slice_count = 10
art = Sketch()
for i in range(slice_count + 1):
plane = Plane(origin=(0, 0, i * 3), z_dir=(0, 0, 1))
art += plane * Circle(10 * sin(i * pi / slice_count) + 5)
art = loft(art)
top_bottom = art.faces().filter_by(GeomType.PLANE)
art = offset(art, openings=top_bottom, amount=0.5)
show(art, names=["art"])
This script creates a a J-shaped pegboard hook. These hooks are commonly used for organizing tools in garages,
workshops, or other spaces where tools and equipment need to be stored neatly and accessibly. The hook is created by
defining a complex path and then sweeping it to define the hook. The sides of the hook are flattened to aid 3D printing.
show(mainp)
show(mainp)
Platonic Solids
class PlatonicSolid(BasePartObject):
"""Part Object: Platonic Solid
Args:
face_count (Literal[4,6,8,12,20]): number of faces
diameter (float): double distance to vertices, i.e. maximum size
rotation (RotationLike, optional): angles to rotate about axes. Defaults to (0,␣
˓→0, 0).
tetrahedron_vertices = [(1, 1, 1), (1, -1, -1), (-1, 1, -1), (-1, -1, 1)]
octahedron_vertices = (
[(i, 0, 0) for i in [-1, 1]]
+ [(0, i, 0) for i in [-1, 1]]
+ [(0, 0, i) for i in [-1, 1]]
)
dodecahedron_vertices = (
[(i, j, k) for i in [-1, 1] for j in [-1, 1] for k in [-1, 1]]
+ [(0, i / PHI, j * PHI) for i in [-1, 1] for j in [-1, 1]]
+ [(i / PHI, j * PHI, 0) for i in [-1, 1] for j in [-1, 1]]
+ [(i * PHI, 0, j / PHI) for i in [-1, 1] for j in [-1, 1]]
)
icosahedron_vertices = (
[(0, i, j * PHI) for i in [-1, 1] for j in [-1, 1]]
+ [(i, j * PHI, 0) for i in [-1, 1] for j in [-1, 1]]
+ [(i * PHI, 0, j) for i in [-1, 1] for j in [-1, 1]]
)
vertices_lookup = {
4: tetrahedron_vertices,
(continues on next page)
def __init__(
self,
face_count: Literal[4, 6, 8, 12, 20],
diameter: float = 1.0,
rotation: RotationLike = (0, 0, 0),
align: Union[None, Align, tuple[Align, Align, Align]] = None,
mode: Mode = Mode.ADD,
):
try:
platonic_vertices = PlatonicSolid.vertices_lookup[face_count]
except KeyError:
raise ValueError(
f"face_count must be one of 4, 6, 8, 12, or 20 not {face_count}"
)
# By definition, all vertices are the same distance from the origin so
# scale proportionally to this distance
platonic_solid = platonic_solid.scale(
(diameter / 2) / Vector(platonic_solid.vertices()[0]).length
)
solids = [
Rot(0, 0, 72 * i) * Pos(1, 0, 0) * PlatonicSolid(faces)
for i, faces in enumerate([4, 6, 8, 12, 20])
]
show(solids)
Playing Cards
This example creates a customs Sketch objects: Club, Spade, Heart, Diamond, and PlayingCard in addition to a two
part playing card box which has suit cutouts in the lid. The four suits are created with Bézier curves that were imported
as code from an SVG file and modified to the code found here.
# [Club]
class Club(BaseSketchObject):
def __init__(
self,
height: float,
rotation: float = 0,
align: tuple[Align, Align] = (Align.CENTER, Align.CENTER),
mode: Mode = Mode.ADD,
):
with BuildSketch() as club:
with BuildLine():
l0 = Line((0, -188), (76, -188))
b0 = Bezier(l0 @ 1, (61, -185), (33, -173), (17, -81))
b1 = Bezier(b0 @ 1, (49, -128), (146, -145), (167, -67))
b2 = Bezier(b1 @ 1, (187, 9), (94, 52), (32, 18))
b3 = Bezier(b2 @ 1, (92, 57), (113, 188), (0, 188))
mirror(about=Plane.YZ)
make_face()
scale(by=height / club.sketch.bounding_box().size.Y)
super().__init__(obj=club.sketch, rotation=rotation, align=align, mode=mode)
# [Club]
class Spade(BaseSketchObject):
def __init__(
self,
height: float,
rotation: float = 0,
align: tuple[Align, Align] = (Align.CENTER, Align.CENTER),
mode: Mode = Mode.ADD,
):
with BuildSketch() as spade:
with BuildLine():
b0 = Bezier((0, 198), (6, 190), (41, 127), (112, 61))
b1 = Bezier(b0 @ 1, (242, -72), (114, -168), (11, -105))
b2 = Bezier(b1 @ 1, (31, -174), (42, -179), (53, -198))
l0 = Line(b2 @ 1, (0, -198))
mirror(about=Plane.YZ)
make_face()
scale(by=height / spade.sketch.bounding_box().size.Y)
super().__init__(obj=spade.sketch, rotation=rotation, align=align, mode=mode)
class Heart(BaseSketchObject):
def __init__(
self,
height: float,
rotation: float = 0,
(continues on next page)
class Diamond(BaseSketchObject):
def __init__(
self,
height: float,
rotation: float = 0,
align: tuple[Align, Align] = (Align.CENTER, Align.CENTER),
mode: Mode = Mode.ADD,
):
with BuildSketch() as diamond:
with BuildLine():
Bezier((135, 0), (94, 69), (47, 134), (0, 198))
mirror(about=Plane.XZ)
mirror(about=Plane.YZ)
make_face()
scale(by=height / diamond.sketch.bounding_box().size.Y)
super().__init__(obj=diamond.sketch, rotation=rotation, align=align, mode=mode)
card_width = 2.5 * IN
card_length = 3.5 * IN
deck = 0.5 * IN
wall = 4 * MM
gap = 0.5 * MM
box = Compound(
[box_builder.part, lid_builder.part.moved(Location((0, 0, (wall + deck) / 2)))]
)
visible, hidden = box.project_to_viewport((70, -50, 120))
max_dimension = max(*Compound(children=visible + hidden).bounding_box().size)
exporter = ExportSVG(scale=100 / max_dimension)
exporter.add_layer("Visible")
exporter.add_layer("Hidden", line_color=(99, 99, 99), line_type=LineType.ISO_DOT)
exporter.add_shape(visible, layer="Visible")
exporter.add_shape(hidden, layer="Hidden")
# exporter.write(f"assets/card_box.svg")
class PlayingCard(BaseSketchObject):
"""PlayingCard
Args:
rank (Literal['A', '2' .. '10', 'J', 'Q', 'K']): card rank
suit (Literal['Clubs', 'Spades', 'Hearts', 'Diamonds']): card suit
"""
width = 2.5 * IN
height = 3.5 * IN
suits = {"Clubs": Club, "Spades": Spade, "Hearts": Heart, "Diamonds": Diamond}
(continues on next page)
def __init__(
self,
rank: Literal["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"],
suit: Literal["Clubs", "Spades", "Hearts", "Diamonds"],
rotation: float = 0,
align: tuple[Align, Align] = (Align.CENTER, Align.CENTER),
mode: Mode = Mode.ADD,
):
with BuildSketch() as playing_card:
Rectangle(
PlayingCard.width, PlayingCard.height, align=(Align.MIN, Align.MIN)
)
fillet(playing_card.vertices(), radius=PlayingCard.width / 15)
with Locations(
(
PlayingCard.width / 7,
8 * PlayingCard.height / 9,
)
):
Text(
txt=rank,
font_size=PlayingCard.width / 7,
mode=Mode.SUBTRACT,
)
with Locations(
(
PlayingCard.width / 7,
7 * PlayingCard.height / 9,
)
):
PlayingCard.suits[suit](
height=PlayingCard.width / 12, mode=Mode.SUBTRACT
)
with Locations(
(
6 * PlayingCard.width / 7,
1 * PlayingCard.height / 9,
)
):
Text(
txt=rank,
font_size=PlayingCard.width / 7,
rotation=180,
mode=Mode.SUBTRACT,
)
with Locations(
(
6 * PlayingCard.width / 7,
2 * PlayingCard.height / 9,
)
(continues on next page)
hand = Compound(
children=[
Rot(0, 0, -20) * Pos(0, 0, 0) * ace_spades,
Rot(0, 0, -10) * Pos(0, 0, -1) * king_hearts,
Rot(0, 0, 0) * Pos(0, 0, -2) * queen_clubs,
Rot(0, 0, 10) * Pos(0, 0, -3) * jack_diamonds,
Rot(0, 0, 20) * Pos(0, 0, -4) * ten_spades,
]
)
Stud Wall
This example demonstrates creatings custom Part objects and putting them into assemblies. The custom object is a
Stud used in the building industry while the assembly is a StudWall created from copies of Stud objects for efficiency.
Both the Stud and StudWall objects use RigidJoints to define snap points which are used to position all of objects.
class Stud(BasePartObject):
"""Part Object: Stud
Args:
length (float): stud size
width (float): stud size
thickness (float): stud size
rotation (RotationLike, optional): angles to rotate about axes. Defaults to (0,␣
˓→0, 0).
_applies_to = [BuildPart._tag]
def __init__(
self,
length: float = 8 * FT,
width: float = 3.5 * IN,
thickness: float = 1.5 * IN,
rotation: RotationLike = (0, 0, 0),
align: Union[None, Align, tuple[Align, Align, Align]] = (
Align.CENTER,
Align.CENTER,
Align.MIN,
),
mode: Mode = Mode.ADD,
):
self.length = length
self.width = width
self.thickness = thickness
class StudWall(Compound):
"""StudWall
(continues on next page)
Args:
length (float): wall length
depth (float, optional): stud width. Defaults to 3.5*IN.
height (float, optional): wall height. Defaults to 8*FT.
stud_spacing (float, optional): center-to-center. Defaults to 16*IN.
stud_thickness (float, optional): Defaults to 1.5*IN.
"""
def __init__(
self,
length: float,
depth: float = 3.5 * IN,
height: float = 8 * FT,
stud_spacing: float = 16 * IN,
stud_thickness: float = 1.5 * IN,
):
# Create the object that will be used for top and sole plates
plate = Stud(
length,
depth,
rotation=(0, -90, 0),
align=(Align.MIN, Align.CENTER, Align.MAX),
)
# Define where studs will go on the plates
stud_locations = Pos(stud_thickness / 2, 0, stud_thickness) * GridLocations(
stud_spacing, 0, int(length / stud_spacing) + 1, 1, align=Align.MIN
)
stud_locations.append(Pos(length - stud_thickness / 2, 0, stud_thickness))
# For efficiency studs in the walls are copies with their own position
studs = []
for i, loc in enumerate(stud_locations):
stud_joint = RigidJoint(f"stud{i}", plate, loc)
stud_copy = copy.copy(stud)
stud_joint.connect_to(stud_copy.joints["end0"])
studs.append(stud_copy)
top_plate = copy.copy(plate)
sole_plate = copy.copy(plate)
# Position the top plate relative to the top of the first stud
studs[0].joints["end1"].connect_to(top_plate.joints["stud0"])
Tea Cup
wall_thickness = 3 * MM
fillet_radius = wall_thickness * 0.49
wall_thickness = 3 * MM
fillet_radius = wall_thickness * 0.49
# Hollow out the bowl with openings on the top and bottom
tea_cup = offset(
tea_cup, -wall_thickness, openings=tea_cup.faces().filter_by(GeomType.PLANE)
)
This example demonstrates the creation a tea cup, which serves as an example of constructing complex, non-flat geo-
metrical shapes programmatically.
The tea cup model involves several CAD techniques, such as:
• Revolve Operations: There is 1 occurrence of a revolve operation. This is used to create the main body of the tea
cup by revolving a profile around an axis, a common technique for generating symmetrical objects like cups.
• Sweep Operations: There are 2 occurrences of sweep operations. The handle are created by sweeping a profile
along a path to generate non-planar surfaces.
• Offset/Shell Operations: the bowl of the cup is hollowed out with the offset operation leaving the top open.
• Fillet Operations: There is 1 occurrence of a fillet operation which is used to round the edges for aesthetic
improvement and to mimic real-world objects more closely.
Toy Truck
# Create the main truck body — from bumper to bed, excluding the cab
with BuildPart() as body:
# The body has two axes of symmetry, so we start with a centered sketch.
# The default workplane is Plane.XY.
with BuildSketch() as body_skt:
Rectangle(20, 35)
# Fillet all the corners of the sketch.
# Alternatively, you could use RectangleRounded.
fillet(body_skt.vertices(), 1)
# Combine edge groups from both sides of the fender and fillet them
fender_edges = body.edges().group_by(Axis.X)[0] + body.edges().group_by(Axis.X)[-1]
fender_edges = fender_edges.group_by(Axis.Z)[1:]
fillet(fender_edges, 0.4)
# Rear window
with BuildSketch(Plane.XZ.shift_origin((0, 0, 3))) as rear_window:
RectangleRounded(8, 4, 0.75)
extrude(amount=10, mode=Mode.SUBTRACT)
# Front window
with BuildSketch(Plane.XZ) as front_window:
RectangleRounded(15.2, 11, 0.75)
extrude(amount=-10, mode=Mode.SUBTRACT)
# Side windows
with BuildSketch(Plane.YZ) as side_window:
with Locations((3.5, 0)):
with GridLocations(10, 0, 2, 1):
Trapezoid(9, 5.5, 80, 100, align=(Align.CENTER, Align.MIN))
fillet(side_window.vertices().group_by(Axis.Y)[-1], 0.5)
extrude(amount=12, both=True, mode=Mode.SUBTRACT)
This example demonstrates how to design a toy truck using BuildPart and BuildSketch in Builder mode. The model
includes a detailed body, cab, grill, and bumper, showcasing techniques like sketch reuse, symmetry, tapered extrusions,
selective filleting, and the use of joints for part assembly. Ideal for learning complex part construction and hierarchical
modeling in build123d.
Vase
This example demonstrates the build123d techniques involving the creation of a vase. Specifically, it showcases the
processes of revolving a sketch, shelling (creating a hollow object by removing material from its interior), and selecting
edges by position range and type for the application of fillets (rounding off the edges).
• Sketching: Drawing a 2D profile or outline that represents the side view of the vase.
• Revolving: Rotating the sketch around an axis to create a 3D object. This step transforms the 2D profile into a
3D vase shape.
• Offset/Shelling: Removing material from the interior of the solid vase to create a hollow space, making it resem-
ble a real vase more closely.
• Edge Filleting: Selecting specific edges of the vase for filleting, which involves rounding those edges. The edges
are selected based on their position and type.
To enhance users’ proficiency with Build123D, this section offers a series of challenges. In these challenges, users are
presented with a CAD drawing and tasked with designing the part. Their goal is to match the part’s mass to a specified
target.
These drawings were skillfully crafted and generously provided to Build123D by Too Tall Toby, a renowned figure in
the realm of 3D CAD. Too Tall Toby is the host of the World Championship of 3D CAD Speedmodeling. For additional
3D CAD challenges and content, be sure to visit Toby’s youtube channel.
Feel free to click on the parts below to embark on these engaging challenges.
Party Pack 01-01 Bearing Bracket Party Pack 01-01 Bearing Bracket
Party Pack 01-02 Post Cap Party Pack 01-02 Post Cap
Party Pack 01-03 C Clamp Base Party Pack 01-03 C Clamp Base
Party Pack 01-04 Angle Bracket Party Pack 01-04 Angle Bracket
Party Pack 01-05 Paste Sleeve Party Pack 01-05 Paste Sleeve
Party Pack 01-06 Bearing Jig Party Pack 01-06 Bearing Jig
Party Pack 01-07 Flanged Hub Party Pack 01-07 Flanged Hub
Party Pack 01-08 Tie Plate Party Pack 01-08 Tie Plate
Party Pack 01-09 Corner Tie Party Pack 01-09 Corner Tie
Party Pack 01-10 Light Cap Party Pack 01-10 Light Cap
Object Mass
797.15 g
Reference Implementation
"""
Too Tall Toby Party Pack 01-01 Bearing Bracket
"""
with BuildPart() as p:
with BuildSketch() as s:
Rectangle(115, 50)
with Locations((5 / 2, 0)):
SlotOverall(90, 12, mode=Mode.SUBTRACT)
extrude(amount=15)
with Locations(zz.faces().sort_by(Axis.Y)[0]):
with Locations((42 / 2 + 6, 0)):
CounterBoreHole(24 / 2, 34 / 2, 4)
mirror(about=Plane.XZ)
show_object(p)
got_mass = p.part.volume*densa
want_mass = 797.15
tolerance = 1
delta = abs(got_mass - want_mass)
print(f"Mass: {got_mass:0.2f} g")
assert delta < tolerance, f'{got_mass=}, {want_mass=}, {delta=}, {tolerance=}'
Object Mass
43.09 g
Reference Implementation
"""
Too Tall Toby Party Pack 01-02 Post Cap
"""
fillet(p.edges().filter_by(GeomType.CIRCLE, reverse=True).group_by(Axis.X)[0], 1)
pts = [
(0, 0),
(42 / 2, 0),
((lc1.line @ 1).X, (lc1.line @ 1).Y),
(0, (lc1.line @ 1).Y),
]
with BuildSketch(Plane.XZ) as sk2:
Polygon(*pts, align=None)
fillet(sk2.vertices().group_by(Axis.X)[1], 3)
revolve(axis=Axis.Z, mode=Mode.SUBTRACT)
show(p)
got_mass = p.part.volume*densc
want_mass = 43.09
tolerance = 1
delta = abs(got_mass - want_mass)
print(f"Mass: {got_mass:0.2f} g")
assert delta < tolerance, f'{got_mass=}, {want_mass=}, {delta=}, {tolerance=}'
Object Mass
96.13 g
Reference Implementation
"""
Too Tall Toby Party Pack 01-03 C Clamp Base
"""
show(ppp0103)
got_mass = ppp0103.part.volume*densb
want_mass = 96.13
tolerance = 1
delta = abs(got_mass - want_mass)
print(f"Mass: {got_mass:0.2f} g")
assert delta < tolerance, f'{got_mass=}, {want_mass=}, {delta=}, {tolerance=}'
Object Mass
310.00 g
Reference Implementation
"""
Too Tall Toby Party Pack 01-04 Angle Bracket
"""
(continues on next page)
with BuildPart() as p:
with BuildSketch() as s:
Circle(d1 / 2)
extrude(amount=h1)
with BuildSketch(Plane.XY.offset(h1)) as s2:
Circle(d2 / 2)
extrude(amount=h2)
with BuildSketch(Plane.YZ) as s3:
Rectangle(d1 + 15, h3, align=(Align.CENTER, Align.MIN))
extrude(amount=w1 - d1 / 2)
# fillet workaround \/
ped = p.part.edges().group_by(Axis.Z)[2].filter_by(GeomType.CIRCLE)
fillet(ped, f1)
with BuildSketch(Plane.YZ) as s3a:
Rectangle(d1 + 15, 15, align=(Align.CENTER, Align.MIN))
Rectangle(d1, 15, mode=Mode.SUBTRACT, align=(Align.CENTER, Align.MIN))
extrude(amount=w1 - d1 / 2, mode=Mode.SUBTRACT)
# end fillet workaround /\
with BuildSketch() as s4:
Circle(d3 / 2)
extrude(amount=h1 + h2, mode=Mode.SUBTRACT)
with BuildSketch() as s5:
with Locations((w1 - d1 / 2 - w2 / 2, 0)):
Rectangle(w2, d1)
extrude(amount=-h4)
fillet(p.part.edges().group_by(Axis.X)[-1].sort_by(Axis.Z)[-1], f2)
fillet(p.part.edges().group_by(Axis.X)[-4].sort_by(Axis.Z)[-2], f3)
pln = Plane.YZ.offset(w1 - d1 / 2)
with BuildSketch(pln) as s6:
with Locations((0, -h4)):
SlotOverall(slotw1 * 2, sloth1, 90)
extrude(amount=-w3, mode=Mode.SUBTRACT)
with BuildSketch(pln) as s6b:
with Locations((0, -h4)):
SlotOverall(slotw2 * 2, sloth2, 90)
extrude(amount=-w2, mode=Mode.SUBTRACT)
got_mass = p.part.volume*densa
want_mass = 310
tolerance = 1
delta = abs(got_mass - want_mass)
print(f"Mass: {got_mass:0.2f} g")
assert delta < tolerance, f'{got_mass=}, {want_mass=}, {delta=}, {tolerance=}'
Object Mass
57.08 g
Reference Implementation
"""
Too Tall Toby Party Pack 01-05 Paste Sleeve
"""
extrude(p.part.faces().sort_by(Axis.Z)[0], amount=30)
show(p)
got_mass = p.part.volume*densc
want_mass = 57.08
tolerance = 1
delta = abs(got_mass - want_mass)
print(f"Mass: {got_mass:0.2f} g")
assert delta < tolerance, f'{got_mass=}, {want_mass=}, {delta=}, {tolerance=}'
Object Mass
328.02 g
Reference Implementation
"""
Too Tall Toby Party Pack 01-06 Bearing Jig
"""
with BuildPart() as p:
Box(200, 200, 22) # Oversized plate
# Cylinder underneath
Cylinder(r1, y2, align=(Align.CENTER, Align.CENTER, Align.MAX))
fillet(p.edges(Select.NEW), r5) # Weld together
extrude(sk_body.sketch, amount=-y1, mode=Mode.INTERSECT) # Cut to shape
# Remove slot
with Locations((0, y_tot - r1 - y4, 0)):
Box(
y_tot,
y_tot,
10,
align=(Align.CENTER, Align.MIN, Align.CENTER),
mode=Mode.SUBTRACT,
)
(continues on next page)
show(p)
got_mass = p.part.volume*densa
want_mass = 328.02
tolerance = 1
delta = abs(got_mass - want_mass)
print(f"Mass: {got_mass:0.2f} g")
assert delta < tolerance, f'{got_mass=}, {want_mass=}, {delta=}, {tolerance=}'
Object Mass
372.99 g
Reference Implementation
"""
Too Tall Toby Party Pack 01-07 Flanged Hub
"""
with BuildPart() as p:
with BuildSketch() as s:
Circle(130 / 2)
extrude(amount=8)
with BuildSketch(Plane.XY.offset(8)) as s2:
Circle(84 / 2)
extrude(amount=25 - 8)
with BuildSketch(Plane.XY.offset(25)) as s3:
Circle(35 / 2)
extrude(amount=52 - 25)
with BuildSketch() as s4:
Circle(73 / 2)
extrude(amount=18, mode=Mode.SUBTRACT)
pln2 = p.part.faces().sort_by(Axis.Z)[5]
with BuildSketch(Plane.XY.offset(52)) as s5:
Circle(20 / 2)
extrude(amount=-52, mode=Mode.SUBTRACT)
fillet(
p.part.edges()
.filter_by(GeomType.CIRCLE)
.sort_by(Axis.Z)[2:-2]
.sort_by(SortBy.RADIUS)[1:],
3,
)
pln = Plane(pln2)
pln.origin = pln.origin + Vector(20 / 2, 0, 0)
pln = pln.rotated((0, 45, 0))
pln = pln.offset(-25 + 3 + 0.10)
with BuildSketch(pln) as s6:
Rectangle((73 - 35) / 2 * 1.414 + 5, 3)
zz = extrude(amount=15, taper=-20 / 2, mode=Mode.PRIVATE)
zz2 = split(zz, bisect_by=Plane.XY.offset(25), mode=Mode.PRIVATE)
zz3 = split(zz2, bisect_by=Plane.YZ.offset(35 / 2 - 1), mode=Mode.PRIVATE)
with PolarLocations(0, 3):
add(zz3)
with Locations(Plane.XY.offset(8)):
with PolarLocations(107.95 / 2, 6):
CounterBoreHole(6 / 2, 13 / 2, 4)
show(p)
got_mass = p.part.volume*densb
want_mass = 372.99
tolerance = 1
delta = abs(got_mass - want_mass)
print(f"Mass: {got_mass:0.2f} g")
assert delta < tolerance, f'{got_mass=}, {want_mass=}, {delta=}, {tolerance=}'
Object Mass
3387.06 g
Reference Implementation
"""
Too Tall Toby Party Pack 01-08 Tie Plate
"""
with BuildPart() as p:
with BuildSketch() as s1:
Rectangle(188 / 2 - 33, 162, align=(Align.MIN, Align.CENTER))
with Locations((188 / 2 - 33, 0)):
SlotOverall(190, 33 * 2, rotation=90)
mirror(about=Plane.YZ)
with GridLocations(188 - 2 * 33, 190 - 2 * 33, 2, 2):
Circle(29 / 2, mode=Mode.SUBTRACT)
Circle(84 / 2, mode=Mode.SUBTRACT)
extrude(amount=16)
show(p)
got_mass = p.part.volume*densa
want_mass = 3387.06
tolerance = 1
delta = abs(got_mass - want_mass)
print(f"Mass: {got_mass:0.2f} g")
assert delta < tolerance, f'{got_mass=}, {want_mass=}, {delta=}, {tolerance=}'
Object Mass
307.23 g
Reference Implementation
"""
Too Tall Toby Party Pack 01-09 Corner Tie
"""
show(ppp109)
got_mass = ppp109.part.volume*densb
want_mass = 307.23
tolerance = 1
delta = abs(got_mass - want_mass)
print(f"Mass: {got_mass:0.2f} g")
assert delta < tolerance, f'{got_mass=}, {want_mass=}, {delta=}, {tolerance=}'
Object Mass
211.30 g
Reference Implementation
"""
Too Tall Toby Party Pack 01-10 Light Cap
"""
OT=40
(continues on next page)
ppp0110 = p
got_mass = ppp0110.volume*densc
want_mass = 211.30
tolerance = 1
delta = abs(got_mass - want_mass)
print(f"Mass: {got_mass:0.1f} g")
assert delta < tolerance, f'{got_mass=}, {want_mass=}, {delta=}, {tolerance=}'
show(ppp0110)
23-02-02 SM Hanger
Object Mass
1028g +/- 10g
Reference Implementation
"""
Creation of a complex sheet metal part
name: ttt_sm_hanger.py
by: Gumyr
date: July 17, 2023
desc:
This example implements the sheet metal part described in Too Tall Toby's
sm_hanger CAD challenge.
"""
sheet_thickness = 4 * MM
got_mass = sm_hanger.part.volume*7800*1e-6
want_mass = 1028
tolerance = 10
delta = abs(got_mass - want_mass)
print(f"Mass: {got_mass:0.1f} g")
assert delta < tolerance, f'{got_mass=}, {want_mass=}, {delta=}, {tolerance=}'
show(sm_hanger)
Object Mass
1294 g
Reference Implementation
"""
Too Tall Toby challenge 23-T-24 CURVED SUPPORT
"""
show(curved_support)
Object Mass
3.92 lbs
Reference Implementation
with BuildPart() as p:
with BuildSketch() as xy:
with BuildLine():
l1 = ThreePointArc((5 / 2, -1.25), (5.5 / 2, 0), (5 / 2, 1.25))
Polyline(l1 @ 0, (0, -1.25), (0, 1.25), l1 @ 1)
make_face()
extrude(amount=4)
# To avoid OCCT problems, don't attempt to extend the top arc, remove instead
with BuildPart(mode=Mode.SUBTRACT) as internals:
y = p.edges().filter_by(Axis.X).sort_by(Axis.Z)[-1].center().Z
with Locations(p.faces(Select.LAST).filter_by(GeomType.PLANE).sort_by(Axis.Z)[-1]):
CounterBoreHole(0.625 / 2, 1.25 / 2, 0.5)
mirror(about=Plane.YZ)
got_mass = part.volume*7800e-6/LB
want_mass = 3.923
tolerance = 0.02
delta = abs(got_mass - want_mass)
print(f"Mass: {got_mass:0.1f} lbs")
assert delta < tolerance, f'{got_mass=}, {want_mass=}, {delta=}, {tolerance=}'
show(p)
To create the perimeter, we’ll use a BuildLine instance as follows. Since the heart is symmetric, we’ll only create half
of its surface here:
Note that l4 is not in the same plane as the other lines; it defines the center line of the heart and archs up off Plane.XY.
In preparation for creating the surface, we’ll define a point on the surface:
Note that the surface was raised up by 0.5 using the locate method. Also, note that the - in front of Face simply flips
the face normal so that the colored side is up, which isn’t necessary but helps with viewing.
Now that one half of the top of the heart has been created, the remainder of the top and bottom can be created by
mirroring:
top_left_surface = top_right_surface.mirror(Plane.YZ)
bottom_right_surface = top_right_surface.mirror(Plane.XY)
bottom_left_surface = -top_left_surface.mirror(Plane.XY)
The sides of the heart are going to be created by extruding the outside of the perimeter as follows:
With the top, bottom, and sides, the complete boundary of the object is defined. We can now put them together, first
into a Shell and then into a Solid:
heart = Solid(
Shell(
[
top_right_surface,
top_left_surface,
bottom_right_surface,
bottom_left_surface,
left_side,
right_side,
]
)
)
ò Note
When creating a Solid from a Shell, the Shell must be “water-tight,” meaning it should have no holes. For ob-
jects with complex Edges, it’s best practice to reuse Edges in adjoining Faces whenever possible to avoid slight
mismatches that can create openings.
Finally, we’ll create the frame around the heart as a simple extrusion of a planar shape defined by the perimeter of the
heart and merge all of the components together:
Note that an additional planar line is used to close l1 and l3 so a Face can be created. The offset() function defines
the outside of the frame as a constant distance from the heart itself.
Summary
In this tutorial, we’ve explored surface modeling techniques to create a non-planar heart-shaped object using build123d.
By utilizing methods from the Face class, such as make_surface(), we constructed the perimeter and central point
of the surface. We then assembled the complete boundary of the object by creating the top, bottom, and sides, and
combined them into a Shell and eventually a Solid. Finally, we added a frame around the heart using the offset()
function to maintain a constant distance from the heart.
1.10 Objects
Objects are Python classes that take parameters as inputs and create 1D, 2D or 3D Shapes. For example, a Torus is
defined by a major and minor radii. In Builder mode, objects are positioned with Locations while in Algebra mode,
objects are positioned with the * operator and shown in these examples:
1.10.1 Align
2D/Sketch and 3D/Part objects can be aligned relative to themselves, either centered, or justified right or left of each
Axis. The following diagram shows how this alignment works in 2D:
For example:
with BuildSketch():
Circle(1, align=(Align.MIN, Align.MIN))
creates a circle who’s minimal X and Y values are on the X and Y axis and is located in the top right corner. The Align
enum has values: MIN, CENTER and MAX.
In 3D the align parameter also contains a Z align value but otherwise works in the same way.
Note that the align will also accept a single Align value which will be used on all axes - as shown here:
with BuildSketch():
Circle(1, align=Align.MIN)
1.10.2 Mode
With the Builder API the mode parameter controls how objects are combined with lines, sketches, or parts under
construction. The Mode enum has values:
• ADD: fuse this object to the object under construction
1.10.3 1D Objects
The following objects all can be used in BuildLine contexts. Note that 1D objects are not affected by Locations in
Builder mode.
Bezier
Curve defined by control points and weights
CenterArc
Arc defined by center, radius, & angles
DoubleTangentArc
Arc defined by point/tangent pair & other curve
EllipticalCenterArc
Elliptical arc defined by center, radii & angles
FilletPolyline
Polyline with filleted corners defined by pts and radius
Helix
Helix defined pitch, radius and height
IntersectingLine
Intersecting line defined by start, direction & other line
JernArc
Arc define by start point, tangent, radius and angle
Line
Line defined by end points
PolarLine
Line defined by start, angle and length
Polyline
Multiple line segments defined by points
RadiusArc
Arc define by two points and a radius
SagittaArc
Arc define by two points and a sagitta
Spline
Curve define by points
TangentArc
Curve define by two points and a tangent
ThreePointArc
Curve define by three points
Reference
class BaseLineObject(curve: ~build123d.topology.one_d.Wire, mode: ~build123d.build_enums.Mode =
<Mode.ADD>)
BaseLineObject specialized for Wire.
Parameters
• curve (Wire) – wire to create
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD
class Bezier(*cntl_pnts: ~build123d.geometry.Vector | tuple[float, float] | tuple[float, float, float] |
~collections.abc.Sequence[float], weights: list[float] | None = None, mode:
~build123d.build_enums.Mode = <Mode.ADD>)
Line Object: Bezier Curve
Create a non-rational bezier curve defined by a sequence of points and include optional weights to create a rational
bezier curve. The number of weights must match the number of control points.
Parameters
• cntl_pnts (sequence[VectorLike]) – points defining the curve
• weights (list[float], optional) – control point weights. Defaults to None
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD
class CenterArc(center: ~build123d.geometry.Vector | tuple[float, float] | tuple[float, float, float] |
~collections.abc.Sequence[float], radius: float, start_angle: float, arc_size: float, mode:
~build123d.build_enums.Mode = <Mode.ADD>)
Line Object: Center Arc
Create a circular arc defined by a center point and radius.
Parameters
• center (VectorLike) – center point of arc
• radius (float) – arc radius
• start_angle (float) – arc starting angle from x-axis
• arc_size (float) – angular size of arc
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD
class DoubleTangentArc(pnt: ~build123d.geometry.Vector | tuple[float, float] | tuple[float, float, float] |
~collections.abc.Sequence[float], tangent: ~build123d.geometry.Vector | tuple[float,
float] | tuple[float, float, float] | ~collections.abc.Sequence[float], other:
~build123d.topology.composite.Curve | ~build123d.topology.one_d.Edge |
~build123d.topology.one_d.Wire, keep: ~build123d.build_enums.Keep =
<Keep.TOP>, mode: ~build123d.build_enums.Mode = <Mode.ADD>)
Line Object: Double Tangent Arc
Create a circular arc defined by a point/tangent pair and another line find a tangent to.
The arc specified with TOP or BOTTOM depends on the geometry and isn’t predictable.
Contains a solver.
Parameters
• pnt (VectorLike) – start point
• tangent (VectorLike) – tangent at start point
• other (Curve | Edge | Wire) – line object to tangent
• keep (Keep, optional) – specify which arc if more than one, TOP or BOTTOM. Defaults
to Keep.TOP
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD
Raises
RunTimeError – no double tangent arcs found
class EllipticalCenterArc(center: ~build123d.geometry.Vector | tuple[float, float] | tuple[float, float, float] |
~collections.abc.Sequence[float], x_radius: float, y_radius: float, start_angle:
float = 0.0, end_angle: float = 90.0, rotation: float = 0.0, angular_direction:
~build123d.build_enums.AngularDirection =
<AngularDirection.COUNTER_CLOCKWISE>, mode:
~build123d.build_enums.Mode = <Mode.ADD>)
Line Object: Elliptical Center Arc
Create an elliptical arc defined by a center point, x- and y- radii.
Parameters
• center (VectorLike) – ellipse center
• x_radius (float) – x radius of the ellipse (along the x-axis of plane)
• y_radius (float) – y radius of the ellipse (along the y-axis of plane)
• start_angle (float, optional) – arc start angle from x-axis. Defaults to 0.0
• end_angle (float, optional) – arc end angle from x-axis. Defaults to 90.0
• rotation (float, optional) – angle to rotate arc. Defaults to 0.0
• angular_direction (AngularDirection, optional) – arc direction. Defaults to An-
gularDirection.COUNTER_CLOCKWISE
• plane (Plane, optional) – base plane. Defaults to Plane.XY
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD
class FilletPolyline(*pts: ~build123d.geometry.Vector | tuple[float, float] | tuple[float, float, float] |
~collections.abc.Sequence[float] | ~collections.abc.Iterable[~build123d.geometry.Vector
| tuple[float, float] | tuple[float, float, float] | ~collections.abc.Sequence[float]], radius:
float, close: bool = False, mode: ~build123d.build_enums.Mode = <Mode.ADD>)
Line Object: Fillet Polyline
Create a sequence of straight lines defined by successive points that are filleted to a given radius.
Parameters
• pts (VectorLike | Iterable[VectorLike]) – sequence of two or more points
• radius (float) – fillet radius
• close (bool, optional) – close end points with extra Edge and corner fillets. Defaults
to False
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD
Raises
• ValueError – Two or more points not provided
• ValueError – radius must be positive
class Helix(pitch: float, height: float, radius: float, center: ~build123d.geometry.Vector | tuple[float, float] |
tuple[float, float, float] | ~collections.abc.Sequence[float] = (0, 0, 0), direction:
~build123d.geometry.Vector | tuple[float, float] | tuple[float, float, float] |
~collections.abc.Sequence[float] = (0, 0, 1), cone_angle: float = 0, lefthand: bool = False, mode:
~build123d.build_enums.Mode = <Mode.ADD>)
Line Object: Helix
Create a helix defined by pitch, height, and radius. The helix may have a taper defined by cone_angle.
If cone_angle is not 0, radius is the initial helix radius at center. cone_angle > 0 increases the final radius.
cone_angle < 0 decreases the final radius.
Parameters
• pitch (float) – distance between loops
• height (float) – helix height
• radius (float) – helix radius
• center (VectorLike, optional) – center point. Defaults to (0, 0, 0)
• direction (VectorLike, optional) – direction of central axis. Defaults to (0, 0, 1)
• cone_angle (float, optional) – conical angle from direction. Defaults to 0
• lefthand (bool, optional) – left handed helix. Defaults to False
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD
class IntersectingLine(start: ~build123d.geometry.Vector | tuple[float, float] | tuple[float, float, float] |
~collections.abc.Sequence[float], direction: ~build123d.geometry.Vector | tuple[float,
float] | tuple[float, float, float] | ~collections.abc.Sequence[float], other:
~build123d.topology.composite.Curve | ~build123d.topology.one_d.Edge |
~build123d.topology.one_d.Wire, mode: ~build123d.build_enums.Mode =
<Mode.ADD>)
Intersecting Line Object: Line
Create a straight line defined by a point/direction pair and another line to intersect.
Parameters
• start (VectorLike) – start point
• direction (VectorLike) – direction to make line
• other (Edge) – line object to intersect
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD
class JernArc(start: ~build123d.geometry.Vector | tuple[float, float] | tuple[float, float, float] |
~collections.abc.Sequence[float], tangent: ~build123d.geometry.Vector | tuple[float, float] |
tuple[float, float, float] | ~collections.abc.Sequence[float], radius: float, arc_size: float, mode:
~build123d.build_enums.Mode = <Mode.ADD>)
1.10.4 2D Objects
Arrow
Arrow with head and path for shaft
ArrowHead
Arrow head with multiple types
Circle
Circle defined by radius
DimensionLine
Dimension line
Ellipse
Ellipse defined by major and minor radius
ExtensionLine
Extension lines for distance or angles
Polygon
Polygon defined by points
Rectangle
Rectangle defined by width and height
RectangleRounded
Rectangle with rounded corners defined by width, height, and radius
RegularPolygon
RegularPolygon defined by radius and number of sides
SlotArc
SlotArc defined by arc and height
SlotCenterPoint
SlotCenterPoint defined by two points and a height
SlotCenterToCenter
SlotCenterToCenter defined by center separation and height
SlotOverall
SlotOverall defined by end-to-end length and height
TechnicalDrawing
A technical drawing with descriptions
Text
Text defined by string and font parameters
Trapezoid
Trapezoid defined by width, height and interior angles
Triangle
Triangle defined by one side & two other sides or interior angles
Reference
class BaseSketchObject(obj: ~build123d.topology.composite.Compound | ~build123d.topology.two_d.Face,
rotation: float = 0, align: ~build123d.build_enums.Align |
tuple[~build123d.build_enums.Align, ~build123d.build_enums.Align] | None = None,
mode: ~build123d.build_enums.Mode = <Mode.ADD>)
Base class for all BuildSketch objects
Parameters
• face (Face) – face to create
• rotation (float, optional) – angle to rotate object. Defaults to 0
• align (Align | tuple[Align, Align], optional) – align MIN, CENTER, or MAX
of object. Defaults to None
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD
class Arrow(arrow_size: float, shaft_path: ~build123d.topology.one_d.Edge | ~build123d.topology.one_d.Wire,
shaft_width: float, head_at_start: bool = True, head_type: ~build123d.build_enums.HeadType =
<HeadType.CURVED>, mode: ~build123d.build_enums.Mode = <Mode.ADD>)
Sketch Object: Arrow with shaft
Parameters
• arrow_size (float) – arrow head tip to tail length
• shaft_path (Edge | Wire) – line describing the shaft shape
• shaft_width (float) – line width of shaft
• head_at_start (bool, optional) – Defaults to True.
• head_type (HeadType, optional) – arrow head shape. Defaults to HeadType.CURVED.
• mode (Mode, optional) – _description_. Defaults to Mode.ADD.
class ArrowHead(size: float, head_type: ~build123d.build_enums.HeadType = <HeadType.CURVED>, rotation:
float = 0, mode: ~build123d.build_enums.Mode = <Mode.ADD>)
Sketch Object: ArrowHead
Parameters
• size (float) – tip to tail length
• head_type (HeadType, optional) – arrow head shape. Defaults to HeadType.CURVED.
• rotation (float, optional) – rotation in degrees. Defaults to 0.
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD.
class Circle(radius: float, align: ~build123d.build_enums.Align | tuple[~build123d.build_enums.Align,
~build123d.build_enums.Align] | None = (<Align.CENTER>, <Align.CENTER>), mode:
~build123d.build_enums.Mode = <Mode.ADD>)
Sketch Object: Circle
Create a circle defined by radius.
Parameters
• radius (float) – circle radius
Parameters
• x_radius (float) – x radius of the ellipse (along the x-axis of plane)
• y_radius (float) – y radius of the ellipse (along the y-axis of plane)
• rotation (float, optional) – angle to rotate object. Defaults to 0
• align (Align | tuple[Align, Align], optional) – align MIN, CENTER, or MAX
of object. Defaults to (Align.CENTER, Align.CENTER)
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD
class ExtensionLine(border: ~build123d.topology.one_d.Wire | ~build123d.topology.one_d.Edge |
list[~build123d.geometry.Vector | ~build123d.topology.zero_d.Vertex | tuple[float, float,
float]], offset: float, draft: ~drafting.Draft, sketch: ~build123d.topology.composite.Sketch |
None = None, label: str | None = None, arrows: tuple[bool, bool] = (True, True),
tolerance: float | tuple[float, float] | None = None, label_angle: bool = False, project_line:
~build123d.geometry.Vector | tuple[float, float] | tuple[float, float, float] |
~collections.abc.Sequence[float] | None = None, mode: ~build123d.build_enums.Mode =
<Mode.ADD>)
Sketch Object: Extension Line
Create a dimension line with two lines extending outward from the part to dimension. Typically used for (but
not restricted to) outside dimensions, with a pair of lines extending from the edge of a part to a dimension line.
Parameters
• border (PathDescriptor) – a very general type of input defining the object to be dimen-
sioned. Typically this value would be extracted from the part but is not restricted to this
use.
• offset (float) – a distance to displace the dimension line from the edge of the object
• draft (Draft) – instance of Draft dataclass
• label (str, optional) – a text string which will replace the length (or arc length) that
would otherwise be extracted from the provided path. Providing a label is useful when il-
lustrating a parameterized input where the name of an argument is desired not an actual
measurement. Defaults to None.
• arrows (tuple[bool, bool], optional) – a pair of boolean values controlling the
placement of the start and end arrows. Defaults to (True, True).
• tolerance (float | tuple[float, float], optional) – an optional tolerance
value to add to the extracted length value. If a single tolerance value is provided it is shown
as ± the provided value while a pair of values are shown as separate + and - values. Defaults
to None.
• label_angle (bool, optional) – a flag indicating that instead of an extracted length
value, the size of the circular arc extracted from the path should be displayed in degrees.
Defaults to False.
• project_line (Vector, optional) – Vector line which to project dimension against.
Defaults to None.
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD.
dimension
length of the dimension
class Text(txt: str, font_size: float, font: str = 'Arial', font_path: str | None = None, font_style:
~build123d.build_enums.FontStyle = <FontStyle.REGULAR>, align: ~build123d.build_enums.Align |
tuple[~build123d.build_enums.Align, ~build123d.build_enums.Align] | None = (<Align.CENTER>,
<Align.CENTER>), path: ~build123d.topology.one_d.Edge | ~build123d.topology.one_d.Wire | None
= None, position_on_path: float = 0.0, rotation: float = 0.0, mode: ~build123d.build_enums.Mode =
<Mode.ADD>)
Sketch Object: Text
Create text defined by text string and font size. May have difficulty finding non-system fonts depending on
platform and render default. font_path defines an exact path to a font file and overrides font.
Parameters
• txt (str) – text to render
• font_size (float) – size of the font in model units
• font (str, optional) – font name. Defaults to “Arial”
• font_path (str, optional) – system path to font file. Defaults to None
• font_style (Font_Style, optional) – font style, REGULAR, BOLD, or ITALIC. De-
faults to Font_Style.REGULAR
• align (Align | tuple[Align, Align], optional) – align MIN, CENTER, or MAX
of object. Defaults to (Align.CENTER, Align.CENTER)
• path (Edge | Wire, optional) – path for text to follow. Defaults to None
• position_on_path (float, optional) – the relative location on path to position the
text, values must be between 0.0 and 1.0. Defaults to 0.0
• rotation (float, optional) – angle to rotate object. Defaults to 0
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD
class Trapezoid(width: float, height: float, left_side_angle: float, right_side_angle: float | None = None,
rotation: float = 0, align: ~build123d.build_enums.Align | tuple[~build123d.build_enums.Align,
~build123d.build_enums.Align] | None = (<Align.CENTER>, <Align.CENTER>), mode:
~build123d.build_enums.Mode = <Mode.ADD>)
C
interior angle ‘C’ in degrees
a
length of side ‘a’
b
length of side ‘b’
c
length of side ‘c’
edge_a
edge ‘a’
edge_b
edge ‘b’
edge_c
edge ‘c’
vertex_A
vertex ‘A’
vertex_B
vertex ‘B’
vertex_C
vertex ‘C’
1.10.5 3D Objects
Box
Box defined by length, width, height
Cone
Cone defined by radii and height
CounterBoreHole
Counter bore hole defined by radii and depths
CounterSinkHole
Counter sink hole defined by radii and depth and angle
Cylinder
Cylinder defined by radius and height
Hole
Hole defined by radius and depth
Sphere
Sphere defined by radius and arc angles
Torus
Torus defined major and minor radii
Wedge
Wedge defined by lengths along multiple Axes
Reference
class BasePartObject(part: ~build123d.topology.composite.Part | ~build123d.topology.three_d.Solid, rotation:
~build123d.geometry.Rotation | tuple[float, float, float] = (0, 0, 0), align:
~build123d.build_enums.Align | tuple[~build123d.build_enums.Align,
~build123d.build_enums.Align, ~build123d.build_enums.Align] | None = None, mode:
~build123d.build_enums.Mode = <Mode.ADD>)
Base class for all BuildPart objects & operations
Parameters
• solid (Solid) – object to create
• rotation (RotationLike, optional) – angles to rotate about axes. Defaults to (0, 0, 0)
• align (Align | tuple[Align, Align, Align] | None, optional) – align MIN,
CENTER, or MAX of object. Defaults to None
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD
class Box(length: float, width: float, height: float, rotation: ~build123d.geometry.Rotation | tuple[float, float,
float] = (0, 0, 0), align: ~build123d.build_enums.Align | tuple[~build123d.build_enums.Align,
~build123d.build_enums.Align, ~build123d.build_enums.Align] = (<Align.CENTER>,
<Align.CENTER>, <Align.CENTER>), mode: ~build123d.build_enums.Mode = <Mode.ADD>)
Part Object: Box
Create a box defined by length, width, and height.
Parameters
• length (float) – box length
• width (float) – box width
• height (float) – box height
• rotation (RotationLike, optional) – angles to rotate about axes. Defaults to (0, 0, 0)
• align (Align | tuple[Align, Align, Align] | None, optional) – align
MIN, CENTER, or MAX of object. Defaults to (Align.CENTER, Align.CENTER,
Align.CENTER)
• mode (Mode, optional) – combine mode. Defaults to Mode.ADD
class Cone(bottom_radius: float, top_radius: float, height: float, arc_size: float = 360, rotation:
~build123d.geometry.Rotation | tuple[float, float, float] = (0, 0, 0), align:
~build123d.build_enums.Align | tuple[~build123d.build_enums.Align, ~build123d.build_enums.Align,
~build123d.build_enums.Align] = (<Align.CENTER>, <Align.CENTER>, <Align.CENTER>), mode:
~build123d.build_enums.Mode = <Mode.ADD>)
Part Object: Cone
Create a cone defined by bottom radius, top radius, and height.
Parameters
• bottom_radius (float) – bottom radius
• top_radius (float) – top radius, may be zero
• height (float) – cone height
Here is an example of a custom sketch object specially created as part of the design of this playing card storage box
(see the playing_cards.py example):
class Club(BaseSketchObject):
def __init__(
self,
height: float,
rotation: float = 0,
align: tuple[Align, Align] = (Align.CENTER, Align.CENTER),
mode: Mode = Mode.ADD,
(continues on next page)
Here the new custom object class is called Club and it’s a sub-class of BaseSketchObject . The __init__ method
contains all of the parameters used to instantiate the custom object, specially a height, rotation, align, and mode -
your objects may contain a sub or super set of these parameters but should always contain a mode parameter such that
it can be combined with a builder’s object.
Next is the creation of the object itself, in this case a sketch of the club suit.
The final line calls the __init__ method of the super class - i.e. BaseSketchObject with its parameters.
That’s it, now the Club object can be used anywhere a Circle would be used - with either the Algebra or Builder API.
1.11 Operations
Operations are functions that take objects as inputs and transform them into new objects. For example, a 2D Sketch
can be extruded to create a 3D Part. All operations are Python functions which can be applied using both the Algebra
and Builder APIs. It’s important to note that objects created by operations are not affected by Locations, meaning
their position is determined solely by the input objects used in the operation.
Here are a couple ways to use extrude(), in Builder and Algebra mode:
The following table summarizes all of the available operations. Operations marked as 1D are applicable to BuildLine
and Algebra Curve, 2D to BuildSketch and Algebra Sketch, 3D to BuildPart and Algebra Part.
The following table summarizes all of the selectors that can be used within the scope of a Builder. Note that they will
extract objects from the builder that is currently within scope without it being explicitly referenced.
Builder
Selector Description Line Sketch Part
edge() Select edge from current builder ✓ ✓ ✓
edges() Select edges from current builder ✓ ✓ ✓
face() Select face from current builder ✓ ✓
faces() Select faces from current builder ✓ ✓
solid() Select solid from current builder ✓
solids() Select solids from current builder ✓
vertex() Select vertex from current builder ✓ ✓ ✓
vertices() Select vertices from current builder ✓ ✓ ✓
wire() Select wire from current builder ✓ ✓ ✓
wires() Select wires from current builder ✓ ✓ ✓
1.11.1 Reference
add(objects: ~build123d.topology.one_d.Edge | ~build123d.topology.one_d.Wire | ~build123d.topology.two_d.Face
| ~build123d.topology.three_d.Solid | ~build123d.topology.composite.Compound |
~build123d.build_common.Builder | ~collections.abc.Iterable[~build123d.topology.one_d.Edge |
~build123d.topology.one_d.Wire | ~build123d.topology.two_d.Face | ~build123d.topology.three_d.Solid |
~build123d.topology.composite.Compound | ~build123d.build_common.Builder], rotation: float |
~build123d.geometry.Rotation | tuple[float, float, float] | None = None, clean: bool = True, mode:
~build123d.build_enums.Mode = <Mode.ADD>) → Compound
Generic Object: Add Object to Part or Sketch
Add an object to a builder.
BuildPart:
Edges and Wires are added to pending_edges. Compounds of Face are added to pending_faces. Solids or
Compounds of Solid are combined into the part.
BuildSketch:
Edges and Wires are added to pending_edges. Compounds of Face are added to sketch.
BuildLine:
Edges and Wires are added to line.
Parameters
• objects (Edge | Wire | Face | Solid | Compound or Iterable of ) – objects
to add
• rotation (float | RotationLike, optional) – rotation angle for sketch, rotation
about each axis for part. Defaults to None.
• clean – Remove extraneous internal structure. Defaults to True.
bounding_box(objects: ~build123d.topology.shape_core.Shape |
~collections.abc.Iterable[~build123d.topology.shape_core.Shape] | None = None, mode:
~build123d.build_enums.Mode = <Mode.PRIVATE>) → Sketch | Part
Generic Operation: Add Bounding Box
Applies to: BuildSketch and BuildPart
Add the 2D or 3D bounding boxes of the object sequence
Parameters
• objects (Shape or Iterable of ) – objects to create bbox for
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD.
chamfer(objects: Edge | Vertex | Iterable[Edge | Vertex], length: float, length2: float | None = None, angle: float |
None = None, reference: Edge | Face | None = None) → Sketch | Part
Generic Operation: chamfer
Applies to 2 and 3 dimensional objects.
Chamfer the given sequence of edges or vertices.
Parameters
• objects (Edge | Vertex or Iterable of ) – edges or vertices to chamfer
• length (float) – chamfer size
• length2 (float, optional) – asymmetric chamfer size. Defaults to None.
• angle (float, optional) – chamfer angle in degrees. Defaults to None.
• reference (Edge | Face) – identifies the side where length is measured. Edge(s) must be
part of the face. Vertex/Vertices must be part of edge
Raises
• ValueError – no objects provided
• ValueError – objects must be Edges
• ValueError – objects must be Vertices
• ValueError – Only one of length2 or angle should be provided
Returns
workplane aligned for projection
Return type
Plane
revolve(profiles: ~build123d.topology.two_d.Face | ~collections.abc.Iterable[~build123d.topology.two_d.Face] |
None = None, axis: ~build123d.geometry.Axis = ((0.0, 0.0, 0.0), (0.0, 0.0, 1.0)), revolution_arc: float =
360.0, clean: bool = True, mode: ~build123d.build_enums.Mode = <Mode.ADD>) → Part
Part Operation: Revolve
Revolve the profile or pending sketches/face about the given axis. Note that the most common use case is when
the axis is in the same plane as the face to be revolved but this isn’t required.
Parameters
• profiles (Face, optional) – 2D profile(s) to revolve.
• axis (Axis, optional) – axis of rotation. Defaults to Axis.Z.
• revolution_arc (float, optional) – angular size of revolution. Defaults to 360.0.
• clean (bool, optional) – Remove extraneous internal structure. Defaults to True.
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD.
Raises
ValueError – Invalid axis of revolution
scale(objects: ~build123d.topology.shape_core.Shape |
~collections.abc.Iterable[~build123d.topology.shape_core.Shape] | None = None, by: float | tuple[float,
float, float] = 1, mode: ~build123d.build_enums.Mode = <Mode.REPLACE>) → Curve | Sketch | Part |
Compound
Generic Operation: scale
Applies to 1, 2, and 3 dimensional objects.
Scale a sequence of objects. Note that when scaling non-uniformly across the three axes, the type of the under-
lying object may change to bspline from line, circle, etc.
Parameters
• objects (Edge | Face | Compound | Solid or Iterable of ) – objects to scale
• by (float | tuple[float, float, float]) – scale factor
• mode (Mode, optional) – combination mode. Defaults to Mode.REPLACE.
Raises
ValueError – missing objects
section(obj: ~build123d.topology.composite.Part | None = None, section_by: ~build123d.geometry.Plane |
~collections.abc.Iterable[~build123d.geometry.Plane] = Plane(o=(0.00, 0.00, 0.00), x=(1.00, 0.00, 0.00),
z=(0.00, -1.00, 0.00)), height: float = 0.0, clean: bool = True, mode: ~build123d.build_enums.Mode =
<Mode.PRIVATE>) → Sketch
Part Operation: section
Slices current part at the given height by section_by or current workplane(s).
Parameters
• obj (Part, optional) – object to section. Defaults to None.
• section_by (Plane, optional) – plane(s) to section object. Defaults to None.
• binormal (Edge | Wire, optional) – guide rotation along path. Defaults to None.
• clean (bool, optional) – Remove extraneous internal structure. Defaults to True.
• mode (Mode, optional) – combination. Defaults to Mode.ADD.
thicken(to_thicken: ~build123d.topology.two_d.Face | ~build123d.topology.composite.Sketch | None = None,
amount: float | None = None, normal_override: ~build123d.geometry.Vector | tuple[float, float] |
tuple[float, float, float] | ~collections.abc.Sequence[float] | None = None, both: bool = False, clean: bool
= True, mode: ~build123d.build_enums.Mode = <Mode.ADD>) → Part
Part Operation: thicken
Create a solid(s) from a potentially non planar face(s) by thickening along the normals.
Parameters
• to_thicken (Union[Face, Sketch], optional) – object to thicken. Defaults to None.
• amount (float) – distance to extrude, sign controls direction.
• normal_override (Vector, optional) – The normal_override vector can be used to in-
dicate which way is ‘up’, potentially flipping the face normal direction such that many faces
with different normals all go in the same direction (direction need only be +/- 90 degrees
from the face normal). Defaults to None.
• both (bool, optional) – thicken in both directions. Defaults to False.
• clean (bool, optional) – Remove extraneous internal structure. Defaults to True.
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD.
Raises
• ValueError – No object to extrude
• ValueError – No target object
Returns
extruded object
Return type
Part
trace(lines: ~build123d.topology.composite.Curve | ~build123d.topology.one_d.Edge |
~build123d.topology.one_d.Wire | ~collections.abc.Iterable[~build123d.topology.composite.Curve |
~build123d.topology.one_d.Edge | ~build123d.topology.one_d.Wire] | None = None, line_width: float = 1,
mode: ~build123d.build_enums.Mode = <Mode.ADD>) → Sketch
Sketch Operation: trace
Convert edges, wires or pending edges into faces by sweeping a perpendicular line along them.
Parameters
• lines (Curve | Edge | Wire | Iterable[Curve | Edge | Wire]], optional)
– lines to trace. Defaults to sketch pending edges.
• line_width (float, optional) – Defaults to 1.
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD.
Raises
ValueError – No objects to trace
Returns
Traced lines
Return type
Sketch
edge(self , select: ~build123d.build_enums.Select = <Select.ALL>) → Edge
Return Edge
Return an edge.
Parameters
select (Select, optional) – Edge selector. Defaults to Select.ALL.
Returns
Edge extracted
Return type
Edge
edges(self , select: ~build123d.build_enums.Select = <Select.ALL>) → ShapeList[Edge]
Return Edges
Return either all or the edges created during the last operation.
Parameters
select (Select, optional) – Edge selector. Defaults to Select.ALL.
Returns
Edges extracted
Return type
ShapeList[Edge]
face(self , select: ~build123d.build_enums.Select = <Select.ALL>) → Face
Return Face
Return a face.
Parameters
select (Select, optional) – Face selector. Defaults to Select.ALL.
Returns
Face extracted
Return type
Face
faces(self , select: ~build123d.build_enums.Select = <Select.ALL>) → ShapeList[Face]
Return Faces
Return either all or the faces created during the last operation.
Parameters
select (Select, optional) – Face selector. Defaults to Select.ALL.
Returns
Faces extracted
Return type
ShapeList[Face]
solid(self , select: ~build123d.build_enums.Select = <Select.ALL>) → Solid
Return Solid
Return a solid.
Parameters
select (Select, optional) – Solid selector. Defaults to Select.ALL.
Returns
Solid extracted
Return type
Solid
solids(self , select: ~build123d.build_enums.Select = <Select.ALL>) → ShapeList[Solid]
Return Solids
Return either all or the solids created during the last operation.
Parameters
select (Select, optional) – Solid selector. Defaults to Select.ALL.
Returns
Solids extracted
Return type
ShapeList[Solid]
vertex(self , select: ~build123d.build_enums.Select = <Select.ALL>) → Vertex
Return Vertex
Return a vertex.
Parameters
select (Select, optional) – Vertex selector. Defaults to Select.ALL.
Returns
Vertex extracted
Return type
Vertex
vertices(self , select: ~build123d.build_enums.Select = <Select.ALL>) → ShapeList[Vertex]
Return Vertices
Return either all or the vertices created during the last operation.
Parameters
select (Select, optional) – Vertex selector. Defaults to Select.ALL.
Returns
Vertices extracted
Return type
ShapeList[Vertex]
wire(self , select: ~build123d.build_enums.Select = <Select.ALL>) → Wire
Return Wire
Return a wire.
Parameters
select (Select, optional) – Wire selector. Defaults to Select.ALL.
Returns
Wire extracted
Return type
Wire
1.12 Builders
The following sections describe each of the build123d stateful context builders.
1.12.1 BuildLine
BuildLine is a python context manager that is used to create one dimensional objects - objects with the property of
length but not area - that are typically used as part of a BuildSketch sketch or a BuildPart path.
The complete API for BuildLine is located at the end of this section.
Basic Functionality
The following is a simple BuildLine example:
The with statement creates the BuildLine context manager with the identifier example_1. The objects and operations
that are within the scope (i.e. indented) of this context will contribute towards the object being created by the context
manager. For BuildLine, this object is line and it’s referenced as example_1.line.
The first object in this example is a Line object which is used to create a straight line from coordinates (0,0) to (2,0)
on the default XY plane. The second object is a ThreePointArc that starts and ends at the two ends of the line.
Constraints
Building with constraints enables the designer to capture design intent and add a high degree of robustness to their
designs. The following sections describe creating positional and tangential constraints as well as using object attributes
to enable this type of design.
@ position_at Operator
In the previous example, the ThreePointArc started and ended at the two ends of the Line but this was done by
referring to the same point (0,0) and (2,0). This can be improved upon by specifying constraints that lock the arc
to those two end points, as follows:
Here instance variables l1 and l2 are assigned to the two BuildLine objects and the ThreePointArc references the
beginning of the straight line with l1 @ 0 and the end with l1 @ 1. The @ operator takes a float (or integer) parameter
between 0 and 1 and determines a position at this fractional position along the line’s length.
This example can be improved on further by calculating the mid-point of the arc as follows:
Here l1 @ 0.5 finds the center of l1 while l1 @ 0.5 + (0, 1) does a vector addition to generate the point (1,1).
To make the design even more parametric, the height of the arc can be calculated from l1 as follows:
The arc height is now calculated as (0, l1.length / 2) by using the length property of Edge and Wire shapes.
At this point the ThreePointArc is fully parametric and able to generate the same shape for any horizontal line.
% tangent_at Operator
The other operator that is commonly used within BuildLine is % the tangent at operator. Here is another example:
BuildLine to BuildSketch
As mentioned previously, one of the two primary reasons to create BuildLine objects is to use them in BuildSketch.
When a BuildLine context manager exits and is within the scope of a BuildSketch context manager it will transfer the
generated line to BuildSketch. The BuildSketch make_face() or make_hull() operations are then used to transform
the line (specifically a list of Edges) into a Face - the native BuildSketch objects.
Here is an example of using BuildLine to create an object that otherwise might be difficult to create:
which generates:
ò Note
would translate the “club.svg” image file’s paths into BuildLine code much like that shown above. From there it’s
easy for a user to add constraints or otherwise enhance the original image and use it in their design.
BuildLine to BuildPart
The other primary reasons to use BuildLine is to create paths for BuildPart sweep() operations. Here some curved
and straight segments define a path:
which generates:
which generates:
Here the BuildLine object is created on Plane.YZ just by specifying the working plane during BuildLine initialization.
There are three rules to keep in mind when working with alternate planes in BuildLine:
1. BuildLine accepts a single Plane to work with as opposed to other Builders that accept more than one work-
plane.
2. Values entered as tuples such as (1, 2) or (1, 2, 3) will be localized to the current workplane. This rule
applies to points and to the use of tuples to modify locations calculated with the @ and % operators such as l1 @
1 + (1, 1). For example, if the workplane is Plane.YZ the local value of (1, 2) would be converted to (0,
1, 2) in global coordinates. Three tuples are converted as well - (1, 2, 3) on Plane.YZ would be (3, 1,
2) in global coordinates. Providing values in local coordinates allows the designer to automate such conversions.
3. Values entered using the Vector class or those generated by the @ operator are considered global values and
are not localized. For example: Line(Vector(1, 2, 3), Vector(4, 5, 6)) will generate the same line
independent of the current workplane. It’s unlikely that users will need to use Vector values but the option is
there.
Finally, BuildLine’s workplane need not be one of the predefined ordinal planes, it could be one created from a surface
of a BuildPart part that is currently under construction.
Reference
class BuildLine(workplane: ~build123d.topology.two_d.Face | ~build123d.geometry.Plane |
~build123d.geometry.Location = Plane(o=(0.00, 0.00, 0.00), x=(1.00, 0.00, 0.00), z=(0.00,
0.00, 1.00)), mode: ~build123d.build_enums.Mode = <Mode.ADD>)
The BuildLine class is a subclass of Builder for building lines (objects with length but not area or volume). It
has an _obj property that returns the current line being built. The class overrides the faces and solids methods
of Builder since they don’t apply to lines.
BuildLine only works with a single workplane which is used to convert tuples as inputs to global coordinates.
For example:
creates an arc from global points (0, 1, 2) to (0, 2, 1). Note that points entered as Vector(x, y, z) are considered
global and are not localized.
The workplane is also used to define planes parallel to the workplane that arcs are created on.
Parameters
• workplane (Union[Face, Plane, Location], optional) – plane used when local
coordinates are used and when creating arcs. Defaults to Plane.XY.
1.12.2 BuildSketch
BuildSketch is a python context manager that is used to create planar two dimensional objects - objects with the property
of area but not volume - that are typically used as profiles for BuildPart operations like extrude() or revolve().
The complete API for BuildSketch is located at the end of this section.
Basic Functionality
The following is a simple BuildSketch example:
The with statement creates the BuildSketch context manager with the identifier circle_with_hole. The objects
and operations that are within the scope (i.e. indented) of this context will contribute towards the object being created
by the context manager. For BuildSketch, this object is sketch and it’s referenced as circle_with_hole.sketch.
The first object in this example is a Circle object which is used to create a filled circular shape on the default XY
plane. The second object is a Rectangle that is subtracted from the circle as directed by the mode=Mode.SUBTRACT
parameter. A key aspect of sketch objects is that they are all filled shapes and not just a shape perimeter which en-
ables combining subsequent shapes with different modes (the valid values of Mode are ADD, SUBTRACT, INTERSECT,
REPLACE, and PRIVATE).
As an example, let’s build the following simple control box with a display on an angled plane:
The highlighted part of the code shows how a face is extracted from the design, a workplane is constructed from this face
and finally this workplane is passed to BuildSketch as the target for the complete sketch. Notice how the display
sketch uses local coordinates for its features thus avoiding having the user to determine how to move and rotate the
sketch to get it where it should go.
Note that BuildSketch accepts a sequence planes, faces and locations for workplanes so creation of an explicit work-
plane is often not required. Being able to work on multiple workplanes at once allows for features to be created on
multiple side of an object - say both the top and bottom - which is convenient for symmetric parts.
while the sketches as applied to their target workplanes is accessible through the sketch property, as follows:
When using the add() operation to add an external Face to a sketch the face will automatically be reoriented to Plane.
XY before being combined with the sketch. As Faces don’t provide an x-direction it’s possible that the new Face may
not be oriented as expected. To reorient the Face manually to Plane.XY one can use the to_local_coords() method
as follows:
reoriented_face = plane.to_local_coords(face)
Locating Features
Within a sketch features are positioned with Locations contexts (see Location Context) on the current workplane(s).
The following location contexts are available within a sketch:
• GridLocations : a X/Y grid of locations
• HexLocations : a hex grid of locations ideal for nesting circles
• Locations : a sequence of arbitrary locations
• PolarLocations : locations defined by radius and angle
Generally one would specify tuples of (X, Y) values when defining locations but there are many options available to
the user.
Reference
class BuildSketch(*workplanes: ~build123d.topology.two_d.Face | ~build123d.geometry.Plane |
~build123d.geometry.Location, mode: ~build123d.build_enums.Mode = <Mode.ADD>)
The BuildSketch class is a subclass of Builder for building planar 2D sketches (objects with area but not volume)
from faces or lines. It has an _obj property that returns the current sketch being built. The sketch property consists
of the sketch(es) applied to the input workplanes while the sketch_local attribute is the sketch constructed on
Plane.XY. The class overrides the solids method of Builder since they don’t apply to lines.
Note that all sketch construction is done within sketch_local on Plane.XY. When objects are added to the sketch
they must be coplanar to Plane.XY, usually handled automatically but may need user input for Edges and Wires
since their construction plane isn’t always able to be determined.
Parameters
• workplanes (Union[Face, Plane, Location], optional) – objects converted to
plane(s) to place the sketch on. Defaults to Plane.XY.
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD.
consolidate_edges() → Wire | list[Wire]
Unify pending edges into one or more Wires
property sketch
The global version of the sketch - may contain multiple sketches
property sketch_local: Sketch | None
Get the builder’s object
solid(*args)
solid() not implemented
solids(*args)
solids() not implemented
1.12.3 BuildPart
BuildPart is a python context manager that is used to create three dimensional objects - objects with the property of
volume - that are typically finished parts.
The complete API for BuildPart is located at the end of this section.
Basic Functionality
The following is a simple BuildPart example:
The with statement creates the BuildPart context manager with the identifier ex2 (this code is the second of the
introductory examples). The objects and operations that are within the scope (i.e. indented) of this context will con-
tribute towards the object being created by the context manager. For BuildPart, this object is part and it’s referenced
as ex2.part.
The first object in this example is a Box object which is used to create a polyhedron with rectangular faces centered on
the default Plane.XY. The second object is a Cylinder that is subtracted from the box as directed by the mode=Mode.
SUBTRACT parameter thus creating a hole.
Implicit Parameters
The BuildPart context keeps track of pending objects such that they can be used implicitly - there are a couple things
to consider when deciding how to proceed:
• For sketches, the planes that they were constructed on is maintained in internal data structures such that operations
like extrude() will have a good reference for the extrude direction. One can pass a Face to extrude but it will
then be forced to use the normal direction at the center of the Face as the extrude direction which unfortunately
can be reversed in some circumstances.
• Implicit parameters save some typing but hide some functionality - users have to decide what works best for
them.
This tea cup example uses implicit parameters - note the sweep() operation on the last line:
wall_thickness = 3 * MM
fillet_radius = wall_thickness * 0.49
sweep() requires a 2D cross section - handle_cross_section - and a path - handle_path - which are both passed
implicitly.
Units
Parts created with build123d have no inherent units associated with them. However, when exporting parts to external
formats like STL or STEP the units are assumed to be millimeters (mm). To be more explicit with units one can use
the technique shown in the above tea cup example where linear dimensions are followed by * MM which multiplies the
dimension by the MM scaling factor - in this case 1.
The following dimensional constants are pre-defined:
MM = 1
CM = 10 * MM
M = 1000 * MM
IN = 25.4 * MM
FT = 12 * IN
THOU = IN / 1000
Some export formats like DXF have the ability to explicitly set the units used.
Reference
class BuildPart(*workplanes: ~build123d.topology.two_d.Face | ~build123d.geometry.Plane |
~build123d.geometry.Location, mode: ~build123d.build_enums.Mode = <Mode.ADD>)
The BuildPart class is another subclass of Builder for building parts (objects with the property of volume) from
sketches or 3D objects. It has an _obj property that returns the current part being built, and several pending
lists for storing faces, edges, and planes that will be integrated into the final part later. The class overrides the
_add_to_pending method of Builder.
Parameters
• workplanes (Plane, optional) – initial plane to work on. Defaults to Plane.XY.
• mode (Mode, optional) – combination mode. Defaults to Mode.ADD.
property location: Location | None
Builder’s location
property part: Part | None
Get the current part
property pending_edges_as_wire: Wire
Return a wire representation of the pending edges
1.13 Joints
Joint’s enable Solid and Compound objects to be arranged relative to each other in an intuitive manner - with the
same degree of motion that is found with the equivalent physical joints. Joint’s always work in pairs - a Joint can
only be connected to another Joint as follows:
Objects may have many joints bound to them each with an identifying label. All Joint objects have a symbol property
that can be displayed to help visualize their position and orientation (the ocp-vscode viewer has built-in support for
displaying joints).
ò Note
If joints are created within the scope of a BuildPart builder, the to_part parameter need not be specified as the
builder will, on exit, automatically transfer the joints created in its scope to the part created.
The following sections provide more detail on the available joints and describes how they are used.
Once a joint is bound to a part this way, the connect_to() method can be used to repositioning another part relative
to self which stay fixed - as follows:
pipe.joints["outlet"].connect_to(flange_outlet.joints["pipe"])
ò Note
The connect_to() method only does a one time re-position of a part and does not bind them in any way; however,
putting them into an Assemblies will maintain there relative locations as will combining parts with boolean operations
or within a BuildPart context.
As a example of creating parts with joints and connecting them together, consider the following code where flanges are
attached to the ends of a curved pipe:
import copy
from build123d import *
from bd_warehouse.flange import WeldNeckFlange
from bd_warehouse.pipe import PipeSection
from ocp_vscode import *
Note how the locations of the joints are determined by the location_at() method and how the - negate operator
is used to reverse the direction of the location without changing its poosition. Also note that the WeldNeckFlange
class predefines two joints, one at the pipe end and one at the face end - both of which are shown in the above image
(generated by ocp-vscode with the render_joints=True flag set in the show function).
class RigidJoint(label: str, to_part: Solid | Compound | None = None, joint_location: Location | None = None)
A rigid joint fixes two components to one another.
Parameters
• label (str) – joint label
• to_part (Union[Solid, Compound], optional) – object to attach joint to
• joint_location (Location) – global location of joint
Variables
relative_location (Location) – joint location relative to bound object
connect_to(other: BallJoint, *, angles: Rotation | tuple[float, float, float] | None = None, **kwargs)
connect_to(other: CylindricalJoint, *, position: float | None = None, angle: float | None = None)
connect_to(other: LinearJoint, *, position: float | None = None)
connect_to(other: RevoluteJoint, *, angle: float | None = None)
connect_to(other: RigidJoint)
Connect the RigidJoint to another Joint
Parameters
• other (Joint) – joint to connect to
• angle (float, optional) – angle in degrees. Defaults to range min.
• angles (RotationLike, optional) – angles about axes in degrees. Defaults to range
minimums.
• position (float, optional) – linear position. Defaults to linear range min.
# show(latch.part, render_joints=True)
# show(slide.part, render_joints=True)
show(latch.part, slide.part, render_joints=True)
Note how the slide is constructed in a different orientation than the direction of motion. The three highlighted lines of
code show how the joints are created and connected together:
• The LinearJoint has an axis and limits of movement
• The RigidJoint has a single location, orientated such that the knob will ultimately be “up”
• The connect_to specifies a position that must be within the predefined limits.
The slider can be moved back and forth by just changing the position value. Values outside of the limits will raise
an exception.
class LinearJoint(label: str, to_part: Solid | Compound | None = None, axis: Axis = ((0.0, 0.0, 0.0), (0.0, 0.0,
1.0)), linear_range: tuple[float, float] = (0, inf))
Component moves along a single axis.
Parameters
• label (str) – joint label
• to_part (Union[Solid, Compound], optional) – object to attach joint to
• axis (Axis) – axis of linear motion
• range (tuple[float, float], optional) – (min,max) position of joint. Defaults to
(0, inf).
Variables
• axis (Axis) – joint axis
• angle (float) – angle of joint
• linear_range (tuple[float,float]) – min and max positional values
• position (float) – joint position
• relative_axis (Axis) – joint axis relative to bound part
connect_to(other: RevoluteJoint, *, position: float | None = None, angle: float | None = None)
connect_to(other: RigidJoint, *, position: float | None = None)
Connect LinearJoint to another Joint
Parameters
• other (Joint) – joint to connect to
• angle (float, optional) – angle in degrees. Defaults to range min.
• position (float, optional) – linear position. Defaults to linear range min.
Raises
• TypeError – other must be of type RevoluteJoint or RigidJoint
• ValueError – position out of range
• ValueError – angle out of range
property location: Location
Location of joint
relative_to(other: RigidJoint, *, position: float | None = None)
relative_to(other: RevoluteJoint, *, position: float | None = None, angle: float | None = None)
Relative location of LinearJoint to RevoluteJoint or RigidJoint
Parameters
• other (Joint) – joint to connect to
• angle (float, optional) – angle in degrees. Defaults to range min.
• position (float, optional) – linear position. Defaults to linear range min.
Raises
• TypeError – other must be of type RevoluteJoint or RigidJoint
• ValueError – position out of range
• ValueError – angle out of range
property symbol: Compound
A CAD symbol of the linear axis positioned relative to_part
show(rod_end.part, ball.part)
Note how limits are defined during the instantiation of the ball joint when ensures that the pin or bolt within the rod
end does not interfere with the rod end itself. The connect_to sets the three angles (only two are significant in this
example).
class BallJoint(label: str, to_part: Solid | Compound | None = None, joint_location: Location | None = None,
angular_range: tuple[tuple[float, float], tuple[float, float], tuple[float, float]] = ((0, 360), (0,
360), (0, 360)), angle_reference: Plane = Plane(o=(0.00, 0.00, 0.00), x=(1.00, 0.00, 0.00),
z=(0.00, 0.00, 1.00)))
A component rotates around all 3 axes using a gimbal system (3 nested rotations).
Parameters
• label (str) – joint label
• to_part (Union[Solid, Compound], optional) – object to attach joint to
• joint_location (Location) – global location of joint
• angular_range – (tuple[ tuple[float, float], tuple[float, float], tuple[float, float] ], optional):
X, Y, Z angle (min, max) pairs. Defaults to ((0, 360), (0, 360), (0, 360)).
• angle_reference (Plane, optional) – plane relative to part defining zero degrees of
rotation. Defaults to Plane.XY.
Variables
• relative_location (Location) – joint location relative to bound part
• angular_range – (tuple[ tuple[float, float], tuple[float, float], tuple[float, float] ]): X, Y, Z
angle (min, max) pairs.
• angle_reference (Plane) – plane relative to part defining zero degrees of
connect_to(other: RigidJoint, *, angles: Rotation | tuple[float, float, float] | None = None)
Connect BallJoint and RigidJoint
Parameters
• other (RigidJoint) – joint to connect to
• angles (RotationLike, optional) – angles about axes in degrees. Defaults to range
minimums.
Raises
• TypeError – invalid other joint type
• ValueError – angles out of range
property location: Location
Location of joint
relative_to(other: RigidJoint, *, angles: Rotation | tuple[float, float, float] | None = None)
relative_to - BallJoint
Return the relative location from this joint to the RigidJoint of another object
Parameters
• other (RigidJoint) – joint to connect to
• angles (RotationLike, optional) – angles about axes in degrees. Defaults to range
minimums.
Raises
• TypeError – invalid other joint type
• ValueError – angles out of range
property symbol: Compound
A CAD symbol representing joint as bound to part
1.14 Assemblies
Most CAD designs consist of more than one part which are naturally arranged in some type of assembly. Once parts
have been assembled in a Compound object they can be treated as a unit - i.e. moved() or exported.
To create an assembly in build123d, one needs to create a tree of parts by simply assigning either a Compound object’s
parent or children attributes. To illustrate the process, we’ll extend the Joint Tutorial.
box.label = "box"
lid.label = "lid"
hinge_outer.label = "outer hinge"
hinge_inner.label = "inner hinge"
m6_screw.label = "M6 screw"
The labels are just strings with no further limitations (they don’t have to be unique within the assembly).
To display the topology of an assembly Compound, the show_topology() method can be used as follows:
print(box_assembly.show_topology())
To add to an assembly Compound one can change either children or parent attributes.
m6_screw.parent = box_assembly
print(box_assembly.show_topology())
CAD object which instead is a reference to the original (OpenCascade refers this as a TShape). As it’s a reference any
changes to the original will be seen in all of the shallow copies.
Consider this example where 100 screws are added to an assembly:
screw = import_step("M6-1x12-countersunk-screw.step")
locs = HexLocations(6, 10, 10).local_locations
which takes about 5 seconds to run (on an older computer) and produces a file of size 51938 KB. However, if a shallow
copy is used instead:
screw = import_step("M6-1x12-countersunk-screw.step")
locs = HexLocations(6, 10, 10).local_locations
this takes about ¼ second and produces a file of size 550 KB - just over 1% of the size of the deepcopy() version and
only 12% larger than the screw’s step file.
Using copy.copy() to create references to the original CAD object for assemblies can substantially reduce the time
and resources used to create and store that assembly.
ò Note
# [import]
from build123d import *
from ocp_vscode import *
1.14.6 pack
The pack.pack() function arranges objects in a compact, non-overlapping layout within a square(ish) 2D area. It is
designed to minimize the space between objects while ensuring that no two objects overlap.
pack(objects: Collection[Shape], padding: float, align_z: bool = False) → Collection[Shape]
Pack objects in a squarish area in Plane.XY.
Parameters
• objects (Collection[Shape]) – objects to arrange
• padding (float) – space between objects
• align_z (bool, optional) – align shape bottoms to Plane.XY. Defaults to False.
Returns
rearranged objects
Return type
Collection[Shape]
Detailed Description
The pack function uses a bin-packing algorithm to efficiently place objects within a 2D plane, ensuring that there is no
overlap and that the space between objects is minimized. This is particularly useful in scenarios where spatial efficiency
is crucial, such as layout design and object arrangement in constrained spaces.
The function begins by calculating the bounding boxes for each object, including the specified padding. It then uses
a helper function _pack2d to determine the optimal positions for each object within the 2D plane. The positions are
then translated back to the original objects, ensuring that they are arranged without overlapping.
Usage Note
The align_z parameter is especially useful when creating print-plates for 3D printing. By aligning the bottoms of the
shapes to the same XY plane, you ensure that the objects are perfectly positioned for slicing software, which will no
longer need to perform this alignment for you. This can streamline the process and improve the accuracy of the print
setup.
Example Usage
# [import]
from build123d import *
from ocp_vscode import *
# [initial space]
b1 = Box(100, 100, 100, align=(Align.CENTER, Align.CENTER, Align.MIN))
b2 = Box(54, 54, 54, align=(Align.CENTER, Align.CENTER, Align.MAX), mode=Mode.SUBTRACT)
b3 = Box(34, 34, 34, align=(Align.MIN, Align.MIN, Align.CENTER), mode=Mode.SUBTRACT)
b4 = Box(24, 24, 24, align=(Align.MAX, Align.MAX, Align.CENTER), mode=Mode.SUBTRACT)
# [pack 2D]
xy_pack = pack(
[b1, b2, b3, b4],
padding=5,
align_z=False
)
z_pack = pack(
[b1, b2, b3, b4],
padding=5,
align_z=True
)
Tip
If you place the arranged objects into a Compound, you can easily determine their bounding box and check whether the
objects fit on your print bed.
# [bounding box]
print(Compound(xy_pack).bounding_box())
# bbox: 0.0 <= x <= 159.0, 0.0 <= y <= 129.0, -54.0 <= z <= 100.0
print(Compound(z_pack).bounding_box())
# bbox: 0.0 <= x <= 159.0, 0.0 <= y <= 129.0, 0.0 <= z <= 100.0
1.15.2 2D before 3D
When creating complex 3D objects, it is generally best to start with 2D work before moving on to 3D. This is because
3D structures are much more intricate, and 3D operations can be slower and more prone to failure. For designers
who come from a Constructive Solid Geometry (CSG) background, such as OpenSCAD, this approach may seem
counterintuitive. On the other hand, designers from a GUI BREP CAD background, like Fusion 360 or SolidWorks,
may find this approach more natural.
In practice, this means that 3D objects are often created by applying operations like extrude() or revolve() to 2D
sketches, as shown below:
With this structure part_profile may have many objects that are combined and modified by operations like fillet()
before being extruded to a 3D shape.
1.15.4 Parameterize
One of the most powerful features of build123d is the ability to design fully parameterized parts. While it may be faster
to use a GUI CAD package for the initial iteration of a part, subsequent iterations can prove frustratingly difficult. By
using variables for critical dimensions and deriving other dimensions from these key variables, not only can a single
part be created, but a whole set of parts can be readily available. When inevitable change requests arise, a simple
parameter adjustment may be all that’s required to make necessary modifications.
When selecting edges to be chamfered one might first select the face that these edges belong to then select the edges as
shown here:
b3d_solid.wrapped = cq_solid.wrapped
cq_solid = cq.Solid.makeBox(1,1,1)
cq_solid.wrapped = b123d_box.part.solid().wrapped
By default, the original Z value of all objects packed using the pack.pack() function is preserved. If you want to align
all objects so that they are “placed” on the zero Z coordinate, the pack() function has an align_z argument. When set
to True, this will align all objects.
This can be useful, for example, when preparing print setups for 3D printing, giving you full control over this alignment
so you don’t have to leave it to the slicer.
In this case the circle is not positioned in the top right as one would expect; in-fact, the position of the circle randomly
switches between the bottom and top corner.
This is because all sketches are created on a local Plane.XY independent of where they will be ultimately placed;
therefore, the sort_by(Axis.Z) is sorting two points that have a Z value of zero as they are located on Plane.XY and
effectively return a random point.
Why does BuildSketch work this way? Consider an example where the user wants to work on a plane not aligned
with any Axis, as follows (this is often done when creating a sketch on a Face of a 3D part but is simulated here by
rotating a Plane):
Here one can see both sketch_local (with the light fill on Plane.XY) and the sketch (with the darker fill) placed
on the user provided workplane. As the selectors work off global coordinates, selection of the “top right” of this sketch
would be quite challenging and would likely change if the sketch was ever moved as could happen if the 3D part
changed. For an example of sketching on a 3D part, see Sketching on other Planes.
1.15.12 Why is BuildLine not working as expected within the scope of BuildSketch?
As described above, all sketching is done on a local Plane.XY; however, the following is a common issue:
Here BuildLine is within the scope of BuildSketch; therefore, all of the drawing should be done on Plane.XY;
however, the user has specified Plane.XZ when creating the BuildLine instance. Although this isn’t absolutely
incorrect it’s almost certainly not what the user intended. Here the face created by make_face will be reoriented to
Plane.XY as all sketching must be done on that plane. This reorienting of objects to Plane.XY allows a user to add
content from other sources to the sketch without having to manually re-orient the object.
Unless there is a good reason and the user understands how the BuildLine object will be reoriented, all BuildLine
instances within the scope of BuildSketch should be done on the default Plane.XY.
1.16 Import/Export
Methods and functions specific to exporting and importing build123d objects are defined below.
For example:
BREP
The BREP (Boundary Representation) file format is a widely used data format in computer-aided design (CAD) and
computer-aided engineering (CAE) applications. BREP represents 3D geometry using topological entities like vertices,
edges, and faces, along with their connectivity information. It provides a precise and comprehensive representation of
complex 3D models, making it suitable for advanced modeling and analysis tasks. BREP files are widely supported
by various CAD software, enabling seamless data exchange between different systems. Its ability to represent both
geometric shapes and their topological relationships makes it a fundamental format for storing and sharing detailed 3D
models.
DXF
The DXF (Drawing Exchange Format) file format is a widely used standard for representing 2D and 3D drawings,
primarily used in computer-aided design (CAD) applications. Developed by Autodesk, DXF files store graphical and
geometric data, such as lines, arcs, circles, and text, as well as information about layers, colors, and line weights. Due to
its popularity, DXF files can be easily exchanged and shared between different CAD software. The format’s simplicity
and human-readable structure make it a versatile choice for sharing designs, drawings, and models across various CAD
platforms, facilitating seamless collaboration in engineering and architectural projects.
glTF
The glTF (GL Transmission Format) is a royalty-free specification for the efficient transmission and loading of 3D
models and scenes by applications. Developed by the Khronos Group, glTF is designed as a compact, interoperable
format that enables the quick display of assets across various platforms and devices. glTF supports a rich feature set,
including detailed meshes, materials, textures, skeletal animations, and more, facilitating complex 3D visualizations. It
streamlines the process of sharing and deploying 3D content in web applications, game engines, and other visualization
tools, making it the “JPEG of 3D.” glTF’s versatility and efficiency have led to its widespread adoption in the 3D content
industry.
STL
The STL (STereoLithography) file format is a widely used file format in 3D printing and computer-aided design (CAD)
applications. It represents 3D geometry using triangular facets to approximate the surface of a 3D model. STL files
are widely supported and can store both the geometry and color information of the model. They are used for rapid
prototyping and 3D printing, as they provide a simple and efficient way to represent complex 3D objects. The format’s
popularity stems from its ease of use, platform independence, and ability to accurately describe the surface of intricate
3D models with a minimal file size.
STEP
The STEP (Standard for the Exchange of Product model data) file format is a widely used standard for representing 3D
product and manufacturing data in computer-aided design (CAD) and computer-aided engineering (CAE) applications.
It is an ISO standard (ISO 10303) and supports the representation of complex 3D geometry, product structure, and
metadata. STEP files store information in a neutral and standardized format, making them highly interoperable across
different CAD/CAM software systems. They enable seamless data exchange between various engineering disciplines,
facilitating collaboration and data integration throughout the entire product development and manufacturing process.
SVG
The SVG (Scalable Vector Graphics) file format is an XML-based standard used for describing 2D vector graphics.
It is widely supported and can be displayed in modern web browsers, making it suitable for web-based graphics and
interactive applications. SVG files define shapes, paths, text, and images using mathematical equations, allowing for
smooth scalability without loss of quality. The format is ideal for logos, icons, illustrations, and other graphics that
require resolution independence. SVG files are also easily editable in text editors or vector graphic software, making
them a popular choice for designers and developers seeking flexible and versatile graphic representation.
1.16.2 2D Exporters
Exports to DXF (Drawing Exchange Format) and SVG (Scalable Vector Graphics) are provided by the 2D Exporters:
ExportDXF and ExportSVG classes.
DXF is a widely used file format for exchanging CAD (Computer-Aided Design) data between different software ap-
plications. SVG is a widely used vector graphics format that is supported by web browsers and various graphic editors.
The core concept to these classes is the creation of a DXF/SVG document with specific properties followed by the
addition of layers and shapes to the documents. Once all of the layers and shapes have been added, the document can
be written to a file.
3D to 2D Projection
There are a couple ways to generate a 2D drawing of a 3D part:
• Generate a section: The section() operation can be used to create a 2D cross section of a 3D part at a given
plane.
• Generate a projection: The project_to_viewport() method can be used to create a 2D projection of a 3D
scene. Similar to a camera, the viewport_origin defines the location of camera, the viewport_up defines
the orientation of the camera, and the look_at parameter defined where the camera is pointed. By default,
viewport_up is the positive z axis and look_up is the center of the shape. The return value is a tuple of lists
of edges, the first the visible edges and the second the hidden edges.
Each of these Edges and Faces can be assigned different line color/types and fill colors as described below (as
project_to_viewport only generates Edges, fill doesn’t apply). The shapes generated from the above steps are
to be added as shapes in one of the exporters described below and written as either a DXF or SVG file as shown in this
example:
LineType
ANSI (American National Standards Institute) and ISO (International Organization for Standardization) standards both
define line types in drawings used in DXF and SVG exported drawings:
• ANSI Standards:
– ANSI/ASME Y14.2 - “Line Conventions and Lettering” is the standard that defines line types, line
weights, and line usage in engineering drawings in the United States.
• ISO Standards:
– ISO 128 - “Technical drawings – General principles of presentation” is the ISO standard that covers
the general principles of technical drawing presentation, including line types and line conventions.
– ISO 13567 - “Technical product documentation (TPD) – Organization and naming of layers for CAD”
provides guidelines for the organization and naming of layers in Computer-Aided Design (CAD) sys-
tems, which may include line type information.
These standards help ensure consistency and clarity in technical drawings, making it easier for engineers, designers,
and manufacturers to communicate and interpret the information presented in the drawings.
The line types used by the 2D Exporters are defined by the LineType Enum and are shown in the following diagram:
ExportDXF
class ExportDXF(version: str = 'AC1027', unit: ~build123d.build_enums.Unit = <Unit.MM>, color:
~exporters.ColorIndex | None = None, line_weight: float | None = None, line_type:
~exporters.LineType | None = None)
The ExportDXF class provides functionality for exporting 2D shapes to DXF (Drawing Exchange Format) format.
DXF is a widely used file format for exchanging CAD (Computer-Aided Design) data between different software
applications.
Parameters
• version (str, optional) – The DXF version to use for the output file. Defaults to
ezdxf.DXF2013.
• unit (Unit, optional) – The unit used for the exported DXF. It should be one of the Unit
enums: Unit.MC, Unit.MM, Unit.CM, Unit.M, Unit.IN, or Unit.FT. Defaults to Unit.MM.
• color (Optional[ColorIndex], optional) – The default color index for shapes. It can
be specified as a ColorIndex enum or None.. Defaults to None.
• line_weight (Optional[float], optional) – The default line weight (stroke width)
for shapes, in millimeters. . Defaults to None.
• line_type (Optional[LineType], optional) – e default line type for shapes. It should
be a LineType enum or None.. Defaults to None.
Example
Raises
ValueError – unit not supported
METRIC_UNITS = {<Unit.CM>, <Unit.M>, <Unit.MM>}
add_layer(name: str, *, color: ColorIndex | None = None, line_weight: float | None = None, line_type:
LineType | None = None) → Self
Adds a new layer to the DXF export with the given properties.
Parameters
• name (str) – The name of the layer definition. Must be unique among all layers.
• color (Optional[ColorIndex], optional) – The color index for shapes on this layer.
It can be specified as a ColorIndex enum or None. Defaults to None.
• line_weight (Optional[float], optional) – The line weight (stroke width) for
shapes on this layer, in millimeters. Defaults to None.
• line_type (Optional[LineType], optional) – The line type for shapes on this layer.
It should be a LineType enum or None. Defaults to None.
Returns
DXF document with additional layer
Return type
Self
add_shape(shape: Shape | Iterable[Shape], layer: str = '') → Self
Adds a shape to the specified layer.
Parameters
• shape (Shape | Iterable[Shape]) – The shape or collection of shapes to be added. It
can be a single Shape object or an iterable of Shape objects.
• layer (str, optional) – The name of the layer where the shape will be added. If not
specified, the default layer will be used. Defaults to “”.
Returns
Document with additional shape
Return type
Self
write(file_name: PathLike | str | bytes)
Writes the DXF data to the specified file name.
Parameters
file_name (PathLike | str | bytes) – The file name (including path) where the DXF
data will be written.
ExportSVG
class ExportSVG(unit: ~build123d.build_enums.Unit = <Unit.MM>, scale: float = 1, margin: float = 0,
fit_to_stroke: bool = True, precision: int = 6, fill_color: ~exporters.ColorIndex |
~ezdxf.colors.RGB | ~build123d.geometry.Color | None = None, line_color:
~exporters.ColorIndex | ~ezdxf.colors.RGB | ~build123d.geometry.Color | None =
ColorIndex.BLACK, line_weight: float = 0.09, line_type: ~exporters.LineType =
LineType.CONTINUOUS, dot_length: ~exporters.DotLength | float =
DotLength.INKSCAPE_COMPAT )
SVG file export functionality.
The ExportSVG class provides functionality for exporting 2D shapes to SVG (Scalable Vector Graphics) format.
SVG is a widely used vector graphics format that is supported by web browsers and various graphic editors.
Parameters
• unit (Unit, optional) – The unit used for the exported SVG. It should be one of the Unit
enums: Unit.MM, Unit.CM, or Unit.IN. Defaults to Unit.MM.
• scale (float, optional) – The scaling factor applied to the exported SVG. Defaults to
1.
• margin (float, optional) – The margin added around the exported shapes. Defaults to
0.
• fit_to_stroke (bool, optional) – A boolean indicating whether the SVG view box
should fit the strokes of the shapes. Defaults to True.
• precision (int, optional) – The number of decimal places used for rounding coordi-
nates in the SVG. Defaults to 6.
• fill_color (ColorIndex | RGB | None, optional) – The default fill color for
shapes. It can be specified as a ColorIndex, an RGB tuple, or None. Defaults to None.
• line_color (ColorIndex | RGB | None, optional) – The default line color for
shapes. It can be specified as a ColorIndex or an RGB tuple, or None. Defaults to Ex-
port2D.DEFAULT_COLOR_INDEX.
• line_weight (float, optional) – The default line weight (stroke width) for shapes, in
millimeters. Defaults to Export2D.DEFAULT_LINE_WEIGHT.
• line_type (LineType, optional) – The default line type for shapes. It should be a Line-
Type enum. Defaults to Export2D.DEFAULT_LINE_TYPE.
• dot_length (DotLength | float, optional) – The width of rendered dots in a
Can be either a DotLength enum or a float value in tenths of an inch. Defaults to
DotLength.INKSCAPE_COMPAT.
Example
Raises
ValueError – Invalid unit.
add_layer(name: str, *, fill_color: ColorIndex | RGB | Color | None = None, line_color: ColorIndex | RGB |
Color | None = ColorIndex.BLACK, line_weight: float = 0.09, line_type: LineType =
LineType.CONTINUOUS) → Self
Adds a new layer to the SVG export with the given properties.
Parameters
• name (str) – The name of the layer. Must be unique among all layers.
• fill_color (ColorIndex | RGB | Color | None, optional) – The fill color for
shapes on this layer. It can be specified as a ColorIndex, an RGB tuple, a Color, or None.
Defaults to None.
• line_color (ColorIndex | RGB | Color | None, optional) – The line color for
shapes on this layer. It can be specified as a ColorIndex or an RGB tuple, a Color, or None.
Defaults to Export2D.DEFAULT_COLOR_INDEX.
• line_weight (float, optional) – The line weight (stroke width) for shapes on this
layer, in millimeters. Defaults to Export2D.DEFAULT_LINE_WEIGHT.
• line_type (LineType, optional) – The line type for shapes on this layer. It should be
a LineType enum. Defaults to Export2D.DEFAULT_LINE_TYPE.
Raises
• ValueError – Duplicate layer name
• ValueError – Unknown linetype
Returns
Drawing with an additional layer
Return type
Self
add_shape(shape: Shape | Iterable[Shape], layer: str = '', reverse_wires: bool = False)
Adds a shape or a collection of shapes to the specified layer.
Parameters
• shape (Shape | Iterable[Shape]) – The shape or collection of shapes to be added. It
can be a single Shape object or an iterable of Shape objects.
• layer (str, optional) – The name of the layer where the shape(s) will be added. De-
faults to “”.
• reverse_wires (bool, optional) – A boolean indicating whether the wires of the
shape(s) should be in reversed direction. Defaults to False.
Raises
ValueError – Undefined layer
1.16.3 3D Exporters
export_brep(to_export: Shape, file_path: PathLike | str | bytes | BytesIO) → bool
Export this shape to a BREP file
Parameters
• to_export (Shape) – object or assembly
• file_path – Union[PathLike, str, bytes, BytesIO]: brep file path or memory buffer
Returns
write status
Return type
bool
export_gltf(to_export: ~build123d.topology.shape_core.Shape, file_path: ~os.PathLike | str | bytes, unit:
~build123d.build_enums.Unit = <Unit.MM>, binary: bool = False, linear_deflection: float = 0.001,
angular_deflection: float = 0.1) → bool
The glTF (GL Transmission Format) specification primarily focuses on the efficient transmission and loading
of 3D models as a compact, binary format that is directly renderable by graphics APIs like WebGL, OpenGL,
and Vulkan. It’s designed to store detailed 3D model data, including meshes (vertices, normals, textures, etc.),
animations, materials, and scene hierarchy, among other aspects.
Parameters
• to_export (Shape) – object or assembly
• file_path (Union[PathLike, str, bytes]) – glTF file path
• unit (Unit, optional) – shape units. Defaults to Unit.MM.
• binary (bool, optional) – output format. Defaults to False.
• linear_deflection (float, optional) – A linear deflection setting which limits the
distance between a curve and its tessellation. Setting this value too low will result in large
meshes that can consume computing resources. Setting the value too high can result in
meshes with a level of detail that is too low. The default is a good starting point for a range
of cases. Defaults to 1e-3.
• angular_deflection (float, optional) – Angular deflection setting which limits the
angle between subsequent segments in a polyline. Defaults to 0.1.
Raises
RuntimeError – Failed to write glTF file
Returns
write status
Return type
bool
export_step(to_export: ~build123d.topology.shape_core.Shape, file_path: ~os.PathLike | str | bytes, unit:
~build123d.build_enums.Unit = <Unit.MM>, write_pcurves: bool = True, precision_mode:
~build123d.build_enums.PrecisionMode = <PrecisionMode.AVERAGE>) → bool
Export a build123d Shape or assembly with color and label attributes. Note that if the color of a node in an
assembly isn’t set, it will be assigned the color of its nearest ancestor.
Parameters
• to_export (Shape) – object or assembly
• file_path (Union[PathLike, str, bytes]) – step file path
• unit (Unit, optional) – shape units. Defaults to Unit.MM.
• write_pcurves (bool, optional) – write parametric curves to the STEP file. Defaults
to True.
• precision_mode (PrecisionMode, optional) – geometric data precision. Defaults to
PrecisionMode.AVERAGE.
Raises
RuntimeError – Unknown Compound type
Returns
success
Return type
bool
export_stl(to_export: Shape, file_path: PathLike | str | bytes, tolerance: float = 0.001, angular_tolerance: float =
0.1, ascii_format: bool = False) → bool
Export STL
Exports a shape to a specified STL file.
Parameters
• to_export (Shape) – object or assembly
• file_path (str) – The path and file name to write the STL output to.
• tolerance (float, optional) – A linear deflection setting which limits the distance be-
tween a curve and its tessellation. Setting this value too low will result in large meshes that
can consume computing resources. Setting the value too high can result in meshes with a
level of detail that is too low. The default is a good starting point for a range of cases. Defaults
to 1e-3.
• angular_tolerance (float, optional) – Angular deflection setting which limits the
angle between subsequent segments in a polyline. Defaults to 0.1.
• ascii_format (bool, optional) – Export the file as ASCII (True) or binary (False) STL
format. Defaults to False (binary).
Returns
Success
Return type
bool
3D Mesh Export
Both 3MF and STL export (and import) are provided with the Mesher class. As mentioned above, the 3MF format it
provides is feature-rich and therefore has a slightly more complex API than the simple Shape exporters.
For example:
Parameters
• Union[PathLike (file_name) – file path
• str – file path
• bytes] – file path
Raises
ValueError – Unknown file format - must be 3mf or stl
Returns
build123d shapes extracted from mesh file
Return type
list[Shape]
property triangle_counts: list[int]
Number of triangles in each of the model’s meshes
property vertex_counts: list[int]
Number of vertices in each of the models’s meshes
Parameters
• Union[Pathlike (file_name) – file path
• str – file path
• bytes] – file path
Raises
ValueError – Unknown file format - must be 3mf or stl
ò Note
If you need to align multiple components for 3D printing, you can use the pack() function to arrange the objects
side by side and align them on the same plane. This ensures that your components are well-organized and ready for
the printing process.
1.16.4 2D Importers
import_svg(svg_file: str | ~pathlib.Path | ~typing.TextIO, *, flip_y: bool = True, align:
~build123d.build_enums.Align | tuple[~build123d.build_enums.Align, ~build123d.build_enums.Align]
| None = <Align.MIN>, ignore_visibility: bool = False, label_by: ~typing.Literal['id', 'class',
'inkscape:label'] | str = 'id', is_inkscape_label: bool | None = None) → ShapeList[Wire | Face]
Parameters
• svg_file (Union[str, Path , TextIO]) – svg file
• flip_y (bool, optional) – flip objects to compensate for svg orientation. Defaults to
True.
• align (Align | tuple[Align, Align] | None, optional) – alignment of the
SVG’s viewbox, if None, the viewbox’s origin will be at (0,0,0). Defaults to Align.MIN.
• ignore_visibility (bool, optional) – Defaults to False.
• label_by (str, optional) – XML attribute to use for imported shapes’ label property.
Defaults to “id”. Use inkscape:label to read labels set from Inkscape’s “Layers and Objects”
panel.
Raises
ValueError – unexpected shape type
Returns
objects contained in svg
Return type
ShapeList[Union[Wire, Face]]
import_svg_as_buildline_code(file_name: PathLike | str | bytes) → tuple[str, str]
translate_to_buildline_code
Translate the contents of the given svg file into executable build123d/BuildLine code.
Parameters
file_name (Union[PathLike, str, bytes]) – svg file name
Returns
code, builder instance name
Return type
tuple[str, str]
1.16.5 3D Importers
import_brep(file_name: PathLike | str | bytes) → Shape
Import shape from a BREP file
Parameters
file_name (Union[PathLike, str, bytes]) – brep file
Raises
ValueError – file not found
Returns
build123d object
Return type
Shape
import_step(filename: PathLike | str | bytes) → Compound
Extract shapes from a STEP file and return them as a Compound object.
Parameters
file_name (Union[PathLike, str, bytes]) – file path of STEP file to import
Raises
ValueError – can’t open file
Returns
contents of STEP file
Return type
Compound
import_stl(file_name: PathLike | str | bytes) → Face
Extract shape from an STL file and return it as a Face reference object.
Note that importing with this method and creating a reference is very fast while creating an editable model (with
Mesher) may take minutes depending on the size of the STL file.
Parameters
file_name (Union[PathLike, str, bytes]) – file path of STL file to import
Raises
ValueError – Could not import file
Returns
STL model
Return type
Face
3D Mesh Import
Both 3MF and STL import (and export) are provided with the Mesher class.
For example:
importer = Mesher()
cone, cyl = importer.read("example.3mf")
print(
f"{importer.mesh_count=}, {importer.vertex_counts=}, {importer.triangle_counts=}"
)
print(f"Imported model unit: {importer.model_unit}")
print(f"{cone.label=}")
print(f"{cone.color.to_tuple()=}")
print(f"{cyl.label=}")
print(f"{cyl.color.to_tuple()=}")
diam = 80
holes = Sketch()
r = Rectangle(2, 2)
for loc in GridLocations(4, 4, 20, 20):
if loc.position.X**2 + loc.position.Y**2 < (diam / 2 - 1.8) ** 2:
holes += loc * r
c = Circle(diam / 2) - holes
One way to avoid it is to use lazy evaluation for the algebra operations. Just collect all objects and then call fuse (+)
once with all objects and clean once. Overall it takes 0.19 sec.
r = Rectangle(2, 2)
holes = [
loc * r
for loc in GridLocations(4, 4, 20, 20).locations
if loc.position.X**2 + loc.position.Y**2 < (diam / 2 - 1.8) ** 2
]
c = Circle(diam / 2) - holes
Another way to leverage the vectorized algebra operations is to add a list comprehension of objects to an empty Part,
Sketch or Curve:
polygons = Sketch() + [
loc * RegularPolygon(radius=5, side_count=5)
(continues on next page)
1. Positioning at a location
show_object(face, name="face")
show_object(location_symbol(loc), name="location")
2) Positioning on a plane
plane = Plane.XZ
show_object(face, name="face")
show_object(plane_symbol(plane), name="plane")
Note that the x-axis and the y-axis of the plane are on the x-axis and the z-axis of the world coordinate
system (red and blue axis)
show_object(face, name="face")
show_object(location_symbol(loc), name="location")
show_object(box, name="box")
The x, y, z components of Pos(0.2, 0.4, 0.1) are relative to the x-axis, y-axis or z-axis of the
underlying location loc.
Note: Plane(loc) *, Plane(face.location) * and loc * are equivalent in this example.
show_object(face, name="face")
show_object(location_symbol(loc), name="location")
show_object(box, name="box")
The box is rotated via Rot(z=80) around the z-axis of the underlying location (and not of the z-axis
of the world).
More general:
show_object(face, name="face")
show_object(location_symbol(loc), name="location")
show_object(box, name="box")
The box is rotated via Rot(20, 40, 80) around all three axes relative to the plane.
3. Rotate and position an object relative to a location
box = loc * Rot(20, 40, 80) * Pos(0.2, 0.4, 0.1) * Box(0.2, 0.2, 0.2)
show_object(face, name="face")
show_object(location_symbol(loc), name="location")
show_object(box, name="box")
show_object(location_symbol(loc * Rot(20, 40, 80), 0.5), options={"color
˓→":(0, 255, 255)}, name="local_location")
The box is positioned via Pos(0.2, 0.4, 0.1) relative to the location loc * Rot(20, 40, 80)
4. Position and rotate an object relative to a location
box = loc * Pos(0.2, 0.4, 0.1) * Rot(20, 40, 80) * Box(0.2, 0.2, 0.2)
show_object(face, name="face")
show_object(location_symbol(loc), name="location")
show_object(box, name="box")
show_object(location_symbol(loc * Pos(0.2, 0.4, 0.1), 0.5), options={"color
˓→":(0, 255, 255)}, name="local_location")
Note: This is the same as box = loc * Location((0.2, 0.4, 0.1), (20, 40, 80)) * Box(0.2, 0.2, 0.2)
One can see that there is are significant differences between the different types of centers. To allow the designer to
choose the center that makes the most sense for the given shape there are three possible values for the CenterOf
Enum:
Python Debugger
Many Python IDEs have step by step debugging systems that can be used to walk through your code monitoring its
operation with full visibility of all Python objects. Here is a screenshot of the Visual Studio Code debugger in action:
This shows that a break-point has been encountered and the code operation has been stopped. From here all of the
Python variables are visible and the system is waiting on input from the user on how to proceed. One can enter the
code that assigns top_face by pressing the down arrow button on the top right. Following code execution like this is
a very powerful debug technique.
Logging
Build123d support standard python logging and generates its own log stream. If one is using cq-editor as a display
system there is a built in Log viewer tab that shows the current log stream - here is an example of a log stream:
˓→-20.00, 0.00), o=(-0.00, 0.00, -0.00)), (p=(30.00, 20.00, 0.00), o=(-0.00, 0.00, -0.
˓→00))]
logging.getLogger("build123d").addHandler(logging.NullHandler())
logger = logging.getLogger("build123d")
logging.basicConfig(
filename="myapp.log",
level=logging.INFO,
format="%(name)s-%(levelname)s %(asctime)s - [%(filename)s:%(lineno)s - \
%(funcName)20s() ] - %(message)s",
)
Printing
Sometimes the best debugging aid is just placing a print statement in your code. Many of the build123d classes are
setup to provide useful information beyond their class and location in memory, as follows:
plane = Plane.XY.offset(1)
print(f"{plane=}")
3D - BuildPart
Box
Cone
CounterBoreHole
CounterSinkHole
Cylinder
Hole
Sphere
Torus
Wedge
Operations 1D - BuildLine
add()
bounding_box()
mirror()
offset()
project()
scale()
split()
2D - BuildSketch
add()
chamfer()
fillet()
full_round()
make_face()
make_hull()
mirror()
offset()
project()
scale()
split()
sweep()
trace()
3D - BuildPart
add()
chamfer()
extrude()
fillet()
loft()
make_brake_formed()
mirror()
offset()
project()
revolve()
scale()
section()
split()
sweep()
Selectors 1D - BuildLine
vertices()
edges()
wires()
2D - BuildSketch
vertices()
edges()
wires()
faces()
3D - BuildPart
vertices()
edges()
wires()
faces()
solids()
Selector Operators
Shape Operators
Plane Operators
Vector Operators
Vertex Operators
Enums
cq-editor fork
GUI editor based on PyQT. This fork has changes from jdegenstein to allow easier use with build123d.
See: jdegenstein’s fork of cq-editor
yet-another-cad-viewer
A CAD viewer capable of displaying OCP models (CadQuery/Build123d) in a web browser. Mainly intended for
deployment of finished models as a static website. It also works for developing models with hot reloading, though this
feature may not be as mature as in ocp-vscode.
See: yet-another-cad-viewer
gggears generator
A gear generation framework that allows easy creation of a wide range of gears and drives.
See gggears
1.19.3 Tools
blendquery
CadQuery and build123d integration for Blender.
See: blendquery
nething
3D generative AI for CAD modeling. Now everyone is an engineer. Make your ideas real.
See: nething
Listen to the following podcast which discusses nething in detail: The Next Byte Podcast
ocp-freecad-cam
CAM for CadQuery and Build123d by leveraging FreeCAD library. Visualizes in CQ-Editor and ocp-cad-viewer.
Spiritual successor of cq-cam
See: ocp-freecad-cam
PartCAD
A package manager for CAD models. Build123d is the most supported Code-CAD framework, but CadQuery and
OpenSCAD are also supported. It can be used by build123d designs to import parts from PartCAD repositories, and
to publish build123d designs to be consumed by others.
dl4to4ocp
Library that helps perform topology optimization on your OCP-based CAD models (CadQuery/Build123d/. . . ) using
the dl4to library.
Returns
Wires extracted
Return type
ShapeList[Wire]
Builder.solids(select: ~build123d.build_enums.Select = <Select.ALL>) → ShapeList[Solid]
Return Solids
Return either all or the solids created during the last operation.
Parameters
select (Select, optional) – Solid selector. Defaults to Select.ALL.
Returns
Solids extracted
Return type
ShapeList[Solid]
1.20.2 Enums
class Align(value)
Align object about Axis
CENTER = 2
MAX = 3
MIN = 1
NONE = None
class CenterOf(value)
Center Options
BOUNDING_BOX = 3
GEOMETRY = 1
MASS = 2
class FontStyle(value)
Text Font Styles
BOLD = 2
ITALIC = 3
REGULAR = 1
class GeomType(value)
CAD geometry object type
BEZIER = 6
BSPLINE = 7
CIRCLE = 12
CONE = 3
CYLINDER = 2
ELLIPSE = 13
EXTRUSION = 9
HYPERBOLA = 14
LINE = 11
OFFSET = 10
OTHER = 16
PARABOLA = 15
PLANE = 1
REVOLUTION = 8
SPHERE = 4
TORUS = 5
class Keep(value)
Split options
ALL = 1
BOTH = 3
BOTTOM = 2
INSIDE = 4
OUTSIDE = 5
TOP = 6
class Kind(value)
Offset corner transition
ARC = 1
INTERSECTION = 2
TANGENT = 3
class Mode(value)
Combination Mode
ADD = 1
INTERSECT = 3
PRIVATE = 5
REPLACE = 4
SUBTRACT = 2
class Select(value)
Selector scope - all, last operation or new objects
ALL = 1
LAST = 2
NEW = 3
class SortBy(value)
Sorting criteria
AREA = 3
DISTANCE = 5
LENGTH = 1
RADIUS = 2
VOLUME = 4
class Transition(value)
Sweep discontinuity handling option
RIGHT = 1
ROUND = 2
TRANSFORMED = 3
class Until(value)
Extrude limit
FIRST = 4
LAST = 2
NEXT = 1
PREVIOUS = 3
1.20.3 Locations
class Locations(*pts: Vector | tuple[float, float] | tuple[float, float, float] | Sequence[float] | Vertex | Location |
Face | Plane | Axis | Iterable[Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float] | Vertex | Location | Face | Plane | Axis])
Location Context: Push Points
Creates a context of locations for Part or Sketch
Parameters
pts (Union[VectorLike, Vertex, Location, Face, Plane, Axis] or iterable
of same) – sequence of points to push
Variables
local_locations (list{Location}) – locations relative to workplane
local_locations
values independent of workplanes
class GridLocations(x_spacing: float, y_spacing: float, x_count: int, y_count: int, align:
~build123d.build_enums.Align | tuple[~build123d.build_enums.Align,
~build123d.build_enums.Align] = (<Align.CENTER>, <Align.CENTER>))
Location Context: Rectangular Array
Creates a context of rectangular array of locations for Part or Sketch
Parameters
• x_spacing (float) – horizontal spacing
• y_spacing (float) – vertical spacing
• x_count (int) – number of horizontal points
• y_count (int) – number of vertical points
• align (Union[Align, tuple[Align, Align]], optional) – align min, center, or
max of object. Defaults to (Align.CENTER, Align.CENTER).
Variables
• x_spacing (float) – horizontal spacing
• y_spacing (float) – vertical spacing
• x_count (int) – number of horizontal points
• y_count (int) – number of vertical points
• align (Union[Align, tuple[Align, Align]]) – align min, center, or max of object.
• local_locations (list{Location}) – locations relative to workplane
Raises
ValueError – Either x or y count must be greater than or equal to one.
local_locations
values independent of workplanes
max
top right corner
min
bottom left corner
size
size of the grid
class HexLocations(radius: float, x_count: int, y_count: int, major_radius: bool = False, align:
~build123d.build_enums.Align | tuple[~build123d.build_enums.Align,
~build123d.build_enums.Align] = (<Align.CENTER>, <Align.CENTER>))
Location Context: Hex Array
Creates a context of hexagon array of locations for Part or Sketch. When creating hex locations for an array of
circles, set radius to the radius of the circle plus one half the spacing between the circles.
Parameters
• radius (float) – distance from origin to vertices (major), or optionally from the origin to
side (minor or apothem) with major_radius = False
Vector
PlaneMeta
Plane
OrientedBoundBox
Matrix
Pos
Location
Rotation
JSONEncoder GeomEncoder
Color LocationEncoder
BoundBox
AxisMeta
Axis
intersect(*args, **kwargs)
Return type
bool
is_opposite(other: Axis, angular_tolerance: float = 1e-05) → bool
are axes opposite
Returns True if the direction of this and another axis are parallel with opposite orientation. That is, if the
angle between the two axes is equal to 180° within the angular_tolerance.
Parameters
• other (Axis) – axis to compare to
• angular_tolerance (float, optional) – max angular deviation. Defaults to 1e-5.
Returns
axes are opposite
Return type
bool
is_parallel(other: Axis, angular_tolerance: float = 1e-05) → bool
are axes parallel
Returns True if the direction of this and another axis are parallel with same orientation or opposite orien-
tation. That is, if the angle between the two axes is equal to 0° or 180° within the angular_tolerance.
Parameters
• other (Axis) – axis to compare to
• angular_tolerance (float, optional) – max angular deviation. Defaults to 1e-5.
Returns
axes are parallel
Return type
bool
is_skew(other: Axis, tolerance: float = 1e-05) → bool
are axes skew
Returns True if this axis and another axis are skew, meaning they are neither parallel nor coplanar. Two
axes are skew if they do not lie in the same plane and never intersect.
Mathematically, this means:
• The axes are not parallel (the cross product of their direction vectors is nonzero).
• The axes are not coplanar (the vector between their positions is not aligned with the plane spanned
by their directions).
If either condition is false (i.e., the axes are parallel or coplanar), they are not skew.
Parameters
• other (Axis) – axis to compare to
• tolerance (float, optional) – max deviation. Defaults to 1e-5.
Returns
axes are skew
Return type
bool
located(new_location: Location)
relocates self to a new location possibly changing position and direction
property location: Location
Return self as Location
property position
reverse() → Axis
Return a copy of self with the direction reversed
to_plane() → Plane
Return self as Plane
class BoundBox(bounding_box: Bnd_Box)
A BoundingBox for a Shape
add(obj: tuple[float, float, float] | Vector | BoundBox, tol: float | None = None) → BoundBox
Returns a modified (expanded) bounding box
obj can be one of several things:
1. a 3-tuple corresponding to x,y, and z amounts to add
2. a vector, containing the x,y,z values to add
3. another bounding box, where a new box will be created that encloses both.
This bounding box is not changed.
Parameters
• obj – tuple[float, float, float] | Vector | BoundBox]:
• tol – float: (Default value = None)
Returns:
center() → Vector
Return center of the bounding box
property diagonal: float
body diagonal length (i.e. object maximum size)
static find_outside_box_2d(bb1: BoundBox, bb2: BoundBox) → BoundBox | None
Compares bounding boxes
Compares bounding boxes. Returns none if neither is inside the other. Returns the outer one if either is
outside the other.
BoundBox.is_inside works in 3d, but this is a 2d bounding box, so it doesn’t work correctly plus, there was
all kinds of rounding error in the built-in implementation i do not understand.
Parameters
• bb1 – BoundBox:
• bb2 – BoundBox:
Returns:
classmethod from_topo_ds(shape: TopoDS_Shape, tolerance: float | None = None, optimal: bool = True,
oriented: bool = False) → BoundBox
Constructs a bounding box from a TopoDS_Shape
Parameters
• shape – TopoDS_Shape:
• tolerance – float: (Default value = None)
• optimal – bool: This algorithm builds precise bounding box (Default value = True)
Returns:
is_inside(second_box: BoundBox) → bool
Is the provided bounding box inside this one?
Parameters
b2 – BoundBox:
Returns:
to_align_offset(align: Align | None | tuple[Align | None, Align | None] | tuple[Align | None, Align | None,
Align | None]) → Vector
Amount to move object to achieve the desired alignment
class Color(*args, **kwargs)
Color object based on OCCT Quantity_ColorRGBA.
Variables
wrapped (Quantity_ColorRGBA) – the OCP color object
__copy__() → Color
Return copy of self
__deepcopy__(_memo) → Color
Return deepcopy of self
to_tuple()
Value as tuple
class Location(*args)
Location in 3D space. Depending on usage can be absolute or relative.
This class wraps the TopLoc_Location class from OCCT. It can be used to move Shape objects in both relative
and absolute manner. It is the preferred type to locate objects in build123d.
Variables
wrapped (TopLoc_Location) – the OCP location object
__copy__() → Location
Lib/copy.py shallow copy
__deepcopy__(_memo) → Location
Lib/copy.py deep copy
__eq__(other: object) → bool
Compare Locations
__mul__(other: Shape | Location | Iterable[Location]) → Shape | Location | list[Location]
Combine locations
__neg__() → Location
Flip the orientation without changing the position operator -
__pow__(exponent: int) → Location
intersect(*args, **kwargs)
inverse() → Location
Inverted location
property orientation: Vector
Extract orientation/rotation component of self
Returns
orientation part of Location
Return type
Vector
property position: Vector
Extract Position component of self
Returns
Position part of Location
Return type
Vector
to_axis() → Axis
Convert the location into an Axis
to_tuple() → tuple[tuple[float, float, float], tuple[float, float, float]]
Convert the location to a translation, rotation tuple.
property x_axis: Axis
Default X axis when used as a plane
property y_axis: Axis
Default Y axis when used as a plane
property z_axis: Axis
Default Z axis when used as a plane
class LocationEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True,
sort_keys=False, indent=None, separators=None, default=None)
Custom JSON Encoder for Location values
Example:
data_dict = {
"part1": {
"joint_one": Location((1, 2, 3), (4, 5, 6)),
"joint_two": Location((7, 8, 9), (10, 11, 12)),
},
"part2": {
"joint_one": Location((13, 14, 15), (16, 17, 18)),
"joint_two": Location((19, 20, 21), (22, 23, 24)),
},
(continues on next page)
Example
read_json = json.load(infile, object_hook=LocationEncoder.location_hook)
class Pos(*args, **kwargs)
A position only sub-class of Location
Rot
alias of Rotation
class Matrix(*args, **kwargs)
A 3d , 4x4 transformation matrix.
Used to move geometry in space.
The provided “matrix” parameter may be None, a gp_GTrsf, or a nested list of values.
If given a nested list, it is expected to be of the form:
[[m11, m12, m13, m14],
[m21, m22, m23, m24], [m31, m32, m33, m34]]
A fourth row may be given, but it is expected to be: [0.0, 0.0, 0.0, 1.0] since this is a transform matrix.
Variables
wrapped (gp_GTrsf ) – the OCP transformation function
__copy__() → Matrix
Return copy of self
__deepcopy__(_memo) → Matrix
Return deepcopy of self
inverse() → Matrix
Invert Matrix
multiply(other)
Matrix multiplication
rotate(axis: Axis, angle: float)
General rotate about axis
transposed_list() → Sequence[float]
Needed by the cqparts gltf exporter
Parameters
• gp_pln (gp_Pln) – an OCCT plane object
• origin (tuple[float, float, float] | Vector) – the origin in global coordinates
• x_dir (tuple[float, float, float] | Vector | None) – an optional vector repre-
senting the X Direction. Defaults to None.
• z_dir (tuple[float, float, float] | Vector | None) – the normal direction for
the plane. Defaults to (0, 0, 1).
Variables
• origin (Vector) – global position of local (0,0,0) point
• x_dir (Vector) – x direction
• y_dir (Vector) – y direction
• z_dir (Vector) – z direction
• local_coord_system (gp_Ax3) – OCP coordinate system
• forward_transform (Matrix) – forward location transformation matrix
• reverse_transform (Matrix) – reverse location transformation matrix
• wrapped (gp_Pln) – the OCP plane object
Raises
• ValueError – z_dir must be non null
• ValueError – x_dir must be non null
• ValueError – the specified x_dir is not orthogonal to the provided normal
Returns
A plane
Return type
Plane
__copy__() → Plane
Return copy of self
__deepcopy__(_memo) → Plane
Return deepcopy of self
__eq__(other: object)
Are planes equal operator ==
__mul__(other: Location | Shape) → Plane | list[Plane] | Shape
__neg__() → Plane
Reverse z direction of plane operator -
contains(obj: Vector | tuple[float, float] | tuple[float, float, float] | Sequence[float] | Axis, tolerance: float =
1e-06) → bool
Is this point or Axis fully contained in this plane?
Parameters
• obj (VectorLike | Axis) – point or Axis to evaluate
• tolerance (float, optional) – comparison tolerance. Defaults to TOLERANCE.
Returns
self contains point or Axis
Return type
bool
from_local_coords(obj: tuple | Vector | Any | BoundBox)
Reposition the object relative from this plane
Parameters
• obj – VectorLike | Shape | BoundBox an object to reposition. Note that
• classes. (type Any refers to all topological)
Returns
an object of the same type, but repositioned to world coordinates
static get_topods_face_normal(face: TopoDS_Face) → Vector
Find the normal at the center of a TopoDS_Face
intersect(*args, **kwargs)
Return type
Plane
to_gp_ax2() → gp_Ax2
Return gp_Ax2 version of the plane
to_local_coords(obj: Vector | tuple[float, float] | tuple[float, float, float] | Sequence[float] | Any |
BoundBox)
Reposition the object relative to this plane
Parameters
• obj – VectorLike | Shape | BoundBox an object to reposition. Note that
• classes. (type Any refers to all topological)
Returns
an object of the same type, but repositioned to local coordinates
class Rotation(*args, **kwargs)
Subclass of Location used only for object rotation
Variables
• X (float) – rotation in degrees about X axis
• Y (float) – rotation in degrees about Y axis
• Z (float) – rotation in degrees about Z axis
• enums, (optionally specify rotation ordering with Intrinsic or
Extrinsic) – defaults to Intrinsic.XYZ
class Vector(*args, **kwargs)
Create a 3-dimensional vector
Parameters
• x (float) – x component
• y (float) – y component
• z (float) – z component
• vec (Vector | Sequence(float) | gp_Vec | gp_Pnt | gp_Dir | gp_XYZ) –
vector representations
Note that if no z value is provided it’s assumed to be zero. If no values are provided the returned Vector has the
value of 0, 0, 0.
Variables
wrapped (gp_Vec) – the OCP vector object
property X: float
Get x value
property Y: float
Get y value
property Z: float
Get z value
__abs__() → float
Vector length operator abs()
__add__(vec: Vector | tuple[float, float] | tuple[float, float, float] | Sequence[float]) → Vector
Mathematical addition operator +
__copy__() → Vector
Return copy of self
__deepcopy__(_memo) → Vector
Return deepcopy of self
__eq__(other: object) → bool
Vectors equal operator ==
__mul__(scale: float) → Vector
Mathematical multiply operator *
__neg__() → Vector
Flip direction of vector operator -
__rmul__(scale: float) → Vector
Mathematical multiply operator *
__sub__(vec: Vector | tuple[float, float] | tuple[float, float, float] | Sequence[float]) → Vector
Mathematical subtraction operator -
__truediv__(denom: float) → Vector
Mathematical division operator /
add(vec: Vector | tuple[float, float] | tuple[float, float, float] | Sequence[float]) → Vector
Mathematical addition function
center() → Vector
Returns
The center of myself is myself. Provided so that vectors, vertices, and other shapes all support
a common interface, when center() is requested for all objects on the stack.
cross(vec: Vector) → Vector
Mathematical cross function
distance_to_plane(plane: Plane) → float
Minimum unsigned distance between vector and plane
dot(vec: Vector) → float
Mathematical dot function
get_angle(vec: Vector) → float
Unsigned angle between vectors
get_signed_angle(vec: Vector, normal: Vector | None = None) → float
Signed Angle Between Vectors
Return the signed angle in degrees between two vectors with the given normal based on this math: angle =
atan2((Va × Vb) Vn, Va Vb)
Parameters
• v (Vector) – Second Vector
Returns:
reverse() → Vector
Return a vector with the same magnitude but pointing in the opposite direction
rotate(axis: Axis, angle: float) → Vector
Rotate about axis
Rotate about the given Axis by an angle in degrees
Parameters
• axis (Axis) – Axis of rotation
• angle (float) – angle in degrees
Returns
rotated vector
Return type
Vector
Curve
Compound Part
Mixin3D
Sketch
Solid
SkipClean
Wire
ShapeList Mixin1D
Face
Mixin2D
Shell
Generic Protocol
GroupBy Vertex
Comparable ShapePredicate
ABC
Joint
class Compound(obj: TopoDS_Compound | Iterable[Shape] | None = None, label: str = '', color: Color | None =
None, material: str = '', joints: dict[str, Joint] | None = None, parent: Compound | None = None,
children: Sequence[Shape] | None = None)
A Compound in build123d is a topological entity representing a collection of geometric shapes grouped together
within a single structure. It serves as a container for organizing diverse shapes like edges, faces, or solids. This hi-
erarchical arrangement facilitates the construction of complex models by combining simpler shapes. Compound
plays a pivotal role in managing the composition and structure of intricate 3D models in computer-aided design
(CAD) applications, allowing engineers and designers to work with assemblies of shapes as unified entities for
efficient modeling and analysis.
classmethod cast(obj: TopoDS_Shape) → Vertex | Edge | Wire | Face | Shell | Solid | Compound
Returns the right type of wrapper, given a OCCT object
center(center_of: ~build123d.build_enums.CenterOf = <CenterOf.MASS>) → Vector
Return center of object
Find center of object
Parameters
center_of (CenterOf, optional) – center option. Defaults to CenterOf.MASS.
Raises
• ValueError – Center of GEOMETRY is not supported for this object
• NotImplementedError – Unable to calculate center of mass of this object
Returns
center
Return type
Vector
compound() → Compound | None
Return the Compound
compounds() → ShapeList[Compound]
compounds - all the compounds in this Shape
do_children_intersect(include_parent: bool = False, tolerance: float = 1e-05) → tuple[bool,
tuple[Shape | None, Shape | None], float]
Do Children Intersect
Determine if any of the child objects within a Compound/assembly intersect by intersecting each of the
shapes with each other and checking for a common volume.
Parameters
• include_parent (bool, optional) – check parent for intersections. Defaults to False.
• tolerance (float, optional) – maximum allowable volume difference. Defaults to
1e-5.
Returns
do the object intersect, intersecting objects, volume of intersection
Return type
tuple[bool, tuple[Shape, Shape], float]
classmethod extrude(obj: Shell, direction: Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float]) → Compound
Extrude a Shell into a Compound.
Parameters
direction (VectorLike) – direction and magnitude of extrusion
Raises
• ValueError – Unsupported class
• RuntimeError – Generated invalid result
Returns
extruded shape
Return type
Edge
get_type(obj_type: type[Vertex] | type[Edge] | type[Face] | type[Shell] | type[Solid] | type[Wire]) →
list[Vertex | Edge | Face | Shell | Solid | Wire]
Extract the objects of the given type from a Compound. Note that this isn’t the same as Faces() etc. which
will extract Faces from Solids.
Parameters
obj_type (Union[Vertex, Edge, Face, Shell, Solid, Wire]) – Object types to
extract
Returns
Extracted objects
Return type
list[Union[Vertex, Edge, Face, Shell, Solid, Wire]]
classmethod make_text(txt: str, font_size: float, font: str = 'Arial', font_path: str | None = None,
font_style: ~build123d.build_enums.FontStyle = <FontStyle.REGULAR>, align:
~build123d.build_enums.Align | tuple[~build123d.build_enums.Align,
~build123d.build_enums.Align] | None = (<Align.CENTER>,
<Align.CENTER>), position_on_path: float = 0.0, text_path:
~topology.one_d.Edge | ~topology.one_d.Wire | None = None) → Compound
2D Text that optionally follows a path.
The text that is created can be combined as with other sketch features by specifying a mode or rotated by
the given angle. In addition, edges have been previously created with arc or segment, the text will follow
the path defined by these edges. The start parameter can be used to shift the text along the path to achieve
precise positioning.
Parameters
• txt – text to be rendered
• font_size – size of the font in model units
• font – font name
• font_path – path to font file
• font_style – text style. Defaults to FontStyle.REGULAR.
• align (Union[Align, tuple[Align, Align]], optional) – align min, center, or
max of object. Defaults to (Align.CENTER, Align.CENTER).
• position_on_path – the relative location on path to position the text, between 0.0 and
1.0. Defaults to 0.0.
• text_path – a path for the text to follows. Defaults to None - linear text.
Returns
a Compound object containing multiple Faces representing the text
Examples:
fox = Compound.make_text(
txt="The quick brown fox jumped over the lazy dog",
font_size=10,
position_on_path=0.1,
text_path=jump_edge,
)
geom_adaptor() → BRepAdaptor_Curve
Return the Geom Curve from this Edge
intersect(*to_intersect: Edge | Axis | Plane) → None | Vertex | Edge | ShapeList[Vertex | Edge]
intersect Edge with Edge or Axis
Parameters
other (Edge | Axis) – other object
Returns
Compound of vertices and/or edges
Return type
Shape | None
classmethod make_bezier(*cntl_pnts: Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float], weights: list[float] | None = None) → Edge
Create a rational (with weights) or non-rational bezier curve. The first and last control points represent the
start and end of the curve respectively. If weights are provided, there must be one provided for each control
point.
Parameters
• cntl_pnts (sequence[VectorLike]) – points defining the curve
• weights (list[float], optional) – control point weights list. Defaults to None.
Raises
• ValueError – Too few control points
• ValueError – Too many control points
• ValueError – A weight is required for each control point
Returns
bezier curve
Return type
Edge
classmethod make_circle(radius: float, plane: ~build123d.geometry.Plane = Plane(o=(0.00, 0.00, 0.00),
x=(1.00, 0.00, 0.00), z=(0.00, 0.00, 1.00)), start_angle: float = 360.0,
end_angle: float = 360, angular_direction:
~build123d.build_enums.AngularDirection =
<AngularDirection.COUNTER_CLOCKWISE>) → Edge
make circle
Create a circle centered on the origin of plane
Parameters
• radius (float) – circle radius
• plane (Plane, optional) – base plane. Defaults to Plane.XY.
• start_angle (float, optional) – start of arc angle. Defaults to 360.0.
• end_angle (float, optional) – end of arc angle. Defaults to 360.
• angular_direction (AngularDirection, optional) – arc direction. Defaults to
AngularDirection.COUNTER_CLOCKWISE.
Returns
full or partial circle
Return type
Edge
classmethod make_ellipse(x_radius: float, y_radius: float, plane: ~build123d.geometry.Plane =
Plane(o=(0.00, 0.00, 0.00), x=(1.00, 0.00, 0.00), z=(0.00, 0.00, 1.00)),
start_angle: float = 360.0, end_angle: float = 360.0, angular_direction:
~build123d.build_enums.AngularDirection =
<AngularDirection.COUNTER_CLOCKWISE>) → Edge
make ellipse
Makes an ellipse centered at the origin of plane.
Parameters
• x_radius (float) – x radius of the ellipse (along the x-axis of plane)
• y_radius (float) – y radius of the ellipse (along the y-axis of plane)
• plane (Plane, optional) – base plane. Defaults to Plane.XY.
• start_angle (float, optional) – Defaults to 360.0.
• end_angle (float, optional) – Defaults to 360.0.
• angular_direction (AngularDirection, optional) – arc direction. Defaults to
AngularDirection.COUNTER_CLOCKWISE.
Returns
full or partial ellipse
Return type
Edge
classmethod make_helix(pitch: float, height: float, radius: float, center: Vector | tuple[float, float] |
tuple[float, float, float] | Sequence[float] = (0, 0, 0), normal: Vector | tuple[float,
float] | tuple[float, float, float] | Sequence[float] = (0, 0, 1), angle: float = 0.0,
lefthand: bool = False) → Wire
Make a helix with a given pitch, height and radius. By default a cylindrical surface is used to create the
helix. If the :angle: is set (the apex given in degree) a conical surface is used instead.
Parameters
• pitch (float) – distance per revolution along normal
• height (float) – total height
• radius (float)
• center (VectorLike, optional) – Defaults to (0, 0, 0).
• normal (VectorLike, optional) – Defaults to (0, 0, 1).
• angle (float, optional) – conical angle. Defaults to 0.0.
• lefthand (bool, optional) – Defaults to False.
Returns
helix
Return type
Wire
Raises
• ValueError – Parameter for each interpolation point
• ValueError – Tangent for each interpolation point
• ValueError – B-spline interpolation failed
Returns
the spline
Return type
Edge
classmethod make_spline_approx(points: list[Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float]], tol: float = 0.001, smoothing: tuple[float, float,
float] | None = None, min_deg: int = 1, max_deg: int = 6) → Edge
Approximate a spline through the provided points.
Parameters
• points (list[Vector])
• tol (float, optional) – tolerance of the algorithm. Defaults to 1e-3.
• smoothing (Tuple[float, float, float], optional) – optional tuple of 3
weights use for variational smoothing. Defaults to None.
• min_deg (int, optional) – minimum spline degree. Enforced only when smoothing is
None. Defaults to 1.
• max_deg (int, optional) – maximum spline degree. Defaults to 6.
Raises
ValueError – B-spline approximation failed
Returns
spline
Return type
Edge
classmethod make_tangent_arc(start: Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float], tangent: Vector | tuple[float, float] | tuple[float, float,
float] | Sequence[float], end: Vector | tuple[float, float] | tuple[float,
float, float] | Sequence[float]) → Edge
Tangent Arc
Makes a tangent arc from point start, in the direction of tangent and ends at end.
Parameters
• start (VectorLike) – start point
• tangent (VectorLike) – start tangent
• end (VectorLike) – end point
Returns
circular arc
Return type
Edge
to_axis() → Axis
Translate a linear Edge to an Axis
to_wire() → Wire
Edge as Wire
trim(start: float, end: float) → Edge
Create a new edge by keeping only the section between start and end.
Parameters
• start (float) – 0.0 <= start < 1.0
• end (float) – 0.0 < end <= 1.0
Raises
ValueError – start >= end
Returns
trimmed edge
Return type
Edge
trim_to_length(start: float, length: float) → Edge
Create a new edge starting at the given normalized parameter of a given length.
Parameters
• start (float) – 0.0 <= start < 1.0
• length (float) – target length
Returns
trimmed edge
Return type
Edge
class Face(obj: TopoDS_Face, label: str = '', color: Color | None = None, parent: Compound | None = None)
class Face(outer_wire: Wire, inner_wires: Iterable[Wire] | None = None, label: str = '', color: Color | None =
None, parent: Compound | None = None)
A Face in build123d represents a 3D bounded surface within the topological data structure. It encapsulates
geometric information, defining a face of a 3D shape. These faces are integral components of complex structures,
such as solids and shells. Face enables precise modeling and manipulation of surfaces, supporting operations
like trimming, filleting, and Boolean operations.
property area_without_holes: float
Calculate the total surface area of the face, including the areas of any holes.
This property returns the overall area of the face as if the inner boundaries (holes) were filled in.
Returns
The total surface area, including the area of holes. Returns 0.0 if the face is empty.
Return type
float
property axes_of_symmetry: list[Axis]
Computes and returns the axes of symmetry for a planar face.
The method determines potential symmetry axes by analyzing the face’s geometry:
Returns
a potentially non-planar face
Return type
Face
make_holes(interior_wires: list[Wire]) → Face
Make Holes in Face
Create holes in the Face ‘self’ from interior_wires which must be entirely interior. Note that making holes
in faces is more efficient than using boolean operations with solid object. Also note that OCCT core may
fail unless the orientation of the wire is correct - use Wire(forward_wire.wrapped.Reversed()) to reverse a
wire.
Example
For example, make a series of slots on the curved walls of a cylinder.
Parameters
• interior_wires – a list of hole outline wires
• interior_wires – list[Wire]:
Returns
‘self’ with holes
Return type
Face
Raises
• RuntimeError – adding interior hole in non-planar face with provided interior_wires
Approximate a spline surface through the provided 2d array of points. The first dimension correspond to
points on the vertical direction in the parameter space of the face. The second dimension correspond to
points on the horizontal direction in the parameter space of the face. The 2 dimensions are U,V dimensions
of the parameter space of the face.
Parameters
• points (list[list[VectorLike]]) – a 2D list of points, first dimension is V parame-
ters second is U parameters.
• tol (float, optional) – tolerance of the algorithm. Defaults to 1e-2.
• smoothing (Tuple[float, float, float], optional) – optional tuple of 3
weights use for variational smoothing. Defaults to None.
• min_deg (int, optional) – minimum spline degree. Enforced only when smoothing is
None. Defaults to 1.
• max_deg (int, optional) – maximum spline degree. Defaults to 3.
Raises
ValueError – B-spline approximation failed
Returns
a potentially non-planar face defined by points
Return type
Face
classmethod make_surface_from_curves(edge1: Edge, edge2: Edge) → Face
classmethod make_surface_from_curves(wire1: Wire, wire2: Wire) → Face
make_surface_from_curves
Create a ruled surface out of two edges or two wires. If wires are used then these must have the same
number of edges.
Parameters
• curve1 (Union[Edge,Wire]) – side of surface
• curve2 (Union[Edge,Wire]) – opposite side of surface
Returns
potentially non planar surface
Return type
Face
normal_at(surface_point: Vector | tuple[float, float] | tuple[float, float, float] | Sequence[float] | None =
None) → Vector
normal_at(u: float, v: float) → Vector
normal_at
Computes the normal vector at the desired location on the face.
Parameters
surface_point (VectorLike, optional) – a point that lies on the surface where the
normal. Defaults to None.
Returns
surface normal direction
Return type
Vector
order = 2.0
outer_wire() → Wire
Extract the perimeter wire from this Face
position_at(u: float, v: float) → Vector
Computes a point on the Face given u, v coordinates.
Parameters
• u (float) – the horizontal coordinate in the parameter space of the Face, between 0.0 and
1.0
• v (float) – the vertical coordinate in the parameter space of the Face, between 0.0 and 1.0
Returns
point on Face
Return type
Vector
project_to_shape(target_object: Shape, direction: Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float]) → ShapeList[Face | Shell]
Project Face to target Object
Project a Face onto a Shape generating new Face(s) on the surfaces of the object.
A projection with no taper is illustrated below:
Note that an array of faces is returned as the projection might result in faces on the “front” and “back”
of the object (or even more if there are intermediate surfaces in the projection path). faces “behind” the
projection are not returned.
Parameters
• target_object (Shape) – Object to project onto
• direction (VectorLike) – projection direction
Returns
Face(s) projected on target object ordered by distance
Return type
ShapeList[Face]
property radii: None | tuple[float, float]
Return the major and minor radii of a torus otherwise None
property radius: None | float
Return the radius of a cylinder or sphere, otherwise None
classmethod sew_faces(faces: Iterable[Face]) → list[ShapeList[Face]]
sew faces
Group contiguous faces and return them in a list of ShapeList
Parameters
faces (Iterable[Face]) – Faces to sew together
Raises
RuntimeError – OCCT SewedShape generated unexpected output
Returns
grouped contiguous faces
Return type
list[ShapeList[Face]]
classmethod sweep(profile: Curve | Edge | Wire, path: Curve | Edge | Wire,
transition=<Transition.TRANSFORMED>) → Face
Sweep a 1D profile along a 1D path. Both the profile and path must be composed of only 1 Edge.
Parameters
• profile (Union[Curve,Edge,Wire]) – the object to sweep
• path (Union[Curve,Edge,Wire]) – the path to follow when sweeping
• transition (Transition, optional) – handling of profile orientation at C1 path dis-
continuities. Defaults to Transition.TRANSFORMED.
Raises
ValueError – Only 1 Edge allowed in profile & path
Returns
resulting face, may be non-planar
Return type
Face
to_arcs(tolerance: float = 0.001) → Face
Approximate planar face with arcs and straight line segments.
Parameters
tolerance (float, optional) – Approximation tolerance. Defaults to 1e-3.
Returns
approximated face
Return type
Face
property volume: float
volume - the volume of this Face, which is always zero
property width: None | float
width of planar face
wire() → Wire
Return the outerwire, generate a warning if inner_wires present
without_holes() → Face
Remove all of the holes from this face.
Returns
A new Face instance identical to the original but without any holes.
Return type
Face
class Mixin1D(obj: TopoDS_Shape | None = None, label: str = '', color: Color | None = None, parent:
Compound | None = None)
Methods to add to the Edge and Wire classes
__matmul__(position: float) → Vector
Position on wire operator @
__mod__(position: float) → Vector
Tangent on wire operator %
classmethod cast(obj: TopoDS_Shape) → Vertex | Edge | Wire
Returns the right type of wrapper, given a OCCT object
center(center_of: ~build123d.build_enums.CenterOf = <CenterOf.GEOMETRY>) → Vector
Center of object
Return the center based on center_of
Parameters
center_of (CenterOf, optional) – centering option. Defaults to Cen-
terOf.GEOMETRY.
Returns
center
Return type
Vector
common_plane(*lines: Edge | Wire | None) → None | Plane
Find the plane containing all the edges/wires (including self). If there is no common plane return None. If
the edges are coaxial, select one of the infinite number of valid planes.
Parameters
lines (sequence of Edge | Wire) – edges in common with self
Returns
Either the common plane or None
Return type
None | Plane
edge() → Edge | None
Return the Edge
edges() → ShapeList[Edge]
edges - all the edges in this Shape
end_point() → Vector
The end point of this edge.
Note that circles may have identical start and end points.
classmethod extrude(obj: Shape, direction: VectorLike) → Edge | Face | Shell | Solid | Compound
Unused - only here because Mixin1D is a subclass of Shape
property is_closed: bool
Are the start and end points equal?
property is_forward: bool
Does the Edge/Wire loop forward or reverse
property is_interior: bool
Check if the edge is an interior edge.
An interior edge lies between surfaces that are part of the body (internal to the geometry) and does not form
part of the exterior boundary.
Returns
True if the edge is an interior edge, False otherwise.
Return type
bool
property length: float
Edge or Wire length
location_at(distance: float, position_mode: ~build123d.build_enums.PositionMode =
<PositionMode.PARAMETER>, frame_method: ~build123d.build_enums.FrameMethod =
<FrameMethod.FRENET>, planar: bool | None = None, x_dir: ~build123d.geometry.Vector |
tuple[float, float] | tuple[float, float, float] | ~collections.abc.Sequence[float] | None = None)
→ Location
Locations along curve
Generate a location along the underlying curve.
Parameters
• distance (float) – distance or parameter value
• position_mode (PositionMode, optional) – position calculation mode. Defaults to
PositionMode.PARAMETER.
• frame_method (FrameMethod, optional) – moving frame calculation method. The
FRENET frame can “twist” or flip unexpectedly, especially near flat spots. The COR-
RECTED frame behaves more like a “camera dolly” or sweep profile would — it’s smoother
and more stable. Defaults to FrameMethod.FRENET.
2d Offset
Offsets a planar edge/wire
Parameters
• distance (float) – distance from edge/wire to offset
• kind (Kind, optional) – offset corner transition. Defaults to Kind.ARC.
• side (Side, optional) – side to place offset. Defaults to Side.BOTH.
• closed (bool, optional) – if Side!=BOTH, close the LEFT or RIGHT offset. Defaults
to True.
Raises
• RuntimeError – Multiple Wires generated
• RuntimeError – Unexpected result type
Returns
offset wire
Return type
Wire
param_at(distance: float) → float
Parameter along a curve
Compute parameter value at the specified normalized distance.
Parameters
d (float) – normalized distance (0.0 >= d >= 1.0)
Returns
parameter value
Return type
float
perpendicular_line(length: float, u_value: float, plane: Plane = Plane(o=(0.00, 0.00, 0.00), x=(1.00,
0.00, 0.00), z=(0.00, 0.00, 1.00))) → Edge
Create a line on the given plane perpendicular to and centered on beginning of self
Parameters
• length (float) – line length
• u_value (float) – position along line between 0.0 and 1.0
• plane (Plane, optional) – plane containing perpendicular line. Defaults to Plane.XY.
Returns
perpendicular line
Return type
Edge
position_at(distance: float, position_mode: ~build123d.build_enums.PositionMode =
<PositionMode.PARAMETER>) → Vector
Position At
Generate a position along the underlying curve.
Parameters
• distance (float) – distance or parameter value
• position_mode (PositionMode, optional) – position calculation mode. Defaults to
PositionMode.PARAMETER.
Returns
position on the underlying curve
Return type
Vector
positions(distances: ~collections.abc.Iterable[float], position_mode:
~build123d.build_enums.PositionMode = <PositionMode.PARAMETER>) → list[Vector]
Positions along curve
Generate positions along the underlying curve
Parameters
• distances (Iterable[float]) – distance or parameter values
• position_mode (PositionMode, optional) – position calculation mode. Defaults to
PositionMode.PARAMETER.
Returns
positions along curve
Return type
list[Vector]
project(face: Face, direction: VectorLike, closest: bool = True) → Edge | Wire | ShapeList[Edge | Wire]
Project onto a face along the specified direction
Parameters
• face – Face:
• direction – VectorLike:
• closest – bool: (Default value = True)
Returns:
project_to_viewport(viewport_origin: Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float], viewport_up: Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float] = (0, 0, 1), look_at: Vector | tuple[float, float] | tuple[float, float,
float] | Sequence[float] | None = None) → tuple[ShapeList[Edge], ShapeList[Edge]]
Project a shape onto a viewport returning visible and hidden Edges.
Parameters
• viewport_origin (VectorLike) – location of viewport
• viewport_up (VectorLike, optional) – direction of the viewport y axis. Defaults to
(0, 0, 1).
• look_at (VectorLike, optional) – point to look at. Defaults to None (center of
shape).
Returns
visible & hidden Edges
Return type
tuple[ShapeList[Edge],ShapeList[Edge]]
property radius: float
Calculate the radius.
Note that when applied to a Wire, the radius is simply the radius of the first edge.
Args:
Returns
radius
Raises
ValueError – if kernel can not reduce the shape to a circular edge
split(tool: TrimmingTool, keep: Literal[Keep.TOP, Keep.BOTTOM]) → Self | list[Self] | None
split(tool: TrimmingTool, keep: Literal[Keep.ALL]) → list[Self]
split(tool: TrimmingTool, keep: Literal[Keep.BOTH]) → tuple[Self | list[Self] | None, Self | list[Self] | None]
split(tool: TrimmingTool) → Self | list[Self] | None
split
Split this shape by the provided plane or face.
Parameters
• surface (Plane | Face) – surface to segment shape
• keep (Keep, optional) – which object(s) to save. Defaults to Keep.TOP.
Returns
result of split
Return type
Shape
Returns
Self | list[Self] | None, Tuple[Self | list[Self] | None]: The result of the split operation.
• Keep.TOP: Returns the top as a Self or list[Self], or None if no top is found.
• Keep.BOTTOM: Returns the bottom as a Self or list[Self], or None if no bottom is found.
• Keep.BOTH: Returns a tuple (inside, outside) where each element is either a Self or
list[Self], or None if no corresponding part is found.
start_point() → Vector
The start point of this edge
Note that circles may have identical start and end points.
tangent_angle_at(location_param: float = 0.5, position_mode: ~build123d.build_enums.PositionMode =
<PositionMode.PARAMETER>, plane: ~build123d.geometry.Plane = Plane(o=(0.00,
0.00, 0.00), x=(1.00, 0.00, 0.00), z=(0.00, 0.00, 1.00))) → float
Compute the tangent angle at the specified location
Parameters
• location_param (float, optional) – distance or parameter value. Defaults to 0.5.
• position_mode (PositionMode, optional) – position calculation mode. Defaults to
PositionMode.PARAMETER.
• plane (Plane, optional) – plane line was constructed on. Defaults to Plane.XY.
Returns
angle in degrees between 0 and 360
Return type
float
tangent_at(position: float | ~build123d.geometry.Vector | tuple[float, float] | tuple[float, float, float] |
~collections.abc.Sequence[float] = 0.5, position_mode: ~build123d.build_enums.PositionMode
= <PositionMode.PARAMETER>) → Vector
Find the tangent at a given position on the 1D shape where the position is either a float (or int) parameter
or a point that lies on the shape.
Parameters
• position (float | VectorLike) – distance, parameter value, or point on shape. De-
faults to 0.5.
• position_mode (PositionMode, optional) – position calculation mode. Defaults to
PositionMode.PARAMETER.
Raises
ValueError – invalid position
Returns
tangent value
Return type
Vector
vertex() → Vertex | None
Return the Vertex
vertices() → ShapeList[Vertex]
vertices - all the vertices in this Shape
property volume: float
volume - the volume of this Edge or Wire, which is always zero
wire() → Wire | None
Return the Wire
wires() → ShapeList[Wire]
wires - all the wires in this Shape
class Mixin2D(obj: TopoDS_Shape | None = None, label: str = '', color: Color | None = None, parent:
Compound | None = None)
Additional methods to add to Face and Shell class
classmethod cast(obj: TopoDS_Shape) → Vertex | Edge | Wire | Face | Shell
Returns the right type of wrapper, given a OCCT object
edge() → Edge | None
Return the Edge
edges() → ShapeList[Edge]
edges - all the edges in this Shape
classmethod extrude(obj: Shape, direction: VectorLike) → Edge | Face | Shell | Solid | Compound
Unused - only here because Mixin1D is a subclass of Shape
face() → Face | None
Return the Face
faces() → ShapeList[Face]
faces - all the faces in this Shape
find_intersection_points(other: Axis, tolerance: float = 1e-06) → list[tuple[Vector, Vector]]
Find point and normal at intersection
Return both the point(s) and normal(s) of the intersection of the axis and the shape
Parameters
axis (Axis) – axis defining the intersection line
Returns
Point and normal of intersection
Return type
list[tuple[Vector, Vector]]
offset(amount: float) → Self
Return a copy of self moved along the normal by amount
project_to_viewport(viewport_origin: Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float], viewport_up: Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float] = (0, 0, 1), look_at: Vector | tuple[float, float] | tuple[float, float,
float] | Sequence[float] | None = None) → tuple[ShapeList[Edge], ShapeList[Edge]]
Project a shape onto a viewport returning visible and hidden Edges.
Parameters
• viewport_origin (VectorLike) – location of viewport
• viewport_up (VectorLike, optional) – direction of the viewport y axis. Defaults to
(0, 0, 1).
• look_at (VectorLike, optional) – point to look at. Defaults to None (center of
shape).
Returns
visible & hidden Edges
Return type
tuple[ShapeList[Edge],ShapeList[Edge]]
shell() → Shell | None
Return the Shell
shells() → ShapeList[Shell]
shells - all the shells in this Shape
split(tool: TrimmingTool, keep: Keep = <Keep.TOP>)
Split this shape by the provided plane or face.
Parameters
• surface (Plane | Face) – surface to segment shape
• keep (Keep, optional) – which object(s) to save. Defaults to Keep.TOP.
Returns
result of split
Return type
Shape
Returns
Self | list[Self] | None, Tuple[Self | list[Self] | None]: The result of the split operation.
• Keep.TOP: Returns the top as a Self or list[Self], or None if no top is found.
• Keep.BOTTOM: Returns the bottom as a Self or list[Self], or None if no bottom is found.
• Keep.BOTH: Returns a tuple (inside, outside) where each element is either a Self or
list[Self], or None if no corresponding part is found.
vertex() → Vertex | None
Return the Vertex
vertices() → ShapeList[Vertex]
vertices - all the vertices in this Shape
wires() → ShapeList[Wire]
wires - all the wires in this Shape
class Mixin3D(obj: TopoDS_Shape | None = None, label: str = '', color: Color | None = None, parent:
Compound | None = None)
Additional methods to add to 3D Shape classes
classmethod cast(obj: TopoDS_Shape) → Self
Returns the right type of wrapper, given a OCCT object
center(center_of: ~build123d.build_enums.CenterOf = <CenterOf.MASS>) → Vector
Return center of object
Find center of object
Parameters
center_of (CenterOf, optional) – center option. Defaults to CenterOf.MASS.
Raises
• ValueError – Center of GEOMETRY is not supported for this object
• NotImplementedError – Unable to calculate center of mass of this object
Returns
center
Return type
Vector
chamfer(length: float, length2: float | None, edge_list: Iterable[Edge], face: Face | None = None) → Self
Chamfer
Chamfers the specified edges of this solid.
Parameters
• length (float) – length > 0, the length (length) of the chamfer
• length2 (Optional[float]) – length2 > 0, optional parameter for asymmetrical cham-
fer. Should be None if not required.
• edge_list (Iterable[Edge]) – a list of Edge objects, which must belong to this solid
• face (Face, optional) – identifies the side where length is measured. The edge(s) must
be part of the face
Returns
Chamfered solid
Return type
Self
dprism(basis: Face | None, bounds: list[Face | Wire], depth: float | None = None, taper: float = 0,
up_to_face: Face | None = None, thru_all: bool = True, additive: bool = True) → Solid
Make a prismatic feature (additive or subtractive)
Parameters
• basis (Optional[Face]) – face to perform the operation on
• bounds (list[Union[Face,Wire]]) – list of profiles
• depth (float, optional) – depth of the cut or extrusion. Defaults to None.
• taper (float, optional) – in degrees. Defaults to 0.
• up_to_face (Face, optional) – a face to extrude until. Defaults to None.
• thru_all (bool, optional) – cut thru_all. Defaults to True.
• additive (bool, optional) – Defaults to True.
Returns
prismatic feature
Return type
Solid
edge() → Edge | None
Return the Edge
edges() → ShapeList[Edge]
edges - all the edges in this Shape
classmethod extrude(obj: Shape, direction: VectorLike) → Edge | Face | Shell | Solid | Compound
Unused - only here because Mixin1D is a subclass of Shape
face() → Face | None
Return the Face
faces() → ShapeList[Face]
faces - all the faces in this Shape
fillet(radius: float, edge_list: Iterable[Edge]) → Self
Fillet
Fillets the specified edges of this solid.
Parameters
• radius (float) – float > 0, the radius of the fillet
• edge_list (Iterable[Edge]) – a list of Edge objects, which must belong to this solid
Returns
Filleted solid
Return type
Any
find_intersection_points(other: Axis, tolerance: float = 1e-06) → list[tuple[Vector, Vector]]
Find point and normal at intersection
Return both the point(s) and normal(s) of the intersection of the axis and the shape
Parameters
axis (Axis) – axis defining the intersection line
Returns
Point and normal of intersection
Return type
list[tuple[Vector, Vector]]
hollow(faces: ~collections.abc.Iterable[~topology.two_d.Face] | None, thickness: float, tolerance: float =
0.0001, kind: ~build123d.build_enums.Kind = <Kind.ARC>) → Solid
Hollow
Return the outer shelled solid of self.
Parameters
• faces (Optional[Iterable[Face]]) – faces to be removed,
• list. (which must be part of the solid. Can be an empty)
• thickness (float) – shell thickness - positive shells outwards, negative shells inwards.
• tolerance (float, optional) – modelling tolerance of the method. Defaults to 0.0001.
• kind (Kind, optional) – intersection type. Defaults to Kind.ARC.
Raises
ValueError – Kind.TANGENT not supported
Returns
A hollow solid.
Return type
Solid
is_inside(point: Vector | tuple[float, float] | tuple[float, float, float] | Sequence[float], tolerance: float =
1e-06) → bool
Returns whether or not the point is inside a solid or compound object within the specified tolerance.
Parameters
• point – tuple or Vector representing 3D point to be tested
• tolerance – tolerance for inside determination, default=1.0e-6
• point – VectorLike:
• tolerance – float: (Default value = 1.0e-6)
Returns
bool indicating whether or not point is within solid
max_fillet(edge_list: Iterable[Edge], tolerance=0.1, max_iterations: int = 10) → float
Find Maximum Fillet Size
Find the largest fillet radius for the given Shape and edges with a recursive binary search.
Example
max_fillet_radius = my_shape.max_fillet(shape_edges) max_fillet_radius =
my_shape.max_fillet(shape_edges, tolerance=0.5, max_iterations=8)
Parameters
• edge_list (Iterable[Edge]) – a sequence of Edge objects, which must belong to this
solid
• tolerance (float, optional) – maximum error from actual value. Defaults to 0.1.
• max_iterations (int, optional) – maximum number of recursive iterations. Defaults
to 10.
Raises
• RuntimeError – failed to find the max value
• ValueError – the provided Shape is invalid
Returns
maximum fillet radius
Return type
float
offset_3d(openings: ~collections.abc.Iterable[~topology.two_d.Face] | None, thickness: float, tolerance:
float = 0.0001, kind: ~build123d.build_enums.Kind = <Kind.ARC>) → Solid
Shell
Make an offset solid of self.
Parameters
• openings (Optional[Iterable[Face]]) – faces to be removed, which must be part of
the solid. Can be an empty list.
• thickness (float) – offset amount - positive offset outwards, negative inwards
• tolerance (float, optional) – modelling tolerance of the method. Defaults to 0.0001.
• kind (Kind, optional) – intersection type. Defaults to Kind.ARC.
Raises
ValueError – Kind.TANGENT not supported
Returns
A shelled solid.
Return type
Solid
project_to_viewport(viewport_origin: Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float], viewport_up: Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float] = (0, 0, 1), look_at: Vector | tuple[float, float] | tuple[float, float,
float] | Sequence[float] | None = None) → tuple[ShapeList[Edge], ShapeList[Edge]]
Project a shape onto a viewport returning visible and hidden Edges.
Parameters
• viewport_origin (VectorLike) – location of viewport
• viewport_up (VectorLike, optional) – direction of the viewport y axis. Defaults to
(0, 0, 1).
Parameters
• obj (TopoDS_Shape, optional) – OCCT object. Defaults to None.
• label (str, optional) – Defaults to ‘’.
• color (Color, optional) – Defaults to None.
• parent (Compound, optional) – assembly parent. Defaults to None.
Variables
• wrapped (TopoDS_Shape) – the OCP object
• label (str) – user assigned label
• color (Color) – object color
• (dict[str (joints) – Joint]): dictionary of joints bound to this object (Solid only)
• children (Shape) – list of assembly children of this object (Compound only)
• topo_parent (Shape) – assembly parent of this object
__add__(other: None | Shape | Iterable[Shape]) → Self | ShapeList[Self]
fuse shape to self operator +
__and__(other: Shape | Iterable[Shape]) → None | Self | ShapeList[Self]
intersect shape with self operator &
__copy__() → Self
Return shallow copy or reference of self
Create an copy of this Shape that shares the underlying TopoDS_TShape.
Used when there is a need for many objects with the same CAD structure but at different Locations, etc.
- for examples fasteners in a larger assembly. By sharing the TopoDS_TShape, the memory size of such
assemblies can be greatly reduced.
Changes to the CAD structure of the base object will be reflected in all instances.
__deepcopy__(memo) → Self
Return deepcopy of self
__eq__(other) → bool
Check if two shapes are the same.
This method checks if the current shape is the same as the other shape. Two shapes are considered the same
if they share the same TShape with the same Locations. Orientations may differ.
Parameters
other (Shape) – The shape to compare with.
Returns
True if the shapes are the same, False otherwise.
Return type
bool
__hash__() → int
Return hash code
__rmul__(other)
right multiply for positioning operator *
compounds() → ShapeList[Compound]
compounds - all the compounds in this Shape
static compute_mass(obj: Shape) → float
Calculates the ‘mass’ of an object.
Parameters
• obj – Compute the mass of this object
• obj – Shape:
Returns:
copy_attributes_to(target: Shape, exceptions: Iterable[str] | None = None)
Copy common object attributes to target
Note that preset attributes of target will not be overridden.
Parameters
• target (Shape) – object to gain attributes
• exceptions (Iterable[str], optional) – attributes not to copy
Raises
ValueError – invalid attribute
cut(*to_cut: Shape) → Self | ShapeList[Self]
Remove the positional arguments from this Shape.
Parameters
*to_cut – Shape:
Returns
Resulting object may be of a different class than self
or a ShapeList if multiple non-Compound object created
Return type
Self | ShapeList[Self]
distance(other: Shape) → float
Minimal distance between two shapes
Parameters
other – Shape:
Returns:
distance_to(other: Shape | Vector | tuple[float, float] | tuple[float, float, float] | Sequence[float]) → float
Minimal distance between two shapes
distance_to_with_closest_points(other: Shape | Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float]) → tuple[float, Vector, Vector]
Minimal distance between two shapes and the points on each shape
distances(*others: Shape) → Iterator[float]
Minimal distances to between self and other shapes
Parameters
*others – Shape:
Returns:
fix() → Self
fix - try to fix shape if not valid
fuse(*to_fuse: Shape, glue: bool = False, tol: float | None = None) → Self | ShapeList[Self]
Fuse a sequence of shapes into a single shape.
Parameters
• to_fuse (sequence Shape) – shapes to fuse
• glue (bool, optional) – performance improvement for some shapes. Defaults to False.
• tol (float, optional) – tolerance. Defaults to None.
Returns
Resulting object may be of a different class than self
or a ShapeList if multiple non-Compound object created
Return type
Self | ShapeList[Self]
geom_LUT_EDGE: dict[GeomAbs_CurveType, GeomType] =
{<GeomAbs_CurveType.GeomAbs_BSplineCurve: 6>: <GeomType.BSPLINE>,
<GeomAbs_CurveType.GeomAbs_BezierCurve: 5>: <GeomType.BEZIER>,
<GeomAbs_CurveType.GeomAbs_Circle: 1>: <GeomType.CIRCLE>,
<GeomAbs_CurveType.GeomAbs_Ellipse: 2>: <GeomType.ELLIPSE>,
<GeomAbs_CurveType.GeomAbs_Hyperbola: 3>: <GeomType.HYPERBOLA>,
<GeomAbs_CurveType.GeomAbs_Line: 0>: <GeomType.LINE>,
<GeomAbs_CurveType.GeomAbs_OffsetCurve: 7>: <GeomType.OFFSET>,
<GeomAbs_CurveType.GeomAbs_OtherCurve: 8>: <GeomType.OTHER>,
<GeomAbs_CurveType.GeomAbs_Parabola: 4>: <GeomType.PARABOLA>}
static get_single_shape(shape: Shape, entity_type: Literal['Vertex', 'Edge', 'Wire', 'Face', 'Shell', 'Solid',
'Compound']) → Shape | None
Helper to extract a single entity of a specific type from a shape, with a warning if count != 1.
get_top_level_shapes() → ShapeList[Shape]
Retrieve the first level of child shapes from the shape.
This method collects all the non-compound shapes directly contained in the current shape. If the wrapped
shape is a TopoDS_Compound, it traverses its immediate children and collects all shapes that are not fur-
ther nested compounds. Nested compounds are traversed to gather their non-compound elements without
returning the nested compound itself.
Returns
A list of all first-level non-compound child shapes.
Return type
ShapeList[Shape]
Example
If the current shape is a compound containing both simple shapes (e.g., edges, vertices) and other com-
pounds, the method returns a list of only the simple shapes directly contained at the top level.
intersect(*to_intersect: Shape | Axis | Plane) → None | Self | ShapeList[Self]
Intersection of the arguments and this shape
Parameters
to_intersect (sequence of Union[Shape, Axis, Plane]) – Shape(s) to intersect
with
Returns
Resulting object may be of a different class than self
or a ShapeList if multiple non-Compound object created
Return type
Self | ShapeList[Self]
inverse_shape_LUT = {'CompSolid': <TopAbs_ShapeEnum.TopAbs_COMPSOLID: 1>,
'Compound': <TopAbs_ShapeEnum.TopAbs_COMPOUND: 0>, 'Edge':
<TopAbs_ShapeEnum.TopAbs_EDGE: 6>, 'Face': <TopAbs_ShapeEnum.TopAbs_FACE: 4>,
'Shell': <TopAbs_ShapeEnum.TopAbs_SHELL: 3>, 'Solid':
<TopAbs_ShapeEnum.TopAbs_SOLID: 2>, 'Vertex': <TopAbs_ShapeEnum.TopAbs_VERTEX: 7>,
'Wire': <TopAbs_ShapeEnum.TopAbs_WIRE: 5>}
Return type
bool
is_null() → bool
Returns true if this shape is null. In other words, it references no underlying shape with the potential to be
given a location and an orientation.
Args:
Returns:
property is_planar_face: bool
Is the shape a planar face even though its geom_type may not be PLANE
is_same(other: Shape) → bool
Returns True if other and this shape are same, i.e. if they share the same TShape with the same Locations.
Orientations may differ. Also see is_equal()
Parameters
other – Shape:
Returns:
is_valid() → bool
Returns True if no defect is detected on the shape S or any of its subshapes. See the OCCT docs on
BRepCheck_Analyzer::IsValid for a full description of what is checked.
Args:
Returns:
locate(loc: Location) → Self
Apply a location in absolute sense to self
Parameters
loc – Location:
Returns:
located(loc: Location) → Self
Apply a location in absolute sense to a copy of self
Parameters
loc (Location) – new absolute location
Returns
copy of Shape at location
Return type
Shape
property location: Location | None
Get this Shape’s Location
property matrix_of_inertia: list[list[float]]
Compute the inertia matrix (moment of inertia tensor) of the shape.
The inertia matrix represents how the mass of the shape is distributed with respect to its reference frame.
It is a 3×3 symmetric tensor that describes the resistance of the shape to rotational motion around different
axes.
Returns
A 3×3 nested list representing the inertia matrix. The elements of the matrix are given as:
where: - Ixx, Iyy, Izz are the moments of inertia about the X, Y, and Z axes. - Ixy, Ixz, Iyz
are the products of inertia.
Return type
list[list[float]]
Example
Notes
• The inertia matrix is computed relative to the shape’s center of mass.
• It is commonly used in structural analysis, mechanical simulations, and physics-based motion calcu-
lations.
Example
Parameters
• faces (Union[list[Face], Compound]) – faces to project
• path – Path on the Shape to follow
• start – Relative location on path to start the faces. Defaults to 0.
Returns
The projected faces
radius_of_gyration(axis: Axis) → float
Compute the radius of gyration of the shape about a given axis.
The radius of gyration represents the distance from the axis at which the entire mass of the shape could
be concentrated without changing its moment of inertia. It provides insight into how mass is distributed
relative to the axis and is useful in structural analysis, rotational dynamics, and mechanical simulations.
Parameters
axis (Axis) – The axis about which the radius of gyration is computed. The axis should be
defined in the same coordinate system as the shape.
Returns
The radius of gyration in the same units as the shape’s dimensions.
Return type
float
Example
Notes
• The radius of gyration is computed based on the shape’s mass properties.
• It is useful for evaluating structural stability and rotational behavior.
relocate(loc: Location)
Change the location of self while keeping it geometrically similar
Parameters
loc (Location) – new location to set for self
rotate(axis: Axis, angle: float) → Self
rotate a copy
Rotates a shape around an axis.
Parameters
• axis (Axis) – rotation Axis
• angle (float) – angle to rotate, in degrees
Returns
a copy of the shape, rotated
scale(factor: float) → Self
Scales this shape through a transformation.
Parameters
factor – float:
Returns:
shape_LUT = {<TopAbs_ShapeEnum.TopAbs_COMPOUND: 0>: 'Compound',
<TopAbs_ShapeEnum.TopAbs_COMPSOLID: 1>: 'CompSolid', <TopAbs_ShapeEnum.TopAbs_EDGE:
6>: 'Edge', <TopAbs_ShapeEnum.TopAbs_FACE: 4>: 'Face',
<TopAbs_ShapeEnum.TopAbs_SHELL: 3>: 'Shell', <TopAbs_ShapeEnum.TopAbs_SOLID: 2>:
'Solid', <TopAbs_ShapeEnum.TopAbs_VERTEX: 7>: 'Vertex',
<TopAbs_ShapeEnum.TopAbs_WIRE: 5>: 'Wire'}
>>> c1.show_topology()
Parameters
• limit_class – type of displayed leaf node. Defaults to ‘Vertex’.
• show_center (bool, optional) – If None, shows the Location of Compound ‘assem-
blies’ and the bounding box center of Shapes. True or False forces the display. Defaults to
None.
Returns
tree representation of internal structure
Return type
str
Example
wires() → ShapeList[Wire]
wires - all the wires in this Shape
class ShapeList(iterable=(), / )
Subclass of list with custom filter and sort methods appropriate to CAD
__and__(other: ShapeList) → ShapeList[T]
Intersect two ShapeLists operator &
__getitem__(key: SupportsIndex) → T
__getitem__(key: slice) → ShapeList[T]
Return slices of ShapeList as ShapeList
__gt__(sort_by: Axis | SortBy = ((0.0, 0.0, 0.0), (0.0, 0.0, 1.0))) → ShapeList[T]
Sort operator >
__lshift__(group_by: Axis | SortBy = ((0.0, 0.0, 0.0), (0.0, 0.0, 1.0))) → ShapeList[T]
Group and select smallest group operator <<
__lt__(sort_by: Axis | SortBy = ((0.0, 0.0, 0.0), (0.0, 0.0, 1.0))) → ShapeList[T]
Reverse sort operator <
__or__(filter_by: Axis | GeomType = ((0.0, 0.0, 0.0), (0.0, 0.0, 1.0))) → ShapeList[T]
Filter by axis or geomtype operator |
__rshift__(group_by: Axis | SortBy = ((0.0, 0.0, 0.0), (0.0, 0.0, 1.0))) → ShapeList[T]
Group and select largest group operator >>
__sub__(other: ShapeList) → ShapeList[T]
Differences between two ShapeLists operator -
center() → Vector
The average of the center of objects within the ShapeList
compound() → Compound
Return the Compound
compounds() → ShapeList[Compound]
compounds - all the compounds in this ShapeList
edge() → Edge
Return the Edge
edges() → ShapeList[Edge]
edges - all the edges in this ShapeList
face() → Face
Return the Face
faces() → ShapeList[Face]
faces - all the faces in this ShapeList
filter_by(filter_by: ShapePredicate | Axis | Plane | GeomType | property, reverse: bool = False, tolerance:
float = 1e-05) → ShapeList[T]
filter by Axis, Plane, or GeomType
Either: - filter objects of type planar Face or linear Edge by their normal or tangent (respectively) and sort
the results by the given axis, or - filter the objects by the provided type. Note that not all types apply to all
objects.
Parameters
• filter_by (Union[Axis,Plane,GeomType]) – axis, plane, or geom type to filter and
possibly sort by. Filtering by a plane returns faces/edges parallel to that plane.
• reverse (bool, optional) – invert the geom type filter. Defaults to False.
• tolerance (float, optional) – maximum deviation from axis. Defaults to 1e-5.
Raises
ValueError – Invalid filter_by type
Returns
filtered list of objects
Return type
ShapeList
filter_by_position(axis: Axis, minimum: float, maximum: float, inclusive: tuple[bool, bool] = (True,
True)) → ShapeList[T]
filter by position
Filter and sort objects by the position of their centers along given axis. min and max values can be inclusive
or exclusive depending on the inclusive tuple.
Parameters
• axis (Axis) – axis to sort by
• minimum (float) – minimum value
• maximum (float) – maximum value
• inclusive (tuple[bool, bool], optional) – include min,max values. Defaults to
(True, True).
Returns
filtered object list
Return type
ShapeList
property first: T
First element in the ShapeList
group_by(group_by: Callable[[Shape], K] | Axis | Edge | Wire | SortBy | property = ((0.0, 0.0, 0.0), (0.0,
0.0, 1.0)), reverse=False, tol_digits=6) → GroupBy[T, K]
group by
Group objects by provided criteria and then sort the groups according to the criteria. Note that not all
group_by criteria apply to all objects.
Parameters
• group_by (SortBy, optional) – group and sort criteria. Defaults to Axis.Z.
• reverse (bool, optional) – flip order of sort. Defaults to False.
• tol_digits (int, optional) – Tolerance for building the group keys by round(key,
tol_digits)
Returns
sorted list of ShapeLists
Return type
GroupBy[K, ShapeList]
property last: T
Last element in the ShapeList
shell() → Shell
Return the Shell
shells() → ShapeList[Shell]
shells - all the shells in this ShapeList
solid() → Solid
Return the Solid
solids() → ShapeList[Solid]
solids - all the solids in this ShapeList
sort_by(sort_by: Axis | Callable[[T], K] | Edge | Wire | SortBy | property = ((0.0, 0.0, 0.0), (0.0, 0.0, 1.0)),
reverse: bool = False) → ShapeList[T]
sort by
Sort objects by provided criteria. Note that not all sort_by criteria apply to all objects.
Parameters
• sort_by (Axis | Callable[[T], K] | Edge | Wire | SortBy, optional) –
sort criteria. Defaults to Axis.Z.
• reverse (bool, optional) – flip order of sort. Defaults to False.
Raises
• ValueError – Cannot sort by an empty axis
• ValueError – Cannot sort by an empty object
• ValueError – Invalid sort_by criteria provided
Returns
sorted list of objects
Return type
ShapeList
sort_by_distance(other: Shape | Vector | tuple[float, float] | tuple[float, float, float] | Sequence[float],
reverse: bool = False) → ShapeList[T]
Sort by distance
Sort by minimal distance between objects and other
Parameters
• other (Union[Shape,VectorLike]) – reference object
• reverse (bool, optional) – flip order of sort. Defaults to False.
Returns
Sorted shapes
Return type
ShapeList
vertex() → Vertex
Return the Vertex
vertices() → ShapeList[Vertex]
vertices - all the vertices in this ShapeList
wire() → Wire
Return the Wire
wires() → ShapeList[Wire]
wires - all the wires in this ShapeList
class Shell(obj: TopoDS_Shell | Face | Iterable[Face] | None = None, label: str = '', color: Color | None = None,
parent: Compound | None = None)
A Shell is a fundamental component in build123d’s topological data structure representing a connected set of
faces forming a closed surface in 3D space. As part of a geometric model, it defines a watertight enclosure,
commonly encountered in solid modeling. Shells group faces in a coherent manner, playing a crucial role in
representing complex shapes with voids and surfaces. This hierarchical structure allows for efficient handling of
surfaces within a model, supporting various operations and analyses.
center() → Vector
Center of mass of the shell
classmethod extrude(obj: Wire, direction: Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float]) → Shell
Extrude a Wire into a Shell.
Parameters
direction (VectorLike) – direction and magnitude of extrusion
Raises
• ValueError – Unsupported class
• RuntimeError – Generated invalid result
Returns
extruded shape
Return type
Edge
classmethod make_loft(objs: Iterable[Vertex | Wire], ruled: bool = False) → Shell
make loft
Makes a loft from a list of wires and vertices. Vertices can appear only at the beginning or end of the list,
but cannot appear consecutively within the list nor between wires. Wires may be closed or opened.
Parameters
• objs (list[Vertex, Wire]) – wire perimeters or vertices
• ruled (bool, optional) – stepped or smooth. Defaults to False (smooth).
Raises
ValueError – Too few wires
Returns
Lofted object
Return type
Shell
order = 2.5
Return type
Union[Compound, Solid]
classmethod from_bounding_box(bbox: BoundBox | OrientedBoundBox) → Solid
A box of the same dimensions and location
classmethod make_box(length: float, width: float, height: float, plane: Plane = Plane(o=(0.00, 0.00, 0.00),
x=(1.00, 0.00, 0.00), z=(0.00, 0.00, 1.00))) → Solid
make box
Make a box at the origin of plane extending in positive direction of each axis.
Parameters
• length (float)
• width (float)
• height (float)
• plane (Plane, optional) – base plane. Defaults to Plane.XY.
Returns
Box
Return type
Solid
classmethod make_cone(base_radius: float, top_radius: float, height: float, plane: Plane =
Plane(o=(0.00, 0.00, 0.00), x=(1.00, 0.00, 0.00), z=(0.00, 0.00, 1.00)), angle:
float = 360) → Solid
make cone
Make a cone with given radii and height
Parameters
• base_radius (float)
• top_radius (float)
• height (float)
• plane (Plane) – base plane. Defaults to Plane.XY.
• angle (float, optional) – arc size. Defaults to 360.
Returns
Full or partial cone
Return type
Solid
classmethod make_cylinder(radius: float, height: float, plane: Plane = Plane(o=(0.00, 0.00, 0.00),
x=(1.00, 0.00, 0.00), z=(0.00, 0.00, 1.00)), angle: float = 360) → Solid
make cylinder
Make a cylinder with a given radius and height with the base center on plane origin.
Parameters
• radius (float)
• height (float)
• plane (Plane) – base plane. Defaults to Plane.XY.
classmethod revolve(section: Face | Wire, angle: float, axis: Axis, inner_wires: list[Wire] | None =
None) → Solid
Revolve
Revolve a cross section about the given Axis by the given angle.
Parameters
• section (Union[Face,Wire]) – cross section
• angle (float) – the angle to revolve through
• axis (Axis) – rotation Axis
• inner_wires (list[Wire], optional) – holes - only used if section is of type Wire.
Defaults to [].
Returns
the revolved cross section
Return type
Solid
Non-planar faces are thickened both towards and away from the center of the sphere.
Parameters
• depth (float) – Amount to thicken face(s), can be positive or negative.
• normal_override (Vector, optional) – Face only. The normal_override vector can
be used to indicate which way is ‘up’, potentially flipping the face normal direction such
that many faces with different normals all go in the same direction (direction need only be
+/- 90 degrees from the face normal). Defaults to None.
Raises
RuntimeError – Opencascade internal failures
Returns
The resulting Solid object
Return type
Solid
property volume: float
volume - the volume of this Solid
class Wire(obj: TopoDS_Wire, label: str = '', color: Color | None = None, parent: Compound | None = None)
class Wire(edge: Edge, label: str = '', color: Color | None = None, parent: Compound | None = None)
class Wire(wire: Wire, label: str = '', color: Color | None = None, parent: Compound | None = None)
class Wire(wire: Curve, label: str = '', color: Color | None = None, parent: Compound | None = None)
class Wire(edges: Iterable[Edge], sequenced: bool = False, label: str = '', color: Color | None = None, parent:
Compound | None = None)
A Wire in build123d is a topological entity representing a connected sequence of edges forming a continuous
curve or path in 3D space. Wires are essential components in modeling complex objects, defining boundaries for
surfaces or solids. They store information about the connectivity and order of edges, allowing precise definition
of paths within a 3D model.
chamfer_2d(distance: float, distance2: float, vertices: Iterable[Vertex], edge: Edge | None = None) → Wire
Apply 2D chamfer to a wire
Parameters
• distance (float) – chamfer length
• distance2 (float) – chamfer length
• vertices (Iterable[Vertex]) – vertices to chamfer
• edge (Edge) – identifies the side where length is measured. The vertices must be part of
the edge
Returns
chamfered wire
Return type
Wire
close() → Wire
Close a Wire
classmethod combine(wires: Iterable[Wire | Edge], tol: float = 1e-09) → ShapeList[Wire]
Combine a list of wires and edges into a list of Wires.
Parameters
• wires (Iterable[Wire | Edge]) – unsorted
• tol (float, optional) – tolerance. Defaults to 1e-9.
Returns
Wires
Return type
ShapeList[Wire]
classmethod extrude(obj: Shape, direction: Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float]) → Wire
extrude - invalid operation for Wire
fillet_2d(radius: float, vertices: Iterable[Vertex]) → Wire
Apply 2D fillet to a wire
Parameters
• radius (float)
• vertices (Iterable[Vertex]) – vertices to fillet
Returns
filleted wire
Return type
Wire
fix_degenerate_edges(precision: float) → Wire
Fix a Wire that contains degenerate (very small) edges
Parameters
precision (float) – minimum value edge length
Returns
fixed wire
Return type
Wire
geom_adaptor() → BRepAdaptor_CompCurve
Return the Geom Comp Curve for this Wire
classmethod make_circle(radius: float, plane: Plane = Plane(o=(0.00, 0.00, 0.00), x=(1.00, 0.00, 0.00),
z=(0.00, 0.00, 1.00))) → Wire
Makes a circle centered at the origin of plane
Parameters
• radius (float) – circle radius
• plane (Plane) – base plane. Defaults to Plane.XY
Returns
a circle
Return type
Wire
classmethod make_convex_hull(edges: Iterable[Edge], tolerance: float = 0.001) → Wire
Create a wire of minimum length enclosing all of the provided edges.
Note that edges can’t overlap each other.
Parameters
• edges (Iterable[Edge]) – edges defining the convex hull
• tolerance (float) – allowable error as a fraction of each edge length. Defaults to 1e-3.
Raises
ValueError – edges overlap
Returns
convex hull perimeter
Return type
Wire
classmethod make_ellipse(x_radius: float, y_radius: float, plane: ~build123d.geometry.Plane =
Plane(o=(0.00, 0.00, 0.00), x=(1.00, 0.00, 0.00), z=(0.00, 0.00, 1.00)),
start_angle: float = 360.0, end_angle: float = 360.0, angular_direction:
~build123d.build_enums.AngularDirection =
<AngularDirection.COUNTER_CLOCKWISE>, closed: bool = True) →
Wire
make ellipse
Makes an ellipse centered at the origin of plane.
Parameters
• x_radius (float) – x radius of the ellipse (along the x-axis of plane)
• y_radius (float) – y radius of the ellipse (along the y-axis of plane)
Example
part.faces(“>z”).vertices(“<y and <x”).val() + (0, 0, 15)
which creates a new Vertex 15 above one extracted from a part. One can add or subtract a Vertex , Vector
or tuple of float values to a Vertex.
__sub__(other: Vertex | Vector | tuple) → Vertex
Subtract
Substract a Vertex with a Vertex, Vector or Tuple from self
Parameters
other – Value to add
Raises
TypeError – other not in [Tuple,Vector,Vertex]
Returns
Result
Example
part.faces(“>z”).vertices(“<y and <x”).val() - Vector(10, 0, 0)
classmethod cast(obj: TopoDS_Shape) → Self
Returns the right type of wrapper, given a OCCT object
center() → Vector
The center of a vertex is itself!
classmethod extrude(obj: Shape, direction: Vector | tuple[float, float] | tuple[float, float, float] |
Sequence[float]) → Vertex
extrude - invalid operation for Vertex
order = 0.0
1.21.3 Import/Export
Methods and functions specific to exporting and importing build123d objects are defined below.
import_brep(file_name: PathLike | str | bytes) → Shape
Import shape from a BREP file
Parameters
file_name (Union[PathLike, str, bytes]) – brep file
Raises
ValueError – file not found
Returns
build123d object
Return type
Shape
import_step(filename: PathLike | str | bytes) → Compound
Extract shapes from a STEP file and return them as a Compound object.
Parameters
file_name (Union[PathLike, str, bytes]) – file path of STEP file to import
Raises
ValueError – can’t open file
Returns
contents of STEP file
Return type
Compound
import_stl(file_name: PathLike | str | bytes) → Face
Extract shape from an STL file and return it as a Face reference object.
Note that importing with this method and creating a reference is very fast while creating an editable model (with
Mesher) may take minutes depending on the size of the STL file.
Parameters
file_name (Union[PathLike, str, bytes]) – file path of STL file to import
Raises
ValueError – Could not import file
Returns
STL model
Return type
Face
import_svg(svg_file: str | ~pathlib.Path | ~typing.TextIO, *, flip_y: bool = True, align:
~build123d.build_enums.Align | tuple[~build123d.build_enums.Align, ~build123d.build_enums.Align]
| None = <Align.MIN>, ignore_visibility: bool = False, label_by: ~typing.Literal['id', 'class',
'inkscape:label'] | str = 'id', is_inkscape_label: bool | None = None) → ShapeList[Wire | Face]
Parameters
• svg_file (Union[str, Path , TextIO]) – svg file
• flip_y (bool, optional) – flip objects to compensate for svg orientation. Defaults to
True.
• align (Align | tuple[Align, Align] | None, optional) – alignment of the
SVG’s viewbox, if None, the viewbox’s origin will be at (0,0,0). Defaults to Align.MIN.
• ignore_visibility (bool, optional) – Defaults to False.
• label_by (str, optional) – XML attribute to use for imported shapes’ label property.
Defaults to “id”. Use inkscape:label to read labels set from Inkscape’s “Layers and Objects”
panel.
Raises
ValueError – unexpected shape type
Returns
objects contained in svg
Return type
ShapeList[Union[Wire, Face]]
import_svg_as_buildline_code(file_name: PathLike | str | bytes) → tuple[str, str]
translate_to_buildline_code
Translate the contents of the given svg file into executable build123d/BuildLine code.
Parameters
file_name (Union[PathLike, str, bytes]) – svg file name
Returns
code, builder instance name
Return type
tuple[str, str]
b
build_enums, 294
build_line, 236
build_part, 242
build_sketch, 239
e
exporters3d, 272
g
geometry, 300
i
importers, 276
j
joints, 243
o
objects_curve, 200
objects_part, 216
objects_sketch, 207
p
pack, 259
t
topology, 314
379
build123d, Release 0.9.2.dev67+gbde03f4
381
build123d, Release 0.9.2.dev67+gbde03f4
382 Index
build123d, Release 0.9.2.dev67+gbde03f4
Index 383
build123d, Release 0.9.2.dev67+gbde03f4
384 Index
build123d, Release 0.9.2.dev67+gbde03f4
Index 385
build123d, Release 0.9.2.dev67+gbde03f4
386 Index
build123d, Release 0.9.2.dev67+gbde03f4
Index 387
build123d, Release 0.9.2.dev67+gbde03f4
U X
Until (class in build_enums), 296 X (Vector property), 310
unwrap() (Compound method), 317 x_axis (Location property), 305
V Y
Vector (class in geometry), 310 Y (Vector property), 310
Vertex (class in topology), 374 y_axis (Location property), 305
vertex() (in module build_common), 232
vertex() (Mixin1D method), 339 Z
vertex() (Mixin2D method), 341 Z (Vector property), 310
vertex() (Mixin3D method), 345 z_axis (Location property), 305
vertex() (ShapeList method), 362
vertex() (Vertex method), 376
vertex_A (Triangle attribute), 215
vertex_B (Triangle attribute), 215
vertex_C (Triangle attribute), 215
vertex_counts (Mesher property), 275
vertices() (Builder method), 293
vertices() (in module build_common), 232
vertices() (Mixin1D method), 339
vertices() (Mixin2D method), 341
vertices() (Mixin3D method), 345
vertices() (ShapeList method), 363
vertices() (Vertex method), 376
volume (Compound property), 317
volume (Face property), 333
volume (Mixin1D property), 339
volume (Shell property), 364
volume (Solid property), 370
VOLUME (SortBy attribute), 296
volume (Vertex property), 376
W
Wedge (class in objects_part), 219
width (Face property), 333
Wire (class in topology), 370
wire() (Face method), 333
wire() (in module build_common), 232
wire() (Mixin1D method), 339
wire() (Mixin3D method), 345
wire() (Shape method), 359
wire() (ShapeList method), 363
wires() (Builder method), 293
wires() (Curve method), 376
wires() (in module build_common), 232
wires() (Mixin1D method), 339
wires() (Mixin2D method), 341
wires() (Mixin3D method), 345
wires() (Shape method), 359
wires() (ShapeList method), 363
without_holes() (Face method), 333
wrapped (Vector property), 313
write() (Mesher method), 275
388 Index