瀏覽代碼

Merge branch '348-order-of-magnitude-infinite-loop'

* 348-order-of-magnitude-infinite-loop:
  Add defaultDecimals to ctkUtils::significantDecimals
Julien Finet 12 年之前
父節點
當前提交
488631a0f5

+ 73 - 33
Libs/Core/Testing/Cpp/ctkUtilsTest.cpp

@@ -158,9 +158,10 @@ void ctkUtilsTester::testClosestPowerOfTen_data()
 void ctkUtilsTester::testSignificantDecimals()
 {
   QFETCH(double, value);
+  QFETCH(int, defaultDecimals);
   QFETCH(int, expectedDecimals);
 
-  QCOMPARE(ctk::significantDecimals(value), expectedDecimals);
+  QCOMPARE(ctk::significantDecimals(value, defaultDecimals), expectedDecimals);
 }
 
 // ----------------------------------------------------------------------------
@@ -169,42 +170,81 @@ void ctkUtilsTester::testSignificantDecimals_data()
   QTest::addColumn<double>("value");
   QTest::addColumn<int>("expectedDecimals");
 
-  QTest::newRow("123456 -> 0") << 123456. << 0;
-  QTest::newRow("123456.1 -> 1") << 123456.1 << 1;
-  QTest::newRow("123456.12 -> 2") << 123456.12 << 2;
-  QTest::newRow("123456.123 -> 3") << 123456.123 << 3;
-  QTest::newRow("123456.122 -> 3") << 123456.122 << 3;
-  QTest::newRow("123456.1223 -> 4") << 123456.1223 << 4;
-  QTest::newRow("123456.1234 -> 4") << 123456.1234 << 4;
-  QTest::newRow("123456.0123 -> 4") << 123456.0123 << 4;
-  QTest::newRow("123456.0012 -> 4") << 123456.0012 << 4;
-  QTest::newRow("123456.001234 -> 6") << 123456.001234 << 6;
-  QTest::newRow("123456.000123 -> 6") << 123456.000123 << 6;
-  QTest::newRow("123456.0000 -> 0") << 123456.0000 << 0;
-  QTest::newRow("123456.0001 -> 4") << 123456.0001 << 4;
-  QTest::newRow("123456.3333333 -> 2") << 123456.3333333 << 2;
-  QTest::newRow("123456.1333333 -> 3") << 123456.1333333 << 3;
-  QTest::newRow("123456.3333334 -> 2") << 123456.3333334 << 2;
-  QTest::newRow("123456.00122 -> 5") << 123456.00122 << 5;
-  QTest::newRow("123456.00123 -> 5") << 123456.00123 << 5;
+  // Default decimals= -1
+  QTest::newRow("123456 -> 0") << 123456. << -1 << 0;
+  QTest::newRow("123456.1 -> 1") << 123456.1 << -1 << 1;
+  QTest::newRow("123456.12 -> 2") << 123456.12 << -1 << 2;
+  QTest::newRow("123456.123 -> 3") << 123456.123 << -1 << 3;
+  QTest::newRow("123456.122 -> 3") << 123456.122 << -1 << 3;
+  QTest::newRow("123456.1223 -> 4") << 123456.1223 << -1 << 4;
+  QTest::newRow("123456.1234 -> 4") << 123456.1234 << -1 << 4;
+  QTest::newRow("123456.0123 -> 4") << 123456.0123 << -1 << 4;
+  QTest::newRow("123456.0012 -> 4") << 123456.0012 << -1 << 4;
+  QTest::newRow("123456.001234 -> 6") << 123456.001234 << -1 << 6;
+  QTest::newRow("123456.000123 -> 6") << 123456.000123 << -1 << 6;
+  QTest::newRow("123456.0000 -> 0") << 123456.0000 << -1 << 0;
+  QTest::newRow("123456.0001 -> 4") << 123456.0001 << -1 << 4;
+  QTest::newRow("123456.3333333 -> 2") << 123456.3333333 << -1 << 2;
+  QTest::newRow("123456.1333333 -> 3") << 123456.1333333 << -1 << 3;
+  QTest::newRow("123456.3333334 -> 2") << 123456.3333334 << -1 << 2;
+  QTest::newRow("123456.00122 -> 5") << 123456.00122 << -1 << 5;
+  QTest::newRow("123456.00123 -> 5") << 123456.00123 << -1 << 5;
   // internally representated as 123456.001109999997425
-  QTest::newRow("123456.00111 -> 5") << 123456.00111 << 5;
+  QTest::newRow("123456.00111 -> 5") << 123456.00111 << -1 << 5;
   // internally representated as 123456.270000000004075
   QTest::newRow("123456.26999999999999996 -> 2")
-    << 123456.26999999999999996 << 2;
-  QTest::newRow("123456.863899999999987 -> 4") << 123456.863899999999987 << 4;
-  QTest::newRow("0.5 -> 1") << 0.5 << 1;
-  QTest::newRow("0.25 -> 2") << 0.25 << 2;
-  QTest::newRow("0.125 -> 3") << 0.125 << 3;
-  QTest::newRow("0.1234567891013151 -> 16") << 0.1234567891013151 << 16;
-  QTest::newRow("0. -> 0") << 0. << 0;
-  QTest::newRow("inf -> 0") << std::numeric_limits<double>::infinity() << 0;
-  QTest::newRow("-inf -> 0") << -std::numeric_limits<double>::infinity() << 0;
-  QTest::newRow("nan -> -1") << std::numeric_limits<double>::quiet_NaN() << -1;
-  QTest::newRow("min -> 16") << std::numeric_limits<double>::min() << 16;
-  QTest::newRow("max -> 0") << std::numeric_limits<double>::max() << 0;
+    << 123456.26999999999999996 << -1 << 2;
+  QTest::newRow("123456.863899999999987 -> 4") << 123456.863899999999987 << -1 << 4;
+  QTest::newRow("0.5 -> 1") << 0.5 << -1 << 1;
+  QTest::newRow("0.25 -> 2") << 0.25 << -1 << 2;
+  QTest::newRow("0.125 -> 3") << 0.125 << -1 << 3;
+  QTest::newRow("0.1234567891013151 -> 16") << 0.1234567891013151 << -1 << 16;
+  QTest::newRow("0. -> 0") << 0. << -1 << 0;
+  QTest::newRow("inf -> 0") << std::numeric_limits<double>::infinity() << -1 << 0;
+  QTest::newRow("-inf -> 0") << -std::numeric_limits<double>::infinity() << -1 << 0;
+  QTest::newRow("nan -> -1") << std::numeric_limits<double>::quiet_NaN() << -1 << -1;
+  QTest::newRow("min -> 16") << std::numeric_limits<double>::min() << -1 << 16;
+  QTest::newRow("max -> 0") << std::numeric_limits<double>::max() << -1 << 0;
   QTest::newRow("denorm -> 16") << std::numeric_limits<double>::denorm_min()
-                                << 16;
+                                << -1 << 16;
+
+  // Default decimals= 3
+  QTest::newRow("123456 -> 0") << 123456. << 3 << 0;
+  QTest::newRow("123456.1 -> 1") << 123456.1 << 3 << 1;
+  QTest::newRow("123456.12 -> 2") << 123456.12 << 3 << 2;
+  QTest::newRow("123456.123 -> 3") << 123456.123 << 3 << 3;
+  QTest::newRow("123456.122 -> 3") << 123456.122 << 3 << 3;
+  QTest::newRow("123456.1223 -> 4") << 123456.1223 << 3 << 4;
+  QTest::newRow("123456.1234 -> 4") << 123456.1234 << 3 << 4;
+  QTest::newRow("123456.0123 -> 4") << 123456.0123 << 3 << 4;
+  QTest::newRow("123456.0012 -> 4") << 123456.0012 << 3 << 4;
+  QTest::newRow("123456.001234 -> 6") << 123456.001234 << 3 << 6;
+  QTest::newRow("123456.000123 -> 6") << 123456.000123 << 3 << 6;
+  QTest::newRow("123456.0000 -> 0") << 123456.0000 << 3 << 0;
+  QTest::newRow("123456.0001 -> 4") << 123456.0001 << 3 << 4;
+  QTest::newRow("123456.3333333 -> 2") << 123456.3333333 << 3 << 2;
+  QTest::newRow("123456.1333333 -> 3") << 123456.1333333 << 3 << 3;
+  QTest::newRow("123456.3333334 -> 2") << 123456.3333334 << 3 << 2;
+  QTest::newRow("123456.00122 -> 5") << 123456.00122 << 3 << 5;
+  QTest::newRow("123456.00123 -> 5") << 123456.00123 << 3 << 5;
+  // internally representated as 123456.001109999997425
+  QTest::newRow("123456.00111 -> 5") << 123456.00111 << 3 << 5;
+  // internally representated as 123456.270000000004075
+  QTest::newRow("123456.26999999999999996 -> 2")
+    << 123456.26999999999999996 << 3 << 2;
+  QTest::newRow("123456.863899999999987 -> 4") << 123456.863899999999987 << 3 << 4;
+  QTest::newRow("0.5 -> 1") << 0.5 << 3 << 1;
+  QTest::newRow("0.25 -> 2") << 0.25 << 3 << 2;
+  QTest::newRow("0.125 -> 3") << 0.125 << 3 << 3;
+  QTest::newRow("0.1234567891013151 -> 16") << 0.1234567891013151 << 3 << 3;
+  QTest::newRow("0. -> 0") << 0. << 3 << 0;
+  QTest::newRow("inf -> 0") << std::numeric_limits<double>::infinity() << 3 << 0;
+  QTest::newRow("-inf -> 0") << -std::numeric_limits<double>::infinity() << 3 << 0;
+  QTest::newRow("nan -> -1") << std::numeric_limits<double>::quiet_NaN() << 3 << -1;
+  QTest::newRow("min -> 16") << std::numeric_limits<double>::min() << 3 << 16;
+  QTest::newRow("max -> 0") << std::numeric_limits<double>::max() << 3 << 0;
+  QTest::newRow("denorm -> 16") << std::numeric_limits<double>::denorm_min()
+                                << 3 << 16;
 
 }
 

+ 8 - 1
Libs/Core/ctkUtils.cpp

@@ -162,7 +162,7 @@ QRegExp ctk::nameFiltersToRegExp(const QStringList& nameFilters)
 }
 
 //-----------------------------------------------------------------------------
-int ctk::significantDecimals(double value)
+int ctk::significantDecimals(double value, int defaultDecimals)
 {
   if (value == 0.
       || qAbs(value) == std::numeric_limits<double>::infinity())
@@ -200,10 +200,17 @@ int ctk::significantDecimals(double value)
     // Last digit
     if (i == fractional.length() - 1)
       {
+      // If we are here, that means that the right number of significant
+      // decimals for the number has not been figured out yet.
       if (previousRepeat > 2 && !(only0s && isUnit) )
         {
         return i - previousRepeat;
         }
+      // If defaultDecimals has been provided, just use it.
+      if (defaultDecimals >= 0)
+        {
+        return defaultDecimals;
+        }
       return fractional.length();
       }
     // get ready for next

+ 5 - 2
Libs/Core/ctkUtils.h

@@ -78,12 +78,15 @@ QRegExp CTK_CORE_EXPORT nameFiltersToRegExp(const QStringList& nameFilters);
 ///
 /// \ingroup Core
 /// Return a "smart" number of decimals needed to display (in a gui) a floating
-/// number. 16 is the max that can be returned, -1 for NaN numbers.
+/// number. 16 is the max that can be returned, -1 for NaN numbers. When the
+/// number of decimals is not obvious, it defaults to defaultDecimals if it is
+/// different from -1, 16 otherwise.
 /// e.g. significantDecimals(120.01) returns 2
 ///      significantDecimals(123456.1333333) returns 3
 ///      significantDecimals(123456.26999999999999996) returns 2
+///      significantDecimals(123456.12345678901234567, 3) return 3
 /// See more cases in the test ctkUtilsSignificantDecimalsTest1
-int CTK_CORE_EXPORT significantDecimals(double value);
+int CTK_CORE_EXPORT significantDecimals(double value, int defaultDecimals = -1);
 
 ///
 /// \ingroup Core

+ 45 - 0
Libs/Widgets/Testing/Cpp/ctkCoordinatesWidgetTest.cpp

@@ -20,6 +20,7 @@
 
 // Qt includes
 #include <QApplication>
+#include <QDoubleSpinBox>
 #include <QString>
 #include <QStyle>
 #include <QStyleOptionSlider>
@@ -39,6 +40,11 @@ private slots:
 
   void testNormalized();
   void testNormalized_data();
+
+  void testDecimalsByValue();
+  void testDecimalsByValue_data();
+private:
+  void testDecimals(ctkCoordinatesWidget* coordinatesWidget, int decimals);
 };
 
 // ----------------------------------------------------------------------------
@@ -94,6 +100,45 @@ void ctkCoordinatesWidgetTester::testNormalized_data()
   QTest::newRow("1,2,3") << QVector3D(1., 2., 3.);
   QTest::newRow("-1,-2,-3") << QVector3D(-1., -2., -3.);
 }
+// ----------------------------------------------------------------------------
+void ctkCoordinatesWidgetTester
+::testDecimals(ctkCoordinatesWidget* coordinatesWidget, int decimals)
+{
+  QList<QDoubleSpinBox*> spinBoxes =
+    coordinatesWidget->findChildren<QDoubleSpinBox*>();
+  foreach(QDoubleSpinBox* spinBox, spinBoxes)
+    {
+    QCOMPARE(spinBox->decimals(), decimals);
+    }
+}
+
+// ----------------------------------------------------------------------------
+void ctkCoordinatesWidgetTester::testDecimalsByValue()
+{
+  ctkCoordinatesWidget coordinatesWidget;
+  coordinatesWidget.setDecimalsOption(
+    ctkDoubleSpinBox::DecimalsByValue);
+  coordinatesWidget.setCoordinates(0.,0.,0.);
+
+  QFETCH(QVector3D, coordinates);
+  coordinatesWidget.setCoordinates(coordinates.x(), coordinates.y(), coordinates.z());
+
+  QFETCH(int, expectedDecimals);
+  testDecimals(&coordinatesWidget, expectedDecimals);
+}
+
+// ----------------------------------------------------------------------------
+void ctkCoordinatesWidgetTester::testDecimalsByValue_data()
+{
+  QTest::addColumn<QVector3D>("coordinates");
+  QTest::addColumn<int>("expectedDecimals");
+
+  QTest::newRow("1, 1, 1.3") << QVector3D(1., 1., 1.3) << 1;
+  QTest::newRow("16 digits") << QVector3D(-86.1234567891234567,
+                                          133.98765432198765432,
+                                          116.01234567891011121) << 3;
+  QTest::newRow("same value more digits") << QVector3D(0.001, 0.002, 0.0004) << 4;
+}
 
 // ----------------------------------------------------------------------------
 CTK_TEST_MAIN(ctkCoordinatesWidgetTest)

+ 15 - 10
Libs/Widgets/Testing/Cpp/ctkDoubleSpinBoxTest.cpp

@@ -447,8 +447,10 @@ void ctkDoubleSpinBoxTester::testDecimalsByValue()
   spinBox.setMaximum(100.);
   spinBox.setValue(1.23);
   spinBox.setDecimalsOption( ctkDoubleSpinBox::DecimalsByValue );
-  QSignalSpy spy(&spinBox, SIGNAL(decimalsChanged(int)));
+  spinBox.setDecimals(4);
+
   const int oldDecimals = spinBox.decimals();
+  QSignalSpy spy(&spinBox, SIGNAL(decimalsChanged(int)));
 
   QFETCH(double, value);
   spinBox.setValue(value);
@@ -457,7 +459,7 @@ void ctkDoubleSpinBoxTester::testDecimalsByValue()
   QFETCH(int, expectedDecimals);
 
   QCOMPARE(spinBox.text(), expectedText);
-  QCOMPARE(spinBox.value(), value);
+  QCOMPARE(spinBox.value(), expectedText.toDouble());
   QCOMPARE(spinBox.decimals(), expectedDecimals);
   QCOMPARE(spy.count(), spinBox.decimals() != oldDecimals ? 1 : 0);
 }
@@ -469,15 +471,18 @@ void ctkDoubleSpinBoxTester::testDecimalsByValue_data()
   QTest::addColumn<QString>("expectedText");
   QTest::addColumn<int>("expectedDecimals");
 
-  QTest::newRow("ctkDoubleSpinBox::DecimalsByValue 0") << 0. << "0"<< 0;
-  QTest::newRow("ctkDoubleSpinBox::DecimalsByValue 0.1") << 0.1 << "0.1" << 1;
-  QTest::newRow("ctkDoubleSpinBox::DecimalsByValue 0.02") << 0.02 << "0.02" << 2;
-  QTest::newRow("ctkDoubleSpinBox::DecimalsByValue 10.003") << 10.003 << "10.003" << 3;
-  QTest::newRow("ctkDoubleSpinBox::DecimalsByValue -0.0004") << -0.0004 << "-0.0004" << 4;
-  QTest::newRow("ctkDoubleSpinBox::DecimalsByValue 0.000056") << 0.000056 << "0.000056" << 6;
+  QTest::newRow("0") << 0. << "0"<< 0;
+  QTest::newRow("0.1") << 0.1 << "0.1" << 1;
+  QTest::newRow("0.02") << 0.02 << "0.02" << 2;
+  QTest::newRow("10.003") << 10.003 << "10.003" << 3;
+  QTest::newRow("-0.0004") << -0.0004 << "-0.0004" << 4;
+  QTest::newRow("0.000056") << 0.000056 << "0.000056" << 6;
   // internally represented as 123456.001109999997425
-  QTest::newRow("ctkDoubleSpinBox::DecimalsByValue 5.00111") << 5.00111 << "5.00111" << 5;
-  QTest::newRow("ctkDoubleSpinBox::DecimalsByValue 0.1234567891013151") << 0.1234567891013151 << "0.1234567891013151" << 16;
+  QTest::newRow("5.00111") << 5.00111 << "5.00111" << 5;
+  QTest::newRow("same value with more decimals") << 1.234567 << "1.234567" << 6;
+  QTest::newRow("same value") << 1.23 << "1.23" << 2;
+  QTest::newRow("same value with less decimals") << 1.234 << "1.234" << 3;
+  QTest::newRow("16 decimals") << 0.1234567891013151 << "0.1235" << 4;
 }
 
 // ----------------------------------------------------------------------------

+ 24 - 6
Libs/Widgets/ctkCoordinatesWidget.cpp

@@ -20,6 +20,7 @@
 
 // Qt includes
 #include <QDebug>
+#include <QDoubleSpinBox>
 #include <QHBoxLayout>
 
 // CTK includes
@@ -68,7 +69,7 @@ void ctkCoordinatesWidget::addSpinBox()
            this, SLOT(updateCoordinate(double)));
   // Same number of decimals within the spinboxes.
   connect( spinBox, SIGNAL(decimalsChanged(int)),
-           this, SLOT(setDecimals(int)));
+           this, SLOT(setTemporaryDecimals(int)));
   this->layout()->addWidget(spinBox);
 }
 
@@ -202,6 +203,21 @@ void ctkCoordinatesWidget::setDecimals(int newDecimals)
 }
 
 //------------------------------------------------------------------------------
+void ctkCoordinatesWidget::setTemporaryDecimals(int newDecimals)
+{
+  for (int i = 0; this->layout()->itemAt(i); ++i)
+    {
+    QLayoutItem* item = this->layout()->itemAt(i);
+    ctkDoubleSpinBox* spinBox = item ? qobject_cast<ctkDoubleSpinBox*>(
+      item->widget()) : 0;
+    if (spinBox)
+      {
+      spinBox->spinBox()->setDecimals(newDecimals);
+      }
+    }
+}
+
+//------------------------------------------------------------------------------
 int ctkCoordinatesWidget::decimals() const
 {
   return this->Decimals;
@@ -307,20 +323,22 @@ void ctkCoordinatesWidget::setCoordinates(double* coordinates)
       {
       // we don't want updateCoordinate() to be called.
       // it could mess with the LastUserEditedCoordinates list.
-      if (spinBox->displayedValue() != this->Coordinates[i])
+      bool spinBoxSignalWasBlocked = spinBox->blockSignals(true);
+      if (spinBox->value() != this->Coordinates[i])
         {
-        bool spinBoxSignalWasBlocked = spinBox->blockSignals(true);
-        spinBox->setValue(this->Coordinates[i]);
-        spinBox->blockSignals(spinBoxSignalWasBlocked);
         valuesModified = true;
         }
+      // Still setValue needs to be called to recompute the number of decimals
+      // if DecimalsByValue is set.
+      spinBox->setValue(this->Coordinates[i]);
+      spinBox->blockSignals(spinBoxSignalWasBlocked);
       maxDecimals = qMax(maxDecimals, spinBox->decimals());
       }
     }
   this->blockSignals(blocked);
+  this->setTemporaryDecimals(maxDecimals);
   if (valuesModified)
     {
-    this->setDecimals(maxDecimals);
     this->updateCoordinates();
     }
 }

+ 1 - 0
Libs/Widgets/ctkCoordinatesWidget.h

@@ -130,6 +130,7 @@ Q_SIGNALS:
 protected Q_SLOTS:
   void updateCoordinate(double);
   void updateCoordinates();
+  void setTemporaryDecimals(int);
 
 protected:
   void addSpinBox();

+ 24 - 5
Libs/Widgets/ctkDoubleSpinBox.cpp

@@ -214,6 +214,12 @@ bool ctkDoubleSpinBoxPrivate::compare(double x1, double x2) const
 }
 
 //-----------------------------------------------------------------------------
+double ctkDoubleSpinBoxPrivate::round(double value, int decimals) const
+{
+  return QString::number(value, 'f', decimals).toDouble();
+}
+
+//-----------------------------------------------------------------------------
 QString ctkDoubleSpinBoxPrivate::stripped(const QString& text, int* pos) const
 {
   Q_Q(const ctkDoubleSpinBox);
@@ -869,7 +875,9 @@ int ctkDoubleSpinBox::decimals() const
 void ctkDoubleSpinBox::setDecimals(int dec)
 {
   Q_D(ctkDoubleSpinBox);
-  if (d->Mode == ctkDoubleSpinBox::SetIfDifferent && dec == this->decimals())
+  if (d->Mode == ctkDoubleSpinBox::SetIfDifferent
+      && dec == this->decimals()
+      && dec == d->DefaultDecimals)
     {
     return;
     }
@@ -914,12 +922,23 @@ void ctkDoubleSpinBox::setValue(double value)
 }
 
 //-----------------------------------------------------------------------------
-void ctkDoubleSpinBox::setValueIfDifferent(double value)
+void ctkDoubleSpinBox::setValueIfDifferent(double newValue)
 {
   Q_D(ctkDoubleSpinBox);
-  if (! d->compare(this->value(), value))
+  bool set = false;
+  if (d->DOption & ctkDoubleSpinBox::DecimalsByValue)
     {
-    this->setValueAlways(value);
+    int newValueDecimals = ctk::significantDecimals(newValue, d->DefaultDecimals);
+    set = this->value() != d->round(newValue, newValueDecimals)
+      || d->SpinBox->decimals() != newValueDecimals;
+    }
+  else
+    {
+    set = !d->compare(this->value(), newValue);
+    }
+  if (set)
+    {
+    this->setValueAlways(newValue);
     }
 }
 
@@ -929,7 +948,7 @@ void ctkDoubleSpinBox::setValueAlways(double value)
   Q_D(ctkDoubleSpinBox);
   if (d->DOption & ctkDoubleSpinBox::DecimalsByValue)
     {
-    d->setValue(value, ctk::significantDecimals(value));
+    d->setValue(value, ctk::significantDecimals(value, d->DefaultDecimals));
     }
   else
     {

+ 2 - 0
Libs/Widgets/ctkDoubleSpinBox_p.h

@@ -94,6 +94,8 @@ public:
   void init();
   /// Compare two double previously rounded according to the number of decimals
   bool compare(double x1, double x2) const;
+  /// Return a value rounded with the number of decimals
+  double round(double value, int decimals)const;
 
   /// Remove prefix and suffix
   QString stripped(const QString& text, int* pos)const;