def __init__(self, graphics_canvas, name, robot=None): self.joints = [] self.num_joints = 0 self.rob_shown = True self.ref_shown = True self.opacity = 1 self.name = name self.__scene = graphics_canvas self.angles = [] self.robot = robot # If Robot given, create the robot if self.robot is not None: # Update name self.name = self.robot.name # Get initial poses zero_angles = self.robot.qz all_poses = self.robot.fkine_all(zero_angles) # Create the base if robot.basemesh is not None: self.append_link("s", robot.base, robot.basemesh, [0, 0], 0) # else: assume no base joint # Create the joints i = 0 for link in self.robot.links: # Get info if link.isprismatic(): j_type = 'p' elif link.isrevolute(): j_type = 'r' else: j_type = 's' pose = all_poses[i] # Pose if link.mesh is None: if i == 0: x1, x2 = SE3().t[0], all_poses[i].t[0] y1, y2 = SE3().t[1], all_poses[i].t[1] z1, z2 = SE3().t[2], all_poses[i].t[2] length = sqrt( (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1)) # Length else: x1, x2 = all_poses[i - 1].t[0], all_poses[i].t[0] y1, y2 = all_poses[i - 1].t[1], all_poses[i].t[1] z1, z2 = all_poses[i - 1].t[2], all_poses[i].t[2] length = sqrt( (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1)) # Length else: length = link.mesh angle_lims = link.qlim # Angle limits theta = link.theta # Current angle i += 1 self.append_link(j_type, pose, length, angle_lims, theta) # Add the robot to the canvas UI graphics_canvas.add_robot(self)
def _coulomb(n1, n2, k, r): """Calculates Coulomb forces and updates node data.""" # Get relevant positional data delta = [x2 - x1 for x1, x2 in zip(n1['velocity'], n2['velocity'])] distance = sqrt(sum([d * d for d in delta])) # If the deltas are too small, use random values to keep things moving if distance < 0.1: delta = [uniform(0.1, 0.2) for i in range(3)] distance = sqrt(sum([d**2 for d in delta])) # If the distance isn't huge (ie. Coulomb is negligible), calculate if distance < r: force = (k / distance)**2 n1['force'] = [f - force * d for f, d in zip(n1['force'], delta)] n2['force'] = [f + force * d for f, d in zip(n2['force'], delta)]
def _hooke(n1, n2, k, r): #k and r are undefined!!!! """Calculates Hooke spring forces and updates node data.""" # Get relevant positional data delta = [x2 - x1 for x1, x2 in zip(n1['velocity'], n2['velocity'])] distance = sqrt(sum([d**2 for d in delta])) # If the deltas are too small, use random values to keep things moving if distance < 0.1: delta = [uniform(0.1, 0.2) for i in range(3)] distance = sqrt(sum([d**2 for d in delta])) # Truncate distance so as to not have crazy springiness distance = min(distance, r) # Calculate Hooke force and update nodes force = (distance**2 - k**2) / (distance * k) n1['force'] = [f + force * d for f, d in zip(n1['force'], delta)] n2['force'] = [f - force * d for f, d in zip(n2['force'], delta)]
def create_binary_system(bounds: tuple) -> list: """Creates a binary system and returns the two stars in a list.""" x_bound, y_bound, z_bound = bounds star_A = create_star(pos=(1 * AU, 0, 0), mass=4 * 1.99E30, vel=(0, 0, 0), radius=4E10) star_B = create_star(pos=(-4 * AU, 0, 0), mass=1.99E30, vel=(0, 0, 0), radius=2E10, color=(1, 0, 0)) star_A.vel = vp.vec( 0, 0.1 * vp.sqrt((G * (star_A.mass + star_B.mass)) / (2 * AU)), 0) star_B.vel = -star_A.mass / star_B.mass * star_A.vel return [star_A, star_B]
def __init__(self, graphics_canvas, name, seriallink=None): self.joints = [] self.num_joints = 0 self.rob_shown = True self.ref_shown = True self.opacity = 1 self.name = name self.__scene = graphics_canvas self.angles = [] self.seriallink = seriallink # If seriallink given, create the robot if self.seriallink is not None: # Update name self.name = self.seriallink.name # Get initial poses zero_angles = [0] * len(self.seriallink.links) all_poses = self.seriallink.fkine(zero_angles, alltout=True) # Create the base if seriallink.basemesh is not None: self.append_link("s", all_poses[0], str(seriallink.basemesh), [0, 0], 0) # else: assume no base joint # Create the joints i = 0 for link in self.seriallink.links: # Get info j_type = link.jointtype # Type of pose = all_poses[i + 1] # Pose if link.mesh is None: x1, x2 = all_poses[i].t[0], all_poses[i + 1].t[0] y1, y2 = all_poses[i].t[1], all_poses[i + 1].t[1] z1, z2 = all_poses[i].t[2], all_poses[i + 1].t[2] length = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1)) # Length else: length = str(link.mesh) angle_lims = link.qlim # Angle limits theta = link.theta # Current angle i += 1 self.append_link(j_type, pose, length, angle_lims, theta) # Add the robot to the canvas UI graphics_canvas.add_robot(self)
def reset(): global theta, thetadot, psi, psidot, phi, phidot theta = 0.3*vp.pi # initial polar angle of shaft (from vertical) thetadot = 0 # initial rate of change of polar angle psi = 0 # initial spin angle psidot = 30 # initial rate of change of spin angle (spin ang. velocity) phi = -vp.pi/2 # initial azimuthal angle phidot = 0 # initial rate of change of azimuthal angle if pureprecession: # Set to True if you want pure precession, without nutation a = (1-I3/I1)*vp.sin(theta)*vp.cos(theta) b = -(I3/I1)*psidot*vp.sin(theta) c = M*g*r*vp.sin(theta)/I1 phidot = (-b+vp.sqrt(b**2-4*a*c))/(2*a) gyro.axis = gyro.length * \ vp.vector(vp.sin(theta)*vp.sin(phi), vp.cos(theta), vp.sin(theta)*vp.cos(phi)) A = vp.norm(gyro.axis) gyro.pos = 0.5*Lshaft*A tip.pos = Lshaft*A tip.clear_trail()
def tetrahedron(radius=1, center=vpy.vec(0, 0, 0)): """ Create a regular tetrahedron which corners are on a sphere of given radius and with the given centerpoint. A regular tetrahedron can be generated using four non-adjacent corners of a cube. That's how this tetrahedron is created. The tetrahedron edges are parallel to the angle bisectors of the x, y and z axes. """ corners = [ vpy.vec(1, 1, 1), vpy.vec(0, 0, 1), vpy.vec(1, 0, 0), vpy.vec(0, 1, 0) ] corners = [ (corner - vpy.vec(.5, .5, .5)) * radius * 2 / vpy.sqrt(3) + center for corner in corners ] faces = [[0, 1, 2], [1, 0, 3], [0, 2, 3], [1, 3, 2]] return corners, faces
def set_force(self, force, scale=1e-1, f_min = 0.1, f_max = 10.): """ :param force: 3*2 states force :param scale: scaling in velocity :param f_min: minimal magnitude of force :param f_max: maximal magnitude of force """ global game_objects orig = [force[:,0],force[:,1],force[:,2]] ff = [force[:,3]*scale,force[:,4]*scale,force[:,5]*scale] for ii in range(len(ff[0])): magn = vis.sqrt(ff[0][ii]*ff[0][ii]+ff[1][ii]*ff[1][ii]+ff[2][ii]*ff[2][ii])+1e-3 if magn > f_max: ff[0][ii] = ff[0][ii] * f_max/magn ff[1][ii] = ff[1][ii] * f_max/magn ff[2][ii] = ff[2][ii] * f_max/magn if magn < f_min: ff[0][ii] = ff[0][ii] * f_min/magn ff[1][ii] = ff[1][ii] * f_min/magn ff[2][ii] = ff[2][ii] * f_min/magn v = Vector_dyn(orig, ff, 'F', self.p, pos=vis.vector(0,0,0), axis=vis.vector(5,0,0), shaftwidth=0.5, color=vis.color.red) game_objects.append( v )
def circle_point_upper(x, r): return sqrt(2 * r * x - x**2) + r
def circle_point_lower(x, r): return r - sqrt(2 * r * x - x**2)
def distance(a: vp.sphere, b: vp.sphere) -> float: """Returns the distance between two VPython spheres.""" return vp.sqrt((a.pos.x - b.pos.x)**2 + (a.pos.y - b.pos.y)**2 + (a.pos.z - b.pos.z)**2)
from vpython import sphere, box, cylinder, cone, color, curve, rate from vpython import sqrt, atan, cos, sin, pi from vpython import vector as vec dirt = vec(1, 0.6, 0.4) ground = box(color=dirt) ground.axis = vec(1, 0, 1) ground.size = vec(0.305 * 120 / sqrt(2), 0.305 * 1, 0.305 * 120 / sqrt(2)) ground.pos = 0.305 * vec(0, -0.5, 0) mound = cone(color=dirt) mound.axis = 0.305 * vec(0, 10 / 12, 0) mound.radius = 0.305 * 9 pitcher = cylinder(color=color.red) pitcher.pos = 0.305 * vec(0, 10 / 12, 0) pitcher.axis = 0.305 * vec(0, 6, 0) plate = box(color=color.yellow) plate.size = vec(1, 0.1, 1) plate.pos = 0.305 * vec(60.5, 0, 0) strikezone = box(color=color.red) strikezone.size = vec(0.305 / 12, 0.305 * 2, 0.305 * 2) strikezone.pos = 0.305 * vec(60.5, 2.5, 0) def in_boundary(x, bound, pos): return x - bound / 2 < pos < x + bound / 2
if __name__ == '__main__': osc0 = Coupled_Oscillator(k=1, m=1, radius=0.15, length=1, origin=vp.vector(0, 0, 0)) osc1 = Coupled_Oscillator(k=1, m=1, radius=0.15, length=1, origin=vp.vector(osc0.body.pos)) osc1.set_initial_conditions(osc1.body.pos, vp.vector(0.5, 0, 0)) dt = 0.01 * 2 * vp.pi * vp.sqrt(osc0.m / osc0.k) while True: vp.rate(100) osc0.calculate_acceleration(osc1) osc1.calculate_acceleration() osc0.set_velocity(dt) osc1.set_velocity(dt) osc0.set_position(dt) osc1.update_origin(osc0.body.pos) osc1.set_position(dt)
import vpython as vp N = 4 # N by N by N array of atoms # Surrounding the N**3 atoms is another layer of invisible fixed-position atoms # that provide stability to the lattice. k = 1 m = 1 spacing = 1 atom_radius = 0.3*spacing L0 = spacing-1.8*atom_radius V0 = vp.pi*(0.5*atom_radius)**2*L0 # initial volume of spring vp.scene.center = 0.5*(N-1)*vp.vector(1, 1, 1) dt = 0.04*(2*vp.pi*vp.sqrt(m/k)) axes = [vp.vector(1, 0, 0), vp.vector(0, 1, 0), vp.vector(0, 0, 1)] vp.scene.caption = """A model of a solid represented as atoms connected by interatomic bonds. To rotate "camera", drag with right button or Ctrl-drag. To zoom, drag with middle button or Alt/Option depressed, or use scroll wheel. On a two-button mouse, middle is left + right. To pan left/right and up/down, Shift-drag. Touch screen: pinch/extend to zoom, swipe or two-finger rotate.""" class crystal: def __init__(self, N, atom_radius, spacing, momentumRange): self.atoms = [] self.springs = [] # Create (N+2)^3 atoms in a grid; the outermost atoms are fixed and invisible for z in range(-1, N+1, 1):
def __init__(self, graphics_canvas, name, robot=None): self.joints = [] self.num_joints = 0 self.rob_shown = True self.ref_shown = True self.opacity = 1 self.name = name self.__scene = graphics_canvas self.angles = [] self.robot = robot # If Robot given, create the robot if self.robot is not None: # Update name self.name = self.robot.name # Get initial poses zero_angles = np.zeros((self.robot.n,)) all_poses = self.robot.fkine_all(zero_angles, old=False) # Create the base try: if robot.basemesh is not None: self.append_link("s", all_poses[0], robot.basemesh, [0, 0], 0) except: pass # else: assume no base joint robot_colours = robot.linkcolormap() # Create the joints for i, link in enumerate(self.robot.links): # Get info if link.isprismatic: j_type = 'p' elif link.isrevolute: j_type = 'r' else: j_type = 's' pose = all_poses[i+1] # link frame pose if link.mesh is None: if i == 0: x1, x2 = SE3().t[0], all_poses[i].t[0] y1, y2 = SE3().t[1], all_poses[i].t[1] z1, z2 = SE3().t[2], all_poses[i].t[2] length = sqrt( (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1)) # Length else: x1, x2 = all_poses[i - 1].t[0], all_poses[i].t[0] y1, y2 = all_poses[i - 1].t[1], all_poses[i].t[1] z1, z2 = all_poses[i - 1].t[2], all_poses[i].t[2] length = sqrt( (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1)) # Length else: length = link.mesh angle_lims = link.qlim # Angle limits theta = link.theta # Current angle self.append_link(j_type, pose, length, angle_lims, theta) # Apply colours for i, joint in enumerate(self.joints): link_colour = list(robot_colours(i))[:3] joint.set_texture(colour=link_colour) # Add the robot to the canvas UI graphics_canvas.add_robot(self)
def __handle_keyboard_inputs(self): """ Pans amount dependent on distance between camera and focus point. Closer = smaller pan amount A = move left (pan) D = move right (pan) W = move up (pan) S = move down (pan) <- = rotate left along camera axes (rotate) -> = rotate right along camera axes (rotate) ^ = rotate up along camera axes (rotate) V = rotate down along camera axes (rotate) Q = roll left (rotate) E = roll right (rotate) ctrl + LMB = rotate (Default Vpython) """ # If camera lock, just skip the function if self.__camera_lock: return # Constants pan_amount = 0.02 # units rot_amount = 1.0 # deg # Current settings cam_distance = self.scene.camera.axis.mag cam_pos = vector(self.scene.camera.pos) cam_focus = vector(self.scene.center) # Weird manipulation to get correct vector directions. (scene.camera.up always defaults to world up) cam_axis = (vector(self.scene.camera.axis)) # X cam_side_axis = self.scene.camera.up.cross(cam_axis) # Y cam_up = cam_axis.cross(cam_side_axis) # Z cam_up.mag = cam_axis.mag # Get a list of keys keys = keysdown() # Userpan uses ctrl, so skip this check to avoid changing camera pose while shift is held if 'shift' in keys: return ################################################################################################################ # PANNING # Check if the keys are pressed, update vectors as required # Changing camera position updates the scene center to follow same changes if 'w' in keys: cam_pos = cam_pos + cam_up * pan_amount if 's' in keys: cam_pos = cam_pos - cam_up * pan_amount if 'a' in keys: cam_pos = cam_pos + cam_side_axis * pan_amount if 'd' in keys: cam_pos = cam_pos - cam_side_axis * pan_amount # Update camera position before rotation (to keep pan and rotate separate) self.scene.camera.pos = cam_pos ################################################################################################################ # Camera Roll # If only one rotation key is pressed if 'q' in keys and 'e' not in keys: # Rotate camera up cam_up = cam_up.rotate(angle=-radians(rot_amount), axis=cam_axis) # Set magnitude as it went to inf cam_up.mag = cam_axis.mag # Set self.scene.up = cam_up # If only one rotation key is pressed if 'e' in keys and 'q' not in keys: # Rotate camera up cam_up = cam_up.rotate(angle=radians(rot_amount), axis=cam_axis) # Set magnitude as it went to inf cam_up.mag = cam_axis.mag # Set self.scene.up = cam_up ################################################################################################################ # CAMERA ROTATION d = cam_distance move_dist = sqrt(d ** 2 + d ** 2 - 2 * d * d * cos(radians(rot_amount))) # SAS Cosine # If only left not right key if 'left' in keys and 'right' not in keys: # Calculate distance to translate cam_pos = cam_pos + norm(cam_side_axis) * move_dist # Calculate new camera axis cam_axis = -(cam_pos - cam_focus) if 'right' in keys and 'left' not in keys: cam_pos = cam_pos - norm(cam_side_axis) * move_dist cam_axis = -(cam_pos - cam_focus) if 'up' in keys and 'down' not in keys: cam_pos = cam_pos + norm(cam_up) * move_dist cam_axis = -(cam_pos - cam_focus) if 'down' in keys and 'up' not in keys: cam_pos = cam_pos - norm(cam_up) * move_dist cam_axis = -(cam_pos - cam_focus) # Update camera position and axis self.scene.camera.pos = cam_pos self.scene.camera.axis = cam_axis
Created on Thu Feb 11 13:58:34 2021 @author: Andrea Bassi """ import vpython as vp from simple_oscillator_with_class import Oscillator class Dumped_Oscillator(Oscillator): def __init__(self, k, m, beta, radius, length): super().__init__(k, m, radius, length) self.beta = beta def dump(self): self.acceleration += -self.beta * self.body.velocity / self.m osc = Dumped_Oscillator(k=1, m=1, beta=0.1, radius=0.15, length=1) osc.set_initial_conditions(vp.vector(1.5, 0, 0), vp.vector(0, 0, 0)) dt = 0.01 * 2 * vp.pi * vp.sqrt(osc.m / osc.k) while True: vp.rate(100) osc.calculate_acceleration() osc.dump() osc.set_velocity(dt) osc.set_position(dt)
def set_clip_poly(self, shape_str="cuboid", size=None, show_edges=True): """ define a polyhedron to set the shape of the puzzle. saves the polyhedron as self.clip_poly and displays it with low opacity inputs: ------- shape_str - (str) - the shape of the polyhedron current options: - 'cuboid' = 'c' (default) - 'cube' - 'octahedron' = 'oct' - 'tetrahedron' = 'tet' size - (float) or (vpy.vector) - if shape is a cuboid, this has to be a vpython vector, otherwise it needs to be a float raises: ------- - ValueError if the shape is not valid - TypeError if the shape is not given as a string """ if not isinstance(shape_str, str): raise TypeError(f"'shape_str' should be of type 'str' \ but was of type '{type(shape_str)}'") if hasattr(self, "clip_poly"): self.clip_poly.obj.visible = False # if isinstance(self.clip_poly, Polyhedron): # self.clip_poly.toggle_visible(False) # else: if shape_str in ("cuboid", "c"): if size == None: xsize = max([obj.pos.x for obj in self.vpy_objects]) \ + abs(min([obj.pos.x for obj in self.vpy_objects])) ysize = max([obj.pos.y for obj in self.vpy_objects]) \ + abs(min([obj.pos.y for obj in self.vpy_objects])) zsize = max([obj.pos.z for obj in self.vpy_objects]) \ + abs(min([obj.pos.z for obj in self.vpy_objects])) size = vpy.vec(xsize, ysize, zsize) elif isinstance(size, (float, int)): size = vpy.vec(size, size, size) corners, faces = shapes["cuboid"](size=size) elif shape_str in ("tetrahedron", "tet"): if size == None: size = 2 * max([obj.pos.mag for obj in self.vpy_objects]) corners, faces = shapes["tetrahedron"](radius=size) elif shape_str in ("cube"): if size == None: size = 2*max( [max([abs(obj.pos.x), abs(obj.pos.y), abs(obj.pos.z)]) \ for obj in self.vpy_objects]) corners, faces = shapes["cube"](sidelength=size) elif shape_str in ("octahedron", "oct"): if size == None: size = 2 * max([obj.pos.mag for obj in self.vpy_objects]) corners, faces = shapes["octahedron"](radius=size) elif shape_str in ("cylinder", "cyl"): if size == None: size = max([ vpy.sqrt(obj.pos.x**2 + obj.pos.y**2) for obj in self.vpy_objects ]) height = max([obj.pos.z for obj in self.vpy_objects]) \ + abs(min([obj.pos.z for obj in self.vpy_objects])) corners, faces = shapes["cylinder"](radius=size, height=height) else: raise ValueError( f"Invalid shape. Got {shape_str} but expected one of ['c', 'cuboid', 'tetrahedron', 'cube', 'oct', 'octahedron']." ) self.clip_poly = Polyhedron(corners, faces, opacity=.2, color=vpy.vec(0.4, 0, 0.6), show_edges=show_edges, show_corners=show_edges)
vp.vector(d, d, -d), vp.vector(-d, d, -d) ]) vert1 = vp.curve(color=gray, radius=r) vert2 = vp.curve(color=gray, radius=r) vert3 = vp.curve(color=gray, radius=r) vert4 = vp.curve(color=gray, radius=r) vert1.append([vp.vector(-d, -d, -d), vp.vector(-d, d, -d)]) vert2.append([vp.vector(-d, -d, d), vp.vector(-d, d, d)]) vert3.append([vp.vector(d, -d, d), vp.vector(d, d, d)]) vert4.append([vp.vector(d, -d, -d), vp.vector(d, d, -d)]) Atoms = [] p = [] apos = [] pavg = vp.sqrt(2 * mass * 1.5 * k * T) # average kinetic energy p**2/(2mass) = (3/2)kT for i in range(Natoms): x = L * vp.random() - L / 2 y = L * vp.random() - L / 2 z = L * vp.random() - L / 2 if i == 0: Atoms.append( vp.sphere(pos=vp.vector(x, y, z), radius=Ratom, color=vp.color.cyan, make_trail=True, retain=100, trail_radius=0.3 * Ratom)) else: Atoms.append(