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