1 #ifndef WATERFALL_3D_DISPLAY_PLOT_C
2 #define WATERFALL_3D_DISPLAY_PLOT_C
4 #include <Waterfall3DDisplayPlot.h>
6 #include <qwt3d_helper.h>
7 #include <qapplication.h>
9 Waterfall3DColorMap::Waterfall3DColorMap(): Qwt3D::Color(), QwtLinearColorMap(){
10 _interval.setInterval(0, 1.0);
14 Waterfall3DColorMap::~Waterfall3DColorMap(){
18 Qwt3D::RGBA Waterfall3DColorMap::operator()(double, double, double z)const{
19 return Qwt3D::RGBA(Qwt3D::Qt2GL(color(_interval, z)));
22 void Waterfall3DColorMap::SetInterval(const double minValue, const double maxValue){
23 _interval.setInterval(minValue, maxValue);
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));
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;
44 Waterfall3DDisplayPlot::Waterfall3DDisplayPlot(QWidget* parent):Qwt3D::SurfacePlot(parent){
46 _stopFrequency = 4000;
48 _createCoordinateSystemFlag = true;
54 _displayIntervalTime = (1.0/5.0); // 1/5 of a second between updates
56 timespec_reset(&_lastReplot);
58 _useCenterFrequencyFlag = false;
59 _centerFrequency = 0.0;
62 timespec_reset(&_dataTimestamp);
64 coordinates()->setAutoScale(false);
66 _waterfallData = new Waterfall3DData(_startFrequency, _stopFrequency, _numPoints, 200);
67 _waterfallData->assign(this);
68 _waterfallData->create();
70 _intensityColorMapType = -1;
71 SetIntensityColorMapType(INTENSITY_COLOR_MAP_TYPE_MULTI_COLOR, Qt::white, Qt::black, true, true);
73 legend()->setScale(Qwt3D::LINEARSCALE);
74 legend()->setTitleString("Intensity");
79 Waterfall3DDisplayPlot::~Waterfall3DDisplayPlot(){
80 delete _waterfallData;
83 void Waterfall3DDisplayPlot::Init(){
84 if(!_initialized && initializedGL()){
85 resize(parentWidget()->width(), parentWidget()->height());
87 // Attempting to prevent valgrind uninitialized variable errors in QwtPlot3d::Drawable class
88 glDisable(GL_POLYGON_OFFSET_FILL);
90 setPlotStyle(Qwt3D::FILLED);
92 setCoordinateStyle(Qwt3D::FRAME);
93 setFloorStyle(Qwt3D::FLOORDATA);
100 void Waterfall3DDisplayPlot::Reset(){
101 _waterfallData->ResizeData(_startFrequency, _stopFrequency, _numPoints);
102 _waterfallData->Reset();
105 setScale(1, static_cast<int>(((_stopFrequency - _startFrequency) / 200) ), 10);
108 _createCoordinateSystemFlag = true;
110 timespec_reset(&_dataTimestamp);
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)
121 double startFreq = constStartFreq / units;
122 double stopFreq = constStopFreq / units;
123 double centerFreq = constCenterFreq / units;
125 if(stopFreq > startFreq) {
126 _startFrequency = startFreq;
127 _stopFrequency = stopFreq;
129 _useCenterFrequencyFlag = useCenterFrequencyFlag;
130 _centerFrequency = centerFreq;
134 // Only replot if screen is visible
141 bool Waterfall3DDisplayPlot::loadFromData(double** data, unsigned int columns, unsigned int rows
142 ,double minx, double maxx, double miny, double maxy){
144 Qwt3D::GridData* gridPtr = (Qwt3D::GridData*)actualData_p;
146 gridPtr->setPeriodic(false,false);
147 gridPtr->setSize(columns,rows);
148 readIn(*gridPtr,data,columns,rows,minx,maxx,miny,maxy);
149 calcNormals(*gridPtr);
154 if( _createCoordinateSystemFlag ){
155 createCoordinateSystem();
157 for (unsigned i=0; i!=coordinates()->axes.size(); ++i)
159 coordinates()->axes[i].setMajors(5);
160 coordinates()->axes[i].setMinors(3);
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)");
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)"));
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));
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));
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()));
193 _createCoordinateSystemFlag = false;
199 double Waterfall3DDisplayPlot::GetStartFrequency()const{
200 return _startFrequency;
203 double Waterfall3DDisplayPlot::GetStopFrequency()const{
204 return _stopFrequency;
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;
218 _createCoordinateSystemFlag = true;
220 _lastReplot = get_highres_clock();
223 _dataTimestamp = timestamp;
224 _timePerFFT = timePerFFT;
226 _waterfallData->addFFTData(dataPoints, numDataPoints, droppedFrames);
227 _waterfallData->IncrementNumLinesToUpdate();
230 // Allow at least a 50% duty cycle
231 if(diff_timespec(get_highres_clock(), _lastReplot) > _displayIntervalTime){
232 // Only update when window is visible
237 _lastReplot = get_highres_clock();
241 void Waterfall3DDisplayPlot::SetIntensityRange(const double minIntensity, const double maxIntensity){
242 _waterfallData->SetFloorValue(minIntensity);
243 _waterfallData->setMinZ(0);
244 _waterfallData->setMaxZ(maxIntensity-minIntensity);
246 _createCoordinateSystemFlag = true;
248 emit UpdatedLowerIntensityLevel(minIntensity);
249 emit UpdatedUpperIntensityLevel(maxIntensity);
251 SetIntensityColorMapType(_intensityColorMapType, _userDefinedLowIntensityColor, _userDefinedLowIntensityColor, true);
254 void Waterfall3DDisplayPlot::replot(){
260 const timespec startTime = get_highres_clock();
262 _waterfallData->create();
264 legend()->setMajors(4);
265 legend()->setMinors(5);
267 coordinates()->axes[Qwt3D::Z1].limits(start,stop);
268 legend()->setLimits( _waterfallData->GetFloorValue(), _waterfallData->GetFloorValue() + stop - start );
270 coordinates()->axes[Qwt3D::X1].limits(start,stop);
272 showColorLegend(true);
276 double differenceTime = (diff_timespec(get_highres_clock(), startTime));
278 // Require at least a 20% duty cycle
279 differenceTime *= 4.0;
280 if(differenceTime > (1.0/5.0)){
281 _displayIntervalTime = differenceTime;
286 int Waterfall3DDisplayPlot::GetIntensityColorMapType()const{
287 return _intensityColorMapType;
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()))){
295 Waterfall3DColorMap* colorMap = new Waterfall3DColorMap();
296 colorMap->SetInterval(_waterfallData->minZ(), _waterfallData->maxZ());
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));
308 case INTENSITY_COLOR_MAP_TYPE_WHITE_HOT:{
309 _intensityColorMapType = newType;
310 colorMap->setColorInterval(Qt::black, Qt::white);
311 setBackgroundColor(Qwt3D::Qt2GL(Qt::blue));
314 case INTENSITY_COLOR_MAP_TYPE_BLACK_HOT:{
315 _intensityColorMapType = newType;
316 colorMap->setColorInterval(Qt::white, Qt::black);
317 setBackgroundColor(Qwt3D::Qt2GL(Qt::blue));
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));
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));
336 colorMap->setColorInterval(Qt::black, Qt::white);
340 // Qwt3D takes over destruction of this object...
341 setDataColor(colorMap);
347 // Update the last replot timer
348 _lastReplot = get_highres_clock();
353 const QColor Waterfall3DDisplayPlot::GetUserDefinedLowIntensityColor()const{
354 return _userDefinedLowIntensityColor;
357 const QColor Waterfall3DDisplayPlot::GetUserDefinedHighIntensityColor()const{
358 return _userDefinedHighIntensityColor;
361 #endif /* WATERFALL_3D_DISPLAY_PLOT_C */