make all parts of the manual compile again; parts of the manual are still out of...
[PyX/mjg.git] / pyx / bbox.py
blob5404348fcf9e5ee072c9ef1c854d8616ce584f6e
1 #!/usr/bin/env python
2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 # TODO: - it would be nice to have a real bbox.transform
25 # - what about __iadd__, ...
27 import math
28 import unit
30 # helper routine for bbox manipulations
32 def _nmin(*args):
33 """minimum of a list of values, where None represents +infinity, not -infinity as
34 in standard min implementation of python"""
35 args = [x for x in args if x is not None]
36 if len(args):
37 return min(args)
38 else:
39 return None
42 # classes representing bounding boxes
45 class _bbox:
47 """class for bounding boxes
49 This variant requires points in the constructor, and is used for internal
50 purposes."""
52 def __init__(self, llx=None, lly=None, urx=None, ury=None):
53 self.llx = llx
54 self.lly = lly
55 self.urx = urx
56 self.ury = ury
58 def __add__(self, other):
59 """join two bboxes"""
61 return _bbox(_nmin(self.llx, other.llx), _nmin(self.lly, other.lly),
62 max(self.urx, other.urx), max(self.ury, other.ury))
64 def __mul__(self, other):
65 """return intersection of two bboxes"""
67 return _bbox(max(self.llx, other.llx), max(self.lly, other.lly),
68 _nmin(self.urx, other.urx), _nmin(self.ury, other.ury))
70 def __str__(self):
71 return "%s %s %s %s" % (self.llx, self.lly, self.urx, self.ury)
73 def write(self, file):
74 file.write("%%%%BoundingBox: %d %d %d %d\n" %
75 (math.floor(self.llx), math.floor(self.lly),
76 math.ceil(self.urx), math.ceil(self.ury)))
77 file.write("%%%%HiResBoundingBox: %g %g %g %g\n" %
78 (self.llx, self.lly, self.urx, self.ury))
80 def intersects(self, other):
81 """check, if two bboxes intersect eachother"""
83 return not (self.llx > other.urx or
84 self.lly > other.ury or
85 self.urx < other.llx or
86 self.ury < other.lly)
88 def transformed(self, trafo):
89 """return bbox transformed by trafo"""
90 # we have to transform all four corner points of the bbox
91 # method correctly handles bboxes with None entries at the corners
92 if None not in (self.llx, self.lly):
93 llx, lly = trafo._apply(self.llx, self.lly)
94 else:
95 llx = lly = None
96 if None not in (self.urx, self.lly):
97 lrx, lry = trafo._apply(self.urx, self.lly)
98 else:
99 lrx = lry = None
100 if None not in (self.urx, self.ury):
101 urx, ury = trafo._apply(self.urx, self.ury)
102 else:
103 urx = ury = None
104 if None not in (self.llx, self.ury):
105 ulx, uly = trafo._apply(self.llx, self.ury)
106 else:
107 ulx = uly = None
109 # now, by sorting, we obtain the lower left and upper right corner
110 # of the new bounding box.
112 return _bbox(_nmin(llx, lrx, urx, ulx), _nmin(lly, lry, ury, uly),
113 max(llx, lrx, urx, ulx), max(lly, lry, ury, uly))
115 def enlarged(self, all=0, bottom=None, left=None, top=None, right=None):
116 """return bbox enlarged
118 all is used, if bottom, left, top and/or right are not given.
121 _bottom = _left = _top = _right = unit.topt(unit.length(all, default_type="v"))
122 if bottom is not None:
123 _bottom = unit.topt(unit.length(bottom, default_type="v"))
124 if left is not None:
125 _left = unit.topt(unit.length(left, default_type="v"))
126 if top is not None:
127 _top = unit.topt(unit.length(top, default_type="v"))
128 if right is not None:
129 _right = unit.topt(unit.length(right, default_type="v"))
130 return _bbox(self.llx-_left, self.lly-_bottom, self.urx+_right, self.ury+_top)
132 def rect(self):
133 """return rectangle corresponding to bbox"""
134 import path
135 return path._rect(self.llx, self.lly, self.urx-self.llx, self.ury-self.lly)
137 path = rect
139 def height(self):
140 """return height of bbox"""
141 return unit.t_pt(self.ury-self.lly)
143 def width(self):
144 """return width of bbox"""
145 return unit.t_pt(self.urx-self.llx)
147 def top(self):
148 """return top coordinate of bbox"""
149 return unit.t_pt(self.ury)
151 def bottom(self):
152 """return bottom coordinate of bbox"""
153 return unit.t_pt(self.lly)
155 def left(self):
156 """return left coordinate of bbox"""
157 return unit.t_pt(self.llx)
159 def right(self):
160 """return right coordinate of bbox"""
161 return unit.t_pt(self.urx)
164 class bbox(_bbox):
166 """class for bounding boxes"""
168 def __init__(self, llx=None, lly=None, urx=None, ury=None):
169 if llx is not None:
170 llx = unit.topt(llx)
171 if lly is not None:
172 lly = unit.topt(lly)
173 if urx is not None:
174 urx = unit.topt(urx)
175 if ury is not None:
176 ury = unit.topt(ury)
177 _bbox.__init__(self, llx, lly, urx, ury)