Documentation

This commit is contained in:
Roger Maitland 2022-07-13 16:13:33 -04:00
parent 73945ed27c
commit 03917ad143
14 changed files with 705 additions and 27 deletions

View file

@ -1,23 +1,39 @@
"""
Build123D Common
name: build123d_common.py
by: Gumyr
date: July 12th 2022
desc:
This python module is a library used to build 3D parts.
TODO:
- Update Vector so it can be initialized with a Vertex or Location
- Update VectorLike to include a Vertex and Location
license:
Copyright 2022 Gumyr
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from math import radians
from typing import Union
from enum import Enum, auto
from cadquery import (
Edge,
Wire,
Vector,
Shape,
Location,
Compound,
Solid,
)
from cadquery.occ_impl.shapes import VectorLike, Real
from OCP.gp import gp_Vec, gp_Pnt, gp_Ax1, gp_Dir, gp_Trsf
from cadquery import Edge, Wire, Vector, Location
from OCP.gp import gp_Pnt, gp_Ax1, gp_Dir, gp_Trsf
import cq_warehouse.extensions
@ -61,10 +77,6 @@ class Keep(Enum):
BOTH = auto()
class FilterBy(Enum):
LAST_OPERATION = auto()
class Mode(Enum):
"""Combination Mode"""
@ -116,17 +128,6 @@ class Axis(Enum):
Z = auto()
class CqObject(Enum):
EDGE = auto()
FACE = auto()
VERTEX = auto()
class BuildAssembly:
def add(self):
pass
class SortBy(Enum):
X = auto()
Y = auto()

View file

@ -527,7 +527,7 @@ class ThreePointArc(Edge):
Add an arc generated by three points.
Args:
pts (VectorLike): sequence of three points
pts (VectorLike): sequence of three points
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
Raises:

View file

@ -11,6 +11,8 @@ desc:
TODO:
- add TwistExtrude, ProjectText
- add centered to wedge
- add Mode.REPLACE for operations like fillet that change the part
- add a Workplane class with a Plane input
license:

20
docs/Makefile Normal file
View file

@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

124
docs/advantages.rst Normal file
View file

@ -0,0 +1,124 @@
##########
Advantages
##########
As mentioned previously, the most significant advantage is that Build123D is more pythonic.
Specifically:
*******************************
Standard Python Context Manager
*******************************
The creation of standard instance variables, looping and other normal python operations
is enabled by the replacement of method chaining (fluent programming) with a standard
python context manager.
.. code-block:: python
# CadQuery Fluent API
pillow_block = (cq.Workplane("XY")
.box(height, width, thickness)
.edges("|Z")
.fillet(fillet)
.faces(">Z")
.workplane()
...
)
.. code-block:: python
# Build123D API
with BuildPart() as pillow_block:
with BuildSketch() as plan:
Rectangle(width, height)
FilletSketch(*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.
.. code-block:: python
with BuildSketch() as plan:
r = Rectangle(width, height)
print(r.Area())
...
*********
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.
.. code-block:: python
with BuildLine() as outline:
...
l5 = Polyline(...)
l6 = Polyline(...)
Spline(l5 @ 1, l6 @ 0, tangents=(l5 % 1, l6 % 0))
**********************
Last Operation Objects
**********************
All of the `vertices()`, `edges()`, `faces()`, and `solids()` methods of the builders
can either return all of the objects requested or just the objects changed during the
last operation. This allows the user to easily access features for further refinement,
as shown in the following code where the final line selects the edges that were added
by the last operation and fillets them. Such a selection would be quite difficult
otherwise.
.. literalinclude:: ../examples/intersecting_pipes.py
**********
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.
***************************
Selectors replaced by Lists
***************************
Sting based selectors have been replaced with standard python filters and
sorting which opens up the fully functionality of python list functionality.
To aid the user, common operations have been optimized as shown here along with
a fully custom selection:
.. code-block:: python
top = rail.faces().filter_by_normal(Axis.Z)[-1]
...
outside_vertices = filter(
lambda v: (v.Y == 0.0 or v.Y == height) and -width / 2 < v.X < width / 2,
din.vertices(),
)
One can sort by all of the following attributes:
.. autoclass:: build123d_common.SortBy

26
docs/build_line.rst Normal file
View file

@ -0,0 +1,26 @@
#########
BuildLine
#########
.. py:module:: build_line
.. autoclass:: BuildLine
:members:
=======
Objects
=======
.. autoclass:: CenterArc
.. autoclass:: Helix
.. autoclass:: Line
.. autoclass:: PolarLine
.. autoclass:: Polyline
.. autoclass:: RadiusArc
.. autoclass:: SagittaArc
.. autoclass:: Spline
.. autoclass:: TangentArc
.. autoclass:: ThreePointArc
==========
Operations
==========
.. autoclass:: MirrorToLine

39
docs/build_part.rst Normal file
View file

@ -0,0 +1,39 @@
#########
BuildPart
#########
.. py:module:: build_part
.. autoclass:: BuildPart
:members:
=======
Objects
=======
.. autoclass:: AddToPart
.. autoclass:: Box
.. autoclass:: Cone
.. autoclass:: Cylinder
.. autoclass:: Sphere
.. autoclass:: Torus
.. autoclass:: Wedge
==========
Operations
==========
.. autoclass:: ChamferPart
.. autoclass:: CounterBoreHole
.. autoclass:: CounterSinkHole
.. autoclass:: Extrude
.. autoclass:: FilletPart
.. autoclass:: Hole
.. autoclass:: Loft
.. autoclass:: PolarArrayToPart
.. autoclass:: PushPointsToPart
.. autoclass:: RectangularArrayToPart
.. autoclass:: Revolve
.. autoclass:: Shell
.. autoclass:: Split
.. autoclass:: Sweep
.. autoclass:: WorkplanesFromFaces

39
docs/build_sketch.rst Normal file
View file

@ -0,0 +1,39 @@
###########
BuildSketch
###########
.. py:module:: build_sketch
.. autoclass:: BuildSketch
:members:
=======
Objects
=======
.. autoclass:: AddToSketch
.. autoclass:: Circle
.. autoclass:: Ellipse
.. autoclass:: Polygon
.. autoclass:: Rectangle
.. autoclass:: RegularPolygon
.. autoclass:: SlotArc
.. autoclass:: SlotCenterPoint
.. autoclass:: SlotCenterToCenter
.. autoclass:: SlotOverall
.. autoclass:: Text
.. autoclass:: Trapezoid
==========
Operations
==========
.. autoclass:: BoundingBoxSketch
.. autoclass:: BuildFace
.. autoclass:: BuildHull
.. autoclass:: ChamferSketch
.. autoclass:: FilletSketch
.. autoclass:: MirrorToSketch
.. autoclass:: Offset
.. autoclass:: PolarArrayToSketch
.. autoclass:: PushPointsToSketch
.. autoclass:: RectangularArrayToSketch

93
docs/conf.py Normal file
View file

@ -0,0 +1,93 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
build123d_path = os.path.dirname(os.path.abspath(os.getcwd()))
source_files_path = os.path.join(build123d_path, "../")
sys.path.insert(0, source_files_path)
sys.path.append(os.path.abspath("sphinxext"))
sys.path.insert(0, os.path.abspath("."))
sys.path.insert(0, os.path.abspath("../"))
# -- Project information -----------------------------------------------------
project = "Build123D"
copyright = "2022, Gumyr"
author = "Gumyr"
# The full version, including alpha/beta/rc tags
with open(os.path.join(build123d_path, "setup.cfg")) as f:
setup_cfg = f.readlines()
for line in setup_cfg:
if "version =" in line:
release = line.split("=")[1].strip()
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
"sphinx.ext.napoleon",
"sphinx.ext.autodoc",
"sphinx_autodoc_typehints",
"sphinx.ext.doctest",
]
# Napoleon settings
napoleon_google_docstring = True
napoleon_numpy_docstring = True
napoleon_include_init_with_doc = False
napoleon_include_private_with_doc = False
napoleon_include_special_with_doc = False
napoleon_use_admonition_for_examples = False
napoleon_use_admonition_for_notes = False
napoleon_use_admonition_for_references = False
napoleon_use_ivar = True
napoleon_use_param = True
napoleon_use_rtype = True
napoleon_use_keyword = True
napoleon_custom_sections = None
autodoc_typehints = ["description"]
# autodoc_typehints = ["both"]
autodoc_mock_imports = ["cadquery", "pkg_resources", "OCP"]
# Sphinx settings
add_module_names = False
python_use_unqualified_type_names = True
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
# html_theme = "alabaster"
html_theme = "sphinx_rtd_theme"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]

10
docs/environment.yaml Normal file
View file

@ -0,0 +1,10 @@
name: docs
channels:
- conda-forge
- defaults
dependencies:
- sphinx
- nbsphinx
- pip:
- sphinx_rtd_theme
- git+https://github.com/gumyr/cq_warehouse.git#egg=cq_warehouse

90
docs/index.rst Normal file
View file

@ -0,0 +1,90 @@
..
Build123D readthedocs documentation
by: Gumyr
date: July 13th 2022
desc: This is the documentation for Build123D on readthedocs
license:
Copyright 2022 Gumyr
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
.. highlight:: python
Build123D is an alternate to the `CadQuery <https://cadquery.readthedocs.io/en/latest/index.html>`_
Fluent API. It has several advantages over this API but the largest one is that Build123D is more
Pythonic than CadQuery 2.x.
########
Overview
########
Build123D uses the standard python context manager - e.g. 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:
.. code-block:: python
with BuildPart() as my_part:
...
with BuildSketch() as my_sketch:
...
with BuildLine() as my_line:
...
...
...
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 simple bearing pillow block:
.. literalinclude:: ../examples/pillow_block.py
#################
Table Of Contents
#################
.. toctree::
:maxdepth: 2
installation.rst
advantages.rst
key_concepts.rst
build_line.rst
build_sketch.rst
build_part.rst
==================
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

8
docs/installation.rst Normal file
View file

@ -0,0 +1,8 @@
############
Installation
############
Install from github:
.. doctest::
>>> python3 -m pip install git+https://github.com/gumyr/cq_warehouse.git#egg=cq_warehouse

191
docs/key_concepts.rst Normal file
View file

@ -0,0 +1,191 @@
############
Key Concepts
############
The following key concepts will help new users understand Build123D quickly.
********
Builders
********
The three builders, `BuildLine`, `BuildSketch`, and `BuildPart` are tools to create
new objects - not the objects themselves. Each of the objects and operations applicable
to these builders create objects of the standard CadQuery Direct API, most commonly
`Compound` objects. This is opposed to CadQuery's Fluent API which creates objects
of the `Workplane` class which frequently needed to be converted back to base
class for further processing.
One can access the objects created by these builders by referencing the appropriate
instance variable. For example:
.. code-block:: python
with BuildPart() as my_part:
...
show_object(my_part.part)
.. code-block:: python
with BuildSketch() as my_sketch:
...
show_object(my_sketch.sketch)
.. code-block:: python
with BuildLine() as my_line:
...
show_object(my_line.line)
****************
Operation Inputs
****************
When one is operating on an existing object, e.g. adding a fillet to a part,
a sequence of objects is often required. A python sequence of objects is
simply either a single object or a string of objects separated by commas.
To pass an array into a sequence, precede it with a `*` operator.
When a sequence is followed by another parameter, that parameter must be
entered as a keyword parameter (e.g. radius=1) to separate this parameter
from the preceding sequence.
Here is the definition of `FilletPart` to help illustrate:
.. code-block:: python
class FilletPart(Compound):
def __init__(self, *edges: Edge, radius: float):
To use this fillet operation, a sequence of edges must be provided followed by
a fillet radius as follows:
.. code-block:: python
with BuildPart() as pipes:
Box(10, 10, 10, rotation=(10, 20, 30))
...
FilletPart(*pipes.edges(Select.LAST), radius=0.2)
Here the list of edges from the last operation of the `pipes` builder are converted
to a sequence and a radius is provided as a keyword argument.
*****************
Combination Modes
*****************
Almost all objects or operations have a `mode` parameter which is defined by the
`Mode` Enum class as follows:
.. code-block:: python
class Mode(Enum):
ADDITION = auto()
SUBTRACTION = auto()
INTERSECTION = auto()
CONSTRUCTION = 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.ADDITION` 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.SUBTRACTION` and `Mode.INTERSECTION` subtract from or intersect and object
with 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.ADDITION` but this isn't always true.
For example, the `Hole` classes use a default `Mode.SUBTRACTION` as they remove
a volume from the part under normal circumstances. However, the `mode` used in
the `Hole` classes can be specified as `Mode.ADDITION` or `Mode.INTERSECTION` to
help in inspection or debugging.
*********************************
Pushing Points & Rotating Objects
*********************************
Build123D stores points (to be specific `Locations`) internally to be used as
positions for the placement of new objects. By default, a single location
will be created at the origin of the given workplane such that:
.. code-block:: python
with BuildPart() as pipes:
Box(10, 10, 10, rotation=(10, 20, 30))
will create a single 10x10x10 box centered at (0,0,0) - by default objects are
centered. One can create multiple objects by pushing points prior to creating
objects as follows:
.. code-block:: python
with BuildPart() as pipes:
PushPointsToPart((-10, -10, -10), (10, 10, 10))
Box(10, 10, 10, rotation=(10, 20, 30))
which will create two boxes. Note that whenever points are pushed, previous
points are replaced.
To orient a part, a `rotation` parameter is available on `BuildSketch`` and
`BuildPart` APIs. When working in a sketch, the rotation is a single angle in
degrees so the parameter is a float. When working on a part, the rotation is
a three dimensional `Rotation` object of the form
`Rotation(<about x>, <about y>, <about z>)` although a simple three tuple of
floats can be used as input. As 3D rotations are not cumulative, one can
combine rotations with the `*` operator like this:
`Rotation(10, 20, 30) * Rotation(0, 90, 0)` to generate any desired rotation.
.. hint::
Experts Only
`PushPoints` will accept `Location` objects for input which allows one
to specify both the position and orientation. However, the orientation
is often determined by the `Plane` that an object was created on.
`Rotation` is a subclass of `Location` and therefore will also accept
a position component.
*************************
Builder's Pending Objects
*************************
When a builder exits, it will push the object created back to its parent if
there was one. Here is an example:
.. code-block:: python
with BuildPart() as pillow_block:
with BuildSketch() as plan:
Rectangle(width, height)
FilletSketch(*plan.vertices(), radius=fillet)
Extrude(thickness)
`BuildSketch` exits after the `FilletSketch` operation and when doing so it transfers
the sketch to the `pillow_block` instance of `BuildPart` as the internal instance variable
`pending_faces`. This allows the `Extrude` operation to be immediately invoked as it
extrudes these pending faces into `Solid` objects. Likewise, `Loft` will take all of the
`pending_faces` and attempt to create a single `Solid` object from them.
Normally the user will not need to interact directly with pending objects.
*************************************
Multiple Work Planes - BuildPart Only
*************************************
When `BuildPart` is invoked it will by default select the XY plane for the user to work on.
One can work on any plane by overriding this `workplane` parameter. The `workplane` can be changed
at any time to one or more planes which is most commonly used to create workplanes from
existing object Faces. The `WorkplanesFromFaces` class is used to do this as shown below:
.. code-block:: python
with BuildPart() as pipes:
Box(10, 10, 10, rotation=(10, 20, 30))
WorkplanesFromFaces(*pipes.faces(), replace=True)
with BuildSketch() as pipe:
Circle(4)
Extrude(-5, mode=Mode.SUBTRACTION)
In this example a `Box` is created and workplanes are created from each of the box's faces.
The following sketch is then created on each of these workplanes and the `Extrude` operation
creates holes in each of the faces of the box.

35
docs/make.bat Normal file
View file

@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd