GPL -> Latex license
[PyX/mjg.git] / pyx / unit.py
blob11eab5ee75c3cc0296076dd7f1f22a35cff33b2b
1 #!/usr/bin/env python
4 # Copyright (C) 2002, 2003 Jörg Lehmann <joergl@users.sourceforge.net>
5 # Copyright (C) 2002, 2003 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 import types
24 import re
25 import helper
27 unit_ps = 1.0
29 scale = { 't':1, 'u':1, 'v':1, 'w':1 }
31 _default_unit = "cm"
33 unit_pattern = re.compile(r"""^\s*([+-]?\d*((\d\.?)|(\.?\d))\d*(E[+-]?\d+)?)
34 (\s+([t-w]))?
35 (\s+(([a-z][a-z]+)|[^t-w]))?\s*$""",
36 re.IGNORECASE | re.VERBOSE)
39 _m = {
40 'm' : 1,
41 'cm': 0.01,
42 'mm': 0.001,
43 'inch': 0.01*2.54,
44 'pt': 0.01*2.54/72,
47 def set(uscale=None, vscale=None, wscale=None, defaultunit=None):
48 if uscale:
49 scale['u'] = uscale
50 if vscale:
51 scale['v'] = vscale
52 if wscale:
53 scale['w'] = wscale
54 if defaultunit:
55 global _default_unit
56 _default_unit = defaultunit
59 def _convert_to(l, dest_unit="m"):
60 if type(l) in (types.IntType, types.LongType, types.FloatType):
61 return l*_m[_default_unit]*scale['u']/_m[dest_unit]
62 elif not isinstance(l, length):
63 l=length(l) # convert to length instance if necessary
65 return ( l.length['t'] +
66 l.length['u']*scale['u'] +
67 l.length['v']*scale['v'] +
68 l.length['w']*scale['w'] ) / _m[dest_unit]
70 def tom(l):
71 return _convert_to(l, "m")
73 def tocm(l):
74 return _convert_to(l, "cm")
76 def tomm(l):
77 return _convert_to(l, "mm")
79 def toinch(l):
80 return _convert_to(l, "inch")
82 def topt(l):
83 return _convert_to(l, "pt")
85 ################################################################################
86 # class for generic length
87 ################################################################################
89 class length:
90 """ general lengths
92 Lengths can either be a initialized with a number or a string:
94 - a length specified as a number corresponds to the default values of
95 unit_type and unit_name
96 - a string has to consist of a maximum of three parts:
97 -quantifier: integer/float value
98 -unit_type: "t", "u", "v", or "w".
99 Optional, defaults to "u"
100 -unit_name: "m", "cm", "mm", "inch", "pt".
101 Optional, defaults to _default_unit
103 Internally all length are stored in units of m as a quadruple of the four
104 unit_types.
108 def __init__(self, l=1, default_type="u", dunit=None):
109 self.length = { 't': 0 , 'u': 0, 'v': 0, 'v':0, 'w':0 }
111 if isinstance(l, length):
112 self.length = l.length
113 elif helper.isstring(l):
114 unit_match = re.match(unit_pattern, l)
115 if unit_match is None:
116 assert 0, "expecting number or string of the form 'number [u|v|w] unit'"
117 else:
118 self.prefactor = float(unit_match.group(1))
119 self.unit_type = unit_match.group(7) or default_type
120 self.unit_name = unit_match.group(9) or dunit or _default_unit
122 self.length[self.unit_type] = self.prefactor*_m[self.unit_name]
123 elif helper.isnumber(l):
124 self.length[default_type] = l*_m[dunit or _default_unit]
125 else:
126 raise ( NotImplementedError,
127 "cannot convert given argument to length type" )
129 def __mul__(self, factor):
130 newlength = self.__class__()
131 for unit_type in newlength.length.keys():
132 newlength.length[unit_type] = self.length[unit_type]*factor
133 return newlength
135 __rmul__=__mul__
137 def __div__(self, factor):
138 newlength = self.__class__()
139 for unit_type in newlength.length.keys():
140 newlength.length[unit_type] = self.length[unit_type]/factor
141 return newlength
143 def __add__(self, l):
144 # convert to length if necessary
145 ll = length(l)
146 newlength = self.__class__()
147 for unit_type in newlength.length.keys():
148 newlength.length[unit_type] = self.length[unit_type] + ll.length[unit_type]
149 return newlength
151 __radd__=__add__
153 def __sub__(self, l):
154 # convert to length if necessary
155 ll = length(l)
156 newlength = self.__class__()
157 for unit_type in newlength.length.keys():
158 newlength.length[unit_type] = self.length[unit_type] - ll.length[unit_type]
159 return newlength
161 def __rsub__(self, l):
162 # convert to length if necessary
163 ll = length(l)
164 newlength = self.__class__()
165 for unit_type in newlength.length.keys():
166 newlength.length[unit_type] = ll.length[unit_type] - self.length[unit_type]
167 return newlength
169 def __neg__(self):
170 newlength = self.__class__()
171 for unit_type in newlength.length.keys():
172 newlength.length[unit_type] = -self.length[unit_type]
173 return newlength
175 def __str__(self):
176 return "(%(t)f t + %(u)f u + %(v)f v + %(w)f w) m" % self.length
179 ################################################################################
180 # class for more specialized lengths
181 ################################################################################
183 # lengths with user units as default
185 class u_pt(length):
186 def __init__(self, l=1, default_type="u"):
187 length.__init__(self, l, default_type=default_type, dunit="pt")
190 class u_m(length):
191 def __init__(self, l=1, default_type="u"):
192 length.__init__(self, l, default_type=default_type, dunit="m")
195 class u_mm(length):
196 def __init__(self, l=1, default_type="u"):
197 length.__init__(self, l, default_type=default_type, dunit="mm")
200 class u_cm(length):
201 def __init__(self, l=1, default_type="u"):
202 length.__init__(self, l, default_type=default_type, dunit="cm")
205 class u_inch(length):
206 def __init__(self, l=1, default_type="u"):
207 length.__init__(self, l, default_type=default_type, dunit="inch")
209 # without further specification, length are user length. Hence we
210 # define the following aliases
212 pt = u_pt
213 m = u_m
214 cm = u_cm
215 mm = u_mm
216 inch = u_inch
218 # true lengths
220 class t_pt(length):
221 def __init__(self, l=1):
222 length.__init__(self, l, default_type="t", dunit="pt")
225 class t_m(length):
226 def __init__(self, l=1):
227 length.__init__(self, l, default_type="t", dunit="m")
230 class t_cm(length):
231 def __init__(self, l=1):
232 length.__init__(self, l, default_type="t", dunit="cm")
235 class t_mm(length):
236 def __init__(self, l=1):
237 length.__init__(self, l, default_type="t", dunit="mm")
240 class t_inch(length):
241 def __init__(self, l=1):
242 length.__init__(self, l, default_type="t", dunit="inch")
244 # visual lengths
246 class v_pt(length):
247 def __init__(self, l=1):
248 length.__init__(self, l, default_type="v", dunit="pt")
251 class v_m(length):
252 def __init__(self, l=1):
253 length.__init__(self, l, default_type="v", dunit="m")
256 class v_cm(length):
257 def __init__(self, l=1):
258 length.__init__(self, l, default_type="v", dunit="cm")
261 class v_mm(length):
262 def __init__(self, l=1):
263 length.__init__(self, l, default_type="v", dunit="mm")
266 class v_inch(length):
267 def __init__(self, l=1):
268 length.__init__(self, l, default_type="v", dunit="inch")
270 # width lengths
272 class w_pt(length):
273 def __init__(self, l=1):
274 length.__init__(self, l, default_type="w", dunit="pt")
277 class w_m(length):
278 def __init__(self, l=1):
279 length.__init__(self, l, default_type="w", dunit="m")
282 class w_cm(length):
283 def __init__(self, l=1):
284 length.__init__(self, l, default_type="w", dunit="cm")
287 class w_mm(length):
288 def __init__(self, l=1):
289 length.__init__(self, l, default_type="w", dunit="mm")
292 class w_inch(length):
293 def __init__(self, l=1):
294 length.__init__(self, l, default_type="w", dunit="inch")