2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002-2006 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
28 # classes representing bounding boxes
33 """class for bounding boxes
35 This variant requires points in the constructor, and is used for internal
38 A bbox for which llx_pt is None represents an empty bbox, i.e., one containing
42 def __init__(self
, llx_pt
, lly_pt
, urx_pt
, ury_pt
):
48 def __add__(self
, other
):
50 if self
.llx_pt
is not None:
51 if other
.llx_pt
is not None:
52 return bbox_pt(min(self
.llx_pt
, other
.llx_pt
), min(self
.lly_pt
, other
.lly_pt
),
53 max(self
.urx_pt
, other
.urx_pt
), max(self
.ury_pt
, other
.ury_pt
))
55 return bbox_pt(self
.llx_pt
, self
.lly_pt
, self
.urx_pt
, self
.ury_pt
)
57 return bbox_pt(other
.llx_pt
, other
.lly_pt
, other
.urx_pt
, other
.ury_pt
)
59 def __iadd__(self
, other
):
60 """join two bboxes inplace"""
61 if self
.llx_pt
is not None:
62 if other
.llx_pt
is not None:
63 self
.llx_pt
= min(self
.llx_pt
, other
.llx_pt
)
64 self
.lly_pt
= min(self
.lly_pt
, other
.lly_pt
)
65 self
.urx_pt
= max(self
.urx_pt
, other
.urx_pt
)
66 self
.ury_pt
= max(self
.ury_pt
, other
.ury_pt
)
68 self
.llx_pt
= other
.llx_pt
69 self
.lly_pt
= other
.lly_pt
70 self
.urx_pt
= other
.urx_pt
71 self
.ury_pt
= other
.ury_pt
74 def __mul__(self
, other
):
75 """return intersection of two bboxes"""
76 if self
.llx_pt
is not None and other
.llx_pt
is not None:
77 return bbox_pt(max(self
.llx_pt
, other
.llx_pt
), max(self
.lly_pt
, other
.lly_pt
),
78 min(self
.urx_pt
, other
.urx_pt
), min(self
.ury_pt
, other
.ury_pt
))
82 def __imul__(self
, other
):
83 """intersect two bboxes in place"""
84 if self
.llx_pt
is not None and other
.llx_pt
is not None:
85 self
.llx_pt
= max(self
.llx_pt
, other
.llx_pt
)
86 self
.lly_pt
= max(self
.lly_pt
, other
.lly_pt
)
87 self
.urx_pt
= min(self
.urx_pt
, other
.urx_pt
)
88 self
.ury_pt
= min(self
.ury_pt
, other
.ury_pt
)
89 elif other
.llx_pt
is None:
94 return bbox_pt(self
.llx_pt
, self
.lly_pt
, self
.urx_pt
, self
.ury_pt
)
97 self
.llx_pt
= other
.llx_pt
98 self
.lly_pt
= other
.lly_pt
99 self
.urx_pt
= other
.urx_pt
100 self
.ury_pt
= other
.ury_pt
102 def lowrestuple_pt(self
):
103 if self
.llx_pt
is None:
104 raise ValueError("Cannot return low-res tuple for empty bbox")
105 return (math
.floor(self
.llx_pt
), math
.floor(self
.lly_pt
),
106 math
.ceil(self
.urx_pt
), math
.ceil(self
.ury_pt
))
108 def highrestuple_pt(self
):
109 if self
.llx_pt
is None:
110 raise ValueError("Cannot return high-res tuple for empty bbox")
111 return (self
.llx_pt
, self
.lly_pt
, self
.urx_pt
, self
.ury_pt
)
113 def intersects(self
, other
):
114 """check, if two bboxes intersect eachother"""
115 if self
.llx_pt
is None or other
.llx_pt
is None:
118 return not (self
.llx_pt
> other
.urx_pt
or
119 self
.lly_pt
> other
.ury_pt
or
120 self
.urx_pt
< other
.llx_pt
or
121 self
.ury_pt
< other
.lly_pt
)
123 def includepoint_pt(self
, x_pt
, y_pt
):
124 if self
.llx_pt
is None:
125 self
.llx_pt
= self
.urx_pt
= x_pt
126 self
.ury_pt
= self
.ury_pt
= y_pt
128 self
.llx_pt
= min(self
.llx_pt
, x_pt
)
129 self
.lly_pt
= min(self
.lly_pt
, y_pt
)
130 self
.urx_pt
= max(self
.urx_pt
, x_pt
)
131 self
.ury_pt
= max(self
.ury_pt
, y_pt
)
133 def transform(self
, trafo
):
134 """transform bbox in place by trafo"""
135 if self
.llx_pt
is None:
137 # we have to transform all four corner points of the bbox
138 llx_pt
, lly_pt
= trafo
.apply_pt(self
.llx_pt
, self
.lly_pt
)
139 lrx_pt
, lry_pt
= trafo
.apply_pt(self
.urx_pt
, self
.lly_pt
)
140 urx_pt
, ury_pt
= trafo
.apply_pt(self
.urx_pt
, self
.ury_pt
)
141 ulx_pt
, uly_pt
= trafo
.apply_pt(self
.llx_pt
, self
.ury_pt
)
143 # Now, by sorting, we obtain the lower left and upper right corner
144 # of the new bounding box.
145 self
.llx_pt
= min(llx_pt
, lrx_pt
, urx_pt
, ulx_pt
)
146 self
.lly_pt
= min(lly_pt
, lry_pt
, ury_pt
, uly_pt
)
147 self
.urx_pt
= max(llx_pt
, lrx_pt
, urx_pt
, ulx_pt
)
148 self
.ury_pt
= max(lly_pt
, lry_pt
, ury_pt
, uly_pt
)
150 def transformed(self
, trafo
):
151 """return bbox transformed by trafo"""
152 if self
.llx_pt
is None:
154 # we have to transform all four corner points of the bbox
155 llx_pt
, lly_pt
= trafo
.apply_pt(self
.llx_pt
, self
.lly_pt
)
156 lrx_pt
, lry_pt
= trafo
.apply_pt(self
.urx_pt
, self
.lly_pt
)
157 urx_pt
, ury_pt
= trafo
.apply_pt(self
.urx_pt
, self
.ury_pt
)
158 ulx_pt
, uly_pt
= trafo
.apply_pt(self
.llx_pt
, self
.ury_pt
)
160 # Now, by sorting, we obtain the lower left and upper right corner
161 # of the new bounding box.
162 return bbox_pt(min(llx_pt
, lrx_pt
, urx_pt
, ulx_pt
), min(lly_pt
, lry_pt
, ury_pt
, uly_pt
),
163 max(llx_pt
, lrx_pt
, urx_pt
, ulx_pt
), max(lly_pt
, lry_pt
, ury_pt
, uly_pt
))
165 def enlarge_pt(self
, all_pt
=0, bottom_pt
=None, left_pt
=None, top_pt
=None, right_pt
=None):
166 """enlarge bbox in place by the given amounts in pts
168 all is used, if bottom, left, top and/or right are not given.
171 if self
.llx_pt
is None:
173 if bottom_pt
is None:
181 self
.llx_pt
-= left_pt
182 self
.lly_pt
-= bottom_pt
183 self
.urx_pt
+= right_pt
184 self
.ury_pt
+= top_pt
186 def enlarged_pt(self
, all_pt
=0, bottom_pt
=None, left_pt
=None, top_pt
=None, right_pt
=None):
187 """return bbox enlarged by the given amounts in pts
189 all is used, if bottom, left, top and/or right are not given.
192 if self
.llx_pt
is None:
194 if bottom_pt
is None:
202 return bbox_pt(self
.llx_pt
-left_pt
, self
.lly_pt
-bottom_pt
, self
.urx_pt
+right_pt
, self
.ury_pt
+top_pt
)
204 def enlarge(self
, all
=0, bottom
=None, left
=None, top
=None, right
=None):
205 """enlarge bbox in place
207 all is used, if bottom, left, top and/or right are not given.
210 if self
.llx_pt
is None:
212 bottom_pt
= left_pt
= top_pt
= right_pt
= unit
.topt(all
)
213 if bottom
is not None:
214 bottom_pt
= unit
.topt(bottom
)
216 left_pt
= unit
.topt(left
)
218 top_pt
= unit
.topt(top
)
219 if right
is not None:
220 right_pt
= unit
.topt(right
)
221 self
.llx_pt
-= left_pt
222 self
.lly_pt
-= bottom_pt
223 self
.urx_pt
+= right_pt
224 self
.ury_pt
+= top_pt
226 def enlarged(self
, all
=0, bottom
=None, left
=None, top
=None, right
=None):
227 """return bbox enlarged
229 all is used, if bottom, left, top and/or right are not given.
232 if self
.llx_pt
is None:
234 bottom_pt
= left_pt
= top_pt
= right_pt
= unit
.topt(all
)
235 if bottom
is not None:
236 bottom_pt
= unit
.topt(bottom
)
238 left_pt
= unit
.topt(left
)
240 top_pt
= unit
.topt(top
)
241 if right
is not None:
242 right_pt
= unit
.topt(right
)
243 return bbox_pt(self
.llx_pt
-left_pt
, self
.lly_pt
-bottom_pt
, self
.urx_pt
+right_pt
, self
.ury_pt
+top_pt
)
246 """return rectangle corresponding to bbox"""
247 if self
.llx_pt
is None:
248 raise ValueError("Cannot return path for empty bbox")
250 return path
.rect_pt(self
.llx_pt
, self
.lly_pt
, self
.urx_pt
-self
.llx_pt
, self
.ury_pt
-self
.lly_pt
)
255 """return height of bbox in pts"""
256 if self
.llx_pt
is None:
257 raise ValueError("Cannot return heigth of empty bbox")
258 return self
.ury_pt
-self
.lly_pt
261 """return width of bbox in pts"""
262 if self
.llx_pt
is None:
263 raise ValueError("Cannot return width of empty bbox")
264 return self
.urx_pt
-self
.llx_pt
267 """return top coordinate of bbox in pts"""
268 if self
.llx_pt
is None:
269 raise ValueError("Cannot return top coordinate of empty bbox")
273 """return bottom coordinate of bbox in pts"""
274 if self
.llx_pt
is None:
275 raise ValueError("Cannot return bottom coordinate of empty bbox")
279 """return left coordinate of bbox in pts"""
280 if self
.llx_pt
is None:
281 raise ValueError("Cannot return left coordinate of empty bbox")
285 """return right coordinate of bbox in pts"""
286 if self
.llx_pt
is None:
287 raise ValueError("Cannot return right coordinate of empty bbox")
291 """return coordinates of the center of the bbox in pts"""
292 if self
.llx_pt
is None:
293 raise ValueError("Cannot return center coordinates of empty bbox")
294 return 0.5 * (self
.llx_pt
+self
.urx_pt
), 0.5 * (self
.lly_pt
+self
.ury_pt
)
297 """return height of bbox"""
298 return self
.height_pt() * unit
.t_pt
301 """return width of bbox"""
302 return self
.width_pt() * unit
.t_pt
305 """return top coordinate of bbox"""
306 return self
.ury_pt
* unit
.t_pt
309 """return bottom coordinate of bbox"""
310 return self
.lly_pt
* unit
.t_pt
313 """return left coordinate of bbox"""
314 return self
.llx_pt
* unit
.t_pt
317 """return right coordinate of bbox"""
318 return self
.urx_pt
* unit
.t_pt
321 """return coordinates of the center of the bbox"""
322 centerx_pt
, centery_pt
= self
.center_pt()
323 return centerx_pt
* unit
.t_pt
, centery_pt
* unit
.t_pt
328 """class for bounding boxes"""
330 def __init__(self
, llx_pt
, lly_pt
, urx_pt
, ury_pt
):
331 llx_pt
= unit
.topt(llx_pt
)
332 lly_pt
= unit
.topt(lly_pt
)
333 urx_pt
= unit
.topt(urx_pt
)
334 ury_pt
= unit
.topt(ury_pt
)
335 bbox_pt
.__init
__(self
, llx_pt
, lly_pt
, urx_pt
, ury_pt
)
338 class empty(bbox_pt
):
340 """empty bounding box, i.e., one containing no point"""
342 bbox_pt
.__init
__(self
, None, None, None, None)