Face pull operation of a cell changes the distribution of the forces. However, the precise amount of change in the area of the pulled face is not visually quantifiable, and it is not immediately apparent how the opeartion will affect the face’s oriented normal. Rather than pulling the faces in arbitrary amounts, finding the new face location such that the resulting face area matches a target value will enable a more force-controlled geometric operation.

A face’s area can be formulated as a function of its \(z\) position along its normal. A simple iterative minimisation technique, such as the Golden Section Search (1), can be used to compute the \(z\) position at which the face area is equal to the target area.


Because arearisation algorithm allows a more precise control of the areas of individual faces of a cell, and therefore the magnitudes of the forces in the corresponding members in the form diagram, it can be used to explain the concept of static indeterminacy of spatial structures. It can also demonstrate that polyhedral reciprocal diagrams are not limited to the exploration of statically determinate spatial structures, but also various possible equilibrium solutions for statically indeterminate structures (2, 3 and 4).

In an indeterminate structure, the distribution of forces among the members of the structure is highly dependent on the boundary conditions, imperfections of the building components and the tolerance accumulated during the assembly on site. Therefore, the actual internal stress state is unknown, difficult to predict and is sensitive to minor changes in the boundary conditions. Using polyhedral force diagrams and the arearisation algorithm, indeterminate states of equilibrium can be visualised and described. In the context of structural design, this indeterminacy can be exploited to explore and obtain different internal equilibrium states.




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

import time

import compas

from compas.geometry import dot_vectors

from compas.utilities import i_to_blue

from compas_rhino.helpers import mesh_from_surface
from compas_rhino.helpers import mesh_select_face

from compas_3gs.algorithms import cell_arearise_face

from compas_3gs.diagrams import Cell

from compas_3gs.operations import cell_relocate_face

from compas_3gs.rhino import MeshConduit

    import rhinoscriptsyntax as rs

except ImportError:

__author__     = 'Juney Lee'
__copyright__  = 'Copyright 2019, BLOCK Research Group - ETH Zurich'
__license__    = 'MIT License'
__email__      = ''

# ------------------------------------------------------------------------------
#   1. make cell from rhino polysurfaces
# ------------------------------------------------------------------------------
layer = 'cell'

guid = rs.GetObject("select a closed polysurface", filter=rs.filter.polysurface)

cell = mesh_from_surface(Cell, guid)

# ------------------------------------------------------------------------------
#   2. Target area
# ------------------------------------------------------------------------------
fkey   = mesh_select_face(cell)

area   = cell.face_area(fkey)
center = cell.face_centroid(fkey)
normal = cell.face_normal(fkey)

target_area = rs.GetReal("Enter target area", number=area)

# ------------------------------------------------------------------------------
#   3. Arearise cell face
# ------------------------------------------------------------------------------

# conduit
conduit = MeshConduit(cell)

def callback(cell, args):

    current_area = cell.face_area(fkey)
    color  = i_to_blue(abs(current_area - target_area) / target_area)
    conduit.face_colordict = {fkey: color}



with conduit.enabled():

# ------------------------------------------------------------------------------
#   4. Check result
# ------------------------------------------------------------------------------
new_area   = cell.face_area(fkey)
new_normal = cell.face_normal(fkey)
if dot_vectors(normal, new_normal) < 0:
    new_area *= -1

if abs(new_area - target_area) > 1:

    print('Arearisation attempted, but did not converge...')
    print('It is likely that the target area is not valid / inexistent...')

    cell_relocate_face(cell, fkey, center, normal)

# ------------------------------------------------------------------------------
#   5. Draw result
# ------------------------------------------------------------------------------


  • If a negative target area is entered, the face must flip its normal direction as well as match the magnitude of the target area. It is possible that one or both of these two constraints can not be satisfied.

  • For a positive target area, two solutions exist. The solution with a \(z\) value that is closer to the initial face position will be given.



Kiefer, J. (1953). Sequential minimax search for a maximum. In Proceedings of the American Mathematical Society 4(3), 502-506.


Kilian, A. and J. Ochsendorf (2005). Particle-spring systems for structural form finding. Journal of the International Association for Shell and Spatial Structures 46(147), 77–84.


Block, P. (2005). Equilibrium systems: Studies in masonry structure. Master’s thesis, Massachusetts Institute of Technology, Cambridge, MA, USA.


Van Mele, T., L. Lachauer, M. Rippmann and P. Block (2012). Geometry-based understanding of structures. Journal of the International Association for Shell and Spatial Structures 53(174), 285–295.