Finally, the simple fix for the qtgui issues; also, changed the naming scheme output...
[debian/gnuradio] / gr-qtgui / src / lib / Waterfall3DDisplayPlot.cc
1 #ifndef WATERFALL_3D_DISPLAY_PLOT_C
2 #define WATERFALL_3D_DISPLAY_PLOT_C
3
4 #include <Waterfall3DDisplayPlot.h>
5
6 #include <qwt3d_helper.h>
7 #include <qapplication.h>
8
9 Waterfall3DColorMap::Waterfall3DColorMap(): Qwt3D::Color(), QwtLinearColorMap(){
10   _interval.setInterval(0, 1.0);
11
12 }
13
14 Waterfall3DColorMap::~Waterfall3DColorMap(){
15
16 }
17
18 Qwt3D::RGBA
19 Waterfall3DColorMap::operator()(double, double, double z) const
20 {
21   return Qwt3D::RGBA(Qwt3D::Qt2GL(color(_interval, z)));
22 }
23
24 void
25 Waterfall3DColorMap::SetInterval(const double minValue, const double maxValue)
26 {
27   _interval.setInterval(minValue, maxValue);
28 }
29
30 Qwt3D::ColorVector&
31 Waterfall3DColorMap::createVector(Qwt3D::ColorVector& vec)
32 {
33   // Generate 100 interval values and then return those
34   Qwt3D::ColorVector colorVec;
35   for(unsigned int number = 0; number < 100; number++){
36     double value = (_interval.width() * (static_cast<double>(number) / 100.0)) + _interval.minValue();
37     colorVec.push_back(operator()(0,0,value));
38   }
39   vec = colorVec;
40   return vec; 
41 }
42
43
44 const int Waterfall3DDisplayPlot::INTENSITY_COLOR_MAP_TYPE_MULTI_COLOR;
45 const int Waterfall3DDisplayPlot::INTENSITY_COLOR_MAP_TYPE_WHITE_HOT;
46 const int Waterfall3DDisplayPlot::INTENSITY_COLOR_MAP_TYPE_BLACK_HOT;
47 const int Waterfall3DDisplayPlot::INTENSITY_COLOR_MAP_TYPE_INCANDESCENT;
48 const int Waterfall3DDisplayPlot::INTENSITY_COLOR_MAP_TYPE_USER_DEFINED;
49
50 Waterfall3DDisplayPlot::Waterfall3DDisplayPlot(QWidget* parent):Qwt3D::SurfacePlot(parent)
51 {
52   _startFrequency = 0;
53   _stopFrequency = 4000;
54
55   _createCoordinateSystemFlag = true;
56
57   _initialized = false;
58
59   _numPoints = 1024;
60
61   _displayIntervalTime = (1.0/5.0); // 1/5 of a second between updates
62
63   timespec_reset(&_lastReplot);
64
65   _useCenterFrequencyFlag = false;
66   _centerFrequency = 0.0;
67
68   _timePerFFT = 1.0;
69   timespec_reset(&_dataTimestamp);
70
71   coordinates()->setAutoScale(false);
72
73   _waterfallData = new Waterfall3DData(_startFrequency, _stopFrequency, _numPoints, 200);
74   _waterfallData->assign(this);
75   _waterfallData->create();
76
77   _intensityColorMapType = -1;
78   SetIntensityColorMapType(INTENSITY_COLOR_MAP_TYPE_MULTI_COLOR, Qt::white, Qt::black, true, true);
79
80   legend()->setScale(Qwt3D::LINEARSCALE);
81   legend()->setTitleString("Intensity");
82
83   enableMouse(true);  
84 }
85
86 Waterfall3DDisplayPlot::~Waterfall3DDisplayPlot()
87 {
88   delete _waterfallData;
89 }
90
91 void
92 Waterfall3DDisplayPlot::Init()
93 {
94   if(!_initialized && initializedGL()){
95     resize(parentWidget()->width(), parentWidget()->height());
96
97     // Attempting to prevent valgrind uninitialized variable errors in QwtPlot3d::Drawable class
98     glDisable(GL_POLYGON_OFFSET_FILL);
99     
100     setPlotStyle(Qwt3D::FILLED);
101     
102     setCoordinateStyle(Qwt3D::FRAME);
103     setFloorStyle(Qwt3D::FLOORDATA);
104     setOrtho(true);  
105
106     _initialized = true;
107   }
108 }
109
110 void
111 Waterfall3DDisplayPlot::Reset()
112 {
113   _waterfallData->ResizeData(_startFrequency, _stopFrequency, _numPoints);
114   _waterfallData->Reset();
115
116   if(initializedGL()){
117     setScale(1, static_cast<int>(((_stopFrequency - _startFrequency) / 200) ), 10);
118   }
119
120   _createCoordinateSystemFlag = true;
121
122   timespec_reset(&_dataTimestamp);
123   _timePerFFT = 1.0;
124 }
125
126 void
127 Waterfall3DDisplayPlot::SetFrequencyRange(const double constStartFreq,
128                                           const double constStopFreq,
129                                           const double constCenterFreq,
130                                           const bool useCenterFrequencyFlag,
131                                           const double units,
132                                           const std::string &strunits)
133 {
134   double startFreq = constStartFreq / units;
135   double stopFreq = constStopFreq / units;
136   double centerFreq = constCenterFreq / units;
137
138   if(stopFreq > startFreq) {
139     _startFrequency = startFreq;
140     _stopFrequency = stopFreq;
141
142     _useCenterFrequencyFlag = useCenterFrequencyFlag;
143     _centerFrequency = centerFreq;
144
145     Reset();
146
147     // Only replot if screen is visible
148     if(isVisible()){
149       replot();
150     }
151   }
152 }
153
154 bool
155 Waterfall3DDisplayPlot::loadFromData(double** data, unsigned int columns, unsigned int rows
156                                      ,double minx, double maxx, double miny, double maxy)
157 {
158
159   Qwt3D::GridData* gridPtr = (Qwt3D::GridData*)actualData_p;
160   
161   gridPtr->setPeriodic(false,false);
162   gridPtr->setSize(columns,rows);
163   readIn(*gridPtr,data,columns,rows,minx,maxx,miny,maxy);
164   calcNormals(*gridPtr);  
165   
166   updateData();
167   updateNormals();
168   
169   if( _createCoordinateSystemFlag ){
170     createCoordinateSystem();
171     
172     for (unsigned i=0; i!=coordinates()->axes.size(); ++i)
173       {
174         coordinates()->axes[i].setMajors(5);
175         coordinates()->axes[i].setMinors(3);
176       }
177     
178     coordinates()->axes[Qwt3D::Y1].setLabelString("Time");
179     coordinates()->axes[Qwt3D::Y2].setLabelString("Time");
180     coordinates()->axes[Qwt3D::Y3].setLabelString("Time");
181     coordinates()->axes[Qwt3D::Y4].setLabelString("Time");
182     coordinates()->axes[Qwt3D::Z1].setLabelString("Intensity (dB)");
183     coordinates()->axes[Qwt3D::Z2].setLabelString("Intensity (dB)");
184     coordinates()->axes[Qwt3D::Z3].setLabelString("Intensity (dB)");
185     coordinates()->axes[Qwt3D::Z4].setLabelString("Intensity (dB)");
186
187     coordinates()->axes[Qwt3D::X1].setLabelString((!_useCenterFrequencyFlag ? "Frequency (Hz)" : "Frequency (kHz)"));
188     coordinates()->axes[Qwt3D::X2].setLabelString((!_useCenterFrequencyFlag ? "Frequency (Hz)" : "Frequency (kHz)"));
189     coordinates()->axes[Qwt3D::X3].setLabelString((!_useCenterFrequencyFlag ? "Frequency (Hz)" : "Frequency (kHz)"));
190     coordinates()->axes[Qwt3D::X4].setLabelString((!_useCenterFrequencyFlag ? "Frequency (Hz)" : "Frequency (kHz)"));
191
192     // The QwtPlot3D Interface takes ownership of these items, so there is no need to delete them...
193     coordinates()->axes[Qwt3D::X1].setScale(new FrequencyScale(_useCenterFrequencyFlag, _centerFrequency));
194     coordinates()->axes[Qwt3D::X2].setScale(new FrequencyScale(_useCenterFrequencyFlag, _centerFrequency));
195     coordinates()->axes[Qwt3D::X3].setScale(new FrequencyScale(_useCenterFrequencyFlag, _centerFrequency));
196     coordinates()->axes[Qwt3D::X4].setScale(new FrequencyScale(_useCenterFrequencyFlag, _centerFrequency));
197
198     coordinates()->axes[Qwt3D::Y1].setScale(new TimeScale(this));
199     coordinates()->axes[Qwt3D::Y2].setScale(new TimeScale(this));
200     coordinates()->axes[Qwt3D::Y3].setScale(new TimeScale(this));
201     coordinates()->axes[Qwt3D::Y4].setScale(new TimeScale(this));
202
203     coordinates()->axes[Qwt3D::Z1].setScale(new IntensityScale(_waterfallData->GetFloorValue()));
204     coordinates()->axes[Qwt3D::Z2].setScale(new IntensityScale(_waterfallData->GetFloorValue()));
205     coordinates()->axes[Qwt3D::Z3].setScale(new IntensityScale(_waterfallData->GetFloorValue()));
206     coordinates()->axes[Qwt3D::Z4].setScale(new IntensityScale(_waterfallData->GetFloorValue()));
207
208     _createCoordinateSystemFlag = false;
209   }
210   
211   return true;
212 }
213
214 double
215 Waterfall3DDisplayPlot::GetStartFrequency() const
216 {
217   return _startFrequency;
218 }
219
220 double
221 Waterfall3DDisplayPlot::GetStopFrequency() const
222 {
223   return _stopFrequency;
224 }
225
226 void
227 Waterfall3DDisplayPlot::PlotNewData(const double* dataPoints,
228                                     const int64_t numDataPoints,
229                                     const double timePerFFT,
230                                     const timespec timestamp,
231                                     const int droppedFrames)
232 {
233   if(numDataPoints > 0){
234     if(numDataPoints != _numPoints){
235       _numPoints = numDataPoints;
236
237       Reset();
238
239       if(isVisible()){
240         replot();
241       }
242
243       _createCoordinateSystemFlag = true;
244
245       _lastReplot = get_highres_clock();
246     }
247
248     _dataTimestamp = timestamp;
249     _timePerFFT = timePerFFT;
250
251     _waterfallData->addFFTData(dataPoints, numDataPoints, droppedFrames);
252     _waterfallData->IncrementNumLinesToUpdate();
253   }
254
255   // Allow at least a 50% duty cycle
256   if(diff_timespec(get_highres_clock(), _lastReplot) > _displayIntervalTime){
257     // Only update when window is visible
258     if(isVisible()){
259       replot();
260     }
261
262     _lastReplot = get_highres_clock();
263   }
264 }
265
266 void
267 Waterfall3DDisplayPlot::SetIntensityRange(const double minIntensity,
268                                           const double maxIntensity)
269 {
270   _waterfallData->SetFloorValue(minIntensity);
271   _waterfallData->setMinZ(0);
272   _waterfallData->setMaxZ(maxIntensity-minIntensity);
273
274   _createCoordinateSystemFlag = true;
275
276   emit UpdatedLowerIntensityLevel(minIntensity);
277   emit UpdatedUpperIntensityLevel(maxIntensity);
278
279   SetIntensityColorMapType(_intensityColorMapType,
280                            _userDefinedLowIntensityColor,
281                            _userDefinedLowIntensityColor, true);
282 }
283
284 void
285 Waterfall3DDisplayPlot::replot()
286 {
287   if(!_initialized){
288     Init();
289   }
290   if(initializedGL()){
291     const timespec startTime = get_highres_clock();
292     
293     _waterfallData->create();
294     
295     legend()->setMajors(4);
296     legend()->setMinors(5);
297     double start, stop;
298     coordinates()->axes[Qwt3D::Z1].limits(start,stop);
299     legend()->setLimits( _waterfallData->GetFloorValue(), _waterfallData->GetFloorValue() + stop - start );
300
301     coordinates()->axes[Qwt3D::X1].limits(start,stop);
302
303     showColorLegend(true);
304
305     updateGL();
306
307     double differenceTime = (diff_timespec(get_highres_clock(), startTime));
308   
309     // Require at least a 20% duty cycle
310     differenceTime *= 4.0;
311     if(differenceTime > (1.0/5.0)){
312       _displayIntervalTime = differenceTime;
313     }
314   }
315 }
316
317 void
318 Waterfall3DDisplayPlot::resizeSlot( QSize *s )
319 {
320   resize(s->width(), s->height());
321 }
322
323 int
324 Waterfall3DDisplayPlot::GetIntensityColorMapType() const
325 {
326   return _intensityColorMapType;
327 }
328
329 void
330 Waterfall3DDisplayPlot::SetIntensityColorMapType(const int newType,
331                                                  const QColor lowColor,
332                                                  const QColor highColor,
333                                                  const bool forceFlag,
334                                                  const bool noReplotFlag)
335 {
336   if(((_intensityColorMapType != newType) || forceFlag) || 
337      ((newType == INTENSITY_COLOR_MAP_TYPE_USER_DEFINED) &&
338       (lowColor.isValid() && highColor.isValid()))){
339
340     Waterfall3DColorMap* colorMap = new Waterfall3DColorMap();
341     colorMap->SetInterval(_waterfallData->minZ(), _waterfallData->maxZ());
342
343     switch(newType){
344     case INTENSITY_COLOR_MAP_TYPE_MULTI_COLOR:{
345       _intensityColorMapType = newType;
346       colorMap->setColorInterval(Qt::darkCyan, Qt::white);
347       colorMap->addColorStop(0.25, Qt::cyan);
348       colorMap->addColorStop(0.5, Qt::yellow);
349       colorMap->addColorStop(0.75, Qt::red);
350       setBackgroundColor(Qwt3D::Qt2GL(Qt::gray));
351       break;
352     }
353     case INTENSITY_COLOR_MAP_TYPE_WHITE_HOT:{
354       _intensityColorMapType = newType;
355       colorMap->setColorInterval(Qt::black, Qt::white);
356       setBackgroundColor(Qwt3D::Qt2GL(Qt::blue));
357       break;
358     }
359     case INTENSITY_COLOR_MAP_TYPE_BLACK_HOT:{
360       _intensityColorMapType = newType;
361       colorMap->setColorInterval(Qt::white, Qt::black);
362       setBackgroundColor(Qwt3D::Qt2GL(Qt::blue));
363       break;
364     }
365     case INTENSITY_COLOR_MAP_TYPE_INCANDESCENT:{
366       _intensityColorMapType = newType;
367       colorMap->setColorInterval(Qt::black, Qt::white);
368       colorMap->addColorStop(0.5, Qt::darkRed);
369       setBackgroundColor(Qwt3D::Qt2GL(Qt::gray));
370       break;
371     }
372     case INTENSITY_COLOR_MAP_TYPE_USER_DEFINED:{
373       _userDefinedLowIntensityColor = lowColor;
374       _userDefinedHighIntensityColor = highColor;
375       _intensityColorMapType = newType;
376       colorMap->setColorInterval(_userDefinedLowIntensityColor, _userDefinedHighIntensityColor);
377       setBackgroundColor(Qwt3D::Qt2GL(Qt::white));
378       break;
379     }
380     default:
381       colorMap->setColorInterval(Qt::black, Qt::white);
382       break;
383     }
384
385     // Qwt3D takes over destruction of this object...
386     setDataColor(colorMap);
387
388     if(!noReplotFlag){
389       // Draw again
390       replot();
391       
392       // Update the last replot timer
393       _lastReplot = get_highres_clock();
394     }
395   }
396 }
397
398 const QColor
399 Waterfall3DDisplayPlot::GetUserDefinedLowIntensityColor() const
400 {
401   return _userDefinedLowIntensityColor;
402 }
403
404 const QColor
405 Waterfall3DDisplayPlot::GetUserDefinedHighIntensityColor() const
406 {
407   return _userDefinedHighIntensityColor;
408 }
409
410 #endif /* WATERFALL_3D_DISPLAY_PLOT_C */