|
| 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 |
0 commit comments