Isis 3 Programmer Reference
MosaicZoomTool.cpp
1 #include "MosaicZoomTool.h"
2 
3 #include <float.h>
4 #include <iomanip>
5 #include <iostream>
6 
7 #include <QDoubleSpinBox>
8 #include <QGraphicsSceneMouseEvent>
9 #include <QHBoxLayout>
10 #include <QLabel>
11 #include <QMenu>
12 #include <QScrollBar>
13 #include <QToolButton>
14 
15 #include "IString.h"
16 #include "MosaicGraphicsView.h"
17 #include "MosaicSceneWidget.h"
18 #include "Projection.h"
19 
20 namespace Isis {
28  p_scaleBox = NULL;
29 
30  m_zoomInAction = new QAction(this);
31  m_zoomInAction->setIcon(getIcon("viewmag+.png"));
32  m_zoomInAction->setText("Zoom In");
33  m_zoomInAction->setToolTip("Zoom in on the mosaic scene");
34  m_zoomInAction->setShortcut(Qt::Key_Plus);
35  QString text =
36  "<b>Function:</b> Zoom in 2X at the center of the active viewport \
37  <p><b>Shortcut:</b> +</p> \
38  <p><b>Mouse:</b> LeftButton zooms in 2X under pointer</p> \
39  <p><b>Modifiers:</b> Shortcuts and mouse clicks can be augmented \
40  using the Ctrl or Alt key for 4X and 8X zooms, respectively</p> \
41  <p><b>Hint:</b> Left click and drag for a local zoom which scales data \
42  in the marquee to the view</p>";
43  m_zoomInAction->setWhatsThis(text);
44  connect(m_zoomInAction, SIGNAL(triggered()), this, SLOT(zoomIn2X()));
45 
46  m_zoomOutAction = new QAction(this);
47  m_zoomOutAction->setIcon(getIcon("viewmag-.png"));
48  m_zoomOutAction->setText("Zoom Out");
49  m_zoomOutAction->setToolTip("Zoom out on the mosaic scene");
50  m_zoomOutAction->setShortcut(Qt::Key_Minus);
51  text =
52  "<b>Function:</b> Zoom out 2X at the center of the view \
53  <p><b>Shortcut:</b> +</p> \
54  <p><b>Mouse:</b> RightButton zooms out 2X under pointer</p> \
55  <p><b>Modifiers:</b> Shortcuts and mouse clicks can be augmented \
56  using the Ctrl or Alt key for 4X and 8X zooms, respectively</p> \
57  <p><b>Hint:</b> Left click and drag for a local zoom which scales data \
58  in the marquee to the view</p>";
59  m_zoomOutAction->setWhatsThis(text);
60  connect(m_zoomOutAction, SIGNAL(triggered()), this, SLOT(zoomOut2X()));
61 
62  m_zoomFitAction = new QAction(this);
63  m_zoomFitAction->setIcon(getIcon("viewmagfit.png"));
64  m_zoomFitAction->setText("Fit in View");
65  m_zoomFitAction->setToolTip("Zoom to where all of the cubes are visible in "
66  "the mosaic scene");
67  m_zoomFitAction->setShortcut(Qt::Key_Asterisk);
68  text =
69  "<b>Function:</b> Fit the entire mosaic inside the view. \
70  <p><b>Shortcut:</b> *</p> \
71  <p><b>Hint:</b> Many shortcuts for the zoom tool and other tools \
72  are easily available on the numeric keypad </p>";
73  m_zoomFitAction->setWhatsThis(text);
74  connect(m_zoomFitAction, SIGNAL(triggered()), this, SLOT(zoomFit()));
75  }
76 
77 
84  if(p_scaleBox) {
85  // Using these two points we can calculated the scene's width.
86  QPointF point1 = getWidget()->getView()->mapToScene(0, 0);
87  QPointF point2 = getWidget()->getView()->mapToScene(
88  (int)getWidget()->getView()->width(), 0);
89  double newWidth = point2.x() - point1.x();
90 
91  // The scene width divided by the viewport's width gives us the screen res.
92  p_screenResolution = newWidth / getWidget()->getView()->viewport()->width();
93 
94  // Update the text box display
95  p_scaleBox->setValue(p_screenResolution);
96  //------------------------------------------------------------------------
97  // This sets the up and down arrows (on the text box) so that each time a
98  // user clicks them, a resonable amount of zoom happens.
99  //------------------------------------------------------------------------
100  p_scaleBox->setSingleStep(p_screenResolution * .05);
101  }
102  }
103 
104 
105  QList<QAction *> MosaicZoomTool::getViewActions() {
106  QList<QAction *> viewActs;
107 
108  viewActs.append(m_zoomInAction);
109  viewActs.append(m_zoomOutAction);
110  viewActs.append(m_zoomFitAction);
111 
112  return viewActs;
113  }
114 
115 
117  QAction *action = new QAction(this);
118  action->setIcon(getIcon("viewmag.png"));
119  action->setToolTip("Zoom (z)");
120  action->setShortcut(Qt::Key_Z);
121  QString text =
122  "<b>Function:</b> Zoom in or out of the current cube.<br><br>"
123  "This tool gives you a <b>click</b> to zoom by 2X and center on the "
124  "point you clicked on, a <b>right-click</b> to zoom out by 2X and center "
125  "on the point you clicked on, a <b>click and drag</b> box to best fit "
126  "the given area into the visible screen, a <b>right-click and drag</b> "
127  "box to zoom out and center on the center (smaller box means zoom out "
128  "more), and disables context menus on the mosaic scene."
129  "<p><b>Shortcut:</b> z</p> ";
130  action->setWhatsThis(text);
131  return action;
132  }
133 
134 
144  QWidget *hbox = new QWidget;
145 
146  QToolButton *zoomInButton = new QToolButton(hbox);
147  zoomInButton->setAutoRaise(true);
148  zoomInButton->setDefaultAction(m_zoomInAction);
149  zoomInButton->setIconSize(QSize(22, 22));
150 
151  QToolButton *zoomOutButton = new QToolButton(hbox);
152  zoomOutButton->setAutoRaise(true);
153  zoomOutButton->setDefaultAction(m_zoomOutAction);
154  zoomOutButton->setIconSize(QSize(22, 22));
155 
156  QToolButton *zoomFitButton = new QToolButton(hbox);
157  zoomFitButton->setAutoRaise(true);
158  zoomFitButton->setDefaultAction(m_zoomFitAction);
159  zoomFitButton->setIconSize(QSize(22, 22));
160 
161  p_scaleBox = new QDoubleSpinBox();
162  p_scaleBox->setRange(DBL_MIN, DBL_MAX);
163  p_scaleBox->setDecimals(8);
164  connect(p_scaleBox, SIGNAL(editingFinished()), this, SLOT(zoomManual()));
165 
166  QLabel *resolutionLabel = new QLabel("Meters per pixel");
167 
168  QHBoxLayout *layout = new QHBoxLayout(hbox);
169  layout->setMargin(0);
170  layout->addWidget(zoomInButton);
171  layout->addWidget(zoomOutButton);
172 
173  //-------------------------------------------
174  // These two actions are not quite ready yet.
175  // layout->addWidget(zoomActButton);
176  //-------------------------------------------
177  layout->addWidget(zoomFitButton);
178  layout->addWidget(p_scaleBox);
179  layout->addWidget(resolutionLabel);
180  layout->addStretch(1);
181  hbox->setLayout(layout);
182  return hbox;
183  }
184 
185 
186  void MosaicZoomTool::mouseButtonRelease(QPointF mouseLoc, Qt::MouseButton s) {
187  if(!isActive())
188  return;
189 
190  if(s == Qt::LeftButton)
191  zoomIn2X(mouseLoc);
192  else if(s == Qt::RightButton)
193  zoomOut2X(mouseLoc);
194  }
195 
196 
197  void MosaicZoomTool::mouseWheel(QPointF mouseLoc, int delta) {
198  static const double sensitivity = 60.0; // this causes factor of 2 changes
199  double scale = delta / sensitivity;
200 
201  if(delta < 0)
202  scale = 1.0 / (-delta / sensitivity);
203 
204  scale = limitZoomBy(scale);
205 
206  QPoint screenMouseLoc(getWidget()->getView()->mapFromScene(mouseLoc));
207  QPoint screenCenter(
208  getWidget()->getView()->viewport()->size().width() / 2,
209  getWidget()->getView()->viewport()->size().height() / 2);
210 
211  // We're going to do this by zooming on the mouse and then
212  // undo-ing the center in screen pixels.
213  zoomBy(scale, mouseLoc);
214 
215  // The new center screen pixel is:
216  // center - mouseLoc
217  QPoint desiredScreenCenter =
218  screenCenter + (screenCenter - screenMouseLoc);
219  QPointF newCenterPoint =
220  getWidget()->getView()->mapToScene(desiredScreenCenter);
221  getWidget()->getView()->centerOn(newCenterPoint);
222  }
223 
224 
229  void MosaicZoomTool::zoomIn2X(QPointF center) {
230  zoomBy(2.0, center);
231  }
232 
233 
238  void MosaicZoomTool::zoomOut2X(QPointF center) {
239  zoomBy(1.0 / 2.0, center);
240  }
241 
242 
247  void MosaicZoomTool::zoomActual(QPointF center) {
248  zoomBy(1.1, center);
249  }
250 
251 
252  double MosaicZoomTool::limitZoomBy(double factor) {
253  QMatrix matrix = getWidget()->getView()->matrix();
254  matrix = matrix.scale(factor, factor).inverted();
255 
256  int smallerDimension = getWidget()->getView()->width();
257  int largerDimension = getWidget()->getView()->height();
258 
259  if(smallerDimension > largerDimension) {
260  int tmp = smallerDimension;
261  smallerDimension = largerDimension;
262  largerDimension = tmp;
263  }
264 
265  QPointF point1 = matrix.map(QPointF(0, 0));
266  QPointF point2 = matrix.map(QPointF(smallerDimension, 0));
267 
268  // If the factor cannot be done, find the one that can
269  // This max zoom in factor isn't right; I haven't found the number
270  // that corresponds to the Qt bug(?) causing us to not pan correctly on
271  // the zoom in.
272  if((point2.x() - point1.x()) < 1) {
273  QMatrix origMatrix = getWidget()->getView()->matrix();
274  factor = smallerDimension / (origMatrix.m11() * 1.0);
275  }
276 
277  point1 = matrix.map(QPointF(0, 0));
278  point2 = matrix.map(QPointF(largerDimension, 0));
279 
280  if((point2.x() - point1.x()) > 1E10) {
281  QMatrix origMatrix = getWidget()->getView()->matrix();
282  factor = largerDimension / (origMatrix.m11() * 1E10);
283  }
284 
285  return factor;
286  }
287 
288 
295  void MosaicZoomTool::zoomBy(double factor, QPointF center) {
296  factor = limitZoomBy(factor);
297 
298  getWidget()->getView()->scale(factor, factor);
299 
300  if(!center.isNull()) {
301  getWidget()->getView()->centerOn(center);
302  }
303 
305  }
306 
307 
313  getWidget()->refit();
315  }
316 
317 
323 
324  }
325 
326 
333 
334  }
335 
336 
347  if(p_scaleBox) {
348  double x = p_screenResolution / p_scaleBox->value();
349  zoomBy(x);
350  }
351  }
352 
353 
360  if(isActive()) {
361  getWidget()->setCubesSelectable(false);
362  getWidget()->getView()->setContextMenuPolicy(Qt::NoContextMenu);
363  getWidget()->enableRubberBand(true);
364  }
365  else {
366  getWidget()->setCubesSelectable(true);
367  getWidget()->getView()->setContextMenuPolicy(Qt::DefaultContextMenu);
368  getWidget()->enableRubberBand(false);
369  }
370 
372  }
373 
374 
382  void MosaicZoomTool::rubberBandComplete(QRectF r, Qt::MouseButton s) {
383  if(!isActive())
384  return;
385 
386  double meters_pixel = 0.0;
387 
388  //--------------------------------------------------------------------
389  // We only user width or height to determine the desired meters/pixel.
390  // Which ever is larger.
391  //--------------------------------------------------------------------
392  if(r.width() > r.height()) {
393  meters_pixel = r.width() / getWidget()->getView()->viewport()->width();
394  }
395  else {
396  meters_pixel = r.height() / getWidget()->getView()->viewport()->height();
397  }
398 
399  // calculate the scale.
400  double scale = p_screenResolution / meters_pixel;
401 
402  // zooming in.
403  if(s == Qt::LeftButton) {
404  zoomBy(scale, r.center());
405  }
406 
407  // zooming out.
408  if(s == Qt::RightButton) {
409  zoomBy(1 / scale, r.center());
410  }
411 
413  }
414 
415 }
void updateTool()
This method updates the line edits text to the correct zoom value.
void zoomIn2X(QPointF center=QPointF())
Zooms in 2 times.
void zoomActual(QPointF center=QPointF())
Zoom back to 1 to 1.
void rubberBandComplete(QRectF r, Qt::MouseButton s)
This method is called when the RubberBandTool is complete.
QWidget * getToolBarWidget()
Creates the widget to add to the tool bar.
This widget encompasses the entire mosaic scene.
void zoomManual()
This method zooms by the value input in the line edit next to the zoom tools.
void zoomFitWidth()
Slot for the "Fit to Width" menu item on the Fit button.
Base class for the MosaicTools.
Definition: MosaicTool.h:37
void refit()
This method refits t:he items in the graphics view.
bool isActive() const
Returns the activeness of this toool.
Definition: MosaicTool.h:50
void zoomOut2X(QPointF center=QPointF())
Zoom out 2 times.
MosaicZoomTool(MosaicSceneWidget *)
MosaicZoomTool constructor.
void zoomFitHeight()
Slot for the "Fit to Heighth" menu item on the Fit button.
void zoomFit()
Fits the in the graphics view.
QAction * getPrimaryAction()
This method returns an action that is used to activate this tool.
void updateResolutionBox()
Updates the text in the screen resolution display box to the current screen resolution, in meters per pixel.
QPixmap getIcon(QString iconName) const
returns the path to the icon directory.
Definition: MosaicTool.cpp:115
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
void zoomBy(double factor, QPointF center=QPointF())
Zoom IN by the given factor.