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
)
96 def lowrestuple_pt(self
):
97 if self
.llx_pt
is None:
98 raise ValueError("Cannot return low-res tuple for empty bbox")
99 return (math
.floor(self
.llx_pt
), math
.floor(self
.lly_pt
),
100 math
.ceil(self
.urx_pt
), math
.ceil(self
.ury_pt
))
102 def highrestuple_pt(self
):
103 if self
.llx_pt
is None:
104 raise ValueError("Cannot return high-res tuple for empty bbox")
105 return (self
.llx_pt
, self
.lly_pt
, self
.urx_pt
, self
.ury_pt
)
107 def intersects(self
, other
):
108 """check, if two bboxes intersect eachother"""
109 if self
.llx_pt
is None or other
.llx_pt
is None:
112 return not (self
.llx_pt
> other
.urx_pt
or
113 self
.lly_pt
> other
.ury_pt
or
114 self
.urx_pt
< other
.llx_pt
or
115 self
.ury_pt
< other
.lly_pt
)
117 def includepoint_pt(self
, x_pt
, y_pt
):
118 if self
.llx_pt
is None:
119 self
.llx_pt
= self
.urx_pt
= x_pt
120 self
.ury_pt
= self
.ury_pt
= y_pt
122 self
.llx_pt
= min(self
.llx_pt
, x_pt
)
123 self
.lly_pt
= min(self
.lly_pt
, y_pt
)
124 self
.urx_pt
= max(self
.urx_pt
, x_pt
)
125 self
.ury_pt
= max(self
.ury_pt
, y_pt
)
127 def transform(self
, trafo
):
128 """transform bbox in place by trafo"""
129 if self
.llx_pt
is None:
131 # we have to transform all four corner points of the bbox
132 llx_pt
, lly_pt
= trafo
.apply_pt(self
.llx_pt
, self
.lly_pt
)
133 lrx_pt
, lry_pt
= trafo
.apply_pt(self
.urx_pt
, self
.lly_pt
)
134 urx_pt
, ury_pt
= trafo
.apply_pt(self
.urx_pt
, self
.ury_pt
)
135 ulx_pt
, uly_pt
= trafo
.apply_pt(self
.llx_pt
, self
.ury_pt
)
137 # Now, by sorting, we obtain the lower left and upper right corner
138 # of the new bounding box.
139 self
.llx_pt
= min(llx_pt
, lrx_pt
, urx_pt
, ulx_pt
)
140 self
.lly_pt
= min(lly_pt
, lry_pt
, ury_pt
, uly_pt
)
141 self
.urx_pt
= max(llx_pt
, lrx_pt
, urx_pt
, ulx_pt
)
142 self
.ury_pt
= max(lly_pt
, lry_pt
, ury_pt
, uly_pt
)
144 def transformed(self
, trafo
):
145 """return bbox transformed by trafo"""
146 if self
.llx_pt
is None:
148 # we have to transform all four corner points of the bbox
149 llx_pt
, lly_pt
= trafo
.apply_pt(self
.llx_pt
, self
.lly_pt
)
150 lrx_pt
, lry_pt
= trafo
.apply_pt(self
.urx_pt
, self
.lly_pt
)
151 urx_pt
, ury_pt
= trafo
.apply_pt(self
.urx_pt
, self
.ury_pt
)
152 ulx_pt
, uly_pt
= trafo
.apply_pt(self
.llx_pt
, self
.ury_pt
)
154 # Now, by sorting, we obtain the lower left and upper right corner
155 # of the new bounding box.
156 return bbox_pt(min(llx_pt
, lrx_pt
, urx_pt
, ulx_pt
), min(lly_pt
, lry_pt
, ury_pt
, uly_pt
),
157 max(llx_pt
, lrx_pt
, urx_pt
, ulx_pt
), max(lly_pt
, lry_pt
, ury_pt
, uly_pt
))
159 def enlarge_pt(self
, all_pt
=0, bottom_pt
=None, left_pt
=None, top_pt
=None, right_pt
=None):
160 """enlarge bbox in place by the given amounts in pts
162 all is used, if bottom, left, top and/or right are not given.
165 if self
.llx_pt
is None:
167 if bottom_pt
is None:
175 self
.llx_pt
-= left_pt
176 self
.lly_pt
-= bottom_pt
177 self
.urx_pt
+= right_pt
178 self
.ury_pt
+= top_pt
180 def enlarged_pt(self
, all_pt
=0, bottom_pt
=None, left_pt
=None, top_pt
=None, right_pt
=None):
181 """return bbox enlarged by the given amounts in pts
183 all is used, if bottom, left, top and/or right are not given.
186 if self
.llx_pt
is None:
188 if bottom_pt
is None:
196 return bbox_pt(self
.llx_pt
-left_pt
, self
.lly_pt
-bottom_pt
, self
.urx_pt
+right_pt
, self
.ury_pt
+top_pt
)
198 def enlarge(self
, all
=0, bottom
=None, left
=None, top
=None, right
=None):
199 """enlarge bbox in place
201 all is used, if bottom, left, top and/or right are not given.
204 if self
.llx_pt
is None:
206 bottom_pt
= left_pt
= top_pt
= right_pt
= unit
.topt(all
)
207 if bottom
is not None:
208 bottom_pt
= unit
.topt(bottom
)
210 left_pt
= unit
.topt(left
)
212 top_pt
= unit
.topt(top
)
213 if right
is not None:
214 right_pt
= unit
.topt(right
)
215 self
.llx_pt
-= left_pt
216 self
.lly_pt
-= bottom_pt
217 self
.urx_pt
+= right_pt
218 self
.ury_pt
+= top_pt
220 def enlarged(self
, all
=0, bottom
=None, left
=None, top
=None, right
=None):
221 """return bbox enlarged
223 all is used, if bottom, left, top and/or right are not given.
226 if self
.llx_pt
is None:
228 bottom_pt
= left_pt
= top_pt
= right_pt
= unit
.topt(all
)
229 if bottom
is not None:
230 bottom_pt
= unit
.topt(bottom
)
232 left_pt
= unit
.topt(left
)
234 top_pt
= unit
.topt(top
)
235 if right
is not None:
236 right_pt
= unit
.topt(right
)
237 return bbox_pt(self
.llx_pt
-left_pt
, self
.lly_pt
-bottom_pt
, self
.urx_pt
+right_pt
, self
.ury_pt
+top_pt
)
240 """return rectangle corresponding to bbox"""
241 if self
.llx_pt
is None:
242 raise ValueError("Cannot return path for empty bbox")
244 return path
.rect_pt(self
.llx_pt
, self
.lly_pt
, self
.urx_pt
-self
.llx_pt
, self
.ury_pt
-self
.lly_pt
)
249 """return height of bbox in pts"""
250 if self
.llx_pt
is None:
251 raise ValueError("Cannot return heigth of empty bbox")
252 return self
.ury_pt
-self
.lly_pt
255 """return width of bbox in pts"""
256 if self
.llx_pt
is None:
257 raise ValueError("Cannot return width of empty bbox")
258 return self
.urx_pt
-self
.llx_pt
261 """return top coordinate of bbox in pts"""
262 if self
.llx_pt
is None:
263 raise ValueError("Cannot return top coordinate of empty bbox")
267 """return bottom coordinate of bbox in pts"""
268 if self
.llx_pt
is None:
269 raise ValueError("Cannot return bottom coordinate of empty bbox")
273 """return left coordinate of bbox in pts"""
274 if self
.llx_pt
is None:
275 raise ValueError("Cannot return left coordinate of empty bbox")
279 """return right coordinate of bbox in pts"""
280 if self
.llx_pt
is None:
281 raise ValueError("Cannot return right coordinate of empty bbox")
285 """return coordinates of the center of the bbox in pts"""
286 if self
.llx_pt
is None:
287 raise ValueError("Cannot return center coordinates of empty bbox")
288 return 0.5 * (self
.llx_pt
+self
.urx_pt
), 0.5 * (self
.lly_pt
+self
.ury_pt
)
291 """return height of bbox"""
292 return self
.height_pt() * unit
.t_pt
295 """return width of bbox"""
296 return self
.width_pt() * unit
.t_pt
299 """return top coordinate of bbox"""
300 return self
.ury_pt
* unit
.t_pt
303 """return bottom coordinate of bbox"""
304 return self
.lly_pt
* unit
.t_pt
307 """return left coordinate of bbox"""
308 return self
.llx_pt
* unit
.t_pt
311 """return right coordinate of bbox"""
312 return self
.urx_pt
* unit
.t_pt
315 """return coordinates of the center of the bbox"""
316 centerx_pt
, centery_pt
= self
.center_pt()
317 return centerx_pt
* unit
.t_pt
, centery_pt
* unit
.t_pt
322 """class for bounding boxes"""
324 def __init__(self
, llx_pt
, lly_pt
, urx_pt
, ury_pt
):
325 llx_pt
= unit
.topt(llx_pt
)
326 lly_pt
= unit
.topt(lly_pt
)
327 urx_pt
= unit
.topt(urx_pt
)
328 ury_pt
= unit
.topt(ury_pt
)
329 bbox_pt
.__init
__(self
, llx_pt
, lly_pt
, urx_pt
, ury_pt
)
332 class empty(bbox_pt
):
334 """empty bounding box, i.e., one containing no point"""
336 bbox_pt
.__init
__(self
, None, None, None, None)