Skip to content

Commit 9b12423

Browse files
author
pv
committed
DOCS tutorials
1 parent a13c29b commit 9b12423

7 files changed

+544
-0
lines changed

docs/tutorial.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
********************************************************************************
22
Tutorial
33
********************************************************************************
4+
5+
.. toctree::
6+
:maxdepth: 1
7+
:titlesonly:
8+
:glob:
9+
10+
tutorial/*
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from compas.geometry import Transformation
2+
from compas_dem.elements import Block
3+
from compas_dem.models import BlockModel
4+
from compas_dem.templates import ArchTemplate
5+
from compas_dem.viewer import DEMViewer
6+
7+
# Data
8+
template = ArchTemplate(rise=3, span=10, thickness=0.5, depth=0.5, n=50)
9+
10+
# Model
11+
model = BlockModel()
12+
for mesh in template.blocks():
13+
element = Block.from_mesh(mesh)
14+
model.add_element(element)
15+
16+
elements = list(model.elements())
17+
18+
# Supports
19+
for element in model.elements():
20+
centroid = element.modelgeometry.centroid()
21+
if centroid[2] < 0.3:
22+
element.is_support = True
23+
24+
# Transformation
25+
elements[25].transformation = Transformation.from_matrix(
26+
[
27+
[1, 0, 0, 0.0],
28+
[0, 1, 0, 0.0],
29+
[0, 0, 1, 1.0],
30+
[0, 0, 0, 1],
31+
]
32+
)
33+
34+
# Centroids
35+
centroids = []
36+
for el in elements:
37+
coords = el.modelgeometry.centroid()
38+
centroids.append(coords)
39+
40+
# Vertices
41+
highlight = 40
42+
vertices = []
43+
mesh = elements[highlight].modelgeometry
44+
vertices, faces = mesh.to_vertices_and_faces()
45+
46+
# Contacts
47+
model.compute_contacts(tolerance=0.001)
48+
49+
contact_polygons = []
50+
for contact in model.contacts():
51+
polygon = contact.polygon
52+
contact_polygons.append(polygon)
53+
54+
for point in polygon:
55+
print(point)
56+
57+
# Interaction
58+
edge = model.add_interaction(elements[0], elements[1])
59+
60+
# Visualization
61+
viewer = DEMViewer(model)
62+
viewer.setup()
63+
viewer.show()
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
********************************************************************************
2+
DEM Data Structure: Overview
3+
********************************************************************************
4+
5+
.. rst-class:: lead
6+
7+
A concise, step-by-step overview that builds a small block model from a template,
8+
computes contacts, inspects element data (centroids, vertices), applies a transformation,
9+
adds an interaction, converts meshes to BREP, and visualizes everything.
10+
11+
12+
Contents
13+
--------
14+
15+
1. `Data`_: instantiate an :class:`compas_dem.templates.ArchTemplate` to generate simple block meshes.
16+
2. `Model`_: create a :class:`compas_dem.models.BlockModel` and add blocks via :meth:`compas_dem.elements.Block.from_mesh`.
17+
3. `Supports`_: set fixed elements.
18+
4. `Transformation`_: assign a transformation matrix to one element to move it.
19+
5. `Centroids`_: query element geometry centroids for each block.
20+
6. `Vertices`_: iterate element geometry vertices and read vertex coordinates.
21+
7. `Contacts`_: call :meth:`compas_dem.models.BlockModel.compute_contacts` then iterate :meth:`compas_dem.models.BlockModel.contacts`.
22+
8. `Interaction`_: connect two elements via :meth:`compas_dem.models.BlockModel.add_interaction`.
23+
9. `Mesh to Brep`_: convert meshes to Brep geometry using COMPAS functions.
24+
10. `Visualization`_: use :class:`compas_dem.viewer.DEMViewer` to add model groups (supports, blocks, contacts, interactions) and overlay centroids/vertices/BREPs.
25+
26+
27+
Imports
28+
^^^^^^^
29+
30+
.. literalinclude:: dem_datastructure_overview.py
31+
:language: python
32+
:end-before: # Data
33+
34+
35+
Data
36+
^^^^
37+
38+
A model is created from a collection of solid Mesh or BRep objects. Most vault and arch topologies are written as templates to automate the geometry generation process. In this tutorial, we use the :class:`compas_dem.templates.ArchTemplate` to generate a vault topology.
39+
40+
.. literalinclude:: dem_datastructure_overview.py
41+
:language: python
42+
:start-after: # Data
43+
:end-before: # Model
44+
45+
46+
.. figure:: ../_images/dem_datastructure_overview_data.png
47+
:align: center
48+
49+
Arch template.
50+
51+
.. tip::
52+
You can also load geometry from an obj file:
53+
54+
.. code-block:: python
55+
56+
from compas.files import OBJ
57+
import pathlib
58+
59+
PATH = pathlib.Path(__file__).parent.parent.parent / "data" /
60+
FILE = "wall.obj"
61+
62+
obj = OBJ(PATH / FILE)
63+
obj.read()
64+
65+
meshes = []
66+
for name in obj.objects:
67+
vertices, faces = obj.objects[name]
68+
mesh: Mesh = Mesh.from_vertices_and_faces(vertices, faces)
69+
mesh.scale(2, 2, 2)
70+
mesh.name = name
71+
meshes.append(mesh)
72+
73+
74+
Model
75+
^^^^^
76+
77+
Then we create a :class:`compas_dem.models.BlockModel` and add blocks via :meth:`compas_dem.elements.Block.from_mesh`. The :class:`compas_dem.models.BlockModel` class represents a general model of hierarchically organized elements with interactions. It contains additional data structures such as a tree and a graph. At this step, the model and initial geometry are the same.
78+
79+
.. literalinclude:: dem_datastructure_overview.py
80+
:language: python
81+
:start-after: # Model
82+
:end-before: # Supports
83+
84+
.. tip::
85+
Check constructor overloads of :class:`compas_dem.elements.Block` to create blocks from different geometries.
86+
87+
.. code-block:: python
88+
89+
Block.from_box()
90+
Block.from_mesh()
91+
Block.from_brep()
92+
93+
.. tip::
94+
Check constructor overloads of :class:`compas_dem.models.BlockModel` to create models from various templates.
95+
96+
.. code-block:: python
97+
98+
BlockModel.from_arch()
99+
BlockModel.from_barrelvault()
100+
BlockModel.from_crossvault()
101+
BlockModel.from_fanvault()
102+
BlockModel.from_pavilionvault()
103+
BlockModel.from_triangulation_dual()
104+
BlockModel.from_meshpattern()
105+
106+
Supports
107+
^^^^^^^^
108+
109+
Elements are fixed by assigning the boolean atribute of the support.
110+
111+
.. literalinclude:: dem_datastructure_overview.py
112+
:language: python
113+
:start-after: # Supports
114+
:end-before: # Transformation
115+
116+
.. figure:: ../_images/dem_datastructure_overview_supports.png
117+
:align: center
118+
119+
Supports.
120+
121+
122+
Transformation
123+
^^^^^^^^^^^^^^
124+
125+
When we assign the transformation matrix to an element, we can change its orientation. If a tree hierarchy is used, the transformations will affect the sub-elements.
126+
127+
.. literalinclude:: dem_datastructure_overview.py
128+
:language: python
129+
:start-after: # Transformation
130+
:end-before: # Centroids
131+
132+
133+
.. figure:: ../_images/dem_datastructure_overview_transformation.png
134+
:align: center
135+
136+
Transformed block.
137+
138+
139+
Centroids
140+
^^^^^^^^^
141+
142+
We can get the centroids of the blocks:
143+
144+
.. literalinclude:: dem_datastructure_overview.py
145+
:language: python
146+
:start-after: # Centroids
147+
:end-before: # Vertices
148+
149+
.. figure:: ../_images/dem_datastructure_overview_centroids.png
150+
:align: center
151+
152+
Centroids.
153+
154+
155+
Vertices
156+
^^^^^^^^
157+
158+
We can extract vertices and faces, where vertices are stored as a list of 3 floats and faces are stored as a list of 3 or n integers.
159+
160+
.. literalinclude:: dem_datastructure_overview.py
161+
:language: python
162+
:start-after: # Vertices
163+
:end-before: # Contacts
164+
165+
.. figure:: ../_images/dem_datastructure_overview_vertices.png
166+
:align: center
167+
168+
Vertices.
169+
170+
171+
Contacts
172+
^^^^^^^^
173+
174+
We can compute contacts between blocks using the :meth:`compas_dem.models.BlockModel.compute_contacts` method. Contacts are stored as a list of contact objects. The detected contacts are highlighted in light blue color and stored as polygons. We can access the contact polygon by iterating :meth:`compas_dem.models.BlockModel.contacts` and accessing the polygon attribute.
175+
176+
.. literalinclude:: dem_datastructure_overview.py
177+
:language: python
178+
:start-after: # Contacts
179+
:end-before: # Interaction
180+
181+
.. figure:: ../_images/dem_datastructure_overview_contacts.png
182+
:align: center
183+
184+
Contacts.
185+
186+
When contacts are detected, the interaction graph displays the connectivity of the elements by lines drawn from the centroids of blocks.
187+
188+
.. figure:: ../_images/dem_datastructure_overview_graph.png
189+
:align: center
190+
191+
Graph edges.
192+
193+
194+
Interaction
195+
^^^^^^^^^^^
196+
197+
While contacts are specific interactions between blocks, interactions are more general and can be used to connect any two elements. By calling the :meth:`compas_dem.models.BlockModel.add_interaction` function, we add an edge to the model graph. Optionally, we can specify a modifier class to define how the second element is modified by the first element. Most often, we use modifiers to define solid Boolean operations between meshes or breps.
198+
199+
.. literalinclude:: dem_datastructure_overview.py
200+
:language: python
201+
:start-after: # Interaction
202+
:end-before: # Visualization
203+
204+
.. figure:: ../_images/dem_datastructure_overview_interaction.png
205+
:align: center
206+
207+
Interaction.
208+
209+
210+
Mesh to Brep
211+
^^^^^^^^^^^^
212+
213+
For using BRep outside Rhino, please insteal compas_occ package and import Brep from compas_occ.geometry. We can convert meshes to breps using COMPAS geometry functions. Breps are stored as a list of Brep objects. Or if we start from breps, we convert them to meshes by extracting polygons from brep faces.
214+
215+
.. code-block:: python
216+
217+
from compas.geometry import Brep
218+
breps = []
219+
for el in elements:
220+
brep = Brep.from_mesh(el.modelgeometry)
221+
breps.append(brep)
222+
# polygons = brep.to_polygons()
223+
# mesh = Mesh.from_polygons(polygons)
224+
225+
226+
Visualization
227+
^^^^^^^^^^^^^
228+
229+
We can visualize the model using the :class:`compas_dem.viewer.DEMViewer` class. The viewer adds model groups (supports, blocks, contacts, interactions) on the left side of the screen. At the top of the screen, there is an additional button called "COMPAS_DEM" with options: "Show Blocks", "Show Contacts", and "Show Interactions".
230+
231+
.. literalinclude:: dem_datastructure_overview.py
232+
:language: python
233+
:start-after: # Visualization
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from compas_dem.templates import ArchTemplate
2+
from compas_dem.models import BlockModel
3+
import numpy as np
4+
from typing import List, Tuple
5+
6+
# Model
7+
template: ArchTemplate = ArchTemplate(rise=3, span=10, thickness=0.5, depth=0.5, n=50)
8+
model: BlockModel = BlockModel.from_template(template)
9+
elements: List = list(model.elements())
10+
model.compute_contacts(tolerance=0.001)
11+
12+
# Meshes to Numpy Arrays
13+
numpy_vertices: List[np.ndarray] = []
14+
numpy_faces: List[np.ndarray] = []
15+
for element in elements:
16+
V, F = element.modelgeometry.to_vertices_and_faces()
17+
numpy_vertices.append(np.asarray(V, dtype=np.float64))
18+
numpy_faces.append(np.asarray(F, dtype=np.int32))
19+
20+
# Centroids
21+
centroids: List = []
22+
for element in elements:
23+
centroids.append(element.modelgeometry.centroid())
24+
numpy_centroids: np.ndarray = np.asarray(centroids, dtype=np.float64)
25+
26+
# Contact Polygons
27+
numpy_contact_polygons: List[np.ndarray] = []
28+
for contact in model.contacts():
29+
numpy_contact_polygons.append(np.asarray(contact.polygon, dtype=np.float64))
30+
31+
# Contact Indices
32+
contact_indices: List[Tuple[int, int]] = []
33+
for edge in model.graph.edges():
34+
contacts = model.graph.edge_attribute(edge, name="contacts")
35+
if contacts:
36+
contact_indices.append(edge)
37+
numpy_contact_indices: np.ndarray = np.asarray(contact_indices, dtype=np.int32)

0 commit comments

Comments
 (0)