Imported Upstream version 3.2.2
[debian/gnuradio] / gr-wxgui / src / python / plotter / common.py
1 #
2 # Copyright 2009 Free Software Foundation, Inc.
3 #
4 # This file is part of GNU Radio
5 #
6 # GNU Radio is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3, or (at your option)
9 # any later version.
10 #
11 # GNU Radio is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with GNU Radio; see the file COPYING.  If not, write to
18 # the Free Software Foundation, Inc., 51 Franklin Street,
19 # Boston, MA 02110-1301, USA.
20 #
21
22 import threading
23 import time
24 import math
25 import wx
26
27 ##################################################
28 # Number formatting
29 ##################################################
30 def get_exp(num):
31         """
32         Get the exponent of the number in base 10.
33         @param num the floating point number
34         @return the exponent as an integer
35         """
36         if num == 0: return 0
37         return int(math.floor(math.log10(abs(num))))
38
39 def get_si_components(num):
40         """
41         Get the SI units for the number.
42         Extract the coeff and exponent of the number.
43         The exponent will be a multiple of 3.
44         @param num the floating point number
45         @return the tuple coeff, exp, prefix
46         """
47         num = float(num)
48         exp = get_exp(num)
49         exp -= exp%3
50         exp = min(max(exp, -24), 24) #bounds on SI table below
51         prefix = {
52                 24: 'Y', 21: 'Z',
53                 18: 'E', 15: 'P',
54                 12: 'T', 9: 'G',
55                 6: 'M', 3: 'k',
56                 0: '',
57                 -3: 'm', -6: 'u',
58                 -9: 'n', -12: 'p',
59                 -15: 'f', -18: 'a',
60                 -21: 'z', -24: 'y',
61         }[exp]
62         coeff = num/10**exp
63         return coeff, exp, prefix
64
65 def sci_format(num):
66         """
67         Format a floating point number into scientific notation.
68         @param num the number to format
69         @return a label string
70         """
71         coeff, exp, prefix = get_si_components(num)
72         if -3 <= exp < 3: return '%g'%num
73         return '%.3ge%d'%(coeff, exp)
74
75 def eng_format(num, units=''):
76         """
77         Format a floating point number into engineering notation.
78         @param num the number to format
79         @param units the units to append
80         @return a label string
81         """
82         coeff, exp, prefix = get_si_components(num)
83         if -3 <= exp < 3: return '%g'%num
84         return '%g%s%s%s'%(coeff, units and ' ' or '', prefix, units)
85
86 ##################################################
87 # Interface with thread safe lock/unlock
88 ##################################################
89 class mutex(object):
90         _lock = threading.Lock()
91         def lock(self): self._lock.acquire()
92         def unlock(self): self._lock.release()
93
94 ##################################################
95 # Periodic update thread for point label
96 ##################################################
97 class point_label_thread(threading.Thread, mutex):
98
99         def __init__(self, plotter):
100                 self._plotter = plotter
101                 self._coor_queue = list()
102                 #bind plotter mouse events
103                 self._plotter.Bind(wx.EVT_MOTION, lambda evt: self.enqueue(evt.GetPosition()))
104                 self._plotter.Bind(wx.EVT_LEAVE_WINDOW, lambda evt: self.enqueue(None))
105                 #start the thread
106                 threading.Thread.__init__(self)
107                 self.start()
108
109         def enqueue(self, coor):
110                 self.lock()
111                 self._coor_queue.append(coor)
112                 self.unlock()
113
114         def run(self):
115                 last_ts = time.time()
116                 last_coor = coor = None
117                 try: 
118                         while True:
119                                 time.sleep(1.0/30.0)
120                                 self.lock()
121                                 #get most recent coor change
122                                 if self._coor_queue:
123                                         coor = self._coor_queue[-1]
124                                         self._coor_queue = list()
125                                 self.unlock()
126                                 #update if coor change, or enough time expired
127                                 if last_coor != coor or (time.time() - last_ts) > (1.0/2.0):
128                                         self._plotter.set_point_label_coordinate(coor)
129                                         last_coor = coor
130                                         last_ts = time.time()
131                 except wx.PyDeadObjectError: pass