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