Unified diagram


A unified diagram represents both the geometry and internal forces of a structure in a single diagram, thereby improving the legibility of reciprocal diagrams (1). In a unified diagram, the constituent polygons or cells of either the force diagram are scaled relative to the coordinates of the corresponding nodes in the form diagram, resulting in an “exploded view” of the force diagram. Each pair of neighbouring polygons of a 2D unified diagram are connected by interstitial rectangles, whereas each pair of neighbouring cells of a 3D unified diagram are connected by interstitial prisms.


Form diagram \(G\), the reciprocal force diagram \(G^\perp\) and the unified diagram \(G^{\perp}({\alpha})\) for a simple truss (After 2).

In contrast to traditional, side-by-side representation of form and force diagrams, the unique visualisation method of unified diagrams provide new insights and perspectives. Unified diagrams are not only more discernible, but also provide an interesting visual representation of the volume of material required for a uniform stress design (2). Furthermore, the unified diagram reveals visual insights in relation to some of the most fundamental principles of structural engineering and analysis, such as: kinematics and mechanisms (1); virtual work and displacements (3); and stress-fields and strut-and-tie models (4, 5).


Animation of unified diagrams for 2D trusses with varying scale factor \(\alpha\).


A simple 3D truss and its unified diagram: \(\Gamma\) of the truss, which is equivalent to \(\Gamma^{\perp}({\alpha}=1)\); and the \(\Gamma^{\perp}({\alpha})\) with varying scaling factor of \(\alpha\).


Animation of the unified diagram for a compression-only spatially branching structure.



from __future__ import absolute_import
from __future__ import print_function
from __future__ import division

import compas

import compas_rhino

from compas_rhino.helpers import volmesh_from_polysurfaces

from compas_3gs.diagrams import FormNetwork
from compas_3gs.diagrams import ForceVolMesh

from compas_3gs.algorithms import volmesh_dual_network
from compas_3gs.algorithms import volmesh_reciprocate

from compas_3gs.algorithms import volmesh_ud

from compas_3gs.utilities import get_force_mags
from compas_3gs.utilities import get_force_colors_uv
from compas_3gs.utilities import get_force_colors_hf

    import rhinoscriptsyntax as rs
except ImportError:

__author__     = 'Juney Lee'
__copyright__  = 'Copyright 2019, BLOCK Research Group - ETH Zurich'
__license__    = 'MIT License'
__email__      = 'juney.lee@arch.ethz.ch'

# ------------------------------------------------------------------------------
# 1. make vomesh from rhino polysurfaces
# ------------------------------------------------------------------------------
layer = 'force_volmesh'

guids = rs.GetObjects("select polysurfaces", filter=rs.filter.polysurface)

forcediagram       = ForceVolMesh()
forcediagram       = volmesh_from_polysurfaces(forcediagram, guids)
forcediagram.layer = layer
forcediagram.attributes['name'] = layer

# ------------------------------------------------------------------------------
# 2. make dual network from volmesh (form diagram)
# ------------------------------------------------------------------------------
layer = 'form_network'

formdiagram       = volmesh_dual_network(forcediagram, cls=FormNetwork)
formdiagram.layer = layer
formdiagram.attributes['name'] = layer

x_move = formdiagram.bounding_box()[0] * 2
for vkey in formdiagram.vertex:
    formdiagram.vertex[vkey]['x'] += x_move

# ------------------------------------------------------------------------------
# 3. reciprocate
# ------------------------------------------------------------------------------

# ------------------------------------------------------------------------------
# 4. draw unified diagram
# ------------------------------------------------------------------------------
alpha = rs.GetReal('unified diagram scale', 1, 0.01, 1.0)

hfkeys = forcediagram.halfface.keys()

# 1. get colors ----------------------------------------------------------------
hf_color = (0, 0, 0)

uv_c_dict = get_force_colors_uv(forcediagram, formdiagram, gradient=True)
# uv_c_dict = get_index_colordict(list(formdiagram.edges()))
hf_c_dict = get_force_colors_hf(forcediagram, formdiagram, uv_c_dict=uv_c_dict)

# 2. compute unified diagram geometries ----------------------------------------
halffaces, prism_faces = volmesh_ud(forcediagram, formdiagram, scale=alpha)

# 3. halffaces and prisms ------------------------------------------------------
faces = []
for hfkey in hfkeys:
    vkeys  = forcediagram.halfface[hfkey]
    hf_xyz = [halffaces[hfkey][i] for i in vkeys]
    name   = '{}.face.ud.{}'.format(forcediagram.name, hfkey)
    faces.append({'points': hf_xyz,
                  'name'  : name,
                  'color' : hf_color})

forces = get_force_mags(forcediagram, formdiagram)

for uv in prism_faces:
    name  = '{}.face.ud.prism.{}'.format(forcediagram.name, uv)

    for face in prism_faces[uv]:
        faces.append({'points': face,
                      'name'  : name,
                      'color' : uv_c_dict[uv]})

# 4. draw ----------------------------------------------------------------------




Zanni G. and Pennock G.R. (2009). A unified graphical approach to the static analysis of axially loaded structures. Mechanism and Machine Theory 44(12), 2187 – 2203.


McRobie A. (2016). Maxwell and rankine reciprocal diagrams via minkowski sums for two-dimensional and three-dimensional trusses under load. International Journal of Space Structures 31(2-4), 203–216.


McRobie A., Konstantatou M., Athanasopoulos G., and Hannigan L. (2017). Graphic kinematics, visual virtual work and elastographics. Royal Society Open Science 4(5).


Schlaich M. and Anagnostou G. (1990). Stress fields for nodes of strut-andtie models. Journal of Structural Engineering 116 (1), 13–23.


Muttoni A., Schwartz J., and Thürlimann B. (1997). Design of Concrete Structures with Stress Fields. Birkhäuser Basel.