1#include "StretchTool.h" 
   14#include <QStackedWidget> 
   18#include <QInputDialog> 
   20#include "AdvancedStretchDialog.h" 
   23#include "CubeViewport.h" 
   25#include "IException.h" 
   27#include "MainWindow.h" 
   28#include "MdiCubeViewport.h" 
   29#include "RubberBandTool.h" 
   30#include "Statistics.h" 
   33#include "ViewportBuffer.h" 
   34#include "ViewportMainWindow.h" 
   37#include "CubeStretch.h" 
   67    QPushButton *hiddenButton = 
new QPushButton();
 
   68    hiddenButton->setVisible(
false);
 
   69    hiddenButton->setDefault(
true);
 
   84    if (parentMainWindow) {
 
   85      connect(
this, SIGNAL(
warningSignal(std::string &, 
const std::string)),
 
   86              parentMainWindow, SLOT(displayWarning(std::string &, 
const std::string &)));
 
 
  113    action->setIcon(QPixmap(
toolIconDir() + 
"/stretch_global.png"));
 
  114    action->setToolTip(
"Stretch (S)");
 
  115    action->setShortcut(Qt::Key_S);
 
  117      "<b>Function:</b>  Change the stretch range of the cube.\ 
  118      <p><b>Shortcut:</b>  S</p> ";
 
  119    action->setWhatsThis(text);
 
 
  148    QToolButton *butt = 
new QToolButton(hbox);
 
  149    butt->setAutoRaise(
true);
 
  150    butt->setIconSize(QSize(22, 22));
 
  151    butt->setIcon(QPixmap(
toolIconDir() + 
"/regional_stretch-2.png"));
 
  152    butt->setToolTip(
"Stretch");
 
  154      "<b>Function:</b> Automatically compute min/max stretch using viewed \ 
  155      pixels in the band(s) of the active viewport.  That is, only pixels \ 
  156      that are visible in the viewport are used. \ 
  157      If the viewport is in RGB color all three bands will be stretched. \ 
  158      <p><b>Shortcut:</b>  Ctrl+R</p> \ 
  159      <p><b>Mouse:</b>  Left click \ 
  160      <p><b>Hint:</b>  Left click and drag for a local stretch.  Uses only \ 
  161      pixels in the red marquee</p>";
 
  162    butt->setWhatsThis(text);
 
  174      "<b>Function:</b> Selecting the color will allow the appropriate \ 
  175      min/max to be seen and/or edited in text fields to the right.";
 
  190      "<b>Function:</b> Select the minimum & maximum value types to \ 
  191      set the stretch to. The four options are: \ 
  192      <p>- Default: Min and max values are set to the \ 
  193        0.5 and 99.5 percentiles, respectively. \ 
  194      <p>- Best: The better of the absolute min/max or the \ 
  195        Chebyshev min/max. The better value is considered the value \ 
  196        closest to the mean. \ 
  197      <p>- Absolute: The absolute min/max value of all valid pixels. \ 
  198      <p>- Chebyshev: The min/max value such that a certain percentage \ 
  199        of data will fall within K standard deviations of the average \ 
  200        (Chebyshev's Theorem). It can be used to obtain a value that \ 
  201        does not include statistical outliers.";
 
  210    QDoubleValidator *dval = 
new QDoubleValidator(hbox);
 
  215      "<b>Function:</b> Shows the current minimum pixel value.  Pixel values \ 
  216      below minimum are shown as black.  Pixel values above the maximum \ 
  217      are shown as white or the highest intensity of red/green/blue \ 
  218      if in color. Pixel values between the minimum and maximum are stretched \ 
  219      linearly between black and white (or color component). \ 
  220      <p><b>Hint:</b>  You can manually edit the minimum but it must be \ 
  221      less than the maximum.";
 
  231      "<b>Function:</b> Shows the current maximum pixel value.  Pixel values \ 
  232      below minimum are shown as black.  Pixel values above the maximum \ 
  233      are shown as white or the highest intensity of red/green/blue \ 
  234      if in color. Pixel values between the minimum and maximum are stretched \ 
  235      linearly between black and white (or color component). \ 
  236      <p><b>Hint:</b>  You can manually edit the maximum but it must be \ 
  237      greater than the minimum";
 
  251    copyAll->setIcon(QPixmap(
toolIconDir() + 
"/copy_stretch.png"));
 
  252    copyAll->setText(
"to All Viewports");
 
  255    copyMenu->addAction(copyAll);
 
  262    m_copyButton->setPopupMode(QToolButton::MenuButtonPopup);
 
  267      "<b>Function:</b> Copy the current stretch to all the \ 
  268      active viewports. Or use the drop down menu to copy the current stretch \ 
  269      to all the  bands in the active viewport. \ 
  270      <p><b>Hint:</b>  Can reset the stretch to an automaticaly computed \ 
  271      stretch by using the 'Reset' stretch button option. </p>";
 
  275    currentView->setText(
"Active Viewport");
 
  276    currentView->setIcon(QPixmap(
toolIconDir() + 
"/global_stretch.png"));
 
  277    globalMenu->addAction(currentView);
 
  278    connect(currentView, SIGNAL(triggered(
bool)), 
this, SLOT(
stretchGlobal()));
 
  281    globalAll->setText(
"All Viewports");
 
  282    globalMenu->addAction(globalAll);
 
  286    globalBands->setText(
"All Bands");
 
  287    globalMenu->addAction(globalBands);
 
  298      "<b>Function:</b> Reset the stretch to be automatically computed " 
  299      "using the statisics from the entire image. Use the drop down menu " 
  300      "to reset the stretch for all the bands in the active viewport or " 
  301      "to reset the stretch for all the viewports.";
 
  304    QPushButton *advancedButton = 
new QPushButton(
"Advanced");
 
  309      "<b>Function:</b> While this button is pressed down, the visible stretch " 
  310      "will be the automatically computed stretch using the statisics from the " 
  311      "entire image. The original stretch is restored once you let up on this " 
  318    QPushButton *saveToCubeButton = 
new QPushButton(
"Save");
 
  319    connect(saveToCubeButton, SIGNAL(clicked(
bool)), 
this, SLOT(
saveStretchToCube()));
 
  321    QPushButton *deleteFromCubeButton = 
new QPushButton(
"Delete");
 
  322    connect(deleteFromCubeButton, SIGNAL(clicked(
bool)), 
this, SLOT(
deleteFromCube()));
 
  324    QPushButton *loadStretchButton = 
new QPushButton(
"Restore");
 
  327    QHBoxLayout *layout = 
new QHBoxLayout(hbox);
 
  328    layout->setMargin(0);
 
  336    layout->addWidget(advancedButton);
 
  341    layout->addWidget(saveToCubeButton);
 
  342    layout->addWidget(deleteFromCubeButton);
 
  343    layout->addWidget(loadStretchButton);
 
  345    layout->addStretch(); 
 
  346    hbox->setLayout(layout);
 
 
  362      if(cvp->isGray() && !cvp->grayBuffer()->working()) {
 
  369          if(hist.ValidPixels() > 0) {
 
  375      else if(!cvp->isGray() &&
 
  376              !cvp->redBuffer()->working() &&
 
  377              !cvp->greenBuffer()->working() &&
 
  378              !cvp->blueBuffer()->working()) {
 
  387          if(redHist.ValidPixels() > 0 &&
 
  388              grnHist.ValidPixels() > 0 &&
 
  389              bluHist.ValidPixels() > 0) {
 
 
  410         !cvp->redBuffer()->working() &&
 
  411         !cvp->greenBuffer()->working() &&
 
  412         !cvp->blueBuffer()->working()) {
 
  417        Stretch redStretch(cvp->redStretch());
 
  418        Stretch grnStretch(cvp->greenStretch());
 
  419        Stretch bluStretch(cvp->blueStretch());
 
  423                                            bluStretch, bluHist);
 
 
  434    Cube* icube = cvp->cube();
 
  435    Pvl* lab = icube->label();
 
  442      for (objIter=lab->beginObject(); objIter<lab->endObject(); objIter++) {
 
  443        if (objIter->name() == 
"Stretch") {
 
  444          PvlKeyword tempKeyword = objIter->findKeyword(
"Name");
 
  445          int bandNumber = int(objIter->findKeyword(
"BandNumber"));
 
  446          if (cvp->grayBand() == bandNumber) {
 
  447            QString tempName = tempKeyword[0];
 
  448            namelist.append(tempName);
 
  454      int redBandNumber = cvp->redBand();
 
  455      int greenBandNumber = cvp->greenBand();
 
  456      int blueBandNumber = cvp->blueBand();
 
  458      QMap<QString, QList<int>> tempNameMap;
 
  460      for (objIter=lab->beginObject(); objIter<lab->endObject(); objIter++) {
 
  461        if (objIter->name() == 
"Stretch") {
 
  462          PvlKeyword tempKeyword = objIter->findKeyword(
"Name");
 
  463          int bandNumber = int(objIter->findKeyword(
"BandNumber"));
 
  464          if (bandNumber == redBandNumber || bandNumber == greenBandNumber
 
  465              || bandNumber == blueBandNumber) {
 
  466            QString tempName = tempKeyword[0];
 
  467            if (tempNameMap.contains(tempName)) {
 
  468              tempNameMap[tempName].append(bandNumber);
 
  472              tempNameMap[tempName] = {bandNumber};
 
  477      QMap<QString, QList<int>>::const_iterator i = tempNameMap.constBegin();
 
  478      while (i != tempNameMap.constEnd()) {
 
  479        if (i.value().contains(redBandNumber) && i.value().contains(greenBandNumber) &&
 
  480            i.value().contains(blueBandNumber) ){
 
  481          namelist.append(i.key());
 
  490    if (namelist.size() >=1) {
 
  491      stretchName = QInputDialog::getItem((
QWidget *)parent(), tr(
"Load Stretch"),
 
  492                                          tr(
"Name of Stretch to Load:"), namelist, 0,
 
  496      QMessageBox::information((
QWidget *)parent(), 
"Information",
 
  497                                   "There are no saved stretches to restore.");
 
  502        CubeStretch cubeStretch = icube->readCubeStretch(stretchName);
 
  510        cvp->stretchGray(grayOriginal);
 
  513        std::vector<PvlKeyword> keywordValueRed;
 
  514        keywordValueRed.push_back(
PvlKeyword(
"BandNumber",  QString::number(cvp->redBand())));
 
  516        std::vector<PvlKeyword> keywordValueGreen;
 
  517        keywordValueGreen.push_back(
PvlKeyword(
"BandNumber", QString::number(cvp->greenBand())));
 
  519        std::vector<PvlKeyword> keywordValueBlue;
 
  520        keywordValueBlue.push_back(
PvlKeyword(
"BandNumber", QString::number(cvp->blueBand())));
 
  522        CubeStretch redStretch = icube->readCubeStretch(stretchName, keywordValueRed);
 
  523        CubeStretch greenStretch = icube->readCubeStretch(stretchName, keywordValueGreen);
 
  524        CubeStretch blueStretch = icube->readCubeStretch(stretchName, keywordValueBlue);
 
  537        greenOriginal.CopyPairs(greenStretch);
 
  538        blueOriginal.CopyPairs(blueStretch);
 
  540        cvp->stretchRed(redOriginal);
 
  541        cvp->stretchGreen(greenOriginal);
 
  542        cvp->stretchBlue(blueOriginal);
 
 
  554    Cube* icube = cvp->cube();
 
  555    Pvl* lab = icube->label();
 
  560    for (objIter=lab->beginObject(); objIter<lab->endObject(); objIter++) {
 
  561      if (objIter->name() == 
"Stretch") {
 
  562        PvlKeyword tempKeyword = objIter->findKeyword(
"Name");
 
  563        int bandNumber = int(objIter->findKeyword(
"BandNumber"));
 
  564        if (cvp->grayBand() == bandNumber) {
 
  565          QString tempName = tempKeyword[0];
 
  566          namelist.append(tempName);
 
  574    if (namelist.size() >= 1) {
 
  575      toDelete = QInputDialog::getItem((
QWidget *)parent(), tr(
"Delete Stretch"),
 
  576                                       tr(
"Name of Stretch to Delete:"), namelist, 0,
 
  580      QMessageBox::information((
QWidget *)parent(), 
"Information",
 
  581                               "There are no saved stretches to delete.");
 
  585      if (icube->isReadOnly()) {
 
  587          cvp->cube()->reopen(
"rw");
 
  590          cvp->cube()->reopen(
"r");
 
  591          QMessageBox::information((
QWidget *)parent(), 
"Error",
 
  592                                   "Cannot open cube read/write to delete stretch");
 
  597      bool cubeDeleted = icube->deleteBlob(toDelete, 
"Stretch");
 
  601        msgBox.setText(
"Stretch Could Not Be Deleted!");
 
  602        msgBox.setInformativeText(
"A stretch with name: \"" + toDelete +
 
  603            "\" Could not be found, so there was nothing to delete from the Cube.");
 
  604        msgBox.setStandardButtons(QMessageBox::Ok);
 
  605        msgBox.setIcon(QMessageBox::Critical);
 
  610      cvp->cube()->reopen(
"r");
 
 
  620    Cube* icube = cvp->cube();
 
  621    Pvl* lab = icube->label();
 
  626    for (objIter=lab->beginObject(); objIter<lab->endObject(); objIter++) {
 
  627      if (objIter->name() == 
"Stretch") {
 
  628        PvlKeyword tempKeyword = objIter->findKeyword(
"Name");
 
  629        QString tempName = tempKeyword[0];
 
  630        namelist.append(tempName);
 
  647    if (!cvp->isGray()) {
 
  655        redStretch = cvp->redStretch();
 
  656        greenStretch = cvp->greenStretch();
 
  657        blueStretch = cvp->blueStretch();
 
  660      int redBand = cvp->redBand();
 
  661      int greenBand = cvp->greenBand();
 
  662      int blueBand = cvp->blueBand();
 
  664      if (((redBand == greenBand) && !(redStretch == greenStretch)) ||
 
  665          ((redBand == blueBand)  && !(redBand == blueBand)) ||
 
  666          ((greenBand == blueBand) && !(greenBand == blueBand))) {
 
  667        QMessageBox::information((
QWidget *)parent(), 
"Error", 
"Sorry, cannot save RGB stretches which include the same band multiple times, but have different stretches for each");
 
  674                                         tr(
"Enter a name to save the stretch as:"), QLineEdit::Normal,
 
  679      if (namelist.contains(text)) {
 
  681        msgBox.setText(tr(
"Stretch Name Already Exists!"));
 
  682        msgBox.setInformativeText(
"A stretch pair with name: \"" + text + 
"\" already exists and " 
  683                                  "the existing saved data will be overwritten. Are you sure you " 
  685        msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
 
  686        msgBox.setIcon(QMessageBox::Warning);
 
  687        msgBox.setDefaultButton(QMessageBox::Cancel);
 
  688        int ret = msgBox.exec();
 
  691      case QMessageBox::Save:
 
  693      case QMessageBox::Cancel:
 
  704      if (icube->isReadOnly()) {
 
  711          QMessageBox::information((
QWidget *)parent(), 
"Error", 
"Cannot open cube read/write to save stretch");
 
  723          stretch = cvp->grayStretch();
 
  732        icube->write(stretch);
 
  742          redStretch = cvp->redStretch();
 
  743          greenStretch = cvp->greenStretch();
 
  744          blueStretch = cvp->blueStretch();
 
  750        icube->write(stretchBlob, 
false);
 
  754        stretchBlob = greenStretch.
toBlob();
 
  755        icube->write(stretchBlob, 
false);
 
  759        stretchBlob = blueStretch.
toBlob();
 
  760        icube->write(stretchBlob, 
false);
 
  764      cvp->cube()->reopen(
"r");
 
 
  786      if(cvp->isGray() && !cvp->grayBuffer()->working()) {
 
  788        Stretch stretch(cvp->grayStretch());
 
  792      else if(!cvp->isGray() &&
 
  793              !cvp->redBuffer()->working() &&
 
  794              !cvp->greenBuffer()->working() &&
 
  795              !cvp->blueBuffer()->working()) {
 
  799        Stretch redStretch(cvp->redStretch());
 
  800        Stretch grnStretch(cvp->greenStretch());
 
  801        Stretch bluStretch(cvp->blueStretch());
 
  804                                         bluStretch, bluHist);
 
 
  836    if(cvp && cvp->isGray()) {
 
 
  877    QRect rect(0, 0, cvp->viewport()->width(), cvp->viewport()->height());
 
  879    if(bandId == (
int)
Gray) {
 
  880      if(cvp->grayBuffer() && cvp->grayBuffer()->hasEntireCube()) {
 
  881        Stretch newStretch = cvp->grayStretch();
 
  883        cvp->stretchGray(newStretch);
 
  887        cvp->stretchGray(newStretch);
 
  892      if(bandId == (
int)
Red || bandId == (
int)
All) {
 
  893        if(cvp->redBuffer() && cvp->redBuffer()->hasEntireCube()) {
 
  894          Stretch newStretch = cvp->redStretch();
 
  896          cvp->stretchRed(newStretch);
 
  900          cvp->stretchRed(newStretch);
 
  903      if(bandId == (
int)
Green || bandId == (
int)
All) {
 
  904        if(cvp->greenBuffer() && cvp->greenBuffer()->hasEntireCube()) {
 
  905          Stretch newStretch = cvp->greenStretch();
 
  907          cvp->stretchGreen(newStretch);
 
  911          cvp->stretchGreen(newStretch);
 
  914      if(bandId == (
int)
Blue || bandId == (
int)
All) {
 
  915        if(cvp->blueBuffer() && cvp->blueBuffer()->hasEntireCube()) {
 
  916          Stretch newStretch = cvp->blueStretch();
 
  918          cvp->stretchBlue(newStretch);
 
  922          cvp->stretchBlue(newStretch);
 
 
  937    if(cvp == NULL) 
return;
 
  948      cvp->stretchKnownGlobal();
 
  965    double min = 0, max = 0;
 
  969      Stretch stretch = cvp->grayStretch();
 
  970      min = stretch.
Input(0);
 
  976      Stretch rstretch = cvp->redStretch();
 
  977      Stretch gstretch = cvp->greenStretch();
 
  978      Stretch bstretch = cvp->blueStretch();
 
  982        min = rstretch.
Input(0);
 
  983        max = rstretch.Input(rstretch.Pairs() - 1);
 
  986        min = gstretch.Input(0);
 
  987        max = gstretch.Input(gstretch.Pairs() - 1);
 
  990        min = bstretch.Input(0);
 
  991        max = bstretch.Input(bstretch.Pairs() - 1);
 
 
 1021    if(cvp == NULL) 
return;
 
 1024      Stretch grayStretch = cvp->grayStretch();
 
 1027      cvp->stretchGray(grayStretch);
 
 1034      Stretch redStretch = cvp->redStretch();
 
 1037      cvp->stretchRed(redStretch);
 
 1039      Stretch grnStretch = cvp->greenStretch();
 
 1042      cvp->stretchGreen(grnStretch);
 
 1044      Stretch bluStretch = cvp->blueStretch();
 
 1047      cvp->stretchBlue(bluStretch);
 
 
 1061    if(cvp == NULL) 
return;
 
 1078      Stretch stretch = cvp->grayStretch();
 
 1087      cvp->stretchGray(stretch);
 
 1091      Stretch redStretch = cvp->redStretch();
 
 1092      Stretch greenStretch = cvp->greenStretch();
 
 1093      Stretch blueStretch = cvp->blueStretch();
 
 1098        redStretch.
AddPair(max, 255.0);
 
 1102        greenStretch.
AddPair(min, 0.0);
 
 1103        greenStretch.
AddPair(max, 255.0);
 
 1107        blueStretch.
AddPair(min, 0.0);
 
 1108        blueStretch.
AddPair(max, 255.0);
 
 1111      cvp->stretchRed(redStretch);
 
 1112      cvp->stretchGreen(greenStretch);
 
 1113      cvp->stretchBlue(blueStretch);
 
 
 1126    int bandNum = cvp->grayBand();
 
 1127    if(bandId == (
int)
Red) {
 
 1128      bandNum = cvp->redBand();
 
 1130    else if(bandId == (
int)
Green) {
 
 1131      bandNum = cvp->greenBand();
 
 1133    else if(bandId == (
int)
Blue) {
 
 1134      bandNum = cvp->blueBand();
 
 1143    double selectedMin = 0;
 
 1144    double selectedMax = 0;
 
 1146    if (minMaxIndex == 0) {
 
 1147      selectedMin = hist.Percent(0.5);
 
 1148      selectedMax = hist.Percent(99.5);
 
 1149    } 
else if (minMaxIndex == 1) {
 
 1151      selectedMin = stats.BestMinimum();
 
 1152      selectedMax = stats.BestMaximum();
 
 1153    } 
else if (minMaxIndex == 2) {
 
 1155      selectedMin = stats.Minimum();
 
 1156      selectedMax = stats.Maximum();
 
 1157    } 
else if (minMaxIndex == 3) {
 
 1159      selectedMin = stats.ChebyshevMinimum();
 
 1160      selectedMax = stats.ChebyshevMaximum();
 
 1163    QString qMin = QString::number(selectedMin);
 
 1164    QString qMax = QString::number(selectedMax);
 
 
 1193    if(cvp == NULL) 
return;
 
 
 1204    if(cvp == NULL) 
return;
 
 1206    cvp->forgetStretches();
 
 
 1216    cvp->stretchKnownGlobal();
 
 
 1240    if(cvp == NULL) 
return;
 
 
 1251      QRect rect(0, 0, cvp->viewport()->width(), cvp->viewport()->height());
 
 1256      QString message = 
"Cannot stretch while the cube is still loading";
 
 1257      QMessageBox::warning((
QWidget *)parent(), 
"Warning", message);
 
 
 1271    if(cvp == NULL) 
return;
 
 1272    if(!rubberBandTool()->isValid()) 
return;
 
 1274    QRect rubberBandRect = rubberBandTool()->
rectangle();
 
 1276    if(rubberBandRect.width() == 0 || rubberBandRect.height() == 0) 
return;
 
 
 1291       newStretch = cvp->grayStretch();
 
 1293       newStretch.CopyPairs(
stretchBuffer(cvp->grayBuffer(), rect));
 
 1294       cvp->stretchGray(newStretch);
 
 1302         newStretch = cvp->redStretch();
 
 1303         newStretch.ClearPairs();
 
 1304         newStretch.CopyPairs(
stretchBuffer(cvp->redBuffer(), rect));
 
 1305         cvp->stretchRed(newStretch);
 
 1308         newStretch = cvp->greenStretch();
 
 1309         newStretch.ClearPairs();
 
 1310         newStretch.CopyPairs(
stretchBuffer(cvp->greenBuffer(), rect));
 
 1311         cvp->stretchGreen(newStretch);
 
 1314         newStretch = cvp->blueStretch();
 
 1315         newStretch.ClearPairs();
 
 1316         newStretch.CopyPairs(
stretchBuffer(cvp->blueBuffer(), rect));
 
 1317         cvp->stretchBlue(newStretch);
 
 1322                            "Unknown stretch band",
 
 
 1340    if(cvp == NULL) 
return;
 
 1346    if(s == Qt::RightButton) {
 
 
 1363    rubberBandTool()->
enable(RubberBandTool::RectangleMode);
 
 
 1375    if(cvp == NULL) 
return;
 
 1382      stretch = cvp->grayStretch();
 
 1388      stretch = cvp->redStretch();
 
 1392      cvp->stretchGreen(stretch);
 
 1393      cvp->stretchBlue(stretch);
 
 1396      stretch = cvp->greenStretch();
 
 1400      cvp->stretchRed(stretch);
 
 1401      cvp->stretchBlue(stretch);
 
 1404      stretch = cvp->blueStretch();
 
 1408      cvp->stretchRed(stretch);
 
 1409      cvp->stretchGreen(stretch);
 
 1415    cvp->setAllBandStretches(stretch);
 
 
 1427    if(thisViewport == NULL) 
return;
 
 1432      if(thisViewport->isGray() && cvp->isGray()) {
 
 1433        Stretch newStretch(cvp->grayStretch());
 
 1434        newStretch.CopyPairs(thisViewport->grayStretch());
 
 1435        cvp->stretchGray(newStretch);
 
 1437      else if(!thisViewport->isGray() && !cvp->isGray()) {
 
 1438        Stretch newStretchRed(cvp->redStretch());
 
 1439        newStretchRed.CopyPairs(thisViewport->redStretch());
 
 1440        cvp->stretchRed(newStretchRed);
 
 1442        Stretch newStretchGreen(cvp->greenStretch());
 
 1443        newStretchGreen.CopyPairs(thisViewport->greenStretch());
 
 1444        cvp->stretchGreen(newStretchGreen);
 
 1446        Stretch newStretchBlue(cvp->blueStretch());
 
 1447        newStretchBlue.CopyPairs(thisViewport->blueStretch());
 
 1448        cvp->stretchBlue(newStretchBlue);
 
 1450      else if(!thisViewport->isGray() && cvp->isGray()) {
 
 1453      else if(thisViewport->isGray() && !cvp->isGray()) {
 
 
 1472    if(stats.ValidPixels() > 1 &&
 
 1473        fabs(stats.Minimum() - stats.Maximum()) > DBL_EPSILON) {
 
 1475                                            stats.BestMinimum(), stats.BestMaximum());
 
 1477      if(fabs(hist.Percent(0.5) - hist.Percent(99.5)) > DBL_EPSILON) {
 
 1478        stretch.
AddPair(hist.Percent(0.5), 0.0);
 
 1479        stretch.
AddPair(hist.Percent(99.5), 255.0);
 
 1483    if(stretch.
Pairs() == 0) {
 
 1484      stretch.
AddPair(-DBL_MAX, 0.0);
 
 1485      stretch.
AddPair(DBL_MAX, 255.0);
 
 
 1500    int bandNum = cvp->grayBand();
 
 1501    Stretch stretch = cvp->grayStretch();
 
 1503      bandNum = cvp->redBand();
 
 1504      stretch = cvp->redStretch();
 
 1506    else if(band == 
Green) {
 
 1507      bandNum = cvp->greenBand();
 
 1508      stretch = cvp->greenStretch();
 
 1510    else if(band == 
Blue) {
 
 1511      bandNum = cvp->blueBand();
 
 1512      stretch = cvp->blueStretch();
 
 1517                                         stats.BestMinimum(), stats.BestMaximum());
 
 1520    if(fabs(hist.Percent(0.5) - hist.Percent(99.5)) > DBL_EPSILON) {
 
 1521      stretch.
AddPair(hist.Percent(0.5), 0.0);
 
 1522      stretch.
AddPair(hist.Percent(99.5), 255.0);
 
 1525      stretch.
AddPair(-DBL_MAX, 0.0);
 
 1526      stretch.
AddPair(DBL_MAX, 255.0);
 
 
 1545    for(
int line = 0; line < cube->
lineCount(); line++) {
 
 1546      brick.SetBasePosition(0, line, band);
 
 1548      stats.AddData(brick.DoubleBuffer(), cube->
sampleCount());
 
 
 1568                       "Cannot stretch while the cube is still loading",
 
 1572    QRect dataArea = QRect(buffer->
bufferXYRect().intersected(rect));
 
 1575    for(
int y = dataArea.top();
 
 1576        !dataArea.isNull() && y <= dataArea.bottom();
 
 1580      for(
int x = dataArea.left(); x < dataArea.right(); x++) {
 
 1581        stats.AddData(line[x - buffer->
bufferXYRect().left()]);
 
 
 1600      double min, 
double max) {
 
 1604    for(
int line = 0; line < cube->
lineCount(); line++) {
 
 1605      brick.SetBasePosition(0, line, band);
 
 1607      hist.AddData(brick.DoubleBuffer(), cube->
sampleCount());
 
 
 1624        stats.BestMinimum(), stats.BestMaximum());
 
 
 1641      QRect rect, 
double min, 
double max) {
 
 1642    QRect dataArea = QRect(buffer->
bufferXYRect().intersected(rect));
 
 1647      for(
int y = dataArea.top(); !dataArea.isNull() && y <= dataArea.bottom(); y++) {
 
 1649        hist.AddData(&line.front() + (dataArea.left() - buffer->
bufferXYRect().left()), dataArea.width());
 
 1658      std::string msg = 
"Insufficient data Min [" + sMin + 
"], Max [" + sMax + 
"]";
 
 1659      msg += 
" in the stretch area.";
 
 
CubeStretch getBluStretch()
This returns the advanced stretch's stretch for blue.
 
void updateHistograms(const Histogram &redHist, const Histogram &grnHist, const Histogram &bluHist)
This calls setHistogram on all of the advanced stretches.
 
void enable(bool enable)
Sets the enabled state to enable.
 
void restoreGrayStretch(CubeStretch stretch)
Restores a saved grayscale stretch from the cube.
 
void updateForRGBMode(Stretch &redStretch, Histogram &redHist, Stretch &grnStretch, Histogram &grnHist, Stretch &bluStretch, Histogram &bluHist)
Update the stretch and histogram for all the bands for All BandId option.
 
void updateHistogram(const Histogram &grayHist)
This calls setHistogram on the gray advanced stretches.
 
void enableRgbMode(Stretch &redStretch, Histogram &redHist, Stretch &grnStretch, Histogram &grnHist, Stretch &bluStretch, Histogram &bluHist)
This displays RGB advanced stretches.
 
CubeStretch getGrnStretch()
This returns the advanced stretch's stretch for green.
 
CubeStretch getGrayStretch()
This returns the advanced stretch's stretch for gray.
 
CubeStretch getRedStretch()
This returns the advanced stretch's stretch for red.
 
bool isRgbMode() const
Returns true if the dialog is displaying the RGB advanced stretches.
 
bool enabled()
Returns true if the advanced stretch is enabled.
 
void restoreRgbStretch(CubeStretch red, CubeStretch green, CubeStretch blue)
Restores a saved RGB stretch from the cube.
 
void updateStretch(CubeViewport *)
This calls setStretch on all applicable advanced stretches.
 
void enableGrayMode(Stretch &grayStretch, Histogram &grayHist)
This displays a gray advanced stretch.
 
Buffer for containing a three dimensional section of an image.
 
IO Handler for Isis Cubes.
 
PixelType pixelType() const
 
void read(Blob &blob, const std::vector< PvlKeyword > keywords=std::vector< PvlKeyword >()) const
This method will read data from the specified Blob object.
 
Stores stretch information for a cube.
 
void setBandNumber(int bandNumber)
Set the band number for the stretch.
 
void setName(QString name)
Set the Stretch name.
 
Isis::Blob toBlob() const
Serialize the CubeStretch to a Blob.
 
Widget to display Isis cubes for qt apps.
 
Container of a cube histogram.
 
@ Unknown
A type of error that cannot be classified as any of the other error types.
 
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
 
@ Programmer
This error is for when a programmer made an API call that was illegal.
 
Adds specific functionality to C++ strings.
 
Cube display widget for certain Isis MDI applications.
 
Container for cube-like labels.
 
A single keyword-value pair.
 
QList< PvlObject >::iterator PvlObjectIterator
The counter for objects.
 
This class is used to accumulate statistics on double arrays.
 
void CopyPairs(const Stretch &other)
Copies the stretch pairs from another Stretch object, but maintains special pixel values.
 
void AddPair(const double input, const double output)
Adds a stretch pair to the list of pairs.
 
double Input(const int index) const
Returns the value of the input side of the stretch pair at the specified index.
 
void ClearPairs()
Clears the stretch pairs.
 
int Pairs() const
Returns the number of stretch pairs.
 
Reads and stores visible DN values.
 
const std::vector< double > & getLine(int line)
Retrieves a line from the buffer.
 
QRect bufferXYRect()
Returns a rect, in screen pixels, of the area this buffer covers.
 
bool working()
This tests if queued actions exist in the viewport buffer.
 
This was called the Qisis MainWindow.
 
This is free and unencumbered software released into the public domain.
 
int toInt(const QString &string)
Global function to convert from a string to an integer.
 
Namespace for the standard library.