Isis 3 Programmer Reference
IndependentCubeViewport.cpp
Go to the documentation of this file.
1 
22 
23 #include <QEvent>
24 #include <QIcon>
25 #include <QMouseEvent>
26 #include <QPainter>
27 #include <QPoint>
28 #include <QScrollBar>
29 #include <QRect>
30 
31 #include <iostream>
32 
33 #include "Camera.h"
34 #include "Projection.h"
35 #include "RingPlaneProjection.h"
36 #include "TProjection.h"
37 #include "Stretch.h"
38 #include "StretchTool.h"
39 #include "ViewportBuffer.h"
40 
41 using namespace std;
42 
43 
44 namespace Isis
45 {
46  IndependentCubeViewport::IndependentCubeViewport(Cube * cube,
47  CubeDataThread * cdt, QWidget * parent) :
48  CubeViewport(cube, cdt, parent)
49  {
50  panningPrevPoint = NULL;
51  bandingPoint1 = NULL;
52  bandingPoint2 = NULL;
53 
54  panningPrevPoint = new QPoint;
55  bandingPoint1 = new QPoint;
56  bandingPoint2 = new QPoint;
57 
58  leftClick = false;
59  banding = false;
60  zooming = false;
61  panning = false;
62  viewport()->setMouseTracking(true);
63  }
64 
65 
66  IndependentCubeViewport::~IndependentCubeViewport()
67  {
68  if (panningPrevPoint)
69  {
70  delete panningPrevPoint;
71  panningPrevPoint = NULL;
72  }
73 
74  if (bandingPoint1)
75  {
76  delete bandingPoint1;
77  bandingPoint1 = NULL;
78  }
79 
80  if (bandingPoint2)
81  {
82  delete bandingPoint2;
83  bandingPoint2 = NULL;
84  }
85  }
86 
87 
89  {
90  // Handle standard mouse tracking on the viewport
91  if (o == viewport())
92  {
93  QMouseEvent *m = (QMouseEvent *) e;
94  QPoint currentPosition(m->pos());
95  Qt::MouseButton b = (Qt::MouseButton)(m->button() + m->modifiers());
96 
97  switch (e->type())
98  {
99  case QEvent::Enter:
100  {
101 // viewport()->setMouseTracking(true);
102  emit mouseEnter();
103  break;
104  }
105  case QEvent::MouseMove:
106  {
107  if (panning)
108  emit synchronize(this);
109 
110  handleMouseMove(currentPosition);
111  break;
112  }
113  case QEvent::Leave:
114  {
115 // viewport()->setMouseTracking(false);
116  emit mouseLeave();
117  break;
118  }
119  case QEvent::MouseButtonPress:
120  {
121  handleMousePress(currentPosition, b);
122  break;
123  }
124  case QEvent::MouseButtonRelease:
125  {
126  handleMouseRelease(currentPosition);
127  emit synchronize(this);
128  break;
129  }
130  default:
131  {
132  return false;
133  }
134  }
135  }
136  else
137  {
138  return QAbstractScrollArea::eventFilter(o, e);
139  }
140  return true;
141  }
142 
143 
145  {
147 
148  QPainter painter(viewport());
149  painter.drawPixmap(0, 0, p_pixmap);
150 
151  if (banding)
152  {
153  QPen pen(QColor(255, 0, 0));
154  pen.setStyle(Qt::SolidLine);
155  painter.setPen(pen);
156  painter.drawRect(bandingRect());
157  }
158 
159  painter.end();
160  }
161 
162 
164  {
165  Stretch globalStretch = grayStretch();
167  stretchGray(globalStretch);
168  }
169 
170 
171  void IndependentCubeViewport::showEvent(QShowEvent * event)
172  {
173  QAbstractScrollArea::show();
174 
176  restretch(grayBuffer());
177  }
178 
179 
180  void IndependentCubeViewport::resetKnownGlobal()
181  {
182 
183  p_globalStretches->clear();
184  for (int i = 0; i < cubeBands(); i++)
185  p_globalStretches->append(NULL);
186 
187  if (isVisible())
188  grayBuffer()->addStretchAction();
189  }
190 
191 
192  void IndependentCubeViewport::cubeDataChanged(int cubeId,
193  const Isis::Brick * data)
194  {
195  if (data->SampleDimension() == cubeSamples() &&
196  data->LineDimension() == cubeLines() &&
197  data->Sample() == 1 &&
198  data->Line() == 1 &&
199  data->BandDimension() == 1 &&
200  data->Band() == grayBand() &&
201  cubeId == cubeID())
202  {
203  // reset the global stretch
204  Stretch *& globalStretch = (*p_globalStretches)[data->Band() - 1];
205 
206  if (globalStretch)
207  {
208  delete globalStretch;
209  globalStretch = NULL;
210  }
211 
212 
213  Stretch newGlobal = grayStretch();
214  newGlobal.ClearPairs();
215  Statistics stats;
216  stats.AddData(data->DoubleBuffer(), data->size());
217 
218  if (stats.ValidPixels() > 1 &&
219  fabs(stats.Minimum() - stats.Maximum()) > DBL_EPSILON)
220  {
221  Histogram hist(stats.BestMinimum(), stats.BestMaximum(), 65536);
222  hist.AddData(data->DoubleBuffer(), data->size());
223 
224  if (fabs(hist.Percent(0.5) - hist.Percent(99.5)) > DBL_EPSILON)
225  {
226  newGlobal.AddPair(hist.Percent(0.5), 0.0);
227  newGlobal.AddPair(hist.Percent(99.5), 255.0);
228  }
229  }
230 
231  if (newGlobal.Pairs() == 0)
232  {
233  newGlobal.AddPair(-DBL_MAX, 0.0);
234  newGlobal.AddPair(DBL_MAX, 255.0);
235  }
236 
237  globalStretch = new Stretch(newGlobal);
238 
239  if (isVisible())
240  stretchGray(newGlobal);
241  }
242 
243  CubeViewport::cubeDataChanged(cubeId, data);
244  }
245 
246 
247  void IndependentCubeViewport::handleMouseMove(QPoint p)
248  {
249  if (panning)
250  {
251  QPoint diff = *panningPrevPoint - p;
252  *panningPrevPoint = p;
253  scrollBy(diff.x(), diff.y());
254  }
255  else
256  {
257  if (banding)
258  {
259  *bandingPoint2 = p;
260  viewport()->repaint();
261  }
262 
263  track(p);
264  }
265  }
266 
267 
268  void IndependentCubeViewport::handleMousePress(QPoint p, Qt::MouseButton b)
269  {
270  bool ctrlPressed = ((b & Qt::ControlModifier) == Qt::ControlModifier);
271  bool shiftPressed = ((b & Qt::ShiftModifier) == Qt::ShiftModifier);
272  bool ctrlShiftPressed = ctrlPressed && shiftPressed;
273  leftClick = ((b & Qt::LeftButton) == Qt::LeftButton);
274 
275  *bandingPoint1 = p;
276  *bandingPoint2 = p;
277  if (ctrlPressed && !shiftPressed)
278  {
279  stretching = true;
280  banding = true;
281  }
282  else
283  {
284  if (ctrlShiftPressed)
285  {
286  panning = true;
287  *panningPrevPoint = p;
288  }
289  else
290  {
291  zooming = true;
292  banding = true;
293  }
294  }
295  }
296 
297 
298  void IndependentCubeViewport::handleMouseRelease(QPoint p)
299  {
300  banding = false;
301  *bandingPoint2 = p;
302  if (zooming)
303  {
304  zooming = false;
305  zoom();
306  }
307  else
308  {
309  if (panning)
310  {
311  panning = false;
312  }
313  else
314  {
315  if (stretching)
316  {
317  stretching = false;
318  if (leftClick)
319  stretch();
320  else
321  stretchKnownGlobal();
322  }
323  }
324  }
325  }
326 
327 
328  void IndependentCubeViewport::handleSynchronization(
329  IndependentCubeViewport * other)
330  {
331  if (!isVisible())
332  return;
333 
334  int deltaWidth = other->viewport()->width() - viewport()->width();
335  int deltaHeight = other->viewport()->height() - viewport()->height();
336 
337  double offsetXToCenter = deltaWidth / 2.0 + viewport()->width() / 2.0;
338  double offsetYToCenter = deltaHeight / 2.0 + viewport()->height() / 2.0;
339 
340  double offsetSampsToCenter = offsetXToCenter / other->scale();
341  double offsetLinesToCenter = offsetYToCenter / other->scale();
342 
343  double otherSS, otherSL; // SS = start sample, SL = start line :)
344  other->viewportToCube(0, 0, otherSS, otherSL);
345 
346  double thisCenterSamp = otherSS + offsetSampsToCenter;
347  double thisCenterLine = otherSL + offsetLinesToCenter;
348 
349  if (scale() == other->scale())
350  center(thisCenterSamp, thisCenterLine);
351  else
352  setScale(other->scale(), thisCenterSamp, thisCenterLine);
353  }
354 
355 
356  QRect IndependentCubeViewport::bandingRect()
357  {
358  QRect rect;
359  rect.setTop(qMin(bandingPoint1->y(), bandingPoint2->y()));
360  rect.setLeft(qMin(bandingPoint1->x(), bandingPoint2->x()));
361  rect.setBottom(qMax(bandingPoint1->y(), bandingPoint2->y()));
362  rect.setRight(qMax(bandingPoint1->x(), bandingPoint2->x()));
363 
364  return rect;
365  }
366 
367 
368  void IndependentCubeViewport::stretch()
369  {
370  QRect rect(bandingRect());
371  if (rect.width() == 0 || rect.height() == 0)
372  return;
373 
374  Stretch newStretch;
375 
376  newStretch = grayStretch();
377  newStretch.CopyPairs(StretchTool::stretchBuffer(grayBuffer(), rect));
378 
379  stretchGray(newStretch);
380  }
381 
382  void IndependentCubeViewport::track(const QPoint & p)
383  {
384  if (grayBuffer()->working())
385  {
386  emit cantTrack("busy", this);
387  return;
388  }
389 
390  double sample, line;
391  viewportToCube(p.x(), p.y(), sample, line);
392 
393  /* cerr << "cubeSamples() + 0.5: " << cubeSamples() + 0.5 << "\n"
394  << "cubeLines() + 0.5: " << cubeLines() + 0.5 << "\n"
395  << "sample: " << sample << "\n"
396  << "line: " << line << "\n";
397  */
398  // if sample and line in range then do tracking
399 
400  double dn;
401  if (sample >= 0.5 && sample <= cubeSamples() + 0.5 &&
402  line >= 0.5 && line <= cubeLines() + 0.5 &&
403  trackBuffer(grayBuffer(), p, dn))
404  {
405  bool camSucceeds = camera() && camera()->SetImage(sample, line);
406  bool projSucceeds = !camSucceeds && projection() &&
407  projection()->SetWorld(sample, line);
408 
409  // Determine the projection type if we have a projection
411  if (projSucceeds) projType = projection()->projectionType();
412 
413  if (camSucceeds || projSucceeds)
414  {
415  double lat = 0.0;
416  double lon = 0.0;
417 
418  if (camSucceeds)
419  {
420  lat = camera()->UniversalLatitude();
421  lon = camera()->UniversalLongitude();
422  }
423  else
424  {
425  // For now just put radius/az into lat/lon TODO do it better
426  if (projType == Projection::Triaxial) {
427  TProjection *tproj = (TProjection *) projection();
428  lat = tproj->Latitude();
429  lon = tproj->Longitude();
430  }
431  else { // Must be RingPlane
432  RingPlaneProjection *rproj = (RingPlaneProjection *) projection();
433  lat = rproj->RingRadius();
434  lon = rproj->RingLongitude();
435  }
436  }
437 
438  emit trackingChanged(sample, line, lat, lon, dn, this);
439  }
440  else
441  {
442  emit trackingChanged(sample, line, dn, this);
443  }
444  }
445  else
446  {
447  emit cantTrack("n/a", this);
448  }
449  }
450 
451 
452  bool IndependentCubeViewport::trackBuffer(ViewportBuffer * buffer,
453  const QPoint & p, double & dn)
454  {
455  const QRect rect(buffer->bufferXYRect());
456  bool success = rect.contains(p, true);
457  if (success)
458  {
459  const int bufX = p.x() - rect.left();
460  const int bufY = p.y() - rect.top();
461  dn = buffer->getLine(bufY)[bufX];
462  }
463 
464  return success;
465  }
466 
467 
468  void IndependentCubeViewport::zoom()
469  {
470  // cerr << "zooming!\n";
471  // To do the zooming we call setScale(double scale, int x, int y) which
472  // will scale the viewport after centering to x, y. Before we can call
473  // setScale however we must first calculate the new scale and the new
474  // center point.
475 
476  QRect rect = bandingRect();
477  int x = rect.x();
478  int y = rect.y();
479  double scale;
480 
481  // cerr << "topleft: " << rect.left() << ", " << rect.top() << "\n"
482  // << "bottomright: " << rect.right() << ", " << rect.bottom() << "\n\n";
483 
484  if (rect.topLeft() == rect.bottomRight())
485  {
486  // initialize zoom factor and invert if zooming out
487  double factor = 2.0;
488  if (!leftClick)
489  factor = 1.0 / factor;
490 
491  scale = this->scale() * factor;
492  }
493  else
494  {
495  if ((rect.width() < 5) || (rect.height() < 5))
496  {
497  viewport()->repaint();
498  return;
499  }
500 
501  x += rect.width() / 2;
502  y += rect.height() / 2;
503  double xscale = (double) viewport()->width() / (double) rect.width();
504  double yscale = (double) viewport()->height() / (double) rect.height();
505  scale = xscale < yscale ? xscale : yscale;
506 
507  if (!leftClick)
508  scale = 1.0 / scale;
509 
510  scale *= this->scale();
511  }
512 
513  // execute zoom
514  setScale(scale, x, y);
515  }
516 
517 }
double * DoubleBuffer() const
Returns the value of the shape buffer.
Definition: Buffer.h:154
Reads and stores visible DN values.
static Stretch stretchBuffer(ViewportBuffer *buffer, QRect rect)
This method computes the stretch over a region using the viewport buffer.
int Band(const int index=0) const
Returns the band position associated with a shape buffer index.
Definition: Buffer.cpp:178
void paintEvent(QPaintEvent *e)
Repaint the viewport.
void restretch(ViewportBuffer *)
This is called by internal viewport buffers when a stretch action should be performed.
static Stretch stretchBand(CubeViewport *cvp, StretchBand band)
This method computes the stretch over the entire cube.
Buffer for containing a three dimensional section of an image.
Definition: Brick.h:61
Namespace for the standard library.
int LineDimension() const
Returns the number of lines in the shape buffer.
Definition: Buffer.h:95
int size() const
Returns the total number of pixels in the shape buffer.
Definition: Buffer.h:113
bool eventFilter(QObject *o, QEvent *e)
Event filter to watch for mouse events on viewport.
int Sample(const int index=0) const
Returns the sample position associated with a shape buffer index.
Definition: Buffer.cpp:143
void CopyPairs(const Stretch &other)
Copies the stretch pairs from another Stretch object, but maintains special pixel values...
Definition: Stretch.cpp:407
int BandDimension() const
Returns the number of bands in the shape buffer.
Definition: Buffer.h:104
Pixel value mapper.
Definition: Stretch.h:72
int Line(const int index=0) const
Returns the line position associated with a shape buffer index.
Definition: Buffer.cpp:161
int SampleDimension() const
Returns the number of samples in the shape buffer.
Definition: Buffer.h:86
virtual void cubeDataChanged(int cubeId, const Isis::Brick *)
This method updates the internal viewport buffer based on changes in cube DN values.
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
virtual void paintEvent(QPaintEvent *e)
Repaint the viewport.
ProjectionType
This enum defines the subclasses of Projection supported in Isis.
Definition: Projection.h:182
void showEvent(QShowEvent *)
This method is called to initially show the viewport.
These projections are used to map triaxial and irregular-shaped bodies.
Definition: Projection.h:182