Skip to content

Commit

Permalink
Adding Stud Wall & Platonic Solids examples
Browse files Browse the repository at this point in the history
  • Loading branch information
gumyr committed Feb 17, 2024
1 parent ef7358e commit 72827ff
Show file tree
Hide file tree
Showing 5 changed files with 347 additions and 7 deletions.
Binary file added docs/assets/examples/platonic_solids.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/examples/stud_wall.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
66 changes: 59 additions & 7 deletions docs/examples_1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The build123d Examples
Overview
--------------------------------

In the GitHub repository you will find an `examples folder <https://github.com/42sol-eu/build123d/tree/examples>`_
In the GitHub repository you will find an `examples folder <https://github.com/42sol-eu/build123d/tree/examples>`_.

Most of the examples show the builder and algebra modes.

Expand Down Expand Up @@ -39,18 +39,26 @@ Most of the examples show the builder and algebra modes.
:link: examples-build123d_logo
:link-type: ref


.. grid-item-card:: Circuit Board With Holes |Builder| |Algebra|
:img-top: assets/examples/thumbnail_canadian_flag_01.png
:img-top: assets/examples/thumbnail_circuit_board_01.png
:link: examples-canadian_flag
:link-type: ref


.. grid-item-card:: Canadian Flag Blowing in The Wind |Builder| |Algebra|
:img-top: assets/examples/thumbnail_circuit_board_01.png
:img-top: assets/examples/thumbnail_canadian_flag_01.png
:link: examples-circuit_board
:link-type: ref


.. grid-item-card:: Stud Wall |Algebra|
:img-top: assets/examples/stud_wall.png
:link: stud_wall
:link-type: ref

.. grid-item-card:: Platonic Solids |Algebra|
:img-top: assets/examples/platonic_solids.png
:link: platonic_solids
:link-type: ref

.. NOTE 01: insert new example thumbnails above this line
.. TODO: Copy this block to add the example thumbnails here
Expand All @@ -71,7 +79,8 @@ Low Poly Benchy
:align: center


The Benchy examples shows hot to import a STL model as a `Solid` object with the class `Mesher` and change it to low poly.
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.

.. note
Expand Down Expand Up @@ -240,6 +249,49 @@ This example demonstrates placing holes around a part.
:start-after: [Code]
:end-before: [End]

.. _stud_wall:

Stud Wall
---------
.. image:: assets/examples/stud_wall.png
:align: center

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.

.. dropdown:: |Algebra| Reference Implementation (Algebra Mode)

.. literalinclude:: ../examples/stud_wall.py
:start-after: [Code]
:end-before: [End]

.. _platonic_solids:

Platonic Solids
---------------
.. image:: assets/examples/platonic_solids.png
:align: center

This example creates a custom Part object PlatonicSolid.

Platonic solids are five three-dimensional shapes that are highly symmetrical,
known since antiquity and named after the ancient Greek philosopher Plato.
These solids are unique because their faces are congruent regular polygons,
with the same number of faces meeting at each vertex. The five Platonic solids
are the tetrahedron (4 triangular faces), cube (6 square faces), octahedron
(8 triangular faces), dodecahedron (12 pentagonal faces), and icosahedron
(20 triangular faces). Each solid represents a unique way in which identical
polygons can be arranged in three dimensions to form a convex polyhedron,
embodying ideals of symmetry and balance.

.. dropdown:: |Algebra| Reference Implementation (Algebra Mode)

.. literalinclude:: ../examples/platonic_solids.py
:start-after: [Code]
:end-before: [End]

.. NOTE 02: insert new example thumbnails above this line
Expand Down
140 changes: 140 additions & 0 deletions examples/platonic_solids.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
"""
The Platonic solids as custom Part objects.
name: platonic_solids.py
by: Gumyr
date: February 17, 2024
desc:
This example creates a custom Part object PlatonicSolid.
Platonic solids are five three-dimensional shapes that are highly symmetrical,
known since antiquity and named after the ancient Greek philosopher Plato.
These solids are unique because their faces are congruent regular polygons,
with the same number of faces meeting at each vertex. The five Platonic solids
are the tetrahedron (4 triangular faces), cube (6 square faces), octahedron
(8 triangular faces), dodecahedron (12 pentagonal faces), and icosahedron
(20 triangular faces). Each solid represents a unique way in which identical
polygons can be arranged in three dimensions to form a convex polyhedron,
embodying ideals of symmetry and balance.
license:
Copyright 2024 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.
"""

# [Code]
from build123d import *
from math import sqrt
from typing import Union, Literal
from scipy.spatial import ConvexHull

from ocp_vscode import show

PHI = (1 + sqrt(5)) / 2 # The Golden Ratio


class PlatonicSolid(BasePartObject):
"""Part Object: Platonic Solid
Create one of the five convex Platonic solids.
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).
align (Union[None, Align, tuple[Align, Align, Align]], optional): align min, center,
or max of object. Defaults to None.
mode (Mode, optional): combine mode. Defaults to Mode.ADD.
"""

tetrahedron_vertices = [(1, 1, 1), (1, -1, -1), (-1, 1, -1), (-1, -1, 1)]

cube_vertices = [(i, j, k) for i in [-1, 1] for j in [-1, 1] for k in [-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,
6: cube_vertices,
8: octahedron_vertices,
12: dodecahedron_vertices,
20: icosahedron_vertices,
}
_applies_to = [BuildPart._tag]

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}"
)

# Create a convex hull from the vertices
hull = ConvexHull(platonic_vertices).simplices.tolist()

# Create faces from the vertex indices
platonic_faces = []
for face_vertex_indices in hull:
corner_vertices = [platonic_vertices[i] for i in face_vertex_indices]
platonic_faces.append(
Face.make_from_wires(Wire.make_polygon(corner_vertices))
)

# Create the solid from the Faces
platonic_solid = Solid.make_solid(Shell.make_shell(platonic_faces)).clean()

# 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
)

super().__init__(part=platonic_solid, rotation=rotation, align=align, mode=mode)


solids = [
Rot(0, 0, 72 * i) * Pos(1, 0, 0) * PlatonicSolid(faces)
for i, faces in enumerate([4, 6, 8, 12, 20])
]
show(solids)

# [End]
148 changes: 148 additions & 0 deletions examples/stud_wall.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
"""
Stud Wall creation using RigidJoints to position components.
name: stud_wall.py
by: Gumyr
date: February 17, 2024
desc:
This example builds stud walls from dimensional lumber as an assembly
with the parts positioned with RigidJoints.
license:
Copyright 2024 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 build123d import *
from ocp_vscode import show
from typing import Union
import copy


# [Code]
class Stud(BasePartObject):
"""Part Object: Stud
Create a dimensional framing 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).
align (Union[Align, tuple[Align, Align, Align]], optional): align min, center,
or max of object. Defaults to (Align.CENTER, Align.CENTER, Align.MIN).
mode (Mode, optional): combine mode. Defaults to Mode.ADD.
"""

_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

# Create the basic shape
with BuildPart() as stud:
with BuildSketch():
RectangleRounded(thickness, width, 0.25 * IN)
extrude(amount=length)

# Create a Part object with appropriate alignment and rotation
super().__init__(part=stud.part, rotation=rotation, align=align, mode=mode)

# Add joints to the ends of the stud
RigidJoint("end0", self, Location())
RigidJoint("end1", self, Location((0, 0, length), (1, 0, 0), 180))


class StudWall(Compound):
"""StudWall
A simple stud wall assembly with top and sole plates.
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))

# Create a single stud that will be copied for efficiency
stud = Stud(height - 2 * stud_thickness, depth, 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"])

# Build the assembly of parts
super().__init__(children=[top_plate, sole_plate] + studs)

# Add joints to the wall
RigidJoint("inside0", self, Location((depth / 2, depth / 2, 0), (0, 0, 1), 90))
RigidJoint("end0", self, Location())


x_wall = StudWall(13 * FT)
y_wall = StudWall(9 * FT)
x_wall.joints["inside0"].connect_to(y_wall.joints["end0"])

show(x_wall, y_wall, render_joints=False)
# [End]

0 comments on commit 72827ff

Please sign in to comment.