Pattern from Triangulations

A triangulated pattern instead, could be a good solution in the case of a complex set of boundaries and features (holes, etc.), since, in this case, the definition of only two clear directions for the flow of forces is not possible.

Outer boundary is a closed polycurve that represents the outline of the diagram.

# ==============================================================================
# Create Pattern
# ==============================================================================
boundary_guids = compas_rhino.select_curves('Select outer boundary.')
compas_rhino.rs.UnselectAllObjects()

target_length = 1.0

gkey_constraints = {}

# outer boundary
boundary = []
for guid in boundary_guids:
    compas_rhino.rs.EnableRedraw(False)
    segments = compas_rhino.rs.ExplodeCurves(guid)
    for segment in segments:
        curve = RhinoCurve.from_guid(segment)
        N = max(int(curve.length() / target_length), 1)
        points = map(list, curve.divide(N, over_space=True))
        for point in points:
            gkey = geometric_key(point)
            if gkey not in gkey_constraints:
                gkey_constraints[gkey] = []
            gkey_constraints[gkey].append(segment)
        boundary.extend(points)
    compas_rhino.rs.HideObjects(segments)
    compas_rhino.rs.EnableRedraw(True)


area = target_length ** 2 * 0.5 * 0.5 * 1.732

proxy = Proxy()
proxy.package = 'compas.geometry'

vertices, faces = proxy.conforming_delaunay_triangulation(boundary,  angle=30, area=area)
vertices[:] = [[float(x), float(y), float(z)] for x, y, z in vertices]

pattern = Pattern.from_vertices_and_faces(vertices, faces)

Inner boundaries are openings of the intended design pattern.

hole_guids = compas_rhino.select_curves('Select inner boundaries.')
compas_rhino.rs.UnselectAllObjects()

# hole polygons
polygons = []
if hole_guids:
    for guid in hole_guids:
        curve = RhinoCurve.from_guid(guid)
        N = int(curve.length() / target_length) or 1
        points = map(list, curve.divide(N, over_space=True))
        for point in points[:-1]:
            gkey = geometric_key(point)
            if gkey not in gkey_constraints:
                gkey_constraints[gkey] = []
            gkey_constraints[gkey].append(guid)
        polygons.append(points)

Another more manual way to make holes is to delete the vertices and modify the vertices inside the hole and modify the vertices on the boundary of the hole to achieve the target shape.

TODO: add select and delete?

Constraint curves are where the vertices and edges will be forced to snapped onto.

segments_guids = compas_rhino.select_curves('Select constraint curves.')
compas_rhino.rs.UnselectAllObjects()

# constraint polylines
polylines = []
if segments_guids:
    for guid in segments_guids:
        curve = RhinoCurve.from_guid(guid)
        N = int(curve.length() / target_length) or 1
        points = map(list, curve.divide(N, over_space=True))
        for point in points:
            gkey = geometric_key(point)
            if gkey not in gkey_constraints:
                gkey_constraints[gkey] = []
            gkey_constraints[gkey].append(guid)
        polylines.append(points)

Ex. Create Free-form Vault from Triangulation

Step 1: Generate Pattern from Triangulation

After the pattern is generated, the session could be serialized.

HERE = os.path.dirname(__file__)
FILE_O = os.path.join(HERE, 'data', 'triangulation.json')
pattern.to_json(FILE_O)

Step 2: Define Boundaries

Select points to anchor.

anchors = []
guids = compas_rhino.select_points(message='Select Points to Anchor')
compas_rhino.rs.HideObjects(guids)
points = compas_rhino.get_point_coordinates(guids)
gkey_key_dict = pattern.gkey_key()
for pt in points:
    vkey = gkey_key_dict[geometric_key(pt)]
    anchors.append(vkey)
    pattern.vertex_attribute(vkey, 'is_anchor', True)

Update the boundary.

It's relatively hard to select a specific edge to compute sag, here all edges are saged at the same time.

Step 3: Generate FormDiagram

form = FormDiagram.from_pattern(pattern)

Step 4: Generate ForceDiagram

force = ForceDiagram.from_formdiagram(form)

Strep 5: Horizontal Equilibrium

Step 6: Vertical Equilibrium

Serialization, Rhino script and RV2 Session

So each diagram could be saved to json and visualize them for later use. Unfortunately, currently RV2 cannot read the FormDiagram, ForceDiagram or ThrustDiagram directly from json. The in RV2, the user could use save session and load session could let you save the ongoing session and reuse it. If a specific diagram needs to be loaded, the following code could be used.

import json

from compas.utilities import DataDecoder
from compas_rv2.datastructures import FormDiagram
from compas_rv2.scene import Scene

with open('bm-3.rv2', 'r') as f:
    session = json.load(f, cls=DataDecoder)

form = FormDiagram.from_data(session['data']['form'])

scene = Scene()
scene.settings = session['settings']
scene.add(form, name='form')
scene.update()

Last updated