import random from compas_rhino.artists import NetworkArtist from compas.datastructures import Network network = Network() network.add_edge(1, 2) network.add_edge(2, 3) network.add_edge(1, 4) network.add_edge(4, 5) network.add_edge(4, 6) for node in network.nodes(): x = random.choice(range(5)) y = random.choice(range(5)) z = random.choice(range(5)) network.node_attributes(node, 'xyz', [x, y, z]) print(network.summary()) text = {node: str(node) for node in network.nodes()} artist = NetworkArtist(network, layer='network') artist.clear_layer() artist.draw_nodelabels(text) artist.draw() artist.redraw()
b = network.add_node(x=10, y=0, z=10, is_anchor=True) c = network.add_node(x=10, y=10, z=0, is_anchor=True) d = network.add_node(x=0, y=10, z=10, is_anchor=True) e = network.add_node(x=5, y=5, z=0) network.add_edge(a, e) network.add_edge(b, e) network.add_edge(c, e) network.add_edge(d, e) # compute all residuals in the current geometry for node in network.nodes(): r = compute_residual(network, node) network.node_attributes(node, ['rx', 'ry', 'rz'], r) # move free nodes in direction of residual for node in network.nodes(): if network.node_attribute(node, 'is_anchor'): continue rx, ry, rz = network.node_attributes(node, ['rx', 'ry', 'rz']) x0, y0, z0 = network.node_attributes(node, 'xyz') x1 = x0 + 0.5 * rx y1 = y0 + 0.5 * ry z1 = z0 + 0.5 * rz network.node_attributes(node, 'xyz', [x1, y1, z1]) # compute all residuals in the new geometry
a = network.add_node(x=0, y=0, z=0, is_anchor=True) b = network.add_node(x=10, y=0, z=10, is_anchor=True) c = network.add_node(x=10, y=10, z=0, is_anchor=True) d = network.add_node(x=0, y=10, z=10, is_anchor=True) e = network.add_node(x=5, y=5, z=0) network.add_edge(a, e) network.add_edge(b, e) network.add_edge(c, e) network.add_edge(d, e) # compute the residual forces in the current geometry for node in network.nodes(): a = network.node_attributes(node, 'xyz') r = [0, 0, 0] for nbr in network.neighbors(node): b = network.node_attributes(nbr, 'xyz') edge = node, nbr if not network.has_edge(*edge): edge = nbr, node force = network.edge_attribute(edge, 'f') length = network.edge_length(*edge) r[0] += force * (b[0] - a[0]) / length r[1] += force * (b[1] - a[1]) / length r[2] += force * (b[2] - a[2]) / length network.node_attributes(node, ['rx', 'ry', 'rz'], r) # visualize the geometry
artist.draw_nodes(color=node_color) artist.draw_edges() # visualize the forces height = 1.0 world = Frame.worldXY() circle = [[0, 0, 0.5 * 0.7 * height], [0, 0, 1]], 0.05 cylinder = Cylinder(circle, 0.7 * height) circle = [[0, 0, 0.7 * height], [0, 0, 1]], 0.1 cone = Cone(circle, 0.3 * height) for node in network.nodes(): a = network.node_attributes(node, 'xyz') for nbr in network.neighbors(node): edge = node, nbr if not network.has_edge(*edge): edge = nbr, node b = network.node_attributes(nbr, 'xyz') force = network.edge_attribute(edge, 'f') direction = normalize_vector(subtract_vectors(b, a)) frame = Frame.from_plane([a, direction]) X = Transformation.from_frame_to_frame(world, frame) S = Scale.from_factors([force, 1, 1]) X = X * S
tol = 0.01 kmax = 100 for k in range(kmax): if k % 10 == 0: if sum(length_vector(R[i]) for i in free) < tol: break update_X() update_R() # update network for node in network.nodes(): index = node_index[node] network.node_attributes(node, ['x', 'y', 'z'], X[index]) network.node_attributes(node, ['rx', 'ry', 'rz'], R[index]) # visualize result layer = "ITA20::L5::FormFinding" artist = NetworkArtist(network, layer=layer) artist.draw_nodes(color={ node: (255, 0, 0) for node in network.nodes_where({'is_anchor': True}) }) artist.draw_edges() draw_reactions(network, layer, (0, 255, 0))