se2ez
renderarea.cpp
Go to the documentation of this file.
1 /* Author: Constantinos Chamzas, Zachary Kingston */
2 
3 #include <iostream>
4 
5 #include <se2ez/core/log.h>
6 #include <se2ez/core/math.h>
7 #include <se2ez/core/robot.h>
8 #include <se2ez/core/state.h>
9 #include <se2ez/core/frame.h>
10 #include <se2ez/core/geometry.h>
11 
12 #include <se2ez/gui/renderarea.h>
13 #include <se2ez/gui/mainwindow.h>
14 
15 #include "ui_mainwindow.h"
16 #include "ui_renderarea.h"
17 
18 using namespace se2ez;
19 
20 ///
21 /// Geometry Drawers
22 ///
23 
25  : robot_(robot), state_(state)
26 {
27 }
28 
30  const RobotPtr &robot, const StatePtr &state)
31  : gui::RenderArea::GeometryDrawer(robot, state), doCollide(doCollide), colliding(colliding)
32 {
33 }
34 
36 {
37 }
38 
39 bool gui::RenderArea::CollideDrawer::frameCallback(RenderArea * /*area*/, QPainter & /*painter*/,
40  const FramePtr & /*frame*/)
41 {
42  return true;
43 }
44 
46  const FramePtr &frame, const GeometryPtr & /*geometry*/)
47 {
48  if (doCollide && colliding.find(frame->getName()) != colliding.end())
49  {
50  QPen pen(QColor(255, 0, 0));
51  pen.setWidth(3);
52  painter.setPen(pen);
53  }
54 
55  return true;
56 }
57 
59  bool doCollide, bool doMin, const CollisionManager::SignedDistance &minimum,
60  const CollisionManager::SignedDistanceMap &distances, const RobotPtr &robot, const StatePtr &state)
61  : gui::RenderArea::GeometryDrawer(robot, state)
62  , doCollide(doCollide)
63  , doMin(doMin)
64  , minimum(minimum)
65  , distances(distances)
66 {
67 }
68 
70 {
71 }
72 
73 bool gui::RenderArea::SignedDistanceDrawer::frameCallback(RenderArea * /*area*/, QPainter & /*painter*/,
74  const FramePtr & /*frame*/)
75 {
76  return true;
77 }
78 
80  const FramePtr &frame,
81  const GeometryPtr & /*geometry*/)
82 {
83  auto f = distances.find(frame->getName());
84  if (f != distances.end())
85  {
86  const CollisionManager::SignedDistance &sd = f->second;
87 
88  if ((doMin && frame->getName() == minimum.frame) || not doMin)
89  {
90  painter.save();
91  painter.resetTransform();
92 
93  QPen pen(QColor(255, 0, 0));
94  pen.setWidth(2);
95  painter.setPen(pen);
96 
97  int x, y, x2, y2, x3, y3, xt, yt;
98  area->toScreen(sd.point[0], sd.point[1], //
99  x, y);
100  area->toScreen(sd.point[0] + sd.normal[0], //
101  sd.point[1] + sd.normal[1], //
102  x2, y2);
103  area->toScreen(sd.point[0] + sd.normal[0] * 0.9, //
104  sd.point[1] + sd.normal[1] * 0.9, //
105  x3, y3);
106  area->toScreen(sd.point[0] + sd.normal[0] * 0.5, //
107  sd.point[1] + sd.normal[1] * 0.5, //
108  xt, yt);
109 
110  painter.drawLine(x, y, x2, y2);
111  painter.drawText(xt + 5, yt, QString(log::format("%1$+3.2f", sd.distance).c_str()));
112 
113  pen.setWidth(4);
114  painter.setPen(pen);
115  painter.drawLine(x2, y2, x3, y3);
116 
117  painter.restore();
118  }
119 
120  // Paint collisions red still
121  if (doCollide && sd.distance < 0)
122  {
123  QPen pen(QColor(255, 0, 0));
124  pen.setWidth(3);
125  painter.setPen(pen);
126  }
127  }
128 
129  return true;
130 }
131 
132 ///
133 /// Render Area
134 ///
135 
136 gui::RenderArea::RenderArea(QWidget *parent, MainWindow *mainwindow)
137  : QWidget(parent), ui_(new Ui::RenderArea), mainwidget_(mainwindow)
138 {
139  // ui_->setupUi(this);
140  setMouseTracking(true);
141 
142  QFont newFont = font();
143  newFont.setPixelSize(12);
144  setFont(newFont);
145 
146  QFontMetrics fontMetrics(newFont);
147  xBoundingRect_ = fontMetrics.boundingRect(tr("x"));
148  yBoundingRect_ = fontMetrics.boundingRect(tr("y"));
149 
150  setOriginX(x_);
151  setOriginY(y_);
152 }
153 
155 {
156  delete ui_;
157 }
158 
160 {
161  x_ = x;
162  origx_ = RATIO / scale_ * x_;
163 
164  mainwidget_->ui_->xSpinBox->blockSignals(true);
165  mainwidget_->ui_->xSpinBox->setValue(x_);
166  mainwidget_->ui_->xSpinBox->blockSignals(false);
167 }
168 
170 {
171  y_ = y;
172  origy_ = RATIO / scale_ * y_;
173 
174  mainwidget_->ui_->ySpinBox->blockSignals(true);
175  mainwidget_->ui_->ySpinBox->setValue(y_);
176  mainwidget_->ui_->ySpinBox->blockSignals(false);
177 }
178 
179 void gui::RenderArea::setScale(double scale)
180 {
181  if (scale < SCALE_BOUNDS[0])
182  scale = SCALE_BOUNDS[0];
183  if (scale > SCALE_BOUNDS[1])
184  scale = SCALE_BOUNDS[1];
185 
186  scale_ = scale;
187  setOriginX(x_);
188  setOriginY(y_);
189 
190  mainwidget_->ui_->zoomSpinBox->blockSignals(true);
191  mainwidget_->ui_->zoomSpinBox->setValue(scale);
192  mainwidget_->ui_->zoomSpinBox->blockSignals(false);
193 }
194 
195 void gui::RenderArea::drawAllFrames(QPainter &painter, RobotPtr robot, StatePtr state)
196 {
197  for (const auto &name : robot->getFrameNames())
198  {
199  const auto &fpose = tf::flattenIsometry(state->getPose(robot, name));
200 
201  painter.save();
202  QTransform t;
203  t.translate(fpose[0] * scale_ * ROBOT, fpose[1] * scale_ * ROBOT);
204  t.rotateRadians(fpose[2]);
205  painter.setTransform(t, true);
206  drawFrame(painter, QString::fromUtf8(name.c_str()));
207  painter.restore();
208  }
209 }
210 
211 void gui::RenderArea::drawGeometry(QPainter &painter, RobotPtr robot, StatePtr state,
212  gui::RenderArea::GeometryDrawerPtr drawer)
213 {
214  for (const auto &name : robot->getFrameNames())
215  {
216  const auto &fpose = tf::flattenIsometry(state->getPose(robot, name));
217  const auto &frame = robot->getFrameConst(name);
218 
219  // Performing the frame transform
220  painter.save();
221  QTransform t;
222  t.translate(fpose[0] * ROBOT * scale_, fpose[1] * ROBOT * scale_);
223  t.rotateRadians(fpose[2]);
224  painter.setTransform(t, true);
225 
226  if (drawer && !drawer->frameCallback(this, painter, frame))
227  continue;
228 
229  for (const auto &geom : frame->getGeometry())
230  {
231  const auto &color = geom->color;
232  const auto &offset = tf::flattenIsometry(geom->offset);
233 
234  // Performing the offset transform
235  painter.save();
236  QTransform offt;
237  offt.translate(offset[0] * ROBOT * scale_, offset[1] * ROBOT * scale_);
238  offt.rotateRadians(offset[2]);
239  painter.setTransform(offt, true);
240 
241  // Converting floats to RGBD colors
242  painter.setPen(QColor(255 * color[0], 255 * color[1], 255 * color[2], 255 * color[3]));
243 
244  if (drawer && !drawer->geometryCallback(this, painter, frame, geom))
245  continue;
246 
247  switch (geom->type)
248  {
249  case Geometry::BOX:
250  painter.drawRect(
251  -scale_ * ROBOT * (geom->dimensions[0]), -scale_ * ROBOT * (geom->dimensions[1]),
252  scale_ * 2 * ROBOT * geom->dimensions[0], scale_ * 2 * ROBOT * geom->dimensions[1]);
253  break;
254 
255  case Geometry::CIRCLE:
256  painter.drawEllipse(QPoint(0, 0), int(scale_ * ROBOT * geom->dimensions[0]),
257  int(scale_ * ROBOT * geom->dimensions[0]));
258  break;
259 
260  case Geometry::CONVEX:
261  case Geometry::SIMPLE:
262  {
263  QPoint points[geom->points.size()];
264  for (unsigned int i = 0; i < geom->points.size(); ++i)
265  points[i] =
266  QPoint(geom->points[i][0] * scale_ * ROBOT, geom->points[i][1] * scale_ * ROBOT);
267 
268  painter.drawPolygon(points, geom->points.size());
269  break;
270  }
271  default:
272  SE2EZ_ERROR("Geometry Type: %d does not exist", geom->type);
273  }
274 
275  painter.restore();
276  }
277 
278  painter.restore();
279  }
280 }
281 
283 {
284  // TODO: make this compatible with zoom
285  QPoint p = painter.window().bottomLeft();
286  QTransform t;
287  t.translate(p.x() + origx_ * scale_, p.y() - origy_ * scale_);
288  t.scale(1, -1);
289  painter.setTransform(t);
290 }
291 
292 void gui::RenderArea::drawGrid(QPainter &painter)
293 {
294  if (!mainwidget_->ui_->grid->isChecked())
295  return;
296 
297  QRect vp = painter.viewport();
298 
299  int vx, vy, tx, ty;
300  double vxd, vyd, txd, tyd;
301  vp.getCoords(&vx, &vy, &tx, &ty);
302 
303  toRobot(vx, vy, vxd, vyd);
304  toRobot(tx, ty, txd, tyd);
305 
306  vxd = floor(vxd);
307  vyd = floor(vyd);
308  txd = ceil(txd);
309  tyd = floor(tyd);
310 
311  // SE2EZ_INFORM("%1% %2%", vxd, vyd);
312  // SE2EZ_INFORM("%1% %2%", txd, tyd);
313 
314  const double move = 1;
315  for (double s = vxd; s <= txd; s += move)
316  {
317  if (fabs(s) <= math::eps)
318  painter.setPen(QColor(220, 220, 220));
319  else
320  painter.setPen(QColor(240, 240, 240));
321 
322  int x, y;
323  toScreen(s, 0, x, y);
324 
325  painter.drawLine(x, 0, x, vp.height());
326 
327  painter.setPen(QColor(180, 180, 180));
328  painter.drawText(x + 2, vp.height() - 2, QString(log::format("%1$+3.0f", s).c_str()));
329  }
330 
331  for (double s = tyd; s <= vyd; s += move)
332  {
333  if (fabs(s) <= math::eps)
334  painter.setPen(QColor(220, 220, 220));
335  else
336  painter.setPen(QColor(240, 240, 240));
337 
338  int x, y;
339  toScreen(0, s, x, y);
340 
341  painter.drawLine(0, y, vp.width(), y);
342 
343  painter.setPen(QColor(180, 180, 180));
344  painter.drawText(2, y - 2, QString(log::format("%1$+3.0f", s).c_str()));
345  }
346 }
347 
348 void gui::RenderArea::paint(bool force)
349 {
350  paint_ = true;
351  if (force)
352  {
353  // SE2EZ_WARN("Forcing repaint");
354  // mainwidget_->resize(mainwidget_->width() + 1, mainwidget_->height());
355  // resize(width(), height());
356 
357  // mainwidget_->update();
358  // update();
359  // QCoreApplication::processEvents();
360  // mainwidget_->resize(mainwidget_->width() - 1, mainwidget_->height());
361  }
362  else
363  update();
364 }
365 
367 {
368  return !paint_;
369 }
370 
371 void gui::RenderArea::paintEvent(QPaintEvent *event)
372 {
373  QRect size = geometry();
374  pixmap_ = QPixmap(size.size());
375  QPainter painter(&pixmap_);
376 
377  // QPainter painter(this);
378  painter.setRenderHint(QPainter::Antialiasing);
379  painter.fillRect(event->rect(), QBrush(Qt::white));
380 
381  drawGrid(painter);
382 
383  bottomLeftTransform(painter);
384 
385  // Delegate all the drawing to the mainwidget
386  mainwidget_->draw(painter, this);
387 
388  QPainter painter2(this);
389  painter2.drawPixmap(size, pixmap_, size);
390  paint_ = false;
391 }
392 
393 void gui::RenderArea::drawFrame(QPainter &painter, QString name)
394 {
395  QPen pen(QColor(200, 20, 20));
396  pen.setWidth(2);
397  painter.setPen(pen);
398 
399  painter.drawLine(0, 0, ROBOT, 0);
400  painter.drawLine(ROBOT - 2, -2, ROBOT, 0);
401  painter.drawLine(ROBOT - 2, 2, ROBOT, 0);
402 
403  painter.drawLine(0, 0, 0, ROBOT);
404  painter.drawLine(-2, ROBOT - 2, 0, ROBOT);
405  painter.drawLine(2, ROBOT - 2, 0, ROBOT);
406 
407  QTransform t = painter.transform();
408 
409  painter.save();
410  painter.resetTransform();
411 
412  QPoint x(ROBOT - xBoundingRect_.width(), //
413  -5 - xBoundingRect_.height() / 2);
414  QPoint y(-5 - yBoundingRect_.width(), //
415  ROBOT - yBoundingRect_.height() / 2);
416 
417  painter.drawText(t.map(x), "x");
418  painter.drawText(t.map(y), "y");
419 
420  painter.drawText(t.map(QPoint(10, 10)), name);
421 
422  painter.restore();
423 }
424 
425 void gui::RenderArea::toRobot(int xin, int yin, double &xout, double &yout)
426 {
427  xout = ((xin) / scale_ - origx_) / ROBOT;
428  yout = ((height() - yin) / scale_ - origy_) / ROBOT;
429 }
430 
431 void gui::RenderArea::toScreen(double xin, double yin, int &xout, int &yout)
432 {
433  xout = scale_ * (xin * ROBOT + origx_);
434  yout = -(scale_ * (yin * ROBOT + origy_) - height());
435 }
436 
437 void gui::RenderArea::mousePressEvent(QMouseEvent *event)
438 {
439  QPoint pos = event->pos();
440 
441  if (event->button() == Qt::LeftButton)
442  {
443  click_ = pos;
444  panning_ = true;
445  }
446  else
447  {
448  double x, y;
449  toRobot(pos.x(), pos.y(), x, y);
450  mainwidget_->click(event, x, y, pos.x(), pos.y());
451  }
452 
453  event->accept();
454 }
455 
456 void gui::RenderArea::mouseMoveEvent(QMouseEvent *event)
457 {
458  QPoint pos = event->pos();
459 
460  double x, y;
461  toRobot(pos.x(), pos.y(), x, y);
462  mainwidget_->ui_->coords->setText(QString(log::format("%1$+6.2f, %2$+6.2f", x, y).c_str()));
463 
464  if ((event->buttons() & Qt::LeftButton) && panning_)
465  {
466  setOriginX(x_ + (1 / RATIO) * (pos.x() - click_.x()));
467  setOriginY(y_ - (1 / RATIO) * (pos.y() - click_.y()));
468 
469  click_ = pos;
471  }
472 
473  if ((event->buttons() & Qt::RightButton))
474  {
475  double x, y;
476  toRobot(pos.x(), pos.y(), x, y);
477  mainwidget_->click(event, x, y, pos.x(), pos.y());
478  }
479 
480  event->accept();
481 }
482 
483 void gui::RenderArea::mouseReleaseEvent(QMouseEvent *event)
484 {
485  if (event->button() == Qt::LeftButton && panning_)
486  panning_ = false;
487 
488  event->accept();
489 }
490 
491 void gui::RenderArea::wheelEvent(QWheelEvent *event)
492 {
493  double delta = event->angleDelta().y() / 1000.;
494  setScale(scale_ + delta);
495 
496  event->accept();
498 }
499 
501 {
502  pixmap_.save(QString(file.c_str()));
503 }
MainWindow * mainwidget_
Definition: renderarea.h:144
GeometryDrawer(const RobotPtr &robot, const StatePtr &state)
Definition: renderarea.cpp:24
void wheelEvent(QWheelEvent *event) override
Definition: renderarea.cpp:491
double area(const Geometry &geometry)
Compute the area of a polygon.
Definition: polygon.cpp:106
A shared pointer wrapper for se2ez::State.
A rectangular prism.
Definition: geometry.h:33
Eigen::Vector3d flattenIsometry(const Eigen::Isometry2d &frame)
Converts a transformation frame into a vector [x, y, t] composed of a translation (x...
Definition: math.cpp:30
const CollisionManager::SignedDistance & minimum
Definition: renderarea.h:95
const CollisionManager::SignedDistanceMap & distances
Definition: renderarea.h:96
Eigen::Vector2d normal
Normal vector to collision.
Definition: collision.h:81
void mouseMoveEvent(QMouseEvent *event) override
Definition: renderarea.cpp:456
A filled circle.
Definition: geometry.h:34
The main widget that acts a container for other widgets (canvas, panels). It also delegates the drawi...
Definition: mainwindow.h:34
A convex polygon.
Definition: geometry.h:35
Definition: cspacepanel.h:22
void paintEvent(QPaintEvent *event) override
Definition: renderarea.cpp:371
bool frameCallback(RenderArea *area, QPainter &painter, const FramePtr &frame)
Definition: renderarea.cpp:73
void mousePressEvent(QMouseEvent *event) override
Definition: renderarea.cpp:437
T end(T... args)
void setOriginY(double y)
Definition: renderarea.cpp:169
void setScale(double scale)
Definition: renderarea.cpp:179
SignedDistanceDrawer(bool doCollide, bool doMin, const CollisionManager::SignedDistance &minimum, const CollisionManager::SignedDistanceMap &distances, const RobotPtr &robot, const StatePtr &state)
Definition: renderarea.cpp:58
bool geometryCallback(RenderArea *area, QPainter &painter, const FramePtr &frame, const GeometryPtr &geometry)
Definition: renderarea.cpp:45
const std::set< std::string > & colliding
Definition: renderarea.h:80
A class that contains all information about the signed distance of a frame to another.
Definition: collision.h:75
void drawGeometry(QPainter &painter, RobotPtr robot, StatePtr state, GeometryDrawerPtr drawer=nullptr)
Definition: renderarea.cpp:211
A shared pointer wrapper for se2ez::Frame.
void drawGrid(QPainter &painter)
Definition: renderarea.cpp:292
void drawFrame(QPainter &painter, QString name="")
Definition: renderarea.cpp:393
CollideDrawer(bool doCollide, const std::set< std::string > &colliding, const RobotPtr &robot, const StatePtr &state)
Definition: renderarea.cpp:29
static const double eps
Definition: math.h:36
A shared pointer wrapper for se2ez::Geometry.
void draw(QPainter &painter, RenderArea *canvas)
Asks all the panels to draw their respective information.
Definition: mainwindow.cpp:134
void bottomLeftTransform(QPainter &painter)
Definition: renderarea.cpp:282
void takeScreenshot(const std::string &file)
Definition: renderarea.cpp:500
RenderArea(QWidget *parent, MainWindow *mainwindow)
Definition: renderarea.cpp:136
Ui::MainWindow * ui_
UI (User Interface) pointer.
Definition: mainwindow.h:101
A simple polygon (no holes).
Definition: geometry.h:36
void toScreen(double xin, double yin, int &xout, int &yout)
Definition: renderarea.cpp:431
Ui::RenderArea * ui_
Definition: renderarea.h:143
void mouseReleaseEvent(QMouseEvent *event) override
Definition: renderarea.cpp:483
const double ROBOT
Definition: renderarea.h:132
T find(T... args)
std::string frame
Frame closet to collision.
Definition: collision.h:82
Eigen::Vector2d point
Point on fixture where normal begins.
Definition: collision.h:80
void setOriginX(double x)
Definition: renderarea.cpp:159
void drawAllFrames(QPainter &painter, RobotPtr robot, StatePtr state)
Definition: renderarea.cpp:195
A shared pointer wrapper for se2ez::Robot.
T c_str(T... args)
std::string format(const std::string &fmt, Args &&... args)
Definition: log.h:25
bool frameCallback(RenderArea *area, QPainter &painter, const FramePtr &frame)
Definition: renderarea.cpp:39
void updateState()
calls the update function from canvas to draw the updated state
Definition: mainwindow.cpp:105
void paint(bool force=false)
Definition: renderarea.cpp:348
The canvas widget. It contains all the drawing functions as well as all the general settings for draw...
Definition: renderarea.h:48
Main namespace.
Definition: collision.h:11
#define SE2EZ_ERROR(fmt,...)
Definition: log.h:39
bool geometryCallback(RenderArea *area, QPainter &painter, const FramePtr &frame, const GeometryPtr &geometry)
Definition: renderarea.cpp:79
const double SCALE_BOUNDS[2]
Definition: renderarea.h:133
SE2EZ_EIGEN_CLASS double distance
Distance to collision.
Definition: collision.h:79
void click(QMouseEvent *event, double x, double y, int sx, int sy)
Asks the top panel to click at the location.
Definition: mainwindow.cpp:143
void toRobot(int xin, int yin, double &xout, double &yout)
Definition: renderarea.cpp:425
const double RATIO
Definition: renderarea.h:131