示例#1
0
 def force_as_dxdy(pixel_a: Pixel_xy, pixel_b: Pixel_xy,
                   screen_distance_unit, repulsive):
     """
     Compute the force between pixel_a pixel and pixel_b and return it as a velocity: direction * force.
     """
     direction: Velocity = normalize_dxdy((
         pixel_a - pixel_b) if repulsive else (pixel_b - pixel_a))
     d = max(1, pixel_a.distance_to(pixel_b))  #, wrap=False))
     if repulsive:
         dist = max(1,
                    pixel_a.distance_to(pixel_b) /
                    screen_distance_unit)  #, wrap=False)
         rep_coefficient = gui_get(REP_COEFF)
         rep_exponent = gui_get(REP_EXPONENT)
         force = direction * (
             (10**rep_coefficient) / 10) * dist**rep_exponent
         return force
     else:  # attraction
         dist = max(1, max(d, screen_distance_unit) / screen_distance_unit)
         att_exponent = gui_get(ATT_EXPONENT)
         force = direction * dist**att_exponent
         # If the link is too short, push away instead of attracting.
         if d < screen_distance_unit:
             force = force * (-1)
         att_coefficient = gui_get(ATT_COEFF)
         final_force = force * 10**(att_coefficient - 1)
         return final_force
示例#2
0
 def force_as_dxdy(pixel_a: Pixel_xy, pixel_b: Pixel_xy,
                   screen_distance_unit, repulsive):
     """
     Compute the force between pixel_a pixel and pixel_b and return it as a velocity: direction * force.
     """
     direction: Velocity = normalize_dxdy((
         pixel_a - pixel_b) if repulsive else (pixel_b - pixel_a))
     d = pixel_a.distance_to(pixel_b, wrap=False)
     if repulsive:
         dist = max(
             1,
             pixel_a.distance_to(pixel_b, wrap=False) /
             screen_distance_unit)
         rep_coefficient = SimEngine.gui_get('rep_coef')
         rep_exponent = SimEngine.gui_get('rep_exponent')
         force = direction * (10**rep_coefficient) / 10 * dist**rep_exponent
         return force
     else:  # attraction
         dist = max(1, max(d, screen_distance_unit) / screen_distance_unit)
         att_exponent = SimEngine.gui_get('att_exponent')
         force = direction * dist**att_exponent
         # If the link is too short, push away instead of attracting.
         if d < screen_distance_unit:
             force = force * (-1)
         att_coefficient = SimEngine.gui_get('att_coef')
         return 10**(att_coefficient - 1) * force
示例#3
0
 def vertical_linked_nodes(LinkType, x, y_top, length=None):
     node_1 = Braess_Node(Pixel_xy((x, y_top)))
     if length is None:
         length = Braess_World.dist_unit
         if LinkType == Braess_Cord:
             length /= 2
     node_2 = Braess_Node(Pixel_xy((x, y_top + length)))
     link_construct = LinkType(node_1, node_2)
     return link_construct
示例#4
0
 def draw_label(self):
     offset = Block.patch_text_offset if isinstance(self, Patch) else Block.agent_text_offset
     text_center = Pixel_xy((self.rect.x + offset, self.rect.y + offset))
     line_color = None if offset == 0 else \
                  Color('white') if isinstance(self, Patch) and self.color == Color('black') else self.color
     obj_center = self.rect.center
     gui.draw_label(self.label, text_center, obj_center, line_color)
示例#5
0
 def pixel_xy_to_patch(pixel_xy: Pixel_xy) -> Patch:
     """
     Get the patch RowCol for this pixel
    """
     row_col: RowCol = pixel_xy.pixel_to_row_col()
     patch = World.patches_array[row_col.row, row_col.col]
     return patch
示例#6
0
    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)
示例#7
0
 def extend_linked_nodes(self, LinkType):
     node_1 = self.node_2
     length = Braess_World.dist_unit
     if LinkType == Braess_Cord:
         length /= 2
     node_2 = Braess_Node(Pixel_xy((node_1.x, node_1.y + length)))
     link_construct = LinkType(node_1, node_2)
     return link_construct
示例#8
0
    def __init__(self, node_1: Braess_Node, node_2: Braess_Node, **kwargs):
        super().__init__(node_1, node_2, **kwargs)

        # This is the resting length. All springs have this as their default length.
        self.resting_length = Braess_World.dist_unit
        if not (isinstance(self, Braess_Bar) or isinstance(self, Braess_Cord)):
            self.node_2.move_to_xy(Pixel_xy((self.node_2.x, self.node_1.y + self.resting_length)))
        self.color = Color('green')
        self.width = 2
示例#9
0
 def create_random_agent(self, color=None, shape_name='netlogo_figure', scale=1.4):
     """
     Create an Agent placed randomly on the screen.
     Set it to face the screen's center pixel.
     """
     agent = self.agent_class(color=color, shape_name=shape_name, scale=scale)
     agent.move_to_xy(Pixel_xy.random_pixel())
     agent.face_xy(center_pixel())
     return agent
示例#10
0
 def __init__(self, center_pixel: Pixel_xy, color=Color('black')):
     super().__init__()
     self.center_pixel = center_pixel
     self.rect = Rect((0, 0), (gui.PATCH_SIZE, gui.PATCH_SIZE))
     # noinspection PyTypeChecker
     sum_pixel: Pixel_xy = center_pixel + Pixel_xy((1, 1))
     self.rect.center = sum_pixel
     self.image = Surface((self.rect.w, self.rect.h))
     self.color = self.base_color = color
     self.label = None
示例#11
0
    def __init__(self, node_1: Braess_Node, node_2: Braess_Node, **kwargs):
        # The link must be directed because we depend on the order of the nodes.
        # Typically node_1 is fixed and node_2 moves.
        super().__init__(node_1, node_2, directed=True, **kwargs)

        # This is the resting length. All springs have this as their default length.
        self.resting_length = Braess_World.dist_unit
        if not (isinstance(self, Braess_Bar) or isinstance(self, Braess_Cord)):
            self.node_2.move_to_xy(Pixel_xy((self.node_2.x, self.node_1.y + self.resting_length)))
        self.color = Color('green')
        self.width = 2
示例#12
0
 def mouse_click(self, xy: Tuple[int, int]):
     """ Toggle clicked patch's aliveness. """
     patch = self.pixel_tuple_to_patch(xy)
     if len(patch.agents) == 1:
         node = choice(list(patch.agents))
     else:
         patches = patch.neighbors_24()
         nodes = {node for patch in patches for node in patch.agents}
         node = nodes.pop() if nodes else Pixel_xy(xy).closest_block(
             World.agents)
     if node:
         node.highlighted = not node.highlighted
示例#13
0
 def mouse_click(self, xy: Tuple[int, int]):
     """ Select closest node. """
     patch = self.pixel_tuple_to_patch(xy)
     if len(patch.agents) == 1:
         node = sample(patch.agents, 1)[0]
     else:
         patches = patch.neighbors_24()
         nodes = {node for patch in patches for node in patch.agents}
         node = nodes.pop() if nodes else Pixel_xy(xy).closest_block(
             World.agents)
     if node:
         node.selected = not node.selected
示例#14
0
 def draw_label(self):
     text = gui.FONT.render(self.label, True, Color('black'),
                            Color('white'))
     offset = Block.patch_text_offset if isinstance(
         self, Patch) else Block.agent_text_offset
     text_center = Pixel_xy((self.rect.x + offset, self.rect.y + offset))
     # gui.SCREEN.blit(text, text_center)
     gui.blit(text, text_center)
     line_color = Color('white') if isinstance(
         self, Patch) and self.color == Color('black') else self.color
     # self.draw_line(line_color=line_color, start_pixel=self.rect.center, end_pixel=text_center)
     gui.draw_line(start_pixel=self.rect.center,
                   end_pixel=text_center,
                   line_color=line_color)
示例#15
0
 def create_random_agents(self,
                          n,
                          shape_name='netlogo_figure',
                          color=None,
                          scale=1.4):
     """
     Create n Agents placed randomly on the screen. They are all facing the screen's center pixel.
     """
     for _ in range(n):
         agent = self.agent_class(color=color,
                                  shape_name=shape_name,
                                  scale=scale)
         agent.move_to_xy(Pixel_xy.random_pixel())
         agent.face_xy(center_pixel())
示例#16
0
 def __init__(self, center_pixel: Pixel_xy, color=Color('black')):
     super().__init__()
     self.center_pixel = center_pixel
     self.rect = Rect((0, 0), (gui.PATCH_SIZE, gui.PATCH_SIZE))
     # noinspection PyTypeChecker
     sum_pixel: Pixel_xy = center_pixel + Pixel_xy((1, 1))
     assert isinstance(sum_pixel, Pixel_xy)
     self.rect.center = sum_pixel  # .as_tuple()
     self.image = Surface((self.rect.w, self.rect.h))
     self.color = self.base_color = color
     self.label = None
     self.font = Font(None, int(1.5 * gui.BLOCK_SPACING()))
     self.agent_text_offset = int(1.5 * gui.PATCH_SIZE)
     self.patch_text_offset = -int(1.0 * gui.PATCH_SIZE)
示例#17
0
    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
示例#18
0
    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()
示例#19
0
 def set_center_pixel(self, xy: Pixel_xy):
     self.center_pixel: Pixel_xy = xy.wrap()
     # Set the center point of this agent's rectangle.
     self.rect.center = (self.center_pixel - Agent.half_patch_pixel).round()
示例#20
0
    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()
示例#21
0
 def pixel_tuple_to_patch(self, xy: Tuple[int, int]):
     """
     Get the patch RowCol for this pixel
    """
     return self.pixel_xy_to_patch(Pixel_xy(xy))
示例#22
0
    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'
示例#23
0
 def __init__(self):
     center_pixel = Pixel_xy(
         (uniform(0, SCREEN_PIXEL_WIDTH()), uniform(0,
                                                    SCREEN_PIXEL_HEIGHT())))
     color = utils.color_random_variation(Color('yellow'))
     super().__init__(center_pixel=center_pixel, color=color, scale=1)
示例#24
0
 def adjust_nodes(self):
     """ Move node_2 up or down to match node_1. """
     if self.node_1.y != self.node_2.y:
         self.node_2.move_to_xy(Pixel_xy((self.node_2.x, self.node_1.y)))