def generate_tube_meshes(path, closed=False, tube_points=10): """Generates list of mesh vertices and triangles from a path Adapted from vispy.visuals.TubeVisual https://github.com/vispy/vispy/blob/master/vispy/visuals/tube.py Parameters ---------- path : (N, 3) array Vertices specifying the path. closed : bool Bool which determines if the path is closed or not. tube_points : int The number of points in the circle-approximating polygon of the tube's cross section. Returns ---------- centers : (M, 3) array Vertices of all triangles for the lines offsets : (M, D) array offsets of all triangles for the lines triangles : (P, 3) array Vertex indices that form the mesh triangles """ points = np.array(path).astype(float) if closed and not np.all(points[0] == points[-1]): points = np.concatenate([points, [points[0]]], axis=0) tangents, normals, binormals = _frenet_frames(points, closed) segments = len(points) - 1 # get the positions of each vertex grid = np.zeros((len(points), tube_points, 3)) grid_off = np.zeros((len(points), tube_points, 3)) for i in range(len(points)): pos = points[i] normal = normals[i] binormal = binormals[i] # Add a vertex for each point on the circle v = np.arange(tube_points, dtype=np.float) / tube_points * 2 * np.pi cx = -1.0 * np.cos(v) cy = np.sin(v) grid[i] = pos grid_off[i] = cx[:, np.newaxis] * normal + cy[:, np.newaxis] * binormal # construct the mesh indices = [] for i in range(segments): for j in range(tube_points): ip = (i + 1) % segments if closed else i + 1 jp = (j + 1) % tube_points index_a = i * tube_points + j index_b = ip * tube_points + j index_c = ip * tube_points + jp index_d = i * tube_points + jp indices.append([index_a, index_b, index_d]) indices.append([index_b, index_c, index_d]) triangles = np.array(indices, dtype=np.uint32) centers = grid.reshape(grid.shape[0] * grid.shape[1], 3) offsets = grid_off.reshape(grid_off.shape[0] * grid_off.shape[1], 3) return centers, offsets, triangles
def __init__(self, points, radius=1.0, closed=False, color='purple', tube_points=8, shading='smooth', vertex_colors=None, face_colors=None, mode='triangles'): points = np.array(points) tangents, normals, binormals = _frenet_frames(points, closed) segments = len(points) - 1 if not isinstance(radius, collections.Iterable): radius = [radius] * len(points) # get the positions of each vertex grid = np.zeros((len(points), tube_points, 3)) for i in range(len(points)): pos = points[i] normal = normals[i] binormal = binormals[i] r = radius[i] # Add a vertex for each point on the circle v = np.arange(tube_points, dtype=np.float) / tube_points * 2 * np.pi cx = -1. * r * np.cos(v) cy = r * np.sin(v) grid[i] = (pos + cx[:, np.newaxis] * normal + cy[:, np.newaxis] * binormal) # construct the mesh indices = [] for i in range(segments): for j in range(tube_points): ip = (i + 1) % segments if closed else i + 1 jp = (j + 1) % tube_points index_a = i * tube_points + j index_b = ip * tube_points + j index_c = ip * tube_points + jp index_d = i * tube_points + jp indices.append([index_a, index_b, index_d]) indices.append([index_b, index_c, index_d]) vertices = grid.reshape(grid.shape[0] * grid.shape[1], 3) color = ColorArray(color) if vertex_colors is None: point_colors = np.resize(color.rgba, (len(points), 4)) vertex_colors = np.repeat(point_colors, tube_points, axis=0) indices = np.array(indices, dtype=np.uint32) MeshVisual.__init__(self, vertices, indices, vertex_colors=vertex_colors, face_colors=face_colors, shading=shading, mode=mode)