def __init__(self, coordinate_factory): self._coordinate_factory = coordinate_factory self._robot_factory = RobotFactory(coordinate_factory) self._world_detector = WorldDetector(coordinate_factory, self._robot_factory) self._world_map_drawing_service = WorldMapDrawingService() self._on_detection_complete = EventHandler() self._world_map = WorldMap() self._display_labels = False self._camera_follow_mode = False self._last_detection_timespan = timedelta(0)
def setup(self, detected_robot_mock, estimated_robot_mock): self._detected_robot_mock_instance = detected_robot_mock.return_value self._detected_robot_mock_instance.creation_source = RobotCreationSource.DETECTION self._detected_robot_mock_instance.creation_time = datetime.now() self._estimated_robot_mock_instance = estimated_robot_mock.return_value self._estimated_robot_mock_instance.creation_source = RobotCreationSource.ESTIMATE self._estimated_robot_mock_instance.creation_time = datetime.now() self._world_map = WorldMap() self._world_descriptor = WorldDescriptor( WorldObjectType.all(), self.SAMPLE_REFERENCE_IMAGE, self.SAMPLE_PLAYFIELD, self._detected_robot_mock_instance, self.SAMPLE_CHARGING_STATION, self.SAMPLE_ISLANDS, self.SAMPLE_TREASURES, )
class TestWorldMap(object): SAMPLE_PLAYFIELD = object() SAMPLE_CHARGING_STATION = object() SAMPLE_ISLANDS = [object(), object()] SAMPLE_TREASURES = [object(), object()] SAMPLE_TREASURES_2 = [object(), object()] SAMPLE_REFERENCE_IMAGE = object() @mock.patch("domain.world_objects.robot.Robot.Robot", autospec=False) @mock.patch("domain.world_objects.robot.Robot.Robot", autospec=False) def setup(self, detected_robot_mock, estimated_robot_mock): self._detected_robot_mock_instance = detected_robot_mock.return_value self._detected_robot_mock_instance.creation_source = RobotCreationSource.DETECTION self._detected_robot_mock_instance.creation_time = datetime.now() self._estimated_robot_mock_instance = estimated_robot_mock.return_value self._estimated_robot_mock_instance.creation_source = RobotCreationSource.ESTIMATE self._estimated_robot_mock_instance.creation_time = datetime.now() self._world_map = WorldMap() self._world_descriptor = WorldDescriptor( WorldObjectType.all(), self.SAMPLE_REFERENCE_IMAGE, self.SAMPLE_PLAYFIELD, self._detected_robot_mock_instance, self.SAMPLE_CHARGING_STATION, self.SAMPLE_ISLANDS, self.SAMPLE_TREASURES, ) def test_given_complete_world_descriptor_when_merging_world_descriptor_then_results_are_merged(self): self._world_map.merge_world_descriptor(self._world_descriptor) assert_is(self._world_map.playfield, self.SAMPLE_PLAYFIELD) assert_is(self._world_map.robot, self._detected_robot_mock_instance) assert_equals(self._world_map.islands, self.SAMPLE_ISLANDS) assert_equals(self._world_map.treasures, self.SAMPLE_TREASURES) assert_is(self._world_map.reference_image, self.SAMPLE_REFERENCE_IMAGE) def test_given_complete_world_descriptor_when_merging_world_descriptor_then_world_map_contains_the_descriptor_objects( self ): self._world_map.merge_world_descriptor(self._world_descriptor) assert_true(self._world_map.contains(WorldObjectType.PLAYFIELD)) assert_true(self._world_map.contains(WorldObjectType.ROBOT)) assert_true(self._world_map.contains(WorldObjectType.ISLAND)) assert_true(self._world_map.contains(WorldObjectType.TREASURE)) def test_given_no_playfield_descriptor_when_merging_world_descriptor_then_last_playfield_is_kept(self): self._world_map.merge_world_descriptor(self._world_descriptor) self._world_descriptor.playfield = None self._world_map.merge_world_descriptor(self._world_descriptor) assert_is(self._world_map.playfield, self.SAMPLE_PLAYFIELD) def test_given_no_robot_descriptor_when_merging_world_descriptor_then_last_robot_is_kept(self): self._world_map.merge_world_descriptor(self._world_descriptor) self._world_descriptor.robot = None self._world_map.merge_world_descriptor(self._world_descriptor) assert_is(self._world_map.robot, self._detected_robot_mock_instance) def test_given_no_charging_station_descriptor_when_merging_world_descriptor_then_last_charging_station_is_kept( self ): self._world_map.merge_world_descriptor(self._world_descriptor) self._world_descriptor.charging_station = None self._world_map.merge_world_descriptor(self._world_descriptor) assert_is(self._world_map.charging_station, self.SAMPLE_CHARGING_STATION) def test_given_partial_descriptor_when_merging_world_descriptor_then_last_objects_are_kept(self): self._world_map.merge_world_descriptor(self._world_descriptor) self._world_descriptor = WorldDescriptor([], self.SAMPLE_REFERENCE_IMAGE) self._world_map.merge_world_descriptor(self._world_descriptor) assert_is(self._world_map.playfield, self.SAMPLE_PLAYFIELD) assert_is(self._world_map.robot, self._detected_robot_mock_instance) assert_equals(self._world_map.islands, self.SAMPLE_ISLANDS) assert_equals(self._world_map.treasures, self.SAMPLE_TREASURES) assert_is(self._world_map.reference_image, self.SAMPLE_REFERENCE_IMAGE) def test_given_treasures_when_merging_treasures_with_append_flag_then_treasures_are_appended(self): self._world_map.merge_world_descriptor(self._world_descriptor) self._world_map.merge_treasures(self.SAMPLE_TREASURES_2, append=True) assert_equals(len(self._world_map.treasures), len(self.SAMPLE_TREASURES) + len(self.SAMPLE_TREASURES_2)) def test_given_estimated_robot_when_getting_estimated_robot_then_estimated_robot_is_returned(self): self._world_map.merge_world_descriptor(self._world_descriptor) self._world_descriptor.robot = self._estimated_robot_mock_instance self._world_map.merge_world_descriptor(self._world_descriptor) returned_robot = self._world_map.estimated_robot assert_is(returned_robot, self._estimated_robot_mock_instance) def test_given_non_empty_world_map_when_fully_resetting_world_map_then_world_map_is_cleared(self): self._world_map.merge_world_descriptor(self._world_descriptor) self._world_map.reset(WorldObjectType.all()) assert_false(self._world_map.contains(WorldObjectType.PLAYFIELD)) assert_false(self._world_map.contains(WorldObjectType.ROBOT)) assert_false(self._world_map.contains(WorldObjectType.ISLAND)) assert_false(self._world_map.contains(WorldObjectType.TREASURE)) def test_given_non_empty_world_map_when_partially_resetting_world_map_then_world_map_is_partially_cleared(self): self._world_map.merge_world_descriptor(self._world_descriptor) self._world_map.reset([WorldObjectType.ROBOT]) assert_true(self._world_map.contains(WorldObjectType.PLAYFIELD)) assert_false(self._world_map.contains(WorldObjectType.ROBOT)) def test_given_no_detected_robot_when_getting_robot_then_estimated_robot_is_returned(self): self._world_descriptor.robot = self._estimated_robot_mock_instance self._world_map.merge_world_descriptor(self._world_descriptor) returned_robot = self._world_map.robot assert_is(returned_robot, self._estimated_robot_mock_instance) def test_given_detected_robot_when_getting_robot_then_detected_robot_is_returned(self): self._world_map.merge_world_descriptor(self._world_descriptor) self._world_descriptor.robot = self._estimated_robot_mock_instance self._world_map.merge_world_descriptor(self._world_descriptor) returned_robot = self._world_map.robot assert_is(returned_robot, self._detected_robot_mock_instance) def test_given_no_detected_robot_when_getting_robot_then_estimated_robot_is_returned(self): self._world_descriptor.robot = self._estimated_robot_mock_instance self._world_map.merge_world_descriptor(self._world_descriptor) returned_robot = self._world_map.robot assert_is(returned_robot, self._estimated_robot_mock_instance) def test_given_detected_robot_with_expired_creation_time_when_getting_robot_then_estimated_robot_is_returned(self): self._world_descriptor.robot.creation_time = datetime.min self._world_map.merge_world_descriptor(self._world_descriptor) self._world_descriptor.robot = self._estimated_robot_mock_instance self._world_map.merge_world_descriptor(self._world_descriptor) returned_robot = self._world_map.robot assert_is(returned_robot, self._estimated_robot_mock_instance) def test_given_detected_robot_with_expired_creation_time_and_no_estimated_robot_when_getting_robot_then_detected_robot_is_returned( self ): self._world_descriptor.robot.creation_time = datetime.min self._world_map.merge_world_descriptor(self._world_descriptor) returned_robot = self._world_map.robot assert_is(returned_robot, self._detected_robot_mock_instance) def test_given_estimated_robot_when_getting_robot_in_estimated_robot_prioritization_mode_then_estimated_robot_is_returned( self ): self._world_map.merge_world_descriptor(self._world_descriptor) self._world_descriptor.robot = self._estimated_robot_mock_instance self._world_map.merge_world_descriptor(self._world_descriptor) self._world_map.robot_prioritization_mode = RobotPrioritizationMode.PRIORITIZE_ESTIMATED returned_robot = self._world_map.robot assert_is(returned_robot, self._estimated_robot_mock_instance) def test_given_no_estimated_robot_when_getting_robot_in_estimated_robot_prioritization_mode_then_detected_robot_is_returned( self ): self._world_map.merge_world_descriptor(self._world_descriptor) self._world_map.robot_prioritization_mode = RobotPrioritizationMode.PRIORITIZE_ESTIMATED returned_robot = self._world_map.robot assert_is(returned_robot, self._detected_robot_mock_instance)
class WorldMapService(object): @property def detection_speed(self): return self._last_detection_timespan @property def world_map(self): return self._world_map @property def display_labels(self): return _display_labels @display_labels.setter def display_labels(self, value): self._display_labels = value @property def camera_follow_mode(self): return _camera_follow_mode @camera_follow_mode.setter def camera_follow_mode(self, value): self._camera_follow_mode = value @property def on_detection_complete(self): return self._on_detection_complete @on_detection_complete.setter def on_detection_complete(self, value): self._on_detection_complete = value def __init__(self, coordinate_factory): self._coordinate_factory = coordinate_factory self._robot_factory = RobotFactory(coordinate_factory) self._world_detector = WorldDetector(coordinate_factory, self._robot_factory) self._world_map_drawing_service = WorldMapDrawingService() self._on_detection_complete = EventHandler() self._world_map = WorldMap() self._display_labels = False self._camera_follow_mode = False self._last_detection_timespan = timedelta(0) def reset(self, world_object_types): self._world_map.reset(world_object_types) def detect_objects(self, image): start_time = datetime.datetime.now() try: self._execute_detection(image) finally: end_time = datetime.datetime.now() self._last_detection_timespan = end_time - start_time self._on_detection_complete.fire() return self._world_map def _execute_detection(self, image): self._world_descriptor = self._world_detector.detect_objects(image, self._get_object_types_to_detect()) self._world_map.merge_world_descriptor(self._world_descriptor) def _get_object_types_to_detect(self): object_types_to_detect = self._world_map.missing_world_object_types object_types_to_detect.append(WorldObjectType.ROBOT) return object_types_to_detect def draw_world_map(self): self._world_map_drawing_service.draw(self._world_map, self._display_labels, self._camera_follow_mode) return self._world_map.reference_image def get_islands(self, island_descriptor): return [island for island in self._world_map.islands if island.matches(island_descriptor)] def get_treasures(self): return self._world_map.treasures def get_pickable_treasures(self): island_locations = [island.get_center() for island in self._world_map.islands] return list(filter(lambda treasure: not treasure.get_pickup_area(self._world_map.playfield, self._world_map.robot).contains(island_locations), self._world_map.treasures)) def get_robot(self): return self._world_map.robot def get_playfield(self): return self._world_map.playfield def remove_treasure(self, treasure): self._world_map.treasures.remove(treasure) def update_estimated_robot_position(self, center = None, angle = None, coordinate_system = CoordinateSystem.GAME): if center is None: center = self._world_map.robot.get_center() if angle is None: angle = self._world_map.robot.angle robot = self._robot_factory.create(center, angle, coordinate_system, RobotCreationSource.ESTIMATE) self._world_map.merge_robot(robot) def clear_estimated_robot_position(self): self._world_map.estimated_robot = None def wait_for_detection(self, world_object_types, strict, timeout): start_time = datetime.datetime.now(); while not self._world_map.contains(world_object_types, strict): self._on_detection_complete.join(timeout) if (datetime.datetime.now() - start_time).total_seconds() > timeout: raise TimeoutError("Timeout was reached while waiting for the specified detection status.") return self._world_map def merge_local_world_map(self, local_world_map): for treasure in local_world_map.treasures: treasure_location = treasure.map_to_playfield(self._world_map.playfield) treasure_location_coordinate = self._coordinate_factory.create(treasure_location, CoordinateSystem.CAMERA) treasure = Treasure(treasure_location_coordinate, len(self._world_map.treasures)) self._world_map.merge_treasures([treasure], append = True)