3 #include "MosaicSceneWidget.h"
8 #include <QGraphicsSceneContextMenuEvent>
10 #include <QHBoxLayout>
12 #include <QMessageBox>
14 #include <QRubberBand>
18 #include <QToolButton>
26 #include "Directory.h"
29 #include "GraphicsView.h"
31 #include "ImageList.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"
51 #include "Projection.h"
52 #include "ProjectionConfigDialog.h"
53 #include "ProjectionFactory.h"
54 #include "PvlObject.h"
60 #include "XmlStackedHandlerReader.h"
67 bool internalizeToolBarsAndProgress,
Directory *directory,
69 m_projectImageZOrders = NULL;
70 m_projectViewTransform = NULL;
71 m_directory = directory;
89 m_quickMapAction = NULL;
91 m_cubesSelectable =
true;
92 m_customRubberBandEnabled =
false;
93 m_customRubberBand = NULL;
94 m_rubberBandOrigin = NULL;
96 m_blockingSelectionChanged =
false;
97 m_queuedSelectionChanged =
false;
98 m_shouldRequeueSelectionChanged =
false;
100 m_userToolControl =
false;
101 m_ownProjection =
false;
104 m_progress->setVisible(
false);
106 QGridLayout * sceneLayout =
new QGridLayout;
107 sceneLayout->setContentsMargins(0, 0, 0, 0);
108 setLayout(sceneLayout);
111 if (!status && internalizeToolBarsAndProgress)
112 status =
new QStatusBar;
120 m_tools->append(cnetTool);
124 connect(cnetTool, SIGNAL(modifyControlPoint(
ControlPoint *)),
127 connect(cnetTool, SIGNAL(deleteControlPoint(
ControlPoint *)),
130 connect(cnetTool, SIGNAL(createControlPoint(
double,
double)),
131 this, SIGNAL(createControlPoint(
double,
double)));
134 connect(
this, SIGNAL(cnetModified()), cnetTool, SLOT(rebuildPointGraphics()));
142 m_tools->at(0)->activate(
true);
146 if (internalizeToolBarsAndProgress) {
161 QHBoxLayout *horizontalToolBarsLayout =
new QHBoxLayout;
163 m_permToolbar =
new QToolBar(
"Standard Tools");
164 m_permToolbar->setWhatsThis(
"This area contains options that are always present in the "
166 horizontalToolBarsLayout->addWidget(m_permToolbar);
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);
174 sceneLayout->addLayout(horizontalToolBarsLayout, 0, 0, 1, 2);
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);
184 QHBoxLayout *horizontalStatusLayout =
new QHBoxLayout;
185 horizontalStatusLayout->addWidget(m_progress);
186 horizontalStatusLayout->addStretch();
187 horizontalStatusLayout->addWidget(status);
189 sceneLayout->addLayout(horizontalStatusLayout, 2, 0, 1, 2);
191 addToPermanent(m_permToolbar);
192 m_permToolbar->addSeparator();
194 addTo(m_activeToolbar);
201 m_userToolControl =
true;
203 setWhatsThis(
"This is the mosaic scene. The opened cubes will be "
204 "shown here. You can fully interact with the files shown here.");
206 getView()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
207 getView()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
209 getView()->enableResizeZooming(
false);
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()));
224 getView()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
225 getView()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
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.");
235 m_currentMinimumFootprintZ = 0;
236 m_currentMaximumFootprintZ = 0;
238 connect(getScene(), SIGNAL(selectionChanged()),
239 this, SLOT(onSelectionChanged()));
242 connect(
this, SIGNAL(queueSelectionChanged()),
243 this, SLOT(onQueuedSelectionChanged()), Qt::QueuedConnection);
246 MosaicSceneWidget::~MosaicSceneWidget() {
247 m_outlineRect = NULL;
264 delete m_projectImageZOrders;
265 m_projectImageZOrders = NULL;
267 delete m_projectViewTransform;
268 m_projectViewTransform = NULL;
276 if (!mapping.hasKeyword(
"EquatorialRadius")) {
278 tmp.findGroup(
"Mapping") += radii[
"EquatorialRadius"];
279 tmp.findGroup(
"Mapping") += radii[
"PolarRadius"];
283 m_ownProjection =
true;
295 QString projName = projectionKeyword[0];
296 m_mapButton->setText(tr(
"View/Edit %1 Projection").arg(projName));
305 if (old && m_ownProjection) {
310 m_ownProjection =
false;
315 void MosaicSceneWidget::setOutlineRect(QRectF outline) {
316 if (outline.united(getView()->sceneRect()) != getView()->sceneRect())
319 if (!m_outlineRect) {
320 m_outlineRect = getScene()->addRect(outline,
323 m_outlineRect->setZValue(DBL_MAX);
326 m_outlineRect->setRect(outline);
329 if (!m_userToolControl)
334 PvlGroup MosaicSceneWidget::createInitialProjection(
336 Projection *proj = NULL;
337 Cube *cube = image->cube();
338 Pvl *label = cube->label();
342 return proj->Mapping();
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");
358 Camera * cam = cube->camera();
362 mappingGrp += PvlKeyword(
"TargetName", cam->target()->name());
363 mappingGrp += PvlKeyword(
"EquatorialRadius",
toString(radii[0].meters()),
365 mappingGrp += PvlKeyword(
"PolarRadius",
toString(radii[2].meters()),
369 catch (IException &) {
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);
394 PvlKeyword projectionKeyword =
396 QString projName = projectionKeyword[0];
397 m_mapButton->setText(projName);
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()));
408 perm->addWidget(m_mapButton);
409 perm->addAction(m_quickMapAction);
413 void MosaicSceneWidget::addTo(
QToolBar *toolbar) {
415 foreach(tool, *m_tools) {
416 tool->addTo(toolbar);
421 void MosaicSceneWidget::addTo(
QMenu *menu) {
423 foreach(tool, *m_tools) {
429 void MosaicSceneWidget::addTo(ToolPad *toolPad) {
431 foreach(tool, *m_tools) {
432 tool->addTo(toolPad);
444 bool handled =
false;
448 foreach (
QGraphicsItem *graphicsItem, selectedGraphicsItems) {
451 if (!sceneImageItem) {
452 sceneImageItem =
dynamic_cast<MosaicSceneItem *
>(graphicsItem->parentItem());
455 if (sceneImageItem && sceneImageItem->image()) {
456 selectedImageItems.append(sceneImageItem);
461 if (selectedImageItems.count()) {
465 title->setEnabled(
false);
473 displayActs.append(NULL);
478 foreach(displayAct, displayActs) {
479 if (displayAct == NULL) {
483 menu.addAction(displayAct);
488 menu.exec(event->screenPos());
496 void MosaicSceneWidget::enableRubberBand(
bool enable) {
497 m_customRubberBandEnabled = enable;
501 MosaicSceneItem *MosaicSceneWidget::cubeToMosaic(Image *image) {
503 QString msg = tr(
"Can not find a NULL image in the mosaic");
507 return cubeToMosaic(image->displayProperties());
511 bool MosaicSceneWidget::blockSelectionChange(
bool block) {
512 bool wasBlocking = m_blockingSelectionChanged;
514 m_blockingSelectionChanged = block;
525 PvlObject MosaicSceneWidget::toPvl()
const {
526 PvlObject output(
"MosaicScene");
532 dataBuffer.open(QIODevice::ReadWrite);
533 QDataStream transformStream(&dataBuffer);
534 transformStream << getView()->transform();
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;
545 output += mosaicScenePosition;
548 foreach(tool, *m_tools) {
549 if (tool->projectPvlObjectName() !=
"") {
550 PvlObject toolObj = tool->toPvl();
551 toolObj.setName(tool->projectPvlObjectName());
556 PvlObject zOrders(
"ZOrdering");
557 foreach(MosaicSceneItem * mosaicSceneItem, *m_mosaicSceneItems) {
558 PvlKeyword zValue(
"ZValue");
559 zValue += mosaicSceneItem->image()->id();
560 zValue +=
toString(mosaicSceneItem->zValue());
568 "Cannot save a scene without a projection to a project file",
586 foreach(tool, *m_tools) {
587 if (tool->projectPvlObjectName() !=
"") {
588 if (project.
hasObject(tool->projectPvlObjectName())) {
590 project.
findObject(tool->projectPvlObjectName()));
591 tool->fromPvl(toolSettings);
598 delete m_projectImageZOrders;
599 m_projectImageZOrders = NULL;
602 for (
int zOrderIndex = 0;
605 const PvlKeyword &zOrder = zOrders[zOrderIndex];
607 (*m_projectImageZOrders)[zOrder[0]] =
toDouble(zOrder[1]);
611 if (project.
hasObject(
"SceneVisiblePosition")) {
615 delete m_projectViewTransform;
616 m_projectViewTransform =
new PvlObject(positionInfo);
627 void MosaicSceneWidget::save(QXmlStreamWriter &stream, Project *, FileName )
const {
629 stream.writeStartElement(
"mosaicScene");
631 stream.writeStartElement(
"projection");
633 std::stringstream strStream;
634 strStream << mapping;
635 stream.writeCharacters(strStream.str().c_str());
636 stream.writeEndElement();
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();
645 stream.writeEndElement();
647 stream.writeStartElement(
"viewTransform");
648 stream.writeAttribute(
"scrollBarXValue",
toString(getView()->horizontalScrollBar()->value()));
649 stream.writeAttribute(
"scrollBarYValue",
toString(getView()->verticalScrollBar()->value()));
651 dataBuffer.open(QIODevice::ReadWrite);
652 QDataStream transformStream(&dataBuffer);
653 transformStream << getView()->transform();
655 stream.writeCharacters(dataBuffer.data().toHex());
656 stream.writeEndElement();
658 foreach(MosaicTool *tool, *m_tools) {
659 QString projectPvlObjectName = tool->projectPvlObjectName();
660 if (projectPvlObjectName !=
"") {
661 PvlObject toolObj = tool->toPvl();
662 toolObj.setName(projectPvlObjectName);
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();
673 stream.writeEndElement();
678 QRectF MosaicSceneWidget::cubesBoundingRect()
const {
681 MosaicSceneItem * mosaicItem;
682 foreach(mosaicItem, *m_mosaicSceneItems) {
683 if (boundingRect.isEmpty())
684 boundingRect = mosaicItem->boundingRect();
686 boundingRect = boundingRect.united(mosaicItem->boundingRect());
690 boundingRect = boundingRect.united(m_outlineRect->boundingRect());
696 MosaicSceneItem *MosaicSceneWidget::cubeToMosaic(DisplayProperties *props) {
698 QString msg = tr(
"Can not find a NULL Display Properties in the mosaic");
702 return m_displayPropsToMosaicSceneItemMap[props];
709 MosaicSceneItem *mosaicSceneItem;
710 foreach(mosaicSceneItem, *m_mosaicSceneItems) {
711 if (mosaicSceneItem->image())
712 cubes.append(mosaicSceneItem->image()->fileName());
719 Directory *MosaicSceneWidget::directory()
const {
724 ImageList MosaicSceneWidget::images() {
727 MosaicSceneItem *mosaicSceneItem;
728 foreach(mosaicSceneItem, *m_mosaicSceneItems) {
729 if (mosaicSceneItem->image())
730 images.
append(mosaicSceneItem->image());
748 foreach (
QGraphicsItem *graphicsItem, selectedGraphicsItems) {
751 if (!sceneImageItem) {
752 sceneImageItem =
dynamic_cast<MosaicSceneItem *
>(graphicsItem->parentItem());
755 if (sceneImageItem && sceneImageItem->image()) {
756 selectedImageItems.append(sceneImageItem);
787 saveList->setText(
"Save Entire Cube List (ordered by &view)...");
788 connect(saveList, SIGNAL(triggered()),
this, SLOT(saveList()));
791 exportActs.append(saveList);
800 foreach(MosaicTool *tool, *m_tools) {
802 viewActs.append(toolViewActs);
814 bool allImagesInView = !images->isEmpty();
816 foreach (
Image *image, *images) {
817 allImagesInView = allImagesInView && (cubeToMosaic(image) != NULL);
820 if (allImagesInView) {
824 results.append(moveToTopAct);
829 results.append(moveUpOneAct);
833 moveToBottomAct->
setData(images);
834 results.append(moveToBottomAct);
838 moveDownOneAct->
setData(images);
839 results.append(moveDownOneAct);
841 results.append(NULL);
844 zoomFitAct->setData(qVariantFromValue(images));
845 connect(zoomFitAct, SIGNAL(triggered()),
this, SLOT(fitInView()));
846 results.append(zoomFitAct);
852 bool MosaicSceneWidget::isControlNetToolActive() {
857 if (cnTool->
isActive())
return true;
864 QWidget * MosaicSceneWidget::getControlNetHelp(
QWidget *cnetToolContainer) {
865 QScrollArea *cnetHelpWidgetScrollArea =
new QScrollArea;
869 QVBoxLayout *cnetHelpLayout =
new QVBoxLayout;
870 cnetHelpWidget->setLayout(cnetHelpLayout);
872 QLabel *title =
new QLabel(
"<h2>Control Networks</h2>");
873 cnetHelpLayout->addWidget(title);
875 QPixmap previewPixmap;
877 if (cnetToolContainer) {
878 previewPixmap = cnetToolContainer->grab().scaled(
879 QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
882 ToolPad tmpToolPad(
"Example Tool Pad", NULL);
883 MosaicControlNetTool tmpTool(NULL);
884 tmpTool.addTo(&tmpToolPad);
886 tmpToolPad.resize(QSize(32, 32));
888 previewPixmap = tmpToolPad.grab();
891 QLabel *previewWrapper =
new QLabel;
892 previewWrapper->setPixmap(previewPixmap);
893 cnetHelpLayout->addWidget(previewWrapper);
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>"
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);
932 cnetHelpWidgetScrollArea->setWidget(cnetHelpWidget);
934 return cnetHelpWidgetScrollArea;
938 QWidget * MosaicSceneWidget::getGridHelp(
QWidget *gridToolContainer) {
939 QScrollArea *gridHelpWidgetScrollArea =
new QScrollArea;
943 QVBoxLayout *gridHelpLayout =
new QVBoxLayout;
944 gridHelpWidget->setLayout(gridHelpLayout);
946 QLabel *title =
new QLabel(
"<h2>Map Grid Tool</h2>");
947 gridHelpLayout->addWidget(title);
949 QPixmap previewPixmap;
951 if (gridToolContainer) {
952 previewPixmap = gridToolContainer->grab().scaled(
953 QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
956 ToolPad tmpToolPad(
"Example Tool Pad", NULL);
957 MosaicGridTool tmpTool(NULL);
958 tmpTool.addTo(&tmpToolPad);
960 tmpToolPad.resize(QSize(32, 32));
962 previewPixmap = tmpToolPad.grab();
965 QLabel *previewWrapper =
new QLabel;
966 previewWrapper->setPixmap(previewPixmap);
967 gridHelpLayout->addWidget(previewWrapper);
969 QLabel *overview =
new QLabel(
"Superimpose a map grid over the area of "
970 "displayed footprints in the 'mosaic scene.'"
973 "<li>The Map Grid Tool is activated by selecting the 'cross-hatch' "
974 "icon or typing 'g' at the keyboard."
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."
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 "
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."
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."
997 "<strong>Options:</strong>"
999 "<li>The 'Show Grid' option draws (checked) or clears (unchecked) the grid."
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."
1005 "<li>The expected units for each entry are displayed to the right of the "
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 "
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."
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."
1021 overview->setWordWrap(
true);
1022 gridHelpLayout->addWidget(overview);
1024 gridHelpWidgetScrollArea->setWidget(gridHelpWidget);
1026 return gridHelpWidgetScrollArea;
1030 QWidget * MosaicSceneWidget::getLongHelp(
QWidget *sceneContainer) {
1031 QScrollArea *longHelpWidgetScrollArea =
new QScrollArea;
1035 QVBoxLayout *longHelpLayout =
new QVBoxLayout;
1036 longHelpWidget->setLayout(longHelpLayout);
1038 QLabel *title =
new QLabel(
"<h2>Mosaic Scene</h2>");
1039 longHelpLayout->addWidget(title);
1041 if (sceneContainer) {
1042 QPixmap previewPixmap = sceneContainer->grab().scaled(
1043 QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
1045 QLabel *previewWrapper =
new QLabel;
1046 previewWrapper->setPixmap(previewPixmap);
1047 longHelpLayout->addWidget(previewWrapper);
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."
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>"
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 "
1071 overview->setWordWrap(
true);
1072 longHelpLayout->addWidget(overview);
1074 longHelpWidgetScrollArea->setWidget(longHelpWidget);
1076 return longHelpWidgetScrollArea;
1081 QScrollArea *mapHelpWidgetScrollArea =
new QScrollArea;
1085 QVBoxLayout *mapHelpLayout =
new QVBoxLayout;
1086 mapHelpWidget->setLayout(mapHelpLayout);
1088 QLabel *title =
new QLabel(tr(
"<h2>Map File</h2>"));
1089 mapHelpLayout->addWidget(title);
1092 QPixmap previewPixmap = mapContainer->grab().scaled(
1093 QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
1095 QLabel *previewWrapper =
new QLabel;
1096 previewWrapper->setPixmap(previewPixmap);
1097 mapHelpLayout->addWidget(previewWrapper);
1100 QLabel *overviewMapIcon =
new QLabel;
1102 overviewMapIcon->setPixmap(
1103 QIcon(FileName(
"$ISISROOT/appdata/images/icons/ographic.png").expanded()).pixmap(32, 32));
1104 mapHelpLayout->addWidget(overviewMapIcon);
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)."));
1116 defaultMapFile->setWordWrap(
true);
1117 mapHelpLayout->addWidget(defaultMapFile);
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()));
1129 userDefinedMapFileOverview->setWordWrap(
true);
1130 mapHelpLayout->addWidget(userDefinedMapFileOverview);
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."));
1136 userDefinedMapFileQuickLoad->setWordWrap(
true);
1137 mapHelpLayout->addWidget(userDefinedMapFileQuickLoad);
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."));
1143 userDefinedMapFileAnyTime->setWordWrap(
true);
1144 mapHelpLayout->addWidget(userDefinedMapFileAnyTime);
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));
1159 preparingMapFile->setOpenExternalLinks(
true);
1160 preparingMapFile->setWordWrap(
true);
1161 mapHelpLayout->addWidget(preparingMapFile);
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."));
1170 mapFileDisplayResults->setWordWrap(
true);
1171 mapHelpLayout->addWidget(mapFileDisplayResults);
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)."));
1180 editingMapFileOverview->setWordWrap(
true);
1181 mapHelpLayout->addWidget(editingMapFileOverview);
1183 QLabel *saveMapFileToDiskBullet =
new QLabel(tr(
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 "
1193 saveMapFileToDiskBullet->setWordWrap(
true);
1194 mapHelpLayout->addWidget(saveMapFileToDiskBullet);
1196 QLabel *mapFileValidityBullet =
new QLabel(tr(
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 "
1208 mapFileValidityBullet->setWordWrap(
true);
1209 mapHelpLayout->addWidget(mapFileValidityBullet);
1211 QLabel *mapFileCommentsBullet =
new QLabel(tr(
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/>"
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\"."
1227 mapFileCommentsBullet->setWordWrap(
true);
1228 mapHelpLayout->addWidget(mapFileCommentsBullet);
1230 mapHelpWidgetScrollArea->setWidget(mapHelpWidget);
1232 return mapHelpWidgetScrollArea;
1236 QWidget * MosaicSceneWidget::getPreviewHelp(
QWidget *worldViewContainer) {
1237 QScrollArea *previewHelpWidgetScrollArea =
new QScrollArea;
1241 QVBoxLayout *previewHelpLayout =
new QVBoxLayout;
1242 previewHelpWidget->setLayout(previewHelpLayout);
1244 QLabel *title =
new QLabel(
"<h2>Mosaic World View</h2>");
1245 previewHelpLayout->addWidget(title);
1247 if (worldViewContainer) {
1248 QPixmap previewPixmap = worldViewContainer->grab().scaled(
1249 QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
1251 QLabel *previewWrapper =
new QLabel;
1252 previewWrapper->setPixmap(previewPixmap);
1253 previewHelpLayout->addWidget(previewWrapper);
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);
1263 previewHelpWidgetScrollArea->setWidget(previewHelpWidget);
1265 return previewHelpWidgetScrollArea;
1269 MosaicSceneItem *MosaicSceneWidget::addImage(Image *image) {
1271 setProjection(createInitialProjection(image), *image->cube()->label());
1274 MosaicSceneItem *mosItem = NULL;
1277 if (!cubeToMosaic(image)) {
1278 mosItem =
new MosaicSceneItem(image,
this);
1282 connect(mosItem, SIGNAL(mosaicCubeClosed(Image *)),
1283 this, SIGNAL(mosCubeClosed(Image *)));
1287 if (m_projectImageZOrders && m_projectImageZOrders->contains(image->id())) {
1288 double zOrder = m_projectImageZOrders->value(image->id());
1289 m_projectImageZOrders->remove(image->id());
1291 foreach (MosaicSceneItem *mosaicItem, *m_mosaicSceneItems) {
1292 if (mosaicItem->zValue() == zOrder) {
1293 mosaicItem->setZValue(maximumZ() + 1);
1294 m_currentMaximumFootprintZ = maximumZ() + 1;
1298 m_currentMaximumFootprintZ = qMax(zOrder, maximumZ());
1299 mosItem->setZValue(zOrder);
1302 mosItem->setZValue(maximumZ() + 1);
1303 m_currentMaximumFootprintZ = maximumZ() + 1;
1306 getScene()->addItem(mosItem);
1307 m_mosaicSceneItems->append(mosItem);
1308 m_displayPropsToMosaicSceneItemMap[image->displayProperties()] = mosItem;
1310 connect(mosItem, SIGNAL(destroyed(
QObject *)),
1311 this, SLOT(removeMosItem(
QObject *)));
1313 ImageDisplayProperties *prop = image->displayProperties();
1314 connect(prop, SIGNAL(moveDownOne()),
1315 this, SLOT(moveDownOne()));
1318 connect(prop, SIGNAL(moveUpOne()),
1319 this, SLOT(moveUpOne()));
1322 connect(prop, SIGNAL(zoomFit()),
1323 this, SLOT(fitInView()));
1330 double MosaicSceneWidget::maximumZ() {
1331 return m_currentMaximumFootprintZ;
1335 double MosaicSceneWidget::minimumZ() {
1336 return m_currentMinimumFootprintZ;
1339 void MosaicSceneWidget::recalcSceneRect() {
1341 double minX, minY, maxX, maxY;
1344 QRectF projRect(minX, -maxY, maxX - minX, maxY - minY);
1345 QRectF cubesBounding = cubesBoundingRect();
1347 QRectF bounding = projRect.united(cubesBounding);
1349 if (m_outlineRect && m_outlineRect->isVisible())
1350 bounding = bounding.united(m_outlineRect->boundingRect());
1352 getView()->setSceneRect(bounding);
1356 void MosaicSceneWidget::addImages(ImageList images) {
1357 if (m_userToolControl)
1358 m_progress->
setText(
"Loading primary scene");
1360 m_progress->
setText(
"Loading secondary scene");
1362 m_progress->setRange(0, images.size() - 1);
1363 m_progress->setValue(0);
1364 m_progress->setVisible(
true);
1366 foreach(Image *image, images) {
1370 catch (IException &e) {
1374 m_progress->setValue(m_progress->value() + 1);
1379 if (m_projectViewTransform) {
1380 PvlObject &positionInfo = *m_projectViewTransform;
1381 QByteArray hexValues(positionInfo[
"ViewTransform"][0].toLatin1());
1382 QDataStream transformStream(QByteArray::fromHex(hexValues));
1384 QTransform viewTransform;
1385 transformStream >> viewTransform;
1386 getView()->setTransform(viewTransform);
1388 QPoint projectScrollPos(
toInt(positionInfo[
"ScrollPosition"][0]),
1389 toInt(positionInfo[
"ScrollPosition"][1]));
1391 getView()->horizontalScrollBar()->setValue(projectScrollPos.x());
1392 getView()->verticalScrollBar()->setValue(projectScrollPos.y());
1398 if (!m_projectImageZOrders || m_projectImageZOrders->isEmpty()) {
1399 delete m_projectViewTransform;
1400 m_projectViewTransform = NULL;
1403 m_progress->setVisible(
false);
1404 emit cubesChanged();
1408 void MosaicSceneWidget::removeImages(ImageList images) {
1411 foreach(Image *image, images) {
1413 MosaicSceneItem *item = cubeToMosaic(image);
1414 item->deleteLater();
1415 removeMosItem(item);
1417 catch (IException &e) {
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;
1436 if (QFileInfo(output).suffix().isEmpty()) {
1437 output = output +
".png";
1440 QString format = QFileInfo(output).suffix();
1441 QPixmap pm = getScene()->views().last()->grab();
1443 std::string formatString = format.toStdString();
1444 if (!pm.save(output, formatString.c_str())) {
1445 QMessageBox::information(
this,
"Error",
1446 "Unable to save [" + output +
"]");
1451 void MosaicSceneWidget::saveList() {
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;
1459 TextFile file(output,
"overwrite");
1462 qSort(sorted.begin(), sorted.end(), zOrderGreaterThan);
1465 foreach(sceneItem, sorted) {
1466 file.PutLine( sceneItem->image()->
fileName() );
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));
1477 emit cubesChanged();
1486 QRectF sceneRect = cubesBoundingRect();
1488 if (sceneRect.isEmpty())
1491 double xPadding = sceneRect.width() * 0.10;
1492 double yPadding = sceneRect.height() * 0.10;
1494 sceneRect.adjust(-xPadding, -yPadding, xPadding, yPadding);
1495 getView()->fitInView(sceneRect, Qt::KeepAspectRatio);
1499 void MosaicSceneWidget::setCubesSelectable(
bool selectable) {
1500 if (m_cubesSelectable != selectable) {
1501 m_cubesSelectable = selectable;
1504 foreach(mosaicSceneItem, *m_mosaicSceneItems) {
1505 mosaicSceneItem->scenePropertiesChanged();
1517 configDialog.exec();
1521 void MosaicSceneWidget::quickConfigProjectionParameters() {
1523 configDialog.setQuickConfig(
true);
1524 configDialog.exec();
1528 void MosaicSceneWidget::sendVisibleRectChanged() {
1529 QPointF topLeft = getView()->mapToScene(0, 0);
1530 QPointF bottomRight = getView()->mapToScene(
1531 (
int)getView()->width(),
1532 (
int)getView()->height());
1534 QRectF visibleRect(topLeft, bottomRight);
1535 emit visibleRectChanged(visibleRect);
1539 bool MosaicSceneWidget::eventFilter(
QObject *obj, QEvent *event) {
1540 bool stopProcessingEvent =
true;
1542 switch(event->type()) {
1543 case QMouseEvent::GraphicsSceneMousePress: {
1544 if (m_customRubberBandEnabled) {
1546 if (!m_customRubberBand) {
1547 m_customRubberBand =
new QRubberBand(QRubberBand::Rectangle,
1551 if (!m_rubberBandOrigin) {
1552 m_rubberBandOrigin =
new QPoint;
1555 *m_rubberBandOrigin = getView()->mapFromScene(
1556 ((QGraphicsSceneMouseEvent *)event)->scenePos());
1557 m_customRubberBand->setGeometry(QRect(*m_rubberBandOrigin, QSize()));
1558 m_customRubberBand->show();
1561 emit mouseButtonPress(
1562 ((QGraphicsSceneMouseEvent *)event)->scenePos(),
1563 ((QGraphicsSceneMouseEvent *)event)->button());
1564 stopProcessingEvent =
false;
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;
1581 delete m_rubberBandOrigin;
1582 m_rubberBandOrigin = NULL;
1584 delete m_customRubberBand;
1585 m_customRubberBand = NULL;
1588 if (!signalEmitted) {
1589 stopProcessingEvent =
false;
1590 emit mouseButtonRelease(
1591 ((QGraphicsSceneMouseEvent *)event)->scenePos(),
1592 ((QGraphicsSceneMouseEvent *)event)->button());
1597 case QMouseEvent::GraphicsSceneMouseDoubleClick:
1598 emit mouseDoubleClick(
1599 ((QGraphicsSceneMouseEvent *)event)->scenePos());
1600 stopProcessingEvent =
false;
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);
1609 QRect rubberBandRect =
1610 QRect(*m_rubberBandOrigin, screenPos).normalized();
1612 m_customRubberBand->setGeometry(rubberBandRect);
1615 stopProcessingEvent =
false;
1619 ((QGraphicsSceneMouseEvent *)event)->scenePos());
1622 case QEvent::GraphicsSceneWheel:
1624 ((QGraphicsSceneWheelEvent *)event)->scenePos(),
1625 ((QGraphicsSceneWheelEvent *)event)->delta());
1627 stopProcessingEvent =
true;
1630 case QMouseEvent::Enter:
1632 stopProcessingEvent =
false;
1635 case QMouseEvent::Leave:
1637 stopProcessingEvent =
false;
1640 case QEvent::GraphicsSceneHelp: {
1642 bool toolTipFound =
false;
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;
1657 stopProcessingEvent =
true;
1659 ((QGraphicsSceneHelpEvent*)event)->screenPos(),
1666 stopProcessingEvent =
false;
1670 return stopProcessingEvent;
1681 if (m_mosaicSceneItems->size() == 0)
1684 if (m_userToolControl)
1685 m_progress->
setText(
"Reprojecting primary scene");
1687 m_progress->
setText(
"Reprojecting secondary scene");
1690 int reprojectsPerUpdate = qMax(1, m_mosaicSceneItems->size() / 20);
1692 m_progress->setRange(0,
1693 (m_mosaicSceneItems->size() - 1) / reprojectsPerUpdate + 1);
1694 m_progress->setValue(0);
1695 m_progress->setVisible(
true);
1699 int progressCountdown = reprojectsPerUpdate;
1700 foreach(mosaicSceneItem, *m_mosaicSceneItems) {
1705 QString msg =
"The file [";
1707 if (mosaicSceneItem->image())
1710 msg +=
"] is being removed due to not being able to project onto the scene";
1714 mosaicSceneItem->image()->deleteLater();
1717 progressCountdown --;
1718 if (progressCountdown == 0) {
1719 m_progress->setValue(m_progress->value() + 1);
1720 progressCountdown = reprojectsPerUpdate;
1725 m_progress->setValue(m_progress->maximum());
1729 m_progress->setVisible(
false);
1733 void MosaicSceneWidget::moveDownOne() {
1737 moveDownOne(cubeToMosaic(props));
1744 double MosaicSceneWidget::moveDownOne(MosaicSceneItem *item) {
1745 MosaicSceneItem *nextDown =
getNextItem(item,
false);
1746 double originalZ = item->zValue();
1749 double newZValue = nextDown->zValue() - 1;
1750 moveZ(item, newZValue,
true);
1759 double MosaicSceneWidget::moveDownOne(Image *image) {
1760 return moveDownOne(cubeToMosaic(image));
1766 QList<double> MosaicSceneWidget::moveDownOne(ImageList *images) {
1769 foreach (Image *image, *images) {
1770 results.append(moveDownOne(image));
1777 void MosaicSceneWidget::moveToBottom() {
1778 DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1790 double originalZ = item->zValue();
1791 double minZ = minimumZ();
1793 if (originalZ != minZ) {
1795 int newZValue = qRound(minZ - 1);
1796 item->setZValue(newZValue);
1799 m_currentMinimumFootprintZ--;
1810 double MosaicSceneWidget::moveToBottom(
Image *image) {
1822 foreach (
Image *image, *images) {
1830 void MosaicSceneWidget::moveUpOne() {
1834 moveUpOne(cubeToMosaic(props));
1841 double MosaicSceneWidget::moveUpOne(MosaicSceneItem *item) {
1842 MosaicSceneItem *nextUp =
getNextItem(item,
true);
1843 double originalZ = item->zValue();
1846 double newZValue = nextUp->zValue() + 1;
1847 moveZ(item, newZValue,
true);
1856 double MosaicSceneWidget::moveUpOne(Image *image) {
1857 return moveUpOne(cubeToMosaic(image));
1863 QList<double> MosaicSceneWidget::moveUpOne(ImageList *images) {
1866 foreach (Image *image, *images) {
1867 results.append(moveUpOne(image));
1874 void MosaicSceneWidget::moveToTop() {
1875 DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1888 double originalZ = item->zValue();
1889 double maxZ = maximumZ();
1891 if (originalZ != maxZ) {
1893 int newZValue = qRound(maxZ + 1);
1894 item->setZValue(newZValue);
1897 m_currentMaximumFootprintZ++;
1918 double MosaicSceneWidget::moveToTop(
Image *image) {
1930 foreach (
Image *image, *images) {
1956 bool newZValueMightExist) {
1957 double originalZ = sceneItem->zValue();
1959 if (newZValueMightExist) {
1961 m_currentMinimumFootprintZ = 0.0;
1962 m_currentMaximumFootprintZ = 0.0;
1965 double otherItemOrigZ = otherItem->zValue();
1966 double otherItemNewZ = otherItemOrigZ;
1969 if (originalZ > newZ && otherItemOrigZ >= newZ && otherItemOrigZ < originalZ) {
1970 otherItemNewZ = otherItemOrigZ + 1;
1973 else if (originalZ < newZ && otherItemOrigZ <= newZ && otherItemOrigZ > originalZ) {
1974 otherItemNewZ = otherItemOrigZ - 1;
1977 m_currentMinimumFootprintZ = qMin(m_currentMinimumFootprintZ, otherItemNewZ);
1978 m_currentMaximumFootprintZ = qMax(m_currentMaximumFootprintZ, otherItemNewZ);
1979 otherItem->setZValue(otherItemNewZ);
1983 sceneItem->setZValue(newZ);
1985 if (!newZValueMightExist) {
1987 if (originalZ == maximumZ() && newZ < originalZ) {
1988 m_currentMaximumFootprintZ--;
1990 else if (originalZ == minimumZ() && newZ > originalZ) {
1991 m_currentMinimumFootprintZ++;
2000 bool newZValueMightExist) {
2001 return moveZ(cubeToMosaic(image), newZ, newZValueMightExist);
2005 void MosaicSceneWidget::fitInView() {
2006 if (m_userToolControl) {
2009 DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
2012 MosaicSceneItem *item = cubeToMosaic(props);
2013 boundingBox = item->boundingRect();
2016 QAction *action = qobject_cast<QAction *>(sender());
2019 ImageList *images = action->data().value<ImageList *>();
2021 foreach (Image *image, *images) {
2022 ASSERT(cubeToMosaic(image));
2023 boundingBox = boundingBox.united(cubeToMosaic(image)->boundingRect());
2028 if (!boundingBox.isNull()) {
2029 double xPadding = boundingBox.width() * 0.10;
2030 double yPadding = boundingBox.height() * 0.10;
2032 boundingBox.setLeft(boundingBox.left() - xPadding);
2033 boundingBox.setRight(boundingBox.right() + xPadding);
2035 boundingBox.setTop(boundingBox.top() - yPadding);
2036 boundingBox.setBottom(boundingBox.bottom() + yPadding);
2038 getView()->fitInView(boundingBox, Qt::KeepAspectRatio);
2039 getView()->centerOn(boundingBox.center());
2045 void MosaicSceneWidget::onSelectionChanged() {
2046 if (!m_blockingSelectionChanged) {
2047 if (!m_queuedSelectionChanged) {
2048 emit queueSelectionChanged();
2049 m_queuedSelectionChanged =
true;
2052 m_shouldRequeueSelectionChanged =
true;
2058 void MosaicSceneWidget::onQueuedSelectionChanged() {
2059 m_queuedSelectionChanged =
false;
2061 if (m_shouldRequeueSelectionChanged) {
2062 m_shouldRequeueSelectionChanged =
false;
2063 onSelectionChanged();
2066 foreach(MosaicSceneItem *mosaicSceneItem, *m_mosaicSceneItems) {
2067 mosaicSceneItem->updateSelection(
true);
2078 foreach(mosaicSceneItem, *m_mosaicSceneItems) {
2079 if (mosaicSceneItem != item &&
2080 mosaicSceneItem->boundingRect().intersects(item->boundingRect())) {
2082 if ( (up && mosaicSceneItem->zValue() > item->zValue()) ||
2083 (!up && mosaicSceneItem->zValue() < item->zValue())) {
2086 if (!nextZValueItem) {
2087 nextZValueItem = mosaicSceneItem;
2092 if ((up && mosaicSceneItem->zValue() < nextZValueItem->zValue()) ||
2093 (!up && mosaicSceneItem->zValue() > nextZValueItem->zValue())) {
2094 nextZValueItem = mosaicSceneItem;
2101 return nextZValueItem;
2107 return first->zValue() > second->zValue();
2111 MosaicSceneWidget::XmlHandler::XmlHandler(MosaicSceneWidget *scene) {
2113 m_scrollBarXValue = -1;
2114 m_scrollBarYValue = -1;
2115 m_imagesToAdd = NULL;
2117 m_imagesToAdd =
new ImageList;
2121 MosaicSceneWidget::XmlHandler::~XmlHandler() {
2122 delete m_imagesToAdd;
2123 m_imagesToAdd = NULL;
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);
2131 m_characterData =
"";
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);
2141 Shape *shape = m_scene->m_directory->project()->shape(
id);
2143 image =
new Image(shape->cube(), shape->footprint(),
id);
2147 m_imagesToAdd->append(image);
2148 m_imageZValues.append(zValue);
2152 else if (localName ==
"viewTransform") {
2153 m_scrollBarXValue = atts.value(
"scrollBarXValue").toInt();
2154 m_scrollBarYValue = atts.value(
"scrollBarYValue").toInt();
2162 bool MosaicSceneWidget::XmlHandler::characters(
const QString &ch) {
2163 bool result = XmlStackedHandler::characters(ch);
2166 m_characterData += ch;
2173 bool MosaicSceneWidget::XmlHandler::endElement(
const QString &namespaceURI,
2174 const QString &localName,
const QString &qName) {
2175 bool result = XmlStackedHandler::endElement(namespaceURI, localName, qName);
2178 if (localName ==
"projection") {
2179 std::stringstream strStream(m_characterData.toStdString());
2180 PvlGroup mappingGroup;
2181 strStream >> mappingGroup;
2182 m_scene->setProjection(mappingGroup);
2184 else if (localName ==
"viewTransform") {
2185 QByteArray hexValues(m_characterData.toLatin1());
2186 QDataStream transformStream(QByteArray::fromHex(hexValues));
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);
2196 else if (localName ==
"toolData") {
2197 PvlObject toolSettings;
2198 std::stringstream strStream(m_characterData.toStdString());
2199 strStream >> toolSettings;
2201 foreach (MosaicTool *tool, *m_scene->m_tools) {
2202 if (tool->projectPvlObjectName() == toolSettings.name()) {
2203 tool->fromPvl(toolSettings);
2207 else if (localName ==
"images" && m_imagesToAdd->count()) {
2208 ASSERT(m_imagesToAdd->count() == m_imageZValues.count());
2209 m_scene->addImages(*m_imagesToAdd);
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,
2215 m_scene->m_currentMaximumFootprintZ = qMax(m_scene->m_currentMaximumFootprintZ,
2221 m_characterData =
"";