def random_positions(plot_radius: bool = False): fig: plt.Figure ax: plt.Axes fig, ax = plt.subplots() plt.subplots_adjust(bottom=0.25) ax.axis('equal') axslider = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor='lightgoldenrodyellow') axbutton = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor='lightgoldenrodyellow') bnew = Button(axbutton, 'New') num_slider = Slider(axslider, 'Robots', 3, 7, valinit=3, valstep=1) # Initalize formation = regular_shape(int(num_slider.val)) positions = random_shape(len(formation)) target, radius = approximation(positions, formation) colors = get_colors(len(formation)) arr = np.arange(positions.shape[0]) srcs = ax.scatter(positions[:,0], positions[:,1], marker='o', color=colors) dsts = ax.scatter(target[:,0], target[:,1], marker='x', color=colors) def get_circles(positions: np.array, radius: float) -> List[plt.Circle]: return [plt.Circle(position, radius) for position in positions] circles = PatchCollection(get_circles(positions, radius), alpha=0.4) circles.set_color(colors) ax.add_collection(circles) def update(event): formation = regular_shape(int(num_slider.val)) positions = random_shape(len(formation)) target, radius = approximation(positions, formation) srcs.set_offsets(positions) dsts.set_offsets(target) circles.set_paths(get_circles(positions, radius)) colors = get_colors(positions.shape[0]) srcs.set_color(colors) dsts.set_color(colors) circles.set_color(colors) # Set Axis Scale points = np.concatenate([positions, target]) llim, hlim = points.min() - radius, points.max() + radius ax.set_xlim(llim, hlim) ax.set_ylim(llim, hlim) ax.autoscale_view() fig.canvas.draw_idle() bnew.on_clicked(update) num_slider.on_changed(update) ax.autoscale_view() plt.show()
def new_positions(val=None): nonlocal positions, formation positions = random_shape(number) formation = regular_shape(number) scatter_positions.set_offsets(positions) # Set Axis Scale points = np.concatenate([positions, formation]) llim, hlim = points.min() - 1, points.max() + 1 ax.set_xlim(llim, hlim) ax.set_ylim(llim, hlim) ax.autoscale_view() update()
def test_four_circles(): """Tests the conjecture that at most four must travel the solution""" pos = random_shape(4, 0.0, 1.0) shp = random_shape(4, 0.0, 1.0) shp = regular_shape(4) rep, radiuses = replication_spanner_circles(shp, pos[0], pos[1], 0.1) ax: plt.Axes fig, ax = plt.subplots() ax.set_aspect('equal', 'box') ax.scatter(*zip(*pos), color='black') ax.scatter(*zip(*rep), color='blue') patches = [plt.Circle(c, radius) for c, radius in zip(rep[2:], radiuses[2:])] ax.add_collection(PatchCollection(patches, alpha=0.4)) plt.show()
def update(event): formation = regular_shape(int(num_slider.val)) positions = random_shape(len(formation)) target, radius = approximation(positions, formation) srcs.set_offsets(positions) dsts.set_offsets(target) circles.set_paths(get_circles(positions, radius)) colors = get_colors(positions.shape[0]) srcs.set_color(colors) dsts.set_color(colors) circles.set_color(colors) # Set Axis Scale points = np.concatenate([positions, target]) llim, hlim = points.min() - radius, points.max() + radius ax.set_xlim(llim, hlim) ax.set_ylim(llim, hlim) ax.autoscale_view() fig.canvas.draw_idle()
def test_same_solution(positions: Optional[np.array] = None, formation: Optional[np.array] = None, speed: float = 0.002): if positions is None: positions = random_shape(3) print(positions) if formation is None: formation = regular_shape(3) fig: plt.Figure ax: plt.Axes fig, ax = plt.subplots() plt.subplots_adjust(bottom=0.25) ax.axis('equal') axslider = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor='lightgoldenrodyellow') axbutton = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor='lightgoldenrodyellow') bnew = Button(axbutton, 'New') speed_slider = Slider(axslider, 'Speed', 0, 0.05, valinit=speed) # Intial computation target, radius = triangle_solution(positions, formation) directions = (target - positions) / np.linalg.norm(target - positions, axis=1)[:, np.newaxis] * speed focuses = [] focus = get_intersect(positions[0], target[0], positions[1], target[1]) focuses.append(focus) # Create scatter plots pos_scatter = ax.scatter(positions[:, 0], positions[:, 1], c='red') tar_scatter = ax.scatter(target[:, 0], target[:, 1], c='blue') foc_scatter = ax.scatter([focus[0]], [focus[1]], c='green') def init(): ax.set_xlim(-2, 2) ax.set_ylim(-2, 2) return pos_scatter, tar_scatter, foc_scatter def new_positions(event): nonlocal positions, focuses, target positions = random_shape(3) target, radius = triangle_solution(positions, formation) focus = get_intersect(positions[0], target[0], positions[1], target[1]) focuses = [focus] bnew.on_clicked(new_positions) def new_speed(event): nonlocal speed, directions speed = speed_slider.val directions = np.linalg.norm(directions, axis=0) * speed speed_slider.on_changed(new_speed) def update(frame): # Gets called for every frame in animation nonlocal target, positions, directions, speed _target, _ = triangle_solution(positions, formation) # switch direction only when a new target is found if not np.allclose(_target, target): target = _target directions = (target - positions) / np.linalg.norm(target - positions, axis=1)[:, np.newaxis] * speed focus = get_intersect(positions[0], target[0], positions[1], target[1]) # foc_scatter.set_offsets([focus]) focuses.append(focus) foc_scatter.set_offsets(focuses) positions += directions pos_scatter.set_offsets(positions) tar_scatter.set_offsets(target) return pos_scatter, tar_scatter, foc_scatter ani = FuncAnimation(fig, update, frames=None, init_func=init, blit=True, repeat=False, interval=1, cache_frame_data=False) plt.show()
def test_replications( formation: Optional[np.array] = None, radius_range: Tuple[float, float] = (0.0, 0.5)) -> None: fig, ax = plt.subplots() plt.subplots_adjust(bottom=0.3) ax.axis('equal') number = 3 positions = random_shape(number) if not formation: formation = regular_shape(number) init_radius = radius_range[1] ax_radius = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor='lightgoldenrodyellow') ax_button = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor='lightgoldenrodyellow') ax_number = plt.axes([0.25, 0.2, 0.65, 0.03], facecolor='lightgoldenrodyellow') num_slider = Slider(ax_number, 'Robots', 3, 7, valinit=3, valstep=1) s_radius = Slider(ax_radius, 'Radius', *radius_range, valinit=init_radius) b_random = Button(ax_button, 'New') scatter_positions = ax.scatter(x=positions[:, 0], y=positions[:, 1], color='black') def get_shapes(radius): c_positions = list(combinations(range(len(positions)), 2)) c_formations = list(combinations(range(len(formation)), 2)) combs = list(product(c_positions, c_formations)) patches = [] colors = get_colors(len(combs)) for color, ((i_pos1, i_pos2), (i_for1, i_for2) )in zip(colors, combs): repl, radiuses = replication_spanner_circles( formation, positions[i_pos1], positions[i_pos2], radius, *sorted([i_for1, i_for2]) ) patches.append(plt.Polygon(repl, color=color, fill=False)) for i, _radius in enumerate(radiuses): # if i in (i_pos1, i_pos2): # continue patches.append(plt.Circle(repl[i], _radius, color=color, fill=False)) for position in positions: patches.append(plt.Circle(position, radius, color='black', fill=False)) return patches collection = PatchCollection(get_shapes(init_radius), match_original=True) ax.add_collection(collection) def update(val=None): collection.set_paths(get_shapes(s_radius.val)) # collection.set_edgecolor(get_colors(len(positions) * (len(positions) - 1))) # collection.set_array(np.array(list(range(len(positions))))) fig.canvas.draw_idle() def new_positions(val=None): nonlocal positions, formation positions = random_shape(number) formation = regular_shape(number) scatter_positions.set_offsets(positions) # Set Axis Scale points = np.concatenate([positions, formation]) llim, hlim = points.min() - 1, points.max() + 1 ax.set_xlim(llim, hlim) ax.set_ylim(llim, hlim) ax.autoscale_view() update() def update_number(val=None): nonlocal number number = int(num_slider.val) new_positions() s_radius.on_changed(update) b_random.on_clicked(new_positions) num_slider.on_changed(update_number) ax.autoscale_view() plt.show()