USGS

Isis 3.0 Object Programmers' Reference

Home

MosaicSceneItem.cpp

00001 #include "MosaicSceneItem.h"
00002 
00003 #include <iostream>
00004 #include <cfloat>
00005 
00006 #include <QApplication>
00007 #include <QBrush>
00008 #include <QEvent>
00009 #include <QGraphicsItem>
00010 #include <QList>
00011 #include <QPainter>
00012 #include <QPen>
00013 #include <QStyleOptionGraphicsItem>
00014 #include <QTreeWidgetItem>
00015 
00016 #include "CubeDisplayProperties.h"
00017 #include "FileDialog.h"
00018 #include "Histogram.h"
00019 #include "iString.h"
00020 #include "ImagePolygon.h"
00021 #include "LineManager.h"
00022 #include "MosaicGraphicsView.h"
00023 #include "MosaicSceneWidget.h"
00024 #include "PolygonTools.h"
00025 #include "SerialNumber.h"
00026 #include "Statistics.h"
00027 #include "Stretch.h"
00028 #include "Table.h"
00029 
00030 using namespace geos::geom;
00031 
00032 namespace Isis {
00040   MosaicSceneItem::MosaicSceneItem(CubeDisplayProperties *cubeDisplay,
00041       MosaicSceneWidget *parent) : QGraphicsObject() {
00042     if (parent->getProjection() == NULL) {
00043       std::string msg = "Parent does not have projection in MosaicWidget";
00044       throw iException::Message(iException::User, msg, _FILEINFO_);
00045     }
00046 
00047     m_cubeDisplay = cubeDisplay;
00048 
00049     connect(m_cubeDisplay, SIGNAL(destroyed(QObject *)),
00050             this, SLOT(lostCubeDisplay()));
00051     connect(m_cubeDisplay, SIGNAL(destroyed(QObject *)),
00052             this, SLOT(deleteLater()));
00053 
00054     m_mp = NULL;
00055     m_polygons = NULL;
00056     m_cubeDnStretch = NULL;
00057     groundMap = NULL;
00058 
00059     m_scene = parent;
00060 
00061     m_polygons = new QList< QGraphicsPolygonItem *>();
00062 
00063     setupFootprint();
00064 
00065     setToolTip(m_cubeDisplay->displayName());
00066 
00067     setAcceptHoverEvents(true);
00068 
00069     m_cubeDisplay->addSupport(CubeDisplayProperties::Color);
00070     m_cubeDisplay->addSupport(CubeDisplayProperties::Selected);
00071     m_cubeDisplay->addSupport(CubeDisplayProperties::ShowDNs);
00072     m_cubeDisplay->addSupport(CubeDisplayProperties::ShowFill);
00073     m_cubeDisplay->addSupport(CubeDisplayProperties::ShowLabel);
00074     m_cubeDisplay->addSupport(CubeDisplayProperties::ShowOutline);
00075 
00076     if(parent->userHasTools()) {
00077       m_cubeDisplay->addSupport(CubeDisplayProperties::Zooming);
00078     }
00079 
00080     m_cubeDisplay->addSupport(CubeDisplayProperties::ZOrdering);
00081 
00082     connect(m_cubeDisplay, SIGNAL(propertyChanged(CubeDisplayProperties *)),
00083             this, SLOT(cubeDisplayChanged()));
00084   }
00085 
00086 
00091   MosaicSceneItem::~MosaicSceneItem() {
00092     if(scene())
00093       scene()->removeItem(this);
00094 
00095     while(m_polygons->size()) {
00096       delete m_polygons->takeAt(0);
00097     }
00098   }
00099 
00100 
00101   QRectF MosaicSceneItem::boundingRect() const {
00102     QRectF boundingRect;
00103 
00104     QGraphicsPolygonItem *polygon;
00105     foreach(polygon, *m_polygons) {
00106       boundingRect = boundingRect.united(polygon->boundingRect());
00107 
00108       QGraphicsItem *polyChild;
00109       foreach(polyChild, polygon->childItems()) {
00110         if(polyChild->isVisible()) {
00111           boundingRect = boundingRect.united(
00112             mapFromItem(polyChild, polyChild->boundingRect()).boundingRect());
00113         }
00114       }
00115     }
00116 
00117     return boundingRect;
00118   }
00119 
00120 
00128   void MosaicSceneItem::paint(QPainter *painter,
00129       const QStyleOptionGraphicsItem *option, QWidget *widget) {
00130     if(m_cubeDisplay &&
00131        m_cubeDisplay->getValue(CubeDisplayProperties::ShowDNs).toBool()) {
00132       drawImage(painter, option);
00133     }
00134   }
00135 
00136 
00140   void MosaicSceneItem::setupFootprint() {
00141     if(m_cubeDisplay) {
00142       m_mp = m_cubeDisplay->footprint();
00143 
00144       try {
00145         reproject();
00146       }
00147       catch(iException &e) {
00148         m_cubeDisplay->deleteLater();
00149 
00150         iString msg = "Could not project the footprint from cube [" +
00151             m_cubeDisplay->displayName() + "]";
00152         throw iException::Message(iException::Io, msg, _FILEINFO_);
00153       }
00154     }
00155   }
00156 
00157 
00162   void MosaicSceneItem::reproject() {
00163     prepareGeometryChange();
00164 
00165     MultiPolygon *mp;
00166     Projection *proj = m_scene->getProjection();
00167 
00168     // Remove current polygons from the scene
00169     while(m_polygons->size()) {
00170       QGraphicsPolygonItem *polyItem = m_polygons->at(0);
00171       m_scene->getScene()->removeItem(polyItem);
00172       m_polygons->removeAll(polyItem);
00173 
00174       delete polyItem;
00175       polyItem = NULL;
00176     }
00177 
00178     if (proj->Has180Domain()) {
00179       m_180mp = PolygonTools::To180(m_mp);
00180       mp = m_180mp;
00181     }
00182     else {
00183       mp = m_mp;
00184     }
00185 
00186     //----------------------------------------------------------
00187     // We need to loop thru the num. geom. because some of the
00188     // cubes will have more than one geom. if it crosses lat/lon
00189     // boundries.
00190     //----------------------------------------------------------
00191     for (unsigned int i = 0; i < mp->getNumGeometries(); i++) {
00192       const Geometry *geom = mp->getGeometryN(i);
00193       CoordinateSequence *pts;
00194 
00195       pts = geom->getCoordinates();
00196       double lat, lon;
00197       QVector<QPointF> polyPoints;
00198 
00199       //--------------------------------------------------------------
00200       // We need to convert the footprint polygons from lat/lon to x/y
00201       // in order to display them in the QGraphicsScene
00202       //--------------------------------------------------------------
00203       for (unsigned int j = 0; j < pts->getSize(); j++) {
00204         lat = pts->getY(j);
00205         lon = pts->getX(j);
00206         if (proj->SetUniversalGround(lat, lon)) {
00207           double x = proj->XCoord();
00208           double y = -1 * (proj->YCoord());
00209 
00210           polyPoints.push_back(QPointF(x, y));
00211         }
00212       }
00213 
00214       setFlag(QGraphicsItem::ItemIsSelectable);
00215 
00216       QGraphicsPolygonItem *polyItem = new QGraphicsPolygonItem(this);
00217       polyItem->setPolygon(QPolygonF(polyPoints));
00218 
00219       QGraphicsSimpleTextItem *label = new QGraphicsSimpleTextItem(polyItem);
00220       if(m_cubeDisplay)
00221         label->setText(m_cubeDisplay->displayName());
00222       label->setFlag(QGraphicsItem::ItemIsMovable);
00223       label->setFont(QFont("Helvetica", 10));
00224       label->setPos(polyItem->polygon().boundingRect().center());
00225       label->setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
00226 
00227       QRectF boundingRect = polyItem->boundingRect();
00228       if(boundingRect.width() < boundingRect.height())
00229         label->rotate(90);
00230 
00231       m_polygons->append(polyItem);
00232 
00233       delete pts;
00234     }
00235 
00236     updateChildren();
00237   }
00238 
00239 
00249   double MosaicSceneItem::getPixelValue(int sample, int line) {
00250     double pixelValue = 0;
00251 
00252     if(m_cubeDisplay) {
00253       Brick gryBrick(1, 1, 1, m_cubeDisplay->cube()->getPixelType());
00254       gryBrick.SetBasePosition((int)(sample + 0.5), (int)(line + 0.5), 1);
00255       m_cubeDisplay->cube()->read(gryBrick);
00256 
00257       pixelValue = gryBrick[0];
00258       if (pixelValue == Null) {
00259         return Null;
00260       }
00261       if (pixelValue < 0) pixelValue = 0;
00262       if (pixelValue > 255) pixelValue = 255;
00263     }
00264 
00265     return pixelValue;
00266   }
00267 
00268 
00274   void MosaicSceneItem::drawImage(QPainter *painter,
00275       const QStyleOptionGraphicsItem *option) {
00276     Stretch *stretch = getStretch();
00277     QApplication::setOverrideCursor(Qt::WaitCursor);
00278 
00279     try {
00280       QGraphicsPolygonItem *polygon;
00281       foreach(polygon, *m_polygons) {
00282         QPolygonF polyBounding = polygon->polygon();
00283         QRectF sceneRect = polyBounding.boundingRect();
00284         QPolygon screenPoly = m_scene->getView()->mapFromScene(sceneRect);
00285         QRect visibleBox = screenPoly.boundingRect();
00286 
00287         int bbWidth  = (int)visibleBox.width();
00288         int bbHeight = (int)visibleBox.height();
00289 
00290         int bbLeft = visibleBox.left();
00291         int bbTop = visibleBox.top();
00292         int bbRight = visibleBox.right();
00293         int bbBottom = visibleBox.bottom();
00294 
00295         QImage image(bbWidth, bbHeight, QImage::Format_ARGB32);
00296 
00297         for (int y = bbTop; y <= bbBottom; y++) {
00298           QRgb *lineData = (QRgb *)image.scanLine(y - bbTop);
00299 
00300           for (int x = bbLeft; x <= bbRight; x++) {
00301             lineData[x - bbLeft] = qRgba(0, 0, 0, 0);
00302 
00303             // We have an x,y in screen space. Let's translate it to
00304             //   projected space, ask the polygon if it's in the area,
00305             QPointF scenePos = m_scene->getView()->mapToScene(
00306                 QPoint(x, y));
00307 
00308             if(polygon->polygon().containsPoint(scenePos, Qt::OddEvenFill)) {
00309               // This is likely in the cube... use the projection to go to
00310               //   lat/lon and use that lat/lon to go to cube sample,line
00311               m_scene->getProjection()->SetCoordinate(scenePos.x(),
00312                                                       -1 * scenePos.y());
00313 
00314               double lat = m_scene->getProjection()->UniversalLatitude();
00315               double lon = m_scene->getProjection()->UniversalLongitude();
00316 
00317               if(m_cubeDisplay) {
00318                 if(!groundMap) {
00319                   groundMap = new UniversalGroundMap(*m_cubeDisplay->cube());
00320                 }
00321 
00322                 if(groundMap->SetUniversalGround(lat, lon)) {
00323                   double dn = Null;
00324 
00325                   if(groundMap->Camera() && groundMap->Camera()->InCube()) {
00326                     double samp = groundMap->Camera()->Sample();
00327                     double line = groundMap->Camera()->Line();
00328 
00329                     dn = getPixelValue((int)(samp + 0.5),
00330                                        (int)(line + 0.5));
00331                   }
00332                   else {
00333                     double samp = groundMap->Projection()->WorldX();
00334                     double line = groundMap->Projection()->WorldY();
00335 
00336                     dn = getPixelValue((int)(samp + 0.5),
00337                                        (int)(line + 0.5));
00338                   }
00339 
00340                   if(!IsSpecial(dn)) {
00341                     int stretched = (int)stretch->Map(dn);
00342 
00343                     lineData[x - bbLeft] = qRgba(stretched, stretched,
00344                                                 stretched, 255);
00345                   }
00346                 }
00347               }
00348             }
00349           }
00350         }
00351 
00352 //         m_lastImages.append(image);
00353         painter->drawImage(polygon->boundingRect(), image);
00354       }
00355     }
00356     catch(iException &e) {
00357       e.Report();
00358       e.Clear();
00359     }
00360 
00361     QApplication::restoreOverrideCursor();
00362   }
00363 
00364 
00365   QColor MosaicSceneItem::color() const {
00366     return
00367         m_cubeDisplay->getValue(CubeDisplayProperties::Color).value<QColor>();
00368   }
00369 
00370 
00375   void MosaicSceneItem::cubeDisplayChanged() {
00376     m_scene->blockSelectionChange(true);
00377     updateSelection(false);
00378     m_scene->blockSelectionChange(false);
00379 
00380     updateChildren();
00381   }
00382 
00383 
00393   bool MosaicSceneItem::sceneEvent(QEvent *event) {
00394     // We need to verify this event is really ours
00395     QPointF scenePos;
00396 
00397     switch (event->type()) {
00398       case QEvent::GraphicsSceneContextMenu:
00399         scenePos = ((QGraphicsSceneContextMenuEvent *)event)->scenePos();
00400         break;
00401       case QEvent::GraphicsSceneHoverEnter:
00402       case QEvent::GraphicsSceneHoverMove:
00403       case QEvent::GraphicsSceneHoverLeave:
00404         scenePos = ((QGraphicsSceneHoverEvent *)event)->scenePos();
00405         break;
00406       case QEvent::GraphicsSceneMouseMove:
00407       case QEvent::GraphicsSceneMousePress:
00408       case QEvent::GraphicsSceneMouseRelease:
00409       case QEvent::GraphicsSceneMouseDoubleClick:
00410         scenePos = ((QGraphicsSceneMouseEvent *)event)->scenePos();
00411         break;
00412       default:
00413         break;
00414     }
00415 
00416     bool ourEvent = true;
00417     if(!scenePos.isNull()) {
00418       ourEvent = contains(scenePos);
00419     }
00420 
00421     if(ourEvent) {
00422       return QGraphicsObject::sceneEvent(event);
00423     }
00424     else {
00425       event->ignore();
00426       return true;
00427     }
00428   }
00429 
00430 
00435   bool MosaicSceneItem::contains(const QPointF &p) const {
00436     if(p.isNull())
00437       return false;
00438 
00439     QGraphicsPolygonItem * polygon;
00440     foreach(polygon, *m_polygons) {
00441       if(polygon->contains(p)) {
00442         return true;
00443       }
00444     }
00445 
00446     return false;
00447   }
00448 
00449 
00456   void MosaicSceneItem::updateSelection(bool save) {
00457     QGraphicsPolygonItem * polygon;
00458     if(save && m_cubeDisplay) {
00459       bool selected = isSelected();
00460 
00461       foreach(polygon, *m_polygons) {
00462         selected = selected || polygon->isSelected();
00463       }
00464 
00465       m_cubeDisplay->setSelected(selected);
00466       updateSelection(false);
00467     }
00468     else if(m_cubeDisplay) {
00469       bool selected =
00470           m_cubeDisplay->getValue(CubeDisplayProperties::Selected).toBool();
00471 
00472       if(selected != isSelected()) {
00473         setSelected(selected);
00474       }
00475 
00476       foreach(polygon, *m_polygons) {
00477         if(polygon->isSelected() != selected) {
00478           polygon->setSelected(selected);
00479         }
00480       }
00481     }
00482 
00483   }
00484 
00485 
00491   void MosaicSceneItem::contextMenuEvent(
00492       QGraphicsSceneContextMenuEvent *event) {
00493     if(m_cubeDisplay) {
00494       QMenu menu;
00495 
00496       QAction *title = menu.addAction(m_cubeDisplay->displayName());
00497       title->setEnabled(false);
00498       menu.addSeparator();
00499 
00500       QList<CubeDisplayProperties *> cubeDisplays;
00501       cubeDisplays.append(m_cubeDisplay);
00502 
00503       QList<QAction *> displayActs =
00504           CubeDisplayProperties::getSupportedDisplayActions(cubeDisplays);
00505 
00506       QAction *displayAct;
00507       foreach(displayAct, displayActs) {
00508         menu.addAction(displayAct);
00509       }
00510 
00511       QList<QAction *> zoomActs =
00512           CubeDisplayProperties::getSupportedZoomActions(cubeDisplays);
00513 
00514       QList<QAction *> zActs =
00515           CubeDisplayProperties::getSupportedZOrderActions(cubeDisplays);
00516 
00517       if((zoomActs.size() || zActs.size()) && displayActs.size()) {
00518         menu.addSeparator();
00519       }
00520 
00521       QAction *zoomAct;
00522       foreach(zoomAct, zoomActs) {
00523         menu.addAction(zoomAct);
00524       }
00525 
00526       QAction *zAct;
00527       foreach(zAct, zActs) {
00528         menu.addAction(zAct);
00529       }
00530 
00531       menu.addSeparator();
00532       QAction *removeAction = menu.addAction("Close Cube");
00533       connect(removeAction, SIGNAL(triggered()),
00534               m_cubeDisplay, SLOT(deleteLater()));
00535 
00536       menu.exec(event->screenPos());
00537     }
00538   }
00539 
00540 
00541   void MosaicSceneItem::lostCubeDisplay() {
00542     m_cubeDisplay = NULL;
00543   }
00544 
00545 
00551   void MosaicSceneItem::updateChildren() {
00552     setFlag(QGraphicsItem::ItemIsSelectable, m_scene->cubesSelectable());
00553 
00554     QList<QRectF> regionsChanged;
00555 
00556     if(m_cubeDisplay) {
00557       QGraphicsPolygonItem * polygon;
00558       foreach(polygon, *m_polygons) {
00559         // Fill
00560         if(m_cubeDisplay->getValue(CubeDisplayProperties::ShowFill).toBool())
00561           polygon->setBrush(color());
00562         else
00563           polygon->setBrush(Qt::NoBrush);
00564 
00565         // Outline
00566         QColor opaqueColor(color());
00567         opaqueColor.setAlpha(255);
00568         if(m_cubeDisplay->getValue(CubeDisplayProperties::ShowOutline).toBool())
00569           polygon->setPen(opaqueColor);
00570         else
00571           polygon->setPen(Qt::NoPen);
00572 
00573         polygon->setFlag(QGraphicsItem::ItemIsSelectable,
00574                         m_scene->cubesSelectable());
00575 
00576         // Children (label is the only child)
00577         QGraphicsItem *polyChild;
00578         foreach(polyChild, polygon->childItems()) {
00579           polyChild->setVisible(
00580               m_cubeDisplay->getValue(
00581                 CubeDisplayProperties::ShowLabel).toBool());
00582 
00583           // Qt documentation was lacking the enum that this matches to, so this
00584           //   is the best I could do
00585           if(polyChild->type() == 9) {
00586             QGraphicsSimpleTextItem * text =
00587                 (QGraphicsSimpleTextItem *)polyChild;
00588             text->setBrush(opaqueColor);
00589           }
00590         }
00591       }
00592 
00593       update();
00594       emit changed(regionsChanged);
00595     }
00596   }
00597 
00598 
00606   Stretch *MosaicSceneItem::getStretch() {
00607     if (m_cubeDnStretch != NULL || !m_cubeDisplay) return m_cubeDnStretch;
00608 
00609     LineManager mgr(*m_cubeDisplay->cube());
00610 
00611     mgr.begin();
00612     Statistics stats;
00613 
00614     const int skip = 0;
00615 
00616     while(mgr ++) {
00617       m_cubeDisplay->cube()->read(mgr);
00618       stats.AddData(mgr.DoubleBuffer(), mgr.size());
00619 
00620       for(int i = 0; i < skip; i++)
00621         mgr ++;
00622     }
00623 
00624     m_cubeDnStretch = new Stretch();
00625     m_cubeDnStretch->AddPair(stats.BestMinimum(), 0.0);
00626     m_cubeDnStretch->AddPair(stats.BestMaximum(), 255.0);
00627 
00628     m_cubeDnStretch->SetNull(0.0);
00629     m_cubeDnStretch->SetLis(0.0);
00630     m_cubeDnStretch->SetLrs(0.0);
00631     m_cubeDnStretch->SetHis(255.0);
00632     m_cubeDnStretch->SetHrs(255.0);
00633     m_cubeDnStretch->SetMinimum(0.0);
00634     m_cubeDnStretch->SetMaximum(255.0);
00635 
00636     return m_cubeDnStretch;
00637   }
00638 }