00001
00012 #include <QMouseEvent>
00013 #include <cmath>
00014 #include <deque>
00015 #include "UrgDataDraw.h"
00016 #include "RangeSensor.h"
00017 #include "ticks.h"
00018 #include <cstdio>
00019
00020 using namespace qrk;
00021 using namespace std;
00022
00023
00024 namespace
00025 {
00026 typedef vector<Point3d<int> > Points;
00027
00028 typedef struct
00029 {
00030 Points points;
00031 qrk::Point3d<int> rotate;
00032 int timestamp;
00033 vector<long> intensity;
00034 } Line;
00035
00036 typedef deque<Line> Lines;
00037 }
00038
00039
00040 struct UrgDataDraw::pImpl
00041 {
00042 enum {
00043
00044 AliveMsec = 20,
00045 };
00046
00047 QColor clear_color_;
00048 vector<long> data_;
00049 vector<long> intensity_data_;
00050 size_t data_max_;
00051 long length_min_;
00052 long length_max_;
00053
00054 Lines saved_lines_data_;
00055 Lines normal_lines_data_;
00056 Line recent_line_data_;
00057
00058 QPoint last_pos_;
00059 int x_rot_;
00060 int y_rot_;
00061 int z_rot_;
00062
00063 bool h_type_;
00064 bool front_only_;
00065 bool pre_record_;
00066
00067 int magnify_;
00068 bool no_plot_;
00069 bool intensity_mode_;
00070
00071 vector<Point3d<double> > color_table_;
00072
00073
00074 pImpl(void)
00075 : clear_color_(Qt::black), data_max_(0),
00076 length_min_(0), length_max_(0),
00077 x_rot_(0), y_rot_(0), z_rot_(0),
00078 h_type_(false), front_only_(false), pre_record_(false),
00079 magnify_(50),
00080 no_plot_(false), intensity_mode_(false)
00081 {
00082
00083 for (int mm_height = 0; mm_height < 1000; ++mm_height) {
00084 QColor color;
00085 color.setHsv(static_cast<int>(360.0 * mm_height / 1000.0), 255, 255);
00086
00087 int r, g, b;
00088 color.getRgb(&r, &g, &b);
00089 color_table_.push_back(Point3d<double>(r / 255.0, g / 255.0, b / 255.0));
00090 }
00091 }
00092
00093
00094 void initializeForm(UrgDataDraw* parent)
00095 {
00096 static_cast<void>(parent);
00097 parent->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00098 }
00099
00100
00101 void initializeGL(UrgDataDraw* parent)
00102 {
00103 parent->qglClearColor(clear_color_);
00104 glEnable(GL_DEPTH_TEST);
00105 glEnable(GL_CULL_FACE);
00106 glEnable(GL_TEXTURE_2D);
00107 }
00108
00109
00110 void paintGL(UrgDataDraw* parent)
00111 {
00112 parent->qglClearColor(clear_color_);
00113 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00114
00115 glLoadIdentity();
00116
00117 glRotated(x_rot_ / 16.0, 1.0, 0.0, 0.0);
00118 glRotated(y_rot_ / 16.0, 0.0, 1.0, 0.0);
00119 glRotated((z_rot_ / 16.0) + 90, 0.0, 0.0, 1.0);
00120
00121
00122 while ((! normal_lines_data_.empty()) &&
00123 ((normal_lines_data_.front().timestamp + AliveMsec) < ticks())) {
00124 normal_lines_data_.pop_front();
00125 }
00126
00127 glBegin(GL_POINTS);
00128
00129
00130 double ratio = (1.0 / 2.0) + (5.0 * magnify_ / 100.0);
00131
00132
00133 if (! no_plot_) {
00134 for (Lines::iterator line_it = normal_lines_data_.begin();
00135 line_it != normal_lines_data_.end(); ++line_it) {
00136
00137 drawLine(line_it, false, ratio);
00138 }
00139 }
00140
00141
00142 for (Lines::iterator line_it = saved_lines_data_.begin();
00143 line_it != saved_lines_data_.end(); ++line_it) {
00144 drawLine(line_it, true, ratio);
00145 }
00146
00147 if (! no_plot_) {
00148
00149 drawLaser(recent_line_data_, ratio);
00150 }
00151 glEnd();
00152 }
00153
00154 void drawLaser(Line& line, double ratio)
00155 {
00156 glColor3d(0.6, 0.0, 0.0);
00157
00158 int index = 0;
00159 for (Points::iterator it = line.points.begin();
00160 it != line.points.end(); ++it, ++index) {
00161
00162 if ((it->x == 0) && (it->y == 0) && (it->z == 0)) {
00163 continue;
00164 }
00165
00166 if ((index & 0x3) == 0x00) {
00167 glBegin(GL_LINE_STRIP);
00168 glVertex3d(0.0, 0.0, 0.0);
00169 glVertex3d(it->x * ratio, it->y * ratio, it->z * ratio);
00170 glEnd();
00171 }
00172 }
00173 }
00174
00175
00176 void drawLine(Lines::iterator line, bool record, double ratio)
00177 {
00178 if (! record) {
00179
00180 double gradation =
00181 1.0 * (AliveMsec - (ticks() - line->timestamp)) / AliveMsec;
00182 glColor3d(1.0 * gradation, 1.0 * gradation, 1.0 * gradation);
00183
00184 } else {
00185
00186 glColor3d(0.0, 1.0, 0.0);
00187 }
00188
00189 int index = 0;
00190 for (Points::iterator it = line->points.begin();
00191 it != line->points.end(); ++it, ++index) {
00192
00193 if (record) {
00194 if (intensity_mode_) {
00195
00196
00197 int ratio = (line->intensity[index] + 1000) % 1000;
00198 Point3d<double>& color = color_table_[ratio];
00199 glColor3d(color.x, color.y, color.z);
00200
00201 } else {
00202
00203
00204 int mm = ((it->x % 1000) + 1000) % 1000;
00205 Point3d<double>& color = color_table_[mm];
00206 glColor3d(color.x, color.y, color.z);
00207 }
00208 }
00209 glVertex3d(it->x * ratio, it->y * ratio, it->z * ratio);
00210 }
00211 }
00212
00213
00214 void convertScanData(Line& line, RangeSensor& sensor)
00215 {
00216 data_max_ = sensor.maxScanLines();
00217 length_min_ = sensor.minDistance();
00218 length_max_ = sensor.maxDistance();
00219
00220 line.timestamp = ticks();
00221 int n = sensor.capture(data_, NULL);
00222 if (n <= 0) {
00223 return;
00224 }
00225
00226
00227 int intensity_n = sensor.captureWithIntensity(data_, intensity_data_,
00228 NULL);
00229 if (intensity_n == 0) {
00230
00231 intensity_mode_ = false;
00232 }
00233
00234
00235 for (int i = 0; i < n; ++i) {
00236 long length = data_[i];
00237 if ((length <= length_min_) || (length >= length_max_)) {
00238 continue;
00239 }
00240
00241 int index = i;
00242 double radian = sensor.index2rad(index);
00243 if (front_only_ && (fabs(radian) > M_PI / 2.0)) {
00244
00245 continue;
00246 }
00247
00248 Point3d<int> p;
00249 if (! h_type_) {
00250 p.x = static_cast<int>(length * cos(radian));
00251 p.y = static_cast<int>(length * sin(radian));
00252 p.z = 0;
00253 } else {
00254 p.x = 0;
00255 p.y = -static_cast<int>(length * cos(radian));
00256 p.z = -static_cast<int>(length * sin(radian));
00257 }
00258
00259 if (h_type_) {
00260 adjustTypeH(p, static_cast<int>(180.0 * radian / M_PI));
00261 }
00262
00263
00264 rotateX(p, line.rotate.x);
00265 rotateY(p, line.rotate.y);
00266 rotateY(p, line.rotate.z);
00267
00268 line.points.push_back(p);
00269 if (intensity_n > index) {
00270 line.intensity.push_back(intensity_data_[index]);
00271 }
00272 }
00273 }
00274
00275
00276 void adjustTypeH(Point3d<int>& p, int degree)
00277 {
00278 if ((degree > -20) && (degree < 20)) {
00279
00280
00281
00282 rotateZ(p, -90);
00283
00284
00285
00286
00287
00288
00289 } else if (degree < -45) {
00290
00291 rotateY(p, +(60 + 15 + 0));
00292
00293
00294
00295
00296 } else if (degree > +45) {
00297
00298 rotateY(p, -(60 + 15 + 0));
00299
00300
00301
00302 } else {
00303
00304 p = Point3d<int>(0, 0, 0);
00305 }
00306 }
00307
00308
00309 void rotateX(Point3d<int>& point, int rotate_degree)
00310 {
00311 double radian = rotate_degree * M_PI / 180.0;
00312 double z2 = (point.z * cos(-radian)) - (point.y * sin(-radian));
00313 double y2 = (point.z * sin(-radian)) + (point.y * cos(-radian));
00314
00315 point.z = static_cast<int>(z2);
00316 point.y = static_cast<int>(y2);
00317 }
00318
00319
00320 void rotateY(Point3d<int>& point, int rotate_degree)
00321 {
00322 double radian = -rotate_degree * M_PI / 180.0;
00323 double z2 = (point.z * cos(-radian)) - (point.x * sin(-radian));
00324 double x2 = (point.z * sin(-radian)) + (point.x * cos(-radian));
00325
00326 point.z = static_cast<int>(z2);
00327 point.x = static_cast<int>(x2);
00328 }
00329
00330
00331 void rotateZ(Point3d<int>& point, int rotate_degree)
00332 {
00333 double radian = rotate_degree * M_PI / 180.0;
00334 double x2 = (point.x * cos(-radian)) - (point.y * sin(-radian));
00335 double y2 = (point.x * sin(-radian)) + (point.y * cos(-radian));
00336
00337 point.x = static_cast<int>(x2);
00338 point.y = static_cast<int>(y2);
00339 }
00340
00341
00342 void addSaveLine(Line& line)
00343 {
00344 saved_lines_data_.push_back(line);
00345 }
00346
00347
00348 void addTemporaryLine(Line& line)
00349 {
00350 normal_lines_data_.push_back(line);
00351 }
00352
00353
00354 void setXRotation(UrgDataDraw* parent, int angle)
00355 {
00356 normalizeAngle(&angle);
00357 if (angle != x_rot_) {
00358 x_rot_ = angle;
00359 parent->updateGL();
00360 }
00361 }
00362
00363
00364 void setYRotation(UrgDataDraw* parent, int angle)
00365 {
00366 normalizeAngle(&angle);
00367 if (angle != y_rot_) {
00368 y_rot_ = angle;
00369 parent->updateGL();
00370 }
00371 }
00372
00373
00374 void setZRotation(UrgDataDraw* parent, int angle)
00375 {
00376 normalizeAngle(&angle);
00377 if (angle != z_rot_) {
00378 z_rot_ = angle;
00379 parent->updateGL();
00380 }
00381 }
00382
00383
00384 void normalizeAngle(int *angle)
00385 {
00386 while (*angle < 0) {
00387 *angle += 360 * 16;
00388 }
00389
00390 while (*angle > 360 * 16) {
00391 *angle -= 360 * 16;
00392 }
00393 }
00394 };
00395
00396
00397 UrgDataDraw::UrgDataDraw(QWidget* parent)
00398 : QGLWidget(parent), pimpl(new pImpl)
00399 {
00400 pimpl->initializeForm(this);
00401 }
00402
00403
00404 UrgDataDraw::~UrgDataDraw(void)
00405 {
00406 }
00407
00408
00409 void UrgDataDraw::initializeGL(void)
00410 {
00411 pimpl->initializeGL(this);
00412 }
00413
00414
00415 void UrgDataDraw::resizeGL(int width, int height)
00416 {
00417 glViewport(0, 0, width, height);
00418
00419 glMatrixMode(GL_PROJECTION);
00420 glLoadIdentity();
00421
00422 double aspect = 1.0 * width / height;
00423 glOrtho(-5000 * aspect, 5000 * aspect, -5000, 5000, -100000, 100000);
00424
00425 glMatrixMode(GL_MODELVIEW);
00426 }
00427
00428
00429 void UrgDataDraw::paintGL(void)
00430 {
00431 pimpl->paintGL(this);
00432 }
00433
00434
00435 QSize UrgDataDraw::minimumSizeHint(void) const
00436 {
00437 return QSize(150, 150);
00438 }
00439
00440
00441 void UrgDataDraw::redraw(RangeSensor& sensor,
00442 Point3d<int>& wii_rotate, bool record, bool no_plot)
00443 {
00444
00445
00446
00447 pimpl->no_plot_ = no_plot;
00448
00449
00450 Line line;
00451 line.rotate = wii_rotate;
00452 pimpl->convertScanData(line, sensor);
00453
00454 if (record) {
00455 if (pimpl->pre_record_ == false) {
00456
00457 pimpl->saved_lines_data_.clear();
00458 }
00459
00460 pimpl->addSaveLine(line);
00461
00462 } else {
00463
00464 pimpl->addTemporaryLine(line);
00465 }
00466
00467
00468 if (! line.points.empty()) {
00469 swap(pimpl->recent_line_data_, line);
00470 }
00471
00472 pimpl->pre_record_ = record;
00473
00474 updateGL();
00475 }
00476
00477
00478 void UrgDataDraw::clearCaptureData(void)
00479 {
00480 pimpl->normal_lines_data_.clear();
00481 pimpl->recent_line_data_.points.clear();
00482 update();
00483 }
00484
00485
00486 void UrgDataDraw::mousePressEvent(QMouseEvent *event)
00487 {
00488 pimpl->last_pos_ = event->pos();
00489 }
00490
00491
00492 void UrgDataDraw::mouseMoveEvent(QMouseEvent *event)
00493 {
00494 int dx = event->x() - pimpl->last_pos_.x();
00495 int dy = event->y() - pimpl->last_pos_.y();
00496
00497 if (event->buttons() & Qt::LeftButton) {
00498 pimpl->setXRotation(this, pimpl->x_rot_ + 8 * dy);
00499 pimpl->setZRotation(this, pimpl->z_rot_ + 8 * dx);
00500
00501 } else if (event->buttons() & Qt::RightButton) {
00502 pimpl->setXRotation(this, pimpl->x_rot_ + 8 * dy);
00503 pimpl->setYRotation(this, pimpl->y_rot_ + 8 * dx);
00504 }
00505 pimpl->last_pos_ = event->pos();
00506 }
00507
00508
00509 void UrgDataDraw::setTypeH(bool checked)
00510 {
00511 pimpl->h_type_ = checked;
00512 }
00513
00514
00515 void UrgDataDraw::setFrontOnly(bool front_only)
00516 {
00517 pimpl->front_only_ = front_only;
00518 }
00519
00520
00521 void UrgDataDraw::magnifyChanged(int value)
00522 {
00523 pimpl->magnify_ = value;
00524 update();
00525 }
00526
00527
00528 void UrgDataDraw::resetView(void)
00529 {
00530 pimpl->x_rot_ = 0;
00531 pimpl->y_rot_ = 0;
00532 pimpl->z_rot_ = 0;
00533 }
00534
00535
00536 void UrgDataDraw::loadVrml(const string& fileName)
00537 {
00538
00539
00540 FILE* fd = fopen(fileName.c_str(), "r");
00541 if (fd == NULL) {
00542 return;
00543 }
00544
00545 enum { BufferMax = 256 };
00546 char buffer[BufferMax];
00547
00548 bool in_data = false;
00549
00550 Line line_data;
00551 while (fgets(buffer, BufferMax, fd) != NULL) {
00552
00553 if (strstr(buffer, "end") != NULL) {
00554
00555 break;
00556 }
00557
00558 if (in_data) {
00559 double x, y, z;
00560 if (sscanf(buffer, "%lf %lf %lf", &x, &y, &z) == 3) {
00561 Point3d<int> point(static_cast<int>(x * 1000.0),
00562 static_cast<int>(y * 1000.0),
00563 static_cast<int>(z * 1000.0));
00564 line_data.points.push_back(point);
00565 }
00566 }
00567
00568 if (strstr(buffer, "begin") != NULL) {
00569
00570 in_data = true;
00571 }
00572 }
00573
00574 pimpl->saved_lines_data_.clear();
00575 pimpl->saved_lines_data_.push_back(line_data);
00576 }
00577
00578
00579 void UrgDataDraw::saveVrml(const string& fileName)
00580 {
00581
00582
00583 const char header[] =
00584 "#VRML V2.0 utf8\n"
00585 "Shape\n"
00586 "{\n"
00587 " geometry PointSet\n"
00588 " {\n";
00589
00590 const char coord_header[] =
00591 " coord Coordinate\n"
00592 " {\n";
00593
00594 const char point_header[] =
00595 " point\n"
00596 " [\n";
00597
00598 const char point_footer[] =
00599 " ]\n";
00600
00601 const char coord_footer[] =
00602 " }\n";
00603
00604 const char color_header[] =
00605 " color Color\n"
00606 " {\n"
00607 " color\n"
00608 " [\n";
00609
00610 const char color_footer[] =
00611 " ]\n"
00612 " }\n";
00613
00614 const char footer[] =
00615 " }\n"
00616 "}\n";
00617
00618 FILE* fd = fopen(fileName.c_str(), "w");
00619 if (fd == NULL) {
00620 return;
00621 }
00622
00623
00624 fprintf(fd, "%s", header);
00625
00626
00627 fprintf(fd, "%s", coord_header);
00628 fprintf(fd, "%s", point_header);
00629 fprintf(fd, " # begin points.\n");
00630 for (Lines::iterator line_it = pimpl->saved_lines_data_.begin();
00631 line_it != pimpl->saved_lines_data_.end(); ++line_it) {
00632 for (Points::iterator it = line_it->points.begin();
00633 it != line_it->points.end(); ++it) {
00634
00635 fprintf(fd, " %.3f %.3f %.3f\n",
00636 it->x / 1000.0, it->y / 1000.0, it->z / 1000.0);
00637 }
00638 }
00639 fprintf(fd, " # end points.\n");
00640 fprintf(fd, "%s", point_footer);
00641 fprintf(fd, "%s", coord_footer);
00642
00643
00644 fprintf(fd, "%s", color_header);
00645 for (Lines::iterator line_it = pimpl->saved_lines_data_.begin();
00646 line_it != pimpl->saved_lines_data_.end(); ++line_it) {
00647 for (Points::iterator it = line_it->points.begin();
00648 it != line_it->points.end(); ++it) {
00649
00650 int mm = ((it->z % 1000) + 1000) % 1000;
00651 Point3d<double>& color = pimpl->color_table_[mm];
00652 fprintf(fd, " %f %f %f,\n", color.x, color.y, color.z);
00653 }
00654 }
00655 fprintf(fd, "%s", color_footer);
00656
00657
00658 fprintf(fd, "%s", footer);
00659 fclose(fd);
00660 }
00661
00662
00663 void UrgDataDraw::setIntensityMode(bool on)
00664 {
00665 pimpl->intensity_mode_ = on;
00666 }