示例#1
0
    def test_what_points_object_contains_when_its_enclosed(self):
        obj_a = Object(2, (0, 0), [(0, 0)])

        obj_b = Object(1, (2, 2), [
            (0, 0),
            (1, 0),
            (2, 0),
            (3, 0),
            (3, 1),
            (3, 2),
            (2, 2),
            (1, 2),
            (0, 2),
            (0, 1),
        ])
        frame_model = ObjectRuntime.make_frame_model_from_objects(
            [obj_a, obj_b], 0)

        self.assertEqual(
            0,
            len(GeometryRuntime.points_contained_by_object(obj_a,
                                                           frame_model)))

        points_contained_by_b = GeometryRuntime.points_contained_by_object(
            obj_b, frame_model)
        self.assertEqual(2, len(points_contained_by_b))
        self.assertSequenceEqual([(3, 3), (4, 3)], points_contained_by_b)
示例#2
0
def are_objects_the_same_kind(a: Object.Object, b: Object.Object) -> bool:
    a_kind = a.get_object_kind()
    b_kind = b.get_object_kind()

    a_colour, a_relative_positions_string = a_kind.split(":")
    b_colour, b_relative_positions_string = b_kind.split(":")

    if a_colour != b_colour:
        return False

    # we convert to sets so that the order of the relative_positions doesn't matter
    a_relative_positions = set(
        map(lambda position: (position[0], position[1]),
            json.loads(a_relative_positions_string)))
    b_relative_positions = set(
        map(lambda position: (position[0], position[1]),
            json.loads(b_relative_positions_string)))

    b_rotated_90: Object.Object = GeometryRuntime.relatively_rotate_object_90(
        b)
    b_rotated_180: Object.Object = GeometryRuntime.relatively_rotate_object_180(
        b)
    b_rotated_270: Object.Object = GeometryRuntime.relatively_rotate_object_270(
        b)

    relative_positions_are_the_same_after_some_rotation = (
        a_relative_positions == b_relative_positions
        or a_relative_positions == set(b_rotated_90.relative_positions)
        or a_relative_positions == set(b_rotated_180.relative_positions)
        or a_relative_positions == set(b_rotated_270.relative_positions))
    return relative_positions_are_the_same_after_some_rotation
示例#3
0
    def test_getting_object_size(self):
        obj_a = Object(1, (0, 0), [
            (0, 0),
            (1, 0),
            (2, 0),
            (3, 0),
            (3, 1),
            (3, 2),
            (2, 2),
            (1, 2),
            (0, 2),
            (0, 1),
        ])
        self.assertEqual(10, ObjectRuntime.get_size(obj_a))

        obj_b = Object(8, (7, 3), [
            (10, 12),
        ])
        self.assertEqual(1, ObjectRuntime.get_size(obj_b))

        obj_c = Object(1, (2, 9), [
            (0, 0),
            (1, 0),
            (1, 1),
            (2, 2),
            (3, 3),
            (4, 4),
        ])
        self.assertEqual(6, ObjectRuntime.get_size(obj_c))
示例#4
0
    def test_making_frame_model_from_objects_with_non_enclosing_top_left_offsets(
            self):
        obj_a = Object(2, (0, 0), [(0, 0)])

        relative_positions = [
            (0, 0),
            (1, 0),
            (2, 0),
            (3, 0),
            (3, 1),
            (3, 2),
            (2, 2),
            (1, 2),
            (0, 2),
            (0, 1),
        ]
        obj_b = Object(1, (2, 2), relative_positions)
        frame_model = ObjectRuntime.make_frame_model_from_objects(
            [obj_a, obj_b], 0)
        self.assertEqual(5, frame_model.number_of_rows)
        self.assertEqual(6, frame_model.number_of_columns)

        self.assertEqual(0, frame_model.background_colour)

        self.assertSequenceEqual([
            [2, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1],
            [0, 0, 1, 0, 0, 1],
            [0, 0, 1, 1, 1, 1],
        ],
                                 frame_model.to_grid().grid_array)
示例#5
0
    def test_making_frame_model_from_one_object_inside_another(self):
        obj_a = Object(
            7,
            (1, 1),
            [
                (0, 0),
                (1, 0),
                (2, 0),
                (2, 1),
                (2, 2),
                (1, 2),
                (0, 2),
                (0, 1),
            ],
        )

        obj_b = Object(
            5,
            (2, 2),
            [(0, 0)],
        )

        frame_model = ObjectRuntime.make_frame_model_from_objects(
            [obj_a, obj_b], 0)
        self.assertEqual(3, frame_model.number_of_rows)
        self.assertEqual(3, frame_model.number_of_columns)

        self.assertEqual(0, frame_model.background_colour)

        self.assertSequenceEqual([
            [7, 7, 7],
            [7, 5, 7],
            [7, 7, 7],
        ],
                                 frame_model.to_grid().grid_array)
示例#6
0
    def test_converting_from_relative_to_absolute_positions(self):
        relative_positions = [(-1, 0), (0, -1), (0, 0), (0, 1), (1, 1), (1, 2)]

        obj = Object(1, (1, 1), relative_positions)

        self.assertEqual([
            (0, 1),
            (1, 0),
            (1, 1),
            (1, 2),
            (2, 2),
            (2, 3),
        ], obj.convert_to_absolute_positions())
示例#7
0
    def test_making_frame_model_from_one_object(self):
        obj = Object(
            7,
            (1, 1),
            [
                (0, 0),
                (1, 0),
                (0, 1),
                (1, 1),
                (1, 2),
            ],
        )

        frame_model = ObjectRuntime.make_frame_model_from_objects([obj], 0)
        self.assertEqual(3, frame_model.number_of_rows)
        self.assertEqual(2, frame_model.number_of_columns)

        self.assertEqual(0, frame_model.background_colour)

        self.assertSequenceEqual([
            [7, 7],
            [7, 7],
            [0, 7],
        ],
                                 frame_model.to_grid().grid_array)
示例#8
0
    def test_grouping_one_object(self):
        obj = Object(1, (1, 0), [
            (0, 0),
            (1, 0),
        ], 0)
        frame_model = FrameModel(3, 3, 0, [obj])
        expected_grouped_objects: Dict[ObjectKind, List[ObjectId]] = {
            obj.get_object_kind(): [obj.id]
        }
        expected_object_group = expected_grouped_objects[obj.get_object_kind()]

        actual_grouped_objects = frame_model.group_same_objects()
        actual_object_group = actual_grouped_objects[obj.get_object_kind()]
        self.assertEqual(1, len(list(actual_grouped_objects.keys())))
        self.assertEqual(1, len(actual_object_group))

        self.assertEqual(list(expected_grouped_objects.keys()),
                         list(actual_grouped_objects.keys()))
        self.assertEqual(expected_object_group, actual_object_group)
示例#9
0
    def test_what_points_object_contains_when_its_not_enclosed(self):
        obj_a = Object(1, (1, 1), [
            (0, 0),
            (1, 0),
            (2, 0),
            (3, 0),
            (3, 2),
            (2, 2),
            (1, 2),
            (0, 2),
            (0, 1),
        ])
        obj_b = Object(2, (5, 5), [(0, 0)])

        frame_model = ObjectRuntime.make_frame_model_from_objects(
            [obj_a, obj_b], 0, False)
        points_contained_by_b = GeometryRuntime.points_contained_by_object(
            obj_a, frame_model)
        self.assertEqual(0, len(points_contained_by_b))
示例#10
0
文件: Grid.py 项目: nd9600/arc
    def parse_objects(self) -> List[Object]:
        objects = []
        '''
        Grid are
            * complete
            * connected
            * solid bodies
            * each square of the object has the same colour, despite noise or occlusion
        
        we loop over every square in the grid, and if it's not black:
            this will be the start of a new object - it can't be part of an existing object, we'd have processed it already
            if we've already seen it (see below), ignore it
            add it to a queue of positions we need to process for this object,
                record that we've seen it,
                add it to a list of positions that this object has
                find all the neighbouring squares that have the same colour, and for each one
                    if we've seen it already, ignore it
                    add to the "needs processing" queue
                make a new object that that has all of the above-processed position in it, and add that object to the grid's list
        '''
        seen_positions: Set[AbsolutePosition] = set()
        for y, row in enumerate(self.grid_array):
            for x, squareColour in enumerate(row):
                current_position = (x, y)
                if (squareColour ==
                        0  # todo: assumes background is always black
                        or current_position in seen_positions):
                    continue

                positions_for_this_object = []
                object_position_queue: Deque[AbsolutePosition] = deque()
                object_position_queue.append(current_position)
                while len(object_position_queue) > 0:
                    current_position = object_position_queue.pop()
                    positions_for_this_object.append(current_position)
                    seen_positions.add(current_position)

                    new_x = current_position[0]
                    new_y = current_position[1]
                    neighbourhood = self.get_neighbourhood(new_x, new_y)
                    neighbouring_squares_with_the_same_colour = list(
                        filter(
                            lambda pos: self.get_colour(pos[0], pos[1]) ==
                            squareColour, neighbourhood))
                    for position in neighbouring_squares_with_the_same_colour:
                        if position not in seen_positions:
                            object_position_queue.append(position)
                            seen_positions.add(position)

                unseen_object = Object.create_with_absolute_positions(
                    squareColour, positions_for_this_object)
                objects.append(unseen_object)

        return objects
示例#11
0
 def test_rotating_line_90_degrees(self):
     obj = Object(1, (1, 0), [
         (0, 0),
         (1, 0),
         (2, 0),
     ])
     rotated_obj: Object = GeometryRuntime.relatively_rotate_object_90(obj)
     self.assertEqual([
         (0, 0),
         (0, 1),
         (0, 2),
     ], rotated_obj.relative_positions)
示例#12
0
    def test_grouping_two_objects(self):
        obj_a = Object(1, (1, 0), [
            (0, 0),
            (1, 0),
        ], 0)
        obj_b = Object(1, (0, 4), [
            (0, 0),
            (1, 0),
        ], 1)
        frame_model = FrameModel(4, 3, 0, [
            obj_a,
            obj_b,
        ])
        expected_grouped_objects: Dict[ObjectKind, List[ObjectId]] = {
            obj_a.get_object_kind(): [obj_a.id, obj_b.id]
        }
        expected_object_group = expected_grouped_objects[
            obj_a.get_object_kind()]

        actual_grouped_objects = frame_model.group_same_objects()
        actual_object_group = actual_grouped_objects[obj_a.get_object_kind()]

        self.assertEqual(1, len(list(actual_grouped_objects.keys())))
        self.assertEqual(2, len(actual_object_group))

        self.assertEqual(list(expected_grouped_objects.keys()),
                         list(actual_grouped_objects.keys()))
        self.assertEqual(expected_object_group, actual_object_group)
 def test_making_grid_from_frame_model_with_an_occluded_object(self):
     frame_model = FrameModel(
         3, 3, 0, {
             1: Object(1, (0, 0), [
                 (0, 0),
                 (1, 0),
                 (0, 1),
                 (1, 1),
             ], 0),
             2: Object(2, (1, 1), [
                 (0, 0),
                 (1, 0),
                 (0, 1),
                 (1, 1),
             ], -1)
         }, [])
     grid = frame_model.to_grid()
     self.assertSequenceEqual([
         [1, 1, 0],
         [1, 1, 2],
         [0, 2, 2],
     ], grid.grid_array)
示例#14
0
    def test_rotating_l_shape_360_degrees_doesnt_move_it_at_all(self):
        obj = Object(1, (1, 0), [
            (0, 0),
            (1, 0),
            (2, 0),
            (2, 1),
        ])

        rotated_obj: Object = GeometryRuntime.relatively_rotate_object(
            360, obj)
        self.assertEqual(obj.top_left_offset, rotated_obj.top_left_offset)
        self.assertEqual(obj.relative_positions,
                         rotated_obj.relative_positions)
示例#15
0
    def test_relatively_rotating_l_shape_270_degrees_when_it_wouldnt_go_off_top_of_grid(
            self):
        obj = Object(1, (5, 5), [
            (0, 0),
            (1, 0),
            (2, 0),
            (2, 1),
        ])

        rotated_obj: Object = GeometryRuntime.relatively_rotate_object_270(obj)
        self.assertEqual((5, 3), rotated_obj.top_left_offset)
        self.assertEqual([(0, 2), (0, 1), (0, 0), (1, 0)],
                         rotated_obj.relative_positions)
示例#16
0
    def test_what_points_object_contains_when_theres_another_object_in_the_way(
            self):
        obj_a = Object(1, (1, 1), [
            (0, 0),
            (1, 0),
            (2, 0),
            (3, 0),
            (3, 2),
            (3, 3),
            (2, 2),
            (1, 2),
            (0, 2),
            (0, 1),
        ])
        obj_b = Object(2, (5, 5), [(0, 0)])
        obj_c = Object(3, (4, 2), [(0, 0)])

        frame_model = ObjectRuntime.make_frame_model_from_objects(
            [obj_a, obj_b, obj_c], 0, False)
        points_contained_by_b = GeometryRuntime.points_contained_by_object(
            obj_a, frame_model)
        self.assertEqual(0, len(points_contained_by_b))
示例#17
0
 def test_relatively_rotating_l_shape_270_degrees(self):
     obj = Object(1, (1, 0), [
         (0, 0),
         (1, 0),
         (2, 0),
         (2, 1),
     ])
     rotated_obj: Object = UsefulFunctions.compose([
         GeometryRuntime.relatively_rotate_object_270,
     ])(obj)
     self.assertEqual((1, 0), rotated_obj.top_left_offset)
     self.assertEqual([(0, 2), (0, 1), (0, 0), (1, 0)],
                      rotated_obj.relative_positions)
示例#18
0
    def test_getting_the_biggest_object(self):
        obj_a = Object(1, (0, 0), [
            (0, 0),
            (1, 1),
            (2, 2),
        ])
        obj_b = Object(2, (0, 1), [
            (0, 0),
            (1, 1),
            (2, 2),
            (3, 3),
        ])
        obj_c = Object(3, (0, 2), [
            (0, 0),
            (1, 1),
        ])

        frame_model = ObjectRuntime.make_frame_model_from_objects(
            [obj_a, obj_b, obj_c], 0)

        # get list of objects
        # find id of biggest object
        #
        biggest_object = ListRuntime.map_list(
            lambda obj: (obj.id, ObjectRuntime.get_size(obj)),
            frame_model.objects_as_list())
        print("\n")
        print(biggest_object)

        new_frame_model = FrameModelRuntime.change_objects(
            frame_model,
            ListRuntime.filter_list(lambda obj: obj == biggest_object,
                                    frame_model.objects_as_list()))
        new_frame_model.to_grid().plot()
        self.assertEqual(1, len(list(new_frame_model.objects.values())))
        self.assertEqual(obj_b, list(new_frame_model.objects.values())[0])
示例#19
0
    def test_is_point_enclosed_in_rectangle(self):
        obj_a = Object(2, (0, 0), [(0, 0)])

        relative_positions = [
            (0, 0),
            (1, 0),
            (2, 0),
            (3, 0),
            (3, 1),
            (3, 2),
            (2, 2),
            (1, 2),
            (0, 2),
            (0, 1),
        ]
        obj_b = Object(1, (2, 2), relative_positions)
        frame_model = ObjectRuntime.make_frame_model_from_objects(
            [obj_a, obj_b], 0)

        self.assertFalse(
            GeometryRuntime.is_point_fully_enclosed((0, 0), frame_model))
        for pos in obj_b.convert_to_absolute_positions():
            self.assertFalse(
                GeometryRuntime.is_point_fully_enclosed(pos, frame_model))

        self.assertFalse(
            GeometryRuntime.is_point_fully_enclosed((1, 0), frame_model))
        self.assertFalse(
            GeometryRuntime.is_point_fully_enclosed((1, 1), frame_model))
        self.assertFalse(
            GeometryRuntime.is_point_fully_enclosed((0, 1), frame_model))

        self.assertTrue(
            GeometryRuntime.is_point_fully_enclosed((3, 3), frame_model))
        self.assertTrue(
            GeometryRuntime.is_point_fully_enclosed((4, 3), frame_model))
示例#20
0
 def test_rotating_l_shape_90_degrees_when_it_wouldnt_go_off_grid(self):
     obj = Object(1, (9, 3), [
         (0, 0),
         (1, 0),
         (2, 0),
         (2, 1),
     ])
     rotated_obj: Object = UsefulFunctions.compose(
         [GeometryRuntime.relatively_rotate_object_90])(obj)
     # the top left offset had to be shifted to accommodate the L being 2 squares wide
     self.assertEqual((8, 3), rotated_obj.top_left_offset)
     self.assertEqual([
         (1, 0),
         (1, 1),
         (1, 2),
         (0, 2),
     ], rotated_obj.relative_positions)
示例#21
0
    def test_making_object_with_absolute_positions(self):
        absolute_positions = [
            (1, 0),
            (1, 1),
            (1, 2),
            (2, 2),
            (2, 3),
        ]
        o = Object.create_with_absolute_positions(1, absolute_positions, 0)
        self.assertEqual((1, 0), o.top_left_offset)

        self.assertEqual([
            (0, 0),
            (0, 1),
            (0, 2),
            (1, 2),
            (1, 3),
        ], o.relative_positions)
示例#22
0
    def test_rotating_l_shape_90_degrees_4_times_doesnt_change_its_relative_positions(
            self):
        """
        rotating an object can make it go off the grid; to prevent that, we snap it back onto the grid
        :return:
        """
        obj = Object(1, (1, 0), [
            (0, 0),
            (1, 0),
            (2, 0),
            (2, 1),
        ])

        rotated_obj = UsefulFunctions.compose([
            GeometryRuntime.relatively_rotate_object_90,
            GeometryRuntime.relatively_rotate_object_90,
            GeometryRuntime.relatively_rotate_object_90,
            GeometryRuntime.relatively_rotate_object_90
        ])(obj)
        self.assertEqual(obj.relative_positions,
                         rotated_obj.relative_positions)
示例#23
0
    def test_is_point_enclosed_in_cropped_rectangle(self):
        relative_positions = [
            (0, 0),
            (1, 0),
            (2, 0),
            (3, 0),
            (3, 1),
            (3, 2),
            (2, 2),
            (1, 2),
            (0, 2),
            (0, 1),
        ]
        obj = Object(1, (0, 0), relative_positions)
        frame_model = ObjectRuntime.make_frame_model_from_objects([obj], 0)

        for pos in relative_positions:
            self.assertFalse(
                GeometryRuntime.is_point_fully_enclosed(pos, frame_model))
        self.assertTrue(
            GeometryRuntime.is_point_fully_enclosed((1, 1), frame_model))
        self.assertTrue(
            GeometryRuntime.is_point_fully_enclosed((2, 1), frame_model))
示例#24
0
    def test_grouping_two_objects_where_one_is_rotated_270_degrees(self):
        g = [
            [0, 1, 1, 1],
            [0, 0, 0, 1],
            [0, 1, 0, 0],
            [0, 1, 0, 0],
            [1, 1, 0, 0],
        ]
        obj_a = Object(1, (1, 0), [
            (0, 0),
            (1, 0),
            (2, 0),
            (2, 1),
        ], 0)
        obj_b = Object(1, (2, 3), [
            (1, 0),
            (1, 1),
            (1, 2),
            (0, 2),
        ], 1)
        frame_model = FrameModel(5, 4, 0, [
            obj_a,
            obj_b,
        ])
        expected_grouped_objects: Dict[ObjectKind, List[ObjectId]] = {
            obj_a.get_object_kind(): [obj_a.id, obj_b.id]
        }
        expected_object_group = expected_grouped_objects[
            obj_a.get_object_kind()]

        actual_grouped_objects = frame_model.group_same_objects()
        actual_object_group = actual_grouped_objects[obj_a.get_object_kind()]

        self.assertEqual(1, len(list(actual_grouped_objects.keys())))
        self.assertEqual(2, len(actual_object_group))

        self.assertEqual(list(expected_grouped_objects.keys()),
                         list(actual_grouped_objects.keys()))
        self.assertEqual(expected_object_group, actual_object_group)
示例#25
0
    def test_matching_one_object_out_of_three_across_frames(self):
        obj_1 = Object(
            1,
            (1, 1),
            [
                (0, 0),
                (1, 0),
                (2, 0),
                (2, 1),
            ],
            0,
            1
        )
        obj_2 = Object(
            2,
            (1, 1),
            [
                (0, 0),
                (1, 0),
                (2, 0),
                (2, 1),
            ],
            0,
            2
        )
        obj_3 = Object(
            1,
            (1, 1),
            [
                (0, 0),
                (1, 0),
                (2, 0),
                (2, 2),
            ],
            0,
            3
        )

        obj_1b = Object(
            1,
            (1, 1),
            [
                (0, 0),
                (1, 0),
                (2, 0),
                (2, 1),
            ],
            0,
            4
        )
        obj_2b = Object(
            3,
            (1, 1),
            [
                (0, 0),
                (1, 0),
                (2, 0),
                (2, 1),
            ],
            0,
            5
        )
        obj_3b = Object(
            1,
            (1, 1),
            [
                (0, 1),
                (1, 0),
                (2, 0),
                (2, 1),
            ],
            0,
            6
        )

        original_frame_model = FrameModel(
            5,
            5,
            0,
            [
                obj_1,
                obj_2,
                obj_3,
            ]
        )
        second_frame_model = FrameModel(
            5,
            5,
            0,
            [
                obj_1b,
                obj_2b,
                obj_3b,
            ]
        )

        self.assertSequenceEqual(
            [
                4,
                5,
                6
            ],
            list(second_frame_model.objects.keys())
        )

        second_frame_model_after_match = ObjectRuntime.match_objects_in_second_frame_to_those_in_first(
            original_frame_model, second_frame_model
        )
        matched_second_object = second_frame_model_after_match.objects[obj_1.id]

        self.assertSequenceEqual(
            [
                1,
                5,
                6
            ],
            list(second_frame_model_after_match.objects.keys())
        )
        self.assertEqual(
            obj_1.colour,
            matched_second_object.colour,
        )
        self.assertEqual(
            obj_1.top_left_offset,
            matched_second_object.top_left_offset,
        )
        self.assertSequenceEqual(
            obj_1.relative_positions,
            matched_second_object.relative_positions,
        )
示例#26
0
def rotate_object_about_point(
        obj: Object.Object,
        angle: int,
        about_point: Tuple[int, int],
        is_relative_rotation: bool = True) -> Object.Object:
    def rotate(point: Tuple[int, int], radian_angle: float,
               origin: Tuple[int, int]):
        """
        Rotate a point counterclockwise by a given angle around a given origin.

        The angle should be given in radians.
        """
        ox, oy = origin
        px, py = point

        qx = ox + math.cos(radian_angle) * (
            px - ox) - math.sin(radian_angle) * (py - oy)
        qy = oy + math.sin(radian_angle) * (
            px - ox) + math.cos(radian_angle) * (py - oy)
        # we need to round them because we'd return stuff like (6.123233995736766e-17, 1.0) otherwise
        return round(qx), round(qy)

    angle_in_radians = (angle) * math.pi / 180

    if is_relative_rotation:
        rotated_relative_positions = list(
            map(lambda pos: rotate(pos, angle_in_radians, about_point),
                obj.relative_positions))

        # if any of the rotated_relative_positions contain a negative int,
        # we need to move the top left offset so that they're all >= 0, and recalculate all the relative positions
        min_x_offset = min(
            list(map(lambda pos: pos[0], rotated_relative_positions)))
        min_y_offset = min(
            list(map(lambda pos: pos[1], rotated_relative_positions)))
        top_left_offset_after_rotation = obj.top_left_offset
        if min_x_offset < 0:
            rotated_relative_positions = list(
                map(lambda pos: (pos[0] + abs(min_x_offset), pos[1]),
                    rotated_relative_positions))
            top_left_offset_after_rotation = (
                top_left_offset_after_rotation[0] + min_x_offset,
                top_left_offset_after_rotation[1])

        if min_y_offset < 0:
            rotated_relative_positions = list(
                map(lambda pos: (pos[0], pos[1] + abs(min_y_offset)),
                    rotated_relative_positions))
            top_left_offset_after_rotation = (
                top_left_offset_after_rotation[0],
                top_left_offset_after_rotation[1] + min_y_offset)

        top_left_offset_after_rotation = (max(
            top_left_offset_after_rotation[0],
            0), max(top_left_offset_after_rotation[1], 0))
        # todo: move the tl offset if (it + max obj offset) is > grid size, too

        return Object.Object(obj.colour, top_left_offset_after_rotation,
                             rotated_relative_positions, obj.depth)
    else:
        rotated_absolute_positions = list(
            map(lambda pos: rotate(pos, angle_in_radians, about_point),
                obj.convert_to_absolute_positions()))

        # if any of the rotated_absolute_positions contain a negative int,
        # we need to move them all so that they're all >= 0
        min_x_offset = min(
            list(map(lambda pos: pos[0], rotated_absolute_positions)))
        min_y_offset = min(
            list(map(lambda pos: pos[1], rotated_absolute_positions)))
        if min_x_offset < 0:
            rotated_absolute_positions = list(
                map(lambda pos: (pos[0] + abs(min_x_offset), pos[1]),
                    rotated_absolute_positions))

        if min_y_offset < 0:
            rotated_absolute_positions = list(
                map(lambda pos: (pos[0], pos[1] + abs(min_y_offset)),
                    rotated_absolute_positions))

        return Object.Object.create_with_absolute_positions(
            obj.colour, rotated_absolute_positions, obj.depth)
示例#27
0
def points_contained_by_object(
    obj: Object.Object, frame_model: "src.FrameModel.FrameModel.FrameModel"
) -> List[AbsolutePosition]:
    obj_min_x = obj.top_left_offset[0] + min(
        list(map(lambda pos: pos[0], obj.relative_positions)))
    obj_max_x = obj.top_left_offset[0] + max(
        list(map(lambda pos: pos[0], obj.relative_positions)))

    obj_min_y = obj.top_left_offset[0] + min(
        list(map(lambda pos: pos[1], obj.relative_positions)))
    obj_max_y = obj.top_left_offset[0] + max(
        list(map(lambda pos: pos[1], obj.relative_positions)))

    grid = frame_model.to_grid()
    objs_positions = set(obj.convert_to_absolute_positions())
    contained_points = []

    seen_positions: Set[AbsolutePosition] = set()
    positions_that_have_neighbours_out_of_bounds: Set[AbsolutePosition] = set()
    """
    a point p is contained by an object o if it's not possible to go outside of o's min or max x or y using 
    neighbouring free squares or objects (this includes neighbours of neighbours, etc.) - the positions mustn't already
    be a part of object o 
    """
    for x in range(obj_min_x, obj_max_x + 1):
        for y in range(obj_min_y, obj_max_y + 1):
            if (
                    x, y
            ) in objs_positions:  # a part of the object definitely isn't contained _in_ the object
                continue

            possible_positions_that_could_have_out_of_bounds_neighbours: Deque[
                AbsolutePosition] = deque()
            possible_positions_that_could_have_out_of_bounds_neighbours.append(
                (x, y))
            neighbours_that_are_out_of_bounds = set()
            while (len(
                    possible_positions_that_could_have_out_of_bounds_neighbours
            )) > 0:
                possible_pos = possible_positions_that_could_have_out_of_bounds_neighbours.pop(
                )
                seen_positions.add(possible_pos)

                possible_x = possible_pos[0]
                possible_y = possible_pos[1]
                neighbourhood = grid.get_neighbourhood(possible_x, possible_y)
                neighbourhood_not_this_obj = list(
                    filter(lambda pos: (pos[0], pos[1]) not in objs_positions,
                           neighbourhood))

                for neighbour in neighbourhood_not_this_obj:
                    neighbour_x = neighbour[0]
                    neighbour_y = neighbour[1]
                    neighbour_is_outside_of_object_bounds = (
                        (neighbour_x < obj_min_x or neighbour_x > obj_max_x) or
                        (neighbour_y < obj_min_y or neighbour_y > obj_max_y))
                    neighbour_has_its_own_neighbours_out_of_bounds = neighbour in positions_that_have_neighbours_out_of_bounds
                    if neighbour_is_outside_of_object_bounds or neighbour_has_its_own_neighbours_out_of_bounds:
                        neighbours_that_are_out_of_bounds.add(neighbour)
                    elif neighbour not in seen_positions:
                        possible_positions_that_could_have_out_of_bounds_neighbours.append(
                            neighbour)

            if len(neighbours_that_are_out_of_bounds) == 0:
                contained_points.append((x, y))
            else:
                positions_that_have_neighbours_out_of_bounds.add((x, y))
    return contained_points