9c98cec5b037320e5bf4b5439ac1f8feea9f4af3
[debian/gnuradio] / gr-qtgui / src / lib / TimeDomainDisplayPlot.cc
1 #ifndef TIME_DOMAIN_DISPLAY_PLOT_C
2 #define TIME_DOMAIN_DISPLAY_PLOT_C
3
4 #include <TimeDomainDisplayPlot.h>
5
6 #include <qwt_scale_draw.h>
7 #include <qwt_legend.h>
8
9
10 class TimePrecisionClass
11 {
12 public:
13   TimePrecisionClass(const int timePrecision)
14   {
15     _timePrecision = timePrecision;
16   }
17
18   virtual ~TimePrecisionClass()
19   {
20   }
21
22   virtual unsigned int GetTimePrecision() const
23   {
24     return _timePrecision;
25   }
26
27   virtual void SetTimePrecision(const unsigned int newPrecision)
28   {
29     _timePrecision = newPrecision;
30   }
31 protected:
32   unsigned int _timePrecision;
33 };
34
35
36 class TimeDomainDisplayZoomer: public QwtPlotZoomer, public TimePrecisionClass
37 {
38 public:
39   TimeDomainDisplayZoomer(QwtPlotCanvas* canvas, const unsigned int timePrecision)
40     : QwtPlotZoomer(canvas),TimePrecisionClass(timePrecision)
41   {
42     setTrackerMode(QwtPicker::AlwaysOn);
43   }
44
45   virtual ~TimeDomainDisplayZoomer(){
46
47   }
48   
49   virtual void updateTrackerText(){
50     updateDisplay();
51   }
52
53   void SetUnitType(const std::string &type)
54   {
55     _unitType = type;
56   }
57
58 protected:
59   using QwtPlotZoomer::trackerText;
60   virtual QwtText trackerText( const QwtDoublePoint& p ) const 
61   {
62     QwtText t(QString("%1 %2, %3 V").arg(p.x(), 0, 'f', GetTimePrecision()).
63               arg(_unitType.c_str()).
64               arg(p.y(), 0, 'f', 4));
65
66     return t;
67   }
68
69 private:
70   std::string _unitType;
71 };
72
73 TimeDomainDisplayPlot::TimeDomainDisplayPlot(QWidget* parent):QwtPlot(parent)
74 {
75   timespec_reset(&_lastReplot);
76
77   resize(parent->width(), parent->height());
78
79   _numPoints = 1024;
80   _realDataPoints = new double[_numPoints];
81   _imagDataPoints = new double[_numPoints];
82   _xAxisPoints = new double[_numPoints];
83
84   _zoomer = new TimeDomainDisplayZoomer(canvas(), 0);
85
86   // Disable polygon clipping
87   QwtPainter::setDeviceClipping(false);
88   
89   // We don't need the cache here
90   canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false);
91   canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false);
92
93   QPalette palette;
94   palette.setColor(canvas()->backgroundRole(), QColor("white"));
95   canvas()->setPalette(palette);  
96
97   setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine);
98   set_xaxis(0, _numPoints);
99   setAxisTitle(QwtPlot::xBottom, "Time (sec)");
100
101   setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
102   set_yaxis(-2.0, 2.0);
103   setAxisTitle(QwtPlot::yLeft, "Normalized Voltage");
104
105   // Automatically deleted when parent is deleted
106   _real_plot_curve = new QwtPlotCurve("Real Data");
107   _real_plot_curve->attach(this);
108   _real_plot_curve->setPen(QPen(Qt::blue));
109   _real_plot_curve->setRawData(_xAxisPoints, _realDataPoints, _numPoints);
110
111   _imag_plot_curve = new QwtPlotCurve("Imaginary Data");
112   _imag_plot_curve->attach(this);
113   _imag_plot_curve->setPen(QPen(Qt::magenta));
114   _imag_plot_curve->setRawData(_xAxisPoints, _imagDataPoints, _numPoints);
115   // _imag_plot_curve->setVisible(false);
116
117   memset(_realDataPoints, 0x0, _numPoints*sizeof(double));
118   memset(_imagDataPoints, 0x0, _numPoints*sizeof(double));
119   memset(_xAxisPoints, 0x0, _numPoints*sizeof(double));
120
121   _sampleRate = 1;
122   _resetXAxisPoints();
123
124   replot();
125
126 #if QT_VERSION < 0x040000
127   _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
128                           Qt::RightButton, Qt::ControlModifier);
129 #else
130   _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
131                           Qt::RightButton, Qt::ControlModifier);
132 #endif
133   _zoomer->setMousePattern(QwtEventPattern::MouseSelect3,
134                           Qt::RightButton);
135
136   _panner = new QwtPlotPanner(canvas());
137   _panner->setAxisEnabled(QwtPlot::yRight, false);
138   _panner->setMouseButton(Qt::MidButton);
139
140   // Avoid jumping when labels with more/less digits
141   // appear/disappear when scrolling vertically
142
143   const QFontMetrics fm(axisWidget(QwtPlot::yLeft)->font());
144   QwtScaleDraw *sd = axisScaleDraw(QwtPlot::yLeft);
145   sd->setMinimumExtent( fm.width("100.00") );
146
147   const QColor c(Qt::darkRed);
148   _zoomer->setRubberBandPen(c);
149   _zoomer->setTrackerPen(c);
150
151   QwtLegend* legendDisplay = new QwtLegend(this);
152   legendDisplay->setItemMode(QwtLegend::CheckableItem);
153   insertLegend(legendDisplay);
154
155   connect(this, SIGNAL( legendChecked(QwtPlotItem *, bool ) ), 
156           this, SLOT( LegendEntryChecked(QwtPlotItem *, bool ) ));
157 }
158
159 TimeDomainDisplayPlot::~TimeDomainDisplayPlot(){
160   delete[] _realDataPoints;
161   delete[] _imagDataPoints;
162   delete[] _xAxisPoints;
163
164   // _fft_plot_curves deleted when parent deleted
165   // _zoomer and _panner deleted when parent deleted
166 }
167
168 void
169 TimeDomainDisplayPlot::set_yaxis(double min, double max)
170 {
171   setAxisScale(QwtPlot::yLeft, min, max);
172   _zoomer->setZoomBase();
173 }
174
175 void
176 TimeDomainDisplayPlot::set_xaxis(double min, double max)
177 {
178   setAxisScale(QwtPlot::xBottom, min, max);
179   _zoomer->setZoomBase();
180 }
181
182
183 void TimeDomainDisplayPlot::replot()
184 {
185   QwtPlot::replot();
186 }
187
188 void
189 TimeDomainDisplayPlot::resizeSlot( QSize *s )
190 {
191   resize(s->width(), s->height());
192 }
193
194 void TimeDomainDisplayPlot::PlotNewData(const double* realDataPoints,
195                                         const double* imagDataPoints,
196                                         const int64_t numDataPoints,
197                                         const double timeInterval)
198 {
199   if((numDataPoints > 0) && 
200      (diff_timespec(get_highres_clock(), _lastReplot) > timeInterval)) {
201   
202     if(numDataPoints != _numPoints){
203       _numPoints = numDataPoints;
204
205       delete[] _realDataPoints;
206       delete[] _imagDataPoints;
207       delete[] _xAxisPoints;
208       _realDataPoints = new double[_numPoints];
209       _imagDataPoints = new double[_numPoints];
210       _xAxisPoints = new double[_numPoints];
211       
212       _real_plot_curve->setRawData(_xAxisPoints, _realDataPoints, _numPoints);
213       _imag_plot_curve->setRawData(_xAxisPoints, _imagDataPoints, _numPoints);
214
215       set_xaxis(0, numDataPoints);
216
217       _resetXAxisPoints();
218     }
219
220     memcpy(_realDataPoints, realDataPoints, numDataPoints*sizeof(double));
221     memcpy(_imagDataPoints, imagDataPoints, numDataPoints*sizeof(double));
222
223     replot();
224
225     _lastReplot = get_highres_clock();
226   }
227 }
228
229 void TimeDomainDisplayPlot::SetImaginaryDataVisible(const bool visibleFlag)
230 {
231   _imag_plot_curve->setVisible(visibleFlag);
232 }
233
234 void TimeDomainDisplayPlot::_resetXAxisPoints()
235 {
236   double delt = 1.0/_sampleRate;
237   for(long loc = 0; loc < _numPoints; loc++){
238     _xAxisPoints[loc] = loc*delt;
239   }
240   setAxisScale(QwtPlot::xBottom, 0, _numPoints*delt);
241
242   // Set up zoomer base for maximum unzoom x-axis
243   // and reset to maximum unzoom level
244   QwtDoubleRect zbase = _zoomer->zoomBase();
245   zbase.setLeft(0);
246   zbase.setRight(_numPoints*delt);
247   _zoomer->zoom(zbase);
248   _zoomer->setZoomBase(zbase);
249   _zoomer->zoom(0);
250 }
251
252 void TimeDomainDisplayPlot::LegendEntryChecked(QwtPlotItem* plotItem, bool on)
253 {
254   plotItem->setVisible(!on);
255 }
256
257 void
258 TimeDomainDisplayPlot::SetSampleRate(double sr, double units,
259                                      const std::string &strunits)
260 {
261   double newsr = sr/units;
262   if(newsr != _sampleRate) {
263     _sampleRate = sr/units;
264     _resetXAxisPoints();
265     
266     // While we could change the displayed sigfigs based on the unit being
267     // displayed, I think it looks better by just setting it to 4 regardless.
268     //double display_units = ceil(log10(units)/2.0);
269     double display_units = 4;
270     setAxisTitle(QwtPlot::xBottom, QString("Time (%1)").arg(strunits.c_str()));
271     ((TimeDomainDisplayZoomer*)_zoomer)->SetTimePrecision(display_units);
272     ((TimeDomainDisplayZoomer*)_zoomer)->SetUnitType(strunits);
273   }
274 }
275
276 #endif /* TIME_DOMAIN_DISPLAY_PLOT_C */