3 #include "MosaicSceneWidget.h"
16 #include "GraphicsView.h"
18 #include "ImageList.h"
21 #include "MosaicAreaTool.h"
22 #include "MosaicControlNetTool.h"
23 #include "MosaicFindTool.h"
24 #include "MosaicGraphicsScene.h"
25 #include "MosaicGraphicsView.h"
26 #include "MosaicGridTool.h"
27 #include "MosaicPanTool.h"
28 #include "MosaicSceneItem.h"
29 #include "MosaicSelectTool.h"
30 #include "MosaicTrackTool.h"
31 #include "MosaicZoomTool.h"
32 #include "MoveDownOneSceneWorkOrder.h"
33 #include "MoveToBottomSceneWorkOrder.h"
34 #include "MoveToTopSceneWorkOrder.h"
35 #include "MoveUpOneSceneWorkOrder.h"
36 #include "ProgressBar.h"
39 #include "ProjectionConfigDialog.h"
47 #include "XmlStackedHandlerReader.h"
54 bool internalizeToolBarsAndProgress,
Directory *directory,
56 m_projectImageZOrders = NULL;
57 m_projectViewTransform = NULL;
58 m_directory = directory;
76 m_quickMapAction = NULL;
78 m_cubesSelectable =
true;
79 m_customRubberBandEnabled =
false;
80 m_customRubberBand = NULL;
81 m_rubberBandOrigin = NULL;
83 m_blockingSelectionChanged =
false;
84 m_queuedSelectionChanged =
false;
85 m_shouldRequeueSelectionChanged =
false;
87 m_userToolControl =
false;
88 m_ownProjection =
false;
91 m_progress->setVisible(
false);
93 QGridLayout * sceneLayout =
new QGridLayout;
94 sceneLayout->setContentsMargins(0, 0, 0, 0);
95 setLayout(sceneLayout);
98 if (!status && internalizeToolBarsAndProgress)
99 status =
new QStatusBar;
113 m_tools->at(0)->activate(
true);
117 if (internalizeToolBarsAndProgress) {
132 QHBoxLayout *horizontalToolBarsLayout =
new QHBoxLayout;
134 m_permToolbar =
new QToolBar(
"Standard Tools");
135 m_permToolbar->setWhatsThis(
"This area contains options that are always present in the "
137 horizontalToolBarsLayout->addWidget(m_permToolbar);
139 m_activeToolbar =
new QToolBar(
"Active Tool",
this);
140 m_activeToolbar->setObjectName(
"Active Tool");
141 m_activeToolbar->setWhatsThis(
"The currently selected tool's options will "
142 "show up here. Not all tools have options.");
143 horizontalToolBarsLayout->addWidget(m_activeToolbar);
145 sceneLayout->addLayout(horizontalToolBarsLayout, 0, 0, 1, 2);
149 m_toolpad =
new ToolPad(
"Tool Pad",
this);
150 m_toolpad->setObjectName(
"Tool Pad");
151 m_toolpad->setOrientation(Qt::Vertical);
152 m_toolpad->setFloatable(
true);
153 sceneLayout->addWidget(m_toolpad, 1, 1, 1, 1);
155 QHBoxLayout *horizontalStatusLayout =
new QHBoxLayout;
156 horizontalStatusLayout->addWidget(m_progress);
157 horizontalStatusLayout->addStretch();
158 horizontalStatusLayout->addWidget(status);
160 sceneLayout->addLayout(horizontalStatusLayout, 2, 0, 1, 2);
162 addToPermanent(m_permToolbar);
163 m_permToolbar->addSeparator();
165 addTo(m_activeToolbar);
172 m_userToolControl =
true;
174 setWhatsThis(
"This is the mosaic scene. The opened cubes will be "
175 "shown here. You can fully interact with the files shown here.");
177 getView()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
178 getView()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
180 getView()->enableResizeZooming(
false);
182 connect(getView()->horizontalScrollBar(), SIGNAL(valueChanged(
int)),
183 this, SLOT(sendVisibleRectChanged()));
184 connect(getView()->verticalScrollBar() , SIGNAL(valueChanged(
int)),
185 this, SLOT(sendVisibleRectChanged()));
186 connect(getView()->horizontalScrollBar(), SIGNAL(rangeChanged(
int,
int)),
187 this, SLOT(sendVisibleRectChanged()));
188 connect(getView()->verticalScrollBar() , SIGNAL(rangeChanged(
int,
int)),
189 this, SLOT(sendVisibleRectChanged()));
195 getView()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
196 getView()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
198 setWhatsThis(
"This is the mosaic world view. The opened cubes will be "
199 "shown here, but you cannot zoom in. You can select cubes by dragging "
200 "a box over them, zoom to a particular cube by right clicking on it "
201 "and selecting 'Zoom Fit', and many other actions are available.");
206 m_currentMinimumFootprintZ = 0;
207 m_currentMaximumFootprintZ = 0;
209 connect(getScene(), SIGNAL(selectionChanged()),
210 this, SLOT(onSelectionChanged()));
213 connect(
this, SIGNAL(queueSelectionChanged()),
214 this, SLOT(onQueuedSelectionChanged()), Qt::QueuedConnection);
217 MosaicSceneWidget::~MosaicSceneWidget() {
218 m_outlineRect = NULL;
230 if (m_ownProjection) {
235 delete m_projectImageZOrders;
236 m_projectImageZOrders = NULL;
238 delete m_projectViewTransform;
239 m_projectViewTransform = NULL;
247 if (!mapping.hasKeyword(
"EquatorialRadius")) {
249 tmp.findGroup(
"Mapping") += radii[
"EquatorialRadius"];
250 tmp.findGroup(
"Mapping") += radii[
"PolarRadius"];
254 m_ownProjection =
true;
264 PvlKeyword projectionKeyword = mapping.findKeyword(
"ProjectionName");
265 QString projName = projectionKeyword[0];
266 m_mapButton->setText(tr(
"View/Edit %1 Projection").arg(projName));
275 if (old && m_ownProjection) {
280 m_ownProjection =
false;
285 void MosaicSceneWidget::setOutlineRect(QRectF outline) {
286 if (outline.united(getView()->sceneRect()) != getView()->sceneRect())
289 if (!m_outlineRect) {
290 m_outlineRect = getScene()->addRect(outline,
293 m_outlineRect->setZValue(DBL_MAX);
296 m_outlineRect->setRect(outline);
299 if (!m_userToolControl)
304 PvlGroup MosaicSceneWidget::createInitialProjection(
306 Projection *proj = NULL;
307 Cube *cube = image->cube();
308 Pvl *label = cube->label();
312 return proj->Mapping();
314 catch(IException &) {
315 Pvl mappingPvl(
"$base/templates/maps/equirectangular.map");
316 PvlGroup &mappingGrp = mappingPvl.findGroup(
"Mapping");
317 mappingGrp += PvlKeyword(
"LatitudeType",
"Planetocentric");
318 mappingGrp += PvlKeyword(
"LongitudeDirection",
"PositiveEast");
319 mappingGrp += PvlKeyword(
"LongitudeDomain",
"360");
320 mappingGrp += PvlKeyword(
"CenterLatitude",
"0");
321 mappingGrp += PvlKeyword(
"CenterLongitude",
"180");
322 mappingGrp += PvlKeyword(
"MinimumLatitude",
"-90");
323 mappingGrp += PvlKeyword(
"MaximumLatitude",
"90");
324 mappingGrp += PvlKeyword(
"MinimumLongitude",
"0");
325 mappingGrp += PvlKeyword(
"MaximumLongitude",
"360");
328 Camera * cam = cube->camera();
332 mappingGrp += PvlKeyword(
"TargetName", cam->target()->name());
333 mappingGrp += PvlKeyword(
"EquatorialRadius",
toString(radii[0].meters()),
335 mappingGrp += PvlKeyword(
"PolarRadius",
toString(radii[2].meters()),
339 catch(IException &) {
358 foreach(mosaicItem, *m_mosaicSceneItems) {
359 if (mosaicItem->isSelected()) {
360 cubes.
append(mosaicItem->image());
368 void MosaicSceneWidget::addToPermanent(
QToolBar *perm) {
369 m_mapButton =
new QToolButton(
this);
370 connect(
this, SIGNAL(destroyed()), m_mapButton, SLOT(deleteLater()));
371 m_mapButton->setText(tr(
"View/Edit/Load Map File"));
372 m_mapButton->setToolTip(tr(
"View/Edit/Load Map File"));
373 m_mapButton->setIcon(QIcon(
FileName(
"$base/icons/ographic.png").expanded()));
374 m_mapButton->setWhatsThis(tr(
"This is the projection used by the mosaic "
375 "scene. Cubes can not be shown in the scene without a projection, so "
376 "if one is not selected, a default of Equirectangular will be used. "
377 "The selected file should be a map file, examples are available in "
378 "$base/templates/maps."));
379 m_mapButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
385 QString projName = projectionKeyword[0];
386 m_mapButton->setText(projName);
389 m_quickMapAction =
new QAction(tr(
"Quick Load Map"),
this);
390 m_quickMapAction->setToolTip(tr(
"Quick Load Map"));
391 m_quickMapAction->setIcon(QIcon(FileName(
"$base/icons/quickopen.png").expanded()));
392 m_quickMapAction->setWhatsThis(tr(
"This is the projection used by the mosaic "
393 "scene. Cubes can not be shown in the scene without a projection, so "
394 "if one is not selected, a default of Equirectangular will be used."));
395 connect(m_quickMapAction, SIGNAL(triggered()),
this, SLOT(quickConfigProjectionParameters()));
397 perm->addWidget(m_mapButton);
398 perm->addAction(m_quickMapAction);
402 void MosaicSceneWidget::addTo(
QToolBar *toolbar) {
404 foreach(tool, *m_tools) {
405 tool->addTo(toolbar);
410 void MosaicSceneWidget::addTo(QMenu *menu) {
412 foreach(tool, *m_tools) {
418 void MosaicSceneWidget::addTo(ToolPad *toolPad) {
420 foreach(tool, *m_tools) {
421 tool->addTo(toolPad);
432 bool handled =
false;
438 foreach (
QGraphicsItem *graphicsItem, selectedGraphicsItems) {
441 if (!sceneImageItem) {
442 sceneImageItem =
dynamic_cast<MosaicSceneItem *
>(graphicsItem->parentItem());
445 if (sceneImageItem && sceneImageItem->image()) {
446 selectedImageItems.append(sceneImageItem);
447 selectedImages.
append(sceneImageItem->image());
451 if (selectedImageItems.count()) {
454 QAction *title = menu.addAction(tr(
"%L1 Selected Images").arg(selectedImages.count()));
455 title->setEnabled(
false);
458 Project *project = m_directory ? m_directory->project() : NULL;
463 displayActs.append(NULL);
464 displayActs.append(m_directory->supportedActions(
new ImageList(selectedImages)));
468 foreach(displayAct, displayActs) {
469 if (displayAct == NULL) {
473 menu.addAction(displayAct);
478 menu.exec(event->screenPos());
485 void MosaicSceneWidget::enableRubberBand(
bool enable) {
486 m_customRubberBandEnabled = enable;
490 MosaicSceneItem *MosaicSceneWidget::cubeToMosaic(Image *image) {
492 IString msg = tr(
"Can not find a NULL image in the mosaic");
496 return cubeToMosaic(image->displayProperties());
500 bool MosaicSceneWidget::blockSelectionChange(
bool block) {
501 bool wasBlocking = m_blockingSelectionChanged;
503 m_blockingSelectionChanged = block;
514 PvlObject MosaicSceneWidget::toPvl()
const {
515 PvlObject output(
"MosaicScene");
521 dataBuffer.open(QIODevice::ReadWrite);
522 QDataStream transformStream(&dataBuffer);
523 transformStream << getView()->transform();
526 PvlObject mosaicScenePosition(
"SceneVisiblePosition");
527 mosaicScenePosition += PvlKeyword(
"ViewTransform",
528 QString(dataBuffer.data().toHex()));
529 PvlKeyword scrollPos(
"ScrollPosition");
530 scrollPos +=
toString(getView()->horizontalScrollBar()->value());
531 scrollPos +=
toString(getView()->verticalScrollBar()->value());
532 mosaicScenePosition += scrollPos;
534 output += mosaicScenePosition;
537 foreach(tool, *m_tools) {
538 if (tool->projectPvlObjectName() !=
"") {
539 PvlObject toolObj = tool->toPvl();
540 toolObj.setName(tool->projectPvlObjectName());
545 PvlObject zOrders(
"ZOrdering");
546 foreach(MosaicSceneItem * mosaicSceneItem, *m_mosaicSceneItems) {
547 PvlKeyword zValue(
"ZValue");
548 zValue += mosaicSceneItem->image()->id();
549 zValue +=
toString(mosaicSceneItem->zValue());
557 "Cannot save a scene without a projection to a project file",
575 foreach(tool, *m_tools) {
576 if (tool->projectPvlObjectName() !=
"") {
577 if (project.
hasObject(tool->projectPvlObjectName())) {
579 project.
findObject(tool->projectPvlObjectName()));
580 tool->fromPvl(toolSettings);
587 delete m_projectImageZOrders;
588 m_projectImageZOrders = NULL;
591 for (
int zOrderIndex = 0;
594 const PvlKeyword &zOrder = zOrders[zOrderIndex];
596 (*m_projectImageZOrders)[zOrder[0]] =
toDouble(zOrder[1]);
600 if (project.
hasObject(
"SceneVisiblePosition")) {
604 delete m_projectViewTransform;
605 m_projectViewTransform =
new PvlObject(positionInfo);
612 xmlReader->pushContentHandler(
new XmlHandler(
this));
616 void MosaicSceneWidget::save(QXmlStreamWriter &stream, Project *, FileName)
const {
618 stream.writeStartElement(
"footprint2DView");
620 stream.writeStartElement(
"projection");
622 std::stringstream strStream;
623 strStream << mapping;
624 stream.writeCharacters(strStream.str().c_str());
625 stream.writeEndElement();
627 stream.writeStartElement(
"images");
628 foreach(MosaicSceneItem * mosaicSceneItem, *m_mosaicSceneItems) {
629 stream.writeStartElement(
"image");
630 stream.writeAttribute(
"id", mosaicSceneItem->image()->id());
631 stream.writeAttribute(
"zValue",
toString(mosaicSceneItem->zValue()));
632 stream.writeEndElement();
634 stream.writeEndElement();
636 stream.writeStartElement(
"viewTransform");
637 stream.writeAttribute(
"scrollBarXValue",
toString(getView()->horizontalScrollBar()->value()));
638 stream.writeAttribute(
"scrollBarYValue",
toString(getView()->verticalScrollBar()->value()));
640 dataBuffer.open(QIODevice::ReadWrite);
641 QDataStream transformStream(&dataBuffer);
642 transformStream << getView()->transform();
644 stream.writeCharacters(dataBuffer.data().toHex());
645 stream.writeEndElement();
647 foreach(MosaicTool *tool, *m_tools) {
648 QString projectPvlObjectName = tool->projectPvlObjectName();
649 if (projectPvlObjectName !=
"") {
650 PvlObject toolObj = tool->toPvl();
651 toolObj.setName(projectPvlObjectName);
653 stream.writeStartElement(
"toolData");
654 stream.writeAttribute(
"objectName", projectPvlObjectName);
655 std::stringstream strStream;
656 strStream << toolObj;
657 stream.writeCharacters(strStream.str().c_str());
658 stream.writeEndElement();
662 stream.writeEndElement();
667 QRectF MosaicSceneWidget::cubesBoundingRect()
const {
670 MosaicSceneItem * mosaicItem;
671 foreach(mosaicItem, *m_mosaicSceneItems) {
672 if (boundingRect.isEmpty())
673 boundingRect = mosaicItem->boundingRect();
675 boundingRect = boundingRect.united(mosaicItem->boundingRect());
679 boundingRect = boundingRect.united(m_outlineRect->boundingRect());
685 MosaicSceneItem *MosaicSceneWidget::cubeToMosaic(DisplayProperties *props) {
687 IString msg = tr(
"Can not find a NULL Display Properties in the mosaic");
691 return m_displayPropsToMosaicSceneItemMap[props];
698 MosaicSceneItem *mosaicSceneItem;
699 foreach(mosaicSceneItem, *m_mosaicSceneItems) {
700 if (mosaicSceneItem->image())
701 cubes.append(mosaicSceneItem->image()->fileName());
708 Directory *MosaicSceneWidget::directory()
const {
713 ImageList MosaicSceneWidget::images() {
716 MosaicSceneItem *mosaicSceneItem;
717 foreach(mosaicSceneItem, *m_mosaicSceneItems) {
718 if (mosaicSceneItem->image())
719 images.
append(mosaicSceneItem->image());
730 exportView->setText(
"&Export View...");
731 connect(exportView, SIGNAL(activated()),
this, SLOT(
exportView()));
734 saveList->setText(
"Save Entire Cube List (ordered by &view)...");
735 connect(saveList, SIGNAL(activated()),
this, SLOT(saveList()));
737 exportActs.append(exportView);
738 exportActs.append(saveList);
747 foreach(MosaicTool *tool, *m_tools) {
749 viewActs.append(toolViewActs);
762 bool allImagesInView = !images->isEmpty();
764 foreach (
Image *image, *images) {
765 allImagesInView = allImagesInView && (cubeToMosaic(image) != NULL);
768 if (allImagesInView) {
771 moveToTopAct->setData(images);
772 results.append(moveToTopAct);
776 moveUpOneAct->setData(images);
777 results.append(moveUpOneAct);
781 moveToBottomAct->setData(images);
782 results.append(moveToBottomAct);
786 moveDownOneAct->setData(images);
787 results.append(moveDownOneAct);
789 results.append(NULL);
792 zoomFitAct->setData(qVariantFromValue(images));
793 connect(zoomFitAct, SIGNAL(triggered()),
this, SLOT(fitInView()));
794 results.append(zoomFitAct);
801 QWidget * MosaicSceneWidget::getControlNetHelp(
QWidget *cnetToolContainer) {
802 QScrollArea *cnetHelpWidgetScrollArea =
new QScrollArea;
806 QVBoxLayout *cnetHelpLayout =
new QVBoxLayout;
807 cnetHelpWidget->setLayout(cnetHelpLayout);
809 QLabel *title =
new QLabel(
"<h2>Control Networks</h2>");
810 cnetHelpLayout->addWidget(title);
812 QPixmap previewPixmap;
814 if (cnetToolContainer) {
815 previewPixmap = QPixmap::grabWidget(cnetToolContainer).scaled(
816 QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
819 ToolPad tmpToolPad(
"Example Tool Pad", NULL);
820 MosaicControlNetTool tmpTool(NULL);
821 tmpTool.addTo(&tmpToolPad);
823 tmpToolPad.resize(QSize(32, 32));
825 previewPixmap = QPixmap::grabWidget(&tmpToolPad);
828 QLabel *previewWrapper =
new QLabel;
829 previewWrapper->setPixmap(previewPixmap);
830 cnetHelpLayout->addWidget(previewWrapper);
832 QLabel *overview =
new QLabel(
"The mosaic scene can display control points "
833 "in addition to the usual cube footprints. This feature is currently "
834 "offered as one of the Mosaic Scene's tools. To open a network, click "
835 "on the control network tool. It will immediately prompt you for a "
836 "control network file if one is not open. Only control points for "
837 "which the latitude and longitude can be established will be "
838 "displayed. Other control points will be ignored by qmos.<br><br>"
839 "<b>Warning: Opening large control networks is slow.</b>"
840 "<h3>Control Network Tool Options</h3>"
842 "<li>The control network tool opens control networks in two ways. "
843 "First, if you select the control network tool and no network is "
844 "open, then it will prompt you for one. Second, if there is an open "
845 "network, the buttons for the available options are displayed in the "
846 "active tool area.</li>"
847 "<li>The control network tool can toggle whether or not control "
848 "points are displayed on the screen using the 'Display' button. "
849 "Control points are always on top and colored based on their "
850 "ignored, locked and type values.</li>"
851 "<li>This tool can also change the color of your footprints based on "
852 "connectivity through control points. This is available through the "
853 "'Color Islands' button. When you press color islands, all of the "
854 "current cube coloring information is lost and re-done based on "
855 "how the control network connects the files. Each set of connected "
856 "cubes are colored differently; generally speaking, islands are not "
857 "a good thing to have in your control network.</li>"
858 "<li>This tool will color your footprints on a per-image basis if you "
859 "click color images, effectively reversing color islands.</li>"
860 "<li>The show movement option under 'Configure Movement Display' "
861 "only displays data when the control "
862 "network has adjusted values. This means that show movement only "
863 "works after you have done a jigsaw solution on the control network. "
864 "This displays arrows emanating from the apriori latitude/longitude "
865 "and pointing toward the adjusted latitude/longitude.</li>");
866 overview->setWordWrap(
true);
867 cnetHelpLayout->addWidget(overview);
869 cnetHelpWidgetScrollArea->setWidget(cnetHelpWidget);
871 return cnetHelpWidgetScrollArea;
875 QWidget * MosaicSceneWidget::getGridHelp(
QWidget *gridToolContainer) {
876 QScrollArea *gridHelpWidgetScrollArea =
new QScrollArea;
880 QVBoxLayout *gridHelpLayout =
new QVBoxLayout;
881 gridHelpWidget->setLayout(gridHelpLayout);
883 QLabel *title =
new QLabel(
"<h2>Map Grid Tool</h2>");
884 gridHelpLayout->addWidget(title);
886 QPixmap previewPixmap;
888 if (gridToolContainer) {
889 previewPixmap = QPixmap::grabWidget(gridToolContainer).scaled(
890 QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
893 ToolPad tmpToolPad(
"Example Tool Pad", NULL);
894 MosaicGridTool tmpTool(NULL);
895 tmpTool.addTo(&tmpToolPad);
897 tmpToolPad.resize(QSize(32, 32));
899 previewPixmap = QPixmap::grabWidget(&tmpToolPad);
902 QLabel *previewWrapper =
new QLabel;
903 previewWrapper->setPixmap(previewPixmap);
904 gridHelpLayout->addWidget(previewWrapper);
906 QLabel *overview =
new QLabel(
"Superimpose a map grid over the area of "
907 "displayed footprints in the 'mosaic scene.'"
910 "<li>The Map Grid Tool is activated by selecting the 'cross-hatch' "
911 "icon or typing 'g' at the keyboard."
913 "<li>The parameter options are displayed below the menubar. "
914 "Clicking the 'Grid Options' button will open the dialog. Checking "
915 "'Auto Grid' will draw a grid based on the open cubes. Hitting "
916 "'Show Grid' will display or hide the grid."
918 "<li>The map grid is defined by the loaded Map File (just as the "
919 "footprints and image data are), the opened cubes, or the grid "
922 "<li>If a Map File has not been selected, the default "
923 "Equirectangular projection will be used. The resulting grid "
924 "lines in the default 'Equi' map file will be drawn for the "
925 "full global range (latitude range = -90,90; longitude range = "
926 "0,360) at the default latitude and longitude increment values."
929 "If the grid lines are not immediately visible, try to "
930 "'zoom out' in the 'mosaic scene' window and modify the "
931 "Latitude and Longitude Increment parameters."
934 "<strong>Options:</strong>"
936 "<li>The 'Show Grid' option draws (checked) or clears (unchecked) the grid."
938 "<li>The 'Auto Grid' option draws a grid with extents and increments "
939 "computed from the set of images that are opened. The values displayed in the dialog "
940 "will reflect those used to draw the grid."
942 "<li>The expected units for each entry are displayed to the right of the "
945 "<li>The 'Extent Type' combo boxes allow you to pick the source of the "
946 "grid extents from the map file, from the open cubes <default>, or manually "
949 "<li>The 'Auto Apply' checkbox, inside the 'Grid Options' dialog box, allows you to see "
950 "real time updates in the grid when you change the parameters."
952 "<li> Depending on the projection, the grid may not behave as expected. For instance, "
953 "with a polarstereographic projection, the pole will not be included in the 'Auto "
954 "Grid' if it is not in the cube region. In this case the 'Manual' option for latitude "
955 "extents allows you to force the grid to the pole."
958 overview->setWordWrap(
true);
959 gridHelpLayout->addWidget(overview);
961 gridHelpWidgetScrollArea->setWidget(gridHelpWidget);
963 return gridHelpWidgetScrollArea;
967 QWidget * MosaicSceneWidget::getLongHelp(
QWidget *sceneContainer) {
968 QScrollArea *longHelpWidgetScrollArea =
new QScrollArea;
972 QVBoxLayout *longHelpLayout =
new QVBoxLayout;
973 longHelpWidget->setLayout(longHelpLayout);
975 QLabel *title =
new QLabel(
"<h2>Mosaic Scene</h2>");
976 longHelpLayout->addWidget(title);
978 if (sceneContainer) {
979 QPixmap previewPixmap = QPixmap::grabWidget(sceneContainer).scaled(
980 QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
982 QLabel *previewWrapper =
new QLabel;
983 previewWrapper->setPixmap(previewPixmap);
984 longHelpLayout->addWidget(previewWrapper);
987 QLabel *overview =
new QLabel(
"The mosaic scene displays cube footprints "
988 "to show where files are on a target and how they overlap. "
989 "The scene always represents projected image space and cannot show raw "
990 "or unprojected images; images will be projected on the fly."
992 "<p>Interact with the mosaic scene in different ways using "
993 "the tools. The tools are usually in a toolbar next to the scene. "
994 "The tools define what is displayed and what happens when you "
995 "click in the mosaic scene. The tools include</p>"
996 "<ul><li>Select Tool</li>"
999 "<li>Control Network Tool</li>"
1000 "<li>Show Area Tool</li>"
1001 "<li>Find Tool</li>"
1002 "<li>Grid Tool</li></ul>"
1003 "<h3>Context Menus</h3>"
1004 "Right click on anything in the mosaic scene and a context menu will pop up showing "
1005 "a list of actions or information relevant to the item you clicked on. "
1006 "<p>Note: The context menu is not associated with any selection, only the item "
1008 overview->setWordWrap(
true);
1009 longHelpLayout->addWidget(overview);
1011 longHelpWidgetScrollArea->setWidget(longHelpWidget);
1013 return longHelpWidgetScrollArea;
1018 QScrollArea *mapHelpWidgetScrollArea =
new QScrollArea;
1022 QVBoxLayout *mapHelpLayout =
new QVBoxLayout;
1023 mapHelpWidget->setLayout(mapHelpLayout);
1025 QLabel *title =
new QLabel(tr(
"<h2>Map File</h2>"));
1026 mapHelpLayout->addWidget(title);
1029 QPixmap previewPixmap = QPixmap::grabWidget(mapContainer).scaled(
1030 QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
1032 QLabel *previewWrapper =
new QLabel;
1033 previewWrapper->setPixmap(previewPixmap);
1034 mapHelpLayout->addWidget(previewWrapper);
1037 QLabel *overviewMapIcon =
new QLabel;
1039 overviewMapIcon->setPixmap(
1040 QIcon(FileName(
"$base/icons/ographic.png").expanded()).pixmap(32, 32));
1041 mapHelpLayout->addWidget(overviewMapIcon);
1043 QLabel *defaultMapFile =
new QLabel(tr(
1044 "<h3>Default Map File</h3>"
1045 "The mosaic scene's projection is defined by a \"Map File\" that consists of keywords "
1046 "that describe the map layout to be used. If a cube or a list of cubes are "
1047 "loaded before a map file is selected, the default map file defines the "
1048 "equirectangular projection, planetocentric latitude, positive longitude east, 360 "
1049 "longitude domain, latitude range=90S-90N, longitude range=0-360E. The radius will "
1050 "default to the IAU standards (ellipsoid or sphere) for the specific planetary body "
1051 "defined for the \"TargetName\" in the labels of the image cube(s)."));
1053 defaultMapFile->setWordWrap(
true);
1054 mapHelpLayout->addWidget(defaultMapFile);
1056 QLabel *userDefinedMapFileOverview =
new QLabel(tr(
1057 "<h3>User Defined Map File</h3>"
1058 "You can load an existing \"Map File\" before loading images into %1 by selecting the "
1059 "\"View/Edit/Load Map File\" option. You will be greeted with a dialog box that will "
1060 "enable you to select an existing map file by clicking on \"Load Map File.\" Once "
1061 "the map file is selected, the contents is displayed in the dialog box where "
1062 "modifications can be made as well. If the modified map file is to be used later, "
1063 "save the map file by clicking on \"Save Map File\" button.")
1064 .arg(QCoreApplication::applicationName()));
1066 userDefinedMapFileOverview->setWordWrap(
true);
1067 mapHelpLayout->addWidget(userDefinedMapFileOverview);
1069 QLabel *userDefinedMapFileQuickLoad =
new QLabel(tr(
1070 "The \"Quick Load Map\" option (lightning icon) allows you to efficiently select a "
1071 "prepared \"Map File\" without an immediate need to view or edit the contents."));
1073 userDefinedMapFileQuickLoad->setWordWrap(
true);
1074 mapHelpLayout->addWidget(userDefinedMapFileQuickLoad);
1076 QLabel *userDefinedMapFileAnyTime =
new QLabel(tr(
1077 "At any point, you have access to the \"View/Edit\" functionality to modify or load a "
1078 "different map file."));
1080 userDefinedMapFileAnyTime->setWordWrap(
true);
1081 mapHelpLayout->addWidget(userDefinedMapFileAnyTime);
1083 QString mapProjWorkshopUrl(
"http://isis.astrogeology.usgs.gov/IsisWorkshop/"
1084 "index.php/Learning_About_Map_Projections");
1085 QLabel *preparingMapFile =
new QLabel(tr(
1086 "<h3>Preparing a Map File</h3>"
1087 "Please refer to Isis applications such as 'maptemplate' or 'mosrange' for more details "
1088 "on creating a custom map file that defines the desired projection, latitude "
1089 "system, and longitude direction and domain. This program will use the latitude range "
1090 "and longitude range if they exist in the loaded file. A choice of map templates that can be used as "
1091 "a starting point for supported map projections can be found in $base/templates/maps (refer "
1092 "to maptemplate or mosrange for more details and information on the required parameters "
1093 "for a projection). Note that through the file name selection box, $base will need "
1094 "to be replaced with the specific Isis3 system path. The website: "
1095 "<a href='%1'>%1</a> also provides useful information about map projections.")
1096 .arg(mapProjWorkshopUrl));
1098 preparingMapFile->setOpenExternalLinks(
true);
1099 preparingMapFile->setWordWrap(
true);
1100 mapHelpLayout->addWidget(preparingMapFile);
1102 QLabel *mapFileDisplayResults =
new QLabel(tr(
1103 "<h3>Display Results with the Map File</h3>"
1104 "The footprints and image data that are displayed in the mosaic scene are defined by the "
1105 "loaded \"Map File\" regardless of whether the opened cubes are Level1 (raw "
1106 "camera space) or Level2 (map projected). The associated footprint polygons for "
1107 "Level2 cubes will be re-mapped as needed based on the loaded map file."));
1109 mapFileDisplayResults->setWordWrap(
true);
1110 mapHelpLayout->addWidget(mapFileDisplayResults);
1112 QLabel *editingMapFileOverview =
new QLabel(tr(
1113 "<h3>Editing a Map File</h3>"
1114 "Editing a map file is possible through the dialog box displayed by clicking on the "
1115 "'View/Edit/Load Map File' icon/button. The edits are "
1116 "applied to the current session and will be included with a 'Saved Project' (refer to "
1117 "the help under File-Save Project or Save Project as)."));
1119 editingMapFileOverview->setWordWrap(
true);
1120 mapHelpLayout->addWidget(editingMapFileOverview);
1122 QLabel *saveMapFileToDiskBullet =
new QLabel(tr(
1125 "To save or write the changes to a map file on disk, choose 'Save Map File' button. "
1126 "Map files can be saved to an existing map file (overwrites) or to a new file. This "
1127 "program always saves <strong>exactly</strong> what you see, the text, in the dialog "
1132 saveMapFileToDiskBullet->setWordWrap(
true);
1133 mapHelpLayout->addWidget(saveMapFileToDiskBullet);
1135 QLabel *mapFileValidityBullet =
new QLabel(tr(
1138 "As you modify the contents of a loaded map file in the dialog box, the entry is "
1139 "verified as you type with a bold black indicator message displaying whether the "
1140 "text is valid or is not valid. If you want to see the actual error messages, "
1141 "select the 'Show Errors' box and the errors will be displayed in red font "
1142 "along with the black bolded message. The errors will update "
1147 mapFileValidityBullet->setWordWrap(
true);
1148 mapHelpLayout->addWidget(mapFileValidityBullet);
1150 QLabel *mapFileCommentsBullet =
new QLabel(tr(
1153 "Map files may contain 'commented-out' lines (text that starts with \"#\" at "
1154 "the beginning of the line). These are referred to as \"unnecessary\""
1155 "or \"unknown\" keywords, they are simply ignored. If these lines are to be saved to "
1156 "the output map file on disk, click 'Save Map File' BEFORE clicking 'Ok' or 'Apply.' "
1157 "The comments are removed from the dialog box when you hit 'Ok' or 'Apply,' if they "
1158 "are just above \"End_Group\" or follow \"End_Group\" or \"End\".<br/><br/>"
1160 "If you want these comments retained, make sure they are immediately above a valid "
1161 "keyword inside of \"Group = Mapping.\" Note that any lines (commented or not) will "
1162 "not be saved if they are placed outside of \"Group = Mapping\" and \"End_Group\"."
1166 mapFileCommentsBullet->setWordWrap(
true);
1167 mapHelpLayout->addWidget(mapFileCommentsBullet);
1169 mapHelpWidgetScrollArea->setWidget(mapHelpWidget);
1171 return mapHelpWidgetScrollArea;
1175 QWidget * MosaicSceneWidget::getPreviewHelp(
QWidget *worldViewContainer) {
1176 QScrollArea *previewHelpWidgetScrollArea =
new QScrollArea;
1180 QVBoxLayout *previewHelpLayout =
new QVBoxLayout;
1181 previewHelpWidget->setLayout(previewHelpLayout);
1183 QLabel *title =
new QLabel(
"<h2>Mosaic World View</h2>");
1184 previewHelpLayout->addWidget(title);
1186 if (worldViewContainer) {
1187 QPixmap previewPixmap = QPixmap::grabWidget(worldViewContainer).scaled(
1188 QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
1190 QLabel *previewWrapper =
new QLabel;
1191 previewWrapper->setPixmap(previewPixmap);
1192 previewHelpLayout->addWidget(previewWrapper);
1195 QLabel *overview =
new QLabel(
"The mosaic world view displays cube "
1196 "footprints to show you where your files are on a target and their "
1197 "general arrangement. The world view does not have tools like "
1198 "mosaic scenes, but otherwise they are very similar.");
1199 overview->setWordWrap(
true);
1200 previewHelpLayout->addWidget(overview);
1202 previewHelpWidgetScrollArea->setWidget(previewHelpWidget);
1204 return previewHelpWidgetScrollArea;
1208 MosaicSceneItem *MosaicSceneWidget::addImage(Image *image) {
1213 MosaicSceneItem *mosItem = NULL;
1216 if (!cubeToMosaic(image)) {
1217 mosItem =
new MosaicSceneItem(image,
this);
1224 if (m_projectImageZOrders && m_projectImageZOrders->contains(image->id())) {
1225 double zOrder = m_projectImageZOrders->value(image->id());
1226 m_projectImageZOrders->remove(image->id());
1228 foreach (MosaicSceneItem *mosaicItem, *m_mosaicSceneItems) {
1229 if (mosaicItem->zValue() == zOrder) {
1230 mosaicItem->setZValue(maximumZ() + 1);
1231 m_currentMaximumFootprintZ = maximumZ() + 1;
1235 m_currentMaximumFootprintZ = qMax(zOrder, maximumZ());
1236 mosItem->setZValue(zOrder);
1239 mosItem->setZValue(maximumZ() + 1);
1240 m_currentMaximumFootprintZ = maximumZ() + 1;
1243 getScene()->addItem(mosItem);
1244 m_mosaicSceneItems->append(mosItem);
1245 m_displayPropsToMosaicSceneItemMap[image->displayProperties()] = mosItem;
1247 connect(mosItem, SIGNAL(destroyed(
QObject *)),
1248 this, SLOT(removeMosItem(
QObject *)));
1250 DisplayProperties *prop = image->displayProperties();
1251 connect(prop, SIGNAL(moveDownOne()),
1252 this, SLOT(moveDownOne()));
1255 connect(prop, SIGNAL(moveUpOne()),
1256 this, SLOT(moveUpOne()));
1259 connect(prop, SIGNAL(zoomFit()),
1260 this, SLOT(fitInView()));
1267 double MosaicSceneWidget::maximumZ() {
1268 return m_currentMaximumFootprintZ;
1272 double MosaicSceneWidget::minimumZ() {
1273 return m_currentMinimumFootprintZ;
1276 void MosaicSceneWidget::recalcSceneRect() {
1278 double minX, minY, maxX, maxY;
1281 QRectF projRect(minX, -maxY, maxX - minX, maxY - minY);
1282 QRectF cubesBounding = cubesBoundingRect();
1284 QRectF bounding = projRect.united(cubesBounding);
1286 if (m_outlineRect && m_outlineRect->isVisible())
1287 bounding = bounding.united(m_outlineRect->boundingRect());
1289 getView()->setSceneRect(bounding);
1293 void MosaicSceneWidget::addImages(ImageList images) {
1294 if (m_userToolControl)
1295 m_progress->
setText(
"Loading primary scene");
1297 m_progress->
setText(
"Loading secondary scene");
1299 m_progress->setRange(0, images.size() - 1);
1300 m_progress->setValue(0);
1301 m_progress->setVisible(
true);
1303 foreach(Image *image, images) {
1307 catch(IException &e) {
1311 m_progress->setValue(m_progress->value() + 1);
1316 if (m_projectViewTransform) {
1317 PvlObject &positionInfo = *m_projectViewTransform;
1318 QByteArray hexValues(positionInfo[
"ViewTransform"][0].toAscii());
1319 QDataStream transformStream(QByteArray::fromHex(hexValues));
1321 QTransform viewTransform;
1322 transformStream >> viewTransform;
1323 getView()->setTransform(viewTransform);
1325 QPoint projectScrollPos(
toInt(positionInfo[
"ScrollPosition"][0]),
1326 toInt(positionInfo[
"ScrollPosition"][1]));
1328 getView()->horizontalScrollBar()->setValue(projectScrollPos.x());
1329 getView()->verticalScrollBar()->setValue(projectScrollPos.y());
1335 if (!m_projectImageZOrders || m_projectImageZOrders->isEmpty()) {
1336 delete m_projectViewTransform;
1337 m_projectViewTransform = NULL;
1340 m_progress->setVisible(
false);
1341 emit cubesChanged();
1350 QFileDialog::getSaveFileName((
QWidget *)parent(),
1351 "Choose output file",
1352 QDir::currentPath() +
"/untitled.png",
1353 QString(
"Images (*.png *.jpg *.tif)"));
1354 if (output.isEmpty())
return;
1357 if (QFileInfo(output).suffix().isEmpty()) {
1358 output = output +
".png";
1361 QString format = QFileInfo(output).suffix();
1362 QPixmap pm = QPixmap::grabWidget(getScene()->views().last());
1364 std::string formatString = format.toStdString();
1365 if (!pm.save(output, formatString.c_str())) {
1366 QMessageBox::information(
this,
"Error",
1367 "Unable to save [" + output +
"]");
1372 void MosaicSceneWidget::saveList() {
1374 QFileDialog::getSaveFileName((
QWidget *)parent(),
1375 "Choose output file",
1376 QDir::currentPath() +
"/files.lis",
1377 QString(
"List File (*.lis);;Text File (*.txt);;All Files (*.*)"));
1378 if (output.isEmpty())
return;
1380 TextFile file(output,
"overwrite");
1383 qSort(sorted.begin(), sorted.end(), zOrderGreaterThan);
1386 foreach(sceneItem, sorted) {
1387 file.PutLine( sceneItem->image()->fileName() );
1392 void MosaicSceneWidget::removeMosItem(
QObject *mosItem) {
1393 MosaicSceneItem *castedMosItem = (MosaicSceneItem *) mosItem;
1394 m_mosaicSceneItems->removeAll(castedMosItem);
1395 m_displayPropsToMosaicSceneItemMap.remove(
1396 m_displayPropsToMosaicSceneItemMap.key(castedMosItem));
1398 emit cubesChanged();
1407 QRectF sceneRect = cubesBoundingRect();
1409 if (sceneRect.isEmpty())
1412 double xPadding = sceneRect.width() * 0.10;
1413 double yPadding = sceneRect.height() * 0.10;
1415 sceneRect.adjust(-xPadding, -yPadding, xPadding, yPadding);
1416 getView()->fitInView(sceneRect, Qt::KeepAspectRatio);
1420 void MosaicSceneWidget::setCubesSelectable(
bool selectable) {
1421 if (m_cubesSelectable != selectable) {
1422 m_cubesSelectable = selectable;
1425 foreach(mosaicSceneItem, *m_mosaicSceneItems) {
1426 mosaicSceneItem->scenePropertiesChanged();
1438 configDialog.exec();
1442 void MosaicSceneWidget::quickConfigProjectionParameters() {
1444 configDialog.setQuickConfig(
true);
1445 configDialog.exec();
1449 void MosaicSceneWidget::sendVisibleRectChanged() {
1450 QPointF topLeft = getView()->mapToScene(0, 0);
1451 QPointF bottomRight = getView()->mapToScene(
1452 (
int)getView()->width(),
1453 (
int)getView()->height());
1455 QRectF visibleRect(topLeft, bottomRight);
1456 emit visibleRectChanged(visibleRect);
1460 bool MosaicSceneWidget::eventFilter(
QObject *obj, QEvent *event) {
1461 bool stopProcessingEvent =
true;
1463 switch(event->type()) {
1464 case QMouseEvent::GraphicsSceneMousePress: {
1465 if (m_customRubberBandEnabled) {
1467 if (!m_customRubberBand) {
1468 m_customRubberBand =
new QRubberBand(QRubberBand::Rectangle,
1472 if (!m_rubberBandOrigin) {
1473 m_rubberBandOrigin =
new QPoint;
1476 *m_rubberBandOrigin = getView()->mapFromScene(
1477 ((QGraphicsSceneMouseEvent *)event)->scenePos());
1478 m_customRubberBand->setGeometry(QRect(*m_rubberBandOrigin, QSize()));
1479 m_customRubberBand->show();
1482 emit mouseButtonPress(
1483 ((QGraphicsSceneMouseEvent *)event)->scenePos(),
1484 ((QGraphicsSceneMouseEvent *)event)->button());
1486 stopProcessingEvent =
false;
1490 case QMouseEvent::GraphicsSceneMouseRelease: {
1491 bool signalEmitted =
false;
1492 if (m_customRubberBandEnabled && m_rubberBandOrigin &&
1493 m_customRubberBand) {
1494 if (m_customRubberBand->geometry().width() +
1495 m_customRubberBand->geometry().height() > 10) {
1496 emit rubberBandComplete(
1497 getView()->mapToScene(
1498 m_customRubberBand->geometry()).boundingRect(),
1499 ((QGraphicsSceneMouseEvent *)event)->button());
1500 signalEmitted =
true;
1503 delete m_rubberBandOrigin;
1504 m_rubberBandOrigin = NULL;
1506 delete m_customRubberBand;
1507 m_customRubberBand = NULL;
1510 if (!signalEmitted) {
1511 stopProcessingEvent =
false;
1512 emit mouseButtonRelease(
1513 ((QGraphicsSceneMouseEvent *)event)->scenePos(),
1514 ((QGraphicsSceneMouseEvent *)event)->button());
1519 case QMouseEvent::GraphicsSceneMouseDoubleClick:
1520 emit mouseDoubleClick(
1521 ((QGraphicsSceneMouseEvent *)event)->scenePos());
1522 stopProcessingEvent =
false;
1525 case QMouseEvent::GraphicsSceneMouseMove:
1526 if (m_customRubberBandEnabled && m_rubberBandOrigin &&
1527 m_customRubberBand) {
1528 QPointF scenePos = ((QGraphicsSceneMouseEvent *)event)->scenePos();
1529 QPoint screenPos = getView()->mapFromScene(scenePos);
1531 QRect rubberBandRect =
1532 QRect(*m_rubberBandOrigin, screenPos).normalized();
1534 m_customRubberBand->setGeometry(rubberBandRect);
1537 stopProcessingEvent =
false;
1541 ((QGraphicsSceneMouseEvent *)event)->scenePos());
1544 case QEvent::GraphicsSceneWheel:
1546 ((QGraphicsSceneWheelEvent *)event)->scenePos(),
1547 ((QGraphicsSceneWheelEvent *)event)->delta());
1549 stopProcessingEvent =
true;
1552 case QMouseEvent::Enter:
1554 stopProcessingEvent =
false;
1557 case QMouseEvent::Leave:
1559 stopProcessingEvent =
false;
1562 case QEvent::GraphicsSceneHelp: {
1564 bool toolTipFound =
false;
1567 foreach(sceneItem, getScene()->items()) {
1568 if (!toolTipFound) {
1569 if (sceneItem->contains(
1570 ((QGraphicsSceneHelpEvent*)event)->scenePos()) &&
1571 sceneItem->toolTip().size() > 0) {
1572 setToolTip(sceneItem->toolTip());
1573 toolTipFound =
true;
1579 stopProcessingEvent =
true;
1581 ((QGraphicsSceneHelpEvent*)event)->screenPos(),
1588 stopProcessingEvent =
false;
1592 return stopProcessingEvent;
1603 if (m_mosaicSceneItems->size() == 0)
1606 if (m_userToolControl)
1607 m_progress->
setText(
"Reprojecting primary scene");
1609 m_progress->
setText(
"Reprojecting secondary scene");
1612 int reprojectsPerUpdate = qMax(1, m_mosaicSceneItems->size() / 20);
1614 m_progress->setRange(0,
1615 (m_mosaicSceneItems->size() - 1) / reprojectsPerUpdate + 1);
1616 m_progress->setValue(0);
1617 m_progress->setVisible(
true);
1621 int progressCountdown = reprojectsPerUpdate;
1622 foreach(mosaicSceneItem, *m_mosaicSceneItems) {
1629 if (mosaicSceneItem->image())
1632 msg +=
"] is being removed due to not being able to project onto the scene";
1636 mosaicSceneItem->image()->deleteLater();
1639 progressCountdown --;
1640 if (progressCountdown == 0) {
1641 m_progress->setValue(m_progress->value() + 1);
1642 progressCountdown = reprojectsPerUpdate;
1647 m_progress->setValue(m_progress->maximum());
1651 m_progress->setVisible(
false);
1655 void MosaicSceneWidget::moveDownOne() {
1659 moveDownOne(cubeToMosaic(props));
1664 void MosaicSceneWidget::moveToBottom() {
1665 DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1673 void MosaicSceneWidget::moveUpOne() {
1674 DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1677 moveUpOne(cubeToMosaic(props));
1682 void MosaicSceneWidget::moveToTop() {
1683 DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1693 double MosaicSceneWidget::moveDownOne(MosaicSceneItem *item) {
1694 MosaicSceneItem *nextDown =
getNextItem(item,
false);
1695 double originalZ = item->zValue();
1698 double newZValue = nextDown->zValue() - 1;
1699 moveZ(item, newZValue,
true);
1708 double MosaicSceneWidget::moveDownOne(Image *image) {
1709 return moveDownOne(cubeToMosaic(image));
1715 QList<double> MosaicSceneWidget::moveDownOne(ImageList *images) {
1718 foreach (Image *image, *images) {
1719 results.append(moveDownOne(image));
1731 double originalZ = item->zValue();
1732 double minZ = minimumZ();
1734 if (originalZ != minZ) {
1736 int newZValue = qRound(minZ - 1);
1737 item->setZValue(newZValue);
1740 m_currentMinimumFootprintZ--;
1751 double MosaicSceneWidget::moveToBottom(
Image *image) {
1763 foreach (
Image *image, *images) {
1776 double originalZ = item->zValue();
1777 double maxZ = maximumZ();
1779 if (originalZ != maxZ) {
1781 int newZValue = qRound(maxZ + 1);
1782 item->setZValue(newZValue);
1785 m_currentMaximumFootprintZ++;
1806 double MosaicSceneWidget::moveToTop(
Image *image) {
1820 foreach (
Image *image, *images) {
1834 double originalZ = item->zValue();
1837 double newZValue = nextUp->zValue() + 1;
1838 moveZ(item, newZValue,
true);
1847 double MosaicSceneWidget::moveUpOne(Image *image) {
1848 return moveUpOne(cubeToMosaic(image));
1854 QList<double> MosaicSceneWidget::moveUpOne(ImageList *images) {
1857 foreach (Image *image, *images) {
1858 results.append(moveUpOne(image));
1881 bool newZValueMightExist) {
1882 double originalZ = sceneItem->zValue();
1884 if (newZValueMightExist) {
1886 m_currentMinimumFootprintZ = 0.0;
1887 m_currentMaximumFootprintZ = 0.0;
1890 double otherItemOrigZ = otherItem->zValue();
1891 double otherItemNewZ = otherItemOrigZ;
1894 if (originalZ > newZ && otherItemOrigZ >= newZ && otherItemOrigZ < originalZ) {
1895 otherItemNewZ = otherItemOrigZ + 1;
1898 else if (originalZ < newZ && otherItemOrigZ <= newZ && otherItemOrigZ > originalZ) {
1899 otherItemNewZ = otherItemOrigZ - 1;
1902 m_currentMinimumFootprintZ = qMin(m_currentMinimumFootprintZ, otherItemNewZ);
1903 m_currentMaximumFootprintZ = qMax(m_currentMaximumFootprintZ, otherItemNewZ);
1904 otherItem->setZValue(otherItemNewZ);
1908 sceneItem->setZValue(newZ);
1910 if (!newZValueMightExist) {
1912 if (originalZ == maximumZ() && newZ < originalZ) {
1913 m_currentMaximumFootprintZ--;
1915 else if (originalZ == minimumZ() && newZ > originalZ) {
1916 m_currentMinimumFootprintZ++;
1925 bool newZValueMightExist) {
1926 return moveZ(cubeToMosaic(image), newZ, newZValueMightExist);
1930 void MosaicSceneWidget::fitInView() {
1931 if (m_userToolControl) {
1934 DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1937 MosaicSceneItem *item = cubeToMosaic(props);
1938 boundingBox = item->boundingRect();
1944 ImageList *images = action->data().value<ImageList *>();
1946 foreach (Image *image, *images) {
1947 ASSERT(cubeToMosaic(image));
1948 boundingBox = boundingBox.united(cubeToMosaic(image)->boundingRect());
1953 if (!boundingBox.isNull()) {
1954 double xPadding = boundingBox.width() * 0.10;
1955 double yPadding = boundingBox.height() * 0.10;
1957 boundingBox.setLeft(boundingBox.left() - xPadding);
1958 boundingBox.setRight(boundingBox.right() + xPadding);
1960 boundingBox.setTop(boundingBox.top() - yPadding);
1961 boundingBox.setBottom(boundingBox.bottom() + yPadding);
1963 getView()->fitInView(boundingBox, Qt::KeepAspectRatio);
1964 getView()->centerOn(boundingBox.center());
1970 void MosaicSceneWidget::onSelectionChanged() {
1971 if (!m_blockingSelectionChanged) {
1972 if (!m_queuedSelectionChanged) {
1973 emit queueSelectionChanged();
1974 m_queuedSelectionChanged =
true;
1977 m_shouldRequeueSelectionChanged =
true;
1983 void MosaicSceneWidget::onQueuedSelectionChanged() {
1984 m_queuedSelectionChanged =
false;
1986 if (m_shouldRequeueSelectionChanged) {
1987 m_shouldRequeueSelectionChanged =
false;
1988 onSelectionChanged();
1991 foreach(MosaicSceneItem *mosaicSceneItem, *m_mosaicSceneItems) {
1992 mosaicSceneItem->updateSelection(
true);
2003 foreach(mosaicSceneItem, *m_mosaicSceneItems) {
2004 if (mosaicSceneItem != item &&
2005 mosaicSceneItem->boundingRect().intersects(item->boundingRect())) {
2007 if ( (up && mosaicSceneItem->zValue() > item->zValue()) ||
2008 (!up && mosaicSceneItem->zValue() < item->zValue())) {
2011 if (!nextZValueItem) {
2012 nextZValueItem = mosaicSceneItem;
2017 if ((up && mosaicSceneItem->zValue() < nextZValueItem->zValue()) ||
2018 (!up && mosaicSceneItem->zValue() > nextZValueItem->zValue())) {
2019 nextZValueItem = mosaicSceneItem;
2026 return nextZValueItem;
2032 return first->zValue() > second->zValue();
2036 MosaicSceneWidget::XmlHandler::XmlHandler(MosaicSceneWidget *scene) {
2038 m_scrollBarXValue = -1;
2039 m_scrollBarYValue = -1;
2040 m_imagesToAdd = NULL;
2042 m_imagesToAdd =
new ImageList;
2046 MosaicSceneWidget::XmlHandler::~XmlHandler() {
2047 delete m_imagesToAdd;
2048 m_imagesToAdd = NULL;
2052 bool MosaicSceneWidget::XmlHandler::startElement(
const QString &namespaceURI,
2053 const QString &localName,
const QString &qName,
const QXmlAttributes &atts) {
2054 bool result = XmlStackedHandler::startElement(namespaceURI, localName, qName, atts);
2056 m_characterData =
"";
2059 if (localName ==
"image" && m_scene->m_directory) {
2060 QString
id = atts.value(
"id");
2061 double zValue = atts.value(
"zValue").toDouble();
2062 Image *image = m_scene->m_directory->project()->image(
id);
2064 m_imagesToAdd->append(image);
2065 m_imageZValues.append(zValue);
2069 else if (localName ==
"viewTransform") {
2070 m_scrollBarXValue = atts.value(
"scrollBarXValue").toInt();
2071 m_scrollBarYValue = atts.value(
"scrollBarYValue").toInt();
2079 bool MosaicSceneWidget::XmlHandler::characters(
const QString &ch) {
2080 bool result = XmlStackedHandler::characters(ch);
2083 m_characterData += ch;
2090 bool MosaicSceneWidget::XmlHandler::endElement(
const QString &namespaceURI,
2091 const QString &localName,
const QString &qName) {
2092 bool result = XmlStackedHandler::endElement(namespaceURI, localName, qName);
2095 if (localName ==
"projection") {
2096 std::stringstream strStream(m_characterData.toStdString());
2097 PvlGroup mappingGroup;
2098 strStream >> mappingGroup;
2099 m_scene->setProjection(mappingGroup);
2101 else if (localName ==
"viewTransform") {
2102 QByteArray hexValues(m_characterData.toAscii());
2103 QDataStream transformStream(QByteArray::fromHex(hexValues));
2105 QTransform viewTransform;
2106 transformStream >> viewTransform;
2107 m_scene->getView()->show();
2108 QCoreApplication::processEvents();
2109 m_scene->getView()->setTransform(viewTransform);
2110 m_scene->getView()->horizontalScrollBar()->setValue(m_scrollBarXValue);
2111 m_scene->getView()->verticalScrollBar()->setValue(m_scrollBarYValue);
2113 else if (localName ==
"toolData") {
2114 PvlObject toolSettings;
2115 std::stringstream strStream(m_characterData.toStdString());
2116 strStream >> toolSettings;
2118 foreach (MosaicTool *tool, *m_scene->m_tools) {
2119 if (tool->projectPvlObjectName() == toolSettings.name()) {
2120 tool->fromPvl(toolSettings);
2124 else if (localName ==
"images" && m_imagesToAdd->count()) {
2125 ASSERT(m_imagesToAdd->count() == m_imageZValues.count());
2126 m_scene->addImages(*m_imagesToAdd);
2128 for (
int i = 0; i < m_imageZValues.count(); i++) {
2129 m_scene->cubeToMosaic(m_imagesToAdd->at(i))->setZValue(m_imageZValues[i]);
2130 m_scene->m_currentMinimumFootprintZ = qMin(m_scene->m_currentMinimumFootprintZ,
2132 m_scene->m_currentMaximumFootprintZ = qMax(m_scene->m_currentMaximumFootprintZ,
2138 m_characterData =
"";