rock_widget_collection  0.1
SonarPlot.cc
Go to the documentation of this file.
1 #include "./SonarPlot.h"
2 #include <iostream>
3 
4 using namespace std;
5 using namespace frame_helper;
6 
7 SonarPlot::SonarPlot(QWidget *parent)
8  : QFrame(parent), scaleX(1), scaleY(1), range(5), changedSize(true), changedSectorScan(false), isMultibeamSonar(true), continuous(true), enabledGrid(true)
9 {
10  motorStep.rad = 0;
11  lastDiffStep.rad = 0;
12  leftLimit.rad = 0;
13  rightLimit.rad = 0;
14 
15  // apply default colormap
16  applyColormap(COLORGRADIENT_JET);
17 
18  QPalette Pal(palette());
19  Pal.setColor(QPalette::Background, QColor(0,0,255));
20  setAutoFillBackground(true);
21  setPalette(Pal);
22 }
23 
25 {
26 }
27 
28 // process sonar data
29 void SonarPlot::setData(const base::samples::Sonar& sonar)
30 {
31  if (!sonar.beam_count || !sonar.bin_count)
32  return;
33 
34  isMultibeamSonar = (sonar.beam_count > 1);
35 
36  // process multibeam sonar data
37  if (isMultibeamSonar) {
38  if(changedSize
39  || sonar.bin_count != lastSonar.bin_count
40  || sonar.beam_count != lastSonar.beam_count
41  || !(sonar.bearings[0] == lastSonar.bearings[0])
42  || !((sonar.bearings[1] - sonar.bearings[0]) == (lastSonar.bearings[1] - lastSonar.bearings[0]))) {
43 
44  // set the transfer vector between image pixels and sonar data
46 
47  changedSize = false;
48  }
49  }
50 
51  // process scanning sonar data
52  else {
53 
54  // check if the motor step size is changed
55  bool changedMotorStep = lastSonar.beam_count && isMotorStepChanged(sonar.bearings[0]);
56 
57  if ((changedSize
58  || changedMotorStep
60  || sonar.bin_count != lastSonar.bin_count) && lastSonar.beam_count && motorStep.rad) {
61 
62  // set the transfer vector between image pixels and sonar data
64 
65  // if the number of bins, the motor step or the sector scan changes, the accumulated sonar data will be reseted
66  if (sonar.bin_count != lastSonar.bin_count || changedMotorStep || changedSectorScan)
67  sonarData.assign(numSteps * sonar.bin_count, 0.0);
68 
69  changedSize = false;
70  changedSectorScan = false;
71  }
72 
73  // add current beam to accumulated scanning sonar data
74  if (sonarData.size())
75  addScanningData(sonar);
76  }
77 
78  lastSonar = sonar;
79  update();
80 }
81 
82 // check is the motor step angle size is changed
83 bool SonarPlot::isMotorStepChanged(const base::Angle& bearing) {
84  base::Angle diffStep = bearing - lastSonar.bearings[0];
85  diffStep.rad = fabs(diffStep.rad);
86 
87  // if the sector scanning is enabled, the diffStep could be lower than motorStep when the bearing is closer to one of the corners
88  if (!continuous && (fabs((leftLimit - bearing).rad) < motorStep.rad || fabs((rightLimit - bearing).rad) < motorStep.rad)) {
89  lastDiffStep = diffStep;
90  return false;
91  }
92 
93  if (!motorStep.isApprox(diffStep) && lastDiffStep.isApprox(diffStep)) {
94  motorStep = diffStep;
95  numSteps = M_PI * 2 / motorStep.rad;
96  lastDiffStep = diffStep;
97  return true;
98  }
99 
100  lastDiffStep = diffStep;
101  return false;
102 }
103 
104 // add current beam to accumulated scanning sonar data
105 void SonarPlot::addScanningData(const base::samples::Sonar& sonar) {
106  int id_beam = round((numSteps - 1) * (sonar.bearings[0].rad + M_PI) / (2 * M_PI));
107  memcpy(&sonarData[id_beam * sonar.bin_count], &sonar.bins[0], sonar.bin_count * sizeof(float));
108 }
109 
110 void SonarPlot::paintEvent(QPaintEvent *)
111 {
112  if (!transfer.size())
113  return;
114 
115  QPainter painter(this);
116  painter.setRenderHint(QPainter::Antialiasing, true);
117 
118  // draw sonar image
119  QImage img(width(), height(), QImage::Format_RGB888);
120  img.fill(QColor(0, 0, 255));
121 
122  if (isMultibeamSonar)
123  sonarData = lastSonar.bins;
124 
125  for (unsigned int i = 0; i < transfer.size() && !changedSize; ++i) {
126  if (transfer[i] != -1) {
127  QColor c = colorMap[round(sonarData[transfer[i]] * 255)];
128  img.setPixel(i % width(), i / width(), qRgb(c.red(), c.green(), c.blue()));
129  }
130  }
131 
132  painter.drawImage(0, 0, img);
133 
134  // draw overlay
135  drawOverlay();
136 
137 }
138 
139 void SonarPlot::resizeEvent ( QResizeEvent * event )
140 {
141  scaleX = 0.2;
142  if(width()>400){
143  scaleX = double(width())/(BASE_WIDTH-134);
144  }
145  scaleY = 0.2;
146  if(height()>200){
147  scaleY = double(height()-100)/(BASE_HEIGHT-100);
148  }
149  origin.setX(width()/2);
150  isMultibeamSonar ? origin.setY(height() - 30) : origin.setY(height() / 2);
151  changedSize=true;
152  QWidget::resizeEvent (event);
153 }
154 
156 {
157  QPainter painter(this);
158  painter.setRenderHint(QPainter::Antialiasing, true);
159 
160  // draw color pallete
161  for(size_t i = 0; i < 256; i++) {
162  painter.setPen(QPen(colorMap[i]));
163  painter.drawRect(width() - 30,height() - 10 -i * 2, 20, 2);
164  }
165 
166  if(!enabledGrid)
167  return;
168 
169  // draw sonar grid
170  painter.setPen(QPen(Qt::white));
171 
172  // multibeam sonar
173  if (isMultibeamSonar) {
174 
175  base::Angle sectorSize = base::Angle::fromRad((lastSonar.beam_width.rad / lastSonar.beam_count) * (lastSonar.beam_count - 1));
176 
177  for(int i=1;i<=5;i++){
178  painter.drawArc(origin.x() - i * scaleX * 100, origin.y() - i * scaleY * 100, i * 200 * scaleX, i * 200 * scaleY, (90 - sectorSize.getDeg() / 2) * 16, sectorSize.getDeg() * 16);
179  QString str = QString::number(i * range * 1.0 / 5);
180  int x = origin.x() + i * 100 * scaleX * sin(sectorSize.rad / 2);
181  int y = height() - i * 100 * scaleY * cos(sectorSize.rad / 2);
182  painter.drawText(x,y-5,str);
183 
184  base::Angle ang = lastSonar.bearings[((lastSonar.beam_count - 1) * 1.0 / 4) * (i-1)];
185  QPoint point(origin.rx() + BINS_REF_SIZE * sin(ang.rad) * scaleX, origin.ry() - BINS_REF_SIZE * cos(ang.rad) * scaleY);
186  painter.drawLine(origin, point);
187  str = QString::number(ang.getDeg(), 'f', 1);
188  painter.drawText(point.x() - 10, point.y() - 10, str);
189  }
190  }
191 
192  // scanning sonar
193  else {
194  double offsetX = BINS_REF_SIZE * 0.75 * scaleX;
195  double offsetY = BINS_REF_SIZE * 0.55 * scaleY;
196  painter.drawLine(QPoint(origin.rx(), origin.ry() - offsetY), QPoint(origin.rx(), origin.ry() + offsetY));
197  painter.drawLine(QPoint(origin.rx() - offsetX, origin.ry()), QPoint(origin.rx() + offsetX, origin.ry()));
198 
199  for (int i = 1; i <= 5; ++i) {
200  int x = i * offsetX / 5;
201  int y = i * offsetY / 5;
202  painter.drawEllipse(origin, x, y);
203  QString str_radius = QString::number(i * range * 1.0 / 5);
204  painter.drawText(origin.rx() + x + 2, origin.ry() - 5, str_radius);
205  }
206 
207  QString str = QString::number(lastSonar.bearings[0].getDeg(), 'f', 1);
208  QPoint point(origin.rx() - offsetX * sin(lastSonar.bearings[0].rad), origin.ry() - offsetY * cos(lastSonar.bearings[0].rad));
209  painter.setPen(QPen(Qt::green));
210  painter.drawLine(origin, point);
211  painter.drawText(point.x() - 10, point.y() - 10, str);
212 
213  if (!continuous) {
214  QPoint point1(origin.rx() - offsetX * sin(leftLimit.rad), origin.ry() - offsetY * cos(leftLimit.rad));
215  QPoint point2(origin.rx() - offsetX * sin(rightLimit.rad), origin.ry() - offsetY * cos(rightLimit.rad));
216  painter.drawLine(origin, point1);
217  painter.drawLine(origin, point2);
218  }
219  }
220 }
221 
222 
223 void SonarPlot::rangeChanged(int value)
224 {
225  range = value;
226 }
227 
228 // update the current palette
230  applyColormap((ColorGradientType) index);
231 }
232 
233 // enable/disable the sonar grid
234 void SonarPlot::gridChanged(bool value){
235  enabledGrid = value;
236 }
237 
238 // update the sector scan (for scanning sonars)
239 void SonarPlot::setSectorScan(bool continuous, base::Angle leftLimit, base::Angle rightLimit){
240 
241  // if the parameters changes, the screen will be clean
242  if (this->continuous != continuous
243  || ((this->leftLimit.rad != leftLimit.rad || this->rightLimit.rad != rightLimit.rad) && !continuous))
244  changedSectorScan = true;
245 
246  this->continuous = continuous;
247  this->leftLimit = leftLimit;
248  this->rightLimit = rightLimit;
249 }
250 
251 // applies a color gradient
252 void SonarPlot::applyColormap(ColorGradientType type){
253 
254  heatMapGradient.colormapSelector(type);
255 
256  colorMap.clear();
257  try {
258  float red, green, blue;
259  for (int i = 0; i < 256; ++i) {
260  heatMapGradient.getColorAtValue((1.0 / 255) * i, red, green, blue);
261  colorMap.push_back(QColor(red * 255, green * 255, blue * 255));
262  }
263  } catch (const std::out_of_range& e) {
264  std::cout << e.what() << std::endl;
265  }
266 }
267 
268 // set the transfer vector between image pixels and sonar data (for multibeam sonars)
269 void SonarPlot::generateMultibeamTransferTable(const base::samples::Sonar& sonar) {
270 
271  transfer.clear();
272 
273  // set the origin
274  origin.setY(height() - 30);
275 
276  // check pixels
277  for (int j = 0; j < height(); j++) {
278  int beam_idx = 0;
279  for (int i = 0; i < width(); i++) {
280 
281  QPoint point(i - origin.x(), j - origin.y());
282  point.rx() /= scaleX * BINS_REF_SIZE / sonar.bin_count;
283  point.ry() /= scaleY * BINS_REF_SIZE / sonar.bin_count;
284 
285  double radius = sqrt(point.x() * point.x() + point.y() * point.y());
286  double angle = atan2(point.x(), -point.y());
287 
288  // pixels out of sonar image
289  if (angle < sonar.bearings[0].rad || angle > sonar.bearings[sonar.beam_count - 1].rad || radius > sonar.bin_count || !radius || j > origin.y())
290  transfer.push_back(-1);
291 
292  // pixels in the sonar image
293  else {
294  while (angle < sonar.bearings[beam_idx].rad || angle >= sonar.bearings[beam_idx + 1].rad)
295  beam_idx++;
296  transfer.push_back(beam_idx * sonar.bin_count + radius);
297  }
298  }
299  }
300 }
301 
302 // set the transfer vector between image pixels and sonar data (for scanning sonars)
303 void SonarPlot::generateScanningTransferTable(const base::samples::Sonar& sonar) {
304 
305  transfer.clear();
306 
307  // check motor step value
308  if (!motorStep.rad)
309  return;
310 
311  // set the origin
312  origin.setY(height() / 2);
313 
314  // check pixels
315  for (int j = 0; j < height(); j++) {
316  for (int i = 0; i < width(); i++) {
317 
318  QPoint point(i - origin.x(), j - origin.y());
319  point.rx() /= scaleX * BINS_REF_SIZE * 0.75 / sonar.bin_count;
320  point.ry() /= scaleY * BINS_REF_SIZE * 0.55 / sonar.bin_count;
321 
322  double radius = sqrt(point.x() * point.x() + point.y() * point.y());
323 
324  // pixels out of sonar image
325  if (radius > sonar.bin_count || !radius)
326  transfer.push_back(-1);
327 
328  // pixels in the sonar image
329  else {
330  double angle = atan2(-point.x(), -point.y());
331  int idBeam = round((numSteps - 1) * (angle + M_PI) / (2 * M_PI));
332  transfer.push_back(idBeam * sonar.bin_count + radius);
333  }
334  }
335  }
336 }
void applyColormap(ColorGradientType type)
Definition: SonarPlot.cc:252
#define BASE_WIDTH
Definition: SonarPlot.h:9
void drawOverlay()
Definition: SonarPlot.cc:155
void addScanningData(const base::samples::Sonar &sonar)
Definition: SonarPlot.cc:105
SonarPlot(QWidget *parent=0)
Definition: SonarPlot.cc:7
bool enabledGrid
Definition: SonarPlot.h:45
void generateScanningTransferTable(const base::samples::Sonar &sonar)
Definition: SonarPlot.cc:303
ColorGradient heatMapGradient
Definition: SonarPlot.h:49
base::Angle motorStep
Definition: SonarPlot.h:50
bool continuous
Definition: SonarPlot.h:44
base::Angle leftLimit
Definition: SonarPlot.h:51
bool changedSize
Definition: SonarPlot.h:41
base::Angle lastDiffStep
Definition: SonarPlot.h:50
void rangeChanged(int)
Definition: SonarPlot.cc:223
virtual ~SonarPlot()
Definition: SonarPlot.cc:24
int range
Definition: SonarPlot.h:39
void setData(const base::samples::Sonar &sonar)
Definition: SonarPlot.cc:29
std::vector< float > sonarData
Definition: SonarPlot.h:52
void gridChanged(bool)
Definition: SonarPlot.cc:234
int numSteps
Definition: SonarPlot.h:40
#define BASE_HEIGHT
Definition: SonarPlot.h:10
QPoint origin
Definition: SonarPlot.h:46
base::samples::Sonar lastSonar
Definition: SonarPlot.h:36
double scaleY
Definition: SonarPlot.h:38
bool isMultibeamSonar
Definition: SonarPlot.h:43
void resizeEvent(QResizeEvent *event)
Definition: SonarPlot.cc:139
void paintEvent(QPaintEvent *event)
Definition: SonarPlot.cc:110
base::Angle rightLimit
Definition: SonarPlot.h:51
bool changedSectorScan
Definition: SonarPlot.h:42
std::vector< QColor > colorMap
Definition: SonarPlot.h:48
double scaleX
Definition: SonarPlot.h:37
void generateMultibeamTransferTable(const base::samples::Sonar &sonar)
Definition: SonarPlot.cc:269
bool isMotorStepChanged(const base::Angle &bearing)
Definition: SonarPlot.cc:83
void setSectorScan(bool continuous, base::Angle leftLimit, base::Angle rightLimit)
Definition: SonarPlot.cc:239
#define BINS_REF_SIZE
Definition: SonarPlot.h:11
void sonarPaletteChanged(int)
Definition: SonarPlot.cc:229
std::vector< int > transfer
Definition: SonarPlot.h:47