ソースを参照

Smarter normalized mode for ctkCoordinatesWidget

Say you have a normal (1,0,0).
You want to change the normal to (0.6,0.6,0.529)
If you change x to 0.6, you get: (0.6,0.566,0.566)
then you change y to 0.6, you get: (0.582,0.6,0.539)
-> x got automatically changed, but you didn't really want to.

This patch ensures that the lastly edited value is not touched when
normalizing the new coordinates.
Julien Finet 12 年 前
コミット
f47c767561
共有2 個のファイルを変更した66 個の追加16 個の削除を含む
  1. 65 16
      Libs/Widgets/ctkCoordinatesWidget.cpp
  2. 1 0
      Libs/Widgets/ctkCoordinatesWidget.h

+ 65 - 16
Libs/Widgets/ctkCoordinatesWidget.cpp

@@ -81,6 +81,7 @@ void ctkCoordinatesWidget::setDimension(int dim)
       {
       newPos[i] = 0.;
       this->addSpinBox();
+      this->LastUserEditedCoordinates.push_back(i);
       }
     }
   else
@@ -92,6 +93,7 @@ void ctkCoordinatesWidget::setDimension(int dim)
       QWidget* widget = item ? item->widget() : 0;
       delete item;
       delete widget;
+      this->LastUserEditedCoordinates.pop_back();
       }
     }
   delete [] this->Coordinates;
@@ -272,7 +274,11 @@ void ctkCoordinatesWidget::setCoordinates(double* coordinates)
       item ? dynamic_cast<QDoubleSpinBox*>(item->widget()) : 0;
     if (spinBox)
       {
+      // we don't want updateCoordinate() to be called.
+      // it could mess with the LastUserEditedCoordinates list.
+      bool spinBoxSignalWasBlocked = spinBox->blockSignals(true);
       spinBox->setValue(this->Coordinates[i]);
+      spinBox->blockSignals(spinBoxSignalWasBlocked);
       }
     }
   this->blockSignals(blocked);
@@ -316,7 +322,6 @@ double const * ctkCoordinatesWidget::coordinates()const
 //------------------------------------------------------------------------------
 void ctkCoordinatesWidget::updateCoordinate(double coordinate)
 {
-  double den = 0.;
   int element = -1;
   for (int i = 0; i < this->Dimension; ++i)
     {
@@ -328,38 +333,82 @@ void ctkCoordinatesWidget::updateCoordinate(double coordinate)
       this->Coordinates[i] = coordinate;
       element = i;
       }
-    else
+    }
+  Q_ASSERT(element != -1);
+  // Update the last edited history by push first the element.
+  for (int i = this->Dimension -1; i > 0; --i)
+    {
+    if (this->LastUserEditedCoordinates[i] == element)
       {
-      den += this->Coordinates[i]*this->Coordinates[i];
+      this->LastUserEditedCoordinates.swap(i,i-1);
       }
     }
-  Q_ASSERT(element != -1);
+  // What is the oldest coordinate to be edited
+  int oldestElement = this->LastUserEditedCoordinates.last();
+
   if (this->isNormalized())
     {
+    // We have to ensure the coordinates are normalized.
+    double den = 0.;
+    double squaredNorm = this->squaredNorm();
     // Old Values xx + yy + zz = 1
     // New values: x'x' + y'y' + z'z' = 1
     // Say we are changing y into y':
     // x'x' + z'z' = 1 - y'y'
-    // Let's pose a the coef to multiply x into x' that keeps the norm to 1:
-    // axax + azaz = 1 - y'y'
-    // aa(xx + zz) = 1 - y'y'
-    // a = sqrt( (1 - y'y') / (xx + zz) )
-    bool mult = true;
-    if (den != 0.0)
+    if (oldestElement != -1 &&
+        this->Coordinates[oldestElement] != 0.0 &&
+        squaredNorm != 0.0)
       {
-      mult = true;
-      den = sqrt( (1. - coordinate * coordinate) / den);
+      // 1) Normalize only with the oldest user edited value
+      // The oldest element is z, that means we try to have
+      // x = x' (so that the user doesn't loose the edit he just made on the
+      // element (x) he edited before this one (y).
+      // Let's pose a the coef to multiply z into z' that keeps the norm to 1
+      // xx + z'z' = 1 - y'y' (because x = x')
+      // xx + azaz = 1 - y'y' (because z' = az)
+      // aa*zz = 1 - y'y' - xx
+      // a = sqrt( (1 - y'y' - xx) / zz )
+      den = (1. - (squaredNorm -
+             this->Coordinates[oldestElement] *
+             this->Coordinates[oldestElement])) /
+              (this->Coordinates[oldestElement] *
+               this->Coordinates[oldestElement]);
+      if (den > 0.)
+        {
+        den = sqrt(den);
+        }
       }
-    else if (this->Dimension > 1)
+    // Maybe 1) failed, then give 2) a chance.
+    if (den <= 0)
       {
-      mult = false;
-      den = sqrt((1. - coordinate*coordinate) / (this->Dimension - 1));
+      oldestElement = -1;
+      }
+    bool mult = true;
+    if (oldestElement == -1)
+      {
+      // 2) Normalize with all the coordinates
+      // Let's pose a the coef to multiply x into x' and z into z' that keeps
+      // the norm to 1:
+      // axax + azaz = 1 - y'y'
+      // aa(xx + zz) = 1 - y'y'
+      // a = sqrt( (1 - y'y') / (xx + zz) )
+      squaredNorm -= coordinate * coordinate;
+      if (squaredNorm != 0.0)
+        {
+        den = sqrt( (1. - coordinate * coordinate) / squaredNorm);
+        }
+      else if (this->Dimension > 1)
+        {
+        mult = false;
+        den = sqrt((1. - coordinate*coordinate) / (this->Dimension - 1));
+        }
       }
     // Normalize coordinates
     double* normalizedCoordinates = new double[this->Dimension];
     for (int i = 0; i < this->Dimension; ++i)
       {
-      if (i != element)
+      if ((i != element && oldestElement == -1) ||
+          (i == oldestElement && oldestElement != -1))
         {
         normalizedCoordinates[i] = mult ? this->Coordinates[i] * den : den;
         }

+ 1 - 0
Libs/Widgets/ctkCoordinatesWidget.h

@@ -134,6 +134,7 @@ protected:
   bool    Normalized;
   int     Dimension;
   double* Coordinates;
+  QList<int> LastUserEditedCoordinates;
 };
 
 #endif