1 | # Allow children to be slightly bigger than their parents to prevent straddling of a boundary |
---|
2 | SPLIT_BORDER_RATIO = 0.55 |
---|
3 | |
---|
4 | class AABB: |
---|
5 | """Axially-aligned bounding box class. |
---|
6 | """ |
---|
7 | |
---|
8 | def __init__(self, xmin, xmax, ymin, ymax): |
---|
9 | """ Define axially-algned bounding box. |
---|
10 | xmin is minimum x |
---|
11 | xmax is maximum x (absolute coord, ie, not size) |
---|
12 | ymin is minimum y |
---|
13 | ymax is maximum y (absolute coord, ie, not size) |
---|
14 | """ |
---|
15 | self.xmin = xmin |
---|
16 | self.xmax = xmax |
---|
17 | self.ymin = ymin |
---|
18 | self.ymax = ymax |
---|
19 | |
---|
20 | |
---|
21 | def __repr__(self): |
---|
22 | return 'AABB(xmin:%f, xmax:%f, ymin:%f, ymax:%f)' \ |
---|
23 | % (round(self.xmin,1), round(self.xmax,1), round(self.ymin,1), round(self.ymax, 1)) |
---|
24 | |
---|
25 | |
---|
26 | def grow(self, amount): |
---|
27 | """ Expand region by given amount. |
---|
28 | amount is a multiplier, ie 1.1 will expand border by 10%. |
---|
29 | """ |
---|
30 | self.ymax += (self.ymax-self.ymin)*amount |
---|
31 | self.xmax += (self.xmax-self.xmin)*amount |
---|
32 | self.ymin -= (self.ymax-self.ymin)*amount |
---|
33 | self.xmin -= (self.xmax-self.xmin)*amount |
---|
34 | |
---|
35 | |
---|
36 | def size(self): |
---|
37 | """return size as (w,h)""" |
---|
38 | return self.xmax - self.xmin, self.ymax - self.ymin |
---|
39 | |
---|
40 | |
---|
41 | def split(self, border=SPLIT_BORDER_RATIO): |
---|
42 | """Split along shorter axis. |
---|
43 | return 2 subdivided AABBs. |
---|
44 | """ |
---|
45 | |
---|
46 | width, height = self.size() |
---|
47 | assert width >= 0 and height >= 0 |
---|
48 | |
---|
49 | if (width > height): |
---|
50 | # split vertically |
---|
51 | return AABB(self.xmin, self.xmin+width*border, self.ymin, self.ymax), \ |
---|
52 | AABB(self.xmax-width*border, self.xmax, self.ymin, self.ymax) |
---|
53 | else: |
---|
54 | # split horizontally |
---|
55 | return AABB(self.xmin, self.xmax, self.ymin, self.ymin+height*border), \ |
---|
56 | AABB(self.xmin, self.xmax, self.ymax-height*border, self.ymax) |
---|
57 | |
---|
58 | |
---|
59 | def is_trivial_in(self, test): |
---|
60 | """ Is trivial in. |
---|
61 | test an x,y point to test against the bounding box |
---|
62 | return True if the test point falls within the bounding box |
---|
63 | """ |
---|
64 | if (test.xmin < self.xmin) or (test.xmax > self.xmax): |
---|
65 | return False |
---|
66 | if (test.ymin < self.ymin) or (test.ymax > self.ymax): |
---|
67 | return False |
---|
68 | return True |
---|
69 | |
---|
70 | def contains(self, x): |
---|
71 | return (self.xmin <= x[0] <= self.xmax) and (self.ymin <= x[1] <= self.ymax) |
---|
72 | |
---|