Isis 3.0 Object Programmers' Reference |
Home |
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 }