Leaning Stack of Blocks

../_images/100_stack.png

Summary

First, we construct an assembly from a stack of blocks. Each block is slightly shifted with respect to the previous one, to creating a leaning tower. Then, we identify the interfaces of the assembly, and compute the contact forces between the blocks that result in static equilibrium with gravitational loads. Finally, we export the assembly to a JSON file and visualize the result with the DEM Viewer.

Equilibrium

Note that the contact forces (in blue) increase towards the bottom of the stack, due to the increasing weight.

The resultant forces (in green) between blocks 0 and 1, blocks 1 and 2, and blocks 2 and 3 are not contained in the interfaces between those blocks. As a result, the stack requires equilibriating “glue” forces (in red) at those interfaces.

Note

This example uses compas_cra for the equilibrium calculations. If you don’t have compas_cra installed, or simply don’t want to compute the contact forces, just comment out lines 3 and 50.

Code

import pathlib

from compas_cra.equilibrium import cra_penalty_solve

import compas
from compas.geometry import Box
from compas.geometry import Translation
from compas_assembly.algorithms import assembly_interfaces
from compas_assembly.datastructures import Assembly
from compas_assembly.datastructures import Block
from compas_assembly.viewer import DEMViewer

ASSEMBLY = pathlib.Path(__file__).parent / "stack_assembly.json"

# =============================================================================
# Geometry
# =============================================================================

base = Box(1, 1, 1)

boxes = []
for i in range(10):
    box = base.transformed(Translation.from_vector([i * 0.13, 0, i * base.zsize]))
    boxes.append(box)

# =============================================================================
# Assembly
# =============================================================================

assembly = Assembly()
for box in boxes:
    assembly.add_block(Block.from_shape(box))

# =============================================================================
# Interfaces
# =============================================================================

assembly_interfaces(assembly, nmax=10, amin=1e-2, tmax=1e-2)

# =============================================================================
# Boundary conditions
# =============================================================================

assembly.set_boundary_condition(0)

# =============================================================================
# Equilibrium
# =============================================================================

cra_penalty_solve(assembly)

# =============================================================================
# Export
# =============================================================================

compas.json_dump(assembly, ASSEMBLY)

# =============================================================================
# Viz
# =============================================================================

viewer = DEMViewer()
viewer.view.camera.position = [0, -17, 5]
viewer.view.camera.look_at([0, 0, 3])

viewer.add_assembly(assembly)

viewer.run()