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
30using namespace std;
31
32
33namespace 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
77 bool IndependentCubeViewport::eventFilter(QObject * o, QEvent * e)
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
133 void IndependentCubeViewport::paintEvent(QPaintEvent * e)
134 {
135 CubeViewport::paintEvent(e);
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
152 void IndependentCubeViewport::restretch(ViewportBuffer * buffer)
153 {
154 CubeStretch globalStretch = grayStretch();
155 globalStretch.CopyPairs(StretchTool::stretchBand(this, StretchTool::Gray));
156 stretchGray(globalStretch);
157 }
158
159
160 void IndependentCubeViewport::showEvent(QShowEvent * event)
161 {
162 QAbstractScrollArea::show();
163
164 CubeViewport::showEvent(event);
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
399 Projection::ProjectionType projType = Projection::Triaxial;
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}
Buffer for containing a three dimensional section of an image.
Definition Brick.h:45
int size() const
Returns the total number of pixels in the shape buffer.
Definition Buffer.h:97
int Line(const int index=0) const
Returns the line position associated with a shape buffer index.
Definition Buffer.cpp:145
double * DoubleBuffer() const
Returns the value of the shape buffer.
Definition Buffer.h:138
int LineDimension() const
Returns the number of lines in the shape buffer.
Definition Buffer.h:79
int Band(const int index=0) const
Returns the band position associated with a shape buffer index.
Definition Buffer.cpp:162
int BandDimension() const
Returns the number of bands in the shape buffer.
Definition Buffer.h:88
int SampleDimension() const
Returns the number of samples in the shape buffer.
Definition Buffer.h:70
int Sample(const int index=0) const
Returns the sample position associated with a shape buffer index.
Definition Buffer.cpp:127
Stores stretch information for a cube.
Definition CubeStretch.h:27
Reads and stores visible DN values.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
Namespace for the standard library.