Group

class geometry.Group(shapes: List[Union[geometry.rect.Rect, geometry.path.Segment, Group]] = <factory>, bbox: Optional[geometry.rect.Rect] = None, user_data: Any = None)

Represents a collection of shapes or nested groups.

>>> Group()
{}
>>> Group([Rect[2, 4]])
{[-1:1, -2:2]} [-1:1, -2:2]
>>> Group([Rect[0:1, 0:1], Rect[9:10, 19:20]])
{[0:1, 0:1], [9:10, 19:20]} [0:10, 0:20]
>>> Group([Rect[0:3, 0:3], Rect[2, 2]])
{[0:3, 0:3], [-1:1, -1:1]} [-1:3, -1:3]

Warning

The group does not keep track of changes to the contained shapes. If you manually change shapes that are inside a group, you must update() the group.

classmethod path_from_points(thickness: Union[int, float], *points: geometry.point.Point, user_data: Any = None) → geometry.group.Group

Create a Path (Group of Segments) from a list of absolute points.

                 end
             +----O----+
             |    |    |
         +---+----|----|    ---
         |   |    |    |     |
start -> O--------O----+   thickness
         |   |    |    |     |
         +--------+----+    ---

O are the given points

>>> p = Group.path_from_points(2, Point(0, 0), Point(10, 0), Point(10, 10))
>>> p.shapes[0]
[0:11, -1:1] (right)
>>> p.shapes[1]
[9:11, -1:10] (up)

Duplicating consecutive points are skipped >>> Group.path_from_points(2, Point(0, 0), Point(5, 0), Point(5, 0), Point(5, 5)) {[0:6, -1:1] (right), [4:6, -1:5] (up)} …

classmethod path_from_vectors(thickness: Union[int, float], start: geometry.point.Point, *edges: geometry.point.Point, user_data: Any = None) → geometry.group.Group

Create a Path (Group of Segments) from a starting point and cumulative directions.

>>> from geometry import Direction
>>> right = Direction.right
>>> g = Group.path_from_vectors(2, Point(0, 0), right * 10, right * 20)
>>> g.shapes[0]
[0:11, -1:1] (right)
>>> g.shapes[1]
[9:30, -1:1] (right)
grid(x_steps: int, x_direction: str, y_steps: int, y_direction: str) → Generator[Tuple[int, int, geometry.group.Group], None, None]

Span a grid of copies of this group.

group.grid(5, ‘right’, 3, ‘down’) will create a grid of 5 times 3 copies

XOOOO
OOOOO
OOOOO

X is the initial group.

The generator yield a tuple of the column number, row number and the group copy.

>>> g = Group([Rect[2, 5]])
>>> [cell.center for x, y, cell in g.grid(3, 'right', 2, 'up')]
[(0, 0), (2, 0), (4, 0), (0, 5), (2, 5), (4, 5)]
append(shape: Union[geometry.rect.Rect, geometry.path.Segment, Group]) → None

Add one shape to the group. The bounding box will be updated.

>>> g = Group([Rect[0:2, 0:3]])
>>> g.bbox
[0:2, 0:3]
>>> g.append(Rect[10:12, 0:1])
>>> g.bbox
[0:12, 0:3]
property bottom

The bottom edge of the rect.

>>> from geometry import Rect
>>> r = Rect[1:2, 3:4]
>>> r.bottom
3.0

Assigning the edge translates the whole rect.

>>> r.bottom = 10
>>> r
[1:2, 10:11]
copy(user_data: Any = <object object>) → Self

Copy the rect or any other shape. You can specify the copy behaviour for the user data object.

The default is a shallow copy

>>> from geometry import Rect
>>> r = Rect[0:1, 0:1, ['my', 'user', 'data']]
>>> r.copy(Rect.shallow_copy)
[0:1, 0:1] ['my', 'user', 'data']

You can force a deep copy

>>> r = Rect[0:1, 0:1, [...]]
>>> r.copy(Rect.deep_copy)
[0:1, 0:1] [...]

You can pass the user data without copying

>>> r = Rect[0:1, 0:1, [...]]
>>> r.copy(Rect.keep)
[0:1, 0:1] [...]

And you can supply a completely new user data object

>>> r = Rect[0:1, 0:1, [...]]
>>> r.copy('completely new')
[0:1, 0:1] 'completely new'
extend(items: Iterable[Item]) → None

Append items from an iterable to the collection.

>>> container.extend([1, 2, 3])

This is equivalent to

>>> for item in [1, 2, 3]:
...     container.append(item)

E.g. Groups support these methods

>>> from geometry import Group, Rect
>>> g = Group()
>>> g.extend([Rect[2, 4], Rect[4, 2]])
>>> g
{[-1:1, -2:2], [-2:2, -1:1]} ...
extend_star(*items: Item) → None

Append items from var args

>>> container.extend_star(1, 2, 3)

This is equivalent to

>>> for item in [1, 2, 3]:
...     container.append(item)

E.g. Groups support these methods

>>> from geometry import Group, Rect
>>> g = Group()
>>> g.extend_star(Rect[2, 4], Rect[4, 2])
>>> g
{[-1:1, -2:2], [-2:2, -1:1]} ...
property height

The width of the bounding box

>>> Group([Rect[0:1, 0:2], Rect[9:10, 19:20]]).height
20.0
property left

The left edge of the rect.

>>> from geometry import Rect
>>> r = Rect[1:2, 3:4]
>>> r.left
1.0

Assigning the edge translates the whole rect.

>>> r.left = 10
>>> r
[10:11, 3:4]
property right

The right edge of the rect.

>>> from geometry import Rect
>>> r = Rect[1:2, 3:4]
>>> r.right
2.0

Assigning the edge translates the whole rect.

>>> r.right = 10
>>> r
[9:10, 3:4]
property top

The top edge of the rect.

>>> from geometry import Rect
>>> r = Rect[1:2, 3:4]
>>> r.top
4.0

Assigning the edge translates the whole rect.

>>> r.top = 10
>>> r
[1:2, 9:10]
translate(**absolute: Union[int, float, geometry.point.Point, geometry.handles.EdgeHandle, geometry.handles.PointHandle]) → geometry.translate.CanTranslate

Translates the whole shape.

>>> from geometry import Rect, right
>>> r = Rect[2, 4]
>>> r.translate(bottom_left=Point(0, 0))  # move the bottom left to the origin
[0:2, 0:4]
>>> r.translate(center=Point(0, 0))  # move the center to the origin
[-1:1, -2:2]
>>> r.translate(left=right)  # move by 2 (width) to the right
[1:3, -2:2]
>>> r.translate(left=right + 1)  # move by 3 (width + 1) to the right
[4:6, -2:2]
update() → None

Recalculate the bounding box for all contained shapes.

This is necessary when you manually change a shape after you added it to the group.

>>> r = Rect[2, 4]
>>> g = Group([r])
>>> r.bottom_left = Point(0, 0)
>>> r in g.bbox
False
>>> g.update()
>>> r in g.bbox
True
property width

The width of the bounding box

>>> Group([Rect[0:1, 0:2], Rect[9:10, 19:20]]).width
10.0
property x

The x coordinate of the center of the bounding box

>>> Group([Rect[0:1, 0:2], Rect[9:10, 19:20]]).x
5.0

Setting the x coordinate moves every shape in the group

>>> g = Group([Rect[2, 2]])
>>> g.x += 10
>>> g.shapes[0]
[9:11, -1:1]
property y

The y coordinate of the center of the bounding box

>>> Group([Rect[0:1, 0:2], Rect[9:10, 19:20]]).y
10.0

Setting the y coordinate moves every shape in the group

>>> g = Group([Rect[2, 2]])
>>> g.y += 10
>>> g.shapes[0]
[-1:1, 9:11]
flip(*, horizontally: bool = False, vertically: bool = False) → None

Mirror the shapes in this group at the center lines of this group.

Either horizontally or vertically or both.

Note: this actually modified the contained shapes. If you don’t want that behaviour, copy the group first: group.copy().flip(...)

E.g. a horizontal flip

+----+----+     +----+----+
|    |    |     |    |    |
+----+    |  => |    +----+
|    +----+     |----+    |
|    |    |     |    |    |
+----+----+     +----+----+
>>> top_left = Rect[0:1, 2:3]
>>> bottom_right = Rect[1:2, 0:1]
>>> g = Group([top_left, bottom_right])
>>> g.flip(horizontally=True)
>>> top_left  # is now top right
[1:2, 2:3]
>>> bottom_right  # is now bottom left
[0:1, 0:1]
>>> g.flip(vertically=True)
>>> top_left  # is now bottom right
[1:2, 0:1]
>>> bottom_right  # is now top left
[0:1, 2:3]