Box¶
Description¶
A Box
is a rectangular area defined by two coordinates:
the top-left corner of the rectangle: the min coord,
the bottom-right corner of the rectangle: the max coord.
The default size of a Box is (1, 1), so you can create a box by only specifying the top-let corner of the rectangle.
>>> from benker.box import Box
>>> Box(1, 2, 2, 3)
Box(min=Coord(x=1, y=2), max=Coord(x=2, y=3))
>>> Box(1, 2)
Box(min=Coord(x=1, y=2), max=Coord(x=1, y=2))
You can use two coordinates to define a box:
>>> from benker.coord import Coord
>>> Box(Coord(5, 6), Coord(7, 8))
Box(min=Coord(x=5, y=6), max=Coord(x=7, y=8))
>>> Box(Coord(5, 6))
Box(min=Coord(x=5, y=6), max=Coord(x=5, y=6))
You can specify the size of a box:
>>> from benker.size import Size
>>> Box(Coord(5, 6), Size(3, 2))
Box(min=Coord(x=5, y=6), max=Coord(x=7, y=7))
We use the Excel convention to represent a Box: columns are represented by letters, rows are represented by numbers.
>>> print(Box(Coord(2, 5)))
B5
>>> print(Box(Coord(2, 5), Size(3, 2)))
B5:D6
Properties¶
You can use the following properties to extract information from a box:
use min to get the top-left corner coordinates,
use max to get the bottom-right corner coordinates,
use width to get the width of the box (number of columns),
use height to get the height of the box (number of rows),
use size to get the size (width and height) of the box.
>>> b1 = Box(Coord(5, 6), Size(3, 2))
>>> b1.min
Coord(x=5, y=6)
>>> b1.max
Coord(x=7, y=7)
>>> b1.width
3
>>> b1.height
2
>>> b1.size
Size(width=3, height=2)
Warning
All properties are non-mutable:
>>> b1.width = 9
Traceback (most recent call last):
...
AttributeError: can't set attribute
Operations¶
Contains¶
You can check if a point, defined by its coordinates (tuple (x, y) or
Coord
instance), is contained in a box:
>>> top_left = Coord(5, 6)
>>> top_right = Coord(6, 6)
>>> bottom_left = Coord(5, 8)
>>> bottom_right = Coord(6, 8)
>>> b1 = Box(top_left, bottom_right)
>>> top_left in b1
True
>>> top_right in b1
True
>>> bottom_left in b1
True
>>> bottom_right in b1
True
>>> Coord(7, 6) in b1
False
>>> (5, 7) in b1
True
Warning
Even if a Size
object is a subtype of tuple
,
such an object cannot be “contained” in a Box
.
>>> b1 = Box(Coord(x=5, y=6), Coord(x=6, y=8))
>>> Size(5, 7) in b1
Traceback (most recent call last):
...
TypeError: <class 'benker.size.Size'>
You can check if a Box
is contained in another box:
>>> b1 = Box(Coord(x=5, y=6), Coord(x=6, y=8))
>>> b2 = Box(Coord(x=5, y=7), Coord(x=6, y=7))
>>> b3 = Box(Coord(x=6, y=6), Coord(x=7, y=6))
>>> b1 in b1
True
>>> b2 in b1
True
>>> b3 in b2
False
Intersection and Union¶
You can find if a Box intersects another Box:
>>> b1 = Box(Coord(x=1, y=1), Coord(x=3, y=3))
>>> b2 = Box(Coord(x=2, y=2), Coord(x=4, y=4))
>>> b3 = Box(Coord(x=4, y=1), Coord(x=5, y=1))
>>> b1.intersect(b2)
True
>>> b1.intersect(b3)
False
Two boxes are disjoint if they don’t intersect each other:
>>> b1.isdisjoint(b2)
False
>>> b1.isdisjoint(b3)
True
You can calculate the intersection of two boxes. You can use the “&” operator to do that:
>>> b1.intersection(b2)
Box(min=Coord(x=2, y=2), max=Coord(x=3, y=3))
>>> b1 & b2
Box(min=Coord(x=2, y=2), max=Coord(x=3, y=3))
Warning
If the two boxes are disjoint, there is no intersection:
>>> b1 & b3
Traceback (most recent call last):
...
ValueError: (Box(min=Coord(x=1, y=1), max=Coord(x=3, y=3)), Box(min=Coord(x=4, y=1), max=Coord(x=5, y=1)))
You can calculate the union of two boxes. The union of two boxes is the bounding box: You can use the “|” operator to do that:
>>> b1.union(b2)
Box(min=Coord(x=1, y=1), max=Coord(x=4, y=4))
>>> b1 | b2
Box(min=Coord(x=1, y=1), max=Coord(x=4, y=4))
Total ordering¶
A total ordering is defined for the boxes. The aim is to order the cells in a grid sorted from left to right and from top to bottom. This order is useful to group the cells by rows.
You can compare boxes:
>>> b1 = Box(Coord(3, 2), Coord(6, 4))
>>> b1 < b1
False
>>> b1 < Box(Coord(3, 2), Coord(6, 5))
True
>>> b1 < Box(Coord(3, 2), Coord(7, 4))
True
>>> b1 < Box(Coord(4, 2), Coord(6, 4))
True
>>> b1 < Box(Coord(3, 3), Coord(6, 4))
True
You can sort boxes. The sort order can be defined as below:
top cells are sorted before bottom cells,
top-left cells are sorted before top-right cells,
smaller cells are sorted before bigger.
>>> from random import shuffle
>>> boxes = [Box(x, y) for x in range(1, 4) for y in range(1, 3)]
>>> [str(box) for box in boxes]
['A1', 'A2', 'B1', 'B2', 'C1', 'C2']
>>> shuffle(boxes)
>>> [str(box) for box in sorted(boxes)]
['A1', 'B1', 'C1', 'A2', 'B2', 'C2']