D2.1 Knit Attributes

Fabrication Constraints

Knitting offers the possibility of creating 3D geometries, including non-developable surfaces. However, we need to limit the surface size according to the size of the machine available. For a nice summary of the automatic generation of knitted surfaces, we refer to the following paper: Popescu, M., Rippmann, M., Van Mele, T. and Block, P., 2018. Automated generation of knit patterns for non-developable surfaces. In Humanizing Digital Reality (pp. 271-284). Springer, Singapore.

For the case of our prototype, we use a knitting machine of the brand and type Steiger Libra at ETH Zürich, which contains a needlebed width of 130 cm. However, there are more variables that we need to take into account, such as: - material properties: thickness of the yarn - gauge: number of needles per inch - textile architecture: stitched geometry - knitting speed - ... Taking all the parameters into account, we separate the bridge into two knittable patches. The procedure will be explained in this subchapter.

Mesh topology: edge_loop, edge_strip

We have learned the mesh data structure and some topological methods in the former sessions. We will use this information to separate the mesh into useful parts. First, let's review how to use the edge_loop and edge_strip.

In our mesh, we know that edge (67, 510) lies along the central arch. Let's find all edges on the crease, i.e. on the same loop as edge (67, 510), and all faces on the strip to the left of (67, 510) and on the strip to the right:

loop = mesh.edge_loop((67, 510))
left = [mesh.halfedge_face(*edge) for edge in mesh.halfedge_strip((67, 510))][:-1]
right = [mesh.halfedge_face(*edge) for edge in mesh.halfedge_strip((510, 67))][:-1]

The next part is only for visualising the different loops and strips. Let's color the start edge red, the edges along the loop green and the strip faces red:

edgecolor = {}
for (u, v) in loop:
    edgecolor[(u, v)] = edgecolor[(v, u)] = (0, 255, 0)

edgecolor[(67, 510)] = (255, 0, 0)

facecolor = {}
for face in left:
    facecolor[face] = (255, 200, 200)
for face in right:
    facecolor[face] = (255, 200, 200)

artist = MeshArtist(mesh, layer="DF21::KnitPatch")
artist.clear_layer()
artist.draw_faces(color=facecolor)
artist.draw_edges(color=edgecolor)

Find faces in two patches

To separate the faces of the mesh into two patches, we apply the same technique to all edges on the loop of the middle arch. For every edge on the loop, we can find the strip of faces to the left and the one to the right and combine them into the left and right patch, respectively.

edges = mesh.edge_loop((67, 510))

left = []
right = []

for u, v in edges:
    left += [mesh.halfedge_face(*edge) for edge in mesh.halfedge_strip((u, v))][:-1]
    right += [mesh.halfedge_face(*edge) for edge in mesh.halfedge_strip((v, u))][:-1]

We visualize the two patches in different colors.

facecolor = {}
for face in left:
    facecolor[face] = (255, 200, 200)

for face in right:
    facecolor[face] = (200, 255, 200)

Alternatively, we can also use compas_rhino to select the boundary edges of the corresponding patch interactively.

artist = MeshArtist(mesh, layer="DF2021_D2::KnitPatch")
artist.clear_layer()
artist.draw_faces(join_faces=True)
guids = artist.draw_edges()

artist.redraw()

guid_edge = dict(zip(guids, mesh.edges()))
guid = compas_rhino.select_line(message="Select edge on middle crease.")

if not guid:
    raise Exception('No edge was selected.')

edge = guid_edge[guid]
edges = mesh.edge_loop(edge)

left = []
right = []

for u, v in edges:
    left += [mesh.halfedge_face(*edge) for edge in mesh.halfedge_strip((u, v))][:-1]
    right += [mesh.halfedge_face(*edge) for edge in mesh.halfedge_strip((v, u))][:-1]

Update attributes

Using data-structure attributes, we can save the patch and seam information in the mesh.

mesh.update_default_face_attributes({'patch': None})
mesh.update_default_edge_attributes({'seam': False})

mesh.faces_attribute('patch', 1, keys=left)
mesh.faces_attribute('patch', 2, keys=right)

print(list(mesh.faces_where({'patch': 1})))
print(list(mesh.faces_where({'patch': 2})))

seam = mesh.edge_loop((67, 510))
mesh.edges_attribute('seam', True, edges=seam)
    
mesh.to_json(FILE_0)

Separate patches

We can separate the two patches - in this case mirror images of the same geometry - into two meshes and serialize them into JSON files . We can keep control of each of the two knitted strips by doing operations separately on each of the files.

mesh_1 = mesh.copy()
mesh_1.name = "patch_1"

for fkey in mesh.faces_where({'patch': 2}):
    mesh_1.delete_face(fkey)
mesh_1.remove_unused_vertices()

mesh_1.to_json(FILE_01)

Modify seams

We create a small gap between the two patches by offsetting the edges by a predefined seam distance.

seam_dis = 0.01

seen = []
for u, v in mesh_1.edges_where({'seam': True}):
    print(u)

    if u not in seen:
        seen.append(u)
        u_x = mesh_1.vertex_attribute(u, 'x')
        mesh_1.vertex_attribute(u, 'x', u_x - seam_dis)

    if v not in seen:
        seen.append(v)
        v_x = mesh_1.vertex_attribute(v, 'x')
        mesh_1.vertex_attribute(v, 'x', v_x - seam_dis)

Last updated