A2. Openings and Relaxation

Ex 1: Openings

An opening is a chain of edges at the boundary of a Pattern, in between two support vertices. In general, openings in TNA cannot be straight, unless there are no internal forces in the non-boundary edges at the openings (i.e. barrel vault or cross vault).

Step 1: Create a Pattern

# ==============================================================================
# Import
# ==============================================================================
import os
from compas_tna.diagrams import FormDiagram
from compas_rhino.artists import MeshArtist

# ==============================================================================
# Unserialization
# ==============================================================================
HERE = os.path.dirname(__file__)
FILE = os.path.join(HERE, 'data', 'pattern.json')
form = FormDiagram.from_json(FILE)

# ==============================================================================
#  Visualization
# ==============================================================================
artist = MeshArtist(form, layer="CSD2::form")
artist.clear_layer()
artist.draw()

Step 2: Anchor Corners

corners = list(form.vertices_where({'vertex_degree': 2}))
form.vertices_attribute('is_anchor', True, keys=corners)

Step 3: Relax Boundary

This feature relaxes the Pattern using the force density method, resulting in curved openings. For each opening, the amount of curvature is defined by using the sag , which is calculated based on the percentage of the length of the opening. The qqs for the boundary edges are automatically calculated based on the target sag values, which are then used for the force density method.

Although this feature is optional, the user should be aware that the treatment of the openings are very much dependent on the type of vault that is being investigated. In some applications where openings may already have some curvature, the relaxation will make the Pattern more "equilibrated" and optimal for the horizontal equilibrium solver later on.

# ==============================================================================
# Relax Boundaries
# ==============================================================================
form.edges_attribute('q', 10.0, keys=form.edges_on_boundary())

proxy = Proxy()
proxy.package = 'compas_tna.utilities'
formdata = proxy.relax_boundary_openings_proxy(form.to_data(), corners)
form = FormDiagram.from_data(formdata)

Step 4: Update Boundaries

Update the boundaries to add outside faces.

form.update_boundaries()

The outside faces can be hidden by the following visualization settings.

artist.draw_faces(faces=list(form.faces_where({'_is_loaded': True})))
artist.draw_edges(edges=list(form.edges_where({'_is_edge': True})))

Step 5: Create ForceDiagram

# ==============================================================================
# Force
# ==============================================================================
force = ForceDiagram.from_formdiagram(form)

# transform the force diagram for better visualization
bbox_form = form.bounding_box_xy()
bbox_force = force.bounding_box_xy()
xmin_form, xmax_form = bbox_form[0][0], bbox_form[1][0]
xmin_force, _ = bbox_force[0][0], bbox_force[1][0]
ymin_form, ymax_form = bbox_form[0][1], bbox_form[3][1]
ymin_force, ymax_force = bbox_force[0][1], bbox_force[3][1]
y_form = ymin_form + 0.5 * (ymax_form - ymin_form)
y_force = ymin_force + 0.5 * (ymax_force - ymin_force)
dx = 1.3 * (xmax_form - xmin_form) + (xmin_form - xmin_force)
dy = y_form - y_force
force.transform(Translation.from_vector([dx, dy, 0]))

# ==============================================================================
#  Visualization
# ==============================================================================
forceartist = MeshArtist(force, layer="CSD2::force")
forceartist.clear_layer()
forceartist.draw()
forceartist.draw_edges(color=(0, 0, 255))

Step 6: Solve Horizontal Equilibrium

Form and Force Diagrams are considered reciprocal if corresponding edges are perpendicular. Horizontal Equilibirum solve the edges to be penpedicular to each other.

proxy.package = 'compas_tna.equilibrium'
formdata, forcedata = proxy.horizontal_numpy_proxy(form.to_data(), force.to_data(), alpha=100)
form = FormDiagram.from_data(formdata)
force = ForceDiagram.from_data(forcedata)

Step 7: Solve Vertical Equilibrium

# ==============================================================================
#  Vertical Equilibirum
# ==============================================================================
thrustdata, scale = proxy.vertical_from_zmax_proxy(form.to_data(), zmax=3)
thrust = FormDiagram.from_data(thrustdata)

# ==============================================================================
#  Visualization
# ==============================================================================
thrustartist = MeshArtist(thrust, layer="CSD2::thrust")
thrustartist.clear_layer()
thrustartist.draw_faces(faces=list(thrust.faces_where({'_is_loaded': True})))
thrustartist.draw_edges(edges=list(thrust.edges_where({'_is_edge': True})))

Last updated