def compute_velocity(self, screen_distance_unit, velocity_adjustment): repulsive_force: Velocity = Velocity((0, 0)) for node in (World.agents - {self}): repulsive_force += self.force_as_dxdy(self.center_pixel, node.center_pixel, screen_distance_unit, repulsive=True) # Also consider repulsive force from walls. repulsive_wall_force: Velocity = Velocity((0, 0)) horizontal_walls = [ Pixel_xy((0, 0)), Pixel_xy((SCREEN_PIXEL_WIDTH(), 0)) ] x_pixel = Pixel_xy((self.center_pixel.x, 0)) for h_wall_pixel in horizontal_walls: repulsive_wall_force += self.force_as_dxdy(x_pixel, h_wall_pixel, screen_distance_unit, repulsive=True) vertical_walls = [ Pixel_xy((0, 0)), Pixel_xy((0, SCREEN_PIXEL_HEIGHT())) ] y_pixel = Pixel_xy((0, self.center_pixel.y)) for v_wall_pixel in vertical_walls: repulsive_wall_force += self.force_as_dxdy(y_pixel, v_wall_pixel, screen_distance_unit, repulsive=True) attractive_force: Velocity = Velocity((0, 0)) for node in (World.agents - {self}): if link_exists(self, node): attractive_force += self.force_as_dxdy(self.center_pixel, node.center_pixel, screen_distance_unit, repulsive=False) # noinspection PyTypeChecker net_force: Velocity = repulsive_force + repulsive_wall_force + attractive_force normalized_force: Velocity = net_force / max( [net_force.x, net_force.y, velocity_adjustment]) normalized_force *= 10 if gui_get(PRINT_FORCE_VALUES): print(f'{self}. \n' f'rep-force {tuple(repulsive_force.round(2))}; \n' f'rep-wall-force {tuple(repulsive_wall_force.round(2))}; \n' f'att-force {tuple(attractive_force.round(2))}; \n' f'net-force {tuple(net_force.round(2))}; \n' f'normalized_force {tuple(normalized_force.round(2))}; \n\n') return normalized_force
def setup(self): nbr_agents = SimEngine.get_gui_value('nbr_agents') for _ in range(nbr_agents): # When created, a agent adds itself to self.agents and to its patch's list of Agents. # self.agent_class(scale=1) Agent(scale=1) initial_velocities = cycle([Velocity((-1, -1)), Velocity((-1, 1)), Velocity((0, 0)), Velocity((1, -1)), Velocity((1, 1))]) for (agent, vel) in zip(World.agents, initial_velocities): agent.set_velocity(vel)
def setup(self): nbr_agents = gui_get('nbr_agents') for _ in range(nbr_agents): self.agent_class(scale=1) vs = [ Velocity((-1, -1)), Velocity((-1, 1)), Velocity((0, 0)), Velocity((1, -1)), Velocity((1, 1)) ] for (agent, vel) in zip(World.agents, cycle(vs)): agent.set_velocity(vel)
def move_agent(self, delta: Velocity): Agent.some_agent_changed = True (capped_x, capped_y) = delta.cap_abs_value(1) # Note that x and y have been defined to be getters for center pixels (x, y). new_center_pixel = Pixel_xy((self.x + capped_x, self.y + capped_y)) self.move_to_xy(new_center_pixel)
def step(self): """ Update the world by moving the agents. """ for agent in World.agents: agent.move_by_velocity() if World.ticks > 125 and random() < 0.01: agent.set_velocity(Velocity((uniform(-2, 2), uniform(-2, 2))))
def bounce_off_screen_edge(self, dxdy): """ Bounce agent off the screen edges. dxdv is the current agent velocity. If the agent should bounce, change it as needed. """ # The center pixel of this agent. current_center_pixel = self.center_pixel # Where the agent will be it if moves by dxdy. next_center_pixel = current_center_pixel + dxdy # The patch's row_col or next_center_pixel. Is that off the screen? If so, the agent should bounce. next_row_col = next_center_pixel.pixel_to_row_col() if next_row_col.row < 0 or gui.PATCH_ROWS <= next_row_col.row: dxdy = Velocity((dxdy.dx, dxdy.dy * (-1))) if next_row_col.col < 0 or gui.PATCH_COLS <= next_row_col.col: dxdy = Velocity((dxdy.dx * (-1), dxdy.dy)) return dxdy
def adjust_nodes(self): """ If the actual length doesn't match the proper length, move Node_2 vertically (up or down) until it does match. Each step moves Node_2 by at most 1 pixel. """ actual_length = self.node_1.distance_to(self.node_2) discrepancy = self.proper_length() - actual_length if abs(discrepancy) > 0: self.node_2.move_node(Velocity((0, discrepancy)))
def setup(self): nbr_agents = int(SimEngine.gui_get('nbr_agents')) for i in range(nbr_agents): # Adds itself to self.agents and to its patch's list of Agents. agent = self.agent_class(color=Color('red')) agent.set_velocity(Velocity((uniform(-2, 2), uniform(-2, 2)))) for patch in self.patches: patch.update_collision_color(World.agents)
def setup(self): nbr_agents = SimEngine.gui_get('nbr_agents') for _ in range(nbr_agents): # When created, a agent adds itself to World.agents and to its patch's list of Agents. # To create an agent: # Agent(scale=1) # More generallly, though, you can use the agent_class the system knows about. self.agent_class(scale=1) initial_velocities = cycle([ Velocity((-1, -1)), Velocity((-1, 1)), Velocity((0, 0)), Velocity((1, -1)), Velocity((1, 1)) ]) for (agent, vel) in zip(World.agents, initial_velocities): agent.set_velocity(vel)
def step(self): """ Update the world by moving the agent and indicating the patches that intersect the agent """ for agent in World.agents: agent.move_by_velocity() if random() < 0.01: agent.set_velocity(Velocity((randint(-2, 2), randint(-2, 2)))) for patch in self.patches: patch.update_collision_color(World.agents)
def adjust_distances(self, velocity_adjustment): #get from gui what the base distance units dist_unit = SimEngine.gui_get(('dist_unit')) #define how many distance units exist per screen screen_distance_unit = sqrt(SCREEN_PIXEL_WIDTH()**2 + SCREEN_PIXEL_HEIGHT()**2) / dist_unit #define initial Veolocity as (0,0), forces act in the x and y directions repulsive_force: Velocity = Velocity((0, 0)) #for all other agents excluding this instance for agent in (World.agents - {self}): #add their respective influence of each other element towards this element, calculate using #this center pixel, elements center pixel and using defined units (optional repulsove flag) repulsive_force += self.force_as_dxdy(self.center_pixel, agent.center_pixel, screen_distance_unit, repulsive=True) # Also consider repulsive force from walls. repulsive_wall_force: Velocity = Velocity((0, 0)) horizontal_walls = [ Pixel_xy((0, 0)), Pixel_xy((SCREEN_PIXEL_WIDTH(), 0)) ] x_pixel = Pixel_xy((self.center_pixel.x, 0)) for h_wall_pixel in horizontal_walls: repulsive_wall_force += self.force_as_dxdy(x_pixel, h_wall_pixel, screen_distance_unit, repulsive=True) vertical_walls = [ Pixel_xy((0, 0)), Pixel_xy((0, SCREEN_PIXEL_HEIGHT())) ] y_pixel = Pixel_xy((0, self.center_pixel.y)) for v_wall_pixel in vertical_walls: repulsive_wall_force += self.force_as_dxdy(y_pixel, v_wall_pixel, screen_distance_unit, repulsive=True) #calculate the attractive force generated by all the nodes connected by a link attractive_force: Velocity = Velocity((0, 0)) for agent in (World.agents - {self}): if link_exists(self, agent): attractive_force += self.force_as_dxdy(self.center_pixel, agent.center_pixel, screen_distance_unit, repulsive=False) #find the final force, find out what velocity adjustment is net_force = repulsive_force + repulsive_wall_force + attractive_force normalized_force: Velocity = net_force / max( [net_force.x, net_force.y, velocity_adjustment]) normalized_force *= 10 #print force values if selected if SimEngine.gui_get('Print force values'): print(f'{self}. \n' f'rep-force {tuple(repulsive_force.round(2))}; \n' f'rep-wall-force {tuple(repulsive_wall_force.round(2))}; \n' f'att-force {tuple(attractive_force.round(2))}; \n' f'net-force {tuple(net_force.round(2))}; \n' f'normalized_force {tuple(normalized_force.round(2))}; \n\n') #set the velocity of this object self.set_velocity(normalized_force) #take a step self.forward()
def random_velocity(): limit = gui_get('Max_speed') return Velocity( (uniform(-limit / 100, limit / 100), uniform(-limit / 100, limit / 100)))
def setup_a(self): """ Set up for the drop weight animation. """ # Move out by a small amount so that the two lines can be seen. step = 5 if SimEngine.gui_get('Pause?') else 0 self.top_spring.move_by_dxdy((step, 0)) self.top_spring.set_target_by_dxdy((self.x_offset-step, 0)) self.weight_cord.set_target_by_dxdy((0, Braess_World.cord_slack)) center_bar_node = self.bottom_spring.node_2 # Construct the full bar. bar_y = center_bar_node.y left_bar_node = Braess_Node(Pixel_xy( (self.x, bar_y) ) ) right_bar_node = Braess_Node(Pixel_xy( (self.x, bar_y) ) ) # By convention, the position of node_1 determines node_2's position. # In this case, since we will be pulling the bar up by its ends, # make the ends the controlling nodes. self.bar_right = Braess_Bar(right_bar_node, center_bar_node) self.bar_left = Braess_Bar(left_bar_node, center_bar_node) # Attach the bottom spring to the left end of the bar. self.bottom_spring.node_2 = left_bar_node left_bar_node.move_by_dxdy(Velocity((-step, 0))) right_bar_node.move_by_dxdy(Velocity((step, 0))) left_bar_node.set_target_by_dxdy(Velocity((-self.x_offset+step, Braess_World.cord_slack))) right_bar_node.set_target_by_dxdy(Velocity((self.x_offset-step, Braess_World.cord_slack))) # Attach the top cord to the right end of the bar rather than the center. self.top_cord.node_2 = right_bar_node # The left cord is a new element in state 2. It is offset to the left. x_coord = self.x cord_length = self.bottom_spring.node_1.y - Braess_World.top self.left_cord = Braess_Link.vertical_linked_nodes(Braess_Cord, x_coord, Braess_World.top, length=cord_length) # The left cord is offset to the left. self.left_cord.move_by_dxdy((-step, 0)) self.left_cord.node_1.set_target_by_dxdy(Velocity((-self.x_offset + step, 0))) self.left_cord.node_2.set_target_by_dxdy(Velocity((-self.x_offset + step, Braess_World.cord_slack))) self.left_cord.color = Color('yellow2') self.top_cord.color = Color('yellow2') # Make the left_cord's bottom node the top node of the bottom spring. World.agents.remove(self.bottom_spring.node_1) self.bottom_spring.node_1 = self.left_cord.node_2 # Add the new cord and bars to the adjustable links. self.adjustable_links.extend([self.left_cord, self.bar_right, self.bar_left]) Agent.key_step_done = False # ## Done with the setup for the animation. ## # SimEngine.gui_set(Braess_World.CUT_CORD, enabled=False) SimEngine.gui_set(GO_ONCE, enabled=True) SimEngine.gui_set(GOSTOP, enabled=True) if SimEngine.gui_get('Slow?'): SimEngine.fps = 15 if not SimEngine.gui_get('Pause?'): gui.WINDOW['GoStop'].click() Braess_World.state = 'a'
def random_velocity(limit=0.75): return Velocity((uniform(-limit, limit), uniform(-limit, limit)))
def move_by_dxdy(self, dxdy: Tuple): self.node_1.move_by_dxdy(Velocity(dxdy)) self.node_2.move_by_dxdy(Velocity(dxdy))
def set_target_by_dxdy(self, dxdy: Tuple): for node in [self.node_1, self.node_2]: node.set_target_by_dxdy(Velocity(dxdy))
def adjust_distances(self, velocity_adjustment): dist_unit = 8 screen_distance_unit = sqrt(SCREEN_PIXEL_WIDTH()**2 + SCREEN_PIXEL_HEIGHT()**2) / dist_unit repulsive_force: Velocity = Velocity((0, 0)) for agent in (World.agents - {self}): repulsive_force += self.force_as_dxdy(self.center_pixel, agent.center_pixel, screen_distance_unit, repulsive=True) # Also consider repulsive force from walls. repulsive_wall_force: Velocity = Velocity((0, 0)) horizontal_walls = [ Pixel_xy((0, 0)), Pixel_xy((SCREEN_PIXEL_WIDTH(), 0)) ] x_pixel = Pixel_xy((self.center_pixel.x, 0)) for h_wall_pixel in horizontal_walls: repulsive_wall_force += self.force_as_dxdy(x_pixel, h_wall_pixel, screen_distance_unit, repulsive=True) vertical_walls = [ Pixel_xy((0, 0)), Pixel_xy((0, SCREEN_PIXEL_HEIGHT())) ] y_pixel = Pixel_xy((0, self.center_pixel.y)) for v_wall_pixel in vertical_walls: repulsive_wall_force += self.force_as_dxdy(y_pixel, v_wall_pixel, screen_distance_unit, repulsive=True) attractive_force: Velocity = Velocity((0, 0)) for agent in (World.agents - {self}): if link_exists(self, agent): attractive_force += self.force_as_dxdy(self.center_pixel, agent.center_pixel, screen_distance_unit, repulsive=False) net_force = repulsive_force + repulsive_wall_force + attractive_force normalized_force: Velocity = net_force / max( [net_force.x, net_force.y, velocity_adjustment]) normalized_force *= 10 if SimEngine.gui_get('Print force values'): print(f'{self}. \n' f'rep-force {tuple(repulsive_force.round(2))}; \n' f'rep-wall-force {tuple(repulsive_wall_force.round(2))}; \n' f'att-force {tuple(attractive_force.round(2))}; \n' f'net-force {tuple(net_force.round(2))}; \n' f'normalized_force {tuple(normalized_force.round(2))}; \n\n') self.set_velocity(normalized_force) self.forward()