Add option to display affines in polar coords.

This commit is contained in:
mfeemster 2015-02-03 17:11:16 -08:00
parent b1d5db261b
commit c01f444d52
6 changed files with 177 additions and 72 deletions

View File

@ -71,6 +71,14 @@ void DoubleSpinBox::DoubleClickNonZero(double val)
m_DoubleClickNonZero = val; m_DoubleClickNonZero = val;
} }
/// <summary>
/// Get the default step used when the user scrolls.
/// </summary>
double DoubleSpinBox::Step()
{
return m_Step;
}
/// <summary> /// <summary>
/// Set the default step to be used when the user scrolls. /// Set the default step to be used when the user scrolls.
/// </summary> /// </summary>
@ -80,6 +88,14 @@ void DoubleSpinBox::Step(double step)
m_Step = step; m_Step = step;
} }
/// <summary>
/// Get the small step to be used when the user holds down shift while scrolling.
/// </summary>
double DoubleSpinBox::SmallStep()
{
return m_SmallStep;
}
/// <summary> /// <summary>
/// Set the small step to be used when the user holds down shift while scrolling. /// Set the small step to be used when the user holds down shift while scrolling.
/// The default is step / 10, so use this if something else is needed. /// The default is step / 10, so use this if something else is needed.

View File

@ -22,7 +22,9 @@ public:
void DoubleClick(bool b); void DoubleClick(bool b);
void DoubleClickZero(double val); void DoubleClickZero(double val);
void DoubleClickNonZero(double val); void DoubleClickNonZero(double val);
double Step();
void Step(double step); void Step(double step);
double SmallStep();
void SmallStep(double step); void SmallStep(double step);
QLineEdit* lineEdit(); QLineEdit* lineEdit();

View File

@ -211,6 +211,7 @@ public slots:
void OnAffineGroupBoxToggled(bool on); void OnAffineGroupBoxToggled(bool on);
void OnAffineDrawAllCurrentRadioButtonToggled(bool checked); void OnAffineDrawAllCurrentRadioButtonToggled(bool checked);
void OnPolarAffineCheckBoxStateChanged(int state);
//Xforms Color. //Xforms Color.
void OnXformColorIndexChanged(double d); void OnXformColorIndexChanged(double d);
@ -384,6 +385,9 @@ private:
DoubleSpinBox* m_PostY2Spin; DoubleSpinBox* m_PostY2Spin;
DoubleSpinBox* m_PostO1Spin; DoubleSpinBox* m_PostO1Spin;
DoubleSpinBox* m_PostO2Spin; DoubleSpinBox* m_PostO2Spin;
DoubleSpinBox* m_PreSpins[6];
DoubleSpinBox* m_PostSpins[6];
//Palette. //Palette.
SpinBox* m_PaletteHueSpin; SpinBox* m_PaletteHueSpin;

View File

@ -353,7 +353,7 @@
<enum>QTabWidget::Triangular</enum> <enum>QTabWidget::Triangular</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>2</number>
</property> </property>
<property name="usesScrollButtons"> <property name="usesScrollButtons">
<bool>true</bool> <bool>true</bool>
@ -504,8 +504,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>259</width> <width>73</width>
<height>852</height> <height>837</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
@ -2285,7 +2285,7 @@ SpinBox
<enum>QTabWidget::Triangular</enum> <enum>QTabWidget::Triangular</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>2</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="ColorTab"> <widget class="QWidget" name="ColorTab">
<property name="sizePolicy"> <property name="sizePolicy">
@ -2825,8 +2825,8 @@ SpinBox
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>118</width> <width>245</width>
<height>597</height> <height>747</height>
</rect> </rect>
</property> </property>
<property name="autoFillBackground"> <property name="autoFillBackground">
@ -4065,6 +4065,13 @@ SpinBox
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="PolarAffineCheckBox">
<property name="text">
<string>Polar</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="PivotGroupBox"> <widget class="QGroupBox" name="PivotGroupBox">
<property name="autoFillBackground"> <property name="autoFillBackground">
@ -5041,8 +5048,8 @@ SpinBox
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>259</width> <width>73</width>
<height>853</height> <height>454</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">

View File

@ -148,6 +148,7 @@ public:
virtual void MoveCurrentXform(double x, double y, bool pre) { } virtual void MoveCurrentXform(double x, double y, bool pre) { }
virtual void ScaleCurrentXform(double scale, bool pre) { } virtual void ScaleCurrentXform(double scale, bool pre) { }
virtual void ResetCurrentXformAffine(bool pre) { } virtual void ResetCurrentXformAffine(bool pre) { }
virtual void FillBothAffines() { }
//Xforms Color. //Xforms Color.
virtual void XformColorIndexChanged(double d, bool updateRender) { } virtual void XformColorIndexChanged(double d, bool updateRender) { }
@ -368,6 +369,7 @@ public:
virtual void MoveCurrentXform(double x, double y, bool pre) override; virtual void MoveCurrentXform(double x, double y, bool pre) override;
virtual void ScaleCurrentXform(double scale, bool pre) override; virtual void ScaleCurrentXform(double scale, bool pre) override;
virtual void ResetCurrentXformAffine(bool pre) override; virtual void ResetCurrentXformAffine(bool pre) override;
virtual void FillBothAffines() override;
void FillAffineWithXform(Xform<T>* xform, bool pre); void FillAffineWithXform(Xform<T>* xform, bool pre);
//Xforms Color. //Xforms Color.

View File

@ -97,48 +97,64 @@ void Fractorium::InitXformsAffineUI()
connect(ui.ShowPostAffineAllRadio, SIGNAL(toggled(bool)), this, SLOT(OnAffineDrawAllCurrentRadioButtonToggled(bool)), Qt::QueuedConnection); connect(ui.ShowPostAffineAllRadio, SIGNAL(toggled(bool)), this, SLOT(OnAffineDrawAllCurrentRadioButtonToggled(bool)), Qt::QueuedConnection);
connect(ui.ShowPostAffineCurrentRadio, SIGNAL(toggled(bool)), this, SLOT(OnAffineDrawAllCurrentRadioButtonToggled(bool)), Qt::QueuedConnection); connect(ui.ShowPostAffineCurrentRadio, SIGNAL(toggled(bool)), this, SLOT(OnAffineDrawAllCurrentRadioButtonToggled(bool)), Qt::QueuedConnection);
connect(ui.PolarAffineCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnPolarAffineCheckBoxStateChanged(int)), Qt::QueuedConnection);
#ifndef WIN32 #ifndef WIN32
//For some reason linux makes these 24x24, even though the designer explicitly says 16x16. //For some reason linux makes these 24x24, even though the designer explicitly says 16x16.
//Also, in order to get 4 pixels of spacing between elements in the grid layout, 0 must be specified. //Also, in order to get 4 pixels of spacing between elements in the grid layout, 0 must be specified.
ui.PreFlipHorizontalButton->setIconSize(QSize(16, 16)); ui.PreFlipHorizontalButton->setIconSize(QSize(16, 16));
ui.PreFlipVerticalButton->setIconSize(QSize(16, 16)); ui.PreFlipVerticalButton->setIconSize(QSize(16, 16));
ui.PreRotate90CButton->setIconSize(QSize(16, 16)); ui.PreRotate90CButton->setIconSize(QSize(16, 16));
ui.PreRotate90CcButton->setIconSize(QSize(16, 16)); ui.PreRotate90CcButton->setIconSize(QSize(16, 16));
ui.PreRotateCButton->setIconSize(QSize(16, 16)); ui.PreRotateCButton->setIconSize(QSize(16, 16));
ui.PreRotateCcButton->setIconSize(QSize(16, 16)); ui.PreRotateCcButton->setIconSize(QSize(16, 16));
ui.PreMoveUpButton->setIconSize(QSize(16, 16)); ui.PreMoveUpButton->setIconSize(QSize(16, 16));
ui.PreMoveDownButton->setIconSize(QSize(16, 16)); ui.PreMoveDownButton->setIconSize(QSize(16, 16));
ui.PreMoveLeftButton->setIconSize(QSize(16, 16)); ui.PreMoveLeftButton->setIconSize(QSize(16, 16));
ui.PreMoveRightButton->setIconSize(QSize(16, 16)); ui.PreMoveRightButton->setIconSize(QSize(16, 16));
ui.PreScaleDownButton->setIconSize(QSize(16, 16)); ui.PreScaleDownButton->setIconSize(QSize(16, 16));
ui.PreScaleUpButton->setIconSize(QSize(16, 16)); ui.PreScaleUpButton->setIconSize(QSize(16, 16));
ui.PreResetButton->setIconSize(QSize(16, 16)); ui.PreResetButton->setIconSize(QSize(16, 16));
ui.PreAffineGridLayout->setHorizontalSpacing(0); ui.PreAffineGridLayout->setHorizontalSpacing(0);
ui.PreAffineGridLayout->setVerticalSpacing(0); ui.PreAffineGridLayout->setVerticalSpacing(0);
ui.PostFlipHorizontalButton->setIconSize(QSize(16, 16)); ui.PostFlipHorizontalButton->setIconSize(QSize(16, 16));
ui.PostFlipVerticalButton->setIconSize(QSize(16, 16)); ui.PostFlipVerticalButton->setIconSize(QSize(16, 16));
ui.PostRotate90CButton->setIconSize(QSize(16, 16)); ui.PostRotate90CButton->setIconSize(QSize(16, 16));
ui.PostRotate90CcButton->setIconSize(QSize(16, 16)); ui.PostRotate90CcButton->setIconSize(QSize(16, 16));
ui.PostRotateCButton->setIconSize(QSize(16, 16)); ui.PostRotateCButton->setIconSize(QSize(16, 16));
ui.PostRotateCcButton->setIconSize(QSize(16, 16)); ui.PostRotateCcButton->setIconSize(QSize(16, 16));
ui.PostMoveUpButton->setIconSize(QSize(16, 16)); ui.PostMoveUpButton->setIconSize(QSize(16, 16));
ui.PostMoveDownButton->setIconSize(QSize(16, 16)); ui.PostMoveDownButton->setIconSize(QSize(16, 16));
ui.PostMoveLeftButton->setIconSize(QSize(16, 16)); ui.PostMoveLeftButton->setIconSize(QSize(16, 16));
ui.PostMoveRightButton->setIconSize(QSize(16, 16)); ui.PostMoveRightButton->setIconSize(QSize(16, 16));
ui.PostScaleDownButton->setIconSize(QSize(16, 16)); ui.PostScaleDownButton->setIconSize(QSize(16, 16));
ui.PostScaleUpButton->setIconSize(QSize(16, 16)); ui.PostScaleUpButton->setIconSize(QSize(16, 16));
ui.PostResetButton->setIconSize(QSize(16, 16)); ui.PostResetButton->setIconSize(QSize(16, 16));
ui.PostAffineGridLayout->setHorizontalSpacing(0); ui.PostAffineGridLayout->setHorizontalSpacing(0);
ui.PostAffineGridLayout->setVerticalSpacing(0); ui.PostAffineGridLayout->setVerticalSpacing(0);
//Further, the size of the dock widget won't be properly adjusted until the xforms tab is shown. //Further, the size of the dock widget won't be properly adjusted until the xforms tab is shown.
//So show it here and it will be switched back in Fractorium's constructor. //So show it here and it will be switched back in Fractorium's constructor.
ui.ParamsTabWidget->setCurrentIndex(2); ui.ParamsTabWidget->setCurrentIndex(2);
ui.DockWidget->update(); ui.DockWidget->update();
#endif #endif
//Placing pointers to the spin boxes in arrays makes them easier to access in various places.
m_PreSpins[0] = m_PreX1Spin;//A
m_PreSpins[1] = m_PreY1Spin;//B
m_PreSpins[2] = m_PreO1Spin;//C
m_PreSpins[3] = m_PreX2Spin;//D
m_PreSpins[4] = m_PreY2Spin;//E
m_PreSpins[5] = m_PreO2Spin;//F
m_PostSpins[0] = m_PostX1Spin;
m_PostSpins[1] = m_PostY1Spin;
m_PostSpins[2] = m_PostO1Spin;
m_PostSpins[3] = m_PostX2Spin;
m_PostSpins[4] = m_PostY2Spin;
m_PostSpins[5] = m_PostO2Spin;
ui.PostAffineGroupBox->setChecked(true);//Flip it once to force the disabling of the group box. ui.PostAffineGroupBox->setChecked(true);//Flip it once to force the disabling of the group box.
ui.PostAffineGroupBox->setChecked(false); ui.PostAffineGroupBox->setChecked(false);
} }
@ -155,32 +171,52 @@ void FractoriumEmberController<T>::AffineSetHelper(double d, int index, bool pre
{ {
UpdateCurrentXform([&] (Xform<T>* xform) UpdateCurrentXform([&] (Xform<T>* xform)
{ {
QObject* objSender = m_Fractorium->sender(); Affine2D<T>* affine = pre ? &xform->m_Affine : &xform->m_Post;
DoubleSpinBox* spinBox = dynamic_cast<DoubleSpinBox*>(objSender); DoubleSpinBox** spinners = pre ? m_Fractorium->m_PreSpins : m_Fractorium->m_PostSpins;
if (spinBox) if (m_Fractorium->ui.PolarAffineCheckBox->isChecked())
{ {
Affine2D<T>* affine = pre ? &xform->m_Affine : &xform->m_Post;
switch (index) switch (index)
{ {
case 0: case 0:
affine->A(spinBox->value()); case 3:
affine->A(cos(spinners[0]->value() * DEG_2_RAD) * spinners[3]->value());
affine->D(sin(spinners[0]->value() * DEG_2_RAD) * spinners[3]->value());
break; break;
case 1: case 1:
affine->B(spinBox->value()); case 4:
affine->B(cos(spinners[1]->value() * DEG_2_RAD) * spinners[4]->value());
affine->E(sin(spinners[1]->value() * DEG_2_RAD) * spinners[4]->value());
break; break;
case 2: case 2:
affine->C(spinBox->value()); case 5:
default:
affine->C(cos(spinners[2]->value() * DEG_2_RAD) * spinners[5]->value());
affine->F(sin(spinners[2]->value() * DEG_2_RAD) * spinners[5]->value());
break;
}
}
else
{
switch (index)
{
case 0:
affine->A(d);
break;
case 1:
affine->B(d);
break;
case 2:
affine->C(d);
break; break;
case 3: case 3:
affine->D(spinBox->value()); affine->D(d);
break; break;
case 4: case 4:
affine->E(spinBox->value()); affine->E(d);
break; break;
case 5: case 5:
affine->F(spinBox->value()); affine->F(d);
break; break;
} }
} }
@ -465,6 +501,16 @@ void FractoriumEmberController<T>::ResetCurrentXformAffine(bool pre)
/// </summary> /// </summary>
void Fractorium::OnResetAffineButtonClicked(bool checked) { m_Controller->ResetCurrentXformAffine(sender() == ui.PreResetButton); } void Fractorium::OnResetAffineButtonClicked(bool checked) { m_Controller->ResetCurrentXformAffine(sender() == ui.PreResetButton); }
/// <summary>
/// Fill the GUI with the pre and post affine xform values.
/// </summary>
template <typename T>
void FractoriumEmberController<T>::FillBothAffines()
{
FillAffineWithXform(CurrentXform(), true);
FillAffineWithXform(CurrentXform(), false);
}
/// <summary> /// <summary>
/// Fill the GUI with the pre/post affine xform values. /// Fill the GUI with the pre/post affine xform values.
/// </summary> /// </summary>
@ -473,23 +519,26 @@ void Fractorium::OnResetAffineButtonClicked(bool checked) { m_Controller->ResetC
template <typename T> template <typename T>
void FractoriumEmberController<T>::FillAffineWithXform(Xform<T>* xform, bool pre) void FractoriumEmberController<T>::FillAffineWithXform(Xform<T>* xform, bool pre)
{ {
if (pre) DoubleSpinBox** spinners = pre ? m_Fractorium->m_PreSpins : m_Fractorium->m_PostSpins;
const Affine2D<T>& affine = pre ? xform->m_Affine : xform->m_Post;
if (m_Fractorium->ui.PolarAffineCheckBox->isChecked())
{ {
m_Fractorium->m_PreX1Spin->SetValueStealth(xform->m_Affine.A()); spinners[0]->SetValueStealth(RAD_2_DEG * atan2(affine.D(), affine.A()));
m_Fractorium->m_PreY1Spin->SetValueStealth(xform->m_Affine.B()); spinners[1]->SetValueStealth(RAD_2_DEG * atan2(affine.E(), affine.B()));
m_Fractorium->m_PreO1Spin->SetValueStealth(xform->m_Affine.C()); spinners[2]->SetValueStealth(RAD_2_DEG * atan2(affine.F(), affine.C()));
m_Fractorium->m_PreX2Spin->SetValueStealth(xform->m_Affine.D()); spinners[3]->SetValueStealth(Hypot(affine.D(), affine.A()));
m_Fractorium->m_PreY2Spin->SetValueStealth(xform->m_Affine.E()); spinners[4]->SetValueStealth(Hypot(affine.E(), affine.B()));
m_Fractorium->m_PreO2Spin->SetValueStealth(xform->m_Affine.F()); spinners[5]->SetValueStealth(Hypot(affine.F(), affine.C()));
} }
else else
{ {
m_Fractorium->m_PostX1Spin->SetValueStealth(xform->m_Post.A()); spinners[0]->SetValueStealth(affine.A());
m_Fractorium->m_PostY1Spin->SetValueStealth(xform->m_Post.B()); spinners[1]->SetValueStealth(affine.B());
m_Fractorium->m_PostO1Spin->SetValueStealth(xform->m_Post.C()); spinners[2]->SetValueStealth(affine.C());
m_Fractorium->m_PostX2Spin->SetValueStealth(xform->m_Post.D()); spinners[3]->SetValueStealth(affine.D());
m_Fractorium->m_PostY2Spin->SetValueStealth(xform->m_Post.E()); spinners[4]->SetValueStealth(affine.E());
m_Fractorium->m_PostO2Spin->SetValueStealth(xform->m_Post.F()); spinners[5]->SetValueStealth(affine.F());
} }
} }
@ -516,6 +565,31 @@ void Fractorium::OnAffineDrawAllCurrentRadioButtonToggled(bool checked)
ui.GLDisplay->update(); ui.GLDisplay->update();
} }
/// <summary>
/// Set whether to display affine values in polar vs. rectangular coordinates.
/// Updates the current affine display.
/// </summary>
/// <param name="state">The state of the checkbox</param>
void Fractorium::OnPolarAffineCheckBoxStateChanged(int state)
{
double mult = state ? 100 : 0.01;
double step = m_PreX1Spin->Step() * mult;
double small = m_PreX1Spin->SmallStep() * mult;
double click = state ? 90 : 1;
for (int i = 0; i < 3; i++)
{
m_PreSpins[i]->Step(step);
m_PreSpins[i]->SmallStep(small);
m_PostSpins[i]->Step(step);
m_PostSpins[i]->SmallStep(small);
m_PreSpins[i]->DoubleClickZero(click);
m_PostSpins[i]->DoubleClickZero(click);
}
m_Controller->FillBothAffines();
}
/// <summary> /// <summary>
/// Setup a spinner to be placed in a table cell. /// Setup a spinner to be placed in a table cell.
/// Special setup function for affine spinners which differs slightly from the regular /// Special setup function for affine spinners which differs slightly from the regular