USGS

Isis 3.0 Object Programmers' Reference

Home

MosaicSceneItem.cpp
1 #include "MosaicSceneItem.h"
2 
3 #include <iostream>
4 #include <cfloat>
5 
6 #include <QApplication>
7 #include <QBrush>
8 #include <QEvent>
9 #include <QGraphicsItem>
10 #include <QList>
11 #include <QPainter>
12 #include <QPen>
13 #include <QStyleOptionGraphicsItem>
14 #include <QTreeWidgetItem>
15 
16 #include "Directory.h"
17 #include "DisplayProperties.h"
18 #include "FileDialog.h"
19 #include "Histogram.h"
20 #include "Image.h"
21 #include "ImageList.h"
22 #include "ImagePolygon.h"
23 #include "IString.h"
24 #include "LineManager.h"
25 #include "MosaicGraphicsView.h"
26 #include "MosaicSceneWidget.h"
27 #include "PolygonTools.h"
28 #include "SerialNumber.h"
29 #include "Statistics.h"
30 #include "Stretch.h"
31 #include "Table.h"
32 #include "TProjection.h"
33 
34 using namespace geos::geom;
35 
36 namespace Isis {
44  MosaicSceneItem::MosaicSceneItem(Image *image, MosaicSceneWidget *parent) : QGraphicsObject() {
45  if (parent->getProjection() == NULL) {
46  std::string msg = "Parent does not have projection in MosaicWidget";
48  }
49 
50  m_image = image;
51 
52  connect(m_image, SIGNAL(destroyed(QObject *)),
53  this, SLOT(lostCubeDisplay()));
54  connect(m_image, SIGNAL(destroyed(QObject *)),
55  this, SLOT(deleteLater()));
56 
57  m_mp = NULL;
58  m_polygons = NULL;
59  m_cubeDnStretch = NULL;
60  groundMap = NULL;
61  m_showingLabel = false;
62  m_ignoreCubeDisplayChanged = false;
63 
64  m_scene = parent;
65 
66  m_polygons = new QList< QGraphicsPolygonItem *>();
67 
68  setupFootprint();
69 
70  setToolTip(m_image->displayProperties()->displayName());
71 
72  setAcceptHoverEvents(true);
73 
74  ImageDisplayProperties *displayProp = m_image->displayProperties();
83 
84  if(parent->userHasTools()) {
85  supportToAdd = (ImageDisplayProperties::Property)
86  (supportToAdd | ImageDisplayProperties::Zooming);
87  }
88 
89  displayProp->addSupport(supportToAdd);
90 
91  connect(displayProp, SIGNAL(propertyChanged(DisplayProperties *)),
92  this, SLOT(cubeDisplayChanged()));
93  }
94 
95 
101  if(scene())
102  scene()->removeItem(this);
103 
104  while(m_polygons->size()) {
105  delete m_polygons->takeAt(0);
106  }
107  }
108 
109 
110  QRectF MosaicSceneItem::boundingRect() const {
111  QRectF boundingRect;
112 
113  QGraphicsPolygonItem *polygon;
114  foreach(polygon, *m_polygons) {
115  boundingRect = boundingRect.united(polygon->boundingRect());
116 
117  QGraphicsItem *polyChild;
118  foreach(polyChild, polygon->childItems()) {
119  if(polyChild->isVisible()) {
120  boundingRect = boundingRect.united(
121  mapFromItem(polyChild, polyChild->boundingRect()).boundingRect());
122  }
123  }
124  }
125 
126  return boundingRect;
127  }
128 
129 
137  void MosaicSceneItem::paint(QPainter *painter,
138  const QStyleOptionGraphicsItem *option, QWidget *widget) {
139  if(m_image &&
141  drawImage(painter, option);
142  }
143 
144  // We don't add the polygon items as children because manually painting them is a huge speed
145  // improvement. It cannot be undone due to the amount of speed it gives.
146  if (!childItems().count()) {
147  foreach (QGraphicsPolygonItem *polyItem, *m_polygons) {
148  polyItem->paint(painter, option, widget);
149  }
150  }
151  }
152 
153 
157  void MosaicSceneItem::setupFootprint() {
158  if(m_image) {
159  m_mp = m_image->footprint();
160 
161  if (!m_mp) {
163  tr("Cannot display footprints of images which have no footprints. "
164  "Tried to display [%1]").arg(m_image->displayProperties()->displayName()),
165  _FILEINFO_);
166  }
167 
168  try {
169  reproject();
170  }
171  catch(IException &e) {
172  m_image->deleteLater();
173 
174  IString msg = "Could not project the footprint from cube [" +
175  m_image->displayProperties()->displayName() + "]";
176  throw IException(e, IException::Unknown, msg, _FILEINFO_);
177  }
178  }
179  }
180 
181 
187  prepareGeometryChange();
188 
189  MultiPolygon *mp;
190  TProjection *proj = (TProjection *)m_scene->getProjection();
191 
192  // Remove current polygons from the scene
193  while(m_polygons->size()) {
194  QGraphicsPolygonItem *polyItem = m_polygons->at(0);
195 
196  if (polyItem->scene()) {
197  polyItem->scene()->removeItem(polyItem);
198  }
199  m_polygons->removeAll(polyItem);
200 
201  delete polyItem;
202  polyItem = NULL;
203  }
204 
205  if (proj->Has180Domain()) {
207  mp = m_180mp;
208  }
209  else {
210  mp = m_mp;
211  }
212 
213  m_showingLabel =
215 
216  //----------------------------------------------------------
217  // We need to loop thru the num. geom. because some of the
218  // cubes will have more than one geom. if it crosses lat/lon
219  // boundries.
220  //----------------------------------------------------------
221  bool useFullChildrenHierarchy = (mp->getNumGeometries() > 1) || m_showingLabel;
222 
223  for (unsigned int i = 0; i < mp->getNumGeometries(); i++) {
224  const Geometry *geom = mp->getGeometryN(i);
225  CoordinateSequence *pts;
226 
227  pts = geom->getCoordinates();
228  double lat, lon;
229  QVector<QPointF> polyPoints;
230 
231  //--------------------------------------------------------------
232  // We need to convert the footprint polygons from lat/lon to x/y
233  // in order to display them in the QGraphicsScene
234  //--------------------------------------------------------------
235  for (unsigned int j = 0; j < pts->getSize(); j++) {
236  lat = pts->getY(j);
237  lon = pts->getX(j);
238  if (proj->SetUniversalGround(lat, lon)) {
239  double x = proj->XCoord();
240  double y = -1 * (proj->YCoord());
241 
242  polyPoints.push_back(QPointF(x, y));
243  }
244  }
245 
246  setFlag(QGraphicsItem::ItemIsSelectable);
247 
248  QGraphicsPolygonItem *polyItem = NULL;
249 
250  if (useFullChildrenHierarchy) {
251  polyItem = new QGraphicsPolygonItem(this);
252  }
253  else {
254  polyItem = new QGraphicsPolygonItem;
255  }
256 
257  polyItem->setPolygon(QPolygonF(polyPoints));
258 
259  if (m_showingLabel) {
260  QGraphicsSimpleTextItem *label = NULL;
261 
262  label = new QGraphicsSimpleTextItem(polyItem);
263 
264  if(m_image)
265  label->setText(m_image->displayProperties()->displayName());
266  label->setFlag(QGraphicsItem::ItemIsMovable);
267  label->setFont(QFont("Helvetica", 10));
268  label->setPos(polyItem->polygon().boundingRect().center());
269  label->setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
270 
271  QRectF boundingRect = polyItem->boundingRect();
272  if(boundingRect.width() < boundingRect.height())
273  label->rotate(90);
274  }
275 
276  m_polygons->append(polyItem);
277 
278  delete pts;
279  }
280 
281  updateChildren();
282  }
283 
284 
294  double MosaicSceneItem::getPixelValue(int sample, int line) {
295  double pixelValue = 0;
296 
297  if(m_image) {
298  Brick gryBrick(1, 1, 1, m_image->cube()->pixelType());
299  gryBrick.SetBasePosition((int)(sample + 0.5), (int)(line + 0.5), 1);
300  m_image->cube()->read(gryBrick);
301 
302  pixelValue = gryBrick[0];
303  if (pixelValue == Null) {
304  return Null;
305  }
306  if (pixelValue < 0) pixelValue = 0;
307  if (pixelValue > 255) pixelValue = 255;
308  }
309 
310  return pixelValue;
311  }
312 
313 
319  void MosaicSceneItem::drawImage(QPainter *painter,
320  const QStyleOptionGraphicsItem *option) {
321  Stretch *stretch = getStretch();
322  QApplication::setOverrideCursor(Qt::WaitCursor);
323 
324  try {
325  QGraphicsPolygonItem *polygon;
326  foreach(polygon, *m_polygons) {
327  QPolygonF polyBounding = polygon->polygon();
328  QRectF sceneRect = polyBounding.boundingRect();
329  QPolygon screenPoly = m_scene->getView()->mapFromScene(sceneRect);
330  QRect visibleBox = screenPoly.boundingRect();
331 
332  int bbWidth = (int)visibleBox.width();
333  int bbHeight = (int)visibleBox.height();
334 
335  int bbLeft = visibleBox.left();
336  int bbTop = visibleBox.top();
337  int bbRight = visibleBox.right();
338  int bbBottom = visibleBox.bottom();
339 
340  QImage image(bbWidth, bbHeight, QImage::Format_ARGB32);
341 
342  for (int y = bbTop; y <= bbBottom; y++) {
343  QRgb *lineData = (QRgb *)image.scanLine(y - bbTop);
344 
345  for (int x = bbLeft; x <= bbRight; x++) {
346  lineData[x - bbLeft] = qRgba(0, 0, 0, 0);
347 
348  // We have an x,y in screen space. Let's translate it to
349  // projected space, ask the polygon if it's in the area,
350  QPointF scenePos = m_scene->getView()->mapToScene(
351  QPoint(x, y));
352 
353  if(polygon->polygon().containsPoint(scenePos, Qt::OddEvenFill)) {
354  // This is likely in the cube... use the projection to go to
355  // lat/lon and use that lat/lon to go to cube sample,line
356  m_scene->getProjection()->SetCoordinate(scenePos.x(),
357  -1 * scenePos.y());
358 
359  double lat = ((TProjection *)(m_scene->getProjection()))->UniversalLatitude();
360  double lon = ((TProjection *)(m_scene->getProjection()))->UniversalLongitude();
361 
362  if(m_image) {
363  if(!groundMap) {
364  groundMap = new UniversalGroundMap(*m_image->cube());
365  }
366 
367  if(groundMap->SetUniversalGround(lat, lon)) {
368  double dn = Null;
369 
370  if(groundMap->Camera() && groundMap->Camera()->InCube()) {
371  double samp = groundMap->Camera()->Sample();
372  double line = groundMap->Camera()->Line();
373 
374  dn = getPixelValue((int)(samp + 0.5),
375  (int)(line + 0.5));
376  }
377  else {
378  double samp = groundMap->Projection()->WorldX();
379  double line = groundMap->Projection()->WorldY();
380 
381  dn = getPixelValue((int)(samp + 0.5),
382  (int)(line + 0.5));
383  }
384 
385  if(!IsSpecial(dn)) {
386  int stretched = (int)stretch->Map(dn);
387 
388  lineData[x - bbLeft] = qRgba(stretched, stretched,
389  stretched, 255);
390  }
391  }
392  }
393  }
394  }
395  }
396 
397 // m_lastImages.append(image);
398  painter->drawImage(polygon->boundingRect(), image);
399  }
400  }
401  catch(IException &e) {
402  e.print();
403  }
404 
405  QApplication::restoreOverrideCursor();
406  }
407 
408 
409  QColor MosaicSceneItem::color() const {
410  return
411  m_image->displayProperties()->getValue(ImageDisplayProperties::Color).value<QColor>();
412  }
413 
414 
420  if (!m_ignoreCubeDisplayChanged) {
421  bool wasBlocking = m_scene->blockSelectionChange(true);
422  updateSelection(false);
423  m_scene->blockSelectionChange(wasBlocking);
424 
425  if (m_showingLabel !=
427  // Reproject will create or not create a label item correctly. This is an important speed
428  // improvement - invisible items still cost us time.
429  reproject();
430  }
431  else {
432  updateChildren();
433  }
434  }
435  }
436 
437 
447  bool MosaicSceneItem::sceneEvent(QEvent *event) {
448  // We need to verify this event is really ours
449  QPointF scenePos;
450 
451  switch (event->type()) {
452  case QEvent::GraphicsSceneContextMenu:
453  scenePos = ((QGraphicsSceneContextMenuEvent *)event)->scenePos();
454  break;
455  case QEvent::GraphicsSceneHoverEnter:
456  case QEvent::GraphicsSceneHoverMove:
457  case QEvent::GraphicsSceneHoverLeave:
458  scenePos = ((QGraphicsSceneHoverEvent *)event)->scenePos();
459  break;
460  case QEvent::GraphicsSceneMouseMove:
461  case QEvent::GraphicsSceneMousePress:
462  case QEvent::GraphicsSceneMouseRelease:
463  case QEvent::GraphicsSceneMouseDoubleClick:
464  scenePos = ((QGraphicsSceneMouseEvent *)event)->scenePos();
465  break;
466  default:
467  break;
468  }
469 
470  bool ourEvent = true;
471  if(!scenePos.isNull()) {
472  ourEvent = contains(scenePos);
473  }
474 
475  if(ourEvent) {
476  return QGraphicsObject::sceneEvent(event);
477  }
478  else {
479  event->ignore();
480  return true;
481  }
482  }
483 
484 
489  bool MosaicSceneItem::contains(const QPointF &p) const {
490  if(p.isNull())
491  return false;
492 
493  QGraphicsPolygonItem * polygon;
494  foreach(polygon, *m_polygons) {
495  if(polygon->contains(p)) {
496  return true;
497  }
498  }
499 
500  return false;
501  }
502 
503 
512  QGraphicsPolygonItem * polygon;
513 
514  m_ignoreCubeDisplayChanged = true;
515  if (m_image) {
516  bool selected =
518 
519  if(save) {
520  selected = isSelected();
521 
522  // This code only works if the polygons are in the scene.
523  foreach(polygon, *m_polygons) {
524  selected = selected || (polygon->scene() && polygon->isSelected());
525  }
526 
527  m_image->displayProperties()->setSelected(selected);
528  }
529 
530  if(selected != isSelected()) {
531  bool wasBlocking = m_scene->blockSelectionChange(true);
532  setSelected(selected);
533  m_scene->blockSelectionChange(wasBlocking);
534  }
535 
536  foreach(polygon, *m_polygons) {
537  if(polygon->isSelected() != selected) {
538  polygon->setSelected(selected);
539  }
540  }
541  }
542  m_ignoreCubeDisplayChanged = false;
543  }
544 
545 
552  QGraphicsSceneContextMenuEvent *event) {
553  if(m_image) {
554  QMenu menu;
555 
556  QAction *title = menu.addAction(m_image->displayProperties()->displayName());
557  title->setEnabled(false);
558  menu.addSeparator();
559 
560  ImageList images;
561  images.append(m_image);
562 
563  Directory *directory = m_scene->directory();
564  Project *project = directory ? directory->project() : NULL;
565 
566  QList<QAction *> displayActs = images.supportedActions(project);
567 
568  if (directory) {
569  displayActs.append(NULL);
570  displayActs.append(directory->supportedActions(new ImageList(images)));
571  }
572 
573  QAction *displayAct;
574  foreach(displayAct, displayActs) {
575  if (displayAct == NULL) {
576  menu.addSeparator();
577  }
578  else {
579  menu.addAction(displayAct);
580  }
581  }
582 
583  menu.addSeparator();
584  QAction *removeAction = menu.addAction("Close Cube");
585  connect(removeAction, SIGNAL(triggered()),
586  m_image, SLOT(deleteLater()));
587 
588  menu.exec(event->screenPos());
589  }
590  }
591 
592 
593  void MosaicSceneItem::lostCubeDisplay() {
594  m_image = NULL;
595  }
596 
597 
604  if (childItems().count()) {
605  setFlag(QGraphicsItem::ItemIsSelectable, false);
606  }
607  else {
608  setFlag(QGraphicsItem::ItemIsSelectable, m_scene->cubesSelectable());
609  }
610 
611  QList<QRectF> regionsChanged;
612 
613  if(m_image) {
614  foreach(QAbstractGraphicsShapeItem *polygon, *m_polygons) {
615  // Fill
616  if (m_image->displayProperties()->getValue(ImageDisplayProperties::ShowFill).toBool()) {
617  polygon->setBrush(color());
618  }
619  else {
620  polygon->setBrush(Qt::NoBrush);
621  }
622 
623  // Outline
624  QColor opaqueColor(color());
625  opaqueColor.setAlpha(255);
627  polygon->setPen(opaqueColor);
628  }
629  else {
630  polygon->setPen(Qt::NoPen);
631  }
632 
633  polygon->setFlag(QGraphicsItem::ItemIsSelectable,
634  m_scene->cubesSelectable());
635 
636  // Children (labels are the only children, and there should only be one)
637  foreach(QGraphicsItem *polyChild, polygon->childItems()) {
638  polyChild->setVisible(
640 
641  polyChild->setFlag(QGraphicsItem::ItemIsSelectable,
642  m_scene->cubesSelectable());
643 
644  // Qt documentation was lacking the enum that this matches to, so this
645  // is the best I could do
646  if(polyChild->type() == 9) {
647  QGraphicsSimpleTextItem * text =
648  (QGraphicsSimpleTextItem *)polyChild;
649  text->setBrush(opaqueColor);
650  }
651  }
652  }
653 
654  update();
655  emit changed(regionsChanged);
656  }
657  }
658 
659 
668  if (m_cubeDnStretch != NULL || !m_image) return m_cubeDnStretch;
669 
670  LineManager mgr(*m_image->cube());
671 
672  mgr.begin();
673  Statistics stats;
674 
675  const int skip = 0;
676 
677  while(mgr ++) {
678  m_image->cube()->read(mgr);
679  stats.AddData(mgr.DoubleBuffer(), mgr.size());
680 
681  for(int i = 0; i < skip; i++)
682  mgr ++;
683  }
684 
685  m_cubeDnStretch = new Stretch();
686  m_cubeDnStretch->AddPair(stats.BestMinimum(), 0.0);
687  m_cubeDnStretch->AddPair(stats.BestMaximum(), 255.0);
688 
689  m_cubeDnStretch->SetNull(0.0);
690  m_cubeDnStretch->SetLis(0.0);
691  m_cubeDnStretch->SetLrs(0.0);
692  m_cubeDnStretch->SetHis(255.0);
693  m_cubeDnStretch->SetHrs(255.0);
694  m_cubeDnStretch->SetMinimum(0.0);
695  m_cubeDnStretch->SetMaximum(255.0);
696 
697  return m_cubeDnStretch;
698  }
699 }