USGS

Isis 3.0 Object Programmers' Reference

Home

SawtoothStretchType.cpp

00001 #include "SawtoothStretchType.h"
00002 
00003 #include <QVBoxLayout>
00004 #include <QLayout>
00005 #include <QLineEdit>
00006 #include <QLabel>
00007 #include <QTableWidget>
00008 
00009 #include "CubeViewport.h"
00010 #include "HistogramWidget.h"
00011 #include "Statistics.h"
00012 #include "Stretch.h"
00013 
00014 namespace Isis {
00023   SawtoothStretchType::SawtoothStretchType(const Histogram &hist,
00024       const Stretch &stretch, const QString &name, const QColor &color) :
00025     StretchType(hist, stretch, name, color) {
00026     p_offsetSlider = NULL;
00027     p_widthSlider = NULL;
00028     p_offsetEdit = NULL;
00029     p_widthEdit = NULL;
00030     p_sliderOverride = false;
00031 
00032     QWidget *sliderWidget = new QWidget();
00033     QGridLayout *sliderLayout = new QGridLayout();
00034     sliderLayout->setColumnStretch(1, 10);
00035 
00036     QLabel *startLabel = new QLabel("Offset");
00037     p_offsetSlider = new QSlider(Qt::Horizontal);
00038     p_offsetSlider->setTickPosition(QSlider::NoTicks);
00039     p_offsetSlider->setMinimum(0);
00040     p_offsetSlider->setMaximum(1000);
00041     p_offsetSlider->setPageStep(50);
00042     connect(p_offsetSlider, SIGNAL(valueChanged(int)),
00043             this, SLOT(offsetSliderMoved(int)));
00044     p_offsetEdit = new QLineEdit();
00045     p_offsetEdit->setMaximumWidth(75);
00046     p_offsetEdit->setText(QString::number(
00047                             p_cubeHist->Maximum() - p_cubeHist->Minimum()
00048                           ));
00049     connect(p_offsetEdit, SIGNAL(textChanged(const QString &)),
00050             this, SLOT(offsetEditChanged(const QString &)));
00051     sliderLayout->addWidget(startLabel,  0, 0);
00052     sliderLayout->addWidget(p_offsetSlider, 0, 1);
00053     sliderLayout->addWidget(p_offsetEdit,   0, 2);
00054 
00055     QLabel *widthLabel = new QLabel("Width");
00056     p_widthSlider = new QSlider(Qt::Horizontal);
00057     p_widthSlider->setTickPosition(QSlider::NoTicks);
00058     p_widthSlider->setMinimum(0);
00059     p_widthSlider->setMaximum(1000);
00060     p_widthSlider->setPageStep(50);
00061     connect(p_widthSlider, SIGNAL(valueChanged(int)),
00062             this, SLOT(widthSliderMoved(int)));
00063     p_widthEdit = new QLineEdit();
00064     p_widthEdit->setMaximumWidth(75);
00065     connect(p_widthEdit, SIGNAL(textChanged(const QString &)),
00066             this, SLOT(widthEditChanged(const QString &)));
00067     sliderLayout->addWidget(widthLabel,  1, 0);
00068     sliderLayout->addWidget(p_widthSlider, 1, 1);
00069     sliderLayout->addWidget(p_widthEdit,   1, 2);
00070 
00071     sliderWidget->setLayout(sliderLayout);
00072     p_mainLayout->addWidget(sliderWidget, 1, 0);
00073 
00074     setLayout(p_mainLayout);
00075 
00076     p_widthEdit->setText(QString::number(
00077                            p_cubeHist->Median() - p_cubeHist->Minimum()
00078                          ));
00079     setStretch(calculateNewStretch());
00080   }
00081 
00082 
00086   SawtoothStretchType::~SawtoothStretchType() {
00087   }
00088 
00089 
00103   void SawtoothStretchType::setStretch(const Stretch newStretch) {
00104     Stretch interpretted;
00105     double offset = 0.0;
00106     double width = 0.0;
00107     bool changed = false;
00108 
00109     if(newStretch.Pairs() < 3) {
00110       // Disable all interpretation of linear stretches
00111       interpretted.CopyPairs(calculateNewStretch());
00112       offset = p_offsetEdit->text().toDouble();
00113       width = p_widthEdit->text().toDouble();
00114       changed = true;
00115     }
00116     else {
00117       // find an offset... should be the second or third point
00118       offset = newStretch.Input(1);
00119 
00120       // offset should always be a low point
00121       if(newStretch.Output(1) > 127)
00122         offset = newStretch.Input(2);
00123 
00124       width = (newStretch.Input(2) - newStretch.Input(0)) / 2;
00125 
00126       interpretted.CopyPairs(calculateNewStretch(offset, width));
00127 
00128       double deltaOffset = fabs(p_offsetEdit->text().toDouble() - offset);
00129       changed = (changed || (deltaOffset > p_cubeHist->BinSize()));
00130 
00131       double deltaWidth = fabs(p_widthEdit->text().toDouble() - width);
00132       changed = (changed || (deltaWidth > p_cubeHist->BinSize()));
00133     }
00134 
00135     if(changed) {
00136       p_stretch->CopyPairs(interpretted);
00137       p_offsetEdit->setText(QString::number(offset));
00138       p_widthEdit->setText(QString::number(width));
00139     }
00140 
00141     // regardless of it all, slider positions could need changed...
00142     offsetEditChanged(QString());
00143     widthEditChanged(QString());
00144 
00145     if(changed) {
00146       emit stretchChanged();
00147     }
00148   }
00149 
00150 
00155   void SawtoothStretchType::offsetSliderMoved(int) {
00156     if(p_offsetSlider->value() >= p_widthSlider->value())
00157       p_offsetSlider->setValue(p_widthSlider->value() - 1);
00158 
00159     if(p_sliderOverride)
00160       return;
00161 
00162     double value = p_cubeHist->Minimum();
00163     value += p_offsetSlider->value() * 2 *
00164              (p_cubeHist->Maximum() - p_cubeHist->Minimum()) / 1000.0;
00165     p_offsetEdit->setText(QString::number(value));
00166   }
00167 
00168 
00174   void SawtoothStretchType::offsetEditChanged(const QString &) {
00175     double value = p_offsetEdit->text().toDouble();
00176 
00177     double percentage = value - p_cubeHist->Minimum();
00178     percentage /= (p_cubeHist->Maximum() - p_cubeHist->Minimum()) * 2;
00179     int valuePos = (int)(percentage * 1000.0);
00180 
00181     p_sliderOverride = true;
00182     p_offsetSlider->setValue(valuePos);
00183     p_sliderOverride = false;
00184 
00185     Stretch newStretch = calculateNewStretch();
00186 
00187     if(newStretch.Text() != p_stretch->Text()) {
00188       p_stretch->CopyPairs(newStretch);
00189       emit stretchChanged();
00190     }
00191 
00192   }
00193 
00194 
00199   void SawtoothStretchType::widthSliderMoved(int) {
00200     if(p_widthSlider->value() <= p_offsetSlider->value())
00201       p_widthSlider->setValue(p_offsetSlider->value() + 1);
00202 
00203     if(p_sliderOverride)
00204       return;
00205 
00206     double highVal = p_cubeHist->Maximum() - p_cubeHist->Minimum();
00207     double lowVal = p_cubeHist->BinSize();
00208     double value = lowVal + p_widthSlider->value() *
00209                    (highVal - lowVal) / 1000.0;
00210     p_widthEdit->setText(QString::number(value));
00211   }
00212 
00213 
00219   void SawtoothStretchType::widthEditChanged(const QString &) {
00220     double value = p_widthEdit->text().toDouble();
00221 
00222     double highVal = p_cubeHist->Maximum() - p_cubeHist->Minimum();
00223     double lowVal = p_cubeHist->BinSize();
00224 
00225     double percentage = value - lowVal;
00226     percentage /= (highVal - lowVal);
00227     int valuePos = (int)(percentage * 1000.0);
00228 
00229     p_sliderOverride = true;
00230     p_widthSlider->setValue(valuePos);
00231     p_sliderOverride = false;
00232 
00233     Stretch newStretch = calculateNewStretch();
00234 
00235     if(newStretch.Text() != p_stretch->Text()) {
00236       p_stretch->CopyPairs(newStretch);
00237       emit stretchChanged();
00238     }
00239   }
00240 
00241 
00253   Stretch SawtoothStretchType::calculateNewStretch(double offset,
00254       double width) {
00255     Stretch stretch;
00256     width = fabs(width);
00257 
00258     if(width < p_cubeHist->BinSize())
00259       width = p_cubeHist->BinSize();
00260 
00261     // Still can't do it? Give up
00262     if(width <= 0) return Stretch();
00263 
00264     bool high = false;
00265 
00266     // We want leftPoint to be our starting point for the sawtooth, one left of
00267     //  the minimum
00268     double leftPoint = offset;
00269 
00270     // If leftPoint is too far left, move it right
00271     while(leftPoint < p_cubeHist->Minimum() - width) {
00272       leftPoint += width;
00273       high = !high;
00274     }
00275 
00276     // If leftPoint is too far fight, move it left
00277     while(leftPoint >= p_cubeHist->Minimum()) {
00278       leftPoint -= width;
00279       high = !high;
00280     }
00281 
00282     double currPoint = leftPoint;
00283 
00284     bool terminated = false;
00285     while(!terminated) {
00286       int outValue = (high) ? 255 : 0;
00287 
00288       // This conversion to a string & back prevents infinite loops due to
00289       //   rounding errors and disagreements betweeen double to string
00290       //   conversions later on (in setStretch)
00291       stretch.AddPair(QString::number(currPoint).toDouble(), outValue);
00292 
00293       if(currPoint > p_cubeHist->Maximum()) {
00294         terminated = true;
00295       }
00296 
00297       high = !high;
00298       currPoint += width;
00299     }
00300 
00301     return stretch;
00302   }
00303 
00304 
00310   Stretch SawtoothStretchType::calculateNewStretch() {
00311     return calculateNewStretch(p_offsetEdit->text().toDouble(),
00312                                p_widthEdit->text().toDouble());
00313   }
00314 }
00315