Isis 3 Programmer Reference
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 <QGraphicsSceneContextMenuEvent>
11#include <QList>
12#include <QMenu>
13#include <QPainter>
14#include <QPen>
15#include <QStyleOptionGraphicsItem>
16#include <QTreeWidgetItem>
17
18#include "Directory.h"
19#include "DisplayProperties.h"
20#include "FileDialog.h"
21#include "Histogram.h"
22#include "Image.h"
23#include "ImageList.h"
24#include "ImagePolygon.h"
25#include "IString.h"
26#include "LineManager.h"
27#include "MosaicGraphicsView.h"
28#include "MosaicSceneWidget.h"
29#include "PolygonTools.h"
30#include "Project.h"
31#include "SerialNumber.h"
32#include "Statistics.h"
33#include "Stretch.h"
34#include "Table.h"
35#include "TProjection.h"
36
37using namespace geos::geom;
38
39namespace Isis {
48 if (parent->getProjection() == NULL) {
49 std::string msg = "Parent does not have projection in MosaicWidget";
50 throw IException(IException::User, msg, _FILEINFO_);
51 }
52
53 m_image = image;
54
55 connect(m_image, SIGNAL(destroyed(QObject *)),
56 this, SLOT(lostCubeDisplay()));
57 connect(m_image, SIGNAL(destroyed(QObject *)),
58 this, SLOT(deleteLater()));
59
60 m_mp = NULL;
61 m_polygons = NULL;
62 m_cubeDnStretch = NULL;
63 groundMap = NULL;
64 m_showingLabel = false;
65 m_ignoreCubeDisplayChanged = false;
66
67 m_scene = parent;
68
69 m_polygons = new QList< QGraphicsPolygonItem *>();
70
71 setupFootprint();
72
73 setToolTip(m_image->displayProperties()->displayName());
74
75 setAcceptHoverEvents(true);
76
77 ImageDisplayProperties *displayProp = m_image->displayProperties();
86
87 if(parent->userHasTools()) {
89 (supportToAdd | ImageDisplayProperties::Zooming);
90 }
91
92 displayProp->addSupport(supportToAdd);
93
94 connect(displayProp, SIGNAL(propertyChanged(DisplayProperties *)),
95 this, SLOT(cubeDisplayChanged()));
96 }
97
98
104 if(scene())
105 scene()->removeItem(this);
106
107 while(m_polygons->size()) {
108 delete m_polygons->takeAt(0);
109 }
110 }
111
112
113 QRectF MosaicSceneItem::boundingRect() const {
114 QRectF boundingRect;
115
116 QGraphicsPolygonItem *polygon;
117 foreach(polygon, *m_polygons) {
118 boundingRect = boundingRect.united(polygon->boundingRect());
119
120 QGraphicsItem *polyChild;
121 foreach(polyChild, polygon->childItems()) {
122 if(polyChild->isVisible()) {
123 boundingRect = boundingRect.united(
124 mapFromItem(polyChild, polyChild->boundingRect()).boundingRect());
125 }
126 }
127 }
128
129 return boundingRect;
130 }
131
132
140 void MosaicSceneItem::paint(QPainter *painter,
141 const QStyleOptionGraphicsItem *option, QWidget *widget) {
142 if(m_image &&
144 drawImage(painter, option);
145 }
146
147 // We don't add the polygon items as children because manually painting them is a huge speed
148 // improvement. It cannot be undone due to the amount of speed it gives.
149 if (!childItems().count()) {
150 foreach (QGraphicsPolygonItem *polyItem, *m_polygons) {
151 polyItem->paint(painter, option, widget);
152 }
153 }
154 }
155
156
160 void MosaicSceneItem::setupFootprint() {
161 if(m_image) {
162 m_mp = m_image->footprint();
163
164 if (!m_mp) {
166 tr("Cannot display footprints of images which have no footprints. "
167 "Tried to display [%1]").arg(m_image->displayProperties()->displayName()),
168 _FILEINFO_);
169 }
170
171 try {
172 reproject();
173 }
174 catch(IException &e) {
175 m_image->deleteLater();
176
177 IString msg = "Could not project the footprint from cube [" +
178 m_image->displayProperties()->displayName() + "]";
179 throw IException(e, IException::Unknown, msg, _FILEINFO_);
180 }
181 }
182 }
183
184
190 prepareGeometryChange();
191
192 MultiPolygon *mp;
193 TProjection *proj = (TProjection *)m_scene->getProjection();
194
195 // Remove current polygons from the scene
196 while(m_polygons->size()) {
197 QGraphicsPolygonItem *polyItem = m_polygons->at(0);
198
199 if (polyItem->scene()) {
200 polyItem->scene()->removeItem(polyItem);
201 }
202 m_polygons->removeAll(polyItem);
203
204 delete polyItem;
205 polyItem = NULL;
206 }
207
208 if (proj->Has180Domain()) {
210 mp = m_180mp;
211 }
212 else {
213 mp = m_mp;
214 }
215
216 m_showingLabel =
218
219 //----------------------------------------------------------
220 // We need to loop thru the num. geom. because some of the
221 // cubes will have more than one geom. if it crosses lat/lon
222 // boundries.
223 //----------------------------------------------------------
224 bool useFullChildrenHierarchy = (mp->getNumGeometries() > 1) || m_showingLabel;
225
226 for (unsigned int i = 0; i < mp->getNumGeometries(); i++) {
227 const Geometry *geom = mp->getGeometryN(i);
228 CoordinateSequence *pts;
229
230 pts = geom->getCoordinates().release();
231 double lat, lon;
232 QVector<QPointF> polyPoints;
233
234 //--------------------------------------------------------------
235 // We need to convert the footprint polygons from lat/lon to x/y
236 // in order to display them in the QGraphicsScene
237 //--------------------------------------------------------------
238 for (unsigned int j = 0; j < pts->getSize(); j++) {
239 lat = pts->getY(j);
240 lon = pts->getX(j);
241 if (proj->SetGround(lat, lon)) {
242 double x = proj->XCoord();
243 double y = -1 * (proj->YCoord());
244
245 polyPoints.push_back(QPointF(x, y));
246 }
247 }
248
249 setFlag(QGraphicsItem::ItemIsSelectable, true);
250 setFlag(QGraphicsItem::ItemIsFocusable, true);
251
252 QGraphicsPolygonItem *polyItem = NULL;
253
254 if (useFullChildrenHierarchy) {
255 polyItem = new QGraphicsPolygonItem(this);
256 }
257 else {
258 polyItem = new QGraphicsPolygonItem;
259 }
260
261 polyItem->setPolygon(QPolygonF(polyPoints));
262
263 if (m_showingLabel) {
264 QGraphicsSimpleTextItem *label = NULL;
265
266 label = new QGraphicsSimpleTextItem(polyItem);
267
268 if(m_image)
269 label->setText(m_image->displayProperties()->displayName());
270 label->setFlag(QGraphicsItem::ItemIsMovable);
271 label->setFont(QFont("Helvetica", 10));
272 label->setPos(polyItem->polygon().boundingRect().center());
273 label->setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
274
275 QRectF boundingRect = polyItem->boundingRect();
276 if(boundingRect.width() < boundingRect.height())
277 label->setRotation(90.0);
278 }
279
280 m_polygons->append(polyItem);
281
282 delete pts;
283 }
284
286 }
287
288
298 double MosaicSceneItem::getPixelValue(int sample, int line) {
299 double pixelValue = 0;
300
301 if(m_image) {
302 Brick gryBrick(1, 1, 1, m_image->cube()->pixelType());
303 gryBrick.SetBasePosition((int)(sample + 0.5), (int)(line + 0.5), 1);
304 m_image->cube()->read(gryBrick);
305
306 pixelValue = gryBrick[0];
307 if (pixelValue == Null) {
308 return Null;
309 }
310 if (pixelValue < 0) pixelValue = 0;
311 if (pixelValue > 255) pixelValue = 255;
312 }
313
314 return pixelValue;
315 }
316
317
323 void MosaicSceneItem::drawImage(QPainter *painter,
324 const QStyleOptionGraphicsItem *option) {
325 Stretch *stretch = getStretch();
326 QApplication::setOverrideCursor(Qt::WaitCursor);
327
328 try {
329 QGraphicsPolygonItem *polygon;
330 foreach(polygon, *m_polygons) {
331 QPolygonF polyBounding = polygon->polygon();
332 QRectF sceneRect = polyBounding.boundingRect();
333 QPolygon screenPoly = m_scene->getView()->mapFromScene(sceneRect);
334 QRect visibleBox = screenPoly.boundingRect();
335
336 int bbWidth = (int)visibleBox.width();
337 int bbHeight = (int)visibleBox.height();
338
339 int bbLeft = visibleBox.left();
340 int bbTop = visibleBox.top();
341 int bbRight = visibleBox.right();
342 int bbBottom = visibleBox.bottom();
343
344 QImage image(bbWidth, bbHeight, QImage::Format_ARGB32);
345
346 for (int y = bbTop; y <= bbBottom; y++) {
347 QRgb *lineData = (QRgb *)image.scanLine(y - bbTop);
348
349 for (int x = bbLeft; x <= bbRight; x++) {
350 lineData[x - bbLeft] = qRgba(0, 0, 0, 0);
351
352 // We have an x,y in screen space. Let's translate it to
353 // projected space, ask the polygon if it's in the area,
354 QPointF scenePos = m_scene->getView()->mapToScene(
355 QPoint(x, y));
356
357 if(polygon->polygon().containsPoint(scenePos, Qt::OddEvenFill)) {
358 // This is likely in the cube... use the projection to go to
359 // lat/lon and use that lat/lon to go to cube sample,line
360 m_scene->getProjection()->SetCoordinate(scenePos.x(),
361 -1 * scenePos.y());
362
363 double lat = ((TProjection *)(m_scene->getProjection()))->UniversalLatitude();
364 double lon = ((TProjection *)(m_scene->getProjection()))->UniversalLongitude();
365
366 if(m_image) {
367 if(!groundMap) {
368 groundMap = new UniversalGroundMap(*m_image->cube());
369 }
370
371 if(groundMap->SetUniversalGround(lat, lon)) {
372 double dn = Null;
373
374 if(groundMap->Camera() && groundMap->Camera()->InCube()) {
375 double samp = groundMap->Camera()->Sample();
376 double line = groundMap->Camera()->Line();
377
378 dn = getPixelValue((int)(samp + 0.5),
379 (int)(line + 0.5));
380 }
381 else {
382 double samp = groundMap->Projection()->WorldX();
383 double line = groundMap->Projection()->WorldY();
384
385 dn = getPixelValue((int)(samp + 0.5),
386 (int)(line + 0.5));
387 }
388
389 if(!IsSpecial(dn)) {
390 int stretched = (int)stretch->Map(dn);
391
392 lineData[x - bbLeft] = qRgba(stretched, stretched,
393 stretched, 255);
394 }
395 }
396 }
397 }
398 }
399 }
400
401// m_lastImages.append(image);
402 painter->drawImage(polygon->boundingRect(), image);
403 }
404 }
405 catch(IException &e) {
406 e.print();
407 }
408
409 QApplication::restoreOverrideCursor();
410 }
411
412
413 QColor MosaicSceneItem::color() const {
414 return
415 m_image->displayProperties()->getValue(ImageDisplayProperties::Color).value<QColor>();
416 }
417
418
424 if (!m_ignoreCubeDisplayChanged) {
425 bool wasBlocking = m_scene->blockSelectionChange(true);
426 updateSelection(false);
427 m_scene->blockSelectionChange(wasBlocking);
428
429 if (m_showingLabel !=
431 // Reproject will create or not create a label item correctly. This is an important speed
432 // improvement - invisible items still cost us time.
433 reproject();
434 }
435 else {
437 }
438 }
439 }
440
441
451 bool MosaicSceneItem::sceneEvent(QEvent *event) {
452 // We need to verify this event is really ours
453 QPointF scenePos;
454
455 switch (event->type()) {
456 case QEvent::GraphicsSceneContextMenu:
457 scenePos = ((QGraphicsSceneContextMenuEvent *)event)->scenePos();
458 break;
459 case QEvent::GraphicsSceneHoverEnter:
460 case QEvent::GraphicsSceneHoverMove:
461 case QEvent::GraphicsSceneHoverLeave:
462 scenePos = ((QGraphicsSceneHoverEvent *)event)->scenePos();
463 break;
464 case QEvent::GraphicsSceneMouseMove:
465 case QEvent::GraphicsSceneMousePress:
466 case QEvent::GraphicsSceneMouseRelease:
467 case QEvent::GraphicsSceneMouseDoubleClick:
468 scenePos = ((QGraphicsSceneMouseEvent *)event)->scenePos();
469 break;
470 default:
471 break;
472 }
473
474 bool ourEvent = true;
475 if(!scenePos.isNull()) {
476 ourEvent = contains(scenePos);
477 }
478
479 if(ourEvent) {
480 return QGraphicsObject::sceneEvent(event);
481 }
482 else {
483// //qDebug()<<"MosaicSceneItem::sceneEvent Ignore event";
484 event->ignore();
485 return true;
486 }
487 }
488
489
494 bool MosaicSceneItem::contains(const QPointF &p) const {
495 if(p.isNull())
496 return false;
497
498 QGraphicsPolygonItem * polygon;
499 foreach(polygon, *m_polygons) {
500 if(polygon->contains(p)) {
501 return true;
502 }
503 }
504
505 return false;
506 }
507
508
517 QGraphicsPolygonItem * polygon;
518
519 m_ignoreCubeDisplayChanged = true;
520 if (m_image) {
521 bool selected =
523
524 if(save) {
525 selected = isSelected();
526
527 // This code only works if the polygons are in the scene.
528 foreach(polygon, *m_polygons) {
529 selected = selected || (polygon->scene() && polygon->isSelected());
530 }
531
532 m_image->displayProperties()->setSelected(selected);
533 }
534
535 if(selected != isSelected()) {
536 bool wasBlocking = m_scene->blockSelectionChange(true);
537 setSelected(selected);
538 m_scene->blockSelectionChange(wasBlocking);
539 }
540
541 foreach(polygon, *m_polygons) {
542 if(polygon->isSelected() != selected) {
543 polygon->setSelected(selected);
544 }
545 }
546 }
547 m_ignoreCubeDisplayChanged = false;
548 }
549
550
557 QGraphicsSceneContextMenuEvent *event) {
558
559 if(m_image) {
560 QMenu menu;
561
562 QAction *title = menu.addAction(m_image->displayProperties()->displayName());
563 title->setEnabled(false);
564 menu.addSeparator();
565
566 ImageList images;
567 images.append(m_image);
568
569 Directory *directory = m_scene->directory();
570 Project *project = directory ? directory->project() : NULL;
571
572 QList<QAction *> displayActs = images.supportedActions(project);
573
574 if (directory) {
575 displayActs.append(NULL);
576 displayActs.append(directory->supportedActions(new ImageList(images)));
577 }
578
579 QAction *displayAct;
580 foreach(displayAct, displayActs) {
581 if (displayAct == NULL) {
582 menu.addSeparator();
583 }
584 else {
585 menu.addAction(displayAct);
586 }
587 }
588
589 menu.addSeparator();
590 QAction *removeAction = menu.addAction("Close Cube");
591
592 if (QApplication::applicationName() == "qmos") {
593 connect(removeAction, SIGNAL(triggered()),
594 m_image, SLOT(deleteLater()));
595 }
596 else {
597 connect(removeAction, SIGNAL(triggered()), SLOT(onCloseCube()));
598 }
599
600 menu.exec(event->screenPos());
601 }
602
603 }
604
605
606 void MosaicSceneItem::lostCubeDisplay() {
607 m_image = NULL;
608 }
609
610
615 emit mosaicCubeClosed(m_image);
616 }
617
618
625 if (childItems().count()) {
626 setFlag(QGraphicsItem::ItemIsSelectable, false);
627 }
628 else {
629 setFlag(QGraphicsItem::ItemIsSelectable, m_scene->cubesSelectable());
630 }
631
632 QList<QRectF> regionsChanged;
633
634 if(m_image) {
635 foreach(QAbstractGraphicsShapeItem *polygon, *m_polygons) {
636 // Fill
638 polygon->setBrush(color());
639 }
640 else {
641 polygon->setBrush(Qt::NoBrush);
642 }
643
644 // Outline
645 QColor opaqueColor(color());
646 opaqueColor.setAlpha(255);
648 // Make sure the outline is cosmetic (i.e. is always 1 pixel width on screen)
649 QPen pen(opaqueColor);
650 pen.setCosmetic(true);
651 polygon->setPen(pen);
652 }
653 else {
654 polygon->setPen(Qt::NoPen);
655 }
656
657 polygon->setFlag(QGraphicsItem::ItemIsSelectable,
658 m_scene->cubesSelectable());
659
660 // Children (labels are the only children, and there should only be one)
661 foreach(QGraphicsItem *polyChild, polygon->childItems()) {
662 polyChild->setVisible(
664
665 polyChild->setFlag(QGraphicsItem::ItemIsSelectable,
666 m_scene->cubesSelectable());
667
668 // Qt documentation was lacking the enum that this matches to, so this
669 // is the best I could do
670 if(polyChild->type() == 9) {
671 QGraphicsSimpleTextItem * text =
672 (QGraphicsSimpleTextItem *)polyChild;
673 text->setBrush(opaqueColor);
674 }
675 }
676 }
677
678 update();
679 emit changed(regionsChanged);
680 }
681 }
682
683
692 if (m_cubeDnStretch != NULL || !m_image) return m_cubeDnStretch;
693
694 LineManager mgr(*m_image->cube());
695
696 mgr.begin();
697 Statistics stats;
698
699 const int skip = 0;
700
701 while(mgr ++) {
702 m_image->cube()->read(mgr);
703 stats.AddData(mgr.DoubleBuffer(), mgr.size());
704
705 for(int i = 0; i < skip; i++)
706 mgr ++;
707 }
708
709 m_cubeDnStretch = new Stretch();
710 m_cubeDnStretch->AddPair(stats.BestMinimum(), 0.0);
711 m_cubeDnStretch->AddPair(stats.BestMaximum(), 255.0);
712
713 m_cubeDnStretch->SetNull(0.0);
714 m_cubeDnStretch->SetLis(0.0);
715 m_cubeDnStretch->SetLrs(0.0);
716 m_cubeDnStretch->SetHis(255.0);
717 m_cubeDnStretch->SetHrs(255.0);
718 m_cubeDnStretch->SetMinimum(0.0);
719 m_cubeDnStretch->SetMaximum(255.0);
720
721 return m_cubeDnStretch;
722 }
723}
Buffer for containing a three dimensional section of an image.
Definition Brick.h:45
virtual double Line() const
Returns the current line number.
Definition Camera.cpp:2740
virtual double Sample() const
Returns the current sample number.
Definition Camera.cpp:2720
bool InCube()
This returns true if the current Sample() or Line() value is outside of the cube (meaning the point m...
Definition Camera.cpp:2649
PixelType pixelType() const
Definition Cube.cpp:1764
void read(Blob &blob, const std::vector< PvlKeyword > keywords=std::vector< PvlKeyword >()) const
This method will read data from the specified Blob object.
Definition Cube.cpp:813
QList< QAction * > supportedActions(DataType data)
Returns a list of supported actions for a WorkOrder.
Definition Directory.h:345
Project * project() const
Gets the Project for this directory.
QVariant getValue(int property) const
Get a property's associated data.
QString displayName() const
Returns the display name.
void addSupport(int property)
Call this with every property you support, otherwise they will not communicate properly between widge...
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition IException.h:126
This is the GUI communication mechanism for cubes.
Property
This is a list of properties and actions that are possible.
@ ShowLabel
True if the cube should show its display name (bool)
@ ShowFill
True if the cube should show a fill area if possible (bool)
@ ShowDNs
True if the cube should show DN values if possible (bool)
@ Selected
The selection state of this cube (bool)
@ Zooming
Data ignored. Tells if the cube supports the zoomFit action.
@ Color
The color of the cube, default randomized (QColor)
@ ZOrdering
Data ignored. Tells if the cube supports the "move*" actions.
@ ShowOutline
True if the cube should be outlined (bool)
void setSelected(bool)
Change the selected state associated with this cube.
This represents a cube in a project-based GUI interface.
Definition Image.h:107
Cube * cube()
Get the Cube pointer associated with this display property.
Definition Image.cpp:287
geos::geom::MultiPolygon * footprint()
Get the footprint of this image (if available).
Definition Image.cpp:374
ImageDisplayProperties * displayProperties()
Get the display (GUI) properties (information) associated with this image.
Definition Image.cpp:320
Internalizes a list of images and allows for operations on the entire list.
Definition ImageList.h:55
void append(Image *const &value)
Appends an image to the image list.
QList< QAction * > supportedActions(Project *project=NULL)
Gets a list of pre-connected actions that have to do with display.
Buffer manager, for moving through a cube in lines.
Definition LineManager.h:39
void updateChildren()
This applies the displayProperties and selectability.
geos::geom::MultiPolygon * m_180mp
This item's multipolygon in the -180/180 longitude domain.
~MosaicSceneItem()
Mosaic Item destructor.
geos::geom::MultiPolygon * m_mp
This item's multipolygon in the 0/360 longitude domain.
void cubeDisplayChanged()
Someone changed something in the cube display properties, re-read the whole thing.
Stretch * getStretch()
This gets a Stretch object that will work for the cubeDisplay converting from DN to screen pixel.
void drawImage(QPainter *painter, const QStyleOptionGraphicsItem *option)
This method reads in and draws the image associated with this item.
void updateSelection(bool)
Update the selected state.
virtual bool sceneEvent(QEvent *event)
This filters out events that happen within our polygons.
virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
The user right clicked on us (or otherwise requested a context menu).
MosaicSceneItem(Image *image, MosaicSceneWidget *parent)
MosaicSceneItem constructor.
void reproject()
Called anytime the user reprojects the cube.
double getPixelValue(int sample, int line)
Returns the pixel value at the given sample/line.
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget=0)
Re-paints the item.
void onCloseCube()
Emits a signal when Close Cube is selected from the context menu.
bool contains(const QPointF &) const
Test if we contain the point.
This widget encompasses the entire mosaic scene.
static geos::geom::MultiPolygon * To180(geos::geom::MultiPolygon *poly360)
Convert polygon coordinates from 360 system to 180.
The main project for ipce.
Definition Project.h:289
virtual double WorldY() const
This returns the world Y coordinate provided SetGround, SetCoordinate, SetUniversalGround,...
virtual double WorldX() const
This returns the world X coordinate provided SetGround, SetCoordinate, SetUniversalGround,...
This class is used to accumulate statistics on double arrays.
Definition Statistics.h:94
Pixel value mapper.
Definition Stretch.h:58
void AddPair(const double input, const double output)
Adds a stretch pair to the list of pairs.
Definition Stretch.cpp:48
void SetNull(const double value)
Sets the mapping for NULL pixels.
Definition Stretch.h:94
void SetHrs(const double value)
Sets the mapping for HRS pixels.
Definition Stretch.h:138
void SetHis(const double value)
Sets the mapping for HIS pixels.
Definition Stretch.h:127
void SetLis(const double value)
Sets the mapping for LIS pixels.
Definition Stretch.h:105
double Map(const double value) const
Maps an input value to an output value based on the stretch pairs and/or special pixel mappings.
Definition Stretch.cpp:69
void SetLrs(const double value)
Sets the mapping for LRS pixels.
Definition Stretch.h:116
Base class for Map TProjections.
Universal Ground Map.
bool SetUniversalGround(double lat, double lon)
Returns whether the lat/lon position was set successfully in the camera model or projection.
Isis::Projection * Projection() const
Return the projection associated with the ground map (NULL implies none)
Isis::Camera * Camera() const
Return the camera associated with the ground map (NULL implies none)
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
const double Null
Value for an Isis Null pixel.
bool IsSpecial(const double d)
Returns if the input pixel is special.