# source:trunk/anuga_core/source/anuga/geometry/aabb.py@7858

Last change on this file since 7858 was 7858, checked in by hudson, 12 years ago

Refactorings to increase code quality, fixed missing log import from sww_interrogate.

File size: 4.3 KB
Line
1"""
2    Axially aligned bounding box.
3    Contains a class describing a bounding box. It contains methods
4    to split itself and return child boxes.
5
6    As of June 2010 this module has a pylint quality rating of 10/10.
7"""
8
9# Allow children to be slightly bigger than their parents to prevent
11SPLIT_BORDER_RATIO    = 0.55
12
13class AABB:
14    """Axially-aligned bounding box class.
15       Defines a box which can check for intersections with other boxes,
16       or if a point lies within it.
17    """
18
19    def __init__(self, xmin, xmax=None, ymin=None, ymax=None):
20        """ Define axially-algned bounding box.
21            xmin is minimum x
22            xmax is maximum x (absolute coord, ie, not size)
23            ymin is minimum y
24            ymax is maximum y (absolute coord, ie, not size)
25        """
26        if not xmax:
27            # try treating first arg as a list of points
28            try:
29                xmin[0][0]
30            except:
31                raise Exception('Single parameter to AABB must be point list.')
32
33            self.xmin, self.ymin = self.xmax, self.ymax = xmin[0]
34            self.include(xmin[1:])
35        else:
36            self.xmin = xmin
37            self.xmax = xmax
38            self.ymin = ymin
39            self.ymax = ymax
40
41
42    def __repr__(self):
43        return 'AABB(xmin:%f, xmax:%f, ymin:%f, ymax:%f)' \
44               % (round(self.xmin,1), round(self.xmax,1), \
45                  round(self.ymin,1), round(self.ymax, 1))
46
47
48    def grow(self, amount):
49        """ Expand region by given amount.
50            amount is a multiplier, ie 1.1 will expand border by 10%.
51        """
52        self.ymax += (self.ymax-self.ymin)*amount
53        self.xmax += (self.xmax-self.xmin)*amount
54        self.ymin -= (self.ymax-self.ymin)*amount
55        self.xmin -= (self.xmax-self.xmin)*amount
56
57
58    def size(self):
59        """return size as (w,h)"""
60        return self.xmax - self.xmin, self.ymax - self.ymin
61
62
63    def split(self, border=SPLIT_BORDER_RATIO):
64        """Split box along shorter axis.
65           return 2 subdivided AABBs. This is useful for recursive
66           algorithms.
67
68           border is the overlap between the 2 regions - if set to 0.5
69                  it will subdivide them exactly, > 0.5 will create a
70                  shared overlapping area.
71        """
72
73        width, height = self.size()
74        assert width >= 0 and height >= 0
75
76        if (width > height):
77            # split vertically
78            split1 = self.xmin+width*border
79            split2 = self.xmax-width*border
80            return AABB(self.xmin, split1, self.ymin, self.ymax), \
81                   AABB(split2, self.xmax, self.ymin, self.ymax)
82        else:
83            # split horizontally
84            split1 = self.ymin+height*border
85            split2 = self.ymax-height*border
86            return AABB(self.xmin, self.xmax, self.ymin, split1), \
87                   AABB(self.xmin, self.xmax, split2, self.ymax)
88
89
90    def is_trivial_in(self, test):
91        """ Is trivial in.
92            test a box to test against the bounding box
93            return True if the test box falls fully within the
94                   bounding box without intersecting it.
95        """
96        if (test.xmin < self.xmin) or (test.xmax > self.xmax):
97            return False
98        if (test.ymin < self.ymin) or (test.ymax > self.ymax):
99            return False
100        return True
101
102    def contains(self, point):
103        """ is point within box
104            point is a test point
105            return True if the point is contained within the box.
106        """
107        return (self.xmin <= point[0] <= self.xmax) \
108                and (self.ymin <= point[1] <= self.ymax)
109
110    def include(self, point_list):
111        """ Include points in AABB.
112            Bounding box will be expanded to include passed points
113
114            point_list is a list of points.
115        """
116        for point in point_list:
117            pt_x, pt_y = point
118            if pt_x < self.xmin:
119                self.xmin = pt_x
120            if pt_x > self.xmax:
121                self.xmax = pt_x
122            if pt_y < self.ymin:
123                self.ymin = pt_y
124            if pt_y > self.ymax:
125                self.ymax = pt_y
Note: See TracBrowser for help on using the repository browser.