def edge_midpoint(self, u, v): """Return the location of the midpoint of an edge. Parameters ---------- u : hashable The key of the start node. v : hashable The key of the end node. Returns ------- list The XYZ coordinates of the midpoint. """ a, b = self.edge_coordinates(u, v) return midpoint_line((a, b))
def edge_midpoint(self, u, v): """Return the location of the midpoint of an edge. Parameters ---------- u : int The key of the start vertex. v : int The key of the end vertex. Returns ------- list[float] The XYZ coordinates of the midpoint. """ a, b = self.edge_coordinates(u, v) return midpoint_line((a, b))
def draw_graph(vertices, edges, loop_size=1.0, spindle_size=1.0, node_radius=0.0, line_radius=0.0, key_to_colour={}): """Draw a graph in Rhino as grouped points and lines with optional element size and node colouring. Loops for edges (u, u) and parallel edges for multiple edges (u, v) and/or (v, u) are allowed. Parameters ---------- vertices : dict A dictionary of vertex keys pointing to point coordinates. edges : list A list of tuples of pairs of vertex indices. loop_size : float, optional Rough size of the loops due to edges (u, u). Default value is 1.0. spindle_size : float, optional Rough size of the spindles due to mutiple edges (u, v) and/or (v, u). Default value is 1.0. node_radius : float, optional Node radius representing the vertices. If equal to 0.0, a point is added, else a sphere. Default value is 1.0. line_radius : float, optional Line radius representing the edges. If equal to 0.0, a line is added, else a pipe. Default value is 1.0. key_to_colour : dict, optional An optional dictonary with vertex keys pointing to RGB colours. Returns ------- group : Rhino group A Rhino group with the list of points or sphere surfaces of the vertices, and the list of the list of curves or pipe surfaces of the edges. """ # nodes as points or spheres with optional colours nodes = [] for key, xyz in vertices.items(): nodes.append(rs.AddPoint(xyz) if node_radius == 0.0 else rs.AddSphere(xyz, node_radius)) if key in key_to_colour: rs.ObjectColor(nodes[-1], key_to_colour[key]) # curves curves = [] while len(edges) > 0: crvs = [] u0, v0 = edges.pop() # count occurences in case of multiple parallel edges n = 1 for u, v in edges: if (u == u0 and v == v0) or (u == v0 and v == u0): edges.remove((u, v)) n += 1 # if not loop edge if u0 != v0: start = vertices[u0] end = vertices[v0] # rough spindle of parallel edges based on third offset point mid = midpoint_line([start, end]) direction = cross_vectors(normalize_vector(subtract_vectors(end, start)), [0.0, 0.0, 1.0]) for i in range(n): k = (float(i) / float(n) * spindle_size) - spindle_size / 2.0 * (float(n) - 1.0) / float(n) dir_mid = add_vectors(mid, scale_vector(direction, k)) crvs.append(rs.AddInterpCurve([start, dir_mid, end], degree=3)) # if loop edge else: xyz0 = vertices[u0] x0, y0, z0 = xyz0 # rough loop based on three additional points xyz1 = [x0 + loop_size / 2.0, y0 - loop_size / 2.0, z0] xyz2 = [x0 + loop_size, y0, z0] xyz3 = [x0 + loop_size / 2.0, y0 + loop_size / 2.0, z0] crvs += [rs.AddInterpCurve([xyz0, xyz1, xyz2, xyz3, xyz0], degree=3) for i in range(n)] # spread if multiple loops for i, crv in enumerate(crvs): rs.RotateObject(crv, [x0, y0, z0], 360 * float(i) / float(n)) # pipe if non-null radius is specified if line_radius != 0.0: pipes = [rs.AddPipe(crv, 0, line_radius) for crv in crvs] rs.DeleteObjects(crvs) crvs = pipes curves += crvs # output group group = rs.AddGroup() rs.AddObjectsToGroup(nodes + curves, group) return group
def edge_midpoint(self, u, v): """Return the location of the midpoint of an edge.""" a, b = self.edge_coordinates(u, v) return midpoint_line((a, b))
def from_skeleton(cls, lines, radius=1): network = Network.from_lines(lines) tube_extremities = {} nodes = [] for vkey in network.vertices(): if len(network.vertex_neighbors(vkey)) > 1: points = [ network.edge_point(vkey, nbr, t=float(radius) / network.edge_length(vkey, nbr)) for nbr in network.vertex_neighbors(vkey) ] faces = convex_hull(points) mesh = cls.from_vertices_and_faces(points, faces) meshes = [] for fkey in mesh.faces(): vertices = [ mesh.edge_midpoint(u, v) for u, v in mesh.face_halfedges(fkey) ] faces = [[0, 1, 2]] meshes.append(cls.from_vertices_and_faces(vertices, faces)) for vkey_2 in mesh.vertices(): tops = [] bottoms = [] n = normalize_vector( subtract_vectors(mesh.vertex_coordinates(vkey_2), network.vertex_coordinates(vkey))) for i in range(len(mesh.vertex_neighbors(vkey_2))): pt_0 = mesh.edge_midpoint( vkey_2, mesh.vertex_neighbors(vkey_2, ordered=True)[i - 1]) bottoms.append(pt_0) pt_1 = mesh.edge_midpoint( vkey_2, mesh.vertex_neighbors(vkey_2, ordered=True)[i]) pt_2 = midpoint_line([pt_0, pt_1]) pt_2 = add_vectors( scale_vector(n, distance_point_point(pt_0, pt_1)), pt_2) tops.append(pt_2) vertices = [pt_0, pt_2, pt_1] faces = [[0, 1, 2]] meshes.append( cls.from_vertices_and_faces(vertices, faces)) for i in range(len(tops)): vertices = [tops[i - 1], tops[i], bottoms[i]] faces = [[0, 1, 2]] meshes.append( cls.from_vertices_and_faces(vertices, faces)) #print network.vertex_neighbors(vkey), network.vertex_neighbors(vkey)[vkey_2] tube_extremities[( vkey, network.vertex_neighbors(vkey)[vkey_2])] = tops mesh = meshes_join_and_weld(meshes) #dense_mesh = trimesh_subdivide_loop(mesh, k = 3) nodes.append(mesh) return nodes[0] meshes_2 = [] for u, v in network.edges(): if len(network.vertex_neighbors(u)) > 1 and len( network.vertex_neighbors(v)) > 1: #print len(tube_extremities[(u, v)]) #print len(tube_extremities[(v, u)]) if len(tube_extremities[(u, v)]) == len(tube_extremities[(v, u)]): n = len(tube_extremities[(u, v)]) l = network.edge_length(u, v) - 2 * radius m = math.floor(l / radius) + 1 pt_uv = tube_extremities[(u, v)] pt_vu = list(reversed(tube_extremities[(v, u)])) dmin = -1 imin = None for i in range(n): distance = sum([ distance_point_point(pt_uv[j], pt_vu[i + j - len(pt_vu)]) for j in range(n) ]) if dmin < 0 or distance < dmin: dmin = distance imin = i pt_vu = [pt_vu[imin + j - len(pt_vu)] for j in range(n)] array = [pt_uv] for i in range(int(m)): polygon = [] for j in range(int(n)): u = pt_uv[j] v = pt_vu[j] polygon.append( add_vectors( scale_vector(u, (float(m) - 1 - float(i)) / float(m - 1)), scale_vector(v, float(i) / float(m - 1)))) array.append(polygon) array.append(pt_vu) #print len(array), len(array[0]), len(array[1]), len(array[2]), len(array[3]) for i in range(int(n)): for j in range(int(m)): vertices = [ array[i - 1][j - 1], array[i - 1][j], array[i][j] ] faces = [[0, 1, 2]] meshes_2.append( Mesh.from_vertices_and_faces(vertices, faces)) vertices, faces = join_and_weld_meshes(meshes_2) #meshes_2 = rs.AddMesh(vertices, faces) meshes = [] for node in nodes: vertices, faces = node.to_vertices_and_faces() meshes.append(rs.AddMesh(vertices, faces))
def trimesh_skeleton(cls, lines, radius=1): network = Network.from_lines(lines) tube_extremities = {} nodes = [] for vkey in network.nodes(): if len(network.adjacency[vkey]) > 1: points = { nbr: network.edge_point(vkey, nbr, t=float(radius) / network.edge_length(vkey, nbr)) for nbr in network.adjacency[vkey] } idx_to_key = { i: key for i, key in enumerate(network.adjacency[vkey]) } faces = convex_hull(list(points.values())) faces = [[idx_to_key[idx] for idx in face] for face in faces] mesh = cls.from_vertices_and_faces(points, faces) nodes.append(mesh) meshes = [] for fkey in mesh.faces(): vertices = [ mesh.edge_midpoint(u, v) for u, v in mesh.face_halfedges(fkey) ] faces = [[0, 1, 2]] meshes.append(cls.from_vertices_and_faces(vertices, faces)) for vkey_2 in mesh.vertices(): tops = [] bottoms = [] n = normalize_vector( subtract_vectors(mesh.vertex_coordinates(vkey_2), network.node_coordinates(vkey))) for i in range(len(mesh.vertex_neighbors(vkey_2))): pt_0 = mesh.edge_midpoint( vkey_2, mesh.vertex_neighbors(vkey_2, ordered=True)[i - 1]) bottoms.append(pt_0) pt_1 = mesh.edge_midpoint( vkey_2, mesh.vertex_neighbors(vkey_2, ordered=True)[i]) pt_2 = midpoint_line([pt_0, pt_1]) pt_2 = add_vectors( scale_vector(n, distance_point_point(pt_0, pt_1)), pt_2) tops.append(pt_2) vertices = [pt_0, pt_2, pt_1] faces = [[0, 1, 2]] meshes.append(cls.from_vertices_and_faces(vertices, faces)) for i in range(len(tops)): vertices = [tops[i - 1], tops[i], bottoms[i]] faces = [[0, 1, 2]] meshes.append(cls.from_vertices_and_faces(vertices, faces)) tube_extremities[(vkey, vkey_2)] = tops mesh = meshes_join_and_weld(meshes) nodes.append(mesh) all_nodes = meshes_join_and_weld(nodes) # leaf node ring for u in network.nodes(): if len(network.adjacency[u]) == 1: v = next(iter(network.adjacency[u].keys())) ring_v = tube_extremities[(v, u)] ring_u = [ add_vectors(pt, network.edge_vector(v, u)) for pt in ring_v[::-1] ] tube_extremities[(u, v)] = ring_u beams = [] for u, v in network.edges(): geom_key_map = { geometric_key(all_nodes.vertex_coordinates(vkey)): vkey for vkey in all_nodes.vertices() } if len(tube_extremities[(u, v)]) != len(tube_extremities[(v, u)]): if len(tube_extremities[(u, v)]) < len(tube_extremities[(v, u)]): a, b = u, v else: a, b = v, u n = len(tube_extremities[(b, a)]) - len(tube_extremities[(a, b)]) for i in range(n): bdry_vkey = geom_key_map[geometric_key( tube_extremities[(a, b)][0])] nbr_vkey = None for nbr in all_nodes.vertex_neighbors(bdry_vkey): if not all_nodes.is_edge_on_boundary(bdry_vkey, nbr): nbr_vkey = nbr k = tube_extremities[(a, b)].index( all_nodes.vertex_coordinates(bdry_vkey)) new_vkey = insert_triface_on_boundary(all_nodes, bdry_vkey, nbr_vkey) tube_extremities[(a, b)].insert( k + 1 - len(tube_extremities[(a, b)]), all_nodes.vertex_coordinates(new_vkey)) if len(tube_extremities[(u, v)]) == len(tube_extremities[(v, u)]): n = len(tube_extremities[(u, v)]) l = network.edge_length(u, v) - 2 * radius m = (floor(l / radius) + 1) * 2 pt_uv = tube_extremities[(u, v)] pt_vu = list(reversed(tube_extremities[(v, u)])) dmin = -1 imin = None for i in range(n): distance = sum([ distance_point_point(pt_uv[j], pt_vu[i + j - len(pt_vu)]) for j in range(n) ]) if dmin < 0 or distance < dmin: dmin = distance imin = i pt_vu = [pt_vu[imin + j - len(pt_vu)] for j in range(n)] # ab = pt_uv# + pt_uv[0:] # dc = pt_vu# + pt_vu[0:] # line = Polyline([ab[0], dc[0]]) # ad = [line.point(i / (m - 1)) for i in range(m)] # bc = ad # vertices, faces = discrete_coons_patch(ab, bc, dc, ad) # tri_faces = [] # for (a, b, c, d) in faces: # tri_faces += [[a, b, c], [a, c, d]] # reverse? # beams.append(Mesh.from_vertices_and_faces(vertices, tri_faces)) array = [pt_uv] for i in range(int(m)): polygon = [] for j in range(int(n)): u = pt_uv[j] v = pt_vu[j] polygon.append( add_vectors( scale_vector(u, (float(m) - 1 - float(i)) / float(m - 1)), scale_vector(v, float(i) / float(m - 1)))) array.append(polygon) array.append(pt_vu) for i in range(1, int(m + 2)): for j in range(int(n)): vertices = [ array[i - 1][j - 1], array[i - 1][j], array[i][j - 1], array[i][j] ] # create staggered pattern? faces = [[3, 1, 0], [2, 3, 0]] beams.append(cls.from_vertices_and_faces(vertices, faces)) # return all_nodes # #return meshes_join_and_weld(beams) return meshes_join_and_weld([all_nodes] + beams)