D3.1 Beam Curves

Calculate edge beam locations

The knit needs to be stretched along its reaction force direction. We can use the reaction forces we have calculated previously in the form-finding session to estimate the location of the beams.

Modify the reaction force direction for the vertices in the corners.

if (mesh.vertex_degree(u) == 2 and mesh.vertex_degree(v) == 3) \
or (mesh.vertex_degree(u) == 3 and mesh.vertex_degree(v) == 4):
    rx, ry, rz = mesh.vertex_attributes(v, ('rx', 'ry', 'rz'))
else:
    rx, ry, rz = mesh.vertex_attributes(u, ('rx', 'ry', 'rz'))

Scale the vertex length to acquire the an estimated location of points on the beam curve.

residual = scale_vector(normalize_vector([rx, ry, rz]), knit_beam_dis)

We can save these estimated points as vertex_attribute.

mesh.update_default_vertex_attributes({'beam_pt': None})
yz = mesh.vertex_coordinates(vkey)
mesh.vertex_attribute(vkey, 'beam_pt', subtract_vectors(xyz, residual))

Find estimated beam polyline

Now we can try to find a 2-d curve to generate our beam. First, we need to find the points along the boundary in sequence.

# find one edge whose edge attribute is seam 
start = list(mesh.edges_where({'seam': True}))[0]

# find the edge loop
loop = mesh.edge_loop(start)
loop_vertices = list(flatten(loop)) 
seen = set()
loop_vertices = [x for x in loop_vertices if x not in seen and not seen.add(x)]
points = mesh.vertices_attributes('xyz', keys=loop_vertices)
polyline = Polyline(points)

Visualization

polyartist = PolylineArtist(polyline, layer="DF2021:: Beam:: Seam:: local")
polyartist.clear_layer()
polyartist.draw(show_points=True)

Transform the polyline to world XY plane

Note that the estimated points are not located in a plane. We can find a best-fit plane from these points. Given a thickness of the beam, all points along the reaction force directions can be projected to the beam.

The best-fit plane can be found in COMPAS using a proxy.

proxy = Proxy('compas.geometry')
bestfit = proxy.bestfit_frame_numpy
local_frame = bestfit(polyline)

Now we can transfer the polyline to world xy plane.

world = Frame.worldXY()
T_local_xy = Transformation.from_frame_to_frame(Frame(*local_frame), world)
polyline_T = polyline.transformed(T_local_xy)

The points are not in world XY plane, which should be projected to world XY plane.

# if the polyline is not in xy plane, run the following 
points = polyline_T.points
xy_points = project_points_plane(points, ([0, 0, 0], [0, 0, 1]))
polyline_T = Polyline(xy_points)

Then we can translate the polyline in xy plane back to the local frame.

Offset the boundary curve

We will offset the boundary curve outwards to generate the beam curve. Note that offset polyline follow the principle: Distance > 0: offset to the "left", distance < 0: offset to the "right". Thus, we need to check the correct offset direction.

# check polyline direction
polyline_vec = subtract_vectors(points[-1], points[0])
cross_vec = cross_vectors(polyline_vec, zaxis_local)
if dot_vectors(cross_vec, [0, 0, 1]) < 0:
    # zaxis_local = scale_vector(zaxis_local, -1)
    polyline = Polyline(points[::-1])

Last updated