def __main__(stdscr, projection=False): angleX, angleY, angleZ = 0, 0, 0 c = Canvas() while 1: # Will hold transformed vertices. t = [] for v in vertices: # Rotate the point around X axis, then around Y axis, and finally around Z axis. p = v.rotateX(angleX).rotateY(angleY).rotateZ(angleZ) if projection: # Transform the point from 3D to 2D p = p.project(50, 50, 50, 50) #Put the point in the list of transformed vertices t.append(p) for f in faces: for x,y in line(t[f[0]].x, t[f[0]].y, t[f[1]].x, t[f[1]].y): c.set(x,y) for x,y in line(t[f[1]].x, t[f[1]].y, t[f[2]].x, t[f[2]].y): c.set(x,y) for x,y in line(t[f[2]].x, t[f[2]].y, t[f[3]].x, t[f[3]].y): c.set(x,y) for x,y in line(t[f[3]].x, t[f[3]].y, t[f[0]].x, t[f[0]].y): c.set(x,y) f = c.frame(-40, -40, 80, 80) stdscr.addstr(0, 0, '{0}\n'.format(f)) stdscr.refresh() angleX += 2 angleY += 3 angleZ += 5 sleep(1.0/20) c.clear()
def draw_tracked_object(self): """ Converts latitude/longitude positions into Canvas positions Draws the current tracked object """ footer_msg = "TRACKING:" if self.parentApp.tracked_object is None: footer_msg += " -" self.w_map_box.footer = footer_msg return coords = self.parentApp.tracked_object.track_global_coordinates() if coords == None: footer_msg += "\"{}\" COORDS:(N/A)".format( str(self.parentApp.tracked_object.name)) else: lat, lon = coords coord_msg = "{},{}".format(round(lat, 2), round(lon, 2)) footer_msg += "\"{}\" COORDS:({})".format( str(self.parentApp.tracked_object.name), coord_msg) point = convert_gps_coord_to_canvas_coord(lat, lon, self.map_pixel_limits) self.map_canvas.set(point[0], point[1]) #self.map_canvas.set_text(point[0],point[1],coord_msg) h_line = drawille.line(self.map_pixel_limits["min_x"], point[1], self.map_pixel_limits["max_x"], point[1]) v_line = drawille.line(point[0], self.map_pixel_limits["min_y"], point[0], self.map_pixel_limits["max_y"]) for i in v_line: self.map_canvas.set(i[0], i[1]) for i in h_line: self.map_canvas.set(i[0], i[1]) self.w_map_box.footer = footer_msg
def __main__(stdscr, projection=False): angleX, angleY, angleZ = 0, 0, 0 c = Canvas() while 1: # Will hold transformed vertices. t = [] for v in vertices: # Rotate the point around X axis, then around Y axis, and finally around Z axis. p = v.rotateX(angleX).rotateY(angleY).rotateZ(angleZ) if projection: # Transform the point from 3D to 2D p = p.project(50, 50, 50, 50) #Put the point in the list of transformed vertices t.append(p) for f in faces: for x, y in line(t[f[0]].x, t[f[0]].y, t[f[1]].x, t[f[1]].y): c.set(x, y) for x, y in line(t[f[1]].x, t[f[1]].y, t[f[2]].x, t[f[2]].y): c.set(x, y) for x, y in line(t[f[2]].x, t[f[2]].y, t[f[3]].x, t[f[3]].y): c.set(x, y) for x, y in line(t[f[3]].x, t[f[3]].y, t[f[0]].x, t[f[0]].y): c.set(x, y) f = c.frame(-40, -40, 80, 80) stdscr.addstr(0, 0, '{0}\n'.format(f)) stdscr.refresh() angleX += 2 angleY += 3 angleZ += 5 sleep(1.0 / 20) c.clear()
def draw_simple_map(stdscr): c = Canvas() v1 = Point(-20, 20) v2 = Point(20, 20) v3 = Point(-20, -20) v4 = Point(20, -20) lines = [ (v1, v2), (v1, v3), (v3, v4), (v4, v2), ] for start, end in lines: for x, y in line(start.x, start.y, end.x, end.y): c.set(x, y) df = c.frame(-40, -40, 80, 80) stdscr.addstr(1, 0, f"{df}") stdscr.refresh() sleep(10) c.clear()
def __main__(stdscr, projection=False): angleX, angleY, angleZ = 0, 0, 0 canvas = Canvas() while 1: # Will hold transformed vertices. transformed_vertices = [] for vertex in vertices: # Rotate the point around X axis, then around Y axis, and finally around Z axis. point = vertex.rotateX(angleX).rotateY(angleY).rotateZ(angleZ) if projection: # Transform the point from 3D to 2D point = point.project(50, 50, 50, 50) #Put the point in the list of transformed vertices transformed_vertices.append(point) for face in faces: for x, y in line(transformed_vertices[face[0]].x, transformed_vertices[face[0]].y, transformed_vertices[face[1]].x, transformed_vertices[face[1]].y): canvas.set(x, y) for x, y in line(transformed_vertices[face[1]].x, transformed_vertices[face[1]].y, transformed_vertices[face[2]].x, transformed_vertices[face[2]].y): canvas.set(x, y) for x, y in line(transformed_vertices[face[2]].x, transformed_vertices[face[2]].y, transformed_vertices[face[3]].x, transformed_vertices[face[3]].y): canvas.set(x, y) for x, y in line(transformed_vertices[face[3]].x, transformed_vertices[face[3]].y, transformed_vertices[face[0]].x, transformed_vertices[face[0]].y): canvas.set(x, y) frame = canvas.frame(-40, -40, 80, 80) stdscr.addstr(0, 0, '{0}\n'.format(frame)) stdscr.refresh() angleX += 2 angleY += 3 angleZ += 5 sleep(1.0 / 20) canvas.clear()
def move(self, x, y): """Move the turtle to a coordinate. :param x: x coordinate :param y: y coordinate """ if self.brush_on: for lx, ly in line(self.pos_x, self.pos_y, x, y): self.set(lx, ly) self.pos_x = x self.pos_y = y
def __main__(projection=False): angleX, angleY, angleZ = 0, 0, 0 c = Canvas() while 1: # Will hold transformed vertices. t = [] for v in vertices: # Rotate the point around X axis, then around Y axis, and finally around Z axis. p = v.rotateX(angleX).rotateY(angleY).rotateZ(angleZ) if projection: # Transform the point from 3D to 2D p = p.project(50, 50, 50, 50) # Put the point in the list of transformed vertices t.append(p) for f in faces: for x, y in line(t[f[0]].x, t[f[0]].y, t[f[1]].x, t[f[1]].y): c.set(x, y) for x, y in line(t[f[1]].x, t[f[1]].y, t[f[2]].x, t[f[2]].y): c.set(x, y) for x, y in line(t[f[2]].x, t[f[2]].y, t[f[3]].x, t[f[3]].y): c.set(x, y) for x, y in line(t[f[3]].x, t[f[3]].y, t[f[0]].x, t[f[0]].y): c.set(x, y) f = c.frame(-20, -20, 20, 20) s = 'broadcast "\\n\\n\\n' for l in format(f).splitlines(): s += l.replace(" ", " ").rstrip("\n") + "\\n" s = s[:-2] s += '"' print(s) sys.stdout.flush() angleX += 2 angleY += 3 angleZ += 5 sleep(1.0 / 10) c.clear()
def __main__(projection=False): angleX, angleY, angleZ = 0, 0, 0 c = Canvas() while 1: # Will hold transformed vertices. t = [] for v in vertices: # Rotate the point around X axis, then around Y axis, and finally around Z axis. p = v.rotateX(angleX).rotateY(angleY).rotateZ(angleZ) if projection: # Transform the point from 3D to 2D p = p.project(50, 50, 50, 50) #Put the point in the list of transformed vertices t.append(p) for f in faces: for x, y in line(t[f[0]].x, t[f[0]].y, t[f[1]].x, t[f[1]].y): c.set(x, y) for x, y in line(t[f[1]].x, t[f[1]].y, t[f[2]].x, t[f[2]].y): c.set(x, y) for x, y in line(t[f[2]].x, t[f[2]].y, t[f[3]].x, t[f[3]].y): c.set(x, y) for x, y in line(t[f[3]].x, t[f[3]].y, t[f[0]].x, t[f[0]].y): c.set(x, y) f = c.frame(-20, -20, 20, 20) s = 'broadcast "\\n\\n\\n' for l in format(f).splitlines(): s += l.replace(' ', ' ').rstrip('\n') + '\\n' s = s[:-2] s += '"' print(s) sys.stdout.flush() angleX += 2 angleY += 3 angleZ += 5 sleep(1.0 / 10) c.clear()
def polygon(center_x=0, center_y=0, sides=4, radius=4): degree = float(360) / sides for n in range(sides): a = n * degree b = (n + 1) * degree x1 = (center_x + math.cos(math.radians(a))) * (radius + 1) / 2 y1 = (center_y + math.sin(math.radians(a))) * (radius + 1) / 2 x2 = (center_x + math.cos(math.radians(b))) * (radius + 1) / 2 y2 = (center_y + math.sin(math.radians(b))) * (radius + 1) / 2 for x, y in line(x1, y1, x2, y2): yield x, y
def __main__(): points = [] for i in range(8): at = i ^ (i >> 1) points.append(ones((3, 1))) for j in range(3): if (at & (1 << j) != 0): points[i][j][0] = -1. points[i] = scala / 2 * matmul(imat, points[i]) ft = omega / fps rotmat = array([[cos(ft), 0., -sin(ft)], [0., 1., 0.], [sin(ft), 0., cos(ft)]]) at = 0 while True: frame = [] frame.extend([coords for coords in line(bor, bor, bor, -bor)]) frame.extend([coords for coords in line(bor, -bor, -bor, -bor)]) frame.extend([coords for coords in line(-bor, -bor, -bor, bor)]) frame.extend([coords for coords in line(-bor, bor, bor, bor)]) for i in range(8): points[i] = matmul(rotmat, points[i]) for edge in edges: x1 = float(points[edge[0]][0][0]) y1 = float(points[edge[0]][1][0]) z1 = float(points[edge[0]][2][0]) x2 = float(points[edge[1]][0][0]) y2 = float(points[edge[1]][1][0]) z2 = float(points[edge[1]][2][0]) obloc = o + wobble * sin((1 + sqrt(5)) * ft * at) x1p, y1p = drawproj(x1, y1, z1, obloc, s, o) x2p, y2p = drawproj(x2, y2, z2, obloc, s, o) frame.extend([coords for coords in line(x1p, y1p, x2p, y2p)]) yield frame at += 1
def _render_canvas(self, name, mx, my): if not self.canvases[name]["dirty"]: # Nothing to do unless the canvas data is dirty. return # NOTE: We can only show at most (x*2) data points because of how the # braille trick works. # We're also accounting for the screen borders, the buffers for # the axis edges, as well as buffering the data some more. _m = -((mx - 2 - (self.edge_buffer + self.data_buffer)) * 2) data = list(self.canvases[name]["data"])[_m:] max_point = float(max(data)) # Round our vertical axes up to the nearest five. This just looks nicer. max_axes = int(math.ceil(max_point / self.rounding)) * self.rounding # max_points represents the "100%" mark for our y-axis. i.e. top. max_points = (my * 4) - self.edge_buffer * 2 - self.data_buffer * 2 canvas = self.canvases[name]["canvas"] canvas.clear() canvas.set(0, 0) # TODO: why do I need this hack? lx, ly = -1, -1 for i, point in enumerate(data): x = i - self.edge_buffer + self.data_buffer # 0 -> 0%, max_point -> 100% mapped = self.map(float(point), 0.0, max_point, 0.0, float(max_points)) # account for edges and stuff, my*8/2 etc. y = (my * 4) - self.edge_buffer - self.data_buffer - mapped canvas.set(x, y) if not self.fill: continue if lx == -1 and ly == -1: lx, ly = x, y continue # Draw a line between the new points and the last point. # It just makes it look better. for nx, ny in line(lx, ly, x, y): canvas.set(nx, ny) lx, ly = x, y
def render_spirograph(c): for n in range(int(cycles.value * resolution.value*100)): i = float(n) / float(resolution.value*100) pow1 = math.pow(c1.value, i) pow2 = math.pow(c2.value, i) pow3 = math.pow(c3.value, i) x1 = a1.value * 100 * pow1 * math.cos(math.pi*2*(i*w1.value + p1.value)) y1 = a1.value * 100 * pow1 * math.sin(math.pi*2*(i*w1.value + p1.value)) x2 = a2.value * 100 * pow2 * math.cos(math.pi*2*(i*w2.value + p2.value)) y2 = a2.value * 100 * pow2 * math.sin(math.pi*2*(i*w2.value + p2.value)) x3 = a3.value * 100 * pow3 * math.cos(math.pi*2*(i*w3.value + p3.value)) y3 = a3.value * 100 * pow3 * math.sin(math.pi*2*(i*w3.value + p3.value)) x = (x1 + x2 + x3)*width/500 + width/2 y = (y1 + y2 + y3)*height/500 + height/2 if n != 0 and not ((x < 0 or x > width) and (y < 0 or y > width) and (prevx < 0 or prevx > height) and (prevy < 0 or prevy > height)): for px,py in drawille.line(prevx, prevy, x, y): c.set(px, py) prevx = x prevy = y
def __main__(): i = 0 height = 40 while True: frame = [] frame.extend([coords for coords in line(0, height, 180, math.sin(math.radians(i)) * height + height)]) frame.extend([(x/2, height + math.sin(math.radians(x+i)) * height) for x in range(0, 360, 2)]) yield frame i += 2
def __main__(): i = 0 height = 40 while True: frame = [] frame.extend([ coords for coords in line(0, height, 180, math.sin(math.radians(i)) * height + height) ]) frame.extend([(x / 2, height + math.sin(math.radians(x + i)) * height) for x in range(0, 360, 2)]) yield frame i += 2
def __main__(stdscr): i = 0 c = Canvas() height = 40 while True: for x,y in line(0, height, 180, int(math.sin(math.radians(i)) * height + height)): c.set(x,y) for x in range(0, 360, 2): coords = (x/2, height + int(round(math.sin(math.radians(x+i)) * height))) c.set(*coords) f = c.frame() stdscr.addstr(0, 0, '{0}\n'.format(f)) stdscr.refresh() i += 2 sleep(1.0/24) c.clear()
def graph2canvas(graph_message): c.clear() graph_dict = json.loads(graph_message) # Draw graph to canvas by iterating through nodes for n in graph_dict['nodes']: # Draw node marker x = n['coords']['x'] y = n['coords']['y'] for xc,yc in polygon(center_x=x, center_y=y, sides=6, radius=3): c.set(xc, yc) # Draw edge line if n['edges']: for e in n['edges']: startx, starty, endx, endy = find_edge_coords( graph_dict['nodes'], e['nodevals']) for xc,yc in line(startx*2, starty*2, endx*2, endy*2): c.set(xc, yc) print(c.frame())
def clock(): radius = 16 while True: frame = [] hour, minute, second = localtime()[3:6] hours = math.pi * (4 * hour / 24. - 1./2) minutes = math.pi * (2 * minute / 60. - 1. / 2) seconds = math.pi * (2 * second / 60. - 1. / 2) for angle, length in [(hours, radius / 2), (minutes, 3 * radius / 4), (seconds, radius)]: frame.extend([c for c in line(radius, radius, radius + length * math.cos(angle), radius + length * math.sin(angle))]) frame.extend([(radius + radius * math.cos(math.radians(x)), radius + radius * math.sin(math.radians(x))) for x in range(0, 360, 3)]) yield frame
def test_row(self): self.assertEqual(list(line(0, 0, 1, 0)), [(0, 0), (1, 0)])
def view_protein(in_file, file_format=None, curr_model=1, chains=[], box_size=100.0): if box_size < 10.0 or box_size > 400.0: print("Box size must be between 10 and 400") return zoom_speed = 1.1 trans_speed = 1.0 rot_speed = 0.1 spin_speed = 0.01 action_count = 500 auto_spin = False cycle_models = False # Infer file format from extension if file_format is None: file_format = os.path.basename(in_file).rsplit(".", 1)[-1] # Handle stdin if in_file == "-": contents = sys.stdin.read() struct_file = StringIO(contents) try: # Redirect stdin from pipe back to terminal sys.stdin = open("/dev/tty", "r") except: print( "Piping structures not supported on this system (no /dev/tty)") return else: struct_file = in_file if file_format.lower() == "pdb": from Bio.PDB import PDBParser p = PDBParser() struc = p.get_structure("", struct_file) elif file_format.lower() in ("mmcif", "cif"): from Bio.PDB.MMCIFParser import MMCIFParser p = MMCIFParser() struc = p.get_structure("", struct_file) elif file_format.lower() == "mmtf": from Bio.PDB.mmtf import MMTFParser struc = MMTFParser.get_structure(struct_file) else: print("Unrecognised file format") return # Get backbone coordinates coords = [] connections = [] atom_counter, res_counter = 0, 0 chain_ids = [] for mi, model in enumerate(struc): model_coords = [] for chain in model: chain_id = chain.get_id() if len(chains) > 0 and chain_id not in chains: continue if mi == 0: chain_ids.append(chain_id) for res in chain: if mi == 0: res_counter += 1 res_n = res.get_id()[1] for atom in res: if mi == 0: atom_counter += 1 if atom.get_name() in ( "N", "CA", "C", # Protein "P", "O5'", "C5'", "C4'", "C3'", "O3'", # Nucleic acid ): if mi == 0 and len(model_coords) > 0: # Determine if the atom is connected to the previous atom connections.append(chain_id == last_chain_id and (res_n == (last_res_n + 1) or res_n == last_res_n)) model_coords.append(atom.get_coord()) last_chain_id, last_res_n = chain_id, res_n model_coords = np.array(model_coords) if mi == 0: if model_coords.shape[0] == 0: print("Nothing to show") return coords_mean = model_coords.mean(0) model_coords -= coords_mean # Center on origin of first model coords.append(model_coords) coords = np.array(coords) if curr_model > len(struc): print("Can't find that model") return info_str = "{} with {} models, {} chains ({}), {} residues, {} atoms".format( os.path.basename(in_file), len(struc), len(chain_ids), "".join(chain_ids), res_counter, atom_counter) # Make square bounding box of a set size and determine zoom x_min, x_max = float(coords[curr_model - 1, :, 0].min()), float(coords[curr_model - 1, :, 0].max()) y_min, y_max = float(coords[curr_model - 1, :, 1].min()), float(coords[curr_model - 1, :, 1].max()) x_diff, y_diff = x_max - x_min, y_max - y_min box_bound = float(np.max([x_diff, y_diff])) + 2.0 zoom = box_size / box_bound x_min = zoom * (x_min - (box_bound - x_diff) / 2.0) x_max = zoom * (x_max + (box_bound - x_diff) / 2.0) y_min = zoom * (y_min - (box_bound - y_diff) / 2.0) y_max = zoom * (y_max + (box_bound - y_diff) / 2.0) # See https://stackoverflow.com/questions/13207678/whats-the-simplest-way-of-detecting-keyboard-input-in-python-from-the-terminal/13207724 fd = sys.stdin.fileno() oldterm = termios.tcgetattr(fd) newattr = termios.tcgetattr(fd) newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO termios.tcsetattr(fd, termios.TCSANOW, newattr) oldflags = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK) canvas = Canvas() trans_x, trans_y = 0.0, 0.0 rot_x, rot_y = 0.0, 0.0 try: while True: os.system("clear") points = [] for x_start, y_start, x_end, y_end in ( (x_min, y_min, x_max, y_min), (x_max, y_min, x_max, y_max), (x_max, y_max, x_min, y_max), (x_min, y_max, x_min, y_min), ): for x, y in line(x_start, y_start, x_end, y_end): points.append([x, y]) rot_mat_x = np.array([ [1.0, 0.0, 0.0], [0.0, np.cos(rot_x), -np.sin(rot_x)], [0.0, np.sin(rot_x), np.cos(rot_x)], ], dtype=np.float32) rot_mat_y = np.array([ [np.cos(rot_y), 0.0, np.sin(rot_y)], [0.0, 1.0, 0.0], [-np.sin(rot_y), 0.0, np.cos(rot_y)], ], dtype=np.float32) trans_coords = coords[curr_model - 1] + np.array( [trans_x, trans_y, 0.0], dtype=np.float32) zoom_rot_coords = zoom * np.matmul( rot_mat_y, np.matmul(rot_mat_x, trans_coords.T)).T for i in range(coords.shape[1] - 1): if connections[i]: x_start, x_end = float(zoom_rot_coords[i, 0]), float( zoom_rot_coords[i + 1, 0]) y_start, y_end = float(zoom_rot_coords[i, 1]), float( zoom_rot_coords[i + 1, 1]) if x_min < x_start < x_max and x_min < x_end < x_max and y_min < y_start < y_max and y_min < y_end < y_max: for x, y in line(x_start, y_start, x_end, y_end): points.append([x, y]) print(info_str) print( "W/A/S/D rotates, T/F/G/H moves, I/O zooms, U spins, P cycles models, Q quits" ) canvas.clear() for x, y in points: canvas.set(x, y) print(canvas.frame()) counter = 0 while True: if auto_spin or cycle_models: counter += 1 if counter == action_count: if auto_spin: rot_y += spin_speed if cycle_models: curr_model += 1 if curr_model > len(struc): curr_model = 1 break try: k = sys.stdin.read(1) if k: if k.upper() == "O": zoom /= zoom_speed elif k.upper() == "I": zoom *= zoom_speed elif k.upper() == "F": trans_x -= trans_speed elif k.upper() == "H": trans_x += trans_speed elif k.upper() == "G": trans_y -= trans_speed elif k.upper() == "T": trans_y += trans_speed elif k.upper() == "S": rot_x -= rot_speed elif k.upper() == "W": rot_x += rot_speed elif k.upper() == "A": rot_y -= rot_speed elif k.upper() == "D": rot_y += rot_speed elif k.upper() == "U": auto_spin = not auto_spin elif k.upper() == "P" and len(struc) > 1: cycle_models = not cycle_models elif k.upper() == "Q": return break except IOError: pass finally: termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm) fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
def draw(self): for x,y in line(self.x, self.height, self.x+self.width, self.height): yield x, y for x,y in line(self.x, self.height, self.x, self.height+self.cap_height): yield x, y for x,y in line(self.x+self.width, self.height, x+self.width, self.height+self.cap_height): yield x, y for x,y in line(self.x, self.height+self.cap_height, self.x+2, self.height+self.cap_height): yield x, y for x,y in line(self.x+self.width-2, self.height+self.cap_height, self.x+self.width, self.height+self.cap_height): yield x, y for x,y in line(self.x+2, self.height+self.cap_height, self.x+2, height): yield x, y for x,y in line(self.x+self.width-2, self.height+self.cap_height, self.x+self.width-2, height): yield x, y for x,y in line(self.x, self.height-self.space, self.x+self.width, self.height-self.space): yield x, y for x,y in line(self.x, self.height-self.space, self.x, self.height-self.cap_height-self.space): yield x, y for x,y in line(self.x+self.width, self.height-self.space, x+self.width, self.height-self.cap_height-self.space): yield x, y for x,y in line(self.x, self.height-self.cap_height-self.space, self.x+2, self.height-self.cap_height-self.space): yield x, y for x,y in line(self.x+self.width-2, self.height-self.cap_height-self.space, self.x+self.width, self.height-self.cap_height-self.space): yield x, y for x,y in line(self.x+2, self.height-self.cap_height-self.space, self.x+2, 0): yield x, y for x,y in line(self.x+self.width-2, self.height-self.cap_height-self.space, self.x+self.width-2, 0): yield x, y
def test_diagonal(self): self.assertEqual(list(line(0, 0, 1, 1)), [(0, 0), (1, 1)])
def view(in_file, file_format=None, curr_model=1, chains=[], box_size=100.0): if box_size < 10.0 or box_size > 400.0: print("Box size must be between 10 and 400") return auto_spin = False cycle_models = False coords, info = read_inputs(in_file, file_format, curr_model, chains) if coords is None: return # Build help strings info_str = ( f"{os.path.basename(in_file)} with {info['num_struc']} models, " f"{len(info['chain_ids'])} chains ({''.join(info['chain_ids'])}) " f"{info['res_counter']} residues, {info['atom_counter']} atoms.") help_str = "W/A/S/D rotates, T/F/G/H moves, I/O zooms, U spins, P cycles models, Q quits" # Make square bounding box of a set size and determine zoom x_min, x_max = float(coords[curr_model - 1, :, 0].min()), float(coords[curr_model - 1, :, 0].max()) y_min, y_max = float(coords[curr_model - 1, :, 1].min()), float(coords[curr_model - 1, :, 1].max()) x_diff, y_diff = x_max - x_min, y_max - y_min box_bound = float(np.max([x_diff, y_diff])) + 2.0 zoom = box_size / box_bound x_min = zoom * (x_min - (box_bound - x_diff) / 2.0) x_max = zoom * (x_max + (box_bound - x_diff) / 2.0) y_min = zoom * (y_min - (box_bound - y_diff) / 2.0) y_max = zoom * (y_max + (box_bound - y_diff) / 2.0) # Set up curses screen # https://docs.python.org/3/howto/curses.html stdscr = curses.initscr() curses.noecho() curses.cbreak() curses.curs_set(False) stdscr.keypad(True) # Respond to keypresses w/o Enter stdscr.nodelay(True) # Don't block while waiting for keypress # Divide curses screen into windows window_info = stdscr.subwin( 2, curses.COLS - 1, # height, width 0, 0) # begin_y, begin_x window_structure = stdscr.subwin( curses.LINES - 1 - 2, curses.COLS - 1, # height, width 2, 0) # begin_y, begin_x # Print help strings (only need to do this once) window_info.addnstr(0, 0, info_str, window_info.getmaxyx()[1] - 1) window_info.addnstr(1, 0, help_str, window_info.getmaxyx()[1] - 1) window_info.refresh() canvas = Canvas() trans_x, trans_y = 0.0, 0.0 rot_x, rot_y = 0.0, 0.0 try: points = [] do_update = True while True: curses.napms(50) # Delay a short while # Re-draw structure if needed if do_update: points = [] for x_start, y_start, x_end, y_end in ( (x_min, y_min, x_max, y_min), (x_max, y_min, x_max, y_max), (x_max, y_max, x_min, y_max), (x_min, y_max, x_min, y_min), ): for x, y in line(x_start, y_start, x_end, y_end): points.append([x, y]) rot_mat_x = np.array([ [1.0, 0.0, 0.0], [0.0, np.cos(rot_x), -np.sin(rot_x)], [0.0, np.sin(rot_x), np.cos(rot_x)], ], dtype=np.float32) rot_mat_y = np.array([ [np.cos(rot_y), 0.0, np.sin(rot_y)], [0.0, 1.0, 0.0], [-np.sin(rot_y), 0.0, np.cos(rot_y)], ], dtype=np.float32) trans_coords = coords[curr_model - 1] + np.array( [trans_x, trans_y, 0.0], dtype=np.float32) zoom_rot_coords = zoom * np.matmul( rot_mat_y, np.matmul(rot_mat_x, trans_coords.T)).T for i in range(coords.shape[1] - 1): if not info['connections'][i]: continue x_start, x_end = float(zoom_rot_coords[i, 0]), float( zoom_rot_coords[i + 1, 0]) y_start, y_end = float(zoom_rot_coords[i, 1]), float( zoom_rot_coords[i + 1, 1]) # Check if the bond fits in the box if x_min < x_start < x_max and x_min < x_end < x_max and y_min < y_start < y_max and y_min < y_end < y_max: for x, y in line(x_start, y_start, x_end, y_end): points.append([x, y]) # Update displayed structure canvas.clear() for x, y in points: canvas.set(x, y) window_structure.addstr(0, 0, canvas.frame()) window_structure.refresh() do_update = False # Prepare rotation/model selection for next time if auto_spin: rot_y += spin_speed do_update = True if cycle_models: curr_model += 1 if curr_model > len(coords): curr_model = 1 do_update = True # Handle keypresses try: c = stdscr.getch() if c != curses.ERR: do_update = True if c in (ord("o"), ord("O")): zoom /= zoom_speed elif c in (ord("i"), ord("I")): zoom *= zoom_speed elif c in (ord("f"), ord("F")): trans_x -= trans_speed elif c in (ord("h"), ord("H")): trans_x += trans_speed elif c in (ord("g"), ord("G")): trans_y -= trans_speed elif c in (ord("t"), ord("T")): trans_y += trans_speed elif c in (ord("s"), ord("S")): rot_x -= rot_speed elif c in (ord("w"), ord("W")): rot_x += rot_speed elif c in (ord("a"), ord("A")): rot_y -= rot_speed elif c in (ord("d"), ord("D")): rot_y += rot_speed elif c in (ord("u"), ord("U")): auto_spin = not auto_spin elif c in (ord("p"), ord("P")) and len(coords) > 1: cycle_models = not cycle_models elif c in (ord("q"), ord("Q")): return except IOError: pass except KeyboardInterrupt: # If user presses Ctrl+C, pretend as if they pressed q. return finally: # Teardown curses interface curses.nocbreak() curses.echo() curses.curs_set(True) stdscr.keypad(False) curses.endwin() # Make sure last view stays on screen print(info_str) print(help_str) print(canvas.frame())
def test_column(self): self.assertEqual(list(line(0, 0, 0, 1)), [(0, 0), (0, 1)])
def test_single_pixel(self): self.assertEqual(list(line(0, 0, 0, 0)), [(0, 0)])
def draw_line(c, x1, y1, x2, y2): for x, y in drawille.line(x1, y1, x2, y2): c.set(x, y)
def test_single_pixel(self): self.assertEqual(list(line(0, 0, 0, 0)), [], "a line with zero length must not set any pixel")