move bbox handling to registry (not yet finished)
[PyX.git] / pyx / bbox.py
blob8167cfa5f75e5f18f8be44e0958dda88076db3c4
1 #!/usr/bin/env python
2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002-2005 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2002-2004 André Wobst <wobsta@users.sourceforge.net>
8 # This file is part of PyX (http://pyx.sourceforge.net/).
10 # PyX is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # PyX is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with PyX; if not, write to the Free Software
22 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 import math
25 import unit
28 # classes representing bounding boxes
31 class bbox_pt:
33 """class for bounding boxes
35 This variant requires points in the constructor, and is used for internal
36 purposes."""
38 def __init__(self, llx_pt, lly_pt, urx_pt, ury_pt):
39 self.llx_pt = llx_pt
40 self.lly_pt = lly_pt
41 self.urx_pt = urx_pt
42 self.ury_pt = ury_pt
44 def __add__(self, other):
45 """join two bboxes"""
46 return bbox_pt(min(self.llx_pt, other.llx_pt), min(self.lly_pt, other.lly_pt),
47 max(self.urx_pt, other.urx_pt), max(self.ury_pt, other.ury_pt))
49 def __iadd__(self, other):
50 """join two bboxes inplace"""
51 self.llx_pt = min(self.llx_pt, other.llx_pt)
52 self.lly_pt = min(self.lly_pt, other.lly_pt)
53 self.urx_pt = max(self.urx_pt, other.urx_pt)
54 self.ury_pt = max(self.ury_pt, other.ury_pt)
55 return self
57 def __mul__(self, other):
58 """return intersection of two bboxes"""
59 return bbox_pt(max(self.llx_pt, other.llx_pt), max(self.lly_pt, other.lly_pt),
60 min(self.urx_pt, other.urx_pt), min(self.ury_pt, other.ury_pt))
62 def __imul__(self, other):
63 """intersect two bboxes in place"""
64 self.llx_pt = max(self.llx_pt, other.llx_pt)
65 self.lly_pt = max(self.lly_pt, other.lly_pt)
66 self.urx_pt = min(self.urx_pt, other.urx_pt)
67 self.ury_pt = min(self.ury_pt, other.ury_pt)
68 return self
70 def copy(self):
71 return bbox_pt(self.llx_pt, self.lly_pt, self.urx_pt, self.ury_pt)
73 def lowrestuple_pt(self):
74 return (math.floor(self.llx_pt), math.floor(self.lly_pt),
75 math.ceil(self.urx_pt), math.ceil(self.ury_pt))
77 def highrestuple_pt(self):
78 return (self.llx_pt, self.lly_pt, self.urx_pt, self.ury_pt)
80 def intersects(self, other):
81 """check, if two bboxes intersect eachother"""
82 return not (self.llx_pt > other.urx_pt or
83 self.lly_pt > other.ury_pt or
84 self.urx_pt < other.llx_pt or
85 self.ury_pt < other.lly_pt)
87 def includepoint_pt(self, x_pt, y_pt):
88 self.llx_pt = min(self.llx_pt, x_pt)
89 self.lly_pt = min(self.lly_pt, y_pt)
90 self.urx_pt = max(self.urx_pt, x_pt)
91 self.ury_pt = max(self.ury_pt, y_pt)
93 def transform(self, trafo):
94 """transform bbox in place by trafo"""
95 # we have to transform all four corner points of the bbox
96 llx_pt, lly_pt = trafo.apply_pt(self.llx_pt, self.lly_pt)
97 lrx_pt, lry_pt = trafo.apply_pt(self.urx_pt, self.lly_pt)
98 urx_pt, ury_pt = trafo.apply_pt(self.urx_pt, self.ury_pt)
99 ulx_pt, uly_pt = trafo.apply_pt(self.llx_pt, self.ury_pt)
101 # Now, by sorting, we obtain the lower left and upper right corner
102 # of the new bounding box.
103 self.llx_pt = min(llx_pt, lrx_pt, urx_pt, ulx_pt)
104 self.lly_pt = min(lly_pt, lry_pt, ury_pt, uly_pt)
105 self.urx_pt = max(llx_pt, lrx_pt, urx_pt, ulx_pt)
106 self.ury_pt = max(lly_pt, lry_pt, ury_pt, uly_pt)
108 def transformed(self, trafo):
109 """return bbox transformed by trafo"""
110 # we have to transform all four corner points of the bbox
111 llx_pt, lly_pt = trafo.apply_pt(self.llx_pt, self.lly_pt)
112 lrx_pt, lry_pt = trafo.apply_pt(self.urx_pt, self.lly_pt)
113 urx_pt, ury_pt = trafo.apply_pt(self.urx_pt, self.ury_pt)
114 ulx_pt, uly_pt = trafo.apply_pt(self.llx_pt, self.ury_pt)
116 # Now, by sorting, we obtain the lower left and upper right corner
117 # of the new bounding box.
118 return bbox_pt(min(llx_pt, lrx_pt, urx_pt, ulx_pt), min(lly_pt, lry_pt, ury_pt, uly_pt),
119 max(llx_pt, lrx_pt, urx_pt, ulx_pt), max(lly_pt, lry_pt, ury_pt, uly_pt))
121 def enlarge_pt(self, all_pt=0, bottom_pt=None, left_pt=None, top_pt=None, right_pt=None):
122 """enlarge bbox in place by the given amounts in pts
124 all is used, if bottom, left, top and/or right are not given.
127 if bottom_pt is None:
128 bottom_pt = all_pt
129 if left_pt is None:
130 left_pt = all_pt
131 if top_pt is None:
132 top_pt = all_pt
133 if right_pt is None:
134 right_pt = all_pt
135 self.llx_pt -= left_pt
136 self.lly_pt -= bottom_pt
137 self.urx_pt += right_pt
138 self.ury_pt += top_pt
140 def enlarged_pt(self, all_pt=0, bottom_pt=None, left_pt=None, top_pt=None, right_pt=None):
141 """return bbox enlarged by the given amounts in pts
143 all is used, if bottom, left, top and/or right are not given.
146 if bottom_pt is None:
147 bottom_pt = all_pt
148 if left_pt is None:
149 left_pt = all_pt
150 if top_pt is None:
151 top_pt = all_pt
152 if right_pt is None:
153 right_pt = all_pt
154 return bbox_pt(self.llx_pt-left_pt, self.lly_pt-bottom_pt, self.urx_pt+right_pt, self.ury_pt+top_pt)
156 def enlarge(self, all=0, bottom=None, left=None, top=None, right=None):
157 """enlarge bbox in place
159 all is used, if bottom, left, top and/or right are not given.
162 bottom_pt = left_pt = top_pt = right_pt = unit.topt(all)
163 if bottom is not None:
164 bottom_pt = unit.topt(bottom)
165 if left is not None:
166 left_pt = unit.topt(left)
167 if top is not None:
168 top_pt = unit.topt(top)
169 if right is not None:
170 right_pt = unit.topt(right)
171 self.llx_pt -= left_pt
172 self.lly_pt -= bottom_pt
173 self.urx_pt += right_pt
174 self.ury_pt += top_pt
176 def enlarged(self, all=0, bottom=None, left=None, top=None, right=None):
177 """return bbox enlarged
179 all is used, if bottom, left, top and/or right are not given.
182 bottom_pt = left_pt = top_pt = right_pt = unit.topt(all)
183 if bottom is not None:
184 bottom_pt = unit.topt(bottom)
185 if left is not None:
186 left_pt = unit.topt(left)
187 if top is not None:
188 top_pt = unit.topt(top)
189 if right is not None:
190 right_pt = unit.topt(right)
191 return bbox_pt(self.llx_pt-left_pt, self.lly_pt-bottom_pt, self.urx_pt+right_pt, self.ury_pt+top_pt)
193 def rect(self):
194 """return rectangle corresponding to bbox"""
195 import path
196 return path.rect_pt(self.llx_pt, self.lly_pt, self.urx_pt-self.llx_pt, self.ury_pt-self.lly_pt)
198 path = rect
200 def height_pt(self):
201 """return height of bbox in pts"""
202 return self.ury_pt-self.lly_pt
204 def width_pt(self):
205 """return width of bbox in pts"""
206 return self.urx_pt-self.llx_pt
208 def top_pt(self):
209 """return top coordinate of bbox in pts"""
210 return self.ury_pt
212 def bottom_pt(self):
213 """return bottom coordinate of bbox in pts"""
214 return self.lly_pt
216 def left_pt(self):
217 """return left coordinate of bbox in pts"""
218 return self.llx_pt
220 def right_pt(self):
221 """return right coordinate of bbox in pts"""
222 return self.urx_pt
224 def center_pt(self):
225 """return coordinates of the center of the bbox in pts"""
226 return 0.5 * (self.llx_pt+self.urx_pt), 0.5 * (self.lly_pt+self.ury_pt)
228 def height(self):
229 """return height of bbox"""
230 return self.height_pt() * unit.t_pt
232 def width(self):
233 """return width of bbox"""
234 return self.width_pt() * unit.t_pt
236 def top(self):
237 """return top coordinate of bbox"""
238 return self.ury_pt * unit.t_pt
240 def bottom(self):
241 """return bottom coordinate of bbox"""
242 return self.lly_pt * unit.t_pt
244 def left(self):
245 """return left coordinate of bbox"""
246 return self.llx_pt * unit.t_pt
248 def right(self):
249 """return right coordinate of bbox"""
250 return self.urx_pt * unit.t_pt
252 def center(self):
253 """return coordinates of the center of the bbox"""
254 centerx_pt, centery_pt = self.center_pt()
255 return centerx_pt * unit.t_pt, centery_pt * unit.t_pt
258 class bbox(bbox_pt):
260 """class for bounding boxes"""
262 def __init__(self, llx_pt, lly_pt, urx_pt, ury_pt):
263 llx_pt = unit.topt(llx_pt)
264 lly_pt = unit.topt(lly_pt)
265 urx_pt = unit.topt(urx_pt)
266 ury_pt = unit.topt(ury_pt)
267 bbox_pt.__init__(self, llx_pt, lly_pt, urx_pt, ury_pt)