]> git.gag.com Git - debian/gnuradio/blob - gr-qtgui/src/lib/Waterfall3DDisplayPlot.cc
Merging qtgui branch-r9068:9837: this ads a qtgui_sink_c and qtgui_sink_f that displa...
[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 Waterfall3DDisplayPlot::SetFrequencyRange(const double startFreq, const double stopFreq, const double centerFreq, const bool useCenterFrequencyFlag){
115   if((stopFreq > 0) && (stopFreq > startFreq)){
116     _startFrequency = startFreq;
117     _stopFrequency = stopFreq;
118
119     _useCenterFrequencyFlag = useCenterFrequencyFlag;
120     _centerFrequency = centerFreq;
121
122     Reset();
123
124     // Only replot if screen is visible
125     if(isVisible()){
126       replot();
127     }
128   }
129 }
130
131 bool Waterfall3DDisplayPlot::loadFromData(double** data, unsigned int columns, unsigned int rows
132                                           ,double minx, double maxx, double miny, double maxy){
133
134   Qwt3D::GridData* gridPtr = (Qwt3D::GridData*)actualData_p;
135   
136   gridPtr->setPeriodic(false,false);
137   gridPtr->setSize(columns,rows);
138   readIn(*gridPtr,data,columns,rows,minx,maxx,miny,maxy);
139   calcNormals(*gridPtr);  
140   
141   updateData();
142   updateNormals();
143   
144   if( _createCoordinateSystemFlag ){
145     createCoordinateSystem();
146     
147     for (unsigned i=0; i!=coordinates()->axes.size(); ++i)
148       {
149         coordinates()->axes[i].setMajors(5);
150         coordinates()->axes[i].setMinors(3);
151       }
152     
153     coordinates()->axes[Qwt3D::Y1].setLabelString("Time");
154     coordinates()->axes[Qwt3D::Y2].setLabelString("Time");
155     coordinates()->axes[Qwt3D::Y3].setLabelString("Time");
156     coordinates()->axes[Qwt3D::Y4].setLabelString("Time");
157     coordinates()->axes[Qwt3D::Z1].setLabelString("Intensity (dB)");
158     coordinates()->axes[Qwt3D::Z2].setLabelString("Intensity (dB)");
159     coordinates()->axes[Qwt3D::Z3].setLabelString("Intensity (dB)");
160     coordinates()->axes[Qwt3D::Z4].setLabelString("Intensity (dB)");
161
162     coordinates()->axes[Qwt3D::X1].setLabelString((!_useCenterFrequencyFlag ? "Frequency (Hz)" : "Frequency (kHz)"));
163     coordinates()->axes[Qwt3D::X2].setLabelString((!_useCenterFrequencyFlag ? "Frequency (Hz)" : "Frequency (kHz)"));
164     coordinates()->axes[Qwt3D::X3].setLabelString((!_useCenterFrequencyFlag ? "Frequency (Hz)" : "Frequency (kHz)"));
165     coordinates()->axes[Qwt3D::X4].setLabelString((!_useCenterFrequencyFlag ? "Frequency (Hz)" : "Frequency (kHz)"));
166
167     // The QwtPlot3D Interface takes ownership of these items, so there is no need to delete them...
168     coordinates()->axes[Qwt3D::X1].setScale(new FrequencyScale(_useCenterFrequencyFlag, _centerFrequency));
169     coordinates()->axes[Qwt3D::X2].setScale(new FrequencyScale(_useCenterFrequencyFlag, _centerFrequency));
170     coordinates()->axes[Qwt3D::X3].setScale(new FrequencyScale(_useCenterFrequencyFlag, _centerFrequency));
171     coordinates()->axes[Qwt3D::X4].setScale(new FrequencyScale(_useCenterFrequencyFlag, _centerFrequency));
172
173     coordinates()->axes[Qwt3D::Y1].setScale(new TimeScale(this));
174     coordinates()->axes[Qwt3D::Y2].setScale(new TimeScale(this));
175     coordinates()->axes[Qwt3D::Y3].setScale(new TimeScale(this));
176     coordinates()->axes[Qwt3D::Y4].setScale(new TimeScale(this));
177
178     coordinates()->axes[Qwt3D::Z1].setScale(new IntensityScale(_waterfallData->GetFloorValue()));
179     coordinates()->axes[Qwt3D::Z2].setScale(new IntensityScale(_waterfallData->GetFloorValue()));
180     coordinates()->axes[Qwt3D::Z3].setScale(new IntensityScale(_waterfallData->GetFloorValue()));
181     coordinates()->axes[Qwt3D::Z4].setScale(new IntensityScale(_waterfallData->GetFloorValue()));
182
183     _createCoordinateSystemFlag = false;
184   }
185   
186   return true;
187 }
188
189 double Waterfall3DDisplayPlot::GetStartFrequency()const{
190   return _startFrequency;
191 }
192
193 double Waterfall3DDisplayPlot::GetStopFrequency()const{
194   return _stopFrequency;
195 }
196
197 void Waterfall3DDisplayPlot::PlotNewData(const double* dataPoints, const int64_t numDataPoints, const double timePerFFT, const timespec timestamp, const int droppedFrames){
198   if(numDataPoints > 0){
199     if(numDataPoints != _numPoints){
200       _numPoints = numDataPoints;
201
202       Reset();
203
204       if(isVisible()){
205         replot();
206       }
207
208       _createCoordinateSystemFlag = true;
209
210       _lastReplot = get_highres_clock();
211     }
212
213     _dataTimestamp = timestamp;
214     _timePerFFT = timePerFFT;
215
216     _waterfallData->addFFTData(dataPoints, numDataPoints, droppedFrames);
217     _waterfallData->IncrementNumLinesToUpdate();
218   }
219
220   // Allow at least a 50% duty cycle
221   if(diff_timespec(get_highres_clock(), _lastReplot) > _displayIntervalTime){
222     // Only update when window is visible
223     if(isVisible()){
224       replot();
225     }
226
227     _lastReplot = get_highres_clock();
228   }
229 }
230
231 void Waterfall3DDisplayPlot::SetIntensityRange(const double minIntensity, const double maxIntensity){
232   _waterfallData->SetFloorValue(minIntensity);
233   _waterfallData->setMinZ(0);
234   _waterfallData->setMaxZ(maxIntensity-minIntensity);
235
236   _createCoordinateSystemFlag = true;
237
238   emit UpdatedLowerIntensityLevel(minIntensity);
239   emit UpdatedUpperIntensityLevel(maxIntensity);
240
241   SetIntensityColorMapType(_intensityColorMapType, _userDefinedLowIntensityColor, _userDefinedLowIntensityColor, true);
242 }
243
244 void Waterfall3DDisplayPlot::replot(){
245
246   if(!_initialized){
247     Init();
248   }
249   if(initializedGL()){
250     const timespec startTime = get_highres_clock();
251     
252     _waterfallData->create();
253     
254     legend()->setMajors(4);
255     legend()->setMinors(5);
256     double start, stop;
257     coordinates()->axes[Qwt3D::Z1].limits(start,stop);
258     legend()->setLimits( _waterfallData->GetFloorValue(), _waterfallData->GetFloorValue() + stop - start );
259
260     coordinates()->axes[Qwt3D::X1].limits(start,stop);
261
262     showColorLegend(true);
263
264     updateGL();
265
266     double differenceTime = (diff_timespec(get_highres_clock(), startTime));
267   
268     // Require at least a 20% duty cycle
269     differenceTime *= 4.0;
270     if(differenceTime > (1.0/5.0)){
271       _displayIntervalTime = differenceTime;
272     }
273   }
274 }
275
276 int Waterfall3DDisplayPlot::GetIntensityColorMapType()const{
277   return _intensityColorMapType;
278 }
279
280 void Waterfall3DDisplayPlot::SetIntensityColorMapType(const int newType, const QColor lowColor, const QColor highColor, const bool forceFlag, const bool noReplotFlag){
281   if(((_intensityColorMapType != newType) || forceFlag) || 
282      ((newType == INTENSITY_COLOR_MAP_TYPE_USER_DEFINED) &&
283       (lowColor.isValid() && highColor.isValid()))){
284
285     Waterfall3DColorMap* colorMap = new Waterfall3DColorMap();
286     colorMap->SetInterval(_waterfallData->minZ(), _waterfallData->maxZ());
287
288     switch(newType){
289     case INTENSITY_COLOR_MAP_TYPE_MULTI_COLOR:{
290       _intensityColorMapType = newType;
291       colorMap->setColorInterval(Qt::darkCyan, Qt::white);
292       colorMap->addColorStop(0.25, Qt::cyan);
293       colorMap->addColorStop(0.5, Qt::yellow);
294       colorMap->addColorStop(0.75, Qt::red);
295       setBackgroundColor(Qwt3D::Qt2GL(Qt::gray));
296       break;
297     }
298     case INTENSITY_COLOR_MAP_TYPE_WHITE_HOT:{
299       _intensityColorMapType = newType;
300       colorMap->setColorInterval(Qt::black, Qt::white);
301       setBackgroundColor(Qwt3D::Qt2GL(Qt::blue));
302       break;
303     }
304     case INTENSITY_COLOR_MAP_TYPE_BLACK_HOT:{
305       _intensityColorMapType = newType;
306       colorMap->setColorInterval(Qt::white, Qt::black);
307       setBackgroundColor(Qwt3D::Qt2GL(Qt::blue));
308       break;
309     }
310     case INTENSITY_COLOR_MAP_TYPE_INCANDESCENT:{
311       _intensityColorMapType = newType;
312       colorMap->setColorInterval(Qt::black, Qt::white);
313       colorMap->addColorStop(0.5, Qt::darkRed);
314       setBackgroundColor(Qwt3D::Qt2GL(Qt::gray));
315       break;
316     }
317     case INTENSITY_COLOR_MAP_TYPE_USER_DEFINED:{
318       _userDefinedLowIntensityColor = lowColor;
319       _userDefinedHighIntensityColor = highColor;
320       _intensityColorMapType = newType;
321       colorMap->setColorInterval(_userDefinedLowIntensityColor, _userDefinedHighIntensityColor);
322       setBackgroundColor(Qwt3D::Qt2GL(Qt::white));
323       break;
324     }
325     default:
326       colorMap->setColorInterval(Qt::black, Qt::white);
327       break;
328     }
329
330     // Qwt3D takes over destruction of this object...
331     setDataColor(colorMap);
332
333     if(!noReplotFlag){
334       // Draw again
335       replot();
336       
337       // Update the last replot timer
338       _lastReplot = get_highres_clock();
339     }
340   }
341 }
342
343 const QColor Waterfall3DDisplayPlot::GetUserDefinedLowIntensityColor()const{
344   return _userDefinedLowIntensityColor;
345 }
346
347 const QColor Waterfall3DDisplayPlot::GetUserDefinedHighIntensityColor()const{
348   return _userDefinedHighIntensityColor;
349 }
350
351 #endif /* WATERFALL_3D_DISPLAY_PLOT_C */