Maxing the x-axis of the time domain plot represent the actual time of the samples...
[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   virtual QwtText trackerText( const QwtDoublePoint& p ) const 
60   {
61     QwtText t(QString("%1 %2, %3 V").arg(p.x(), 0, 'f', GetTimePrecision()).
62               arg(_unitType.c_str()).
63               arg(p.y(), 0, 'f', 4));
64
65     return t;
66   }
67
68 private:
69   std::string _unitType;
70 };
71
72 TimeDomainDisplayPlot::TimeDomainDisplayPlot(QWidget* parent):QwtPlot(parent)
73 {
74   timespec_reset(&_lastReplot);
75
76   resize(parent->width(), parent->height());
77
78   _numPoints = 1024;
79   _realDataPoints = new double[_numPoints];
80   _imagDataPoints = new double[_numPoints];
81   _xAxisPoints = new double[_numPoints];
82
83   _zoomer = new TimeDomainDisplayZoomer(canvas(), 0);
84
85   // Disable polygon clipping
86   QwtPainter::setDeviceClipping(false);
87   
88   // We don't need the cache here
89   canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false);
90   canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false);
91
92   QPalette palette;
93   palette.setColor(canvas()->backgroundRole(), QColor("white"));
94   canvas()->setPalette(palette);  
95
96   setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine);
97   set_xaxis(0, _numPoints);
98   setAxisTitle(QwtPlot::xBottom, "Time (sec)");
99
100   setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
101   set_yaxis(-2.0, 2.0);
102   setAxisTitle(QwtPlot::yLeft, "Normalized Voltage");
103
104   // Automatically deleted when parent is deleted
105   _real_plot_curve = new QwtPlotCurve("Real Data");
106   _real_plot_curve->attach(this);
107   _real_plot_curve->setPen(QPen(Qt::blue));
108   _real_plot_curve->setRawData(_xAxisPoints, _realDataPoints, _numPoints);
109
110   _imag_plot_curve = new QwtPlotCurve("Imaginary Data");
111   _imag_plot_curve->attach(this);
112   _imag_plot_curve->setPen(QPen(Qt::magenta));
113   _imag_plot_curve->setRawData(_xAxisPoints, _imagDataPoints, _numPoints);
114   // _imag_plot_curve->setVisible(false);
115
116   memset(_realDataPoints, 0x0, _numPoints*sizeof(double));
117   memset(_imagDataPoints, 0x0, _numPoints*sizeof(double));
118   memset(_xAxisPoints, 0x0, _numPoints*sizeof(double));
119
120   _sampleRate = 1;
121   _resetXAxisPoints();
122
123   replot();
124
125 #if QT_VERSION < 0x040000
126   _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
127                           Qt::RightButton, Qt::ControlModifier);
128 #else
129   _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
130                           Qt::RightButton, Qt::ControlModifier);
131 #endif
132   _zoomer->setMousePattern(QwtEventPattern::MouseSelect3,
133                           Qt::RightButton);
134
135   _panner = new QwtPlotPanner(canvas());
136   _panner->setAxisEnabled(QwtPlot::yRight, false);
137   _panner->setMouseButton(Qt::MidButton);
138
139   // Avoid jumping when labels with more/less digits
140   // appear/disappear when scrolling vertically
141
142   const QFontMetrics fm(axisWidget(QwtPlot::yLeft)->font());
143   QwtScaleDraw *sd = axisScaleDraw(QwtPlot::yLeft);
144   sd->setMinimumExtent( fm.width("100.00") );
145
146   const QColor c(Qt::darkRed);
147   _zoomer->setRubberBandPen(c);
148   _zoomer->setTrackerPen(c);
149
150   QwtLegend* legendDisplay = new QwtLegend(this);
151   legendDisplay->setItemMode(QwtLegend::CheckableItem);
152   insertLegend(legendDisplay);
153
154   connect(this, SIGNAL( legendChecked(QwtPlotItem *, bool ) ), 
155           this, SLOT( LegendEntryChecked(QwtPlotItem *, bool ) ));
156 }
157
158 TimeDomainDisplayPlot::~TimeDomainDisplayPlot(){
159   delete[] _realDataPoints;
160   delete[] _imagDataPoints;
161   delete[] _xAxisPoints;
162
163   // _fft_plot_curves deleted when parent deleted
164   // _zoomer and _panner deleted when parent deleted
165 }
166
167 void
168 TimeDomainDisplayPlot::set_yaxis(double min, double max)
169 {
170   setAxisScale(QwtPlot::yLeft, min, max);
171   _zoomer->setZoomBase();
172 }
173
174 void
175 TimeDomainDisplayPlot::set_xaxis(double min, double max)
176 {
177   setAxisScale(QwtPlot::xBottom, min, max);
178   _zoomer->setZoomBase();
179 }
180
181
182 void TimeDomainDisplayPlot::replot()
183 {
184   QwtPlot::replot();
185 }
186
187 void
188 TimeDomainDisplayPlot::resizeSlot( QSize *s )
189 {
190   resize(s->width(), s->height());
191 }
192
193 void TimeDomainDisplayPlot::PlotNewData(const double* realDataPoints,
194                                         const double* imagDataPoints,
195                                         const int64_t numDataPoints,
196                                         const double timeInterval)
197 {
198   if((numDataPoints > 0) && 
199      (diff_timespec(get_highres_clock(), _lastReplot) > timeInterval)) {
200   
201     if(numDataPoints != _numPoints){
202       _numPoints = numDataPoints;
203
204       delete[] _realDataPoints;
205       delete[] _imagDataPoints;
206       delete[] _xAxisPoints;
207       _realDataPoints = new double[_numPoints];
208       _imagDataPoints = new double[_numPoints];
209       _xAxisPoints = new double[_numPoints];
210       
211       _real_plot_curve->setRawData(_xAxisPoints, _realDataPoints, _numPoints);
212       _imag_plot_curve->setRawData(_xAxisPoints, _imagDataPoints, _numPoints);
213
214       set_xaxis(0, numDataPoints);
215
216       _resetXAxisPoints();
217     }
218
219     memcpy(_realDataPoints, realDataPoints, numDataPoints*sizeof(double));
220     memcpy(_imagDataPoints, imagDataPoints, numDataPoints*sizeof(double));
221
222     replot();
223
224     _lastReplot = get_highres_clock();
225   }
226 }
227
228 void TimeDomainDisplayPlot::SetImaginaryDataVisible(const bool visibleFlag)
229 {
230   _imag_plot_curve->setVisible(visibleFlag);
231 }
232
233 void TimeDomainDisplayPlot::_resetXAxisPoints()
234 {
235   double delt = 1.0/_sampleRate;
236   for(long loc = 0; loc < _numPoints; loc++){
237     _xAxisPoints[loc] = loc*delt;
238   }
239   setAxisScale(QwtPlot::xBottom, 0, _numPoints*delt);
240 }
241
242 void TimeDomainDisplayPlot::LegendEntryChecked(QwtPlotItem* plotItem, bool on)
243 {
244   plotItem->setVisible(!on);
245 }
246
247 void
248 TimeDomainDisplayPlot::SetSampleRate(double sr, double units,
249                                      const std::string &strunits)
250 {
251   _sampleRate = sr/units;
252   _resetXAxisPoints();
253
254   // While we could change the displayed sigfigs based on the unit being
255   // displayed, I think it looks better by just setting it to 4 regardless.
256   //double display_units = ceil(log10(units)/2.0);
257   double display_units = 4;
258   setAxisTitle(QwtPlot::xBottom, QString("Time (%1)").arg(strunits.c_str()));
259   ((TimeDomainDisplayZoomer*)_zoomer)->SetTimePrecision(display_units);
260   ((TimeDomainDisplayZoomer*)_zoomer)->SetUnitType(strunits);
261 }
262
263 #endif /* TIME_DOMAIN_DISPLAY_PLOT_C */