def create_remote_brick_instance(self, brick: Brick): def create_callback(response: dict): if "placement_allowed" in response: if response["placement_allowed"]: # set the remote asset id #FIXME: does this reference to the brick instance work? brick.object_id = int(response["object_id"]) else: logger.info("placement of brick {} is not allowed".format(brick)) brick.status = BrickStatus.OUTDATED_BRICK else: logger.warning("protocol error which creating brick {}".format(brick)) # TODO: should the brick status change? logger.debug("creating a brick instance for {}".format(brick)) # Compute geographical coordinates for bricks Extent.calc_world_pos(brick, self.extent_tracker.board, self.extent_tracker.map_extent) # Send request creating remote brick instance and save the response message = SEND_REC_CREATE_OBJECT_MSG.copy() message["shape"] = str(brick.token.shape).replace("BrickShape.", "") message["color"] = str(brick.token.color).replace("BrickColor.", "") message["position_x"] = brick.map_pos_x message["position_y"] = brick.map_pos_y self.send_message(message, create_callback)
def game_mode_change(self, response: dict): logger.info("the landscapelab tries to change the game mode") if "projection_epsg" in response: epsg = int(response["projection_epsg"]) else: epsg = self.config.get("map_settings", "coordinate_reference_system") # calculate the main map extent based on the starting location start_position = Vector(float(response["start_position_x"]), float(response["start_position_y"])) width = float(response["start_extent_x"]) height = float(response["start_extent_y"]) start_extent = Extent.around_center(start_position, width, height/width) self.extent_tracker.map_extent = start_extent # setup the minimap extent mm_min_x = float(response["minimap_min_x"]) mm_min_y = float(response["minimap_min_y"]) mm_max_x = float(response["minimap_max_x"]) mm_max_y = float(response["minimap_max_y"]) minimap_extent = Extent(mm_min_x, mm_min_y, mm_max_x, mm_max_y) # change the maps self.mini_map.initialize_map(epsg, minimap_extent) self.main_map.initialize_map(epsg, start_extent) # reset the tracker and feed him the allowed brick combinations allowed_bricks = [] for token_dict in response["used_tokens"]: shape = BrickShape[token_dict["shape"]] color = BrickColor[token_dict["color"]] icon_id = token_dict["icon_name"] brick_config.icon_config[(token_dict["shape"], token_dict["color"])] = icon_id disappear = float(token_dict["disappear_after_seconds"]) # FIXME: to be implemented token = Token(shape, color, icon_id) # FIXME: currently the svg is not implemented (coded via icon names) allowed_bricks.append(token) self.tracker.change_game_mode(allowed_bricks) # add new tokens for brick in response["existing_tokens"]: self.create_local_brick(brick) # create the scores for the new game mode scores = [] for score_dict in response["scores"]: score_id = int(score_dict["score_id"]) initial_value = float(score_dict["initial_value"]) target_value = float(score_dict["target_value"]) name = "" if score_dict["name"]: name = score_dict["name"] score = Score(score_id, target_value, initial_value, name) scores.append(score) UISetup.add_progressbars_to_ui(self.progressbars_ui, self.config, scores) # finally set to EXTERNAL ProgramStage self.program_stage.next()
def set_virtual_brick_at_global_pos_of(self, brick: Brick): virtual_brick = brick.clone() Extent.calc_local_pos(virtual_brick, self.extent_tracker.board, self.extent_tracker.map_extent) self.virtual_bricks.append(virtual_brick) Tracker.BRICKS_REFRESHED = True
def __init__(self, config: Configurator, name: str, extent: Extent, zoom_limits: Tuple[int, int], resolution: Tuple[int, int]): self.name = name self.config = config self.extent_tracker = ExtentTracker.get_instance() self.min_zoom, self.max_zoom = zoom_limits # set resolution self.resolution_x, self.resolution_y = resolution # initialize two black images self.map_image = [ ImageHandler.ensure_alpha_channel( np.ones((self.resolution_y, self.resolution_x, 3), np.uint8) * 255), ImageHandler.ensure_alpha_channel( np.ones( (self.resolution_y, self.resolution_x, 3), np.uint8) * 255) ] self.current_image = 0 # crs is initialized with a local configuration but overwritten once a connection with the LL is established self.crs = config.get("map_settings", "coordinate_reference_system") extent.fit_to_ratio(self.resolution_y / self.resolution_x) self.current_extent: Extent = extent # set extent modifiers pan_up_modifier = np.array([0, 1, 0, 1]) pan_down_modifier = np.array([0, -1, 0, -1]) pan_left_modifier = np.array([-1, 0, -1, 0]) pan_right_modifier = np.array([1, 0, 1, 0]) self.zoom_in_modifier = np.array([1, 1, -1, -1]) self.zoom_out_modifier = np.array([-1, -1, 1, 1]) # get navigation settings pan_distance = config.get('map_settings', 'pan_distance') zoom_strength = config.get('map_settings', 'zoom_strength') # these functions can be used to interact with the map # by calling these functions one can pan and zoom on the map # the functions will automatically request a new rendered map extent from the QGIS plugin # they need accept an unused brick parameter to make it possible to call these functions via UICallback self.pan_up = partial(self.modify_extent, pan_up_modifier, pan_distance) self.pan_down = partial(self.modify_extent, pan_down_modifier, pan_distance) self.pan_left = partial(self.modify_extent, pan_left_modifier, pan_distance) self.pan_right = partial(self.modify_extent, pan_right_modifier, pan_distance) self.zoom_in = partial(self.modify_extent, self.zoom_in_modifier, zoom_strength) self.zoom_out = partial(self.modify_extent, self.zoom_out_modifier, zoom_strength)
def __init__(self, config: Configurator, position: Vector, size: Vector, color: List = None, border_color: List = None, border_weight: float = None): super().__init__() # overwrite none values with defaults if color is None: color = config.get("ui_settings", "nav_block_background_color") if border_color is None: border_color = config.get("ui_settings", "nav_block_border_color") if border_weight is None: border_weight = config.get("ui_settings", "nav_block_border_weight") # set block position/size self.position = position # only modify with set_position self.size = size # only modify with set_size self.area = Extent.from_vectors(position, position + size, False) # only modify with set_area self.is_ellipse = False # set block color self.color = (color[0], color[1], color[2]) self.show_background_color = True self.border_thickness: float = border_weight self.border_color = (border_color[0], border_color[1], border_color[2]) self.show_border = True
def beamer_mouse_callback(self, event, x, y, flags, param): if self.program_stage.current_stage == ProgramStage.INTERNAL_MODE \ or self.program_stage.current_stage == ProgramStage.EXTERNAL_MODE: if event == cv2.EVENT_LBUTTONDOWN or event == cv2.EVENT_RBUTTONDOWN: color = BrickColor.BLUE_BRICK if event == cv2.EVENT_RBUTTONDOWN: color = BrickColor.RED_BRICK # create brick on mouse position mouse_brick = Extent.remap_brick(Brick(x, y, Token(BrickShape.SQUARE_BRICK, color)), self.extent_tracker.beamer, self.extent_tracker.board ) # check for nearby virtual bricks virtual_brick = self.tracker.check_min_distance(mouse_brick, self.tracker.virtual_bricks) if virtual_brick: # if mouse brick is on top of other virtual brick, remove that brick self.tracker.remove_external_virtual_brick(virtual_brick) else: # otherwise add the mouse brick self.tracker.virtual_bricks.append(mouse_brick) # set mouse brick refreshed flag TableOutputStream.MOUSE_BRICKS_REFRESHED = True
def mark_external_bricks_outdated_if_map_updated(self): # if the extent changed, set external bricks as outdated self.extent_changed = self.extent_tracker.extent_changed if self.extent_changed is True: logger.debug("recalculate virtual brick position") for brick in self.virtual_bricks: if brick.status == BrickStatus.EXTERNAL_BRICK: Extent.calc_local_pos(brick, self.extent_tracker.board, self.extent_tracker.map_extent) logger.info("set bricks outdated because extent changed") self.invalidate_external_bricks() # set the flag back self.extent_tracker.extent_changed = False
def get_start_extent(self): starting_location = Vector(self.config.get("map_settings", "start_x"), self.config.get("map_settings", "start_y")) # extrude start location to start extent zoom = self.config.get("map_settings", "start_zoom") return Extent.around_center(starting_location, zoom, 1)
def compute_board_size(self, corners): min_x, min_y, max_x, max_y = self.find_min_max(corners) # Compute board size self.board.width = max_x - min_x self.board.height = max_y - min_y ExtentTracker.get_instance().board = Extent.from_rectangle(0, 0, self.board.width, self.board.height) logger.info('board has been set to {}'.format(ExtentTracker.get_instance().board))
def render_callback(response: dict): extent = Extent(float(response["extent"]["x_min"]), float(response["extent"]["y_min"]), float(response["extent"]["x_max"]), float(response["extent"]["y_max"]), True) # convert response to the bytebuffer base64_bytes = response["image"].encode("ascii") buffer = base64.standard_b64decode(base64_bytes) self.callbacks[response["target"]].refresh(extent, buffer)
def set_screen_config_info(config): monitors = screeninfo.get_monitors() config.set("screen_resolution", "width", monitors[0].width) config.set("screen_resolution", "height", monitors[0].height) config.set("screen_resolution", "pos_x", monitors[0].x - 1) config.set("screen_resolution", "pos_y", monitors[0].y - 1) beamer_id = config.get("beamer_resolution", "screen_id") if beamer_id >= 0: # if beamer-id out of bounds use last screen beamer_id = min(beamer_id, len(monitors) - 1) beamer = monitors[beamer_id] config.set("beamer_resolution", "width", beamer.width) config.set("beamer_resolution", "height", beamer.height) config.set("beamer_resolution", "pos_x", beamer.x - 1) config.set("beamer_resolution", "pos_y", beamer.y - 1) ExtentTracker.get_instance().beamer = Extent(0, 0, beamer.width, beamer.height)
def ellipse(img, area: Extent, color, border_thickness): cv.ellipse(img, area.get_center().as_point(), (area.get_size() / 2).as_point(), 0, 0, 360, color, border_thickness)
def rectangle(img, area: Extent, color, border_thickness): cv.rectangle(img, area.get_upper_left().as_point(), area.get_lower_right().as_point(), color, border_thickness)
def set_area(self, area: Extent): self.position = area.get_upper_left self.size = area.get_size() self.area = area
def brick_would_land_on_ui(self, brick): brick_on_beamer = Extent.remap_brick(brick, self.extent_tracker.board, self.extent_tracker.beamer) return self.ui_root.brick_would_land_on_element(brick_on_beamer)
def get_global_area(self) -> Extent: pos = self.get_global_pos() return Extent.from_vectors(pos, pos + self.size)
class UIStructureBlock(UIElement): def __init__(self, config: Configurator, position: Vector, size: Vector, color: List = None, border_color: List = None, border_weight: float = None): super().__init__() # overwrite none values with defaults if color is None: color = config.get("ui_settings", "nav_block_background_color") if border_color is None: border_color = config.get("ui_settings", "nav_block_border_color") if border_weight is None: border_weight = config.get("ui_settings", "nav_block_border_weight") # set block position/size self.position = position # only modify with set_position self.size = size # only modify with set_size self.area = Extent.from_vectors(position, position + size, False) # only modify with set_area self.is_ellipse = False # set block color self.color = (color[0], color[1], color[2]) self.show_background_color = True self.border_thickness: float = border_weight self.border_color = (border_color[0], border_color[1], border_color[2]) self.show_border = True # draws the block onto an image def draw(self, img): if self.visible: self.draw_background(img, self.color) self.draw_border(img, self.border_color) self.draw_hierarchy(img) # draws the background of the structure block onto an image def draw_background(self, img, color, force=False): if self.show_background_color or force: if self.is_ellipse: # draw ellipse UIStructureBlock.ellipse(img, self.get_global_area(), color, cv.FILLED) else: # draw rect UIStructureBlock.rectangle(img, self.get_global_area(), color, cv.FILLED) # draws the border of the structure block onto an image def draw_border(self, img, color, force=False): if self.show_border or force: if self.is_ellipse: # draw ellipse UIStructureBlock.ellipse(img, self.get_global_area(), color, self.border_thickness) else: # draw rect UIStructureBlock.rectangle(img, self.get_global_area(), color, self.border_thickness) # checks if a given brick lies on top of the block or any of it's children def brick_on_element(self, brick: Brick) -> bool: if self.visible: return super().brick_on_element(brick) or self.pos_on_block( Vector.from_brick(brick)) return False # checks if a given (unconfirmed) brick would land on top of the block or any of it's children def brick_would_land_on_element(self, brick: Brick) -> bool: if self.visible: return super().brick_would_land_on_element( brick) or self.pos_on_block(Vector.from_brick(brick)) return False # checks if any screen coordinate lies on top of def pos_on_block(self, pos: Vector) -> bool: if self.visible: return self.get_global_area().vector_inside(pos) return False # get the global area as extent def get_global_area(self) -> Extent: pos = self.get_global_pos() return Extent.from_vectors(pos, pos + self.size) # overwrites current position # also updates area def set_position(self, pos: Vector): self.area.move_by(pos - self.position) super().set_position(pos) # overwrites current size and updates area def set_size(self, size: Vector): self.area = Extent(self.area.get_upper_left(), self.position + size) self.size = size # overwrites current area and updates size and position def set_area(self, area: Extent): self.position = area.get_upper_left self.size = area.get_size() self.area = area # draws a rectangle using a given area @staticmethod def rectangle(img, area: Extent, color, border_thickness): cv.rectangle(img, area.get_upper_left().as_point(), area.get_lower_right().as_point(), color, border_thickness) # draws a rectangle using a given area @staticmethod def ellipse(img, area: Extent, color, border_thickness): cv.ellipse(img, area.get_center().as_point(), (area.get_size() / 2).as_point(), 0, 0, 360, color, border_thickness)
def render_brick(self, brick, render_target, virtual=False): b = Extent.remap_brick(brick, self.extent_tracker.board, self.extent_tracker.beamer) pos = (int(b.centroid_x), int(b.centroid_y)) icon = self.get_brick_icon(brick, virtual) ImageHandler.img_on_background(render_target, icon, pos)
def add_external_brick(self, brick: Brick): # TODO: maybe add security checks to not add the same brick twice etc? Extent.calc_local_pos(brick, self.extent_tracker.board, self.extent_tracker.map_extent) self.virtual_bricks.append(brick)
def set_size(self, size: Vector): self.area = Extent(self.area.get_upper_left(), self.position + size) self.size = size