def initialize(self): #particles index = 0 for i, button in enumerate(self.buttons): if button.selected: index = i if index == len(self.particle_options): mass = 0.1 Charge = 0 if float(self.txt_mass.text)>0: mass = float(self.txt_mass.text) if len(self.txt_charge.text)>0: charge = float(self.txt_charge.text) self.ball = physics.ball(mass, self.radius, self.ball.pos.x, self.ball.pos.y) self.ball.name = self.txt_name.text self.ball.charge = charge else: self.ball = self.particle_options[index] v = physics.vector3(self.v, 0) if len(self.txt_xsp.text)>0 and len(self.txt_ysp.text)>0: v = physics.vector3(float(self.txt_xsp.text), float(self.txt_ysp.text)) self.ball.vel = v #fields self.E = physics.vector3(float(self.txt_E_x.text),float(self.txt_E_y.text), float(self.txt_E_z.text)) self.B = physics.vector3(float(self.txt_B_x.text),float(self.txt_B_y.text), float(self.txt_B_z.text)) self.trail = [self.ball.pos] self.draw_all()
def draw_spring(canvas, start, end, width, line_width = 1, colour = "#222222"): ''' Draw a spring between two points, specified as vector objects using the physics module for anvil. canvas must be an anvil canvas in the parent Form. start, end must be vector3 objects, although the z-component is not used. width specifies the width of the zig-zags of the spring line_width and colour give the line style used for the spring colour must be a #rrggbb string in hexadecimal ''' section = (end - start)/6 # Length of a section of the spring, a more useful measure of it's length direction = (end - start).norm() # Direction of the spring sideways = 0.5 * width * direction.phi_rotate(math.pi/2, vector3(0,0)) # Vector giving sideways offset to corners pencil = vector3(start.x, start.y) # Vector to keep track of drawing position canvas.stroke_style = colour canvas.line_width = line_width canvas.begin_path() canvas.move_to(pencil.x, pencil.y) pencil += section canvas.line_to(pencil.x, pencil.y) # Draw the first flat section pencil += 0.5 * section + sideways canvas.line_to(pencil.x, pencil.y) # Draw the first half diagonal pencil += section - 2 * sideways canvas.line_to(pencil.x, pencil.y) # Draw the next diagonal pencil += section + 2 * sideways canvas.line_to(pencil.x, pencil.y) # Draw the next diagonal pencil += section - 2 * sideways canvas.line_to(pencil.x, pencil.y) # Draw the next diagonal pencil += 0.5 * section + sideways canvas.line_to(pencil.x, pencil.y) # Draw the last half diagonal pencil += section canvas.line_to(pencil.x, pencil.y) # Draw the last flat section canvas.stroke()
def __init__(self, canvas, value=0, pos=[0,0], vert=1, label_args=["","none","",True], arrow_args=["","none","","",False]): # Inheriting generic component initialisation procedure component.__init__(self, canvas, value, pos, vert, label_args, arrow_args) [x, y] = [20*self.pos[0], 20*self.pos[1]] self.dic_a2 = {"aboveright":[vector3(60,0,0,"source voltage"), x-10, y-17], "aboveleft":[vector3(-60,0,0,"source voltage"), x+50, y-17], "belowright":[vector3(60,0,0,"source voltage"), x-10, y+15], "belowleft":[vector3(-60,0,0,"source voltage"), x+50, y+15], "leftup":[vector3(0,-60,0,"source voltage"), x-15, y+50], "leftdown":[ vector3(0,60,0,"source voltage"), x-15, y-10], "rightup":[vector3(0,-60,0,"source voltage"), x+15, y+50],"rightdown":[vector3(0,60,0,"source voltage"), x+15, y-10]}
def __init__(self, canvas, value=0, pos=[0,0], vert= 0, label_args=["","none","",True], arrow_args=["","none","","",False]): component.__init__(self, canvas, value, pos, vert, label_args, arrow_args) if value < 0: raise "Inductance must be positive." [x, y] = [20*self.pos[0], 20*self.pos[1]] self.dic_a2 = {"aboveright":[vector3(60,0,0,"inductance"), x, y-16], "aboveleft":[vector3(-60,0,0,"inductance"), x+60, y-16], "belowright":[vector3(60,0,0,"inductance"), x, y+16], "belowleft":[vector3(-60,0,0,"inductance"), x+60, y+16], "leftup":[vector3(0,-60,0,"inductance"), x-18, y+60], "leftdown":[ vector3(0,60,0,"inductance"), x-18, y], "rightup":[vector3(0,-60,0,"inductance"), x+18, y+60],"rightdown":[vector3(0,60,0,"inductance"), x+18, y]}
def __init__(self, canvas, value=0, pos=[0,0], vert=1, label_args=["","none","",True], arrow_args=["","none","","",False]): # Inheriting generic component initialisation procedure component.__init__(self, canvas, value, pos, vert, label_args, arrow_args) if self.value not in [0,1]: # 0 being open, 1 being closed raise "Switch's value property should be set to 0 (open) or 1 (closed)." [x, y] = [20*self.pos[0], 20*self.pos[1]] self.dic_a2 = {"aboveright":[vector3(60,0,0,"source voltage"), x-10, y-17], "aboveleft":[vector3(-60,0,0,"source voltage"), x+50, y-17], "belowright":[vector3(60,0,0,"source voltage"), x-10, y+15], "belowleft":[vector3(-60,0,0,"source voltage"), x+50, y+15], "leftup":[vector3(0,-60,0,"source voltage"), x-15, y+50], "leftdown":[ vector3(0,60,0,"source voltage"), x-15, y-10], "rightup":[vector3(0,-60,0,"source voltage"), x+15, y+50],"rightdown":[vector3(0,60,0,"source voltage"), x+15, y-10]}
def txt_change (self, **event_args): Ex = self.txt_E_x.text Ey = self.txt_E_y.text Ez = self.txt_E_z.text Bx = self.txt_B_x.text By = self.txt_B_y.text Bz = self.txt_B_z.text if len(Ex)>0 and len(Ey)>0 and len(Ez)>0: self.E = physics.vector3(float(self.txt_E_x.text),float(self.txt_E_y.text), float(self.txt_E_z.text)) if len(Bx)>0 and len(By)>0 and len(Ez)>0: self.B = physics.vector3(float(self.txt_B_x.text),float(self.txt_B_y.text), float(self.txt_B_z.text)) self.draw_all()
def __init__(self, canvas, value=0, pos=[0,0], vert= 0, label_args=["","none","",True], arrow_args=["","none","","",False]): # Inheriting generic component initialisation procedure component.__init__(self, canvas, value, pos, vert, label_args, arrow_args) if value < 0: # Resisor-specific code raise "Resistance must be positive." # Arrow positioning dictionary placed here to reduce workload in draw() [x, y] = [20*self.pos[0], 20*self.pos[1]] self.dic_a2 = {"aboveright":[vector3(60,0,0,"resistance"), x, y-16], "aboveleft":[vector3(-60,0,0,"resistance"), x+60, y-16], "belowright":[vector3(60,0,0,"resistance"), x, y+16], "belowleft":[vector3(-60,0,0,"resistance"), x+60, y+16], "leftup":[vector3(0,-60,0,"resistance"), x-18, y+60], "leftdown":[ vector3(0,60,0,"resistance"), x-18, y], "rightup":[vector3(0,-60,0,"resistance"), x+18, y+60],"rightdown":[vector3(0,60,0,"resistance"), x+18, y]}
def __init__(self, canvas, value=0, pos=[0,0], vert=1, label_args=["","none","",True], arrow_args=["","none","","",False]): # Inheriting generic component initialisation procedure component.__init__(self, canvas, value, pos, vert, label_args, arrow_args) if value < 0: raise "Capacitance can't be negative." [x, y] = [20*self.pos[0], 20*self.pos[1]] self.dic_a2 = {"aboveright":[vector3(60,0,0,"capacitance"), x-20, y-20], "aboveleft":[vector3(-60,0,0,"capacitance"), x+40, y-20], "belowright":[vector3(60,0,0,"capacitance"), x-20, y+18], "belowleft":[vector3(-60,0,0,"capacitance"), x+40, y+18], "leftup":[vector3(0,-60,0,"capacitance"), x-18, y+45], "leftdown":[ vector3(0,60,0,"capacitance"), x-18, y], "rightup":[vector3(0,-60,0,"capacitance"), x+18, y+45],"rightdown":[vector3(0,60,0,"capacitance"), x+18, y]}
def __init__(self): # This sets up a variable for every component on this form. # For example, if we've drawn a button called "send_button", we can # refer to it as self.send_button: self.init_components() # Any code you write here will run when the form opens. #Uncomment as required. self.running = False self.reset = True self.first = True self.dt = self.timer.interval self.mousedown = False self.mouse = physics.vector3(0, 0, 0) self.t = 0 self.paths = [] #SET SCALE (pixels per m, or unit used in code) self.xu = 1 self.L = 50 self.D = 0.1 self.v = 30 #APPEND ALL PARAMETER BOXES self.param_boxes = [] self.param_boxes.append(self.txt_ang) self.param_boxes.append(self.txt_spd)
def init_ball(self): xsp = 0 ysp = 0 ang = round(float(self.txt_ang.text), 2) * math.pi / 180 v = float(self.txt_spd.text) if v < 50: self.v = v if ang > 0: xsp = self.v * math.cos(ang) ysp = self.v * math.sin(ang) self.ball = physics.ball(1, 0.2) self.ball.pos = physics.vector3(self.ball.radius, self.ball.radius + self.floor_height) self.ball.vel = physics.vector3(xsp, ysp) self.path = 0
def __init__(self): # This sets up a variable for every component on this form. self.init_components() self.running = False self.first = True self.first_run = True self.reset = True self.mousedown = [False, False, False, False, False, False] self.mouse = physics.vector3(0, 0, 0) self.collided = False self.zoom = False # list of parameter inputs self.param_boxes = [] self.param_boxes.append(self.txt_mass_1) self.param_boxes.append(self.txt_mass_2) self.param_boxes.append(self.txt_xsp_1) self.param_boxes.append(self.txt_xsp_2) self.param_boxes.append(self.txt_ysp_1) self.param_boxes.append(self.txt_ysp_2) self.param_boxes.append(self.radio_elastic) self.param_boxes.append(self.radio_inelastic) self.param_boxes.append(self.txt_x_1) self.param_boxes.append(self.txt_x_2) self.param_boxes.append(self.txt_y_1) self.param_boxes.append(self.txt_y_2) self.param_boxes.append(self.btn_velreset) self.starts = [] self.collides = [] self.ends = []
def __init__(self): # This sets up a variable for every component on this form. self.init_components() self.running = False self.first = True self.first_run = True self.reset = True self.mousedown = [False, False, False, False, False, False] self.mouse = physics.vector3(0, 0, 0) self.collided = False self.zoom = False #list of parameter inputs self.param_boxes = [ self.txt_mass_1, self.txt_mass_2, self.txt_xsp_1, self.txt_xsp_2, self.txt_ysp_1 ] self.param_boxes += [ self.txt_ysp_2, self.radio_elastic, self.radio_inelastic, self.txt_x_1, self.txt_x_2, self.txt_y_1, self.txt_y_2, self.btn_velreset ] self.starts = [] self.collides = [] self.ends = []
def txt_change(self, **event_args): Ex = self.txt_E_x.text Ey = self.txt_E_y.text Ez = self.txt_E_z.text Bx = self.txt_B_x.text By = self.txt_B_y.text Bz = self.txt_B_z.text if len(Ex) > 0 and len(Ey) > 0 and len(Ez) > 0: self.E = physics.vector3(float(self.txt_E_x.text), float(self.txt_E_y.text), float(self.txt_E_z.text)) if len(Bx) > 0 and len(By) > 0 and len(Ez) > 0: self.B = physics.vector3(float(self.txt_B_x.text), float(self.txt_B_y.text), float(self.txt_B_z.text)) self.draw_all()
def btn_velreset_click (self, **event_args): if self.reset: self.reset = False for i in range(4): self.param_boxes[i+2].text = "0" self.balls[i].vel = physics.vector3(0,0) self.reset = True
def init_ball(self): xsp = 0 ysp = 0 ang = round(float(self.txt_ang.text),2)*math.pi/180 v =float(self.txt_spd.text) if v<50: self.v = v if ang>0: xsp = self.v*math.cos(ang) ysp = self.v*math.sin(ang) self.ball = physics.ball(1, 0.2) self.ball.pos = physics.vector3(self.ball.radius, self.ball.radius+self.floor_height) self.ball.vel = physics.vector3(xsp, ysp) self.path = 0
def btn_velreset_click(self, **event_args): if self.reset: self.reset = False for i in range(4): self.param_boxes[i + 2].text = "0" self.balls[i].vel = physics.vector3(0, 0) self.reset = True
def __init__(self): # This sets up a variable for every component on this form. # For example, if we've drawn a button called "send_button", we can # refer to it as self.send_button: self.init_components() self.points = [] self.pulses = [] self.initalize() self.mouse = physics.vector3(0,0) self.moved = 0 # Any code you write here will run when the form opens. #Uncomment as required. self.running= False self.reset = True self.dt = self.timer.interval self.first = True self.t = 0 #SET SCALE (pixels per m, or unit used in code) #APPEND ALL PARAMETER BOXES self.param_boxes= []
def move_bug(self, bug): aim = (bug.pos.phi_rotate(-self.a, physics.vector3(0, 0, 0)) - bug.pos).norm() bug.vel = aim * self.v bug.pos = bug.pos + bug.vel * self.dt self.t += self.dt self.lbl_t.text = "t = {0}s".format(repr(self.t))
def initial(self, canvas): draw.reset2(canvas, self.xu) draw.clear_canvas(canvas, "#fff") self.draw_polygon(canvas, self.N, self.L) self.bug.pos = physics.vector3(-self.L/2, self.d, 0) draw.reset2(canvas, self.xu) self.draw_bugs(canvas, self.bug.pos, "#2a2ac7") draw.reset2(canvas, self.xu)
def initial(self, canvas): draw.reset2(canvas, self.xu) draw.clear_canvas(canvas, "#fff") self.draw_polygon(canvas, self.N, self.L) self.bug.pos = physics.vector3(-self.L / 2, self.d, 0) draw.reset2(canvas, self.xu) self.draw_bugs(canvas, self.bug.pos, "#2a2ac7") draw.reset2(canvas, self.xu)
def initalize(self): self.spd = 0.1 self.wav = float(self.txt_wave.text) self.point1 = physics.point_source(radius = 0.01, speed= 0, wavelength = self.wav) self.point1.vel = physics.vector3(0.1,0) self.points = [self.point1] for point in self.points: point.mousedown = False
def draw_arrow(canvas, start, vect, width = 1, colour = "#222222"): '''Draw a simple arrow from start along vect, with a fixed size (10px) arrowhead.''' canvas.stroke_style = colour canvas.line_width = width end = start + vect direction = vect.norm() # Arrow direction canvas.begin_path() canvas.move_to(start.x, start.y) # Draw the main line canvas.line_to(end.x, end.y) flick = direction.phi_rotate(-5*math.pi/6, vector3(0, 0)) # Direction of one of the arrow tip lines flick *= 8 # Length of the arrow end lines canvas.line_to(end.x + flick.x, end.y + flick.y) # Draw one line of the arrow tip flick = direction.phi_rotate(5*math.pi/6, vector3(0, 0)) # Direction of the other arrow tip line flick *= 8 canvas.move_to(end.x, end.y) canvas.line_to(end.x + flick.x, end.y + flick.y) # Draw the other line of the arrow tip canvas.stroke()
def move_bug(self, bug): aim = (bug.pos.phi_rotate(-self.a, physics.vector3(0,0,0)) - bug.pos).norm() bug.vel = aim*self.v if self.counter % int(1/self.v) ==0: self.path.append(bug.pos) bug.pos = bug.pos + bug.vel*self.dt self.t += self.dt self.lbl_t.text = "t = {0}s".format(repr(self.t))
def __init__(self): # This sets up a variable for every component on this form. # For example, if we've drawn a button called "send_button", we can # refer to it as self.send_button: self.init_components() # Any code you write here will run when the form opens. #Uncomment as required. self.running= False self.reset = True self.dt = self.timer.interval/(1e7) self.first = True self.zoom = False self.t = 0 #SET SCALE (pixels per m, or unit used in code) self.xu =5 self.old = 1 self.paths = [] self.cur_path = [] self.trail= [] self.mousedown = False self.arrowdown = False self.mouse = physics.vector3(0,0) electron = physics.ball(self.me, self.radius) electron.charge = -self.e electron.name = "Electron" electron.E = physics.vector3(0, 1e3, 0) electron.B = physics.vector3(0, 0, 5e-3) positron = physics.ball(self.me, self.radius) positron.charge = self.e positron.name = "Positron" positron.E = physics.vector3(0, 1e3, 0) positron.B = physics.vector3(0, 0, 5e-3) alpha = physics.ball(4*self.mp, self.radius) alpha.charge = 2*self.e alpha.name = "Alpha Particle" alpha.E = physics.vector3(0, 1e5, 0) alpha.B = physics.vector3(0, 0, 5e-1) self.particle_options = [electron, positron, alpha] self.buttons = [] for index, particle in enumerate(self.particle_options): button = RadioButton(text= particle.name, value = index, group_name = "radio_particles") self.buttons.append(button) if index == 0: button.selected = True self.grid_particles.add_component(button, row = "A", col_xs = 2*index + 1, width_xs = 2) self.custom = RadioButton(text = "Custom", value = len(self.particle_options), group_name = "radio_particles") self.grid_particles.add_component(self.custom, row ="A", col_xs = 2*len(self.particle_options) + 1, width_xs =2) self.buttons.append(self.custom) self.param_boxes = self.buttons + self.grid_custom.get_components() + self.grid_fields.get_components() + self.grid_vel.get_components()
def component_arrows(self, canvas, vector, axis_vector = physics.vector3(0,1), x= 0, y=0, vector_from_start = "both", what_to_draw = "arrow", colour_parallel = "black",colour_perpendicular = "black"): """Draws components of vector parallel and perpendicular to axis_vector, in the x-y plane returns a list containing vector3 objects corresponding to the components parallel and perpendicular to axis_vector. Default it draws arrow components. Can modifiy to dashed lines by setting what_to_draw = "dashed" """ #Created by Michael C, April 2016 #canvas(canvas) - canvas to draw on #vector(vector3 object) - vector to split into components #axis_vector(vector3 object) - vector describing direction of axis components should be given parallel # or perpendicular to #x(float) - x position on canvas from which components should be drawn #y(float) - y position on canvas from which components should be drawn #vector_from_start(string) - which of the component vectors should be drawn from the given x,y - if not "both", other #will be drawn from end of this component #what_to_draw(string) - should these components be drawn as arrows or dashes #colour_parallel(string) #colour_perpendicular(string) - colours of these two lines/arrows if vector.z != 0 or axis_vector.z != 0: raise #canvas.translate(x, y) #component_parallel to axis_vector: parallel_vector = (vector.dot(axis_vector)/(axis_vector.mag()**2)) * axis_vector parallel_vector.vector_type = vector.vector_type perpendicular_vector = vector - parallel_vector if vector_from_start == "both": parallel_vector_start_x = 0 parallel_vector_start_y = 0 perpendicular_vector_start_x = 0 perpendicular_vector_start_y = 0 elif vector_from_start == "parallel": parallel_vector_start_x = 0 parallel_vector_start_y = 0 perpendicular_vector_start_x = parallel_vector.x perpendicular_vector_start_y = parallel_vector.y else: parallel_vector_start_x = perpendicular_vector.x parallel_vector_start_y = perpendicular_vector.y perpendicular_vector_start_x = 0 perpendicular_vector_start_y = 0 if what_to_draw == "arrow": new_arrow(canvas, parallel_vector, parallel_vector_start_x+x, parallel_vector_start_y+y) new_arrow(canvas, perpendicular_vector, perpendicular_vector_start_x+x, perpendicular_vector_start_y+y) elif what_to_draw == "dashed": dashed_line(canvas, 10, parallel_vector.x + parallel_vector_start_x +x, parallel_vector.y + parallel_vector_start_y+y, x=parallel_vector_start_x+x, y= parallel_vector_start_y+y, colour = colour_parallel) dashed_line(canvas, 10, perpendicular_vector.x + perpendicular_vector_start_x+x, perpendicular_vector.y + perpendicular_vector_start_y+y, x=perpendicular_vector_start_x+x, y= perpendicular_vector_start_y+y, colour = colour_perpendicular) return [parallel_vector, perpendicular_vector]
def initalize(self): self.spd = 0.1 self.wav = float(self.txt_wave.text) self.point1 = physics.point_source(radius=0.01, speed=0, wavelength=self.wav) self.point1.vel = physics.vector3(0.1, 0) self.points = [self.point1] for point in self.points: point.mousedown = False
def cart_arrows(self, canvas, vector, line_width, arrow_scale = 0.15, colours = {'x':"#666666",'y':"#666666",'z':"#666666"}, x= 0, y=0 ): """Draw cartesian components of vector (physics.vector3 type) in xyz in approriate colours. Default colour is isaac middle grey. Draws an axes in bottom left.""" #Modified by Michael Conterio, March 2016 #Draw axis reminder canvas.translate(50,50) canvas.rotate(math.pi/6 + math.pi) canvas.scale(10*line_width, 10*line_width) canvas.begin_path() #dashed axes self.dashed_line(canvas, 0.2, 1,0) canvas.line_width = 0.06 canvas.stroke() canvas.scale(0.1/line_width, 0.1/line_width) canvas.rotate(-math.pi/6- math.pi) canvas.scale(10*line_width, 10*line_width) canvas.begin_path() self.dashed_line(canvas, 0.2,1,0) canvas.line_width = 0.06 canvas.stroke() canvas.scale(0.1/line_width, 0.1/line_width) canvas.rotate(math.pi/2) canvas.scale(10*line_width, 10*line_width) canvas.begin_path() canvas.stroke_style = "#000000" self.dashed_line(canvas, 0.2,1,0) canvas.line_width = 0.06 canvas.stroke() canvas.scale(0.1/line_width, 0.1/line_width) canvas.rotate(-math.pi/2) canvas.translate(-50,-50) #z component canvas.translate(x, y) canvas.rotate(math.pi/6 + math.pi) #component arrow z_vector = physics.vector3(1,0,0,vector.vector_type) self.arrow(canvas, vector.z*vector3(1,0,0,vector.vector_type),0,0) canvas.rotate(-math.pi/6- math.pi) #x component self.arrow(canvas, vector.x*vector3(1,0,0,vector.vector_type),0,0) #y component canvas.rotate(math.pi/2) self.arrow(canvas, vector.y*vector3(1,0,0,vector.vector_type),0,0) canvas.rotate(-math.pi/2) canvas.translate(-x,-y)
def init_ball(self): xsp = 0 ysp = 0 self.v = 0 ang = round(float(self.txt_ang.text))*math.pi/180 v = float(self.txt_v.text) if 20>=v>0: self.v = v if ang>0: xsp = self.v*math.cos(ang) ysp = self.v*math.sin(ang) self.ball = physics.ball(1, 0.1) self.ball.pos = physics.vector3(self.ball.radius, self.ball.radius+self.floor_height) self.ball.vel = physics.vector3(xsp, ysp) self.d = self.v**2/self.g.mag() d =self.d if d>0: self.xu = self.cw/(d+3*self.ball.radius) self.path = 0
def set_fill_colour(self, colour = ""): """Sets fill colour of self.canvas to specified colour, or vector type colour as default. Can be called as simply set_fill_colour() for defaults. Colour as 6-digit hex string of form "#aabbcc". """ if colour != "": self.canvas.fill_style = colour else: # Must call new_arrow to access colour_dict # Creates dummy arrow, while preserving line width previous_line_width = self.canvas.line_width vector_type = self.dic_a2.values()[0][0].vector_type # Takes it from first dict entry new_arrow(self.canvas, vector3(1,0,0,vector_type), -1000, -1000) self.canvas.line_width = previous_line_width
def init_ball(self): xsp = 0 ysp = 0 self.v = 0 ang = round(float(self.txt_ang.text)) * math.pi / 180 v = float(self.txt_v.text) if 20 >= v > 0: self.v = v if ang > 0: xsp = self.v * math.cos(ang) ysp = self.v * math.sin(ang) self.ball = physics.ball(1, 0.1) self.ball.pos = physics.vector3(self.ball.radius, self.ball.radius + self.floor_height) self.ball.vel = physics.vector3(xsp, ysp) self.d = self.v**2 / self.g.mag() d = self.d if d > 0: self.xu = self.cw / (d + 3 * self.ball.radius) self.path = 0
def set_origin(self, origin = "default"): '''Sets the origin and the scaling factors for drawing the graph. The origin is a vector object which is used in drawing the graph to determine where the crossing point of the axes, (0, 0) is on the canvas. The scaling factors are floats giving the number of pixels per unit on the x, y axes. ''' if type(origin) is not vector3 and origin is not "default": # Need a vector raise TypeError("the origin must be set to a vector coordinate") elif origin == "default": # Check whether we are in default origin mode # Now set the scaling factors, as defined above, the 0.0s are to avoid integer division if self.x_range[0] >= 0: # If the axis is 0 -> x max self.scale_x = (self.cw - 2 * self.gap + 0.0) / self.x_range[1] elif self.x_range[1] <= 0: # If the axis is x min -> 0 self.scale_x = (self.cw - 2 * self.gap + 0.0) / abs(self.x_range[0]) else: # If the axis is x min -> x max self.scale_x = (self.cw - 2 * self.gap + 0.0) / (self.x_range[1] - self.x_range[0]) if self.y_range[0] >= 0: # If the axis is 0 -> y max self.scale_y = (self.ch - (2 * self.gap) + 0.0) / self.y_range[1] elif self.y_range[1] <= 0: # If the axis is y min -> 0 self.scale_y = (self.ch - (2 * self.gap) + 0.0) / abs(self.y_range[0]) else: # If the axis is y min -> y max self.scale_y = (self.ch - (2 * self.gap) + 0.0) / (self.y_range[1] - self.y_range[0]) # Note the self.gaps here are the gap between the axis ends and the canvas edge if self.x_range[0] >= 0 and self.y_range[0] >= 0: self.origin = vector3(self.gap, self.gap) # Bottom left corner if only top right quadrant needed elif self.x_range[0] >= 0 and self.y_range[1] <= 0: self.origin = vector3(self.gap, self.ch - self.gap) # Top left corner if only bottom right quadrant needed elif self.x_range[1] <= 0 and self.y_range[0] >= 0: self.origin = vector3(self.cw - self.gap, self.gap) # Bottom right corner if only top left quadrant needed elif self.x_range[1] <= 0 and self.y_range[1] <= 0: self.origin = vector3(self.cw - self.gap, self.ch - self.gap) # Top right corner if only bottom left quadrant needed elif self.x_range[0] >= 0: # If only the right half is needed self.origin = vector3(self.gap, -1 * self.y_range[0] * self.scale_y + self.gap) elif self.x_range[1] <= 0: # If only the left half is needed self.origin = vector3(self.cw - self.gap, -1 * self.y_range[0] * self.scale_y + self.gap) elif self.y_range[0] >= 0: # If only the top half is needed self.origin = vector3(-1 * self.x_range[0] * self.scale_x + self.gap, self.gap) elif self.y_range[1] <= 0: # If only the bottom half is needed self.origin = vector3(-1 * self.x_range[0] * self.scale_x + self.gap, self.cw - self.gap) else: # Otherwise all four quadrants are needed self.origin = vector3(-1 * self.x_range[0] * self.scale_x + self.gap, -1 * self.y_range[0] * self.scale_y + self.gap) else: self.origin = origin # If they have specified an origin
def canvas_mouse_move (self, x, y, **event_args): # This method is called when the mouse cursor moves over this component #record mouse pos self.mouse.x = x/self.xu self.mouse.y = (self.ch-y)/self.xu #change text box value based on where mouse is if self.mousedown: x = ((self.mouse - self.ball.pos).x) y = ((self.mouse - self.ball.pos).y) ang = math.atan(y/x) if 0<=ang<=math.pi/2: self.txt_ang.text = "{0}".format(int(ang*180/math.pi)) self.ball.vel = physics.vector3(self.v*math.cos(ang), self.v*math.sin(ang))
def draw_current(self, direction = None): # Calibrated for resistor display but can be called for any component object # Currently only supports left and down arrows olw = self.canvas.line_width if direction == None: # tries to decide for itself if self.vert == 0: direction = "left" else: direction = "down" if direction == "left": # Comes left out of resistor node 1 vect = vector3(-30, 0, 0, "acceleration") new_arrow(self.canvas, vect, 20*self.node1()[0], 20*self.node1()[1]) self.canvas.fill_style = "#4c7fbe" mt = self.canvas.measure_text(self.i) # Preventing overlap with label on resistor if self.label_args[3] and self.label_args[1] == "above": mt_r = self.canvas.measure_text(self.label_args[0]) elif self.arrow_args[4] and self.arrow_args[1] == "above": mt_r = self.canvas.measure_text(self.arrow_args[0]) else: mt_r = -1000 overlap = mt_r/2 + mt/2 - 43 overlap = overlap * (overlap > 0) self.canvas.fill_text(self.i, 20*self.node1()[0]-15-mt/2-overlap, 20*self.node1()[1]-20) elif direction == "down": vect = vector3(0, 30, 0, "acceleration") new_arrow(self.canvas, vect, 20*self.node2()[0], 20*self.node2()[1]) self.canvas.fill_style = "#4c7fbe" mt = self.canvas.measure_text(self.i) self.canvas.fill_text(self.i, 20*self.node2()[0]+10, 20*self.node2()[1]+19) self.canvas.line_width = olw
def initialize(self): #particles index = 0 for i, button in enumerate(self.buttons): if button.selected: index = i if index == len(self.particle_options): mass = 0.1 Charge = 0 if float(self.txt_mass.text) > 0: mass = float(self.txt_mass.text) if len(self.txt_charge.text) > 0: charge = float(self.txt_charge.text) self.ball = physics.ball(mass, self.radius, self.ball.pos.x, self.ball.pos.y) self.ball.name = self.txt_name.text self.ball.charge = charge else: self.ball = self.particle_options[index] v = physics.vector3(self.v, 0) if len(self.txt_xsp.text) > 0 and len(self.txt_ysp.text) > 0: v = physics.vector3(float(self.txt_xsp.text), float(self.txt_ysp.text)) self.ball.vel = v #fields self.E = physics.vector3(float(self.txt_E_x.text), float(self.txt_E_y.text), float(self.txt_E_z.text)) self.B = physics.vector3(float(self.txt_B_x.text), float(self.txt_B_y.text), float(self.txt_B_z.text)) self.trail = [self.ball.pos] self.draw_all()
def canvas_mouse_move(self, x, y, **event_args): # This method is called when the mouse cursor moves over this component #record mouse pos self.mouse.x = x / self.xu self.mouse.y = (self.ch - y) / self.xu #change text box value based on where mouse is if self.mousedown: x = ((self.mouse - self.ball.pos).x) y = ((self.mouse - self.ball.pos).y) ang = math.atan(y / x) if 0 <= ang <= math.pi / 2: self.txt_ang.text = "{0}".format(int(ang * 180 / math.pi)) self.ball.vel = physics.vector3(self.v * math.cos(ang), self.v * math.sin(ang))
def set_data(self, xvals, yvals, name = "graph_1"): '''Sets the internal data set of the graph from two lists of x values and y values. Will raise errors if the two are not both lists of the same length. ''' # Check for input errors try: if len(xvals) is not len(yvals): raise ValueError("The x and y datasets must be the same length") except TypeError: raise TypeError("The x and y datasets must be lists. If you only want one point, use [point]") # Change the given two lists into a single vector3 list data = list(range(0, len(xvals))) # Make data a list of equivalent length for i in list(range(0, len(xvals))): data[i] = vector3(xvals[i], yvals[i]) if name not in self.data: # If this is a new dataset self.datasets += 1 self.set_line_colour("new", name) # Set the plot parameters self.set_plot_type("line", name) self.set_line_weight(1, name) self.data[name] = sorted(data, key=lambda a: a.x)
def initial(self, canvas): draw.reset2(canvas, self.xu) draw.clear_canvas(canvas, "#fff") self.N = self.slid_N.value self.L = self.slid_L.value self.v = self.slid_v.value self.draw_polygon(canvas, self.N, self.L) if self.reset: self.bug.pos = physics.vector3(-self.L/2, self.d, 0) self.path = [self.bug.pos, self.bug.pos] draw.reset2(canvas, self.xu) self.draw_bugs(canvas, self.bug.pos, "#2a2ac7") # for i in range(len(self.path)-1): # canvas.begin_path() # canvas.move_to(self.path[i].x, self.path[i].y) # canvas.line_to(self.path[i+1].x, self.path[i+1].y) # canvas.stroke() draw.reset2(canvas, self.xu)
def move_bug(self, bug): aim = (bug.pos.phi_rotate(-self.a, physics.vector3(0,0,0)) - bug.pos).norm() bug.vel = aim*self.v bug.pos = bug.pos + bug.vel*self.dt self.t += self.dt self.lbl_t.text = "t = {0}s".format(repr(self.t))
def __init__(self): # This sets up a variable for every component on this form. # For example, if we've drawn a button called "send_button", we can # refer to it as self.send_button: self.init_components() # Any code you write here will run when the form opens. #Uncomment as required. self.running = False self.reset = True self.dt = self.timer.interval / (1e7) self.first = True self.zoom = False self.t = 0 #SET SCALE (pixels per m, or unit used in code) self.xu = 5 self.old = 1 self.paths = [] self.cur_path = [] self.trail = [] self.mousedown = False self.arrowdown = False self.mouse = physics.vector3(0, 0) electron = physics.ball(self.me, self.radius) electron.charge = -self.e electron.name = "Electron" electron.E = physics.vector3(0, 1e3, 0) electron.B = physics.vector3(0, 0, 5e-3) positron = physics.ball(self.me, self.radius) positron.charge = self.e positron.name = "Positron" positron.E = physics.vector3(0, 1e3, 0) positron.B = physics.vector3(0, 0, 5e-3) alpha = physics.ball(4 * self.mp, self.radius) alpha.charge = 2 * self.e alpha.name = "Alpha Particle" alpha.E = physics.vector3(0, 1e5, 0) alpha.B = physics.vector3(0, 0, 5e-1) self.particle_options = [electron, positron, alpha] self.buttons = [] for index, particle in enumerate(self.particle_options): button = RadioButton(text=particle.name, value=index, group_name="radio_particles") self.buttons.append(button) if index == 0: button.selected = True self.grid_particles.add_component(button, row="A", col_xs=2 * index + 1, width_xs=2) self.custom = RadioButton(text="Custom", value=len(self.particle_options), group_name="radio_particles") self.grid_particles.add_component( self.custom, row="A", col_xs=2 * len(self.particle_options) + 1, width_xs=2) self.buttons.append(self.custom) self.param_boxes = self.buttons + self.grid_custom.get_components( ) + self.grid_fields.get_components() + self.grid_vel.get_components()
def init_pos(self,points): self.points[0].pos = physics.vector3(0.05, self.ch/(2.0*self.xu))
def init_pos(self, points): self.points[0].pos = physics.vector3(0.05, self.ch / (2.0 * self.xu))
def cart_arrows(self, canvas, vector, line_width, arrow_scale=0.15, colours={ 'x': "#666666", 'y': "#666666", 'z': "#666666" }, x=0, y=0): """Draw cartesian components of vector (physics.vector3 type) in xyz in approriate colours. Default colour is isaac middle grey. Draws an axes in bottom left.""" #Modified by Michael Conterio, March 2016 #Draw axis reminder canvas.translate(50, 50) canvas.rotate(math.pi / 6 + math.pi) canvas.scale(10 * line_width, 10 * line_width) canvas.begin_path() #dashed axes self.dashed_line(canvas, 0.2, 1, 0) canvas.line_width = 0.06 canvas.stroke() canvas.scale(0.1 / line_width, 0.1 / line_width) canvas.rotate(-math.pi / 6 - math.pi) canvas.scale(10 * line_width, 10 * line_width) canvas.begin_path() self.dashed_line(canvas, 0.2, 1, 0) canvas.line_width = 0.06 canvas.stroke() canvas.scale(0.1 / line_width, 0.1 / line_width) canvas.rotate(math.pi / 2) canvas.scale(10 * line_width, 10 * line_width) canvas.begin_path() canvas.stroke_style = "#000000" self.dashed_line(canvas, 0.2, 1, 0) canvas.line_width = 0.06 canvas.stroke() canvas.scale(0.1 / line_width, 0.1 / line_width) canvas.rotate(-math.pi / 2) canvas.translate(-50, -50) #z component canvas.translate(x, y) canvas.rotate(math.pi / 6 + math.pi) #component arrow z_vector = physics.vector3(1, 0, 0, vector.vector_type) self.arrow(canvas, vector.z * vector3(1, 0, 0, vector.vector_type), 0, 0) canvas.rotate(-math.pi / 6 - math.pi) #x component self.arrow(canvas, vector.x * vector3(1, 0, 0, vector.vector_type), 0, 0) #y component canvas.rotate(math.pi / 2) self.arrow(canvas, vector.y * vector3(1, 0, 0, vector.vector_type), 0, 0) canvas.rotate(-math.pi / 2) canvas.translate(-x, -y)
class Form1(Form1Template): #acceleration vector g = physics.vector3(0, -9.81) floor_height = 0.2 arrow_scale = 0.1 line_width = 0.05 def txt_change(self, **event_args): self.init_ball() def canvas_mouse_move(self, x, y, **event_args): # This method is called when the mouse cursor moves over this component #record mouse pos self.mouse.x = x / self.xu self.mouse.y = (self.ch - y) / self.xu #change text box value based on where mouse is if self.mousedown: x = ((self.mouse - self.ball.pos).x) y = ((self.mouse - self.ball.pos).y) ang = math.atan(y / x) if 0 <= ang <= math.pi / 2: self.txt_ang.text = "{0}".format(int(ang * 180 / math.pi)) self.ball.vel = physics.vector3(self.v * math.cos(ang), self.v * math.sin(ang)) def canvas_mouse_up(self, x, y, button, **event_args): # This method is called when a mouse button is released on this component self.mousedown = False def canvas_mouse_down(self, x, y, button, **event_args): # This method is called when a mouse button is pressed on this component self.mouse.x = x / self.xu self.mouse.y = (self.ch - y) / self.xu #arrow detect if (0.9 * self.arrow_scale * self.ball.vel + self.ball.pos - self.mouse).mag() <= self.ball.radius * 3 and self.reset: self.mousedown = True def btn_path_click(self, **event_args): self.paths = [] def btn_run_click(self, **event_args): # This method is called when the button is clicked if not self.running: if self.reset: self.init_ball() self.running = True self.reset = False self.btn_run.text = "Pause" else: self.running = False self.btn_run.text = "Run" self.cur_path = [] self.paths.append(self.cur_path) #make parameters only editable while reset for box in self.param_boxes: box.enabled = self.reset def btn_reset_click(self, **event_args): #This method is called when the button is clicked self.running = False self.init_ball() #self.draw_floor() self.reset = True self.btn_run.enabled = True self.btn_run.text = "Run" self.t = 0 #make parameters only editable while reset for box in self.param_boxes: box.enabled = self.reset def timer_tick(self, **event_args): # This method is called Every [interval] seconds dt = self.dt canvas = self.canvas self.cw = canvas.get_width() self.ch = canvas.get_height() cw = self.cw ch = self.ch xu = self.xu if self.first: self.init_ball() self.xu = cw / (self.L + 2) canvas.height = "{0}".format(10 * self.xu * (self.v**2) / (2 * 9.81)) self.first = False if self.running: if self.ball.pos.y - self.ball.radius - self.floor_height <= 0.001 and self.t > 0: #to show exact solution, uncomment below # if abs(self.ball.pos.x - (self.L + self.ball.radius)) <= self.D: # self.t = 0 # self.running = False # self.btn_run.text = "Run" # self.btn_run.enabled = False self.ball.pos.y = self.ball.radius + self.floor_height #restitution self.ball.vel.y *= -0.7 #friction self.ball.vel.x *= 0.95 if self.running: self.ball.move(dt) if int(self.t / self.dt) % 3 == 0: self.cur_path.append(self.ball.pos) self.ball.vel = self.ball.vel + self.g * dt self.path += dt * self.ball.vel.mag() self.t += dt self.lbl_path.text = "Path = {0:.2f}m".format(self.path) self.draw_all() def draw_all(self): canvas = self.canvas cw = self.cw ch = self.ch xu = self.xu ball = self.ball draw.reset2(canvas, xu) draw.clear_canvas(canvas, "#7ec0ee") #floor canvas.fill_style = "#1f8107" canvas.fill_rect(0, 0, cw / self.xu, self.floor_height) #pole canvas.fill_style = "rgb(111, 62, 55)" canvas.fill_rect(self.L + self.ball.radius, self.floor_height, self.D, 3) canvas.translate(self.L + self.ball.radius - 0.05, 3 + self.floor_height) canvas.rotate(-math.pi / 2) draw.polygon(canvas, 3, self.D * 6) canvas.fill_style = "rgb(227, 81, 61)" canvas.fill() draw.reset2(canvas, xu) #ball draw.circle(canvas, ball.radius, ball.pos.x, ball.pos.y) canvas.fill_style = "#fff" canvas.fill() #arrow if not self.running: ball = self.ball #velocity vector canvas.translate(ball.pos.x, ball.pos.y) if ball.vel.y > 0: canvas.rotate(ball.vel.phi()) else: canvas.rotate(-ball.vel.phi()) draw.arrow(canvas, ball.vel.mag() * self.arrow_scale, 4 * self.line_width) canvas.fill_style = "#49902a" canvas.fill() draw.reset2(canvas, xu) #dashes canvas.begin_path() if not self.running: for path in self.paths: if len(path) > 2: for i in range(len(path) - 1): canvas.move_to(path[i].x, path[i].y) diff = path[i + 1] - path[i] new = path[i] + diff * 0.8 canvas.line_to(new.x, new.y) canvas.line_width = self.line_width canvas.stroke() def init_ball(self): xsp = 0 ysp = 0 ang = round(float(self.txt_ang.text), 2) * math.pi / 180 v = float(self.txt_spd.text) if v < 50: self.v = v if ang > 0: xsp = self.v * math.cos(ang) ysp = self.v * math.sin(ang) self.ball = physics.ball(1, 0.2) self.ball.pos = physics.vector3(self.ball.radius, self.ball.radius + self.floor_height) self.ball.vel = physics.vector3(xsp, ysp) self.path = 0 def __init__(self): # This sets up a variable for every component on this form. # For example, if we've drawn a button called "send_button", we can # refer to it as self.send_button: self.init_components() # Any code you write here will run when the form opens. #Uncomment as required. self.running = False self.reset = True self.first = True self.dt = self.timer.interval self.mousedown = False self.mouse = physics.vector3(0, 0, 0) self.t = 0 self.paths = [] #SET SCALE (pixels per m, or unit used in code) self.xu = 1 self.L = 50 self.D = 0.1 self.v = 30 #APPEND ALL PARAMETER BOXES self.param_boxes = [] self.param_boxes.append(self.txt_ang) self.param_boxes.append(self.txt_spd)
def component_arrows(self, canvas, vector, axis_vector=physics.vector3(0, 1), x=0, y=0, vector_from_start="both", what_to_draw="arrow", colour_parallel="black", colour_perpendicular="black"): """Draws components of vector parallel and perpendicular to axis_vector, in the x-y plane returns a list containing vector3 objects corresponding to the components parallel and perpendicular to axis_vector. Default it draws arrow components. Can modifiy to dashed lines by setting what_to_draw = "dashed" """ #Created by Michael C, April 2016 #canvas(canvas) - canvas to draw on #vector(vector3 object) - vector to split into components #axis_vector(vector3 object) - vector describing direction of axis components should be given parallel # or perpendicular to #x(float) - x position on canvas from which components should be drawn #y(float) - y position on canvas from which components should be drawn #vector_from_start(string) - which of the component vectors should be drawn from the given x,y - if not "both", other #will be drawn from end of this component #what_to_draw(string) - should these components be drawn as arrows or dashes #colour_parallel(string) #colour_perpendicular(string) - colours of these two lines/arrows if vector.z != 0 or axis_vector.z != 0: raise #canvas.translate(x, y) #component_parallel to axis_vector: parallel_vector = (vector.dot(axis_vector) / (axis_vector.mag()**2)) * axis_vector parallel_vector.vector_type = vector.vector_type perpendicular_vector = vector - parallel_vector if vector_from_start == "both": parallel_vector_start_x = 0 parallel_vector_start_y = 0 perpendicular_vector_start_x = 0 perpendicular_vector_start_y = 0 elif vector_from_start == "parallel": parallel_vector_start_x = 0 parallel_vector_start_y = 0 perpendicular_vector_start_x = parallel_vector.x perpendicular_vector_start_y = parallel_vector.y else: parallel_vector_start_x = perpendicular_vector.x parallel_vector_start_y = perpendicular_vector.y perpendicular_vector_start_x = 0 perpendicular_vector_start_y = 0 if what_to_draw == "arrow": new_arrow(canvas, parallel_vector, parallel_vector_start_x + x, parallel_vector_start_y + y) new_arrow(canvas, perpendicular_vector, perpendicular_vector_start_x + x, perpendicular_vector_start_y + y) elif what_to_draw == "dashed": dashed_line(canvas, 10, parallel_vector.x + parallel_vector_start_x + x, parallel_vector.y + parallel_vector_start_y + y, x=parallel_vector_start_x + x, y=parallel_vector_start_y + y, colour=colour_parallel) dashed_line(canvas, 10, perpendicular_vector.x + perpendicular_vector_start_x + x, perpendicular_vector.y + perpendicular_vector_start_y + y, x=perpendicular_vector_start_x + x, y=perpendicular_vector_start_y + y, colour=colour_perpendicular) return [parallel_vector, perpendicular_vector]
class Form1(Form1Template): #acceleration vector g = physics.vector3(0, -9.81) floor_height = 0.05 arrow_scale = 0.05 linewidth = 0.01 def txt_change(self, **event_args): self.init_ball() def canvas_mouse_move(self, x, y, **event_args): # This method is called when the mouse cursor moves over this component #record mouse pos self.mouse.x = x / self.xu self.mouse.y = (self.ch - y) / self.xu #change text box value based on where mouse is if self.mousedown: x = ((self.mouse - self.ball.pos).x) y = ((self.mouse - self.ball.pos).y) ang = math.atan(y / x) if 0 <= ang <= math.pi / 2: self.txt_ang.text = "{0}".format(int(ang * 180 / math.pi)) self.ball.vel = physics.vector3(self.v * math.cos(ang), self.v * math.sin(ang)) def canvas_mouse_up(self, x, y, button, **event_args): # This method is called when a mouse button is released on this component self.mousedown = False def canvas_mouse_down(self, x, y, button, **event_args): # This method is called when a mouse button is pressed on this component self.mouse.x = x / self.xu self.mouse.y = (self.ch - y) / self.xu #arrow detect if (0.9 * self.arrow_scale * self.ball.vel + self.ball.pos - self.mouse).mag() <= self.ball.radius / 3 and self.reset: self.mousedown = True def btn_path_click(self, **event_args): self.paths = [] def btn_run_click(self, **event_args): # This method is called when the button is clicked if not self.running: if self.reset: self.init_ball() self.running = True self.reset = False self.btn_run.text = "Pause" else: self.running = False self.btn_run.text = "Run" self.cur_path = [] self.paths.append(self.cur_path) #make parameters only editable while reset for box in self.param_boxes: box.enabled = self.reset def btn_reset_click(self, **event_args): #This method is called when the button is clicked self.running = False self.init_ball() #self.draw_floor() self.reset = True self.btn_run.enabled = True self.btn_run.text = "Run" self.t = 0 #make parameters only editable while reset for box in self.param_boxes: box.enabled = self.reset def timer_tick(self, **event_args): # This method is called Every [interval] seconds dt = self.dt canvas = self.canvas self.cw = canvas.get_width() self.ch = canvas.get_height() cw = self.cw ch = self.ch xu = self.xu if self.first: self.init_ball() d = self.v**2 / self.g.mag() if d > 0: self.xu = cw / (d + 4 * self.ball.radius) canvas.height = "{0}".format(round(self.xu * (d / 2))) self.first = False if self.running: if self.ball.pos.y - self.ball.radius - self.floor_height <= 0.001 and self.t > 0: self.ball.pos.y = self.ball.radius + self.floor_height self.t = 0 self.running = False self.btn_run.text = "Run" self.btn_run.enabled = False else: self.ball.move(dt) if int(self.t / self.dt) % 3 == 0: self.cur_path.append(self.ball.pos) self.ball.vel = self.ball.vel + self.g * dt self.path += dt * self.ball.vel.mag() self.t += dt self.lbl_path.text = "Path = {0:.2f}m".format(self.path) self.draw_all() def draw_all(self): canvas = self.canvas self.cw = canvas.get_width() self.ch = canvas.get_height() cw = self.cw ch = self.ch xu = self.xu ball = self.ball draw.reset2(canvas, xu) draw.clear_canvas(canvas, "#fff") canvas.fill_style = "#000" canvas.fill_rect(0, 0, cw, self.floor_height) draw.circle(canvas, ball.radius, ball.pos.x, ball.pos.y) canvas.fill_style = "#3683f3" canvas.fill() #arrow if not self.running: ball = self.ball #velocity vector canvas.translate(ball.pos.x, ball.pos.y) if ball.vel.y > 0: canvas.rotate(ball.vel.phi()) else: canvas.rotate(-ball.vel.phi()) draw.arrow(canvas, ball.vel.mag() * self.arrow_scale, 4 * self.linewidth) canvas.fill_style = "#49902a" canvas.fill() draw.reset2(canvas, xu) #dashes if not self.running: draw.paths(canvas, self.paths, self.linewidth, "#000") def init_ball(self): xsp = 0 ysp = 0 self.v = 0 ang = round(float(self.txt_ang.text)) * math.pi / 180 v = float(self.txt_v.text) if 20 >= v > 0: self.v = v if ang > 0: xsp = self.v * math.cos(ang) ysp = self.v * math.sin(ang) self.ball = physics.ball(1, 0.1) self.ball.pos = physics.vector3(self.ball.radius, self.ball.radius + self.floor_height) self.ball.vel = physics.vector3(xsp, ysp) self.d = self.v**2 / self.g.mag() d = self.d if d > 0: self.xu = self.cw / (d + 3 * self.ball.radius) self.path = 0 def __init__(self): # This sets up a variable for every component on this form. # For example, if we've drawn a button called "send_button", we can # refer to it as self.send_button: self.init_components() # Any code you write here will run when the form opens. #Uncomment as required. self.running = False self.reset = True self.first = True self.dt = self.timer.interval self.mousedown = False self.mouse = physics.vector3(0, 0, 0) self.t = 0 self.paths = [] #SET SCALE (pixels per m, or unit used in code) self.xu = 6 self.v = 0 #APPEND ALL PARAMETER BOXES self.param_boxes = [self.txt_v, self.txt_ang]