USGS

Isis 3.0 Object Programmers' Reference

Home

StretchTool.cpp
1 #include "StretchTool.h"
2 
3 #include <QHBoxLayout>
4 #include <QMenuBar>
5 #include <QPixmap>
6 #include <QSizePolicy>
7 #include <QToolBar>
8 #include <QValidator>
9 
10 #include "AdvancedStretchDialog.h"
11 #include "Brick.h"
12 #include "CubeViewport.h"
13 #include "Histogram.h"
14 #include "IException.h"
15 #include "IString.h"
16 #include "MainWindow.h"
17 #include "MdiCubeViewport.h"
18 #include "RubberBandTool.h"
19 #include "Statistics.h"
20 #include "Stretch.h"
21 #include "ToolPad.h"
22 #include "ViewportBuffer.h"
23 #include "ViewportMainWindow.h"
24 #include "Workspace.h"
25 
26 using namespace std;
27 
28 namespace Isis {
35  StretchTool::StretchTool(QWidget *parent) : Tool::Tool(parent) {
36  m_chipViewportStretch = NULL;
37  m_preGlobalStretches = NULL;
38  m_advancedStretch = NULL;
39 
41 
43  connect(m_advancedStretch, SIGNAL(stretchChanged()),
44  this, SLOT(advancedStretchChanged()));
45  connect(m_advancedStretch, SIGNAL(visibilityChanged()),
46  this, SLOT(updateTool()));
47 
48  QPushButton *hiddenButton = new QPushButton();
49  hiddenButton->setVisible(false);
50  hiddenButton->setDefault(true);
51 
52  m_stretchGlobal = new QAction(parent);
53  m_stretchGlobal->setShortcut(Qt::CTRL + Qt::Key_G);
54  m_stretchGlobal->setText("Global Stretch");
55  connect(m_stretchGlobal, SIGNAL(activated()), this, SLOT(stretchGlobal()));
56 
57  m_stretchRegional = new QAction(parent);
58  m_stretchRegional->setShortcut(Qt::CTRL + Qt::Key_R);
59  m_stretchRegional->setText("Regional Stretch");
60  connect(m_stretchRegional, SIGNAL(activated()), this, SLOT(stretchRegional()));
61 
62  // Emit a signal when an exception occurs and connect to the Warning object
63  // to display Warning icon and the message
64  ViewportMainWindow *parentMainWindow = qobject_cast<ViewportMainWindow *>(parent);
65  if (parentMainWindow) {
66  connect(this, SIGNAL(warningSignal(std::string &, const std::string)),
67  parentMainWindow, SLOT(displayWarning(std::string &, const std::string &)));
68  }
69  }
70 
71 
76  delete [] m_preGlobalStretches;
77  m_preGlobalStretches = NULL;
78 
79  delete m_chipViewportStretch;
80  m_chipViewportStretch = NULL;
81  }
82 
83 
93  QAction *action = new QAction(pad);
94  action->setIcon(QPixmap(toolIconDir() + "/stretch_global.png"));
95  action->setToolTip("Stretch (S)");
96  action->setShortcut(Qt::Key_S);
97  QString text =
98  "<b>Function:</b> Change the stretch range of the cube.\
99  <p><b>Shortcut:</b> S</p> ";
100  action->setWhatsThis(text);
101 
102  return action;
103  }
104 
105 
112  void StretchTool::addTo(QMenu *menu) {
113  menu->addAction(m_stretchGlobal);
114  menu->addAction(m_stretchRegional);
115  }
116 
117 
126  QWidget *StretchTool::createToolBarWidget(QStackedWidget *parent) {
127  QWidget *hbox = new QWidget(parent);
128 
129  QToolButton *butt = new QToolButton(hbox);
130  butt->setAutoRaise(true);
131  butt->setIconSize(QSize(22, 22));
132  butt->setIcon(QPixmap(toolIconDir() + "/regional_stretch-2.png"));
133  butt->setToolTip("Stretch");
134  QString text =
135  "<b>Function:</b> Automatically compute min/max stretch using viewed \
136  pixels in the band(s) of the active viewport. That is, only pixels \
137  that are visible in the viewport are used. \
138  If the viewport is in RGB color all three bands will be stretched. \
139  <p><b>Shortcut:</b> Ctrl+R</p> \
140  <p><b>Mouse:</b> Left click \
141  <p><b>Hint:</b> Left click and drag for a local stretch. Uses only \
142  pixels in the red marquee</p>";
143  butt->setWhatsThis(text);
144  connect(butt, SIGNAL(clicked()), this, SLOT(stretchRegional()));
146 
147  m_stretchBandComboBox = new QComboBox(hbox);
148  m_stretchBandComboBox->setEditable(false);
149  m_stretchBandComboBox->addItem("Red Band", Red);
150  m_stretchBandComboBox->addItem("Green Band", Green);
151  m_stretchBandComboBox->addItem("Blue Band", Blue);
152  m_stretchBandComboBox->addItem("All Bands", All);
153  m_stretchBandComboBox->setToolTip("Select Color");
154  text =
155  "<b>Function:</b> Selecting the color will allow the appropriate \
156  min/max to be seen and/or edited in text fields to the right.";
157 
158 // The All option implies the same min/max will be applied
159 // to all three colors (RGB) if either text field is edited";
160  m_stretchBandComboBox->setWhatsThis(text);
161  m_stretchBand = All;
162  m_stretchBandComboBox->setCurrentIndex(
164  connect(m_stretchBandComboBox, SIGNAL(currentIndexChanged(int)),
165  this, SLOT(stretchBandChanged(int)));
166 
167  QDoubleValidator *dval = new QDoubleValidator(hbox);
168  m_stretchMinEdit = new QLineEdit(hbox);
169  m_stretchMinEdit->setValidator(dval);
170  m_stretchMinEdit->setToolTip("Minimum");
171  text =
172  "<b>Function:</b> Shows the current minimum pixel value. Pixel values \
173  below minimum are shown as black. Pixel values above the maximum \
174  are shown as white or the highest intensity of red/green/blue \
175  if in color. Pixel values between the minimum and maximum are stretched \
176  linearly between black and white (or color component). \
177  <p><b>Hint:</b> You can manually edit the minimum but it must be \
178  less than the maximum.";
179  m_stretchMinEdit->setWhatsThis(text);
180  m_stretchMinEdit->setMaximumWidth(100);
181  connect(m_stretchMinEdit, SIGNAL(returnPressed()),
182  this, SLOT(changeStretch()));
183 
184  m_stretchMaxEdit = new QLineEdit(hbox);
185  m_stretchMaxEdit->setValidator(dval);
186  m_stretchMaxEdit->setToolTip("Maximum");
187  text =
188  "<b>Function:</b> Shows the current maximum pixel value. Pixel values \
189  below minimum are shown as black. Pixel values above the maximum \
190  are shown as white or the highest intensity of red/green/blue \
191  if in color. Pixel values between the minimum and maximum are stretched \
192  linearly between black and white (or color component). \
193  <p><b>Hint:</b> You can manually edit the maximum but it must be \
194  greater than the minimum";
195  m_stretchMaxEdit->setWhatsThis(text);
196  m_stretchMaxEdit->setMaximumWidth(100);
197  connect(m_stretchMaxEdit, SIGNAL(returnPressed()), this, SLOT(changeStretch()));
198 
199  // Create the two menus that drop down from the buttons
200  QMenu *copyMenu = new QMenu();
201  QMenu *globalMenu = new QMenu();
202 
203  m_copyBands = new QAction(parent);
204  m_copyBands->setText("to All Bands");
205  connect(m_copyBands, SIGNAL(triggered(bool)), this, SLOT(setStretchAcrossBands()));
206 
207  QAction *copyAll = new QAction(parent);
208  copyAll->setIcon(QPixmap(toolIconDir() + "/copy_stretch.png"));
209  copyAll->setText("to All Viewports");
210  connect(copyAll, SIGNAL(triggered(bool)), this, SLOT(setStretchAllViewports()));
211 
212  copyMenu->addAction(copyAll);
213  copyMenu->addAction(m_copyBands);
214 
215  m_copyButton = new QToolButton();
216  m_copyButton->setAutoRaise(true);
217  m_copyButton->setIconSize(QSize(22, 22));
218  m_copyButton->setIcon(QPixmap(toolIconDir() + "/copy_stretch.png"));
219  m_copyButton->setPopupMode(QToolButton::MenuButtonPopup);
220  m_copyButton->setMenu(copyMenu);
221  m_copyButton->setDefaultAction(copyAll);
222  m_copyButton->setToolTip("Copy");
223  text =
224  "<b>Function:</b> Copy the current stretch to all the \
225  active viewports. Or use the drop down menu to copy the current stretch \
226  to all the bands in the active viewport. \
227  <p><b>Hint:</b> Can reset the stretch to an automaticaly computed \
228  stretch by using the 'Reset' stretch button option. </p>";
229  m_copyButton->setWhatsThis(text);
230 
231  QAction *currentView = new QAction(parent);
232  currentView->setText("Active Viewport");
233  currentView->setIcon(QPixmap(toolIconDir() + "/global_stretch.png"));
234  globalMenu->addAction(currentView);
235  connect(currentView, SIGNAL(triggered(bool)), this, SLOT(stretchGlobal()));
236 
237  QAction *globalAll = new QAction(parent);
238  globalAll->setText("All Viewports");
239  globalMenu->addAction(globalAll);
240  connect(globalAll, SIGNAL(triggered(bool)), this, SLOT(stretchGlobalAllViewports()));
241 
242  QAction *globalBands = new QAction(parent);
243  globalBands->setText("All Bands");
244  globalMenu->addAction(globalBands);
245  connect(globalBands, SIGNAL(triggered(bool)), this, SLOT(stretchGlobalAllBands()));
246 
247  m_globalButton = new QToolButton(); //basically acts as a 'reset'
248  m_globalButton->setAutoRaise(true);
249  m_globalButton->setIconSize(QSize(22, 22));
250  m_globalButton->setPopupMode(QToolButton::MenuButtonPopup);
251  m_globalButton->setMenu(globalMenu);
252  m_globalButton->setDefaultAction(currentView);
253  m_globalButton->setToolTip("Reset");
254  text =
255  "<b>Function:</b> Reset the stretch to be automatically computed "
256  "using the statisics from the entire image. Use the drop down menu "
257  "to reset the stretch for all the bands in the active viewport or "
258  "to reset the stretch for all the viewports.";
259  m_globalButton->setWhatsThis(text);
260 
261  QPushButton *advancedButton = new QPushButton("Advanced");
262  connect(advancedButton, SIGNAL(clicked()), this, SLOT(showAdvancedDialog()));
263 
264  m_flashButton = new QPushButton("Show Global");
265  text =
266  "<b>Function:</b> While this button is pressed down, the visible stretch "
267  "will be the automatically computed stretch using the statisics from the "
268  "entire image. The original stretch is restored once you let up on this "
269  "button.";
270  m_flashButton->setWhatsThis(text);
271  connect(m_flashButton, SIGNAL(pressed()), this, SLOT(stretchChanged()));
272  connect(m_flashButton, SIGNAL(released()), this, SLOT(stretchChanged()));
273 
274  QHBoxLayout *layout = new QHBoxLayout(hbox);
275  layout->setMargin(0);
276  layout->addWidget(m_copyButton);
277  layout->addWidget(m_globalButton);
278  layout->addWidget(m_stretchRegionalButton);
279  layout->addWidget(m_stretchBandComboBox);
280  layout->addWidget(m_stretchMinEdit);
281  layout->addWidget(m_stretchMaxEdit);
282  layout->addWidget(advancedButton);
283  layout->addWidget(m_flashButton);
284  layout->addStretch(); // Pushes everything else left in the menu bar
285  hbox->setLayout(layout);
286 
287  return hbox;
288  }
289 
290 
296  if(m_advancedStretch->isVisible()) {
297  MdiCubeViewport *cvp = cubeViewport();
298 
299  if(!cvp) return;
300 
301  if(cvp->isGray() && !cvp->grayBuffer()->working()) {
303  updateTool();
304  }
305  else {
306  Histogram hist(histFromBuffer(cvp->grayBuffer()));
307 
308  if(hist.ValidPixels() > 0) {
310  }
311  }
312  }
313  //Otherwise it is in color mode
314  else if(!cvp->isGray() &&
315  !cvp->redBuffer()->working() &&
316  !cvp->greenBuffer()->working() &&
317  !cvp->blueBuffer()->working()) {
318  if(!m_advancedStretch->isRgbMode()) {
319  updateTool();
320  }
321  else {
322  Histogram redHist(histFromBuffer(cvp->redBuffer()));
323  Histogram grnHist(histFromBuffer(cvp->greenBuffer()));
324  Histogram bluHist(histFromBuffer(cvp->blueBuffer()));
325 
326  if(redHist.ValidPixels() > 0 &&
327  grnHist.ValidPixels() > 0 &&
328  bluHist.ValidPixels() > 0) {
329  m_advancedStretch->updateHistograms(redHist, grnHist, bluHist);
330  }
331  }
332  }
333  }
334  }
335 
343  {
344  if(m_advancedStretch->isVisible()) {
345  MdiCubeViewport *cvp = cubeViewport();
346 
347  if(!cvp->isGray() &&
348  !cvp->redBuffer()->working() &&
349  !cvp->greenBuffer()->working() &&
350  !cvp->blueBuffer()->working()) {
351 
352  Histogram redHist(histFromBuffer(cvp->redBuffer()));
353  Histogram grnHist(histFromBuffer(cvp->greenBuffer()));
354  Histogram bluHist(histFromBuffer(cvp->blueBuffer()));
355  Stretch redStretch(cvp->redStretch());
356  Stretch grnStretch(cvp->greenStretch());
357  Stretch bluStretch(cvp->blueStretch());
358 
359  m_advancedStretch->updateForRGBMode(redStretch, redHist,
360  grnStretch, grnHist,
361  bluStretch, bluHist);
362  }
363  }
364  }
365 
371  }
372 
373 
380  if(m_advancedStretch->isVisible()) {
381  m_advancedStretch->enable(true);
382  //If the viewport is in gray mode
383  if(cvp->isGray() && !cvp->grayBuffer()->working()) {
384  Histogram hist(histFromBuffer(cvp->grayBuffer()));
385  Stretch stretch(cvp->grayStretch());
386  m_advancedStretch->enableGrayMode(stretch, hist);
387  }
388  //Otherwise it is in color mode
389  else if(!cvp->isGray() &&
390  !cvp->redBuffer()->working() &&
391  !cvp->greenBuffer()->working() &&
392  !cvp->blueBuffer()->working()) {
393  Histogram redHist(histFromBuffer(cvp->redBuffer()));
394  Histogram grnHist(histFromBuffer(cvp->greenBuffer()));
395  Histogram bluHist(histFromBuffer(cvp->blueBuffer()));
396  Stretch redStretch(cvp->redStretch());
397  Stretch grnStretch(cvp->greenStretch());
398  Stretch bluStretch(cvp->blueStretch());
399  m_advancedStretch->enableRgbMode(redStretch, redHist,
400  grnStretch, grnHist,
401  bluStretch, bluHist);
402  }
403  else {
404  m_advancedStretch->enable(false);
405  }
406  }
407  else {
408  m_advancedStretch->enable(false);
409  }
410  }
411 
412 
418  CubeViewport *cvp = cubeViewport();
419 
420  if(cvp == NULL) {
421  //If the current viewport is NULL and the advanced dialog is visible, hide it
422  if(m_advancedStretch->isVisible()) {
423  m_advancedStretch->hide();
424  }
425  }
426  else {
427  if(!m_advancedStretch->enabled() ||
428  m_advancedStretch->isRgbMode() != !cvp->isGray()) {
429  setCubeViewport(cvp);
430  }
431  }
432 
433  if(cvp && cvp->isGray()) {
434  m_copyBands->setEnabled(true);
435  m_stretchBandComboBox->setShown(false);
436  m_stretchMinEdit->show();
437  m_stretchMaxEdit->show();
438  }
439  else if(cvp) {
440  m_copyBands->setEnabled(true);
441  m_stretchBandComboBox->setShown(true);
443  }
444  else {
445  m_copyBands->setEnabled(false);
446  m_stretchBandComboBox->setShown(false);
447  }
448 
449  if(m_advancedStretch->isVisible()) {
450  m_stretchMinEdit->setEnabled(false);
451  m_stretchMaxEdit->setEnabled(false);
452  }
453  else {
454  m_stretchMinEdit->setEnabled(true);
455  m_stretchMaxEdit->setEnabled(true);
456  }
457 
458  stretchChanged();
460  }
461 
462 
471  // Yeah this is a hack... but it's necessary to make this tool
472  // do anything while its not the active tool.
473  connect(cvp, SIGNAL(screenPixelsChanged()), this, SLOT(updateHistograms()));
474  QRect rect(0, 0, cvp->viewport()->width(), cvp->viewport()->height());
475 
476  if(bandId == (int)Gray) {
477  if(cvp->grayBuffer() && cvp->grayBuffer()->hasEntireCube()) {
478  Stretch newStretch = cvp->grayStretch();
479  newStretch.CopyPairs(stretchBuffer(cvp->grayBuffer(), rect));
480  cvp->stretchGray(newStretch);
481  }
482  else {
483  Stretch newStretch = stretchBand(cvp, (StretchBand)bandId);
484  cvp->stretchGray(newStretch);
485  }
486  }
487  else
488  {
489  if(bandId == (int)Red || bandId == (int)All) {
490  if(cvp->redBuffer() && cvp->redBuffer()->hasEntireCube()) {
491  Stretch newStretch = cvp->redStretch();
492  newStretch.CopyPairs(stretchBuffer(cvp->redBuffer(), rect));
493  cvp->stretchRed(newStretch);
494  }
495  else {
496  Stretch newStretch = stretchBand(cvp, Red);
497  cvp->stretchRed(newStretch);
498  }
499  }
500  if(bandId == (int)Green || bandId == (int)All) {
501  if(cvp->greenBuffer() && cvp->greenBuffer()->hasEntireCube()) {
502  Stretch newStretch = cvp->greenStretch();
503  newStretch.CopyPairs(stretchBuffer(cvp->greenBuffer(), rect));
504  cvp->stretchGreen(newStretch);
505  }
506  else {
507  Stretch newStretch = stretchBand(cvp, Green);
508  cvp->stretchGreen(newStretch);
509  }
510  }
511  if(bandId == (int)Blue || bandId == (int)All) {
512  if(cvp->blueBuffer() && cvp->blueBuffer()->hasEntireCube()) {
513  Stretch newStretch = cvp->blueStretch();
514  newStretch.CopyPairs(stretchBuffer(cvp->blueBuffer(), rect));
515  cvp->stretchBlue(newStretch);
516  }
517  else {
518  Stretch newStretch = stretchBand(cvp, Blue);
519  cvp->stretchBlue(newStretch);
520  }
521  }
522  }
523  stretchChanged();
524  }
525 
526 
533  MdiCubeViewport *cvp = cubeViewport();
534  if(cvp == NULL) return;
535 
536  if(m_flashButton->isDown()) {
537  if(!m_preGlobalStretches) {
538  m_preGlobalStretches = new Stretch[4];
539  m_preGlobalStretches[0] = cvp->grayStretch();
540  m_preGlobalStretches[1] = cvp->redStretch();
542  m_preGlobalStretches[3] = cvp->blueStretch();
543  }
544 
545  cvp->stretchKnownGlobal();
546  return;
547  }
548  else if(m_preGlobalStretches) {
549  if(cvp->isGray()) {
551  }
552  else {
556  }
557 
558  delete [] m_preGlobalStretches;
559  m_preGlobalStretches = NULL;
560  }
561 
562  double min = 0, max = 0;
563  //If the viewport is in gray mode
564  if(cvp->isGray()) {
565  //Get the min/max from the current stretch
566  Stretch stretch = cvp->grayStretch();
567  min = stretch.Input(0);
568  max = stretch.Input(stretch.Pairs() - 1);
569  }
570 
571  //Otherwise it is in color mode
572  else {
573  Stretch rstretch = cvp->redStretch();
574  Stretch gstretch = cvp->greenStretch();
575  Stretch bstretch = cvp->blueStretch();
576 
577  //Get the min/max from the current stretch
578  if(m_stretchBand == Red) {
579  min = rstretch.Input(0);
580  max = rstretch.Input(rstretch.Pairs() - 1);
581  }
582  else if(m_stretchBand == Green) {
583  min = gstretch.Input(0);
584  max = gstretch.Input(gstretch.Pairs() - 1);
585  }
586  else if(m_stretchBand == Blue) {
587  min = bstretch.Input(0);
588  max = bstretch.Input(bstretch.Pairs() - 1);
589  }
590  }
591 
592  //Set the min/max text fields
593  if(m_stretchBand != All || cvp->isGray()) {
594  QString strMin;
595  strMin.setNum(min);
596  m_stretchMinEdit->setText(strMin);
597 
598  QString strMax;
599  strMax.setNum(max);
600  m_stretchMaxEdit->setText(strMax);
601  }
602 
603  if(m_advancedStretch->isVisible()) {
604  if(m_stretchBand == All){
606  }
608  }
609  }
610 
611 
617  CubeViewport *cvp = cubeViewport();
618  if(cvp == NULL) return;
619 
620  if(!m_advancedStretch->isRgbMode()) {
621  Stretch grayStretch = cvp->grayStretch();
622  grayStretch.ClearPairs();
624  cvp->stretchGray(grayStretch);
625 
626  // send the stretch to any ChipViewports that want to listen
627  *m_chipViewportStretch = grayStretch;
629  }
630  else {
631  Stretch redStretch = cvp->redStretch();
632  redStretch.ClearPairs();
634  cvp->stretchRed(redStretch);
635 
636  Stretch grnStretch = cvp->greenStretch();
637  grnStretch.ClearPairs();
639  cvp->stretchGreen(grnStretch);
640 
641  Stretch bluStretch = cvp->blueStretch();
642  bluStretch.ClearPairs();
644  cvp->stretchBlue(bluStretch);
645  }
646  stretchChanged();
647  }
648 
649 
657  MdiCubeViewport *cvp = cubeViewport();
658  if(cvp == NULL) return;
659 
660  // Make sure the user didn't enter bad min/max and if so fix it
661  double min = m_stretchMinEdit->text().toDouble();
662  double max = m_stretchMaxEdit->text().toDouble();
663 
664  if(min >= max || m_stretchMinEdit->text() == "" ||
665  m_stretchMaxEdit->text() == "") {
666  updateTool();
667  return;
668  }
669 
670  //The viewport is in gray mode
671  if(cvp->isGray()) {
672  Stretch stretch = cvp->grayStretch();
673  stretch.ClearPairs();
674  stretch.AddPair(min, 0.0);
675  stretch.AddPair(max, 255.0);
676 
677  // send the stretch to any ChipViewports that want to listen
678  *m_chipViewportStretch = stretch;
680 
681  cvp->stretchGray(stretch);
682  }
683  //Otherwise the viewport is in color mode
684  else {
685  Stretch redStretch = cvp->redStretch();
686  Stretch greenStretch = cvp->greenStretch();
687  Stretch blueStretch = cvp->blueStretch();
688 
689  if(m_stretchBand == Red) {
690  redStretch.ClearPairs();
691  redStretch.AddPair(min, 0.0);
692  redStretch.AddPair(max, 255.0);
693  }
694  if(m_stretchBand == Green) {
695  greenStretch.ClearPairs();
696  greenStretch.AddPair(min, 0.0);
697  greenStretch.AddPair(max, 255.0);
698  }
699  if(m_stretchBand == Blue) {
700  blueStretch.ClearPairs();
701  blueStretch.AddPair(min, 0.0);
702  blueStretch.AddPair(max, 255.0);
703  }
704 
705  cvp->stretchRed(redStretch);
706  cvp->stretchGreen(greenStretch);
707  cvp->stretchBlue(blueStretch);
708  }
709 
710  stretchChanged();
711  }
712 
713 
719  if(m_advancedStretch->isVisible()) return;
720 
721  if(cubeViewport()) {
723  m_advancedStretch->show();
724  }
725 
726  updateTool();
727  }
728 
729 
735  CubeViewport *cvp = cubeViewport();
736  if(cvp == NULL) return;
737 
738  stretchGlobal(cvp);
739  }
740 
741 
746  CubeViewport *cvp = cubeViewport();
747  if(cvp == NULL) return;
748 
749  cvp->forgetStretches();
750  stretchGlobal(cvp);
751  }
752 
753 
759  cvp->stretchKnownGlobal();
760  stretchChanged();
761  }
762 
763 
769  for(int i = 0; i < (int)cubeViewportList()->size(); i++) {
770  CubeViewport *cvp = cubeViewportList()->at(i);
771 
772  stretchGlobal(cvp);
773  }
774  }
775 
776 
782  CubeViewport *cvp = cubeViewport();
783  if(cvp == NULL) return;
784 
785  stretchRegional(cvp);
786  }
787 
793  QRect rect(0, 0, cvp->viewport()->width(), cvp->viewport()->height());
794 
795  stretchRect(cvp, rect);
796  }
797 
798 
806  CubeViewport *cvp = cubeViewport();
807  if(cvp == NULL) return;
808  if(!rubberBandTool()->isValid()) return;
809 
810  QRect rubberBandRect = rubberBandTool()->rectangle();
811  //Return if the width or height is zero
812  if(rubberBandRect.width() == 0 || rubberBandRect.height() == 0) return;
813 
814  stretchRect(cvp, rubberBandRect);
815  }
816 
817 
824  void StretchTool::stretchRect(CubeViewport *cvp, QRect rect) {
825  Stretch newStretch;
826  if(cvp->isGray()) {
827  newStretch = cvp->grayStretch();
828  newStretch.ClearPairs();
829  newStretch.CopyPairs(stretchBuffer(cvp->grayBuffer(), rect));
830  cvp->stretchGray(newStretch);
831 
832  // send the stretch to any ChipViewports that want to listen
833  *m_chipViewportStretch = newStretch;
835  }
836  else {
837  if (m_stretchBand==Red || m_stretchBand==All) {
838  newStretch = cvp->redStretch();
839  newStretch.ClearPairs();
840  newStretch.CopyPairs(stretchBuffer(cvp->redBuffer(), rect));
841  cvp->stretchRed(newStretch);
842  }
844  newStretch = cvp->greenStretch();
845  newStretch.ClearPairs();
846  newStretch.CopyPairs(stretchBuffer(cvp->greenBuffer(), rect));
847  cvp->stretchGreen(newStretch);
848  }
850  newStretch = cvp->blueStretch();
851  newStretch.ClearPairs();
852  newStretch.CopyPairs(stretchBuffer(cvp->blueBuffer(), rect));
853  cvp->stretchBlue(newStretch);
854  }
855  if(m_stretchBand != Red && m_stretchBand != Blue &&
858  "Unknown stretch band",
859  _FILEINFO_);
860  }
861  }
862 
863  stretchChanged();
864  }
865 
866 
874  void StretchTool::mouseButtonRelease(QPoint start, Qt::MouseButton s) {
875  CubeViewport *cvp = cubeViewport();
876  if(cvp == NULL) return;
877 
878  // Call the parent Tool function to reset the Warning as different activity is
879  // taking place
880  Tool::mouseButtonRelease(start, s);
881 
882  if(s == Qt::RightButton) {
883  stretchGlobal(cvp);
884 
885  // notify any ChipViewports listening that the CubeViewport was stretched
886  // back to global
887  emit stretchChipViewport(NULL, cvp);
888 
889  // Resets the RubberBandTool on screen.
891  }
892  }
893 
899  rubberBandTool()->enable(RubberBandTool::RectangleMode);
900  rubberBandTool()->setDrawActiveViewportOnly(true);
901  }
902 
903 
910  CubeViewport *cvp = cubeViewport();
911  if(cvp == NULL) return;
912 
913  double min = m_stretchMinEdit->text().toDouble();
914  double max = m_stretchMaxEdit->text().toDouble();
915 
916  Stretch stretch;
917  if(cvp->isGray()) {
918  stretch = cvp->grayStretch();
919  stretch.ClearPairs();
920  stretch.AddPair(min, 0.0);
921  stretch.AddPair(max, 255.0);
922  }
923  else if(m_stretchBand == Red) {
924  stretch = cvp->redStretch();
925  stretch.ClearPairs();
926  stretch.AddPair(min, 0.0);
927  stretch.AddPair(max, 255.0);
928  cvp->stretchGreen(stretch);
929  cvp->stretchBlue(stretch);
930  }
931  else if(m_stretchBand == Green) {
932  stretch = cvp->greenStretch();
933  stretch.ClearPairs();
934  stretch.AddPair(min, 0.0);
935  stretch.AddPair(max, 255.0);
936  cvp->stretchRed(stretch);
937  cvp->stretchBlue(stretch);
938  }
939  else if(m_stretchBand == Blue) {
940  stretch = cvp->blueStretch();
941  stretch.ClearPairs();
942  stretch.AddPair(min, 0.0);
943  stretch.AddPair(max, 255.0);
944  cvp->stretchRed(stretch);
945  cvp->stretchGreen(stretch);
946  }
947  else {
948  return;
949  }
950 
951  cvp->setAllBandStretches(stretch);
952  }
953 
954 
961  CubeViewport *thisViewport = cubeViewport();
962 
963  if(thisViewport == NULL) return;
964 
965  for(int i = 0; i < (int)cubeViewportList()->size(); i++) {
966  CubeViewport *cvp = cubeViewportList()->at(i);
967 
968  if(thisViewport->isGray() && cvp->isGray()) {
969  Stretch newStretch(cvp->grayStretch());
970  newStretch.CopyPairs(thisViewport->grayStretch());
971  cvp->stretchGray(newStretch);
972  }
973  else if(!thisViewport->isGray() && !cvp->isGray()) {
974  Stretch newStretchRed(cvp->redStretch());
975  newStretchRed.CopyPairs(thisViewport->redStretch());
976  cvp->stretchRed(newStretchRed);
977 
978  Stretch newStretchGreen(cvp->greenStretch());
979  newStretchGreen.CopyPairs(thisViewport->greenStretch());
980  cvp->stretchGreen(newStretchGreen);
981 
982  Stretch newStretchBlue(cvp->blueStretch());
983  newStretchBlue.CopyPairs(thisViewport->blueStretch());
984  cvp->stretchBlue(newStretchBlue);
985  }
986  else if(!thisViewport->isGray() && cvp->isGray()) {
987  // don't copy rgb to gray
988  }
989  else if(thisViewport->isGray() && !cvp->isGray()) {
990  // don't copy gray stretches to rgb
991  }
992  }
993 
994  stretchChanged();
995  }
996 
997 
1005  //Get the statistics and histogram from the region
1006  Statistics stats = statsFromBuffer(buffer, rect);
1007  Stretch stretch;
1008  if(stats.ValidPixels() > 1 &&
1009  fabs(stats.Minimum() - stats.Maximum()) > DBL_EPSILON) {
1010  Histogram hist = histFromBuffer(buffer, rect,
1011  stats.BestMinimum(), stats.BestMaximum());
1012 
1013  if(fabs(hist.Percent(0.5) - hist.Percent(99.5)) > DBL_EPSILON) {
1014  stretch.AddPair(hist.Percent(0.5), 0.0);
1015  stretch.AddPair(hist.Percent(99.5), 255.0);
1016  }
1017  }
1018 
1019  if(stretch.Pairs() == 0) {
1020  stretch.AddPair(-DBL_MAX, 0.0);
1021  stretch.AddPair(DBL_MAX, 255.0);
1022  }
1023 
1024  return stretch;
1025  }
1026 
1027 
1035 
1036  int bandNum = cvp->grayBand();
1037  Stretch stretch = cvp->grayStretch();
1038  if(band == Red) {
1039  bandNum = cvp->redBand();
1040  stretch = cvp->redStretch();
1041  }
1042  else if(band == Green) {
1043  bandNum = cvp->greenBand();
1044  stretch = cvp->greenStretch();
1045  }
1046  else if(band == Blue) {
1047  bandNum = cvp->blueBand();
1048  stretch = cvp->blueStretch();
1049  }
1050 
1051  Statistics stats = statsFromCube(cvp->cube(), bandNum);
1052  Histogram hist = histFromCube(cvp->cube(), bandNum,
1053  stats.BestMinimum(), stats.BestMaximum());
1054 
1055  stretch.ClearPairs();
1056  if(fabs(hist.Percent(0.5) - hist.Percent(99.5)) > DBL_EPSILON) {
1057  stretch.AddPair(hist.Percent(0.5), 0.0);
1058  stretch.AddPair(hist.Percent(99.5), 255.0);
1059  }
1060  else {
1061  stretch.AddPair(-DBL_MAX, 0.0);
1062  stretch.AddPair(DBL_MAX, 255.0);
1063  }
1064 
1065  return stretch;
1066  }
1067 
1078  Statistics stats;
1079  Brick brick(cube->sampleCount(), 1, 1, cube->pixelType());
1080 
1081  for(int line = 0; line < cube->lineCount(); line++) {
1082  brick.SetBasePosition(0, line, band);
1083  cube->read(brick);
1084  stats.AddData(brick.DoubleBuffer(), cube->sampleCount());
1085  }
1086 
1087  return stats;
1088  }
1089 
1090 
1101  QRect rect) {
1102  if(buffer->working()) {
1104  "Cannot stretch while the cube is still loading",
1105  _FILEINFO_);
1106  }
1107 
1108  QRect dataArea = QRect(buffer->bufferXYRect().intersected(rect));
1109  Statistics stats;
1110 
1111  for(int y = dataArea.top();
1112  !dataArea.isNull() && y <= dataArea.bottom();
1113  y++) {
1114  const std::vector<double> &line = buffer->getLine(y - buffer->bufferXYRect().top());
1115 
1116  for(int x = dataArea.left(); x < dataArea.right(); x++) {
1117  stats.AddData(line[x - buffer->bufferXYRect().left()]);
1118  }
1119  }
1120 
1121  return stats;
1122  }
1123 
1136  double min, double max) {
1137  Histogram hist(min, max);
1138  Brick brick(cube->sampleCount(), 1, 1, cube->pixelType());
1139 
1140  for(int line = 0; line < cube->lineCount(); line++) {
1141  brick.SetBasePosition(0, line, band);
1142  cube->read(brick);
1143  hist.AddData(brick.DoubleBuffer(), cube->sampleCount());
1144  }
1145 
1146  return hist;
1147  }
1148 
1149 
1158  Statistics stats = statsFromBuffer(buffer, buffer->bufferXYRect());
1159  return histFromBuffer(buffer, buffer->bufferXYRect(),
1160  stats.BestMinimum(), stats.BestMaximum());
1161 
1162  }
1163 
1164 
1177  QRect rect, double min, double max) {
1178  QRect dataArea = QRect(buffer->bufferXYRect().intersected(rect));
1179 
1180  try {
1181  Histogram hist(min, max);
1182 
1183  for(int y = dataArea.top(); !dataArea.isNull() && y <= dataArea.bottom(); y++) {
1184  const std::vector<double> &line = buffer->getLine(y - buffer->bufferXYRect().top());
1185  hist.AddData(&line.front() + (dataArea.left() - buffer->bufferXYRect().left()), dataArea.width());
1186  }
1187 
1188  return hist;
1189  }
1190  catch(IException &e) {
1191  // get the min and max DN values of the data area
1192  IString sMin(min);
1193  IString sMax(max);
1194  std::string msg = "Insufficient data Min [" + sMin + "], Max [" + sMax + "]";
1195  msg += " in the stretch area.";
1196 
1197  // Emit signal to the parent tool to display Warning object with the warning message
1198  //emit warningSignal(msg, e.Errors());
1199 
1200  throw IException(e, IException::Unknown, msg, _FILEINFO_);
1201  }
1202  }
1203 
1204 
1205 
1210 
1212  m_stretchBandComboBox->currentIndex()
1213  ).toInt();
1214 
1215  if(m_stretchBand == All) {
1216  m_stretchMinEdit->hide();
1217  m_stretchMaxEdit->hide();
1218  }
1219  else {
1220  m_stretchMinEdit->show();
1221  m_stretchMaxEdit->show();
1222  }
1223  stretchChanged();
1224  }
1225 
1226 
1341 }