fix rational test: itruediv was missing
[PyX.git] / unit.py
blob629f4d12ec605d1030e147dc1fa6206c4029ba64
1 # -*- encoding: utf-8 -*-
4 # Copyright (C) 2002-2004 Jörg Lehmann <joergl@users.sourceforge.net>
5 # Copyright (C) 2002-2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 import types, functools
25 scale = dict(u=1, v=1, w=1, x=1)
27 _default_unit = "cm"
29 _m = {
30 "m": 1,
31 "cm": 0.01,
32 "mm": 0.001,
33 "inch": 0.01*2.54,
34 "pt": 0.01*2.54/72,
37 def set(uscale=None, vscale=None, wscale=None, xscale=None, defaultunit=None):
38 if uscale is not None:
39 scale["u"] = uscale
40 if vscale is not None:
41 scale["v"] = vscale
42 if wscale is not None:
43 scale["w"] = wscale
44 if xscale is not None:
45 scale["x"] = xscale
46 if defaultunit is not None:
47 global _default_unit
48 _default_unit = defaultunit
51 def _convert_to(l, dest_unit="m"):
52 if isinstance(l, length):
53 return (l.t + l.u*scale["u"] + l.v*scale["v"] + l.w*scale["w"] + l.x*scale["x"]) / _m[dest_unit]
54 else:
55 return l * _m[_default_unit] * scale["u"] / _m[dest_unit]
57 def tom(l):
58 return _convert_to(l, "m")
60 def tocm(l):
61 return _convert_to(l, "cm")
63 def tomm(l):
64 return _convert_to(l, "mm")
66 def toinch(l):
67 return _convert_to(l, "inch")
69 def topt(l):
70 return _convert_to(l, "pt")
72 ################################################################################
73 # class for generic length
74 ################################################################################
76 @functools.total_ordering
77 class length:
78 """ PyX lengths
80 PyX lengths are composed of five components (t=true, u=user, v=visual,
81 w=width, and x=TeX) which can be scaled separately (except for the true
82 component, which is always unscaled). Lengths can be constructed in units
83 of "pt", "mm", "cm", "m" and "inch". When no unit is given, a module
84 default is used, which can be changed with the help of the module level function
85 set().
86 """
88 def __init__(self, f=0, type="u", unit=None):
89 """ create a length instance of the given type with a length f
90 in the given unit. If unit is not set, the currently set default unit is used.
91 """
92 self.t = self.u = self.v = self.w = self.x = 0
93 l = float(f) * _m[unit or _default_unit]
94 if type == "t":
95 self.t = l
96 elif type == "u":
97 self.u = l
98 elif type == "v":
99 self.v = l
100 elif type == "w":
101 self.w = l
102 elif type == "x":
103 self.x = l
105 def __eq__(self, other):
106 try:
107 return tom(self) == tom(other)
108 except TypeError:
109 return NotImplemented
111 def __lt__(self, other):
112 try:
113 return tom(self) < tom(other)
114 except TypeError:
115 return NotImplemented
117 def __mul__(self, factor):
118 result = length()
119 result.t = factor * self.t
120 result.u = factor * self.u
121 result.v = factor * self.v
122 result.w = factor * self.w
123 result.x = factor * self.x
124 return result
126 __rmul__=__mul__
128 def __div__(self, divisor):
129 if isinstance(divisor, length):
130 return tom(self) / tom(divisor)
131 result = length()
132 result.t = self.t / divisor
133 result.u = self.u / divisor
134 result.v = self.v / divisor
135 result.w = self.w / divisor
136 result.x = self.x / divisor
137 return result
139 __truediv__ = __div__
141 def __add__(self, other):
142 # convert to length if necessary
143 if not isinstance(other, length):
144 # if other is not a length, we try to convert it into a length and
145 # if this fails, we give other a chance to do the addition
146 try:
147 other = length(other)
148 except:
149 return other + self
150 result = length()
151 result.t = self.t + other.t
152 result.u = self.u + other.u
153 result.v = self.v + other.v
154 result.w = self.w + other.w
155 result.x = self.x + other.x
156 return result
158 __radd__ = __add__
160 def __sub__(self, other):
161 # convert to length if necessary
162 if not isinstance(other, length):
163 # if other is not a length, we try to convert it into a length and
164 # if this fails, we give other a chance to do the subtraction
165 try:
166 other = length(other)
167 except:
168 return -other + self
169 result = length()
170 result.t = self.t - other.t
171 result.u = self.u - other.u
172 result.v = self.v - other.v
173 result.w = self.w - other.w
174 result.x = self.x - other.x
175 return result
177 def __rsub__(self, other):
178 # convert to length if necessary
179 if not isinstance(other, length):
180 other = length(other)
181 result = length()
182 result.t = other.t - self.t
183 result.u = other.u - self.u
184 result.v = other.v - self.v
185 result.w = other.w - self.w
186 result.x = other.x - self.x
187 return result
189 def __neg__(self):
190 result = length()
191 result.t = -self.t
192 result.u = -self.u
193 result.v = -self.v
194 result.w = -self.w
195 result.x = -self.x
196 return result
198 def __str__(self):
199 return "(%(t)f t + %(u)f u + %(v)f v + %(w)f w + %(x)f x) m" % self.__dict__
202 ################################################################################
203 # predefined instances which can be used as length units
204 ################################################################################
206 # user lengths and unqualified length which are also user length
207 u_pt = pt = length(1, type="u", unit="pt")
208 u_m = m = length(1, type="u", unit="m")
209 u_mm = mm = length(1, type="u", unit="mm")
210 u_cm = cm = length(1, type="u", unit="cm")
211 u_inch = inch = length(1, type="u", unit="inch")
213 # true lengths
214 t_pt = length(1, type="t", unit="pt")
215 t_m = length(1, type="t", unit="m")
216 t_mm = length(1, type="t", unit="mm")
217 t_cm = length(1, type="t", unit="cm")
218 t_inch = length(1, type="t", unit="inch")
220 # visual lengths
221 v_pt = length(1, type="v", unit="pt")
222 v_m = length(1, type="v", unit="m")
223 v_mm = length(1, type="v", unit="mm")
224 v_cm = length(1, type="v", unit="cm")
225 v_inch = length(1, type="v", unit="inch")
227 # width lengths
228 w_pt = length(1, type="w", unit="pt")
229 w_m = length(1, type="w", unit="m")
230 w_mm = length(1, type="w", unit="mm")
231 w_cm = length(1, type="w", unit="cm")
232 w_inch = length(1, type="w", unit="inch")
234 # TeX lengths
235 x_pt = length(1, type="x", unit="pt")
236 x_m = length(1, type="x", unit="m")
237 x_mm = length(1, type="x", unit="mm")
238 x_cm = length(1, type="x", unit="cm")
239 x_inch = length(1, type="x", unit="inch")