Unverified Commit 3b955cd8 authored by Kristin's avatar Kristin Committed by GitHub
Browse files

Adds the ability to save and restore a greyscale stretch to/from a Cube (#3717)



* Update meta.yaml to rename conda package to isis from isis3

* Initial stretch attempt

* Now will write a single stretch with a name and type to the cube

* Stretch updated to inherit from Blob, re-loading a saved stretch works but only if Linear right now

* Clean up Stretch class

* Completely move stretchTypes into stretch class, and some minor cleanup

* Fixed combo-box not updating bug and more cleanup

* Further cleanup of propagated earlier changes with types and names being removed from unnecessary classes

* Removed added unneeded member variables from StretchType

* Cleanup StretchTool class

* Update enter-text dialogs to drop down selection options

* Wrapped some long strings

* Initial commit to address most of review comments

* Removed buttons in case of RGB stretch and add a 'Color' PvlKeyword to Stretch output

Co-authored-by: default avatarStuart Sides <ssides@usgs.gov>
parent 834b5b53
Loading
Loading
Loading
Loading
+105 −1
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ namespace Isis {
   * Constructs a Stretch object with default mapping of special pixel values to
   * themselves.
   */
  Stretch::Stretch() {
  Stretch::Stretch() : Blob("ImageStretch", "Stretch") {
    p_null = Isis::NULL8;
    p_lis = Isis::LOW_INSTR_SAT8;
    p_lrs = Isis::LOW_REPR_SAT8;
@@ -47,8 +47,29 @@ namespace Isis {
    p_minimum = p_lrs;
    p_maximum = p_hrs;
    p_pairs = 0;
    p_type = "None";
  }


  /**
   * Constructs a Stretch object with default mapping of special pixel values to
   * themselves and a provided name. 
   *  
   * @param name Name to use for Stretch 
   */
  Stretch::Stretch(QString name) : Blob(name, "Stretch") {
    p_null = Isis::NULL8;
    p_lis = Isis::LOW_INSTR_SAT8;
    p_lrs = Isis::LOW_REPR_SAT8;
    p_his = Isis::HIGH_INSTR_SAT8;
    p_hrs = Isis::HIGH_REPR_SAT8;
    p_minimum = p_lrs;
    p_maximum = p_hrs;
    p_pairs = 0;
    p_type = "None";
  }


  /**
   * Adds a stretch pair to the list of pairs. Note that all input pairs must be
   * in ascending order.
@@ -410,6 +431,89 @@ namespace Isis {
    this->p_output = other.p_output;
  }


  /**
   * Read saved Stretch data from a Cube into this object. 
   *  
   * This is called by Blob::Read() and is the actual data reading function 
   * ultimately called when running something like cube->read(stretch);  
   * 
   * @param is input stream containing the saved Stretch information
   */
  void Stretch::ReadData(std::istream &is) {
    // Set the Stretch Type
     p_type = p_blobPvl["StretchType"][0];

     // Read in the Stretch Pairs
     streampos sbyte = p_startByte - 1;
     is.seekg(sbyte, std::ios::beg);
     if (!is.good()) {
       QString msg = "Error preparing to read data from " + p_type +
                    " [" + p_blobName + "]";
       throw IException(IException::Io, msg, _FILEINFO_);
     }

     char *buf = new char[p_nbytes+1];
     memset(buf, 0, p_nbytes + 1);

     is.read(buf, p_nbytes);

     // Read buffer data into a QString so we can call Parse()
     std::string stringFromBuffer(buf);
     QString qStringFromBuffer = QString::fromStdString(stringFromBuffer);
     Parse(qStringFromBuffer);

     delete [] buf;

     if (!is.good()) {
       QString msg = "Error reading data from " + p_type + " [" +
                    p_blobName + "]";
       throw IException(IException::Io, msg, _FILEINFO_);
     }
   }


  /**
   * Get the Type of Stretch. This is only used by the AdvancedStretchTool.
   * 
   * @return QString Type of Stretch. 
   */
  QString Stretch::getType(){
    return p_type;
  }


  /**
   * Set the Type of Stretch. This is only used by the AdvancedStretchTool.
   *  
   * @param stretchType The type of stretch.  
   */
  void Stretch::setType(QString stretchType){
    // check to see if valid input
    p_type = stretchType;
  }


  /**
   *  Initializes for writing stretch to cube blob
   */
  void Stretch::WriteInit() {
    p_nbytes = Text().toStdString().size(); 
  }


  /**
   * Writes the stretch information to a cube. 
   *  
   * This is called by Blob::write() and is ultimately the function 
   * called when running something like cube->write(stretch);  
   *  
   * @param os output stream to write the stretch data to.
   */
  void Stretch::WriteData(std::fstream &os) {
    os.write(Text().toStdString().c_str(), p_nbytes);
  }

} // end namespace isis

+15 −2
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <string>
#include "Pvl.h"
#include "Histogram.h"
#include "Blob.h"

namespace Isis {
  /**
@@ -67,9 +68,10 @@ namespace Isis {
   *               Created second Parse method for handling pairs where the
   *               input side is a perentage.  Fixed Input and Output getters
   *               to check both sides of boundry condition for valid data
   *
   *  @history 2020-02-27 Kristin Berry - Updated to inherit from Blob so Stretches can be
   *               saved and restored from cubes. 
   */
  class Stretch {
  class Stretch : public Isis::Blob {
    private:
      std::vector<double> p_input;   //!< Array for input side of stretch pairs
      std::vector<double> p_output;  //!< Array for output side of stretch pairs
@@ -88,10 +90,13 @@ namespace Isis {
      double p_minimum; //!<By default this value is set to p_lrs
      double p_maximum; //!<By default this value is set to p_hrs

      QString p_type; //! Type of stretch. This is only currently used in the AdvancedStretchTool.

      std::pair<double, double> NextPair(QString &pairs);

    public:
      Stretch();
      Stretch(QString name);

      //! Destroys the Stretch object
      ~Stretch() {};
@@ -177,6 +182,9 @@ namespace Isis {
        return p_pairs;
      };

      QString getType(); 
      void setType(QString type); 

      double Input(const int index) const;
      double Output(const int index) const;

@@ -188,6 +196,11 @@ namespace Isis {
      };

      void CopyPairs(const Stretch &other);

    protected:
      void WriteInit();
      void ReadData(std::istream &is);
      void WriteData(std::fstream &os);
  };
};

+53 −8
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#include <QHBoxLayout>
#include <QLabel>
#include <QComboBox>
#include <QMessageBox>

#include "Stretch.h"
#include "IString.h"
@@ -35,40 +36,52 @@ namespace Isis {
    typeSelectionArea->setLayout(new QHBoxLayout());
    typeSelectionArea->layout()->addWidget(new QLabel("Stretch Type"));

    QComboBox *stretchTypeSelection = new QComboBox();
    stretchTypeSelection->addItem("Linear",   0);
    stretchTypeSelection->addItem("Sawtooth", 1);
    stretchTypeSelection->addItem("Binary",   2);
    stretchTypeSelection->addItem("Manual",   3);
    p_stretchTypeSelection = new QComboBox();
    p_stretchTypeSelection->addItem("Linear",   0);
    p_stretchTypeSelection->addItem("Sawtooth", 1);
    p_stretchTypeSelection->addItem("Binary",   2);
    p_stretchTypeSelection->addItem("Manual",   3);

    typeSelectionArea->layout()->addWidget(stretchTypeSelection);
    typeSelectionArea->layout()->addWidget(p_stretchTypeSelection);
    layout()->addWidget(typeSelectionArea);

    p_stretchTypeStack = new QStackedWidget();
    LinearStretchType *linear = new LinearStretchType(hist, curStretch,
        name, color);
    connect(linear, SIGNAL(stretchChanged()), this, SIGNAL(stretchChanged()));
    connect(linear, SIGNAL(saveToCube()), this, SIGNAL(saveToCube()));
    connect(linear, SIGNAL(deleteFromCube()), this, SIGNAL(deleteFromCube()));
    connect(linear, SIGNAL(loadStretch()), this, SIGNAL(loadStretch()));
    p_stretchTypeStack->addWidget(linear);

    SawtoothStretchType *sawtooth = new SawtoothStretchType(hist, curStretch,
        name, color);
    connect(sawtooth, SIGNAL(stretchChanged()), this, SIGNAL(stretchChanged()));
    connect(sawtooth, SIGNAL(saveToCube()), this, SIGNAL(saveToCube()));
    connect(sawtooth, SIGNAL(deleteFromCube()), this, SIGNAL(deleteFromCube()));
    connect(sawtooth, SIGNAL(loadStretch()), this, SIGNAL(loadStretch()));
    p_stretchTypeStack->addWidget(sawtooth);

    BinaryStretchType *binary = new BinaryStretchType(hist, curStretch,
        name, color);
    connect(binary, SIGNAL(stretchChanged()), this, SIGNAL(stretchChanged()));
    connect(binary, SIGNAL(saveToCube()), this, SIGNAL(saveToCube()));
    connect(binary, SIGNAL(deleteFromCube()), this, SIGNAL(deleteFromCube()));
    connect(binary, SIGNAL(loadStretch()), this, SIGNAL(loadStretch()));
    p_stretchTypeStack->addWidget(binary);

    ManualStretchType *manual = new ManualStretchType(hist, curStretch,
        name, color);
    connect(manual, SIGNAL(stretchChanged()), this, SIGNAL(stretchChanged()));
    connect(manual, SIGNAL(saveToCube()), this, SIGNAL(saveToCube()));
    connect(manual, SIGNAL(deleteFromCube()), this, SIGNAL(deleteFromCube()));
    connect(manual, SIGNAL(loadStretch()), this, SIGNAL(loadStretch()));
    p_stretchTypeStack->addWidget(manual);

    layout()->addWidget(p_stretchTypeStack);
    connect(stretchTypeSelection, SIGNAL(currentIndexChanged(int)),
    connect(p_stretchTypeSelection, SIGNAL(currentIndexChanged(int)),
            p_stretchTypeStack, SLOT(setCurrentIndex(int)));
    connect(stretchTypeSelection, SIGNAL(currentIndexChanged(int)),
    connect(p_stretchTypeSelection, SIGNAL(currentIndexChanged(int)),
            this, SIGNAL(stretchChanged()));
  }

@@ -105,6 +118,38 @@ namespace Isis {
  }


  /**
   * Used to restore a saved Stretch from a cube. This function is 
   * distinct from setStretch in that setStretch deliberately _does not_ 
   * change the stretch type, and this function does change the stretch type.  
   *  
   * @param newStretch saved stretch to restore
   */
  void AdvancedStretch::restoreSavedStretch(Stretch newStretch) {
    QString stretchTypeName = newStretch.getType(); 

    int index = 0;
    if (stretchTypeName.compare("LinearStretch") == 0 ) {
      index = 0; 
    }
    else if (stretchTypeName.compare("SawtoothStretch") == 0 ) {
      index = 1; 
    }
    else if (stretchTypeName.compare("BinaryStretch") == 0) {
      index = 2; 
    }
    else if (stretchTypeName.compare("ManualStretch") == 0) {
      index = 3;
    }
    // Fail by defaulting to Linear

    p_stretchTypeSelection->setCurrentIndex(index);
    StretchType *stretchType = (StretchType *)
                               p_stretchTypeStack->currentWidget();
    stretchType->setStretch(newStretch);
  }


  /**
   * This is called when the visible area changes, so that the
   * histogram can be updated. It is essential that the stretch
+6 −2
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
#include <QWidget>

class QStackedWidget;
class QComboBox;
class QLayout;
class QString;
class QColor;
@@ -36,16 +37,19 @@ namespace Isis {
      ~AdvancedStretch();
      Stretch getStretch();
      void setStretch(Stretch newStretch);
      void restoreSavedStretch(Stretch newStretch);
      void setHistogram(const Histogram &newHist);

    signals:
      //! Emitted when a new stretch is available
      void stretchChanged();

    protected:
      void saveToCube();
      void deleteFromCube(); 
      void loadStretch(); 

    private:
      QStackedWidget *p_stretchTypeStack; //!< StretchType's
      QComboBox *p_stretchTypeSelection; //!< ComboBox of StretchTypes
  };
};

+20 −1
Original line number Diff line number Diff line
@@ -21,7 +21,10 @@ namespace Isis {
    p_bluStretch = NULL;
    p_enabled = false;

    setWindowTitle("Advanced Stretch Tool");

    QHBoxLayout *layout = new QHBoxLayout();
    
    setLayout(layout);
  }

@@ -124,6 +127,22 @@ namespace Isis {

    connect(p_grayStretch, SIGNAL(stretchChanged()),
            this, SIGNAL(stretchChanged()));
    connect(p_grayStretch, SIGNAL(saveToCube()),
            this, SIGNAL(saveToCube()));
    connect(p_grayStretch, SIGNAL(deleteFromCube()),
            this, SIGNAL(deleteFromCube()));
    connect(p_grayStretch, SIGNAL(loadStretch()),
            this, SIGNAL(loadStretch()));
  }


  /**
   * Restores a saved stretch from the cube 
   *  
   * @param stretch 
   */
  void AdvancedStretchDialog::restoreSavedStretch(Stretch stretch){
    p_grayStretch->restoreSavedStretch(stretch);
  }


@@ -213,7 +232,7 @@ namespace Isis {


  /**
   * This calls setHistogram on the gray advanced stretche. This
   * This calls setHistogram on the gray advanced stretches. This
   * should be called every time the visible area changes.
   *
   * @param grayHist Histogram of visible area on gray band
Loading