Fréchet View  1.6.0
A Tool for Exploring Fréchet Distance Algorithms
freespaceview.cpp
Go to the documentation of this file.
1 
2 #include <freespaceview.h>
3 #include <structure.h>
4 #include <poly/algorithm.h>
5 
6 #include <QGraphicsPolygonItem>
7 #include <QSettings>
8 #include <QApplication>
9 
10 #include <frechetviewapplication.h>
12 
13 using namespace frechet;
14 using namespace data;
15 using namespace view;
16 using namespace app;
17 
18 //const QPen FreeSpaceView::GRID_PEN(Qt::black, 0.5, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin);
19 //const QPen FreeSpaceView::AREA_PEN(Qt::red, 0.5, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin);
20 //const QPen FreeSpaceView::BOUNDS_PEN(Qt::green, 0.5, Qt::DotLine, Qt::SquareCap, Qt::RoundJoin);
21 
22 const QBrush FreeSpaceView::AREA_BRUSH1(QColor(Qt::blue).darker());
23 const QBrush FreeSpaceView::AREA_BRUSH2(Qt::blue);
24 
25 const double FreeSpaceView::TF_MAX_ARG = 1e6;
26 const double CellView::MAX_DIAMETER = 1e5;
27 
28 const QColor FreeSpaceView::LIGHT_GRAY (230,230,230);
29 const QColor FreeSpaceView::AREA_COLOR (228,37,72);
30 
31 FreeSpaceView::FreeSpaceView(QWidget *parent)
32  : BaseView(parent,"Free-Space Diagram",false),
33  _showBounds(false),
34  componentPalette(),
35  pathView(nullptr), select(nullptr),
36  cells(nullptr)
37 {
38  GRID_PEN[SOLID] = QPen(Qt::black, 0.5, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin);
39  GRID_PEN[THIN] = QPen(Qt::black, 0.2, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin);
40  GRID_PEN[DOTTED] = QPen(Qt::black, 0.5, Qt::DotLine, Qt::SquareCap, Qt::RoundJoin);
41 
42  AREA_PEN = QPen(Qt::red, 0.5, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin);
43  BOUNDS_PEN = QPen(Qt::green, 0.5, Qt::DotLine, Qt::SquareCap, Qt::RoundJoin);
44  PATH_PEN = QPen(Qt::yellow, 2.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
45  // mirror horizontally; Origin is at the lower right.
46  flipVertical(true);
47  view()->setMouseTracking(true);
48  view()->viewport()->setMouseTracking(true);
49 }
50 
52 {
53  FreeSpace::ptr freeSpace = FrechetViewApplication::instance()->getFreeSpace();
54  for(int i=0; i < freeSpace->n-1; ++i)
55  for(int j=0; j < freeSpace->m-1; ++j)
56  delete cells->at(i,j);
57 }
58 
60 {
61  Grid::ptr grid = FrechetViewApplication::instance()->getGrid();
62  FreeSpace::ptr freeSpace = FrechetViewApplication::instance()->getFreeSpace();
63 // frechet::reach::FSPath::ptr fspath = FrechetViewApplication::instance()->getFSPath();
64 // frechet::k::kAlgorithm::ptr kalgorithm = FrechetViewApplication::instance()->getKAlgorithm();
65 
67  new CellView::Matrix (
68  std::max(freeSpace->n-1,0),
69  std::max(freeSpace->m-1,0)));
70 
71 
72  scene->clear();
73  graphicsView->setViewportUpdateMode(QGraphicsView::NoViewportUpdate);
75 
76  // set pen width relative to scene size
77  QRectF r = grid->sceneRect();
78  double pen_width = std::min(2.0, std::max(r.width(),r.height()) * 0.001);
79 
80  GRID_PEN[SOLID].setWidthF(pen_width);
81  GRID_PEN[THIN].setWidthF(pen_width*0.4);
82  GRID_PEN[DOTTED].setWidthF(pen_width);
83 
84  BOUNDS_PEN.setWidthF(2*pen_width);
85  AREA_PEN.setWidthF(pen_width);
86  PATH_PEN.setWidthF(4*pen_width);
87  //PEN_SELECT.setWidthF(8*pen_width);
88 
89  // paint the grid
90  for(int i=0; i < freeSpace->n; ++i)
91  addGridLine( grid->verticalGridLine(i), grid->hor().lineStyle(i) );
92 
93  for(int j=0; j < freeSpace->m; ++j)
94  addGridLine( grid->horizontalGridLine(j), grid->vert().lineStyle(j) );
95 
96  for(int i=0; i < freeSpace->n-1; ++i)
97  for(int j=0; j < freeSpace->m-1; ++j)
98  {
99  cells->at(i,j) = NULL;
100  // created on demand
101  }
102  // IntervalViews
105 
106  // total bounds
107  if ((freeSpace->n > 0) && (freeSpace->m > 0))
108  {
109  // leave room for IntervalViews TODO be more precise?
110 // r.adjust(
111 // -10 * intervalView[0]->ROW_HEIGHT,
112 // -10 * intervalView[0]->ROW_HEIGHT, 0,0);
113  scene->setSceneRect(r);
114  graphicsView->setSceneRect(r);
115  }
116 
117  scene->addItem(intervalView[0]);
118  scene->addItem(intervalView[1]);
119 
120  pathView = new QGraphicsItemGroup();
121  //pathView->setPen(PATH_PEN);
122  scene->addItem(pathView);
123 
124  select = new QGraphicsPathItem();
125  select->setVisible(false);
126  select->setZValue(+3);
127  select->setPen(PEN_SELECT);
128  setPenWidth(select,8*pen_width);
129  scene->addItem(select);
130 
131  graphicsView->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
132 }
133 
135 {
136  for(int i=0; i < cells->n; ++i)
137  for(int j=0; j < cells->m; ++j)
138  {
139  CellView*& cv = cells->at(i,j);
140  if (cv && !cv->dropUnusedItems()) {
141  scene->removeItem(cv);
142  delete cv;
143  cv = NULL;
144  }
145  }
146 }
147 
148 
150 {
151  CellView* cv = cells->at(i,j);
152  if (! cv) {
153  cv = new CellView(this,i,j);
154  scene->addItem(cv);
155  cells->at(i,j) = cv;
156  }
157  return cv;
158 }
159 
160 
162 {
163  FreeSpace::ptr freeSpace = FrechetViewApplication::instance()->getFreeSpace();
164  if (!freeSpace) return; // before initialisation
165 
166  frechet::k::kAlgorithm::ptr kalgorithm = FrechetViewApplication::instance()->getKAlgorithm();
167  frechet::reach::FSPath::ptr fspath = FrechetViewApplication::instance()->getFSPath();
168  frechet::poly::Algorithm::ptr poly = FrechetViewApplication::instance()->getPolyAlgorithm();
169 
170  // TODO move to Application !?
171  QApplication::setOverrideCursor(Qt::WaitCursor);
172 
173  freeSpace->calculateFreeSpace(eps);
174  /* Note: cell bounds are only needed for k-Frechet.
175  * For curve alogithms, bounds are not relevant.
176  * But they make for nicer visualisation.
177  */
178  freeSpace->calculateBounds(eps);
179 
180  path_ok = false; // show path only for. ...
181  switch(FrechetViewApplication::instance()->currentAlgorithm())
182  {
183  case FrechetViewApplication::ALGORITHM_K_FRECHET:
184  {
185  freeSpace->components().calculateComponents(*freeSpace);
186  // automatically calculate k-Frechet Greedy
187  // cancel BG job
188  FrechetViewApplication::instance()->cancelBackgroundJob();
189  kalgorithm->runGreedy();
190  } break;
191 
192  case FrechetViewApplication::ALGORITHM_CURVE:
193  { // components are not relevant
194  freeSpace->components().clear();
195 
196  path_ok = (bool)poly->decideCurve(freeSpace,fspath,NAN,false); // TOOD update status ? or not ?
197  emit curveFinished(path_ok);
198  } break;
199 
200  case FrechetViewApplication::ALGORITHM_POLYGON:
201  { // components are not relevant
202  freeSpace->components().clear();
203 
204  switch (poly->status()) {
207  path_ok = (bool)poly->decideCurve(freeSpace,fspath,NAN,false); // TOOD update status ? or not ?
208  emit curveFinished(path_ok);
209  break;
210  default:
215  path_ok = false;// path is only available later, not now
216  //fspath->clearReachability();
217  //fspath->clear();
218  break;
219  }
220  } break;
221  }
222 
223  updateView(eps);
224 
225  QApplication::restoreOverrideCursor();
226 }
227 
229 {
230  FreeSpace::ptr freeSpace = FrechetViewApplication::instance()->getFreeSpace();
231  graphicsView->setViewportUpdateMode(QGraphicsView::NoViewportUpdate);
232 // graphicsView->setInteractive(false);
233 
234  Grid::ptr grid = FrechetViewApplication::instance()->getGrid();
235  frechet::reach::FSPath::ptr fspath = FrechetViewApplication::instance()->getFSPath();
236 
237  int countEmpty=0, countEllipse=0, countPoly=0;
238  QLineF bounds[4];
239 
240  for(int i=0; i < freeSpace->n-1; ++i)
241  for(int j=0; j < freeSpace->m-1; ++j)
242  {
243  CellView* cl = cells->at(i,j);
244  if (cl || ! freeSpace->cellEmptyBounds(i,j))
245  {
246  cl = getCellView(i,j); // created on demand
247 
248  size_t comp = freeSpace->component(i,j);
249  if (FrechetViewApplication::instance()->currentAlgorithm(
250  FrechetViewApplication::ALGORITHM_K_FRECHET))
251  {
252  if (_showBounds)
253  createBoundsRect(i,j,bounds);
254  cl->update(eps, _showBounds, bounds);
255 
256  if (comp != Components::NO_COMPONENT)
257  cl->setColor(componentPalette[comp]);
258 
259  // double check components
260  Q_ASSERT((i==0) || !freeSpace->cell(i,j).L || (comp==freeSpace->component(i-1,j)));
261  Q_ASSERT((j==0) || !freeSpace->cell(i,j).B || (comp==freeSpace->component(i,j-1)));
262  }
263  else
264  {
265  if (_showBounds)
266  createReachabilityRect(i,j,bounds);
267  cl->update(eps, _showBounds, bounds);
268  // components are not relevant
269  cl->setColor(AREA_COLOR, PATH_PEN.color());
270  }
271 
272  switch(cl->what & CellView::MASK)
273  {
274  case CellView::NOTHING: countEmpty++; break;
275  case CellView::POLY: countPoly++; break;
276  case CellView::ELLIPSE: countEllipse++; break;
277  } }
278  else {
279  countEmpty++;
280  }
281  }
282 
283  showPath(path_ok);
284 
285  //qDebug() << "empty="<<countEmpty<<" ellipse="<<countEllipse<<" poly="<<countPoly<<"\n";
286 
287  /* Update Intervals
288  * */
289  updateIntervals();
290 
291  graphicsView->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
292 // graphicsView->setInteractive(true);
293 }
294 
295 void FreeSpaceView::showPath(bool show)
296 {
297  if (!show) {
298  pathView->setVisible(false);
299  segmentSelected(nullptr); // also informs other views
300  updateBounds();
301  return;
302  }
303 
304  Grid::ptr grid = FrechetViewApplication::instance()->getGrid();
305  frechet::reach::FSPath::ptr fspath = FrechetViewApplication::instance()->getFSPath();
306 
307  /*
308  * show feasible path (that was calculated above)
309  * */
310  QList<QGraphicsItem*> children = pathView->childItems();
311  GraphicsHoverLineItem* item;
312  int k=0;
313  for(int i=0; i < 2; ++i) {
314  Curve c = fspath->getPath(i);
315  c = grid->mapCurve(c);
316  // TODO delegate mapping to FSPath; needs specialisation for PolyPath
317 
318  for(int j=0; j+1 < c.size(); ++j) {
319  QLineF line(c[j],c[j+1]);
320  if (k < children.size()) {
321  item = (GraphicsHoverLineItem*)children[k++];
322  item->setLine(line);
323  item->setVisible(true);
324  }
325  else {
326  item = new GraphicsHoverLineItem(line,
328  pathView);
329  item->setPen(PATH_PEN);
330  k++;
331  }
332  Q_ASSERT(item->loc==GraphicsHoverLineItem::FS);
333  item->update(i,j);
334  }
335  }
336  for( ; k < children.size(); ++k)
337  children[k]->setVisible(false);
338 
339  pathView->setVisible(true);
340  pathView->setZValue(+1); // to front
341 
342  updateBounds();
343 }
344 
346 {
347  FreeSpace::ptr freeSpace = FrechetViewApplication::instance()->getFreeSpace();
348 
349  graphicsView->setViewportUpdateMode(QGraphicsView::NoViewportUpdate);
350  QLineF bounds[4];
351 
352  /* Update Free Space
353  * */
354  for(int i=0; i < freeSpace->n-1; ++i)
355  for(int j=0; j < freeSpace->m-1; ++j)
356  {
357  CellView* cl = cells->at(i,j);
358  if (cl || ! freeSpace->cellEmptyBounds(i,j))
359  {
360  cl = getCellView(i,j);
361 
362  if (FrechetViewApplication::instance()->currentAlgorithm()
363  ==FrechetViewApplication::ALGORITHM_K_FRECHET)
364  {
365  // eps < 0 indicates that only _showBounds needs to be updated
366  if (_showBounds)
367  createBoundsRect(i,j,bounds);
368  cl->update(-1.0, _showBounds, bounds);
369 
370  size_t comp = freeSpace->component(i,j);
371  if (comp!=Components::NO_COMPONENT)
372  cl->setColor(componentPalette[comp]);
373  }
374  else
375  {
376  // eps < 0 indicates that only _showBounds needs to be updated
377  if (_showBounds)
378  createReachabilityRect(i,j,bounds);
379  cl->update(-1.0, _showBounds, bounds);
380  cl->setColor(AREA_COLOR, PATH_PEN.color());
381  }
382  }
383  }
384 
385  updateIntervals();
386 
387  graphicsView->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
388 }
389 
391 {
392  Grid::ptr grid = FrechetViewApplication::instance()->getGrid();
393  frechet::k::kAlgorithm::ptr kalgorithm = FrechetViewApplication::instance()->getKAlgorithm();
394 
395  QRectF old_scene = scene->sceneRect();
396  QRectF r = grid->sceneRect();
397 
398  if (_showBounds &&
399  FrechetViewApplication::instance()->currentAlgorithm(
400  FrechetViewApplication::ALGORITHM_K_FRECHET))
401  {
402  // k-Frechet Intervals
403  intervalView[0]->clear();
404  intervalView[1]->clear();
405 
406  intervalView[0]->addAll(kalgorithm->horizontalIntervals());
407  intervalView[1]->addAll(kalgorithm->verticalIntervals());
408 
409  r.adjust( -intervalView[0]->extent(),
410  -intervalView[1]->extent(), 0,0);
411 
412  intervalView[0]->setVisible(true);
413  intervalView[1]->setVisible(true);
414  }
415  else
416  {
417  intervalView[0]->setVisible(false);
418  intervalView[1]->setVisible(false);
419  }
420 
421  // adjust scene rect
422  if (r!=old_scene) {
423  scene->setSceneRect(r);
424  graphicsView->setSceneRect(r);
425  setupMatrix();
426  }
427 }
428 
429 void FreeSpaceView::showResult(const BitSet* resultSet)
430 {
431  FreeSpace::ptr freeSpace = FrechetViewApplication::instance()->getFreeSpace();
432 
433  for(int i=0; i < freeSpace->n-1; ++i)
434  for(int j=0; j < freeSpace->m-1; ++j)
435  {
436  CellView* cl = cells->at(i,j);
437  if (cl || ! freeSpace->cellEmptyBounds(i,j))
438  {
439  cl = getCellView(i,j);
440 
441  size_t comp = freeSpace->component(i,j);
442  if (FrechetViewApplication::instance()->currentAlgorithm(
443  FrechetViewApplication::ALGORITHM_K_FRECHET))
444  {
445  if (comp!=Components::NO_COMPONENT)
446  {
447  if (!resultSet || resultSet->contains(comp))
448  cl->setColor(componentPalette[comp]);
449  else
450  cl->setColor(LIGHT_GRAY);
451  }
452  }
453  else { // components are not relevant
454  cl->setColor(AREA_COLOR, PATH_PEN.color());
455  }
456  }
457  }
458 
459  intervalView[0]->showResult(resultSet);
460  intervalView[1]->showResult(resultSet);
461 }
462 
464 {
465  FreeSpace::ptr freeSpace = FrechetViewApplication::instance()->getFreeSpace();
466  Grid::ptr grid = FrechetViewApplication::instance()->getGrid();
467 
468  Point s1 = freeSpace->P[i];
469  Point s2 = freeSpace->P[i+1];
470 
471  Point t1 = freeSpace->Q[j];
472  Point t2 = freeSpace->Q[j+1];
473 
474  Point p0 = intersection(s1,s2, t1,t2);
475  Point dir1 = normalized(s2-s1);
476  Point dir2 = normalized(t2-t1);
477 
478  double origx = grid->hor().map(i) - Point::dotProduct(s1-p0,dir1);
479  double origy = grid->vert().map(j) - Point::dotProduct(t1-p0,dir2);
480  // = center of ellipse
481  double ang = Point::dotProduct(dir1,dir2);
482  double mu = 1.0/sqrt(2*(1-ang));
483  double mv = 1.0/sqrt(2*(1+ang));
484 
485  return QTransform( mu, mu, -mv, mv, origx, origy );
486 }
487 
488 bool FreeSpaceView::validTransform(const QTransform& tf)
489 {
490  return validTransformArg(tf.m11())
491  && validTransformArg(tf.m12())
492  //&& validTransformArg(tf.m13())
493  && validTransformArg(tf.m21())
494  && validTransformArg(tf.m22())
495  //&& validTransformArg(tf.m23())
496  && validTransformArg(tf.m31())
497  && validTransformArg(tf.m32());
498  //&& validTransformArg(tf.m33());
499 }
500 
502 {
503  return !std::isnan(x)
504  && std::isfinite(x)
505  && (abs(x) < FreeSpaceView::TF_MAX_ARG);
506 }
507 
508 void FreeSpaceView::addGridLine(QLineF line, LineStyle style)
509 {
510  if (style != NONE) {
511  Q_ASSERT(style==SOLID || style==THIN || style==DOTTED);
512  scene->addLine( line, GRID_PEN[style] );
513  }
514 }
515 
516 void FreeSpaceView::showBounds(bool on)
517 {
518  if (on != _showBounds) {
519  _showBounds = on;
520  updateBounds();
521  }
522 }
523 
525 {
526  frechet::k::kAlgorithm::ptr kalgorithm = FrechetViewApplication::instance()->getKAlgorithm();
527  showResult(&kalgorithm->greedyResult().result);
528 }
529 
531 {
532  frechet::k::kAlgorithm::ptr kalgorithm = FrechetViewApplication::instance()->getKAlgorithm();
533  showResult(&kalgorithm->optimalResult().result);
534 }
535 
537 {
538  showResult(NULL);
539 }
540 
542 {
543  if (!pathView->isVisible())
544  item = selected_item = nullptr;
545 
546  if (item) {
547  doHiliteSegment(item->loc,item->a,item->b);
548  emit hiliteSegment(item->loc, item->a,item->b);
549  }
550  else {
553  }
554 }
555 
556 void FreeSpaceView::onHiliteSegment(int aloc, int a, int b)
557 {
559 }
560 
562 {
563  const reach::FSPath::ptr fspath = FrechetViewApplication::instance()->getFSPath();
564  Grid::ptr grid = FrechetViewApplication::instance()->getGrid();
565 
566  if (!fspath || fspath->empty() || !pathView->isVisible())
568 
569  Curve mapped[2];
570  QPainterPath path;
571  switch(loc)
572  {
574  fspath->mapFromP(poly::Segment(a,b),mapped);
575  break;
576 
578  fspath->mapFromQ(poly::Segment(a,b),mapped);
579  break;
580 
582  // TODO
583  // here, things get complicated. We should replace part of the FS diagram
584  // with a Shortest-Path Free-Space diagram.
585  // in the mean time, we display just the endpoints of the diagonal
586  Point q1 = fspath->mapFromP(a);
587  Point q2 = fspath->mapFromP(b);
588  double penw = select->pen().widthF();
589  addPoint(path, grid->mapPoint(q1), penw);
590  addPoint(path, grid->mapPoint(q2), penw);
591  } break;
592 
594  // TODO
595  // here, things get complicated. We should replace part of the FS diagram
596  // with a Shortest-Path Free-Space diagram.
597  // in the mean time, we display just the endpoints of the diagonal
598  Point p1 = fspath->mapFromQ(a);
599  Point p2 = fspath->mapFromQ(b);
600  double penw = select->pen().widthF();
601  addPoint(path, grid->mapPoint(p1), penw);
602  addPoint(path, grid->mapPoint(p2), penw);
603  } break;
604 
606  Curve c = fspath->getPath(a);
607  mapped[0].push_back(c[b]);
608  mapped[0].push_back(c[b+1]);
609  Q_ASSERT((c[b].x() != c[b+1].x()) && (c[b].y() != c[b+1].y()));
610  } break;
611 
613  // clear selection
614  break;
615 
616  default:
617  Q_ASSERT(false);
618  }
619 
620  if (loc != GraphicsHoverLineItem::None) {
621  addPolygon(path, grid->mapCurve(mapped[0]));
622  addPolygon(path, grid->mapCurve(mapped[1]));
623  select->setPath(path);
624  }
625 
626  select->setVisible(loc != GraphicsHoverLineItem::None);
627 }
628 
630 {
631  QPainterPath path;
632  Grid::ptr grid = FrechetViewApplication::instance()->getGrid();
633  double penw = select->pen().widthF();
634  addPoint(path, grid->mapPoint(p), penw);
635  select->setPath(path);
636  select->setVisible(true);
637 }
638 
639 void FreeSpaceView::saveSettings(QSettings& settings, QString group)
640 {
641  settings.beginGroup(group);
642  settings.setValue("show.bounds",_showBounds);
643  settings.endGroup();
644 
645  BaseView::saveSettings(settings,group);
646 }
647 
648 void FreeSpaceView::restoreSettings(QSettings& settings, QString group)
649 {
650  settings.beginGroup(group);
651  _showBounds = settings.value("show.bounds",false).toBool();
652  settings.endGroup();
653 
654  BaseView::restoreSettings(settings,group);
655 }
656 
657 
658 static const double OPACITY = 0.8;
659 
660 CellView::CellView(FreeSpaceView* aparent, int ai, int aj)
661  : QGraphicsItemGroup(),
662  parent(aparent),
663  i(ai), j(aj),
664  cellBounds(), clipShape(),
665  _poly(NULL),
666  _ellipse(NULL), useEllipse(true), // unless..
667  _bounds(),
668  what(NOTHING)
669 {
670  Grid::ptr grid = FrechetViewApplication::instance()->getGrid();
671  cellBounds = grid->cellBounds(i,j);
672  clipShape.addRect(cellBounds);
673  _bounds[0]=_bounds[1]=_bounds[2]=_bounds[3]=NULL;
674 }
675 
677 {
678  // delete lines[] ?
679 }
680 
681 // on-demand methods
682 
683 
684 QGraphicsPolygonItem* CellView::getPoly() {
685  if (! _poly) {
686  _poly = new QGraphicsPolygonItem(this);
687  _poly->setPen(Qt::NoPen);
689  _poly->setOpacity(OPACITY);
690  //removeFromGroup(poly); // might be added later
691  }
692  return _poly;
693 }
694 
695 QGraphicsEllipseItem* CellView::getEllipse(){
696  if(! _ellipse && useEllipse) {
697  QTransform tf = parent->createEllipseTransform(i,j);
698  // The transformation becomes invalid, or impracticable,
699  // when the line segments are (almost) parallel.
700  // In this case, we draw a polygon insteadd.
702  if (useEllipse) {
703  _ellipse = new QGraphicsEllipseItem(this);
704  _ellipse->setPen(Qt::NoPen);
706  _ellipse->setOpacity(OPACITY);
707  _ellipse->setTransform(tf,false);
708  //removeFromGroup(ellipse); // might be added, later
709  }
710  }
711  return _ellipse;
712 }
713 
714 QGraphicsLineItem* CellView::getBounds(int i)
715 {
716  if (! _bounds[i]){
717  _bounds[i] = new QGraphicsLineItem(this);
718  _bounds[i]->setPen(parent->BOUNDS_PEN);
719  //_bounds[i]->setBrush(Qt::NoBrush);
720  _bounds[i]->setOpacity(OPACITY);
721  _bounds[i]->setZValue(1.0);
722  //removeFromGroup(rect); // might be added later
723  }
724  return _bounds[i];
725 }
726 
727 
728 void CellView::setBounds(QLineF bounds[4])
729 {
730  for(int i=0; i < 4; ++i)
731  if (bounds[i].isNull()) {
732  if (_bounds[i]) {
733  _bounds[i]->setVisible(false);
734  _bounds[i]->setLine(bounds[i]);
735  }
736  }
737  else {
738  addToGroup(getBounds(i));
739  getBounds(i)->setVisible(true);
740  getBounds(i)->setLine(bounds[i]);
741  }
742 }
743 
744 void CellView::setColor(QColor areaColor, QColor boundsColor)
745 {
746  if (what==NOTHING)
747  return;
748 
749  if (what & ELLIPSE)
750  setBrushColor(getEllipse(),areaColor);
751 
752  if (what & POLY) {
753  setBrushColor(getPoly(),areaColor);
754  setPenColor(getPoly(),areaColor);
755  }
756 
757  if (what & BOUNDS) {
758  setBoundsPenColor(_bounds,4, boundsColor.isValid() ? boundsColor : areaColor);
759  }
760 }
761 
762 void CellView::setPenColor(QAbstractGraphicsShapeItem* item, QColor col)
763 {
764  QPen pen = item->pen();
765  if ((pen.style()!=Qt::NoPen) && (pen.color() != col)) {
766  pen.setColor(col);
767  item->setPen(pen);
768  }
769 }
770 
771 void CellView::setBoundsPenColor(QGraphicsLineItem** items, int len, QColor col)
772 {
773  for(int i=0; i < len; ++i)
774  if (items[i]) {
775  QPen pen = items[i]->pen();
776  if ((pen.style()!=Qt::NoPen) && (pen.color() != col)) {
777  pen.setColor(col);
778  items[i]->setPen(pen);
779  }
780  }
781 }
782 
783 void CellView::setBrushColor(QAbstractGraphicsShapeItem* item, QColor col)
784 {
785  QBrush brush = item->brush();
786  if ((brush.style() != Qt::NoBrush) && (brush.color() != col)) {
787  brush.setColor(col);
788  item->setBrush(brush);
789  }
790 }
791 
792 void CellView::setPenStyle(QAbstractGraphicsShapeItem* item, Qt::PenStyle style)
793 {
794  QPen pen = item->pen();
795  if (pen.style() != style) {
796  pen.setStyle(style);
797  item->setPen(pen);
798  }
799 }
800 
801 void CellView::setPenStyleWidth(QAbstractGraphicsShapeItem* item, Qt::PenStyle style, float width)
802 {
803  QPen pen = item->pen();
804  if (pen.style() != style) {
805  pen.setStyle(style);
806  item->setPen(pen);
807  }
808  if (pen.widthF() != width) {
809  pen.setWidthF(width);
810  item->setPen(pen);
811  }
812 }
813 
815 {
816  if ((w & BOUNDS) != (what & BOUNDS))
817  {
818  if (what & BOUNDS) {
819  for (int i=0; i < 4; ++i)
820  if (_bounds[i]) {
821  removeFromGroup(_bounds[i]);
822  scene()->removeItem(_bounds[i]);
823  _bounds[i]->setVisible(false);
824  }
825  }
826  else {
827  for(int i=0; i < 4; ++i) {
828  if (_bounds[i] && ! _bounds[i]->line().isNull()) {
829  addToGroup(_bounds[i]);
830  _bounds[i]->setVisible(true);
831  }
832  }
833  }
834  }
835 
836  if ((w & MASK) != (what & MASK))
837  {
838  switch(what & MASK)
839  {
840  case POLY:
841  if (_poly) {
842  removeFromGroup(_poly);
843  scene()->removeItem(_poly);
844  _poly->setVisible(false);
845  }
846  break;
847  case ELLIPSE:
848  if (_ellipse) {
849  removeFromGroup(_ellipse);
850  scene()->removeItem(_ellipse);
851  _ellipse->setVisible(false);
852  }
853  setFlag(GraphicsItemFlag::ItemClipsToShape,false);
854  setFlag(GraphicsItemFlag::ItemClipsChildrenToShape,false);
855  break;
856  }
857 
858  switch(w & MASK)
859  {
860  case POLY:
861  addToGroup(getPoly());
862  _poly->setVisible(true);
863  break;
864  case ELLIPSE:
865  addToGroup(getEllipse());
866  setFlag(GraphicsItemFlag::ItemClipsToShape,true);
867  setFlag(GraphicsItemFlag::ItemClipsChildrenToShape,true);
868  _ellipse->setVisible(true);
869  break;
870  }
871  }
872 
873  // draw either poly or ellipse; never both
874  Q_ASSERT(! (_poly && _poly->isVisible() && _ellipse && _ellipse->isVisible()));
875  what = w;
876 }
877 
878 void CellView::dropUnusedItem(QGraphicsItem** item)
879 {
880  if (*item && !(*item)->isVisible()) {
881  delete *item;
882  item = NULL;
883  }
884 }
885 
887 {
888  bool any_bounds=false; // unless...
889  for(int i=0; i < 4; ++i) {
890  dropUnusedItem((QGraphicsItem**)&_bounds[i]);
891  if (_bounds[i]) any_bounds=true;
892  }
893 
894  dropUnusedItem((QGraphicsItem**)&_poly);
895  dropUnusedItem((QGraphicsItem**)&_ellipse);
896  return any_bounds || _poly || _ellipse;
897 }
898 
899 void CellView::update(double eps,
900  bool showBounds,
901  QLineF bounds[4])
902 {
903  FreeSpace::ptr freeSpace = FrechetViewApplication::instance()->getFreeSpace();
904 
905  // TODO heuristic:
906  // if ( | [s1,s2] p0 | > 1000 * (bounds.width()+bounds.heigth())
907  // drawPoly=true
908  if (freeSpace->cellEmptyBounds(i,j))
909  {
910  dodraw(NOTHING);
911  return;
912  }
913 
914  // Boundary rectangle
915  if (showBounds)
916  setBounds(bounds);
917 
918  if (freeSpace->cellFull(i,j))
919  { // draw filled rect
920  if (getPoly()->polygon() != QPolygonF(cellBounds))
921  getPoly()->setPolygon(cellBounds);
922  setPenStyle(getPoly(), Qt::NoPen);
923  dodraw(showBounds ? POLY_AND_BOUNDS : POLY);
924  return;
925  }
926 
927  if (getEllipse())
928  { // draw ellipse
929  // (unless it becomes too large)
930  if (eps >= 0.0)
931  getEllipse()->setRect(-eps,-eps,2*eps,2*eps);
932  // else:
933  // eps < 0 indicates that eps has not changed
934 
935  // Transform already set. Not need to update.
936  dodraw(showBounds ? ELLIPSE_AND_BOUNDS : ELLIPSE);
937  return;
938  }
939  // else:
940  // draw (almost) parallel lines
941  bool thin;
942  Curve p = createPolygon(i,j, &thin);
943  //poly->setPen(showSegments ? FreeSpaceView::GRID_PEN : Qt::NoPen);
944  if (getPoly()->polygon()!=p)
945  getPoly()->setPolygon(p);
946  // if the polygon is thin (only a line); use pen !
947 
949  thin ? parent->AREA_PEN.style() : Qt::NoPen,
950  parent->AREA_PEN.widthF());
951 
952  dodraw(showBounds ? POLY_AND_BOUNDS : POLY);
953 }
954 
955 
956 void FreeSpaceView::createBoundsRect(int i, int j, QLineF result[4])
957 {
958  FreeSpace::ptr freeSpace = FrechetViewApplication::instance()->getFreeSpace();
959  QRectF r = freeSpace->segmentBounds(i,j);
960 
961  if (r.left() > 0.0 && !std::isnan(r.height()))
962  result[0] = boundsLine(r.bottomLeft(),r.topLeft(), i,j);
963  else
964  result[0] = QLineF();
965 
966  if (r.right() < 1.0 && !std::isnan(r.height()))
967  result[1] = boundsLine(r.bottomRight(),r.topRight(), i,j);
968  else
969  result[1] = QLineF();
970 
971  if (r.top() > 0.0 && !std::isnan(r.width()))
972  result[2] = boundsLine(r.topLeft(),r.topRight(), i,j);
973  else
974  result[2] = QLineF();
975 
976  if (r.bottom() < 1.0 && !std::isnan(r.width()))
977  result[3] = boundsLine(r.bottomLeft(),r.bottomRight(), i,j);
978  else
979  result[3] = QLineF();
980 }
981 
982 void FreeSpaceView::createReachabilityRect(int i, int j, QLineF result[4])
983 {
984  frechet::reach::FSPath::ptr fspath = FrechetViewApplication::instance()->getFSPath();
985 
986  const Interval& L = fspath->left(i,j);
987  const Interval& B = fspath->bottom(i,j);
988  const Interval& R = fspath->left(i+1,j);
989  const Interval& T = fspath->bottom(i,j+1);
990 
991  // left
992  if (L)
993  result[0] = boundsLine(
994  QPointF(0.0, L.lower()),
995  QPointF(0.0, L.upper()), i,j);
996  else
997  result[0] = QLineF();
998 
999  // bottom
1000  if (B)
1001  result[1] = boundsLine(
1002  QPointF(B.lower(), 0.0),
1003  QPointF(B.upper(), 0.0), i,j);
1004  else
1005  result[1] = QLineF();
1006 
1007  // right
1008 // if ((i+1)==(freeSpace->n-1)) {
1009  if (R.valid())
1010  result[2] = boundsLine(
1011  QPointF(1.0,R.lower()),
1012  QPointF(1.0,R.upper()), i,j);
1013  else
1014  result[2] = QLineF();
1015 
1016  // upper
1017 // if ((j+1)==(freeSpace->m-1)) {
1018  if (T)
1019  result[3] = boundsLine(
1020  QPointF(T.lower(),1.0),
1021  QPointF(T.upper(),1.0), i,j);
1022  else
1023  result[3] = QLineF();
1024 
1025  // Note: currently, upper and right bounds are drawn TWICE
1026  // to counter clipping. Better: extend the clipping bounds slightly(?)
1027 }
1028 
1029 QLineF FreeSpaceView::boundsLine(QPointF a, QPointF b, int i, int j)
1030 {
1031  Grid::ptr grid = FrechetViewApplication::instance()->getGrid();
1032 
1033  QLineF line (a,b);
1034  line.translate(i,j);
1035  return grid->mapLine(line);
1036 }
1037 
1039  if (pathView) showPath(false);
1040 }
1041 
1042 QPolygonF CellView::createPolygon(int i, int j,
1043  bool* thin)
1044 {
1045  FreeSpace::ptr freeSpace = FrechetViewApplication::instance()->getFreeSpace();
1046  Grid::ptr grid = FrechetViewApplication::instance()->getGrid();
1047 
1048  // Polygon
1049  const Interval& L = freeSpace->cell(i,j).L;
1050  const Interval& R = freeSpace->cell(i+1,j).L;
1051 
1052  const Interval& B = freeSpace->cell(i,j).B;
1053  const Interval& T = freeSpace->cell(i,j+1).B;
1054 
1055  *thin = true; // unless...
1056  QPolygonF result;
1057  if (L) {
1058  result.append(grid->mapPoint(Point(i,j+L.lower())));
1059  result.append(grid->mapPoint(Point(i,j+L.upper())));
1060  if(L.lower() < L.upper()) *thin=false;
1061  // TODO small threshold?
1062  }
1063  if (T) {
1064  result.append(grid->mapPoint(Point(i+T.lower(),j+1)));
1065  result.append(grid->mapPoint(Point(i+T.upper(),j+1)));
1066  if(T.lower() < T.upper()) *thin=false;
1067  }
1068  if (R) {
1069  result.append(grid->mapPoint(Point(i+1,j+R.upper())));
1070  result.append(grid->mapPoint(Point(i+1,j+R.lower())));
1071  if(R.lower() < R.upper()) *thin=false;
1072  }
1073  if (B) {
1074  result.append(grid->mapPoint(Point(i+B.upper(),j)));
1075  result.append(grid->mapPoint(Point(i+B.lower(),j)));
1076  if(B.lower() < B.upper()) *thin=false;
1077  }
1078  return result;
1079 }
1080 
base class for view widgets.
Definition: baseview.h:79
Represents a polygon line segment from node i to j.
Definition: types.h:39
QGraphicsPolygonItem * _poly
content area may be a polygon (created on demand)
Definition: freespaceview.h:56
QGraphicsLineItem * _bounds[4]
boundary lines of the content area
Definition: freespaceview.h:63
virtual void segmentSelected(GraphicsHoverLineItem *item) override
called when the mouse hovers over a sensitve line item
void setColor(QColor areaColor, QColor borderColor=QColor())
update drawing colors
static void setPenStyle(QAbstractGraphicsShapeItem *item, Qt::PenStyle style)
update pen style (dotted,solid,...) of a graphics item
used for segments that are not mouse sensitive
Definition: baseview.h:243
void showOptimalResult()
show the optimal result of the k-Frechet (brute-force) algorithms. Highlights all components that are...
static bool validTransform(const QTransform &tf)
validity test for a transformation. If transform parameters become excessively large,...
QPen BOUNDS_PEN
pen for bounding rectangles
bool path_ok
true, if there is a feasible path
What
display mode; what is displayed? Flags can be combined (except Poly and Ellipse).
Definition: freespaceview.h:69
QGraphicsPathItem * select
highlighted line segment (or nullptr)
void addGridLine(QLineF line, LineStyle style)
add a grid line to the graphics scene
input data have been successfully processed, the algorithm is now ready to execute
Definition: algorithm.h:92
static const QColor LIGHT_GRAY
used for disabled components (k-Frechet)
FreeSpaceView * parent
pointer to parent
Definition: freespaceview.h:48
bool _showBounds
true, if bounding rectangle are shown
Point normalized(Point p)
normalize a vector to unit length
Definition: numeric.h:265
void dropUnusedItem(QGraphicsItem **item)
release an unused item
negative result of the decision version
Definition: algorithm.h:87
QGraphicsView * view() const
Definition: baseview.cpp:302
QGraphicsEllipseItem * getEllipse()
global definitions for all algorithms.
bool useEllipse
true if an ellipse is to be shown
Definition: freespaceview.h:61
input data are faulty. P is convex.
Definition: algorithm.h:110
IntervalView * intervalView[2]
k-Frechet: show component intervals below and to the left
void clear()
remove all entries from the map
Definition: palette.cpp:52
positive result of the decision version
Definition: algorithm.h:86
static void setBoundsPenColor(QGraphicsLineItem **bounds, int len, QColor col)
update pen color of several graphics item
display a clipped ellipse
Definition: freespaceview.h:73
the algorithm is currently computing (decision variant, or optimisation variant)
Definition: algorithm.h:77
void hiliteSegment(int loc, int a, int b)
raised when the mouse moves over a highlighted segment This signal triggers the display of associated...
boost::shared_ptr< Algorithm > ptr
(smart) pointer to an Algorithm object
Definition: algorithm.h:236
void populateScene()
create the grid lines and an array of CellView objects
a segment of the feasible paht (displayed in the free-space diagram)
Definition: baseview.h:248
void createReachabilityRect(int i, int j, QLineF result[4])
create a set of line segments for reachability intervals
QGraphicsItemGroup * pathView
the feasible path
void onHiliteSegment(int loc, int a, int b)
highlight a segment of the feasible path
CellView(FreeSpaceView *parent, int i, int j)
default constructor
static const QColor AREA_COLOR
color for content area (except k-Frechet)
Display k-Frechet intervals, i.e. projections of connected components to the domain axes.
Definition: intervalview.h:33
static const QBrush AREA_BRUSH2
brush (fill color) for content area
display the free-space diagram.
boost::shared_ptr< Matrix > MatrixPtr
pointer to an array of cell views
Definition: freespaceview.h:85
static void addPolygon(QPainterPath &ppath, const QPolygonF &poly)
add a polygon curve segment to a QPainterPath
Definition: baseview.cpp:622
QGraphicsLineItem * getBounds(int i)
draw a dotted line
Definition: grid.h:21
Float sqrt(const Float &x)
square-root function template for floating point types
draw a solid line
Definition: grid.h:19
display bounding rect
Definition: freespaceview.h:75
void setBounds(QLineF bounds[4])
update bounding rectangle
void setupMatrix()
set up transformation matrix to account for zoom,rotate,scroll
Definition: baseview.cpp:374
double upper() const
Definition: interval.h:96
const Location loc
location on screen
Definition: baseview.h:251
void onAlgorithmChanged(int alg)
updatee free-space diagram when a new algorithm is selected. For example, for the k-Frechet algorithm...
QPainterPath clipShape
shape used for clipping ellipses
Definition: freespaceview.h:53
void updateBounds()
update bounding rectangles
void createBoundsRect(int i, int j, QLineF result[4])
create a boundary rectangle for a cell
QGraphicsScene * scene
scene that is displayed by graphicsView
Definition: baseview.h:174
QPen PATH_PEN
pen for feasible path
QGraphicsPolygonItem * getPoly()
static const QPen PEN_SELECT
pen for drawing selected polygon segment
Definition: baseview.h:163
QPolygonF createPolygon(int i, int j, bool *thin)
create a polygon that draws the content area
GraphicsHoverLineItem * selected_item
the currently selected mouse sensitve polyon segment (or nullptr)
Definition: baseview.h:189
void showGreedyResult()
show the result of the k-Frechet greedy algorithms. Highlights all components that are part of the so...
a QGraphicsLitem that can handle mouse hover events. It is used to highlight mouse sensitve polygon s...
Definition: baseview.h:239
int i
column index in free-space grid
Definition: freespaceview.h:44
virtual ~FreeSpaceView()
destructor; releases all items
display polygon plus bounding rect
Definition: freespaceview.h:78
void update(int a, int b)
update identifiers
Definition: baseview.cpp:669
QTransform createEllipseTransform(int i, int j)
compute the transformation for drawing an ellipse
QPointF Point
a point in the plane; with double floating point precision. This type is heavily used throughout all ...
Definition: types.h:14
void hideResult()
hide results of the k-Frechet algorithms. Remove gray-out, display all components in their original c...
bool contains(int offset) const
Definition: bitset.cpp:71
void flipVertical(bool flip)
flip graphics scene vertically
Definition: baseview.cpp:322
Point intersection(Point p1, Point p2, Point p3, Point p4)
compute the intersection of two lines
Definition: numeric.h:278
boost::shared_ptr< FSPath > ptr
smart pointer to an FSPath object
Definition: fs_path.h:65
bool dropUnusedItems()
release graphics items that are not currently displayed
enum frechet::view::CellView::What what
QRectF cellBounds
bounding rectangle
Definition: freespaceview.h:51
static void addPoint(QPainterPath &ppath, const QPointF &point, double diameter=1.0)
add a dot to a QPainterPath
Definition: baseview.cpp:638
void update(double eps, bool showBounds, QLineF bounds[4])
update display
virtual void dropUnusedItems() override
release graphics items that are currently not drawn implements empty method from super-class
draw a thin, solid line
Definition: grid.h:20
const int a
parameters loc,a, and b identify a segment.
Definition: baseview.h:257
static void setPenStyleWidth(QAbstractGraphicsShapeItem *item, Qt::PenStyle style, float width)
update pen style and pen width of a graphics item
QPen AREA_PEN
pen for content area
QPolygonF Curve
a polygonal curve in the plane; with double floating point precision. This type is heavily used throu...
Definition: types.h:20
QLineF boundsLine(QPointF a, QPointF b, int i, int j)
calculates one boundary line
void curveFinished(bool yes)
raised when after decision variant of the curve algorithm
double lower() const
Definition: interval.h:92
A simple two-dimensional array of fixed size.
Definition: array2d.h:19
virtual void restoreSettings(QSettings &settings, QString group)
load settings from application preferences
void showResult(const frechet::data::BitSet *resultSet)
highlight result set of a k-Frechet algorithm. All intervals that are not part of the result set are ...
double min(double a, double b)
minimum function with checks for NAN
Definition: numeric.h:222
void dodraw(What what)
update content
virtual void restoreSettings(QSettings &settings, QString group)
load view settings to application prefs
Definition: baseview.cpp:533
static const double TF_MAX_ARG
max. value for affine transforms
CellView * getCellView(int i, int j)
get a free-space cell view
draw no grid line
Definition: grid.h:22
virtual ~CellView()
destructor
boost::shared_ptr< Grid > ptr
smart pointer to a Grid object
Definition: grid.h:128
display ellipse plus bounding rect
Definition: freespaceview.h:77
void addAll(const k::IntervalMap &mvals)
add a set of intervals
virtual void saveSettings(QSettings &settings, QString group)
store settings to application preferences
static void setBrushColor(QAbstractGraphicsShapeItem *item, QColor col)
update brush (fill) color of a graphics item
A simple bit vector of fixed size.
Definition: bitset.h:16
QGraphicsView * graphicsView
the embedded QGraphicsView
Definition: baseview.h:172
displays one cell of the free-space diagram.
Definition: freespaceview.h:40
empty cell. display nothing
Definition: freespaceview.h:71
LineStyle
display style of grid lines in free-space diagram
Definition: grid.h:15
void showPath(bool show)
show or hide feasible path
static bool validTransformArg(double x)
validity test for a transformation
static const double OPACITY
static void setPenColor(QAbstractGraphicsShapeItem *item, QColor col)
update pen (edge) color of a graphics item
virtual void saveSettings(QSettings &settings, QString group)
store view settings to application prefs
Definition: baseview.cpp:512
int j
row index in free-space grid
Definition: freespaceview.h:46
input data are faulty. Q is convex.
Definition: algorithm.h:112
void updateIntervals()
update component intervals (k-Frechet only)
CellView::MatrixPtr cells
free space areas for all cells (i,j)
boost::shared_ptr< kAlgorithm > ptr
smart pointer to an kAlgorithm object
Definition: kalgorithm.h:320
an interval of two double values.
Definition: interval.h:31
QGraphicsEllipseItem * _ellipse
Definition: freespaceview.h:59
void doHiliteSegment(GraphicsHoverLineItem::Location loc, int a, int b)
highlight a line segment
static const component_id_t NO_COMPONENT
empty cells have an invalid component ID
Definition: components.h:60
Number abs(const Number &x)
abs() function template for arbitrary numerical types
Definition: numeric.h:91
Location
location of the polygon segment
Definition: baseview.h:243
bool valid() const
validity test
Definition: interval.h:74
void hilitePoint(QPointF p)
hilite on point inf the diagram (used for animation only)
boost::shared_ptr< FreeSpace > ptr
smart pointer to FreeSpace object
Definition: freespace.h:92
void clear()
remove all intervals
void updateView(double eps)
update free-space view in response to a change of epsilon
void showResult(const data::BitSet *resultSet)
show the result of a k-Frechet algorithm
double max(double a, double b)
maximum function with checks for NAN
Definition: numeric.h:233
static void setPenWidth(QGraphicsItem *item, double width)
update the pen width of a graphics item
Definition: baseview.cpp:579
void calculateFreeSpace(double epsilon)
update free-space diagram when epsilon changes. If the curve algorithm is selected,...