File failed to load: https://isis.astrogeology.usgs.gov/6.0.0/Object/assets/jax/output/NativeMML/config.js
Isis 3 Programmer Reference
MosaicSceneWidget.cpp
1 #include "IsisDebug.h"
2 
3 #include "MosaicSceneWidget.h"
4 
5 #include <sstream>
6 
7 #include <QFileDialog>
8 #include <QGraphicsSceneContextMenuEvent>
9 #include <QGridLayout>
10 #include <QHBoxLayout>
11 #include <QLabel>
12 #include <QMessageBox>
13 #include <QMenu>
14 #include <QRubberBand>
15 #include <QScrollBar>
16 #include <QStatusBar>
17 #include <QString>
18 #include <QToolButton>
19 #include <QToolTip>
20 #include <QtCore>
21 #include <QtWidgets>
22 #include <QtXml>
23 
24 #include "Camera.h"
25 #include "Cube.h"
26 #include "Directory.h"
27 #include "Distance.h"
28 #include "FileName.h"
29 #include "GraphicsView.h"
30 #include "Image.h"
31 #include "ImageList.h"
32 #include "Latitude.h"
33 #include "Longitude.h"
34 #include "MosaicAreaTool.h"
35 #include "MosaicControlNetTool.h"
36 #include "MosaicFindTool.h"
37 #include "MosaicGraphicsScene.h"
38 #include "MosaicGraphicsView.h"
39 #include "MosaicGridTool.h"
40 #include "MosaicPanTool.h"
41 #include "MosaicSceneItem.h"
42 #include "MosaicSelectTool.h"
43 #include "MosaicTrackTool.h"
44 #include "MosaicZoomTool.h"
45 #include "MoveDownOneSceneWorkOrder.h"
46 #include "MoveToBottomSceneWorkOrder.h"
47 #include "MoveToTopSceneWorkOrder.h"
48 #include "MoveUpOneSceneWorkOrder.h"
49 #include "ProgressBar.h"
50 #include "Project.h"
51 #include "Projection.h"
52 #include "ProjectionConfigDialog.h"
53 #include "ProjectionFactory.h"
54 #include "PvlObject.h"
55 #include "Pvl.h"
56 #include "Shape.h"
57 #include "TextFile.h"
58 #include "Target.h"
59 #include "ToolPad.h"
60 #include "XmlStackedHandlerReader.h"
61 
62 namespace Isis {
66  MosaicSceneWidget::MosaicSceneWidget(QStatusBar *status, bool showTools,
67  bool internalizeToolBarsAndProgress, Directory *directory,
68  QWidget *parent) : QWidget(parent) {
69  m_projectImageZOrders = NULL;
70  m_projectViewTransform = NULL;
71  m_directory = directory;
72 
73  m_mosaicSceneItems = new QList<MosaicSceneItem *>;
74 
76  m_graphicsScene->installEventFilter(this);
77 
80  m_graphicsView->setInteractive(true);
81 // m_graphicsView->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
82  m_graphicsView->setResizeAnchor(QGraphicsView::AnchorViewCenter);
83  // This enables OpenGL acceleration
84 // m_graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
85 // QPixmapCache::setCacheLimit(1024 * 1024);
86 
87  m_projection = NULL;
88  m_mapButton = NULL;
89  m_quickMapAction = NULL;
90 
91  m_cubesSelectable = true;
92  m_customRubberBandEnabled = false;
93  m_customRubberBand = NULL;
94  m_rubberBandOrigin = NULL;
95  m_outlineRect = NULL;
96  m_blockingSelectionChanged = false;
97  m_queuedSelectionChanged = false;
98  m_shouldRequeueSelectionChanged = false;
99 
100  m_userToolControl = false;
101  m_ownProjection = false;
102 
103  m_progress = new ProgressBar;
104  m_progress->setVisible(false);
105 
106  QGridLayout * sceneLayout = new QGridLayout;
107  sceneLayout->setContentsMargins(0, 0, 0, 0);
108  setLayout(sceneLayout);
109 
110  // If we are making our own layout, we can create our own status area.
111  if (!status && internalizeToolBarsAndProgress)
112  status = new QStatusBar;
113 
114  // Create the tools we want
115  m_tools = new QList<MosaicTool *>;
116  m_tools->append(new MosaicSelectTool(this));
117  m_tools->append(new MosaicZoomTool(this));
118  m_tools->append(new MosaicPanTool(this));
119  MosaicControlNetTool *cnetTool = new MosaicControlNetTool(this);
120  m_tools->append(cnetTool);
121 
122  // Pass on Signals emitted from MosaicControlNetTool
123  // TODO 2016-09-09 TLS Design: Use a proxy model instead of signals?
124  connect(cnetTool, SIGNAL(modifyControlPoint(ControlPoint *)),
125  this, SIGNAL(modifyControlPoint(ControlPoint *)));
126 
127  connect(cnetTool, SIGNAL(deleteControlPoint(ControlPoint *)),
128  this, SIGNAL(deleteControlPoint(ControlPoint *)));
129 
130  connect(cnetTool, SIGNAL(createControlPoint(double, double)),
131  this, SIGNAL(createControlPoint(double, double)));
132 
133  // Pass on signals to the MosaicControlNetTool
134  connect(this, SIGNAL(cnetModified()), cnetTool, SLOT(rebuildPointGraphics()));
135 
136  m_tools->append(new MosaicAreaTool(this));
137  m_tools->append(new MosaicFindTool(this));
138  m_tools->append(new MosaicGridTool(this));
139  if (status)
140  m_tools->append(new MosaicTrackTool(this, status));
141 
142  m_tools->at(0)->activate(true);
143 
144  if (showTools) {
145 
146  if (internalizeToolBarsAndProgress) {
147  // Internalized Toolbar Layout:
148  /*
149  * -------TOOLBARS------ Colspan=2, Rowspan=1
150  * | SCENE | T |
151  * | CS=1, RS=1 | O |
152  * | | O |
153  * | | L |
154  * | | B |
155  * | | A |
156  * | | R |*Vertical tool bar CS=1, RS=1
157  * ----PROGRESS---STATUS- Colspan=2, Rowspan=1
158  *
159  *
160  */
161  QHBoxLayout *horizontalToolBarsLayout = new QHBoxLayout;
162 
163  m_permToolbar = new QToolBar("Standard Tools");
164  m_permToolbar->setWhatsThis("This area contains options that are always present in the "
165  "footprint view");
166  horizontalToolBarsLayout->addWidget(m_permToolbar);
167 
168  m_activeToolbar = new QToolBar("Active Tool", this);
169  m_activeToolbar->setObjectName("Active Tool");
170  m_activeToolbar->setWhatsThis("The currently selected tool's options will "
171  "show up here. Not all tools have options.");
172  horizontalToolBarsLayout->addWidget(m_activeToolbar);
173 
174  sceneLayout->addLayout(horizontalToolBarsLayout, 0, 0, 1, 2);
175 
176  sceneLayout->addWidget(m_graphicsView, 1, 0, 1, 1);
177 
178  m_toolpad = new ToolPad("Tool Pad", this);
179  m_toolpad->setObjectName("Tool Pad");
180  m_toolpad->setOrientation(Qt::Vertical);
181  m_toolpad->setFloatable(true);
182  sceneLayout->addWidget(m_toolpad, 1, 1, 1, 1);
183 
184  QHBoxLayout *horizontalStatusLayout = new QHBoxLayout;
185  horizontalStatusLayout->addWidget(m_progress);
186  horizontalStatusLayout->addStretch();
187  horizontalStatusLayout->addWidget(status);
188 
189  sceneLayout->addLayout(horizontalStatusLayout, 2, 0, 1, 2);
190 
191  addToPermanent(m_permToolbar);
192  m_permToolbar->addSeparator();
193 
194  addTo(m_activeToolbar);
195  addTo(m_toolpad);
196  }
197  else {
198  sceneLayout->addWidget(m_graphicsView, 0, 0, 1, 1);
199  }
200 
201  m_userToolControl = true;
202 
203  setWhatsThis("This is the mosaic scene. The opened cubes will be "
204  "shown here. You can fully interact with the files shown here.");
205 
206  getView()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
207  getView()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
208 
209  getView()->enableResizeZooming(false);
210 
211  connect(getView()->horizontalScrollBar(), SIGNAL(valueChanged(int)),
212  this, SLOT(sendVisibleRectChanged()));
213  connect(getView()->verticalScrollBar() , SIGNAL(valueChanged(int)),
214  this, SLOT(sendVisibleRectChanged()));
215  connect(getView()->horizontalScrollBar(), SIGNAL(rangeChanged(int, int)),
216  this, SLOT(sendVisibleRectChanged()));
217  connect(getView()->verticalScrollBar() , SIGNAL(rangeChanged(int, int)),
218  this, SLOT(sendVisibleRectChanged()));
219 
220  }
221  else {
222  sceneLayout->addWidget(m_graphicsView, 0, 0, 1, 1);
223 
224  getView()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
225  getView()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
226 
227  setWhatsThis("This is the mosaic world view. The opened cubes will be "
228  "shown here, but you cannot zoom in. You can select cubes by dragging "
229  "a box over them, zoom to a particular cube by right clicking on it "
230  "and selecting 'Zoom Fit', and many other actions are available.");
231  }
232 
233  // These values are OK as long as they are less than the min/greater than the max. No footprints
234  // are available yet, so 0 qualifies for both (makes a good starting point).
235  m_currentMinimumFootprintZ = 0;
236  m_currentMaximumFootprintZ = 0;
237 
238  connect(getScene(), SIGNAL(selectionChanged()),
239  this, SLOT(onSelectionChanged()));
240  // This is set up to do a single selection changed after all selections have changed, instead
241  // of 1 selection changed per 1 changed item.
242  connect(this, SIGNAL(queueSelectionChanged()),
243  this, SLOT(onQueuedSelectionChanged()), Qt::QueuedConnection);
244  }
245 
246  MosaicSceneWidget::~MosaicSceneWidget() {
247  m_outlineRect = NULL; // The scene will clean this up
248 
249  if (m_tools) {
250  foreach(MosaicTool *tool, *m_tools) {
251  delete tool;
252  tool = NULL;
253  }
254 
255  delete m_tools;
256  m_tools = NULL;
257  }
258 
259  if (m_ownProjection && m_projection) {
260  delete m_projection;
261  }
262  m_projection = NULL;
263 
264  delete m_projectImageZOrders;
265  m_projectImageZOrders = NULL;
266 
267  delete m_projectViewTransform;
268  m_projectViewTransform = NULL;
269  }
270 
271 
272  void MosaicSceneWidget::setProjection(const PvlGroup &mapping, Pvl label) {
273  Pvl tmp;
274  tmp += mapping;
275 
276  if (!mapping.hasKeyword("EquatorialRadius")) {
277  PvlGroup radii = Target::radiiGroup(label, mapping);
278  tmp.findGroup("Mapping") += radii["EquatorialRadius"];
279  tmp.findGroup("Mapping") += radii["PolarRadius"];
280  }
281 
283  m_ownProjection = true;
284  }
285 
286 
291  PvlGroup mapping(proj->Mapping());
292 
293  if (m_mapButton) {
294  PvlKeyword projectionKeyword = mapping.findKeyword("ProjectionName");
295  QString projName = projectionKeyword[0];
296  m_mapButton->setText(tr("View/Edit %1 Projection").arg(projName));
297  }
298 
299  Projection *old = m_projection;
300  m_projection = proj;
301 
302  reprojectItems();
303  emit projectionChanged(m_projection);
304 
305  if (old && m_ownProjection) {
306  delete old;
307  old = NULL;
308  }
309 
310  m_ownProjection = false;
311  }
312 
313 
314 
315  void MosaicSceneWidget::setOutlineRect(QRectF outline) {
316  if (outline.united(getView()->sceneRect()) != getView()->sceneRect())
317  outline = QRectF();
318 
319  if (!m_outlineRect) {
320  m_outlineRect = getScene()->addRect(outline,
321  QPen(Qt::black),
322  Qt::NoBrush);
323  m_outlineRect->setZValue(DBL_MAX);
324  }
325  else {
326  m_outlineRect->setRect(outline);
327  }
328 
329  if (!m_userToolControl)
330  refit();
331  }
332 
333 
334  PvlGroup MosaicSceneWidget::createInitialProjection(
335  Image *image) {
336  Projection *proj = NULL;
337  Cube *cube = image->cube();
338  Pvl *label = cube->label();
339 
340  try {
341  proj = ProjectionFactory::CreateFromCube(*label);
342  return proj->Mapping();
343  }
344  catch (IException &) {
345  Pvl mappingPvl("$ISISROOT/appdata/templates/maps/equirectangular.map");
346  PvlGroup &mappingGrp = mappingPvl.findGroup("Mapping");
347  mappingGrp += PvlKeyword("LatitudeType", "Planetocentric");
348  mappingGrp += PvlKeyword("LongitudeDirection", "PositiveEast");
349  mappingGrp += PvlKeyword("LongitudeDomain", "360");
350  mappingGrp += PvlKeyword("CenterLatitude", "0");
351  mappingGrp += PvlKeyword("CenterLongitude", "180");
352  mappingGrp += PvlKeyword("MinimumLatitude", "-90");
353  mappingGrp += PvlKeyword("MaximumLatitude", "90");
354  mappingGrp += PvlKeyword("MinimumLongitude", "0");
355  mappingGrp += PvlKeyword("MaximumLongitude", "360");
356 
357  try {
358  Camera * cam = cube->camera();
359  Distance radii[3];
360  cam->radii(radii);
361 
362  mappingGrp += PvlKeyword("TargetName", cam->target()->name());
363  mappingGrp += PvlKeyword("EquatorialRadius", toString(radii[0].meters()),
364  "meters");
365  mappingGrp += PvlKeyword("PolarRadius", toString(radii[2].meters()),
366  "meters");
367 
368  }
369  catch (IException &) {
370  mappingGrp +=
371  label->findGroup("Instrument", Pvl::Traverse)["TargetName"];
372  }
373 
374  return mappingGrp;
375  }
376  }
377 
378 
379  void MosaicSceneWidget::addToPermanent(QToolBar *perm) {
380  m_mapButton = new QToolButton(this);
381  connect(this, SIGNAL(destroyed()), m_mapButton, SLOT(deleteLater()));
382  m_mapButton->setText(tr("View/Edit/Load Map File"));
383  m_mapButton->setToolTip(tr("View/Edit/Load Map File"));
384  m_mapButton->setIcon(QIcon(FileName("$ISISROOT/appdata/images/icons/ographic.png").expanded()));
385  m_mapButton->setWhatsThis(tr("This is the projection used by the mosaic "
386  "scene. Cubes can not be shown in the scene without a projection, so "
387  "if one is not selected, a default of Equirectangular will be used. "
388  "The selected file should be a map file, examples are available in "
389  "$ISISROOT/appdata/templates/maps."));
390  m_mapButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
391  connect(m_mapButton, SIGNAL(clicked()), this, SLOT(configProjectionParameters()));
392 
393  if (m_projection) {
394  PvlKeyword projectionKeyword =
395  m_projection->Mapping().findKeyword("ProjectionName");
396  QString projName = projectionKeyword[0];
397  m_mapButton->setText(projName);
398  }
399 
400  m_quickMapAction = new QAction(tr("Quick Load Map"), this);
401  m_quickMapAction->setToolTip(tr("Quick Load Map"));
402  m_quickMapAction->setIcon(QIcon(FileName("$ISISROOT/appdata/images/icons/quickopen.png").expanded()));
403  m_quickMapAction->setWhatsThis(tr("This is the projection used by the mosaic "
404  "scene. Cubes can not be shown in the scene without a projection, so "
405  "if one is not selected, a default of Equirectangular will be used."));
406  connect(m_quickMapAction, SIGNAL(triggered()), this, SLOT(quickConfigProjectionParameters()));
407 
408  perm->addWidget(m_mapButton);
409  perm->addAction(m_quickMapAction);
410  }
411 
412 
413  void MosaicSceneWidget::addTo(QToolBar *toolbar) {
414  MosaicTool *tool;
415  foreach(tool, *m_tools) {
416  tool->addTo(toolbar);
417  }
418  }
419 
420 
421  void MosaicSceneWidget::addTo(QMenu *menu) {
422  MosaicTool *tool;
423  foreach(tool, *m_tools) {
424  tool->addTo(menu);
425  }
426  }
427 
428 
429  void MosaicSceneWidget::addTo(ToolPad *toolPad) {
430  MosaicTool *tool;
431  foreach(tool, *m_tools) {
432  tool->addTo(toolPad);
433  }
434  }
435 
436 
442  bool MosaicSceneWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
443 
444  bool handled = false;
445  QList<QGraphicsItem *> selectedGraphicsItems = getScene()->selectedItems();
446  QList<MosaicSceneItem *> selectedImageItems;
448  foreach (QGraphicsItem *graphicsItem, selectedGraphicsItems) {
449  MosaicSceneItem *sceneImageItem = dynamic_cast<MosaicSceneItem *>(graphicsItem);
450 
451  if (!sceneImageItem) {
452  sceneImageItem = dynamic_cast<MosaicSceneItem *>(graphicsItem->parentItem());
453  }
454 
455  if (sceneImageItem && sceneImageItem->image()) {
456  selectedImageItems.append(sceneImageItem);
457  selectedImages.append(sceneImageItem->image());
458  }
459  }
460 
461  if (selectedImageItems.count()) {
462  QMenu menu;
463 
464  QAction *title = menu.addAction(tr("%L1 Selected Images").arg(selectedImages.count()));
465  title->setEnabled(false);
466  menu.addSeparator();
467 
468  Project *project = m_directory ? m_directory->project() : NULL;
469 
470  QList<QAction *> displayActs = selectedImages.supportedActions(project);
471 
472  if (m_directory) {
473  displayActs.append(NULL);
474  displayActs.append(m_directory->supportedActions(new ImageList(selectedImages)));
475  }
476 
477  QAction *displayAct;
478  foreach(displayAct, displayActs) {
479  if (displayAct == NULL) {
480  menu.addSeparator();
481  }
482  else {
483  menu.addAction(displayAct);
484  }
485  }
486 
487  handled = true;
488  menu.exec(event->screenPos());
489  }
490 
491  return handled;
492 
493  }
494 
495 
496  void MosaicSceneWidget::enableRubberBand(bool enable) {
497  m_customRubberBandEnabled = enable;
498  }
499 
500 
501  MosaicSceneItem *MosaicSceneWidget::cubeToMosaic(Image *image) {
502  if (image == NULL) {
503  QString msg = tr("Can not find a NULL image in the mosaic");
504  throw IException(IException::Programmer, msg, _FILEINFO_);
505  }
506 
507  return cubeToMosaic(image->displayProperties());
508  }
509 
510 
511  bool MosaicSceneWidget::blockSelectionChange(bool block) {
512  bool wasBlocking = m_blockingSelectionChanged;
513 
514  m_blockingSelectionChanged = block;
515 
516  return wasBlocking;
517  }
518 
519 
520  QProgressBar *MosaicSceneWidget::getProgress() {
521  return m_progress;
522  }
523 
524 
525  PvlObject MosaicSceneWidget::toPvl() const {
526  PvlObject output("MosaicScene");
527 
528  if (m_projection) {
529  output += m_projection->Mapping();
530 
531  QBuffer dataBuffer;
532  dataBuffer.open(QIODevice::ReadWrite);
533  QDataStream transformStream(&dataBuffer);
534  transformStream << getView()->transform();
535  dataBuffer.seek(0);
536 
537  PvlObject mosaicScenePosition("SceneVisiblePosition");
538  mosaicScenePosition += PvlKeyword("ViewTransform",
539  QString(dataBuffer.data().toHex()));
540  PvlKeyword scrollPos("ScrollPosition");
541  scrollPos += toString(getView()->horizontalScrollBar()->value());
542  scrollPos += toString(getView()->verticalScrollBar()->value());
543  mosaicScenePosition += scrollPos;
544 
545  output += mosaicScenePosition;
546 
547  MosaicTool *tool;
548  foreach(tool, *m_tools) {
549  if (tool->projectPvlObjectName() != "") {
550  PvlObject toolObj = tool->toPvl();
551  toolObj.setName(tool->projectPvlObjectName());
552  output += toolObj;
553  }
554  }
555 
556  PvlObject zOrders("ZOrdering");
557  foreach(MosaicSceneItem * mosaicSceneItem, *m_mosaicSceneItems) {
558  PvlKeyword zValue("ZValue");
559  zValue += mosaicSceneItem->image()->id();
560  zValue += toString(mosaicSceneItem->zValue());
561  zOrders += zValue;
562  }
563 
564  output += zOrders;
565  }
566  else {
567  throw IException(IException::User,
568  "Cannot save a scene without a projection to a project file",
569  _FILEINFO_);
570  }
571 
572  return output;
573  }
574 
575 
581  void MosaicSceneWidget::fromPvl(const PvlObject &project) {
582  setProjection(project.findGroup("Mapping"));
583  recalcSceneRect();
584 
585  MosaicTool *tool;
586  foreach(tool, *m_tools) {
587  if (tool->projectPvlObjectName() != "") {
588  if (project.hasObject(tool->projectPvlObjectName())) {
589  const PvlObject &toolSettings(
590  project.findObject(tool->projectPvlObjectName()));
591  tool->fromPvl(toolSettings);
592  }
593  }
594 
595  if (project.hasObject("ZOrdering")) {
596  const PvlObject &zOrders = project.findObject("ZOrdering");
597 
598  delete m_projectImageZOrders;
599  m_projectImageZOrders = NULL;
600  m_projectImageZOrders = new QHash<QString, double>;
601 
602  for (int zOrderIndex = 0;
603  zOrderIndex < zOrders.keywords();
604  zOrderIndex ++) {
605  const PvlKeyword &zOrder = zOrders[zOrderIndex];
606 
607  (*m_projectImageZOrders)[zOrder[0]] = toDouble(zOrder[1]);
608  }
609  }
610 
611  if (project.hasObject("SceneVisiblePosition")) {
612  const PvlObject &positionInfo =
613  project.findObject("SceneVisiblePosition");
614 
615  delete m_projectViewTransform;
616  m_projectViewTransform = new PvlObject(positionInfo);
617  }
618  }
619  }
620 
621 
622  void MosaicSceneWidget::load(XmlStackedHandlerReader *xmlReader) {
623  xmlReader->pushContentHandler(new XmlHandler(this));
624  }
625 
626 
627  void MosaicSceneWidget::save(QXmlStreamWriter &stream, Project *, FileName ) const {
628  if (m_projection) {
629  stream.writeStartElement("mosaicScene");
630 
631  stream.writeStartElement("projection");
632  PvlGroup mapping = m_projection->Mapping();
633  std::stringstream strStream;
634  strStream << mapping;
635  stream.writeCharacters(strStream.str().c_str());
636  stream.writeEndElement();
637 
638  stream.writeStartElement("images");
639  foreach(MosaicSceneItem * mosaicSceneItem, *m_mosaicSceneItems) {
640  stream.writeStartElement("image");
641  stream.writeAttribute("id", mosaicSceneItem->image()->id());
642  stream.writeAttribute("zValue", toString(mosaicSceneItem->zValue()));
643  stream.writeEndElement();
644  }
645  stream.writeEndElement();
646 
647  stream.writeStartElement("viewTransform");
648  stream.writeAttribute("scrollBarXValue", toString(getView()->horizontalScrollBar()->value()));
649  stream.writeAttribute("scrollBarYValue", toString(getView()->verticalScrollBar()->value()));
650  QBuffer dataBuffer;
651  dataBuffer.open(QIODevice::ReadWrite);
652  QDataStream transformStream(&dataBuffer);
653  transformStream << getView()->transform();
654  dataBuffer.seek(0);
655  stream.writeCharacters(dataBuffer.data().toHex());
656  stream.writeEndElement();
657 
658  foreach(MosaicTool *tool, *m_tools) {
659  QString projectPvlObjectName = tool->projectPvlObjectName();
660  if (projectPvlObjectName != "") {
661  PvlObject toolObj = tool->toPvl();
662  toolObj.setName(projectPvlObjectName);
663 
664  stream.writeStartElement("toolData");
665  stream.writeAttribute("objectName", projectPvlObjectName);
666  std::stringstream strStream;
667  strStream << toolObj;
668  stream.writeCharacters(strStream.str().c_str());
669  stream.writeEndElement();
670  }
671  }
672 
673  stream.writeEndElement();
674  }
675  }
676 
677 
678  QRectF MosaicSceneWidget::cubesBoundingRect() const {
679  QRectF boundingRect;
680 
681  MosaicSceneItem * mosaicItem;
682  foreach(mosaicItem, *m_mosaicSceneItems) {
683  if (boundingRect.isEmpty())
684  boundingRect = mosaicItem->boundingRect();
685  else
686  boundingRect = boundingRect.united(mosaicItem->boundingRect());
687  }
688 
689  if (m_outlineRect)
690  boundingRect = boundingRect.united(m_outlineRect->boundingRect());
691 
692  return boundingRect;
693  }
694 
695 
696  MosaicSceneItem *MosaicSceneWidget::cubeToMosaic(DisplayProperties *props) {
697  if (props == NULL) {
698  QString msg = tr("Can not find a NULL Display Properties in the mosaic");
699  throw IException(IException::Programmer, msg, _FILEINFO_);
700  }
701 
702  return m_displayPropsToMosaicSceneItemMap[props];
703  }
704 
705 
706  QStringList MosaicSceneWidget::cubeFileNames() {
707  QStringList cubes;
708 
709  MosaicSceneItem *mosaicSceneItem;
710  foreach(mosaicSceneItem, *m_mosaicSceneItems) {
711  if (mosaicSceneItem->image())
712  cubes.append(mosaicSceneItem->image()->fileName());
713  }
714 
715  return cubes;
716  }
717 
718 
719  Directory *MosaicSceneWidget::directory() const {
720  return m_directory;
721  }
722 
723 
724  ImageList MosaicSceneWidget::images() {
725  ImageList images;
726 
727  MosaicSceneItem *mosaicSceneItem;
728  foreach(mosaicSceneItem, *m_mosaicSceneItems) {
729  if (mosaicSceneItem->image())
730  images.append(mosaicSceneItem->image());
731  }
732 
733  return images;
734  }
735 
736 
743 
744  QList<QGraphicsItem *> selectedGraphicsItems = getScene()->selectedItems();
745  QList<MosaicSceneItem *> selectedImageItems;
747 
748  foreach (QGraphicsItem *graphicsItem, selectedGraphicsItems) {
749  MosaicSceneItem *sceneImageItem = dynamic_cast<MosaicSceneItem *>(graphicsItem);
750 
751  if (!sceneImageItem) {
752  sceneImageItem = dynamic_cast<MosaicSceneItem *>(graphicsItem->parentItem());
753  }
754 
755  if (sceneImageItem && sceneImageItem->image()) {
756  selectedImageItems.append(sceneImageItem);
757  selectedImages.append(sceneImageItem->image());
758  }
759  }
760  return selectedImages;
761 
762 
763 
764 
765 
766 // ImageList images;
767 // //qDebug()<<"MosaicSceneWidget::selectedImages TotalItems = "<<m_mosaicSceneItems->size();
768 // MosaicSceneItem *mosaicItem;
769 // foreach(mosaicItem, *m_mosaicSceneItems) {
770 // if (mosaicItem->isSelected()) {
771 // images.append(mosaicItem->image());
772 // }
773 // }
774 //
775 // return images;
776  }
777 
778 
779  QList<QAction *> MosaicSceneWidget::getExportActions() {
780  QList<QAction *> exportActs;
781 
782  QAction *exportView = new QAction(this);
783  exportView->setText("&Export View...");
784  connect(exportView, SIGNAL(triggered()), this, SLOT(exportView()));
785 
786  QAction *saveList = new QAction(this);
787  saveList->setText("Save Entire Cube List (ordered by &view)...");
788  connect(saveList, SIGNAL(triggered()), this, SLOT(saveList()));
789 
790  exportActs.append(exportView);
791  exportActs.append(saveList);
792 
793  return exportActs;
794  }
795 
796 
797  QList<QAction *> MosaicSceneWidget::getViewActions() {
798  QList<QAction *> viewActs;
799 
800  foreach(MosaicTool *tool, *m_tools) {
801  QList<QAction *> toolViewActs = tool->getViewActions();
802  viewActs.append(toolViewActs);
803  }
804 
805  return viewActs;
806  }
807 
808 
813  QList<QAction *> results;
814  bool allImagesInView = !images->isEmpty();
815 
816  foreach (Image *image, *images) {
817  allImagesInView = allImagesInView && (cubeToMosaic(image) != NULL);
818  }
819 
820  if (allImagesInView) {
821  MoveToTopSceneWorkOrder *moveToTopAct =
822  new MoveToTopSceneWorkOrder(this, m_directory->project());
823  moveToTopAct->setData(images);
824  results.append(moveToTopAct);
825 
826  MoveUpOneSceneWorkOrder *moveUpOneAct =
827  new MoveUpOneSceneWorkOrder(this, m_directory->project());
828  moveUpOneAct->setData(images);
829  results.append(moveUpOneAct);
830 
831  MoveToBottomSceneWorkOrder *moveToBottomAct =
832  new MoveToBottomSceneWorkOrder(this, m_directory->project());
833  moveToBottomAct->setData(images);
834  results.append(moveToBottomAct);
835 
836  MoveDownOneSceneWorkOrder *moveDownOneAct =
837  new MoveDownOneSceneWorkOrder(this, m_directory->project());
838  moveDownOneAct->setData(images);
839  results.append(moveDownOneAct);
840 
841  results.append(NULL);
842 
843  QAction *zoomFitAct = new QAction(tr("Zoom Fit"), this);
844  zoomFitAct->setData(qVariantFromValue(images));
845  connect(zoomFitAct, SIGNAL(triggered()), this, SLOT(fitInView()));
846  results.append(zoomFitAct);
847  }
848  return results;
849  }
850 
851 
852  bool MosaicSceneWidget::isControlNetToolActive() {
853 
854  foreach(MosaicTool *tool, *m_tools) {
855  MosaicControlNetTool *cnTool = dynamic_cast<MosaicControlNetTool *>(tool);
856  if (cnTool) {
857  if (cnTool->isActive()) return true;
858  }
859  }
860  return false;
861  }
862 
863 
864  QWidget * MosaicSceneWidget::getControlNetHelp(QWidget *cnetToolContainer) {
865  QScrollArea *cnetHelpWidgetScrollArea = new QScrollArea;
866 
867  QWidget *cnetHelpWidget = new QWidget;
868 
869  QVBoxLayout *cnetHelpLayout = new QVBoxLayout;
870  cnetHelpWidget->setLayout(cnetHelpLayout);
871 
872  QLabel *title = new QLabel("<h2>Control Networks</h2>");
873  cnetHelpLayout->addWidget(title);
874 
875  QPixmap previewPixmap;
876 
877  if (cnetToolContainer) {
878  previewPixmap = cnetToolContainer->grab().scaled(
879  QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
880  }
881  else {
882  ToolPad tmpToolPad("Example Tool Pad", NULL);
883  MosaicControlNetTool tmpTool(NULL);
884  tmpTool.addTo(&tmpToolPad);
885 
886  tmpToolPad.resize(QSize(32, 32));
887 
888  previewPixmap = tmpToolPad.grab();
889  }
890 
891  QLabel *previewWrapper = new QLabel;
892  previewWrapper->setPixmap(previewPixmap);
893  cnetHelpLayout->addWidget(previewWrapper);
894 
895  QLabel *overview = new QLabel("The mosaic scene can display control points "
896  "in addition to the usual cube footprints. This feature is currently "
897  "offered as one of the Mosaic Scene's tools. To open a network, click "
898  "on the control network tool. It will immediately prompt you for a "
899  "control network file if one is not open. Only control points for "
900  "which the latitude and longitude can be established will be "
901  "displayed. Other control points will be ignored by qmos.<br><br>"
902  "<b>Warning: Opening large control networks is slow.</b>"
903  "<h3>Control Network Tool Options</h3>"
904  "<ul>"
905  "<li>The control network tool opens control networks in two ways. "
906  "First, if you select the control network tool and no network is "
907  "open, then it will prompt you for one. Second, if there is an open "
908  "network, the buttons for the available options are displayed in the "
909  "active tool area.</li>"
910  "<li>The control network tool can toggle whether or not control "
911  "points are displayed on the screen using the 'Display' button. "
912  "Control points are always on top and colored based on their "
913  "ignored, locked and type values.</li>"
914  "<li>This tool can also change the color of your footprints based on "
915  "connectivity through control points. This is available through the "
916  "'Color Islands' button. When you press color islands, all of the "
917  "current cube coloring information is lost and re-done based on "
918  "how the control network connects the files. Each set of connected "
919  "cubes are colored differently; generally speaking, islands are not "
920  "a good thing to have in your control network.</li>"
921  "<li>This tool will color your footprints on a per-image basis if you "
922  "click color images, effectively reversing color islands.</li>"
923  "<li>The show movement option under 'Configure Movement Display' "
924  "only displays data when the control "
925  "network has adjusted values. This means that show movement only "
926  "works after you have done a jigsaw solution on the control network. "
927  "This displays arrows emanating from the apriori latitude/longitude "
928  "and pointing toward the adjusted latitude/longitude.</li>");
929  overview->setWordWrap(true);
930  cnetHelpLayout->addWidget(overview);
931 
932  cnetHelpWidgetScrollArea->setWidget(cnetHelpWidget);
933 
934  return cnetHelpWidgetScrollArea;
935  }
936 
937 
938  QWidget * MosaicSceneWidget::getGridHelp(QWidget *gridToolContainer) {
939  QScrollArea *gridHelpWidgetScrollArea = new QScrollArea;
940 
941  QWidget *gridHelpWidget = new QWidget;
942 
943  QVBoxLayout *gridHelpLayout = new QVBoxLayout;
944  gridHelpWidget->setLayout(gridHelpLayout);
945 
946  QLabel *title = new QLabel("<h2>Map Grid Tool</h2>");
947  gridHelpLayout->addWidget(title);
948 
949  QPixmap previewPixmap;
950 
951  if (gridToolContainer) {
952  previewPixmap = gridToolContainer->grab().scaled(
953  QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
954  }
955  else {
956  ToolPad tmpToolPad("Example Tool Pad", NULL);
957  MosaicGridTool tmpTool(NULL);
958  tmpTool.addTo(&tmpToolPad);
959 
960  tmpToolPad.resize(QSize(32, 32));
961 
962  previewPixmap = tmpToolPad.grab();
963  }
964 
965  QLabel *previewWrapper = new QLabel;
966  previewWrapper->setPixmap(previewPixmap);
967  gridHelpLayout->addWidget(previewWrapper);
968 
969  QLabel *overview = new QLabel("Superimpose a map grid over the area of "
970  "displayed footprints in the 'mosaic scene.'"
971  "<h2>Overview</h2>"
972  "<ul>"
973  "<li>The Map Grid Tool is activated by selecting the 'cross-hatch' "
974  "icon or typing 'g' at the keyboard."
975  "</li>"
976  "<li>The parameter options are displayed below the menubar. "
977  "Clicking the 'Grid Options' button will open the dialog. Checking "
978  "'Auto Grid' will draw a grid based on the open cubes. Hitting "
979  "'Show Grid' will display or hide the grid."
980  "</li>"
981  "<li>The map grid is defined by the loaded Map File (just as the "
982  "footprints and image data are), the opened cubes, or the grid "
983  "tool parameters."
984  "</li>"
985  "<li>If a Map File has not been selected, the default "
986  "Equirectangular projection will be used. The resulting grid "
987  "lines in the default 'Equi' map file will be drawn for the "
988  "full global range (latitude range = -90,90; longitude range = "
989  "0,360) at the default latitude and longitude increment values."
990  "</li>"
991  "<li>"
992  "If the grid lines are not immediately visible, try to "
993  "'zoom out' in the 'mosaic scene' window and modify the "
994  "Latitude and Longitude Increment parameters."
995  "</li>"
996  "</ul>"
997  "<strong>Options:</strong>"
998  "<ul>"
999  "<li>The 'Show Grid' option draws (checked) or clears (unchecked) the grid."
1000  "</li>"
1001  "<li>The 'Auto Grid' option draws a grid with extents and increments "
1002  "computed from the set of images that are opened. The values displayed in the dialog "
1003  "will reflect those used to draw the grid."
1004  "</li>"
1005  "<li>The expected units for each entry are displayed to the right of the "
1006  "dialog box."
1007  "</li>"
1008  "<li>The 'Extent Type' combo boxes allow you to pick the source of the "
1009  "grid extents from the map file, from the open cubes <default>, or manually "
1010  "entered."
1011  "</li>"
1012  "<li>The 'Auto Apply' checkbox, inside the 'Grid Options' dialog box, allows you to see "
1013  "real time updates in the grid when you change the parameters."
1014  "</li>"
1015  "<li> Depending on the projection, the grid may not behave as expected. For instance, "
1016  "with a polarstereographic projection, the pole will not be included in the 'Auto "
1017  "Grid' if it is not in the cube region. In this case the 'Manual' option for latitude "
1018  "extents allows you to force the grid to the pole."
1019  "</li>"
1020  "</ul>");
1021  overview->setWordWrap(true);
1022  gridHelpLayout->addWidget(overview);
1023 
1024  gridHelpWidgetScrollArea->setWidget(gridHelpWidget);
1025 
1026  return gridHelpWidgetScrollArea;
1027  }
1028 
1029 
1030  QWidget * MosaicSceneWidget::getLongHelp(QWidget *sceneContainer) {
1031  QScrollArea *longHelpWidgetScrollArea = new QScrollArea;
1032 
1033  QWidget *longHelpWidget = new QWidget;
1034 
1035  QVBoxLayout *longHelpLayout = new QVBoxLayout;
1036  longHelpWidget->setLayout(longHelpLayout);
1037 
1038  QLabel *title = new QLabel("<h2>Mosaic Scene</h2>");
1039  longHelpLayout->addWidget(title);
1040 
1041  if (sceneContainer) {
1042  QPixmap previewPixmap = sceneContainer->grab().scaled(
1043  QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
1044 
1045  QLabel *previewWrapper = new QLabel;
1046  previewWrapper->setPixmap(previewPixmap);
1047  longHelpLayout->addWidget(previewWrapper);
1048  }
1049 
1050  QLabel *overview = new QLabel("The mosaic scene displays cube footprints "
1051  "to show where files are on a target and how they overlap. "
1052  "The scene always represents projected image space and cannot show raw "
1053  "or unprojected images; images will be projected on the fly."
1054  "<h3>Tools</h3>"
1055  "<p>Interact with the mosaic scene in different ways using "
1056  "the tools. The tools are usually in a toolbar next to the scene. "
1057  "The tools define what is displayed and what happens when you "
1058  "click in the mosaic scene. The tools include</p>"
1059  "<ul><li>Select Tool</li>"
1060  "<li>Zoom Tool</li>"
1061  "<li>Pan Tool</li>"
1062  "<li>Control Network Tool</li>"
1063  "<li>Show Area Tool</li>"
1064  "<li>Find Tool</li>"
1065  "<li>Grid Tool</li></ul>"
1066  "<h3>Context Menus</h3>"
1067  "Right click on anything in the mosaic scene and a context menu will pop up showing "
1068  "a list of actions or information relevant to the item you clicked on. "
1069  "<p>Note: The context menu is not associated with any selection, only the item "
1070  "clicked on.</p>");
1071  overview->setWordWrap(true);
1072  longHelpLayout->addWidget(overview);
1073 
1074  longHelpWidgetScrollArea->setWidget(longHelpWidget);
1075 
1076  return longHelpWidgetScrollArea;
1077  }
1078 
1079 
1080  QWidget * MosaicSceneWidget::getMapHelp(QWidget *mapContainer) {
1081  QScrollArea *mapHelpWidgetScrollArea = new QScrollArea;
1082 
1083  QWidget *mapHelpWidget = new QWidget;
1084 
1085  QVBoxLayout *mapHelpLayout = new QVBoxLayout;
1086  mapHelpWidget->setLayout(mapHelpLayout);
1087 
1088  QLabel *title = new QLabel(tr("<h2>Map File</h2>"));
1089  mapHelpLayout->addWidget(title);
1090 
1091  if (mapContainer) {
1092  QPixmap previewPixmap = mapContainer->grab().scaled(
1093  QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
1094 
1095  QLabel *previewWrapper = new QLabel;
1096  previewWrapper->setPixmap(previewPixmap);
1097  mapHelpLayout->addWidget(previewWrapper);
1098  }
1099 
1100  QLabel *overviewMapIcon = new QLabel;
1101 
1102  overviewMapIcon->setPixmap(
1103  QIcon(FileName("$ISISROOT/appdata/images/icons/ographic.png").expanded()).pixmap(32, 32));
1104  mapHelpLayout->addWidget(overviewMapIcon);
1105 
1106  QLabel *defaultMapFile = new QLabel(tr(
1107  "<h3>Default Map File</h3>"
1108  "The mosaic scene's projection is defined by a \"Map File\" that consists of keywords "
1109  "that describe the map layout to be used. If a cube or a list of cubes are "
1110  "loaded before a map file is selected, the default map file defines the "
1111  "equirectangular projection, planetocentric latitude, positive longitude east, 360 "
1112  "longitude domain, latitude range=90S-90N, longitude range=0-360E. The radius will "
1113  "default to the IAU standards (ellipsoid or sphere) for the specific planetary body "
1114  "defined for the \"TargetName\" in the labels of the image cube(s)."));
1115 
1116  defaultMapFile->setWordWrap(true);
1117  mapHelpLayout->addWidget(defaultMapFile);
1118 
1119  QLabel *userDefinedMapFileOverview = new QLabel(tr(
1120  "<h3>User Defined Map File</h3>"
1121  "You can load an existing \"Map File\" before loading images into %1 by selecting the "
1122  "\"View/Edit/Load Map File\" option. You will be greeted with a dialog box that will "
1123  "enable you to select an existing map file by clicking on \"Load Map File.\" Once "
1124  "the map file is selected, the contents is displayed in the dialog box where "
1125  "modifications can be made as well. If the modified map file is to be used later, "
1126  "save the map file by clicking on \"Save Map File\" button.")
1127  .arg(QCoreApplication::applicationName()));
1128 
1129  userDefinedMapFileOverview->setWordWrap(true);
1130  mapHelpLayout->addWidget(userDefinedMapFileOverview);
1131 
1132  QLabel *userDefinedMapFileQuickLoad = new QLabel(tr(
1133  "The \"Quick Load Map\" option (lightning icon) allows you to efficiently select a "
1134  "prepared \"Map File\" without an immediate need to view or edit the contents."));
1135 
1136  userDefinedMapFileQuickLoad->setWordWrap(true);
1137  mapHelpLayout->addWidget(userDefinedMapFileQuickLoad);
1138 
1139  QLabel *userDefinedMapFileAnyTime = new QLabel(tr(
1140  "At any point, you have access to the \"View/Edit\" functionality to modify or load a "
1141  "different map file."));
1142 
1143  userDefinedMapFileAnyTime->setWordWrap(true);
1144  mapHelpLayout->addWidget(userDefinedMapFileAnyTime);
1145 
1146  QString mapProjWorkshopUrl("https://github.com/USGS-Astrogeology/ISIS3/wiki/Learning_About_Map_Projections");
1147  QLabel *preparingMapFile = new QLabel(tr(
1148  "<h3>Preparing a Map File</h3>"
1149  "Please refer to Isis applications such as 'maptemplate' or 'mosrange' for more details "
1150  "on creating a custom map file that defines the desired projection, latitude "
1151  "system, and longitude direction and domain. This program will use the latitude range "
1152  "and longitude range if they exist in the loaded file. A choice of map templates that can be used as "
1153  "a starting point for supported map projections can be found in $ISISROOT/appdata/templates/maps (refer "
1154  "to maptemplate or mosrange for more details and information on the required parameters "
1155  "for a projection). The website: "
1156  "<a href='%1'>%1</a> also provides useful information about map projections.")
1157  .arg(mapProjWorkshopUrl));
1158 
1159  preparingMapFile->setOpenExternalLinks(true);
1160  preparingMapFile->setWordWrap(true);
1161  mapHelpLayout->addWidget(preparingMapFile);
1162 
1163  QLabel *mapFileDisplayResults = new QLabel(tr(
1164  "<h3>Display Results with the Map File</h3>"
1165  "The footprints and image data that are displayed in the mosaic scene are defined by the "
1166  "loaded \"Map File\" regardless of whether the opened cubes are Level1 (raw "
1167  "camera space) or Level2 (map projected). The associated footprint polygons for "
1168  "Level2 cubes will be re-mapped as needed based on the loaded map file."));
1169 
1170  mapFileDisplayResults->setWordWrap(true);
1171  mapHelpLayout->addWidget(mapFileDisplayResults);
1172 
1173  QLabel *editingMapFileOverview = new QLabel(tr(
1174  "<h3>Editing a Map File</h3>"
1175  "Editing a map file is possible through the dialog box displayed by clicking on the "
1176  "'View/Edit/Load Map File' icon/button. The edits are "
1177  "applied to the current session and will be included with a 'Saved Project' (refer to "
1178  "the help under File-Save Project or Save Project as)."));
1179 
1180  editingMapFileOverview->setWordWrap(true);
1181  mapHelpLayout->addWidget(editingMapFileOverview);
1182 
1183  QLabel *saveMapFileToDiskBullet = new QLabel(tr(
1184  "<ul>"
1185  "<li>"
1186  "To save or write the changes to a map file on disk, choose 'Save Map File' button. "
1187  "Map files can be saved to an existing map file (overwrites) or to a new file. This "
1188  "program always saves <strong>exactly</strong> what you see, the text, in the dialog "
1189  "box."
1190  "</li>"
1191  "</ul>"));
1192 
1193  saveMapFileToDiskBullet->setWordWrap(true);
1194  mapHelpLayout->addWidget(saveMapFileToDiskBullet);
1195 
1196  QLabel *mapFileValidityBullet = new QLabel(tr(
1197  "<ul>"
1198  "<li>"
1199  "As you modify the contents of a loaded map file in the dialog box, the entry is "
1200  "verified as you type with a bold black indicator message displaying whether the "
1201  "text is valid or is not valid. If you want to see the actual error messages, "
1202  "select the 'Show Errors' box and the errors will be displayed in red font "
1203  "along with the black bolded message. The errors will update "
1204  "as you type."
1205  "</li>"
1206  "</ul>"));
1207 
1208  mapFileValidityBullet->setWordWrap(true);
1209  mapHelpLayout->addWidget(mapFileValidityBullet);
1210 
1211  QLabel *mapFileCommentsBullet = new QLabel(tr(
1212  "<ul>"
1213  "<li>"
1214  "Map files may contain 'commented-out' lines (text that starts with \"#\" at "
1215  "the beginning of the line). These are referred to as \"unnecessary\""
1216  "or \"unknown\" keywords, they are simply ignored. If these lines are to be saved to "
1217  "the output map file on disk, click 'Save Map File' BEFORE clicking 'Ok' or 'Apply.' "
1218  "The comments are removed from the dialog box when you hit 'Ok' or 'Apply,' if they "
1219  "are just above \"End_Group\" or follow \"End_Group\" or \"End\".<br/><br/>"
1220 
1221  "If you want these comments retained, make sure they are immediately above a valid "
1222  "keyword inside of \"Group = Mapping.\" Note that any lines (commented or not) will "
1223  "not be saved if they are placed outside of \"Group = Mapping\" and \"End_Group\"."
1224  "</li>"
1225  "</ul>"));
1226 
1227  mapFileCommentsBullet->setWordWrap(true);
1228  mapHelpLayout->addWidget(mapFileCommentsBullet);
1229 
1230  mapHelpWidgetScrollArea->setWidget(mapHelpWidget);
1231 
1232  return mapHelpWidgetScrollArea;
1233  }
1234 
1235 
1236  QWidget * MosaicSceneWidget::getPreviewHelp(QWidget *worldViewContainer) {
1237  QScrollArea *previewHelpWidgetScrollArea = new QScrollArea;
1238 
1239  QWidget *previewHelpWidget = new QWidget;
1240 
1241  QVBoxLayout *previewHelpLayout = new QVBoxLayout;
1242  previewHelpWidget->setLayout(previewHelpLayout);
1243 
1244  QLabel *title = new QLabel("<h2>Mosaic World View</h2>");
1245  previewHelpLayout->addWidget(title);
1246 
1247  if (worldViewContainer) {
1248  QPixmap previewPixmap = worldViewContainer->grab().scaled(
1249  QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
1250 
1251  QLabel *previewWrapper = new QLabel;
1252  previewWrapper->setPixmap(previewPixmap);
1253  previewHelpLayout->addWidget(previewWrapper);
1254  }
1255 
1256  QLabel *overview = new QLabel("The mosaic world view displays cube "
1257  "footprints to show you where your files are on a target and their "
1258  "general arrangement. The world view does not have tools like "
1259  "mosaic scenes, but otherwise they are very similar.");
1260  overview->setWordWrap(true);
1261  previewHelpLayout->addWidget(overview);
1262 
1263  previewHelpWidgetScrollArea->setWidget(previewHelpWidget);
1264 
1265  return previewHelpWidgetScrollArea;
1266  }
1267 
1268 
1269  MosaicSceneItem *MosaicSceneWidget::addImage(Image *image) {
1270  if (m_projection == NULL) {
1271  setProjection(createInitialProjection(image), *image->cube()->label());
1272  }
1273 
1274  MosaicSceneItem *mosItem = NULL;
1275 
1276  // Verify we don't have this cube already... if we do, ignore the add request
1277  if (!cubeToMosaic(image)) {
1278  mosItem = new MosaicSceneItem(image, this);
1279 
1280  connect(mosItem, SIGNAL(changed(const QList<QRectF> &)),
1281  m_graphicsView, SLOT(updateScene(const QList<QRectF> &)));
1282  connect(mosItem, SIGNAL(mosaicCubeClosed(Image *)),
1283  this, SIGNAL(mosCubeClosed(Image *)));
1284 
1285  // We want everything to have a unique Z value so we can manage the z order
1286  // well.
1287  if (m_projectImageZOrders && m_projectImageZOrders->contains(image->id())) {
1288  double zOrder = m_projectImageZOrders->value(image->id());
1289  m_projectImageZOrders->remove(image->id());
1290 
1291  foreach (MosaicSceneItem *mosaicItem, *m_mosaicSceneItems) {
1292  if (mosaicItem->zValue() == zOrder) {
1293  mosaicItem->setZValue(maximumZ() + 1);
1294  m_currentMaximumFootprintZ = maximumZ() + 1;
1295  }
1296  }
1297 
1298  m_currentMaximumFootprintZ = qMax(zOrder, maximumZ());
1299  mosItem->setZValue(zOrder);
1300  }
1301  else {
1302  mosItem->setZValue(maximumZ() + 1);
1303  m_currentMaximumFootprintZ = maximumZ() + 1;
1304  }
1305 
1306  getScene()->addItem(mosItem);
1307  m_mosaicSceneItems->append(mosItem);
1308  m_displayPropsToMosaicSceneItemMap[image->displayProperties()] = mosItem;
1309 
1310  connect(mosItem, SIGNAL(destroyed(QObject *)),
1311  this, SLOT(removeMosItem(QObject *)));
1312 
1313  ImageDisplayProperties *prop = image->displayProperties();
1314  connect(prop, SIGNAL(moveDownOne()),
1315  this, SLOT(moveDownOne()));
1316  connect(prop, SIGNAL(moveToBottom()),
1317  this, SLOT(moveToBottom()));
1318  connect(prop, SIGNAL(moveUpOne()),
1319  this, SLOT(moveUpOne()));
1320  connect(prop, SIGNAL(moveToTop()),
1321  this, SLOT(moveToTop()));
1322  connect(prop, SIGNAL(zoomFit()),
1323  this, SLOT(fitInView()));
1324  }
1325 
1326  return mosItem;
1327  }
1328 
1329 
1330  double MosaicSceneWidget::maximumZ() {
1331  return m_currentMaximumFootprintZ;
1332  }
1333 
1334 
1335  double MosaicSceneWidget::minimumZ() {
1336  return m_currentMinimumFootprintZ;
1337  }
1338 
1339  void MosaicSceneWidget::recalcSceneRect() {
1340  if (m_projection) {
1341  double minX, minY, maxX, maxY;
1342  m_projection->XYRange(minX, maxX, minY, maxY);
1343 
1344  QRectF projRect(minX, -maxY, maxX - minX, maxY - minY);
1345  QRectF cubesBounding = cubesBoundingRect();
1346 
1347  QRectF bounding = projRect.united(cubesBounding);
1348 
1349  if (m_outlineRect && m_outlineRect->isVisible())
1350  bounding = bounding.united(m_outlineRect->boundingRect());
1351 
1352  getView()->setSceneRect(bounding);
1353  }
1354  }
1355 
1356  void MosaicSceneWidget::addImages(ImageList images) {
1357  if (m_userToolControl)
1358  m_progress->setText("Loading primary scene");
1359  else
1360  m_progress->setText("Loading secondary scene");
1361 
1362  m_progress->setRange(0, images.size() - 1);
1363  m_progress->setValue(0);
1364  m_progress->setVisible(true);
1365 
1366  foreach(Image *image, images) {
1367  try {
1368  addImage(image);
1369  }
1370  catch (IException &e) {
1371  e.print();
1372  }
1373 
1374  m_progress->setValue(m_progress->value() + 1);
1375  }
1376 
1377  recalcSceneRect();
1378 
1379  if (m_projectViewTransform) {
1380  PvlObject &positionInfo = *m_projectViewTransform;
1381  QByteArray hexValues(positionInfo["ViewTransform"][0].toLatin1());
1382  QDataStream transformStream(QByteArray::fromHex(hexValues));
1383 
1384  QTransform viewTransform;
1385  transformStream >> viewTransform;
1386  getView()->setTransform(viewTransform);
1387 
1388  QPoint projectScrollPos(toInt(positionInfo["ScrollPosition"][0]),
1389  toInt(positionInfo["ScrollPosition"][1]));
1390 
1391  getView()->horizontalScrollBar()->setValue(projectScrollPos.x());
1392  getView()->verticalScrollBar()->setValue(projectScrollPos.y());
1393  }
1394  else {
1395  refit();
1396  }
1397 
1398  if (!m_projectImageZOrders || m_projectImageZOrders->isEmpty()) {
1399  delete m_projectViewTransform;
1400  m_projectViewTransform = NULL;
1401  }
1402 
1403  m_progress->setVisible(false);
1404  emit cubesChanged();
1405  }
1406 
1407 
1408  void MosaicSceneWidget::removeImages(ImageList images) {
1409  // TODO: 2016-08-02 TLS Should this be done similarly to addImages. Re-do Image list
1410  // then redo scene?
1411  foreach(Image *image, images) {
1412  try {
1413  MosaicSceneItem *item = cubeToMosaic(image);
1414  item->deleteLater();
1415  removeMosItem(item);
1416  }
1417  catch (IException &e) {
1418  e.print();
1419  }
1420  }
1421  }
1422 
1423 
1428  QString output =
1429  QFileDialog::getSaveFileName((QWidget *)parent(),
1430  "Choose output file",
1431  QDir::currentPath() + "/untitled.png",
1432  QString("Images (*.png *.jpg *.tif)"));
1433  if (output.isEmpty()) return;
1434 
1435  // Use png format is the user did not add a suffix to their output filename.
1436  if (QFileInfo(output).suffix().isEmpty()) {
1437  output = output + ".png";
1438  }
1439 
1440  QString format = QFileInfo(output).suffix();
1441  QPixmap pm = getScene()->views().last()->grab();
1442 
1443  std::string formatString = format.toStdString();
1444  if (!pm.save(output, formatString.c_str())) {
1445  QMessageBox::information(this, "Error",
1446  "Unable to save [" + output + "]");
1447  }
1448  }
1449 
1450 
1451  void MosaicSceneWidget::saveList() {
1452  QString output =
1453  QFileDialog::getSaveFileName((QWidget *)parent(),
1454  "Choose output file",
1455  QDir::currentPath() + "/files.lis",
1456  QString("List File (*.lis);;Text File (*.txt);;All Files (*.*)"));
1457  if (output.isEmpty()) return;
1458 
1459  TextFile file(output, "overwrite");
1460 
1461  QList<MosaicSceneItem *> sorted = *m_mosaicSceneItems;
1462  qSort(sorted.begin(), sorted.end(), zOrderGreaterThan);
1463 
1464  MosaicSceneItem *sceneItem;
1465  foreach(sceneItem, sorted) {
1466  file.PutLine( sceneItem->image()->fileName() );
1467  }
1468  }
1469 
1470 
1471  void MosaicSceneWidget::removeMosItem(QObject *mosItem) {
1472  MosaicSceneItem *castedMosItem = (MosaicSceneItem *) mosItem;
1473  m_mosaicSceneItems->removeAll(castedMosItem);
1474  m_displayPropsToMosaicSceneItemMap.remove(
1475  m_displayPropsToMosaicSceneItemMap.key(castedMosItem));
1476  recalcSceneRect();
1477  emit cubesChanged();
1478  }
1479 
1480 
1486  QRectF sceneRect = cubesBoundingRect();
1487 
1488  if (sceneRect.isEmpty())
1489  return;
1490 
1491  double xPadding = sceneRect.width() * 0.10;
1492  double yPadding = sceneRect.height() * 0.10;
1493 
1494  sceneRect.adjust(-xPadding, -yPadding, xPadding, yPadding);
1495  getView()->fitInView(sceneRect, Qt::KeepAspectRatio);
1496  }
1497 
1498 
1499  void MosaicSceneWidget::setCubesSelectable(bool selectable) {
1500  if (m_cubesSelectable != selectable) {
1501  m_cubesSelectable = selectable;
1502 
1503  MosaicSceneItem *mosaicSceneItem;
1504  foreach(mosaicSceneItem, *m_mosaicSceneItems) {
1505  mosaicSceneItem->scenePropertiesChanged();
1506  }
1507  }
1508  }
1509 
1510 
1516  ProjectionConfigDialog configDialog(this);
1517  configDialog.exec();
1518  }
1519 
1520 
1521  void MosaicSceneWidget::quickConfigProjectionParameters() {
1522  ProjectionConfigDialog configDialog(this);
1523  configDialog.setQuickConfig(true);
1524  configDialog.exec();
1525  }
1526 
1527 
1528  void MosaicSceneWidget::sendVisibleRectChanged() {
1529  QPointF topLeft = getView()->mapToScene(0, 0);
1530  QPointF bottomRight = getView()->mapToScene(
1531  (int)getView()->width(),
1532  (int)getView()->height());
1533 
1534  QRectF visibleRect(topLeft, bottomRight);
1535  emit visibleRectChanged(visibleRect);
1536  }
1537 
1538 
1539  bool MosaicSceneWidget::eventFilter(QObject *obj, QEvent *event) {
1540  bool stopProcessingEvent = true;
1541 
1542  switch(event->type()) {
1543  case QMouseEvent::GraphicsSceneMousePress: {
1544  if (m_customRubberBandEnabled) {
1545  // Intiate the rubber banding!
1546  if (!m_customRubberBand) {
1547  m_customRubberBand = new QRubberBand(QRubberBand::Rectangle,
1548  getView());
1549  }
1550 
1551  if (!m_rubberBandOrigin) {
1552  m_rubberBandOrigin = new QPoint;
1553  }
1554 
1555  *m_rubberBandOrigin = getView()->mapFromScene(
1556  ((QGraphicsSceneMouseEvent *)event)->scenePos());
1557  m_customRubberBand->setGeometry(QRect(*m_rubberBandOrigin, QSize()));
1558  m_customRubberBand->show();
1559  }
1560 
1561  emit mouseButtonPress(
1562  ((QGraphicsSceneMouseEvent *)event)->scenePos(),
1563  ((QGraphicsSceneMouseEvent *)event)->button());
1564  stopProcessingEvent = false;
1565  break;
1566  }
1567 
1568  case QMouseEvent::GraphicsSceneMouseRelease: {
1569  bool signalEmitted = false;
1570  if (m_customRubberBandEnabled && m_rubberBandOrigin &&
1571  m_customRubberBand) {
1572  if (m_customRubberBand->geometry().width() +
1573  m_customRubberBand->geometry().height() > 10) {
1574  emit rubberBandComplete(
1575  getView()->mapToScene(
1576  m_customRubberBand->geometry()).boundingRect(),
1577  ((QGraphicsSceneMouseEvent *)event)->button());
1578  signalEmitted = true;
1579  }
1580 
1581  delete m_rubberBandOrigin;
1582  m_rubberBandOrigin = NULL;
1583 
1584  delete m_customRubberBand;
1585  m_customRubberBand = NULL;
1586  }
1587 
1588  if (!signalEmitted) {
1589  stopProcessingEvent = false;
1590  emit mouseButtonRelease(
1591  ((QGraphicsSceneMouseEvent *)event)->scenePos(),
1592  ((QGraphicsSceneMouseEvent *)event)->button());
1593  }
1594  break;
1595  }
1596 
1597  case QMouseEvent::GraphicsSceneMouseDoubleClick:
1598  emit mouseDoubleClick(
1599  ((QGraphicsSceneMouseEvent *)event)->scenePos());
1600  stopProcessingEvent = false;
1601  break;
1602 
1603  case QMouseEvent::GraphicsSceneMouseMove:
1604  if (m_customRubberBandEnabled && m_rubberBandOrigin &&
1605  m_customRubberBand) {
1606  QPointF scenePos = ((QGraphicsSceneMouseEvent *)event)->scenePos();
1607  QPoint screenPos = getView()->mapFromScene(scenePos);
1608 
1609  QRect rubberBandRect =
1610  QRect(*m_rubberBandOrigin, screenPos).normalized();
1611 
1612  m_customRubberBand->setGeometry(rubberBandRect);
1613  }
1614  else {
1615  stopProcessingEvent = false;
1616  }
1617 
1618  emit mouseMove(
1619  ((QGraphicsSceneMouseEvent *)event)->scenePos());
1620  break;
1621 
1622  case QEvent::GraphicsSceneWheel:
1623  emit mouseWheel(
1624  ((QGraphicsSceneWheelEvent *)event)->scenePos(),
1625  ((QGraphicsSceneWheelEvent *)event)->delta());
1626  event->accept();
1627  stopProcessingEvent = true;
1628  break;
1629 
1630  case QMouseEvent::Enter:
1631  emit mouseEnter();
1632  stopProcessingEvent = false;
1633  break;
1634 
1635  case QMouseEvent::Leave:
1636  emit mouseLeave();
1637  stopProcessingEvent = false;
1638  break;
1639 
1640  case QEvent::GraphicsSceneHelp: {
1641  setToolTip("");
1642  bool toolTipFound = false;
1643 
1644  QGraphicsItem *sceneItem;
1645  foreach(sceneItem, getScene()->items()) {
1646  if (!toolTipFound) {
1647  if (sceneItem->contains(
1648  ((QGraphicsSceneHelpEvent*)event)->scenePos()) &&
1649  sceneItem->toolTip().size() > 0) {
1650  setToolTip(sceneItem->toolTip());
1651  toolTipFound = true;
1652  }
1653  }
1654  }
1655 
1656  if (toolTipFound) {
1657  stopProcessingEvent = true;
1658  QToolTip::showText(
1659  ((QGraphicsSceneHelpEvent*)event)->screenPos(),
1660  toolTip());
1661  }
1662  break;
1663  }
1664 
1665  default:
1666  stopProcessingEvent = false;
1667  break;
1668  }
1669 
1670  return stopProcessingEvent;
1671  }
1672 
1673 
1681  if (m_mosaicSceneItems->size() == 0)
1682  return;
1683 
1684  if (m_userToolControl)
1685  m_progress->setText("Reprojecting primary scene");
1686  else
1687  m_progress->setText("Reprojecting secondary scene");
1688 
1689  // This gives some pretty graphics as thing work
1690  int reprojectsPerUpdate = qMax(1, m_mosaicSceneItems->size() / 20);
1691 
1692  m_progress->setRange(0,
1693  (m_mosaicSceneItems->size() - 1) / reprojectsPerUpdate + 1);
1694  m_progress->setValue(0);
1695  m_progress->setVisible(true);
1696 
1697  MosaicSceneItem *mosaicSceneItem;
1698 
1699  int progressCountdown = reprojectsPerUpdate;
1700  foreach(mosaicSceneItem, *m_mosaicSceneItems) {
1701  try {
1702  mosaicSceneItem->reproject();
1703  }
1704  catch (IException &e) {
1705  QString msg = "The file [";
1706 
1707  if (mosaicSceneItem->image())
1708  msg += mosaicSceneItem->image()->displayProperties()->displayName();
1709 
1710  msg += "] is being removed due to not being able to project onto the scene";
1711 
1712  IException tmp(e, IException::Programmer, msg, _FILEINFO_);
1713  tmp.print();
1714  mosaicSceneItem->image()->deleteLater();
1715  }
1716 
1717  progressCountdown --;
1718  if (progressCountdown == 0) {
1719  m_progress->setValue(m_progress->value() + 1);
1720  progressCountdown = reprojectsPerUpdate;
1721  refit();
1722  }
1723  }
1724 
1725  m_progress->setValue(m_progress->maximum());
1726 
1727  recalcSceneRect();
1728  refit();
1729  m_progress->setVisible(false);
1730  }
1731 
1732 
1733  void MosaicSceneWidget::moveDownOne() {
1734  DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1735 
1736  if (props) {
1737  moveDownOne(cubeToMosaic(props));
1738  }
1739  }
1740 
1741 
1744  double MosaicSceneWidget::moveDownOne(MosaicSceneItem *item) {
1745  MosaicSceneItem *nextDown = getNextItem(item, false);
1746  double originalZ = item->zValue();
1747 
1748  if (nextDown) {
1749  double newZValue = nextDown->zValue() - 1;
1750  moveZ(item, newZValue, true);
1751  }
1752 
1753  return originalZ;
1754  }
1755 
1756 
1759  double MosaicSceneWidget::moveDownOne(Image *image) {
1760  return moveDownOne(cubeToMosaic(image));
1761  }
1762 
1763 
1766  QList<double> MosaicSceneWidget::moveDownOne(ImageList *images) {
1767  QList<double> results;
1768 
1769  foreach (Image *image, *images) {
1770  results.append(moveDownOne(image));
1771  }
1772 
1773  return results;
1774  }
1775 
1776 
1777  void MosaicSceneWidget::moveToBottom() {
1778  DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1779  if (props) {
1780  moveToBottom(cubeToMosaic(props));
1781  }
1782  }
1783 
1784 
1789  double MosaicSceneWidget::moveToBottom(MosaicSceneItem *item) {
1790  double originalZ = item->zValue();
1791  double minZ = minimumZ();
1792 
1793  if (originalZ != minZ) {
1794  // We know min-1 isn't already used
1795  int newZValue = qRound(minZ - 1);
1796  item->setZValue(newZValue);
1797 
1798  // Remove this if we enable the compress
1799  m_currentMinimumFootprintZ--;
1800  }
1801 
1802  return originalZ;
1803  }
1804 
1805 
1810  double MosaicSceneWidget::moveToBottom(Image *image) {
1811  return moveToBottom(cubeToMosaic(image));
1812  }
1813 
1814 
1819  QList<double> MosaicSceneWidget::moveToBottom(ImageList *images) {
1820  QList<double> results;
1821 
1822  foreach (Image *image, *images) {
1823  results.append(moveToBottom(image));
1824  }
1825 
1826  return results;
1827  }
1828 
1829 
1830  void MosaicSceneWidget::moveUpOne() {
1831  DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1832 
1833  if (props) {
1834  moveUpOne(cubeToMosaic(props));
1835  }
1836  }
1837 
1838 
1841  double MosaicSceneWidget::moveUpOne(MosaicSceneItem *item) {
1842  MosaicSceneItem *nextUp = getNextItem(item, true);
1843  double originalZ = item->zValue();
1844 
1845  if (nextUp) {
1846  double newZValue = nextUp->zValue() + 1;
1847  moveZ(item, newZValue, true);
1848  }
1849 
1850  return originalZ;
1851  }
1852 
1853 
1856  double MosaicSceneWidget::moveUpOne(Image *image) {
1857  return moveUpOne(cubeToMosaic(image));
1858  }
1859 
1860 
1863  QList<double> MosaicSceneWidget::moveUpOne(ImageList *images) {
1864  QList<double> results;
1865 
1866  foreach (Image *image, *images) {
1867  results.append(moveUpOne(image));
1868  }
1869 
1870  return results;
1871  }
1872 
1873 
1874  void MosaicSceneWidget::moveToTop() {
1875  DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1876 
1877  if (props) {
1878  moveToTop(cubeToMosaic(props));
1879  }
1880  }
1881 
1882 
1887  double MosaicSceneWidget::moveToTop(MosaicSceneItem *item) {
1888  double originalZ = item->zValue();
1889  double maxZ = maximumZ();
1890 
1891  if (originalZ != maxZ) {
1892  // We know max+1 isn't already used
1893  int newZValue = qRound(maxZ + 1);
1894  item->setZValue(newZValue);
1895 
1896  // Remove this if we enable the compress
1897  m_currentMaximumFootprintZ++;
1898  }
1899 
1900  // Compress... this makes this method have a time complexity of N instead of constant; there
1901  // isn't really a good justification for the slow down. I'm leaving this (working) code here
1902  // for reference and in case it's needed later.
1903  // foreach (MosaicSceneItem *otherItem, *m_mosaicSceneItems) {
1904  // double otherItemZ = otherItem->zValue();
1905  // if (otherItemZ > originalZ) {
1906  // otherItem->setZValue(otherItemZ - 1.0);
1907  // }
1908  // }
1909 
1910  return originalZ;
1911  }
1912 
1913 
1918  double MosaicSceneWidget::moveToTop(Image *image) {
1919  return moveToTop(cubeToMosaic(image));
1920  }
1921 
1922 
1927  QList<double> MosaicSceneWidget::moveToTop(ImageList *images) {
1928  QList<double> results;
1929 
1930  foreach (Image *image, *images) {
1931  results.append(moveToTop(image));
1932  }
1933 
1934 
1935 // printZ(m_mosaicSceneItems);
1936  return results;
1937  }
1938 
1939 
1955  double MosaicSceneWidget::moveZ(MosaicSceneItem *sceneItem, double newZ,
1956  bool newZValueMightExist) {
1957  double originalZ = sceneItem->zValue();
1958 
1959  if (newZValueMightExist) {
1960  // Adjust items between original and new position, recalculate min/max - time complexity=N
1961  m_currentMinimumFootprintZ = 0.0;
1962  m_currentMaximumFootprintZ = 0.0;
1963 
1964  foreach (MosaicSceneItem *otherItem, *m_mosaicSceneItems) {
1965  double otherItemOrigZ = otherItem->zValue();
1966  double otherItemNewZ = otherItemOrigZ;
1967 
1968  // Moving downwards (new Z is lower than current Z) and item is in the middle
1969  if (originalZ > newZ && otherItemOrigZ >= newZ && otherItemOrigZ < originalZ) {
1970  otherItemNewZ = otherItemOrigZ + 1;
1971  }
1972  // Moving upwards (new Z is higher than current Z) and item is in the middle
1973  else if (originalZ < newZ && otherItemOrigZ <= newZ && otherItemOrigZ > originalZ) {
1974  otherItemNewZ = otherItemOrigZ - 1;
1975  }
1976 
1977  m_currentMinimumFootprintZ = qMin(m_currentMinimumFootprintZ, otherItemNewZ);
1978  m_currentMaximumFootprintZ = qMax(m_currentMaximumFootprintZ, otherItemNewZ);
1979  otherItem->setZValue(otherItemNewZ);
1980  }
1981  }
1982 
1983  sceneItem->setZValue(newZ);
1984 
1985  if (!newZValueMightExist) {
1986  // If we moved the max or min item, adjust the max down or min up respectively
1987  if (originalZ == maximumZ() && newZ < originalZ) {
1988  m_currentMaximumFootprintZ--;
1989  }
1990  else if (originalZ == minimumZ() && newZ > originalZ) {
1991  m_currentMinimumFootprintZ++;
1992  }
1993  }
1994 
1995  return originalZ;
1996  }
1997 
1998 
1999  double MosaicSceneWidget::moveZ(Image *image, double newZ,
2000  bool newZValueMightExist) {
2001  return moveZ(cubeToMosaic(image), newZ, newZValueMightExist);
2002  }
2003 
2004 
2005  void MosaicSceneWidget::fitInView() {
2006  if (m_userToolControl) {
2007  QRectF boundingBox;
2008 
2009  DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
2010 
2011  if (props) {
2012  MosaicSceneItem *item = cubeToMosaic(props);
2013  boundingBox = item->boundingRect();
2014  }
2015  else {
2016  QAction *action = qobject_cast<QAction *>(sender());
2017 
2018  if (action) {
2019  ImageList *images = action->data().value<ImageList *>();
2020 
2021  foreach (Image *image, *images) {
2022  ASSERT(cubeToMosaic(image));
2023  boundingBox = boundingBox.united(cubeToMosaic(image)->boundingRect());
2024  }
2025  }
2026  }
2027 
2028  if (!boundingBox.isNull()) {
2029  double xPadding = boundingBox.width() * 0.10;
2030  double yPadding = boundingBox.height() * 0.10;
2031 
2032  boundingBox.setLeft(boundingBox.left() - xPadding);
2033  boundingBox.setRight(boundingBox.right() + xPadding);
2034 
2035  boundingBox.setTop(boundingBox.top() - yPadding);
2036  boundingBox.setBottom(boundingBox.bottom() + yPadding);
2037 
2038  getView()->fitInView(boundingBox, Qt::KeepAspectRatio);
2039  getView()->centerOn(boundingBox.center());
2040  }
2041  }
2042  }
2043 
2044 
2045  void MosaicSceneWidget::onSelectionChanged() {
2046  if (!m_blockingSelectionChanged) {
2047  if (!m_queuedSelectionChanged) {
2048  emit queueSelectionChanged();
2049  m_queuedSelectionChanged = true;
2050  }
2051  else {
2052  m_shouldRequeueSelectionChanged = true;
2053  }
2054  }
2055  }
2056 
2057 
2058  void MosaicSceneWidget::onQueuedSelectionChanged() {
2059  m_queuedSelectionChanged = false;
2060 
2061  if (m_shouldRequeueSelectionChanged) {
2062  m_shouldRequeueSelectionChanged = false;
2063  onSelectionChanged();
2064  }
2065  else {
2066  foreach(MosaicSceneItem *mosaicSceneItem, *m_mosaicSceneItems) {
2067  mosaicSceneItem->updateSelection(true);
2068  }
2069  }
2070  }
2071 
2072 
2075  MosaicSceneItem *nextZValueItem = NULL;
2076  MosaicSceneItem *mosaicSceneItem;
2077 
2078  foreach(mosaicSceneItem, *m_mosaicSceneItems) {
2079  if (mosaicSceneItem != item &&
2080  mosaicSceneItem->boundingRect().intersects(item->boundingRect())) {
2081  // Does this item qualify as above or below at all?
2082  if ( (up && mosaicSceneItem->zValue() > item->zValue()) ||
2083  (!up && mosaicSceneItem->zValue() < item->zValue())) {
2084  // It is in the correct direction, set the initial guess if we don't
2085  // have one or test if it's better
2086  if (!nextZValueItem) {
2087  nextZValueItem = mosaicSceneItem;
2088  }
2089  else {
2090  // We know it qualifies, we want to know if it's closer than
2091  // nextZValueItem
2092  if ((up && mosaicSceneItem->zValue() < nextZValueItem->zValue()) ||
2093  (!up && mosaicSceneItem->zValue() > nextZValueItem->zValue())) {
2094  nextZValueItem = mosaicSceneItem;
2095  }
2096  }
2097  }
2098  }
2099  }
2100 
2101  return nextZValueItem;
2102  }
2103 
2104 
2105  bool MosaicSceneWidget::zOrderGreaterThan(MosaicSceneItem *first,
2106  MosaicSceneItem *second) {
2107  return first->zValue() > second->zValue();
2108  }
2109 
2110 
2111  MosaicSceneWidget::XmlHandler::XmlHandler(MosaicSceneWidget *scene) {
2112  m_scene = scene;
2113  m_scrollBarXValue = -1;
2114  m_scrollBarYValue = -1;
2115  m_imagesToAdd = NULL;
2116 
2117  m_imagesToAdd = new ImageList;
2118  }
2119 
2120 
2121  MosaicSceneWidget::XmlHandler::~XmlHandler() {
2122  delete m_imagesToAdd;
2123  m_imagesToAdd = NULL;
2124  }
2125 
2126 
2127  bool MosaicSceneWidget::XmlHandler::startElement(const QString &namespaceURI,
2128  const QString &localName, const QString &qName, const QXmlAttributes &atts) {
2129  bool result = XmlStackedHandler::startElement(namespaceURI, localName, qName, atts);
2130 
2131  m_characterData = "";
2132 
2133  if (result) {
2134  if (localName == "image" && m_scene->m_directory) {
2135  QString id = atts.value("id");
2136  double zValue = atts.value("zValue").toDouble();
2137  Image *image = m_scene->m_directory->project()->image(id);
2138  // If Image for id doesn't exist, check shapes. If corresponds to Shape, new Image will
2139  // need to be created.
2140  if (!image) {
2141  Shape *shape = m_scene->m_directory->project()->shape(id);
2142  if (shape) {
2143  image = new Image(shape->cube(), shape->footprint(), id);
2144  }
2145  }
2146  if (image) {
2147  m_imagesToAdd->append(image);
2148  m_imageZValues.append(zValue);
2149 // m_scene->cubeToMosaic(image)->setZValue(zValue);
2150  }
2151  }
2152  else if (localName == "viewTransform") {
2153  m_scrollBarXValue = atts.value("scrollBarXValue").toInt();
2154  m_scrollBarYValue = atts.value("scrollBarYValue").toInt();
2155  }
2156  }
2157 
2158  return result;
2159  }
2160 
2161 
2162  bool MosaicSceneWidget::XmlHandler::characters(const QString &ch) {
2163  bool result = XmlStackedHandler::characters(ch);
2164 
2165  if (result) {
2166  m_characterData += ch;
2167  }
2168 
2169  return result;
2170  }
2171 
2172 
2173  bool MosaicSceneWidget::XmlHandler::endElement(const QString &namespaceURI,
2174  const QString &localName, const QString &qName) {
2175  bool result = XmlStackedHandler::endElement(namespaceURI, localName, qName);
2176 
2177  if (result) {
2178  if (localName == "projection") {
2179  std::stringstream strStream(m_characterData.toStdString());
2180  PvlGroup mappingGroup;
2181  strStream >> mappingGroup;
2182  m_scene->setProjection(mappingGroup);
2183  }
2184  else if (localName == "viewTransform") {
2185  QByteArray hexValues(m_characterData.toLatin1());
2186  QDataStream transformStream(QByteArray::fromHex(hexValues));
2187 
2188  QTransform viewTransform;
2189  transformStream >> viewTransform;
2190  m_scene->getView()->show();
2191  QCoreApplication::processEvents();
2192  m_scene->getView()->setTransform(viewTransform);
2193  m_scene->getView()->horizontalScrollBar()->setValue(m_scrollBarXValue);
2194  m_scene->getView()->verticalScrollBar()->setValue(m_scrollBarYValue);
2195  }
2196  else if (localName == "toolData") {
2197  PvlObject toolSettings;
2198  std::stringstream strStream(m_characterData.toStdString());
2199  strStream >> toolSettings;
2200 
2201  foreach (MosaicTool *tool, *m_scene->m_tools) {
2202  if (tool->projectPvlObjectName() == toolSettings.name()) {
2203  tool->fromPvl(toolSettings);
2204  }
2205  }
2206  }
2207  else if (localName == "images" && m_imagesToAdd->count()) {
2208  ASSERT(m_imagesToAdd->count() == m_imageZValues.count());
2209  m_scene->addImages(*m_imagesToAdd);
2210 
2211  for (int i = 0; i < m_imageZValues.count(); i++) {
2212  m_scene->cubeToMosaic(m_imagesToAdd->at(i))->setZValue(m_imageZValues[i]);
2213  m_scene->m_currentMinimumFootprintZ = qMin(m_scene->m_currentMinimumFootprintZ,
2214  m_imageZValues[i]);
2215  m_scene->m_currentMaximumFootprintZ = qMax(m_scene->m_currentMaximumFootprintZ,
2216  m_imageZValues[i]);
2217  }
2218  }
2219  }
2220 
2221  m_characterData = "";
2222 
2223  return result;
2224  }
2225 }
Isis::Target::radiiGroup
static PvlGroup radiiGroup(QString target)
Creates a Pvl Group with keywords TargetName, EquitorialRadius, and PolarRadius.
Definition: Target.cpp:403
Isis::MosaicSceneWidget::setProjection
void setProjection(Projection *)
This method takes ownership of proj.
Definition: MosaicSceneWidget.cpp:290
QWidget
QProgressBar
Isis::PvlObject::findGroup
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:129
Isis::MosaicSceneWidget::m_graphicsView
MosaicGraphicsView * m_graphicsView
The graphics view.
Definition: MosaicSceneWidget.h:365
Isis::PvlObject
Contains Pvl Groups and Pvl Objects.
Definition: PvlObject.h:61
Isis::IException::print
void print() const
Prints a string representation of this exception to stderr.
Definition: IException.cpp:445
Isis::MosaicSceneWidget::moveToBottom
double moveToBottom(MosaicSceneItem *)
This doesn't compress the Z values - the original Z values of this scene item is guaranteed to be emp...
Definition: MosaicSceneWidget.cpp:1789
Isis::Directory
Definition: Directory.h:271
Isis::MosaicSelectTool
Handles selection operations for Isis qt apps.
Definition: MosaicSelectTool.h:19
Isis::PvlKeyword
A single keyword-value pair.
Definition: PvlKeyword.h:82
QList
This is free and unencumbered software released into the public domain.
Definition: BoxcarCachingAlgorithm.h:13
Isis::ProgressBar
Definition: ProgressBar.h:15
Project.h
Isis::MosaicGridTool
This controls the 'Grid' abilities in the MosaicSceneWidget.
Definition: MosaicGridTool.h:53
Isis::MosaicTrackTool
Definition: MosaicTrackTool.h:18
Isis::MosaicSceneWidget::configProjectionParameters
void configProjectionParameters()
This happens when the user clicks on the map action (the button that is named after the current proje...
Definition: MosaicSceneWidget.cpp:1515
Isis::MosaicSceneWidget::contextMenuEvent
bool contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
This is called by MosaicGraphicsScene::contextMenuEvent.
Definition: MosaicSceneWidget.cpp:442
Isis::MosaicSceneWidget::refit
void refit()
This method refits t:he items in the graphics view.
Definition: MosaicSceneWidget.cpp:1485
Isis::XmlStackedHandlerReader::pushContentHandler
virtual void pushContentHandler(XmlStackedHandler *newHandler)
Push a contentHandler and maybe continue parsing...
Definition: XmlStackedHandlerReader.cpp:55
QMenu
Isis::MosaicSceneWidget::MosaicSceneWidget
MosaicSceneWidget(QStatusBar *status, bool showTools, bool internalizeToolBarsAndProgress, Directory *directory, QWidget *parent=0)
Create a scene widget.
Definition: MosaicSceneWidget.cpp:66
Isis::Directory::supportedActions
QList< QAction * > supportedActions(DataType data)
Returns a list of supported actions for a WorkOrder.
Definition: Directory.h:345
Isis::MosaicSceneWidget::moveZ
double moveZ(MosaicSceneItem *sceneItem, double newZ, bool newZValueMightExist=true)
This method moves the given scene item to the given Z value.
Definition: MosaicSceneWidget.cpp:1955
Isis::ImageList::append
void append(Image *const &value)
Appends an image to the image list.
Definition: ImageList.cpp:153
Isis::TextFile
Provides access to sequential ASCII stream I/O.
Definition: TextFile.h:38
Isis::DisplayProperties
Definition: DisplayProperties.h:34
Isis::MosaicFindTool
This controls the 'Find' abilities in the MosaicSceneWidget.
Definition: MosaicFindTool.h:29
Isis::Image::fileName
QString fileName() const
Get the file name of the cube that this image represents.
Definition: Image.cpp:340
Isis::Directory::project
Project * project() const
Gets the Project for this directory.
Definition: Directory.cpp:1311
Image.h
Isis::MosaicSceneItem::reproject
void reproject()
Called anytime the user reprojects the cube.
Definition: MosaicSceneItem.cpp:189
Isis::MosaicSceneWidget::moveToTop
double moveToTop(MosaicSceneItem *)
This doesn't compress the Z values - the original Z values of this scene item is guaranteed to be emp...
Definition: MosaicSceneWidget.cpp:1887
Isis::MosaicSceneWidget::getNextItem
MosaicSceneItem * getNextItem(MosaicSceneItem *item, bool up)
Implemented because we want invisible items too.
Definition: MosaicSceneWidget.cpp:2074
Isis::MosaicSceneWidget::m_graphicsScene
QGraphicsScene * m_graphicsScene
The graphics scene that makes up this widget.
Definition: MosaicSceneWidget.h:364
Isis::MosaicTool
Base class for the MosaicTools.
Definition: MosaicTool.h:37
Isis::MosaicSceneWidget::exportView
void exportView()
Saves the scene as a png, jpg, or tif file.
Definition: MosaicSceneWidget.cpp:1427
QToolBar
QStringList
Isis::toString
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:211
Isis::XmlStackedHandlerReader
Manage a stack of content handlers for reading XML files.
Definition: XmlStackedHandlerReader.h:30
Isis::Project
The main project for ipce.
Definition: Project.h:289
Isis::ImageList
Internalizes a list of images and allows for operations on the entire list.
Definition: ImageList.h:55
Isis::PvlObject::Traverse
@ Traverse
Search child objects.
Definition: PvlObject.h:158
Isis::ControlPoint
A single control point.
Definition: ControlPoint.h:354
Isis::ImageList::supportedActions
QList< QAction * > supportedActions(Project *project=NULL)
Gets a list of pre-connected actions that have to do with display.
Definition: ImageList.cpp:565
QHash< QString, double >
Isis::PvlGroup
Contains multiple PvlContainers.
Definition: PvlGroup.h:41
Isis::WorkOrder::setData
virtual void setData(Context)
Sets the context data for this WorkOrder.
Definition: WorkOrder.cpp:248
Isis::MosaicAreaTool
This displays a box with a given distance from a point.
Definition: MosaicAreaTool.h:28
Isis::toInt
int toInt(const QString &string)
Global function to convert from a string to an integer.
Definition: IString.cpp:93
Isis::MosaicSceneWidget::supportedActions
QList< QAction * > supportedActions(ImageList *)
Get a list of actions this scene can perform given "images".
Definition: MosaicSceneWidget.cpp:812
Isis::MoveToBottomSceneWorkOrder
Move images below all other images in a mosaic scene This workorder is synchronous and undoable.
Definition: MoveToBottomSceneWorkOrder.h:20
Isis::PvlObject::findObject
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
Definition: PvlObject.h:274
Isis::DisplayProperties::displayName
QString displayName() const
Returns the display name.
Definition: DisplayProperties.cpp:88
Isis::MosaicSceneWidget::reprojectItems
void reprojectItems()
Reprojects all the items in the view.
Definition: MosaicSceneWidget.cpp:1680
Isis::Image
This represents a cube in a project-based GUI interface.
Definition: Image.h:107
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::ProjectionFactory::Create
static Isis::Projection * Create(Isis::Pvl &label, bool allowDefaults=false)
This method returns a pointer to a Projection object.
Definition: ProjectionFactory.cpp:51
Isis::PvlObject::hasObject
bool hasObject(const QString &name) const
Returns a boolean value based on whether the object exists in the current PvlObject or not.
Definition: PvlObject.h:323
Isis::MosaicSceneWidget::fromPvl
void fromPvl(const PvlObject &)
Call this method after loading any cubes when loading a project.
Definition: MosaicSceneWidget.cpp:581
Isis::ProjectionFactory::CreateFromCube
static Isis::Projection * CreateFromCube(Isis::Cube &cube)
This method is a helper method.
Definition: ProjectionFactory.cpp:1069
Isis::Image::displayProperties
ImageDisplayProperties * displayProperties()
Get the display (GUI) properties (information) associated with this image.
Definition: Image.cpp:320
Isis::MosaicSceneWidget::selectedImages
ImageList selectedImages()
Returns a list of all the cubes selected in the scene.
Definition: MosaicSceneWidget.cpp:742
Isis::ToolPad
Definition: ToolPad.h:14
Isis::MoveUpOneSceneWorkOrder
Move images, one by one, on top of the immediately-above intersecting image in a scene This workorder...
Definition: MoveUpOneSceneWorkOrder.h:20
Isis::MosaicTool::isActive
bool isActive() const
Returns the activeness of this toool.
Definition: MosaicTool.h:50
Isis::toDouble
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition: IString.cpp:149
Isis::IException::Programmer
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:146
Isis::MosaicSceneItem
A single cube in the mosaic scene.
Definition: MosaicSceneItem.h:47
Isis::MosaicControlNetTool
//TODO: Remove debug printout & comment // 2016-08-25 Tracie Sucharski - Checking Directory pointer f...
Definition: MosaicControlNetTool.h:74
Isis::MosaicGraphicsView
A graphics view that resizes in a more friendly way.
Definition: MosaicGraphicsView.h:19
Isis::MosaicPanTool
Handles panning operations for Isis qt apps.
Definition: MosaicPanTool.h:22
Isis::PvlContainer::keywords
int keywords() const
Returns the number of keywords contained in the PvlContainer.
Definition: PvlContainer.h:86
Isis::PvlContainer::findKeyword
PvlKeyword & findKeyword(const QString &name)
Find a keyword with a specified name.
Definition: PvlContainer.cpp:62
Isis::ProgressBar::setText
void setText(QString text)
Set custom text for this progress bar.
Definition: ProgressBar.cpp:32
QObject
Isis::MosaicSceneWidget::m_projection
Projection * m_projection
The current projection type.
Definition: MosaicSceneWidget.h:366
Isis::Projection
Base class for Map Projections.
Definition: Projection.h:155
Isis::ProjectionConfigDialog
This is the configuration dialog for the MosaicSceneWidget's projection parameters (map file).
Definition: ProjectionConfigDialog.h:24
QAction
Isis::MoveToTopSceneWorkOrder
Move images on top of all other images in a mosaic scene This workorder is synchronous and undoable.
Definition: MoveToTopSceneWorkOrder.h:20
QGraphicsItem
Isis::MosaicZoomTool
Handles zoom operations for Isis qt apps.
Definition: MosaicZoomTool.h:26
Isis::MosaicGraphicsScene
A graphics scene with improved user-interaction for use with the MosaicSceneWidget.
Definition: MosaicGraphicsScene.h:24
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::IException::User
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition: IException.h:126
Isis::MoveDownOneSceneWorkOrder
Move images, one by one, below the immediately-below intersecting image in a scene This workorder is ...
Definition: MoveDownOneSceneWorkOrder.h:20

U.S. Department of the Interior | U.S. Geological Survey
ISIS | Privacy & Disclaimers | Astrogeology Research Program
To contact us, please post comments and questions on the USGS Astrogeology Discussion Board
To report a bug, or suggest a feature go to: ISIS Github
File Modified: 07/13/2023 15:16:54