瀏覽代碼

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