USGS

Isis 3.0 Object Programmers' Reference

Home

MosaicZoomTool.cpp

00001 #include "MosaicZoomTool.h"
00002 
00003 #include <float.h>
00004 #include <iomanip>
00005 #include <iostream>
00006 
00007 #include <QDoubleSpinBox>
00008 #include <QGraphicsSceneMouseEvent>
00009 #include <QHBoxLayout>
00010 #include <QLabel>
00011 #include <QMenu>
00012 #include <QScrollBar>
00013 #include <QToolButton>
00014 
00015 #include "IString.h"
00016 #include "MosaicGraphicsView.h"
00017 #include "MosaicSceneWidget.h"
00018 #include "Projection.h"
00019 
00020 namespace Isis {
00027   MosaicZoomTool::MosaicZoomTool(MosaicSceneWidget *scene) : MosaicTool(scene) {
00028     p_scaleBox = NULL;
00029 
00030     m_zoomInAction = new QAction(this);
00031     m_zoomInAction->setIcon(getIcon("viewmag+.png"));
00032     m_zoomInAction->setText("Zoom In");
00033     m_zoomInAction->setToolTip("Zoom in on the mosaic scene");
00034     m_zoomInAction->setShortcut(Qt::Key_Plus);
00035     QString text =
00036       "<b>Function:</b> Zoom in 2X at the center of the active viewport \
00037       <p><b>Shortcut:</b>  +</p> \
00038       <p><b>Mouse:</b>  LeftButton zooms in 2X under pointer</p> \
00039       <p><b>Modifiers:</b>  Shortcuts and mouse clicks can be augmented \
00040       using the Ctrl or Alt key for 4X and 8X zooms, respectively</p> \
00041       <p><b>Hint:</b>  Left click and drag for a local zoom which scales data \
00042       in the marquee to the view</p>";
00043     m_zoomInAction->setWhatsThis(text);
00044     connect(m_zoomInAction, SIGNAL(triggered()), this, SLOT(zoomIn2X()));
00045 
00046     m_zoomOutAction = new QAction(this);
00047     m_zoomOutAction->setIcon(getIcon("viewmag-.png"));
00048     m_zoomOutAction->setText("Zoom Out");
00049     m_zoomOutAction->setToolTip("Zoom out on the mosaic scene");
00050     m_zoomOutAction->setShortcut(Qt::Key_Minus);
00051     text =
00052       "<b>Function:</b> Zoom out 2X at the center of the view \
00053       <p><b>Shortcut:</b>  +</p> \
00054       <p><b>Mouse:</b>  RightButton zooms out 2X under pointer</p> \
00055       <p><b>Modifiers:</b>  Shortcuts and mouse clicks can be augmented \
00056       using the Ctrl or Alt key for 4X and 8X zooms, respectively</p> \
00057       <p><b>Hint:</b>  Left click and drag for a local zoom which scales data \
00058       in the marquee to the view</p>";
00059     m_zoomOutAction->setWhatsThis(text);
00060     connect(m_zoomOutAction, SIGNAL(triggered()), this, SLOT(zoomOut2X()));
00061 
00062     m_zoomFitAction = new QAction(this);
00063     m_zoomFitAction->setIcon(getIcon("viewmagfit.png"));
00064     m_zoomFitAction->setText("Fit in View");
00065     m_zoomFitAction->setToolTip("Zoom to where all of the cubes are visible in "
00066                                 "the mosaic scene");
00067     m_zoomFitAction->setShortcut(Qt::Key_Asterisk);
00068     text =
00069       "<b>Function:</b> Fit the entire mosaic inside the view. \
00070       <p><b>Shortcut:</b> *</p> \
00071       <p><b>Hint:</b>  Many shortcuts for the zoom tool and other tools \
00072       are easily available on the numeric keypad </p>";
00073     m_zoomFitAction->setWhatsThis(text);
00074     connect(m_zoomFitAction, SIGNAL(triggered()), this, SLOT(zoomFit()));
00075   }
00076 
00077 
00083   void MosaicZoomTool::updateResolutionBox() {
00084     if(p_scaleBox) {
00085       // Using these two points we can calculated the scene's width.
00086       QPointF point1 = getWidget()->getView()->mapToScene(0, 0);
00087       QPointF point2 = getWidget()->getView()->mapToScene(
00088           (int)getWidget()->getView()->width(), 0);
00089       double newWidth = point2.x() - point1.x();
00090 
00091       // The scene width divided by the viewport's width gives us the screen res.
00092       p_screenResolution = newWidth / getWidget()->getView()->viewport()->width();
00093 
00094       // Update the text box display
00095       p_scaleBox->setValue(p_screenResolution);
00096       //------------------------------------------------------------------------
00097       // This sets the up and down arrows (on the text box) so that each time a
00098       // user clicks them, a resonable amount of zoom happens.
00099       //------------------------------------------------------------------------
00100       p_scaleBox->setSingleStep(p_screenResolution * .05);
00101     }
00102   }
00103 
00104 
00105   QList<QAction *> MosaicZoomTool::getViewActions() {
00106     QList<QAction *> viewActs;
00107 
00108     viewActs.append(m_zoomInAction);
00109     viewActs.append(m_zoomOutAction);
00110     viewActs.append(m_zoomFitAction);
00111 
00112     return viewActs;
00113   }
00114 
00115 
00116   QAction *MosaicZoomTool::getPrimaryAction() {
00117     QAction *action = new QAction(this);
00118     action->setIcon(getIcon("viewmag.png"));
00119     action->setToolTip("Zoom (z)");
00120     action->setShortcut(Qt::Key_Z);
00121     QString text  =
00122       "<b>Function:</b>  Zoom in or out of the current cube.<br><br>"
00123       "This tool gives you a <b>click</b> to zoom by 2X and center on the "
00124       "point you clicked on, a <b>right-click</b> to zoom out by 2X and center "
00125       "on the point you clicked on, a <b>click and drag</b> box to best fit "
00126       "the given area into the visible screen, a <b>right-click and drag</b> "
00127       "box to zoom out and center on the center (smaller box means zoom out "
00128       "more), and disables context menus on the mosaic scene."
00129       "<p><b>Shortcut:</b>  z</p> ";
00130     action->setWhatsThis(text);
00131     return action;
00132   }
00133 
00134 
00143   QWidget *MosaicZoomTool::getToolBarWidget() {
00144     QWidget *hbox = new QWidget;
00145 
00146     QToolButton *zoomInButton = new QToolButton(hbox);
00147     zoomInButton->setAutoRaise(true);
00148     zoomInButton->setDefaultAction(m_zoomInAction);
00149     zoomInButton->setIconSize(QSize(22, 22));
00150 
00151     QToolButton *zoomOutButton = new QToolButton(hbox);
00152     zoomOutButton->setAutoRaise(true);
00153     zoomOutButton->setDefaultAction(m_zoomOutAction);
00154     zoomOutButton->setIconSize(QSize(22, 22));
00155 
00156     QToolButton *zoomFitButton = new QToolButton(hbox);
00157     zoomFitButton->setAutoRaise(true);
00158     zoomFitButton->setDefaultAction(m_zoomFitAction);
00159     zoomFitButton->setIconSize(QSize(22, 22));
00160 
00161     p_scaleBox = new QDoubleSpinBox();
00162     p_scaleBox->setRange(DBL_MIN, DBL_MAX);
00163     p_scaleBox->setDecimals(8);
00164     connect(p_scaleBox, SIGNAL(editingFinished()), this, SLOT(zoomManual()));
00165 
00166     QLabel *resolutionLabel = new QLabel("Meters per pixel");
00167 
00168     QHBoxLayout *layout = new QHBoxLayout(hbox);
00169     layout->setMargin(0);
00170     layout->addWidget(zoomInButton);
00171     layout->addWidget(zoomOutButton);
00172 
00173     //-------------------------------------------
00174     // These two actions are not quite ready yet.
00175     // layout->addWidget(zoomActButton);
00176     //-------------------------------------------
00177     layout->addWidget(zoomFitButton);
00178     layout->addWidget(p_scaleBox);
00179     layout->addWidget(resolutionLabel);
00180     layout->addStretch(1);
00181     hbox->setLayout(layout);
00182     return hbox;
00183   }
00184 
00185 
00186   void MosaicZoomTool::mouseButtonRelease(QPointF mouseLoc, Qt::MouseButton s) {
00187     if(!isActive())
00188       return;
00189 
00190     if(s == Qt::LeftButton)
00191       zoomIn2X(mouseLoc);
00192     else if(s == Qt::RightButton)
00193       zoomOut2X(mouseLoc);
00194   }
00195 
00196 
00197   void MosaicZoomTool::mouseWheel(QPointF mouseLoc, int delta) {
00198     static const double sensitivity = 60.0; // this causes factor of 2 changes
00199     double scale = delta / sensitivity;
00200 
00201     if(delta < 0)
00202       scale = 1.0 / (-delta / sensitivity);
00203 
00204     scale = limitZoomBy(scale);
00205 
00206     QPoint screenMouseLoc(getWidget()->getView()->mapFromScene(mouseLoc));
00207     QPoint screenCenter(
00208         getWidget()->getView()->viewport()->size().width() / 2,
00209         getWidget()->getView()->viewport()->size().height() / 2);
00210 
00211     // We're going to do this by zooming on the mouse and then
00212     //   undo-ing the center in screen pixels.
00213     zoomBy(scale, mouseLoc);
00214 
00215     // The new center screen pixel is:
00216     //   center - mouseLoc
00217     QPoint desiredScreenCenter =
00218         screenCenter + (screenCenter - screenMouseLoc);
00219     QPointF newCenterPoint =
00220         getWidget()->getView()->mapToScene(desiredScreenCenter);
00221     getWidget()->getView()->centerOn(newCenterPoint);
00222   }
00223 
00224 
00229   void MosaicZoomTool::zoomIn2X(QPointF center) {
00230     zoomBy(2.0, center);
00231   }
00232 
00233 
00238   void MosaicZoomTool::zoomOut2X(QPointF center) {
00239     zoomBy(1.0 / 2.0, center);
00240   }
00241 
00242 
00247   void MosaicZoomTool::zoomActual(QPointF center) {
00248     zoomBy(1.1, center);
00249   }
00250 
00251 
00252   double MosaicZoomTool::limitZoomBy(double factor) {
00253     QMatrix matrix = getWidget()->getView()->matrix();
00254     matrix = matrix.scale(factor, factor).inverted();
00255 
00256     int smallerDimension = getWidget()->getView()->width();
00257     int largerDimension = getWidget()->getView()->height();
00258 
00259     if(smallerDimension > largerDimension) {
00260       int tmp = smallerDimension;
00261       smallerDimension = largerDimension;
00262       largerDimension = tmp;
00263     }
00264 
00265     QPointF point1 = matrix.map(QPointF(0, 0));
00266     QPointF point2 = matrix.map(QPointF(smallerDimension, 0));
00267 
00268     // If the factor cannot be done, find the one that can
00269     //   This max zoom in factor isn't right; I haven't found the number
00270     //   that corresponds to the Qt bug(?) causing us to not pan correctly on
00271     //   the zoom in.
00272     if((point2.x() - point1.x()) < 1) {
00273       QMatrix origMatrix = getWidget()->getView()->matrix();
00274       factor = smallerDimension / (origMatrix.m11() * 1.0);
00275     }
00276 
00277     point1 = matrix.map(QPointF(0, 0));
00278     point2 = matrix.map(QPointF(largerDimension, 0));
00279 
00280     if((point2.x() - point1.x()) > 1E10) {
00281       QMatrix origMatrix = getWidget()->getView()->matrix();
00282       factor = largerDimension / (origMatrix.m11() * 1E10);
00283     }
00284 
00285     return factor;
00286   }
00287 
00288 
00295   void MosaicZoomTool::zoomBy(double factor, QPointF center) {
00296     factor = limitZoomBy(factor);
00297 
00298     getWidget()->getView()->scale(factor, factor);
00299 
00300     if(!center.isNull()) {
00301       getWidget()->getView()->centerOn(center);
00302     }
00303 
00304     updateResolutionBox();
00305   }
00306 
00307 
00312   void MosaicZoomTool::zoomFit() {
00313     getWidget()->refit();
00314     updateResolutionBox();
00315   }
00316 
00317 
00322   void MosaicZoomTool::zoomFitWidth() {
00323 
00324   }
00325 
00326 
00332   void MosaicZoomTool::zoomFitHeight() {
00333 
00334   }
00335 
00336 
00346   void MosaicZoomTool::zoomManual() {
00347     if(p_scaleBox) {
00348       double x = p_screenResolution / p_scaleBox->value();
00349       zoomBy(x);
00350     }
00351   }
00352 
00353 
00359   void MosaicZoomTool::updateTool() {
00360     if(isActive()) {
00361       getWidget()->setCubesSelectable(false);
00362       getWidget()->getView()->setContextMenuPolicy(Qt::NoContextMenu);
00363       getWidget()->enableRubberBand(true);
00364     }
00365     else {
00366       getWidget()->setCubesSelectable(true);
00367       getWidget()->getView()->setContextMenuPolicy(Qt::DefaultContextMenu);
00368       getWidget()->enableRubberBand(false);
00369     }
00370 
00371     updateResolutionBox();
00372   }
00373 
00374 
00382   void MosaicZoomTool::rubberBandComplete(QRectF r, Qt::MouseButton s) {
00383     if(!isActive())
00384       return;
00385 
00386     double meters_pixel = 0.0;
00387 
00388     //--------------------------------------------------------------------
00389     // We only user width or height to determine the desired meters/pixel.
00390     // Which ever is larger.
00391     //--------------------------------------------------------------------
00392     if(r.width() > r.height()) {
00393       meters_pixel = r.width() / getWidget()->getView()->viewport()->width();
00394     }
00395     else {
00396       meters_pixel = r.height() / getWidget()->getView()->viewport()->height();
00397     }
00398 
00399     // calculate the scale.
00400     double scale = p_screenResolution / meters_pixel;
00401 
00402     // zooming in.
00403     if(s == Qt::LeftButton) {
00404       zoomBy(scale, r.center());
00405     }
00406 
00407     // zooming out.
00408     if(s == Qt::RightButton) {
00409       zoomBy(1 / scale, r.center());
00410     }
00411 
00412     updateResolutionBox();
00413   }
00414 
00415 }
00416