added advanced algebra topics

This commit is contained in:
Bernhard 2023-03-25 19:13:24 +01:00
parent 72d083eaa0
commit c87a5a8797
13 changed files with 446 additions and 3 deletions

View file

@ -6,6 +6,9 @@ Advanced Topics
:maxdepth: 2 :maxdepth: 2
assemblies.rst assemblies.rst
algebra_performance.rst
location_arithmetic.rst
algebra_definition.rst
center.rst center.rst
custom.rst custom.rst
debugging_logging.rst debugging_logging.rst

110
docs/algebra_definition.rst Normal file
View file

@ -0,0 +1,110 @@
.. _algebra_definition:
Algebraic definition
========================
Objects and object arithmetic
----------------------------------
Set definitions:
:math:`P` is the set of all ``Part`` objects ``p`` with ``p._dim = 3``
:math:`S` is the set of all ``Sketch`` objects ``s`` with ``s._dim = 2``
:math:`C` is the set of all ``Curve`` objects ``c`` with ``c._dim = 3``
Neutral elements:
:math:`p_0` := ``p0`` is the empty ``Part`` object ``p0`` with ``p0._dim = 3`` and ``p0.wrapped = None``
:math:`s_0` := ``s0`` is the empty ``SKetch`` object ``s0`` with ``s0._dim = 2`` and ``s0.wrapped = None``
:math:`c_0` := ``c0`` is the empty ``Curve`` object ``c0`` with ``c0._dim = 1`` and ``c0.wrapped = None``
**Sets of predefined basic shapes:**
:math:`P_D := \lbrace` ``Part``, ``Box``, ``Cylinder``, ``Cone``, ``Sphere``, ``Torus``, ``Wedge``, ``Hole``, ``CounterBoreHole``, ``CounterSinkHole`` :math:`\rbrace`
:math:`S_D := \lbrace` ``Sketch``, ``Rectangle``, ``Circle``, ``Ellipse``, ``Rectangle``, ``Polygon``, ``RegularPolygon``, ``Text``, ``Trapezoid``, ``SlotArc``, ``SlotCenterPoint``, ``SlotCenterToCenter``, ``SlotOverall`` :math:`\rbrace`
:math:`C_D := \lbrace` ``Curve``, ``Bezier``, ``PolarLine``, ``Polyline``, ``Spline``, ``Helix``, ``CenterArc``, ``EllipticalCenterArc``, ``RadiusArc``, ``SagittaArc``, ``TangentArc``, ``ThreePointArc``, ``JernArc`` :math:`\rbrace`
with :math:`P_D \subset P, S_D \subset S` and :math:`C_D \subset C`
**Operations:**
:math:`+: P \times P \rightarrow P` with :math:`(a,b) \mapsto a + b`
:math:`+: S \times S \rightarrow S` with :math:`(a,b) \mapsto a + b`
:math:`+: C \times C \rightarrow C` with :math:`(a,b) \mapsto a + b`
and :math:`a + b :=` ``a.fuse(b)`` for each operation
:math:`-: P \rightarrow P` with :math:`a \mapsto -a`
:math:`-: S \rightarrow S` with :math:`a \mapsto -a`
:math:`-: C \rightarrow C` with :math:`a \mapsto -a`
and :math:`b + (-a) :=` ``b.cut(a)`` for each operation (implicit definition)
:math:`\&: P \times P \rightarrow P` with :math:`(a,b) \mapsto a \& b`
:math:`\&: S \times S \rightarrow S` with :math:`(a,b) \mapsto a \& b`
:math:`\&: C \times C \rightarrow C` with :math:`(a,b) \mapsto a \& b`
and :math:`a \; \& \; b :=` ``a.intersect(b)`` for each operation
Note: :math:`a \; \& \; b = (a + b) + -(a + (-b)) + -(b + (-a))`
**Abelian groups**
:math:`( P, p_0, +, -)`, :math:`( S, s_0, +, -)`, :math:`( C, c_0, +, -)` are abelian groups
Notes:
* The implementation ``a - b = a.cut(b)`` needs to be read as :math:`a + (-b)` since the group does not have a binary ``-`` operation. As such, :math:`a - (b - c) = a + -(b + -c)) \ne a - b + c`
* This definition also includes that neither ``-`` nor ``&`` are commutative.
Locations, planes and location arithmentic
---------------------------------------------
:math:`L := \lbrace` ``Location((x, y, z), (a, b, c))`` :math:`: x,y,z \in R \land a,b,c \in R\rbrace` with :math:`a,b,c` being angles in degrees
:math:`Q := \lbrace` ``Plane(o, x, z)`` :math:`: o,x,z ∈ R^3 \land \|x\| = \|z\| = 1\rbrace` with ``o`` being the origin and ``x``, ``z`` the x- and z-direction of the plane.
:math:`*: L \times L \rightarrow L` (multiply two locations :math:`l_1, l_2 \in L`, i.e. ``l1 * l2``)
:math:`*: Q \times L \rightarrow Q` (move plane :math:`p \in Q` to location :math:`l \in L`, i.e. ``Plane(p.to_location() * l)``)
Neutral element: :math:`l_0 \in L`: ``Location()``
Inverse element: :math:`l^{-1} \in L`: ``l.inverse()``
**Placing objects onto planes**
:math:`*: Q \times P \rightarrow P` (locate an object :math:`p \in P` onto plane :math:`q \in Q`, i.e. ``p.moved(q.to_location())``)
:math:`*: Q \times S \rightarrow S` (locate an object :math:`s \in S` onto plane :math:`q \in Q`, i.e. ``s.moved(q.to_location())``)
:math:`*: Q \times C \rightarrow C` (locate an object :math:`c \in C` onto plane :math:`q \in Q`, i.e. ``c.moved(q.to_location())``)
**Placing objects at locations**
:math:`*: L \times P \rightarrow P` (locate an object :math:`p \in P` at location :math:`l \in L`, i.e. ``p.moved(l)``)
:math:`*: L \times S \rightarrow S` (locate an object :math:`s \in S` at location :math:`l \in L`, i.e. ``s.moved(l)``)
:math:`*: L \times C \rightarrow C` (locate an object :math:`c \in C` at location :math:`l \in L`, i.e. ``c.moved(l)``)

View file

@ -0,0 +1,34 @@
.. _algebra_performance:
Performance considerations in algebra mode
===============================================
Creating lots of Shapes in a loop means for every step ``fuse`` and ``clean`` will be called.
In an example like the below, both functions get slower and slower the more objects are
already fused. Overall it takes on an M1 Mac 4.76 sec.
.. code-block:: python
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.
.. code-block:: python
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View file

@ -270,12 +270,18 @@ 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 provide multiple output formats, support for multiple languages and can be
integrated with code management tools. integrated with code management tools.
********************** ****************************************
Build123d Key Concepts Key Concepts (context mode)
********************** ****************************************
.. include:: key_concepts.rst .. include:: key_concepts.rst
****************************************
Key Concepts (algebra mode)
****************************************
.. include:: key_concepts_algebra.rst
************************ ************************
Advantages Over CadQuery Advantages Over CadQuery
************************ ************************

View file

@ -0,0 +1,135 @@
Build123d's algebra mode works on objects of the classes ``Shape``, ``Part``, ``Sketch`` and ``Curve`` and is based on two concepts:
1. **Object arithmetic**
2. **Placement arithmetic**
Object arithmetic
=====================
- Creating a box and a cylinder centered at ``(0, 0, 0)``
.. code-block:: python
b = Box(1, 2, 3)
c = Cylinder(0.2, 5)
- Fusing a box and a cylinder
.. code-block:: python
r = Box(1, 2, 3) + Cylinder(0.2, 5)
- Cutting a cylinder from a box
.. code-block:: python
r = Box(1, 2, 3) - Cylinder(0.2, 5)
- Intersecting a box and a cylinder
.. code-block:: python
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 :ref:`algebra_performance`.
Placement arithmetic
=======================
A ``Part``, ``Sketch``or ``Curve`` does not have any location or rotation paramater.
The rationale is that an object defines its topology (shape, sizes and its center), but does not know
where in space it will be located. Instead, it will be relocated with the ``*`` operator onto a plane
and to location relative to the plane (similar ``moved``).
The generic forms of object placement are:
1. Placement on ``plane`` or at ``location`` relative to XY plane:
.. code-block:: python
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 corrdinate system of the plane).
.. code-block:: python
plane * location * alg_compound
**???** Details can be found in [Locations](./docs/locations.md).
Examples:
- Box on the ``XY`` plane, centered at `(0, 0, 0)` (both forms are equivalent):
.. code-block:: python
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):
.. code-block:: python
Plane.XY * Pos(0, 1, 0) * Box(1, 2, 3)
Pos(0, 1, 0) * Box(1, 2, 3)
Pos(y=1) * Box(1, 2, 3)
Note: Again, ``Plane.XY`` can be omitted.
- Box on plane ``Plane.XZ``:
.. code-block:: python
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:
.. code-block:: python
Plane.XZ * Pos(1, 2, 3) * Box(1, 2, 3)
- 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:
.. code-block:: python
Plane.XZ * Pos(1, 2, 3) * Rot(0, 100, 45) * Box(1, 2, 3)
Location((1, 2, 3), (0, 100, 45)) * Box(1, 2, 3)
Note: ``Pos * Rot`` is the same as using ``Location`` directly
- 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:
.. code-block:: python
Plane.XZ * Rot(0, 100, 45) * Pos(0,1,2) * Box(1, 2, 3)
Combing both concepts
==========================
**Object arithmetic** and **Placement at locations** can be combined:
.. code-block:: python
b = Plane.XZ * Rot(x=30) * Box(1, 2, 3) + Plane.YZ * Pos(x=-1) * Cylinder(0.2, 5)
**Note:** In Python ``*`` binds stronger then ``+``, ``-``, ``&``, hence brackets are not needed.

View file

@ -0,0 +1,155 @@
.. _location_arithmetics:
Location arithmetic for algebra mode
======================================
Position a shape relative to the XY plane
---------------------------------------------
For the following use the helper function:
.. code-block:: python
def location_symbol(self, l=1) -> Compound:
axes = SVG.axes(axes_scale=l).locate(self)
return Compound.make_compound(axes)
1. **Positioning at a location**
.. code-block:: python
loc = Location((0.1, 0.2, 0.3), (10, 20, 30))
face = loc * Rectangle(1,2)
show_object(face, name="face")
show_object(location_symbol(loc), name="location")
.. image:: assets/location-example-01.png
2) **Positioning on a plane**
.. code-block:: python
plane = Plane.XZ
face = plane * Rectangle(1, 2)
show_object(face, name="face")
show_object(plane_symbol(plane), name="plane")
.. image:: assets/location-example-07.png
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)
Relative positioning to a plane
------------------------------------
1. **Position an object on a plane relative to the plane**
.. code-block:: python
loc = Location((0.1, 0.2, 0.3), (10, 20, 30))
face = loc * Rectangle(1,2)
box = Plane(loc) * Pos(0.2, 0.4, 0.1) * Box(0.2, 0.2, 0.2)
# box = Plane(face.location) * Pos(0.2, 0.4, 0.1) * Box(0.2, 0.2, 0.2)
# box = loc * 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")
.. image:: assets/location-example-02.png
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.
2. **Rotate an object on a plane relative to the plane**
.. code-block:: python
loc = Location((0.1, 0.2, 0.3), (10, 20, 30))
face = loc * Rectangle(1,2)
box = Plane(loc) * Rot(z=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")
.. image:: assets/location-example-03.png
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:
.. code-block:: python
loc = Location((0.1, 0.2, 0.3), (10, 20, 30))
face = loc * Rectangle(1,2)
box = loc * 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")
.. image:: assets/location-example-04.png
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**
.. code-block:: python
loc = Location((0.1, 0.2, 0.3), (10, 20, 30))
face = loc * Rectangle(1,2)
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")
.. image:: assets/location-example-05.png
The box is positioned via ``Pos(0.2, 0.4, 0.1)`` relativce to the location ``loc * Rot(20, 40, 80)``
4. **Position and rotate an object relative to a location**
.. code-block:: python
loc = Location((0.1, 0.2, 0.3), (10, 20, 30))
face = loc * Rectangle(1,2)
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")
.. image:: assets/location-example-06.png
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)`