GPL -> Latex license
[PyX/mjg.git] / pyx / bbox.py
blobead7b34b08ddc372dc03a0b96dd0210d9c827a8a
1 #!/usr/bin/env python
4 # Copyright (C) 2002 Jörg Lehmann <joergl@users.sourceforge.net>
5 # Copyright (C) 2002 André Wobst <wobsta@users.sourceforge.net>
7 # This file is part of PyX (http://pyx.sourceforge.net/).
9 # PyX is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
14 # PyX is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with PyX; if not, write to the Free Software
21 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 # TODO: - it would be nice to have a real bbox.transform
24 # - what about __iadd__, ...
26 import math
27 import unit
29 # helper routine for bbox manipulations
31 def _nmin(x, y):
32 """minimum of two values, where None represents +infinity, not -infinity as
33 in standard min implementation of python"""
34 if x is None: return y
35 if y is None: return x
36 return min(x,y)
39 # classes representing bounding boxes
42 class _bbox:
44 """class for bounding boxes
46 This variant requires points in the constructor, and is used for internal
47 purposes."""
49 def __init__(self, llx=None, lly=None, urx=None, ury=None):
50 self.llx = llx
51 self.lly = lly
52 self.urx = urx
53 self.ury = ury
55 def __add__(self, other):
56 """join two bboxes"""
58 return _bbox(_nmin(self.llx, other.llx), _nmin(self.lly, other.lly),
59 max(self.urx, other.urx), max(self.ury, other.ury))
61 def __mul__(self, other):
62 """return intersection of two bboxes"""
64 return _bbox(max(self.llx, other.llx), max(self.lly, other.lly),
65 _nmin(self.urx, other.urx), _nmin(self.ury, other.ury))
67 def __str__(self):
68 return "%s %s %s %s" % (self.llx, self.lly, self.urx, self.ury)
70 def write(self, file):
71 file.write("%%%%BoundingBox: %d %d %d %d\n" %
72 (math.floor(self.llx), math.floor(self.lly),
73 math.ceil(self.urx), math.ceil(self.ury)))
74 file.write("%%%%HiResBoundingBox: %g %g %g %g\n" %
75 (self.llx, self.lly, self.urx, self.ury))
77 def intersects(self, other):
78 """check, if two bboxes intersect eachother"""
80 return not (self.llx > other.urx or
81 self.lly > other.ury or
82 self.urx < other.llx or
83 self.ury < other.lly)
85 def transformed(self, trafo):
86 """return bbox transformed by trafo"""
87 # we have to transform all four corner points of the bbox
88 (llx, lly)=trafo._apply(self.llx, self.lly)
89 (lrx, lry)=trafo._apply(self.urx, self.lly)
90 (urx, ury)=trafo._apply(self.urx, self.ury)
91 (ulx, uly)=trafo._apply(self.llx, self.ury)
93 # now, by sorting, we obtain the lower left and upper right corner
94 # of the new bounding box.
96 return _bbox(min(llx, lrx, urx, ulx), min(lly, lry, ury, uly),
97 max(llx, lrx, urx, ulx), max(lly, lry, ury, uly))
99 def enlarged(self, all=0, bottom=None, left=None, top=None, right=None):
100 """return bbox enlarged
102 all is used, if bottom, left, top and/or right are not given.
105 _bottom = _left = _top = _right = unit.topt(unit.length(all, default_type="v"))
106 if bottom is not None:
107 _bottom = unit.topt(unit.length(bottom, default_type="v"))
108 if left is not None:
109 _left = unit.topt(unit.length(left, default_type="v"))
110 if top is not None:
111 _top = unit.topt(unit.length(top, default_type="v"))
112 if right is not None:
113 _right = unit.topt(unit.length(right, default_type="v"))
114 return _bbox(self.llx-_left, self.lly-_bottom, self.urx+_right, self.ury+_top)
116 def rect(self):
117 """return rectangle corresponding to bbox"""
118 import path
119 return path._rect(self.llx, self.lly, self.urx-self.llx, self.ury-self.lly)
121 path = rect
123 def height(self):
124 """return height of bbox"""
125 return unit.t_pt(self.ury-self.lly)
127 def width(self):
128 """return width of bbox"""
129 return unit.t_pt(self.urx-self.llx)
131 def top(self):
132 """return top coordinate of bbox"""
133 return unit.t_pt(self.ury)
135 def bottom(self):
136 """return bottom coordinate of bbox"""
137 return unit.t_pt(self.lly)
139 def left(self):
140 """return left coordinate of bbox"""
141 return unit.t_pt(self.llx)
143 def right(self):
144 """return right coordinate of bbox"""
145 return unit.t_pt(self.urx)
148 class bbox(_bbox):
150 """class for bounding boxes"""
152 def __init__(self, llx=None, lly=None, urx=None, ury=None):
153 if llx is not None:
154 llx = unit.topt(llx)
155 if lly is not None:
156 lly = unit.topt(lly)
157 if urx is not None:
158 urx = unit.topt(urx)
159 if ury is not None:
160 ury = unit.topt(ury)
161 _bbox.__init__(self, llx, lly, urx, ury)