def set_display_info(self) -> List[MapDisplay]: ret: List[MapDisplay] = super().set_display_info() if not self.SIMPLE_ANIMATIONS: if self.__is_local_anim and self.__local_kernel_anim: ret += self.__local_kernel_anim.instance.set_display_info() if not self.__is_local_anim and self.__global_kernel_anim: ret += self.__global_kernel_anim.instance.set_display_info() visited_colour = self._services.state.views.add_colour( "visited", Colour(0.19, 0.19, 0.2, 0.8)) waypoint_colour = self._services.state.views.add_colour( "waypoint", Colour(0, 1, 1)) ret.append( SolidIterableMapDisplay(self._services, self.display_info_data[0], visited_colour, z_index=70)) ret.append( SolidIterableMapDisplay(self._services, self.display_info_data[1], visited_colour, z_index=65)) ret.append( SolidIterableMapDisplay(self._services, self.way_points, waypoint_colour, z_index=200)) return ret
def __init__(self, services: Services, testing: BasicTesting = None): super().__init__(services, testing) self.mem = CGDS.InternalMemory(self._services) self.pq_colour_max = self._services.state.views.add_colour("explored max", BLUE) self.pq_colour_min = self._services.state.views.add_colour("explored min", Colour(0.27, 0.33, 0.35, 0.2)) self.visited_colour = self._services.state.views.add_colour("visited", Colour(0.19, 0.19, 0.2, 0.8)) self.__map_displays = [SolidIterableMapDisplay(self._services, self.mem.visited, self.visited_colour, z_index=50), GradientListMapDisplay(self._services, self.mem.dequeVisual, min_colour=self.pq_colour_min, max_colour=self.pq_colour_max, z_index=49, inverted=True) ]
def __init__(self, name: str, visibility_callback: Callable[[str, bool], None], colour_callback: Callable[[str, Colour], None], cv_clicked_callback: Callable[['ViewElement'], None], parent: DirectFrame, visible: bool = True, colour: Colour = Colour(0.2, 0.3, 0.4, 0.5), mouse1_press_callbacks: List[Callable[[], None]] = []): self.__name = name self.__visible = visible self.__visibility_callback = None self.__colour_callback = None self.__cv_clicked_callback = None self.__frame = DirectFrame(parent=parent, frameColor=WINDOW_BG_COLOUR) self.__cv = ColourView(self.__frame, colour) self.__cv.frame.set_scale((0.15, 1.0, 0.15)) self.__cv.frame.set_pos((-0.65, 1.0, 0.0)) self.__cv_btn = DirectButton(parent=self.__cv.frame, frameColor=TRANSPARENT, borderWidth=(0, 0), frameSize=self.__cv.view["frameSize"], scale=self.__cv.view["scale"], pos=self.__cv.view["pos"], command=self.__cv_clicked) self.__label = DirectLabel(parent=self.__frame, text=self.__name, text_fg=WHITE, text_bg=WINDOW_BG_COLOUR, frameColor=WINDOW_BG_COLOUR, text_align=TextNode.ALeft, borderWidth=(.0, .0), pos=(-0.3, 0.0, -0.03), scale=(0.1, 1.0, 0.1)) visibility_filename = os.path.join(GUI_DATA_PATH, "visible.png") self.__visibility_btn = DirectButton(parent=self.__frame, image=visibility_filename, frameColor=TRANSPARENT, pos=(-0.92, 0.0, 0.0), scale=(0.09, 1.0, 0.06), command=self.__toggle_visible) self.__visibility_bar = DirectFrame(parent=self.__frame, borderWidth=(.0, .0), frameColor=WINDOW_BG_COLOUR, frameSize=(-0.1, 0.1, -0.01, 0.01), pos=(-0.92, 0.0, 0.0), hpr=(40, 0, 40)) self.visible = self.__visible # trigger UI update self.__visibility_callback = visibility_callback self.__colour_callback = colour_callback self.__cv_clicked_callback = cv_clicked_callback
def __colour_picked_callback(self, colour: Colour): n = 3 r, g, b, _ = colour self.__r.update(r) self.__g.update(g) self.__b.update(b) self.__cv_picked.colour = Colour(r, g, b, self.__cv_picked.colour.a) self.__dirty_rem_no_hide = 3 # something fishy is going on self.__callback(self.__cv_picked.colour)
def blend_colours(src: Colour, dst: Colour): wda = dst.a * (1 - src.a) # weighted dst alpha cs = np.multiply(src.values, src.a) + np.multiply(dst.values, wda) a = src.a + wda if a != 0: cs = np.divide(cs, a) return Colour(*cs)
def __init__(self, base: ShowBase, parent: DirectFrame, callback: Callable[[Colour], None], mouse1_press_callbacks: List[Callable[[], None]], colour: Colour = Colour(0.25, 0.5, 0.75, 1.0)): self.__base = base self.__colour = colour self.__callback = callback self.__enabled = True self.__frame = DirectFrame(parent=parent) self.__colour_picker = ColourPicker(self.__base, self.__colour_picked_callback, parent=self.__frame, relief=DGG.SUNKEN, borderWidth=(.0, .0), image_scale=(1., 1., 1.), frameColor=WIDGET_BG_COLOUR, frameSize=(-1., 1., -1., 1.), scale=(1.0, 1.0, 0.75), pos=(0.0, 0.0, 0.15)) self.__cv_picked = ColourView(self.__frame, self.__colour) self.__cv_picked.frame.set_pos(-0.74, 0.0, -1.41) self.__cv_hovered = ColourView(self.__frame) self.__cv_hovered.frame.set_pos(-0.74, 0.0, -0.89) def update_cv_hovered(task): c = self.__colour_picker.colour_under_mouse() self.__cv_hovered.colour = c return task.cont self.__base.taskMgr.add(update_cv_hovered, 'update_cv_hovered') c = self.__colour f = self.__frame sc = self.__colour_channel_slider_edit_callback ec = self.__colour_channel_entry_edit_callback self.__r = ColourChannel(f, "R", c[0], sc, ec, mouse1_press_callbacks) self.__g = ColourChannel(f, "G", c[1], sc, ec, mouse1_press_callbacks) self.__b = ColourChannel(f, "B", c[2], sc, ec, mouse1_press_callbacks) self.__a = ColourChannel(f, "A", c[3], sc, ec, mouse1_press_callbacks) x = 0.14 y_base = -0.8 y_inc = -0.25 self.__r.frame.set_pos((x, 0.0, y_base)) self.__g.frame.set_pos((x, 0.0, y_base + y_inc)) self.__b.frame.set_pos((x, 0.0, y_base + y_inc * 2)) self.__a.frame.set_pos((x, 0.0, y_base + y_inc * 3)) self.__dirty_rem_no_hide = 0
def __init__(self, services: Services, ray_colour: Optional[DynamicColour] = None, bearing_colour: Optional[DynamicColour] = None, custom_map: Map = None): super().__init__(services, z_index=250, custom_map=custom_map) self.ray_colour = self._services.state.views.add_colour( "ray", RED) if ray_colour is None else ray_colour self.bearing_colour = self._services.state.views.add_colour( "bearing", Colour(1, 0, 1)) if bearing_colour is None else bearing_colour
def __colour_channel_entry_edit_callback(self, chn: ColourChannel, value: float): if chn != self.__a: if self.__dirty_rem_no_hide: self.__dirty_rem_no_hide -= 1 else: self.__colour_picker.marker.hide() chn.update_slider(value) self.__cv_picked.colour = Colour(self.__r.value, self.__g.value, self.__b.value, self.__a.value) self.__callback(self.__cv_picked.colour)
def __create_lines(self, c: Colour, wfc: Colour) -> Tuple[bytes, bytes, bytes]: def conv(f): return int(round(f * 255)) def to_pixel(c): return (conv(c.b), conv(c.g), conv(c.r), conv(c.a)) wfd2 = int(self.wf_thickness // 2) if wfd2 != self.wf_line_cnt: bc = blend_colours(wfc.with_a(wfc.a * ((self.wf_thickness / 2) - wfd2)), c) tpixel = to_pixel(bc) else: bc = None pixel = to_pixel(c) wfpixel = to_pixel(blend_colours(wfc, c)) line = array.array('B') for _ in range(wfd2): line.extend(wfpixel) if bc is not None: line.extend(tpixel) for _ in range(self.square_size - 2 * self.wf_line_cnt): line.extend(pixel) if bc is not None: line.extend(tpixel) for _ in range(wfd2): line.extend(wfpixel) lbytes = line.tobytes() wfline = array.array('B') for _ in range(self.square_size): wfline.extend(wfpixel) wflbytes = wfline.tobytes() if bc is None: tlbytes = wflbytes else: tline = array.array('B') for _ in range(wfd2): tline.extend(wfpixel) tline.extend(tpixel) for _ in range(self.square_size - 2 * self.wf_line_cnt): tline.extend(tpixel) tline.extend(tpixel) for _ in range(wfd2): tline.extend(wfpixel) tlbytes = tline.tobytes() self.__lines[(c, wfc)] = (lbytes, wflbytes, tlbytes) return lbytes, wflbytes, tlbytes
def get_colour(self, val: float) -> Optional[Colour]: mag = (val - self.min_val) d = (self.max_val - self.min_val) if d != 0: mag /= d # catch NaN in addition to out-of-bounds if not (mag >= 0 and mag <= 1): return None cmag = Colour(mag, mag, mag, mag) cmin = self.__deduced_min_colour cmax = self.__deduced_max_colour cvec: Colour = cmax - cmin clr = (cmax - cmag * cvec) if self.inverted else (cmin + cmag * cvec) return clr
def set_display_info(self): active_kernel_displays = [] if self.__active_kernel: active_kernel_displays = [ # *self.__active_kernel.instance.set_display_info(), OnlineLSTMMapDisplay(self._services, custom_map=self.__active_kernel.map), EntitiesMapDisplay(self._services, custom_map=self.__active_kernel.map), ] trace_colour = self._services.state.views.add_colour( "trace", Colour(0, 0.9, 0)) return super().set_display_info() + [ *active_kernel_displays, SolidIterableMapDisplay( self._services, self.__total_path, trace_colour, z_index=80), ]
def __init__(self, services: Services, model: Model, root_view: Optional[View]) -> None: super().__init__(services, model, root_view) self.__displays = [] self.__tracked_data = [] self.__cube_update_displays = [] self.__previous_cube_update_displays = [] self.__previous_cube_update_displays_rendered = [] self.__cubes_requiring_update = set() self.__cube_colour = None # world (dummy node) self.__world = self._services.graphics.window.render.attach_new_node("world") # MAP # extended_walls: bool = False map_size = self._services.algorithm.map.size map_data = np.empty((*map_size, 1) if map_size.n_dim == 2 else map_size, dtype=np.uint8) self.__cube_modified = np.empty(map_data.shape, dtype=bool) for x, y, z in np.ndindex(map_data.shape): p = Point(x, y) if map_size.n_dim == 2 else Point(x, y, z) i = self._services.algorithm.map.at(p) if i == Map.WALL_ID: map_data[x, y, z] = MapData.OBSTACLE_MASK self.__cube_modified[x, y, z] = False elif i == Map.EXTENDED_WALL_ID: map_data[x, y, z] = MapData.EXTENDED_WALL_MASK | MapData.TRAVERSABLE_MASK self.__cube_modified[x, y, z] = True extended_walls = True elif i == Map.UNMAPPED_ID: map_data[x, y, z] = MapData.UNMAPPED_MASK self.__cube_modified[x, y, z] = False else: map_data[x, y, z] = MapData.TRAVERSABLE_MASK self.__cube_modified[x, y, z] = True if map_size.n_dim == 2: self.__map = FlatMap(self._services, map_data, self.world) self.__set_cube_colour = lambda p, c, wfc: self.map.render_square(p, c, wfc) else: self.__map = VoxelMap(self._services, map_data, self.world) self.__set_cube_colour = lambda p, c, *discard: self.map.traversables_mesh.set_cube_colour(p, c) self.__map.center() self.__overlay = self.map.root.attach_new_node("overlay") self.__scratch = self.map.root.attach_new_node("scratch") self.renderer.push_root(self.__scratch) self.__entities_map_display = None self.__weight_grid_display = None self.__extended_walls_display = None self.__persistent_displays = [EntitiesMapDisplay(self._services)] self.__entities_map_display = self.__persistent_displays[-1] if extended_walls: grid = TrackedGrid(self.map.data, copy=False) dc = self._services.state.views.add_colour("extended wall", Colour(0.5).with_a(0.5)) self.__persistent_displays.append(SolidGridMapDisplay(self._services, grid, dc, z_index=0, comparator=lambda x: bool(x & MapData.EXTENDED_WALL_MASK))) self.__extended_walls_display = self.__persistent_displays[-1] if hasattr(self._services.algorithm.map, "weight_grid"): mp = self._services.algorithm.map wg = TrackedGrid(mp.weight_grid, copy=False) dc_min = self._services.state.views.add_colour("min occupancy", BLACK.with_a(0)) dc_max = self._services.state.views.add_colour("max occupancy", BLACK) display = GradientGridMapDisplay(self._services, wg, min_colour=dc_min, max_colour=dc_max, value_bounds=(0.1, mp.traversable_threshold)) self.__persistent_displays.append(display) self.__weight_grid_display = self.__persistent_displays[-1] self.__deduced_traversables_colour = self._services.state.views.effective_view.colours[MapData.TRAVERSABLES]() self.__deduced_traversables_wf_colour = self._services.state.views.effective_view.colours[MapData.TRAVERSABLES_WF]() self.__sphere_scale = 0.2 """ def rescale_sphere(dim): while (self.__sphere_scale < 0.75) and ((self.__sphere_scale * dim) < 8): self.__sphere_scale *= 1.25 rescale_sphere(self.map.logical_w) rescale_sphere(self.map.logical_h) rescale_sphere(self.map.logical_d) """ self.__circle_filled_radius = 0.06 def resize_circle_filled(dim): if dim < 40: pass elif dim < 75: dim /= 1.5 elif dim < 100: dim /= 2 while (self.__circle_filled_radius < 1) and (dim / self.__circle_filled_radius > 250): self.__circle_filled_radius *= 1.25 resize_circle_filled(self.map.logical_w) resize_circle_filled(self.map.logical_h) resize_circle_filled(self.map.logical_d) self.__line_thickness = 2.5 def change_line_thickness(dim): while (self.__line_thickness < 4) and (dim / self.__line_thickness > 160): self.__line_thickness *= 1.25 change_line_thickness(self.map.logical_w) change_line_thickness(self.map.logical_h) change_line_thickness(self.map.logical_d) self.renderer.line_segs.set_thickness(self.__line_thickness) self.__update_view(True) self._services.ev_manager.broadcast(StateInitialisedEvent())
from structures import Colour from utility.compatibility import Final WINDOW_BG_COLOUR: Final[Colour] = Colour(0.5, 0.5, 0.5, 1.0) WIDGET_BG_COLOUR: Final[Colour] = Colour(0.3, 0.3, 0.3, 1.0)
def get_cube_colour(self, p: Point) -> Colour: return Colour(*self.__cubes[p.values].get_color())
class MapData(ABC): _services: Services __name: Final[str] __root: Final[NodePath] __colour_callbacks: Dict[str, Callable[[DynamicColour], None]] TRAVERSABLE_MASK: Final = np.uint8(1 << 0) OBSTACLE_MASK: Final = np.uint8(1 << 1) UNMAPPED_MASK: Final = np.uint8(1 << 2) EXTENDED_WALL_MASK: Final = np.uint8(1 << 3) data: Final[NDArray[(Any, Any, Any), np.uint8]] # REQUIRED COLOURS / COMPONENTS # BG: Final[str] = "background" # OPTIONAL COLOURS / COMPONENTS # TRAVERSABLES: Final[str] = "traversables" TRAVERSABLES_WF: Final[str] = "traversables w.f." OBSTACLES: Final[str] = "obstacles" OBSTACLES_WF: Final[str] = "obstacles w.f." AGENT: Final[str] = "agent" TRACE: Final[str] = "trace" GOAL: Final[str] = "goal" _DEFAULTS: Final[Dict[str, Colour]] = { BG: Colour(0, 0, 0.2, 1), TRAVERSABLES: WHITE, TRAVERSABLES_WF: BLACK, OBSTACLES: BLACK, OBSTACLES_WF: WHITE, AGENT: Colour(0.8, 0, 0), TRACE: Colour(0, 0.9, 0), GOAL: Colour(0, 0.9, 0) } logical_w: Final[int] # x-axis (width) logical_h: Final[int] # y-axis (height) logical_d: Final[int] # z-axis (depth) def __init__(self, services: Services, data: NDArray[(Any, Any, Any), bool], parent: NodePath, name: str = "map"): self._services = services self.__name = name self.__colour_callbacks = {} self.data = data self.logical_w = int(self.data.shape[0]) self.logical_h = int(self.data.shape[1]) self.logical_d = int(self.data.shape[2]) self._services.ev_manager.register_listener(self) self.__root = parent.attach_new_node(self.name) self.root.set_transparency(TransparencyAttrib.M_alpha) self._add_colour(MapData.BG, callback=lambda dc: self._services.graphics.window. set_background_color(*dc())) def notify(self, event: Event) -> None: if isinstance(event, ColourUpdateEvent): if event.colour.name in self.__colour_callbacks: self.__colour_callbacks[event.colour.name](event.colour) @property @abstractmethod def dim(self) -> int: ... @property def root(self) -> NodePath: return self.__root @property def name(self) -> NodePath: return self.__name def _add_colour( self, name: str, default_colour: Optional[Colour] = None, default_visible: bool = True, invoke_callback: bool = True, callback: Optional[Callable[[DynamicColour], None]] = None ) -> DynamicColour: if default_colour is None: default_colour = MapData._DEFAULTS[name] dc = self._services.state.views.add_colour(name, default_colour, default_visible) if callback is None: return dc if name not in self.__colour_callbacks: self.__colour_callbacks[name] = callback if invoke_callback: callback(dc) return dc def center(self) -> None: world = self.root.get_parent() (x1, y1, z1), (x2, y2, z2) = self.root.get_tight_bounds() self.root.set_pos(world.getX() - (x2 - x1) / 2, world.getY() - (y2 - y1) / 2, world.getZ() - (z2 - z1) / 2) def destroy(self) -> None: self.__root.remove_node() self._services.ev_manager.unregister_listener(self)
def _from_json(self, data: Dict[str, Any]) -> None: for n, c in data["colours"].items(): colour = Colour(*c["colour"]) visible = bool(c["visible"]) self.colours[n] = DynamicColour(colour, n, self.__colour_callback, visible)