Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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)