SoDaRadio-5.0.3-master:8901fb5
soda_wfall.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2017 Matthew H. Reilly (kb1vc)
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8 
9  Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11  Redistributions in binary form must reproduce the above copyright
12  notice, this list of conditions and the following disclaimer in
13  the documentation and/or other materials provided with the
14  distribution.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include <iostream>
30 #include <boost/format.hpp>
31 #include <cmath>
32 
33 #include <qwt/qwt_plot_grid.h>
34 #include <qwt/qwt_scale_engine.h>
35 #include <qwt/qwt_scale_widget.h>
36 #include <qwt/qwt_color_map.h>
37 
38 #include "soda_wfall.hpp"
39 
40 using namespace GUISoDa;
41 
42 #define FIVECOLOR
43 
44 
45 class GUISoDa::WFColorMap : public QwtLinearColorMap
46 {
47 public:
48  enum MapSelector {C5, C7};
50  : QwtLinearColorMap(Qt::black, Qt::red, QwtColorMap::RGB)
51  {
52  if(sel == C5) {
53  addColorStop(1.0, Qt::red);
54  addColorStop(0.75, Qt::yellow);
55  // addColorStop(0.50, Qt::green);
56  addColorStop(0.25, Qt::cyan);
57  addColorStop(0.0, Qt::blue);
58  }
59  else {
60  addColorStop(1.0, Qt::white);
61  addColorStop(0.84, Qt::red);
62  addColorStop(0.67, Qt::yellow);
63  addColorStop(0.5, Qt::green);
64  addColorStop(0.33, Qt::cyan);
65  addColorStop(0.16, Qt::blue);
66  addColorStop(0.0, Qt::black);
67  }
68  }
69 };
70 
71 
72 class GUISoDa::PlotSpectrogram : public QwtPlotSpectrogram
73 {
74 public:
75  explicit PlotSpectrogram() : QwtPlotSpectrogram() {
76  rescan_required = false;
77  }
78 
80  }
81 
82  void setData(QwtRasterData * dp) {
83  data_p = dp;
84  QwtPlotSpectrogram::setData(dp);
85  }
86 
87  void rescan() {
88  rescan_required = true;
89  }
90 
91 protected:
92  QImage renderImage(
93  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
94  const QRectF &area, const QSize &imageSize ) const
95  {
96  const QwtColorMap * cmap_p = colorMap();
97 
98  if ( imageSize.isEmpty() || data_p == NULL
99  || cmap_p == NULL )
100  {
101  return QImage();
102  }
103 
104  const QwtInterval intensityRange = data_p->interval( Qt::ZAxis );
105  if ( !intensityRange.isValid() )
106  return QImage();
107 
108  QImage::Format format = ( cmap_p->format() == QwtColorMap::RGB )
109  ? QImage::Format_ARGB32 : QImage::Format_Indexed8;
110 
111  data_p->initRaster(area, imageSize);
112 
113  QImage image( imageSize, format );
114  if(rescan_required || (lastSize != imageSize)) {
115  rescan_required = false;
116  const QRect tile( 0, 0, image.width(), image.height() );
117  renderTile( xMap, yMap, tile, &image );
118  lastSize = imageSize;
119  }
120  else {
121  // copy all the lines from the old image to the new image
122  uchar * to_start = image.bits();
123  uchar * from_start = saved_image.scanLine(1);
124  memcpy(to_start, from_start, image.byteCount() - image.bytesPerLine());
125  // scan a new line in.
126  const QRect tile( 0, image.height()-1, image.width(), 1);
127  renderTile( xMap, yMap, tile, &image );
128  }
129  saved_image = image; // .copy();
130  return image;
131  }
132 
133  mutable QSize lastSize;
134  mutable QImage saved_image;
135  mutable bool rescan_required;
136  QwtRasterData * data_p;
137 };
138 
139 GUISoDa::WFall::WFall(QWidget *parent) :
140  QwtPlot(parent)
141 {
142  initPlot();
143 }
144 
146 {
147 }
148 
149 
151 {
153  sgram->setRenderThreadCount(1);
154 
155  sgram->setColorMap(new GUISoDa::WFColorMap());
156  wfall_data = new WFallData();
158  sgram->attach(this);
159  right_axis = axisWidget( QwtPlot::yRight);
160  right_axis->setTitle("Signal Strength");
161  right_axis->setColorBarEnabled(true);
162  right_axis->setColorBarWidth(10);
163  right_axis->setColorMap(wfall_data->interval(Qt::ZAxis), new GUISoDa::WFColorMap());
164 
165  setAxisScale(QwtPlot::yRight, wfall_data->interval(Qt::ZAxis).minValue(),
166  wfall_data->interval(Qt::ZAxis).maxValue());
167  enableAxis(QwtPlot::yRight, true);
168  enableAxis(QwtPlot::yLeft, false);
169 
170  freq_scale_p = new FreqScaleDraw();
171  setAxisScaleDraw(QwtPlot::xBottom, freq_scale_p);
172  setFreqCenter(1.0e6);
173  freq_span = 200e3;
174 
175  sgram->setDisplayMode(QwtPlotSpectrogram::ImageMode, true);
176  sgram->setDefaultContourPen(QPen(Qt::black, 0));
177 
178  picker_p = new WFallPicker(QwtPlot::xBottom, QwtPlot::yLeft, canvas());
179  connect(picker_p, SIGNAL(selected(const QPointF&)), SLOT(pickPoint(const QPointF&)));
180 
181  last_input_cfreq = 0.0;
182 
183  setMarkerOffset(-1.0, 1.0);
184 
185  replot();
186  show();
187 }
188 
190 {
191  if((cfreq + 0.5 * freq_span) > (last_input_cfreq + 0.5 * spectrum_input_span)) {
192  cfreq = (last_input_cfreq + 0.5 * (spectrum_input_span - freq_span));
193  }
194  if((cfreq - 0.5 * freq_span) < (last_input_cfreq - 0.5 * spectrum_input_span)) {
195  cfreq = (last_input_cfreq - 0.5 * (spectrum_input_span - freq_span));
196  }
197  return cfreq;
198 }
199 
200 void GUISoDa::WFall::setFreqCenter(double cfreq, bool check_boundary)
201 {
202  if(check_boundary) {
203  cfreq = correctCenterFreq(cfreq);
204  }
205  center_freq = cfreq;
207  setAxisScale(QwtPlot::xBottom, cfreq - 0.5 * freq_span, cfreq + 0.5 * freq_span);
208  sgram->rescan();
209  replot();
210 }
211 
212 void GUISoDa::WFall::setFreqSpan(double span, bool check_boundary)
213 {
214  freq_span = span;
215  if(check_boundary && (center_freq != 0.0)) {
217  // and make sure we don't scroll the marker away.
218  if((marker_freq < (center_freq - 0.5 * freq_span)) ||
219  (marker_freq > (center_freq + 0.5 * freq_span))) {
221  }
222  }
223 
225  setAxisScale(QwtPlot::xBottom, center_freq - 0.5 * freq_span, center_freq + 0.5 * freq_span);
226  sgram->rescan();
227  replot();
228 }
229 
230 
231 void GUISoDa::WFall::updateData(double cfreq, float * spect)
232 {
233  last_input_cfreq = cfreq;
234  wfall_data->updateData(cfreq, spect);
235  replot();
236 }
237 
238 void GUISoDa::WFall::setMarkerOffset(double lo, double hi) {
239  marker_lo_offset = lo;
240  marker_hi_offset = hi;
242 }
243 
245 {
246  marker_freq = freq;
248 }
249 
250 void GUISoDa::WFall::pickPoint(const QPointF & pos)
251 {
252  double freq = pos.x() - marker_lo_offset;
253  setFreqMarker(freq);
254  emit xClick(freq);
255 }
256 
258 {
259  wfall_data->setDynamicRange(drange);
260  setZAxis();
261 }
262 
264 {
265  wfall_data->setRefLevel((double) reflvl);
266  setZAxis();
267 }
268 
270 {
271  const QwtInterval z_interval = wfall_data->interval(Qt::ZAxis);
272  right_axis->setColorMap(z_interval, new GUISoDa::WFColorMap());
273 
274  setAxisScale(QwtPlot::yRight, z_interval.minValue(),
275  z_interval.maxValue());
276 
277  sgram->rescan();
278 }
279 
WFColorMap(MapSelector sel=C5)
Definition: soda_wfall.cpp:49
void setFreqCenter(double cf, bool check_boundary=false)
Definition: soda_wfall.cpp:200
double marker_hi_offset
Definition: soda_wfall.hpp:101
QImage renderImage(const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &area, const QSize &imageSize) const
Definition: soda_wfall.cpp:92
void setFreqSpan(double fs, bool check_boundary=false)
Definition: soda_wfall.cpp:212
double last_input_cfreq
Definition: soda_wfall.hpp:115
void setFreqStep(double cf, double st)
void setMarkerOffset(double lo, double hi)
Definition: soda_wfall.cpp:238
QwtRasterData * data_p
Definition: soda_wfall.cpp:136
void setDynamicRange(double drange)
Definition: soda_wfall.cpp:257
PlotSpectrogram * sgram
Definition: soda_wfall.hpp:120
double correctCenterFreq(double cfreq)
Definition: soda_wfall.cpp:189
FreqScaleDraw * freq_scale_p
Definition: soda_wfall.hpp:124
void updateData(double cf, float *y)
Definition: soda_wfall.cpp:231
double marker_freq
Definition: soda_wfall.hpp:116
void setMarkers(double lo, double hi)
Definition: soda_wfall.hpp:97
WFall(QWidget *parent=0)
Definition: soda_wfall.cpp:139
void xClick(double x)
WFallPicker * picker_p
Definition: soda_wfall.hpp:122
void setRefLevel(int rlvl)
Definition: soda_wfall.cpp:263
void pickPoint(const QPointF &pos)
Definition: soda_wfall.cpp:250
QwtScaleWidget * right_axis
Definition: soda_wfall.hpp:126
virtual void updateData(double cfreq, float *spect)
double center_freq
Definition: soda_wfall.hpp:112
void setDynamicRange(double drange)
double marker_lo_offset
Definition: soda_wfall.hpp:100
void setData(QwtRasterData *dp)
Definition: soda_wfall.cpp:82
void setFreqMarker(double freq)
Definition: soda_wfall.cpp:244
double spectrum_input_span
Definition: soda_wfall.hpp:114
void setRefLevel(double reflvl)
WFallData * wfall_data
Definition: soda_wfall.hpp:119