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);
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;
119 _useCenterFrequencyFlag = useCenterFrequencyFlag;
120 _centerFrequency = centerFreq;
124 // Only replot if screen is visible
131 bool Waterfall3DDisplayPlot::loadFromData(double** data, unsigned int columns, unsigned int rows
132 ,double minx, double maxx, double miny, double maxy){
134 Qwt3D::GridData* gridPtr = (Qwt3D::GridData*)actualData_p;
136 gridPtr->setPeriodic(false,false);
137 gridPtr->setSize(columns,rows);
138 readIn(*gridPtr,data,columns,rows,minx,maxx,miny,maxy);
139 calcNormals(*gridPtr);
144 if( _createCoordinateSystemFlag ){
145 createCoordinateSystem();
147 for (unsigned i=0; i!=coordinates()->axes.size(); ++i)
149 coordinates()->axes[i].setMajors(5);
150 coordinates()->axes[i].setMinors(3);
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)");
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)"));
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));
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));
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()));
183 _createCoordinateSystemFlag = false;
189 double Waterfall3DDisplayPlot::GetStartFrequency()const{
190 return _startFrequency;
193 double Waterfall3DDisplayPlot::GetStopFrequency()const{
194 return _stopFrequency;
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;
208 _createCoordinateSystemFlag = true;
210 _lastReplot = get_highres_clock();
213 _dataTimestamp = timestamp;
214 _timePerFFT = timePerFFT;
216 _waterfallData->addFFTData(dataPoints, numDataPoints, droppedFrames);
217 _waterfallData->IncrementNumLinesToUpdate();
220 // Allow at least a 50% duty cycle
221 if(diff_timespec(get_highres_clock(), _lastReplot) > _displayIntervalTime){
222 // Only update when window is visible
227 _lastReplot = get_highres_clock();
231 void Waterfall3DDisplayPlot::SetIntensityRange(const double minIntensity, const double maxIntensity){
232 _waterfallData->SetFloorValue(minIntensity);
233 _waterfallData->setMinZ(0);
234 _waterfallData->setMaxZ(maxIntensity-minIntensity);
236 _createCoordinateSystemFlag = true;
238 emit UpdatedLowerIntensityLevel(minIntensity);
239 emit UpdatedUpperIntensityLevel(maxIntensity);
241 SetIntensityColorMapType(_intensityColorMapType, _userDefinedLowIntensityColor, _userDefinedLowIntensityColor, true);
244 void Waterfall3DDisplayPlot::replot(){
250 const timespec startTime = get_highres_clock();
252 _waterfallData->create();
254 legend()->setMajors(4);
255 legend()->setMinors(5);
257 coordinates()->axes[Qwt3D::Z1].limits(start,stop);
258 legend()->setLimits( _waterfallData->GetFloorValue(), _waterfallData->GetFloorValue() + stop - start );
260 coordinates()->axes[Qwt3D::X1].limits(start,stop);
262 showColorLegend(true);
266 double differenceTime = (diff_timespec(get_highres_clock(), startTime));
268 // Require at least a 20% duty cycle
269 differenceTime *= 4.0;
270 if(differenceTime > (1.0/5.0)){
271 _displayIntervalTime = differenceTime;
276 int Waterfall3DDisplayPlot::GetIntensityColorMapType()const{
277 return _intensityColorMapType;
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()))){
285 Waterfall3DColorMap* colorMap = new Waterfall3DColorMap();
286 colorMap->SetInterval(_waterfallData->minZ(), _waterfallData->maxZ());
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));
298 case INTENSITY_COLOR_MAP_TYPE_WHITE_HOT:{
299 _intensityColorMapType = newType;
300 colorMap->setColorInterval(Qt::black, Qt::white);
301 setBackgroundColor(Qwt3D::Qt2GL(Qt::blue));
304 case INTENSITY_COLOR_MAP_TYPE_BLACK_HOT:{
305 _intensityColorMapType = newType;
306 colorMap->setColorInterval(Qt::white, Qt::black);
307 setBackgroundColor(Qwt3D::Qt2GL(Qt::blue));
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));
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));
326 colorMap->setColorInterval(Qt::black, Qt::white);
330 // Qwt3D takes over destruction of this object...
331 setDataColor(colorMap);
337 // Update the last replot timer
338 _lastReplot = get_highres_clock();
343 const QColor Waterfall3DDisplayPlot::GetUserDefinedLowIntensityColor()const{
344 return _userDefinedLowIntensityColor;
347 const QColor Waterfall3DDisplayPlot::GetUserDefinedHighIntensityColor()const{
348 return _userDefinedHighIntensityColor;
351 #endif /* WATERFALL_3D_DISPLAY_PLOT_C */