python version
[PyX/mjg.git] / pyx / unit.py
blob3b2f11686984f2559bf0e17003ab913394ea0f58
1 #!/usr/bin/env python
2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002, 2003 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2002, 2003 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 import types
25 import re
26 import helper
28 unit_ps = 1.0
30 scale = { 't':1, 'u':1, 'v':1, 'w':1 }
32 _default_unit = "cm"
34 unit_pattern = re.compile(r"""^\s*([+-]?\d*((\d\.?)|(\.?\d))\d*(E[+-]?\d+)?)
35 (\s+([t-w]))?
36 (\s+(([a-z][a-z]+)|[^t-w]))?\s*$""",
37 re.IGNORECASE | re.VERBOSE)
40 _m = {
41 'm' : 1,
42 'cm': 0.01,
43 'mm': 0.001,
44 'inch': 0.01*2.54,
45 'pt': 0.01*2.54/72,
48 def set(uscale=None, vscale=None, wscale=None, defaultunit=None):
49 if uscale:
50 scale['u'] = uscale
51 if vscale:
52 scale['v'] = vscale
53 if wscale:
54 scale['w'] = wscale
55 if defaultunit:
56 global _default_unit
57 _default_unit = defaultunit
60 def _convert_to(l, dest_unit="m"):
61 if type(l) in (types.IntType, types.LongType, types.FloatType):
62 return l*_m[_default_unit]*scale['u']/_m[dest_unit]
63 elif not isinstance(l, length):
64 l=length(l) # convert to length instance if necessary
66 return ( l.length['t'] +
67 l.length['u']*scale['u'] +
68 l.length['v']*scale['v'] +
69 l.length['w']*scale['w'] ) / _m[dest_unit]
71 def tom(l):
72 return _convert_to(l, "m")
74 def tocm(l):
75 return _convert_to(l, "cm")
77 def tomm(l):
78 return _convert_to(l, "mm")
80 def toinch(l):
81 return _convert_to(l, "inch")
83 def topt(l):
84 return _convert_to(l, "pt")
86 ################################################################################
87 # class for generic length
88 ################################################################################
90 class length:
91 """ general lengths
93 Lengths can either be a initialized with a number or a string:
95 - a length specified as a number corresponds to the default values of
96 unit_type and unit_name
97 - a string has to consist of a maximum of three parts:
98 -quantifier: integer/float value
99 -unit_type: "t", "u", "v", or "w".
100 Optional, defaults to "u"
101 -unit_name: "m", "cm", "mm", "inch", "pt".
102 Optional, defaults to _default_unit
104 Internally all length are stored in units of m as a quadruple of the four
105 unit_types.
109 def __init__(self, l=1, default_type="u", dunit=None):
110 self.length = { 't': 0 , 'u': 0, 'v': 0, 'v':0, 'w':0 }
112 if isinstance(l, length):
113 self.length = l.length
114 elif helper.isstring(l):
115 unit_match = re.match(unit_pattern, l)
116 if unit_match is None:
117 raise ValueError("expecting number or string of the form 'number [u|v|w] unit'")
118 else:
119 self.prefactor = float(unit_match.group(1))
120 self.unit_type = unit_match.group(7) or default_type
121 self.unit_name = unit_match.group(9) or dunit or _default_unit
123 self.length[self.unit_type] = self.prefactor*_m[self.unit_name]
124 elif helper.isnumber(l):
125 self.length[default_type] = l*_m[dunit or _default_unit]
126 else:
127 raise ( NotImplementedError,
128 "cannot convert given argument to length type" )
130 def __mul__(self, factor):
131 newlength = self.__class__()
132 for unit_type in newlength.length.keys():
133 newlength.length[unit_type] = self.length[unit_type]*factor
134 return newlength
136 __rmul__=__mul__
138 def __div__(self, factor):
139 newlength = self.__class__()
140 for unit_type in newlength.length.keys():
141 newlength.length[unit_type] = self.length[unit_type]/factor
142 return newlength
144 def __add__(self, l):
145 # convert to length if necessary
146 ll = length(l)
147 newlength = self.__class__()
148 for unit_type in newlength.length.keys():
149 newlength.length[unit_type] = self.length[unit_type] + ll.length[unit_type]
150 return newlength
152 __radd__=__add__
154 def __sub__(self, l):
155 # convert to length if necessary
156 ll = length(l)
157 newlength = self.__class__()
158 for unit_type in newlength.length.keys():
159 newlength.length[unit_type] = self.length[unit_type] - ll.length[unit_type]
160 return newlength
162 def __rsub__(self, l):
163 # convert to length if necessary
164 ll = length(l)
165 newlength = self.__class__()
166 for unit_type in newlength.length.keys():
167 newlength.length[unit_type] = ll.length[unit_type] - self.length[unit_type]
168 return newlength
170 def __neg__(self):
171 newlength = self.__class__()
172 for unit_type in newlength.length.keys():
173 newlength.length[unit_type] = -self.length[unit_type]
174 return newlength
176 def __str__(self):
177 return "(%(t)f t + %(u)f u + %(v)f v + %(w)f w) m" % self.length
180 ################################################################################
181 # class for more specialized lengths
182 ################################################################################
184 # lengths with user units as default
186 class u_pt(length):
187 def __init__(self, l=1, default_type="u"):
188 length.__init__(self, l, default_type=default_type, dunit="pt")
191 class u_m(length):
192 def __init__(self, l=1, default_type="u"):
193 length.__init__(self, l, default_type=default_type, dunit="m")
196 class u_mm(length):
197 def __init__(self, l=1, default_type="u"):
198 length.__init__(self, l, default_type=default_type, dunit="mm")
201 class u_cm(length):
202 def __init__(self, l=1, default_type="u"):
203 length.__init__(self, l, default_type=default_type, dunit="cm")
206 class u_inch(length):
207 def __init__(self, l=1, default_type="u"):
208 length.__init__(self, l, default_type=default_type, dunit="inch")
210 # without further specification, length are user length. Hence we
211 # define the following aliases
213 pt = u_pt
214 m = u_m
215 cm = u_cm
216 mm = u_mm
217 inch = u_inch
219 # true lengths
221 class t_pt(length):
222 def __init__(self, l=1):
223 length.__init__(self, l, default_type="t", dunit="pt")
226 class t_m(length):
227 def __init__(self, l=1):
228 length.__init__(self, l, default_type="t", dunit="m")
231 class t_cm(length):
232 def __init__(self, l=1):
233 length.__init__(self, l, default_type="t", dunit="cm")
236 class t_mm(length):
237 def __init__(self, l=1):
238 length.__init__(self, l, default_type="t", dunit="mm")
241 class t_inch(length):
242 def __init__(self, l=1):
243 length.__init__(self, l, default_type="t", dunit="inch")
245 # visual lengths
247 class v_pt(length):
248 def __init__(self, l=1):
249 length.__init__(self, l, default_type="v", dunit="pt")
252 class v_m(length):
253 def __init__(self, l=1):
254 length.__init__(self, l, default_type="v", dunit="m")
257 class v_cm(length):
258 def __init__(self, l=1):
259 length.__init__(self, l, default_type="v", dunit="cm")
262 class v_mm(length):
263 def __init__(self, l=1):
264 length.__init__(self, l, default_type="v", dunit="mm")
267 class v_inch(length):
268 def __init__(self, l=1):
269 length.__init__(self, l, default_type="v", dunit="inch")
271 # width lengths
273 class w_pt(length):
274 def __init__(self, l=1):
275 length.__init__(self, l, default_type="w", dunit="pt")
278 class w_m(length):
279 def __init__(self, l=1):
280 length.__init__(self, l, default_type="w", dunit="m")
283 class w_cm(length):
284 def __init__(self, l=1):
285 length.__init__(self, l, default_type="w", dunit="cm")
288 class w_mm(length):
289 def __init__(self, l=1):
290 length.__init__(self, l, default_type="w", dunit="mm")
293 class w_inch(length):
294 def __init__(self, l=1):
295 length.__init__(self, l, default_type="w", dunit="inch")