VPTissue Reference Manual
TransformationWidget.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2016 Universiteit Antwerpen
3  *
4  * Licensed under the EUPL, Version 1.1 or as soon they will be approved by
5  * the European Commission - subsequent versions of the EUPL (the "Licence");
6  * You may not use this work except in compliance with the Licence.
7  * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl5
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the Licence is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the Licence for the specific language governing
13  * permissions and limitations under the Licence.
14  */
22 #include "TransformationWidget.h"
23 
24 #include <cmath>
25 #include <QBoxLayout>
26 #include <QCheckBox>
27 #include <QDial>
28 #include <QFrame>
29 #include <QSlider>
30 #include <QSpinBox>
31 #include <QLabel>
32 
33 namespace SimPT_Editor {
34 
35 namespace {
36 
37 double IntRatioToFactor(int intRatio)
38 {
39  // Mapping
40  // First: ratio = slider integer value / 100
41  // Then:
42  // 0 -> 1.0 Not scaled
43  // +x -> x + 1 Ratio y : 1 magnification (with y = x + 1: for every increase of 100 above 0 of the value of the slider, we increase the y : 1 scaling ratio by one)
44  // -x -> 1 / -(x - 1) Ratio 1 : y reduction (inverse of previous line)
45  double ratio = intRatio / 100.0;
46  return (ratio >= 0 ? (ratio + 1) : 1 / (1 - ratio));
47 }
48 
49 int FactorToIntRatio(double factor)
50 {
51  // Mapping is the inverse of IntRatioToFactor
52  double ratio = factor >= 1.0 ? factor - 1 : 1 - 1 / factor;
53  return std::round(ratio * 100);
54 }
55 
56 }
57 
58 TransformationWidget::TransformationWidget(int maxScaleRatio, double maxTranslationX, double maxTranslationY, QWidget *parent)
59  : QWidget(parent), m_rotation(0), m_scaling_x(1.0), m_scaling_y(1.0), m_aspect_ratio_maintained(true), m_translation_x(0.0), m_translation_y(0.0), m_updating(false)
60 {
61  SetupGui(maxScaleRatio, maxTranslationX, maxTranslationY);
62 }
63 
65 {
66 }
67 
68 void TransformationWidget::UpdateRotation(int degrees)
69 {
70  m_rotation = degrees;
71 
72  emit TransformationChanged();
73 }
74 
75 void TransformationWidget::UpdateScalingX(double factor)
76 {
77  m_scaling_x = factor;
78  if (!m_updating) { // To remove annoying mutual signal-slots invocations
79  m_updating = true;
80  m_scaling_x_slider->setValue(FactorToIntRatio(factor));
81  if (m_aspect_ratio_maintained) {
82  m_scaling_y_spin_box->setValue(factor);
83  m_scaling_y_slider->setValue(m_scaling_x_slider->value());
84  }
85  m_updating = false;
86 
87  emit TransformationChanged();
88  }
89 }
90 
91 void TransformationWidget::UpdateScalingX(int value)
92 {
93  if (!m_updating) { // To remove annoying mutual signal-slots invocations
94  m_updating = true;
95  m_scaling_x_spin_box->setValue(IntRatioToFactor(value));
96  if (m_aspect_ratio_maintained) {
97  m_scaling_y_spin_box->setValue(m_scaling_x_spin_box->value());
98  m_scaling_y_slider->setValue(value);
99  }
100  m_updating = false;
101 
102  emit TransformationChanged();
103  }
104 }
105 
106 void TransformationWidget::UpdateScalingY(double factor)
107 {
108  m_scaling_y = factor;
109  if (!m_updating) { // To remove annoying mutual signal-slots invocations
110  m_updating = true;
111  m_scaling_y_slider->setValue(FactorToIntRatio(factor));
112  m_updating = false;
113 
114  emit TransformationChanged();
115  }
116 }
117 
118 void TransformationWidget::UpdateScalingY(int value)
119 {
120  if (!m_updating) { // To remove annoying mutual signal-slots invocations
121  m_updating = true;
122  m_scaling_y_spin_box->setValue(IntRatioToFactor(value));
123  m_updating = false;
124 
125  emit TransformationChanged();
126  }
127 }
128 
129 void TransformationWidget::UpdateAspectRatioMaintained(bool checked)
130 {
131  m_aspect_ratio_maintained = checked;
132  m_scaling_y_spin_box->setEnabled(!checked);
133  m_scaling_y_slider->setEnabled(!checked);
134 
135  emit TransformationChanged();
136 }
137 
138 void TransformationWidget::UpdateTranslationX(double position)
139 {
140  m_translation_x = position;
141  if (!m_updating) { // To remove annoying mutual signal-slots invocations
142  m_updating = true;
143  m_translation_x_slider->setValue(std::round(position * 100));
144  m_updating = false;
145 
146  emit TransformationChanged();
147  }
148 }
149 
150 void TransformationWidget::UpdateTranslationX(int position)
151 {
152  if (!m_updating) { // To remove annoying mutual signal-slots invocations
153  m_updating = true;
154  m_translation_x_spin_box->setValue(position / 100.0);
155  m_updating = false;
156 
157  emit TransformationChanged();
158  }
159 }
160 
161 void TransformationWidget::UpdateTranslationY(double position)
162 {
163  m_translation_y = position;
164  if (!m_updating) { // To remove annoying mutual signal-slots invocations
165  m_updating = true;
166  m_translation_y_slider->setValue(std::round(position * 100));
167  m_updating = false;
168 
169  emit TransformationChanged();
170  }
171 }
172 
173 void TransformationWidget::UpdateTranslationY(int position)
174 {
175  if (!m_updating) { // To remove annoying mutual signal-slots invocations
176  m_updating = true;
177  m_translation_y_spin_box->setValue(position / 100.0);
178  m_updating = false;
179 
180  emit TransformationChanged();
181  }
182 }
183 
184 
185 void TransformationWidget::SetupGui(int maxScaleRatio, double maxTranslationX, double maxTranslationY)
186 {
187  // > GUI Layout
188  QVBoxLayout *layout = new QVBoxLayout();
189 
190  // > Rotation
191  QHBoxLayout *rotationLayout = new QHBoxLayout();
192  rotationLayout->addWidget(new QLabel("rotation"));
193  rotationLayout->addStretch();
194 
195  QSpinBox *rotationSpinBox = new QSpinBox();
196  rotationSpinBox->setRange(-180, 180);
197  rotationSpinBox->setValue(0);
198  rotationSpinBox->setSuffix(QString::fromUtf8("��"));
199  rotationLayout->addWidget(rotationSpinBox);
200  layout->addLayout(rotationLayout);
201 
202  QDial *rotationDial = new QDial();
203  rotationDial->setRange(-180, 180);
204  rotationDial->setWrapping(true);
205  rotationDial->setValue(0);
206  layout->addWidget(rotationDial);
207 
208  connect(rotationSpinBox, SIGNAL(valueChanged(int)), rotationDial, SLOT(setValue(int)));
209  connect(rotationDial, SIGNAL(valueChanged(int)), rotationSpinBox, SLOT(setValue(int)));
210  connect(rotationDial, SIGNAL(valueChanged(int)), this, SLOT(UpdateRotation(int)));
211  // < Rotation
212 
213  QFrame *line = new QFrame();
214  line->setFrameShape(QFrame::HLine);
215  line->setFrameShadow(QFrame::Sunken);
216  layout->addWidget(line);
217 
218  // > Scaling
219  QHBoxLayout *scalingXLayout = new QHBoxLayout();
220  scalingXLayout->addWidget(new QLabel("x scale"));
221  scalingXLayout->addStretch();
222 
223  m_scaling_x_spin_box = new QDoubleSpinBox();
224  m_scaling_x_spin_box->setRange(1.0 / maxScaleRatio, maxScaleRatio);
225  m_scaling_x_spin_box->setValue(m_scaling_x);
226  m_scaling_x_spin_box->setDecimals(2);
227  m_scaling_x_spin_box->setSingleStep(0.1);
228  scalingXLayout->addWidget(m_scaling_x_spin_box);
229  layout->addLayout(scalingXLayout);
230 
231  m_scaling_x_slider = new QSlider(Qt::Horizontal);
232  m_scaling_x_slider->setRange((1 - maxScaleRatio) * 100, (maxScaleRatio - 1) * 100);
233  m_scaling_x_slider->setValue(0);
234  layout->addWidget(m_scaling_x_slider);
235 
236  connect(m_scaling_x_spin_box, SIGNAL(valueChanged(double)), this, SLOT(UpdateScalingX(double)));
237  connect(m_scaling_x_slider, SIGNAL(valueChanged(int)), this, SLOT(UpdateScalingX(int)));
238 
239  QHBoxLayout *scalingYLayout = new QHBoxLayout();
240  scalingYLayout->addWidget(new QLabel("y scale"));
241  scalingYLayout->addStretch();
242 
243  m_scaling_y_spin_box = new QDoubleSpinBox();
244  m_scaling_y_spin_box->setRange(1.0 / maxScaleRatio, maxScaleRatio);
245  m_scaling_y_spin_box->setValue(m_scaling_y);
246  m_scaling_y_spin_box->setDecimals(2);
247  m_scaling_y_spin_box->setSingleStep(0.1);
248  scalingYLayout->addWidget(m_scaling_y_spin_box);
249  layout->addLayout(scalingYLayout);
250 
251  m_scaling_y_slider = new QSlider(Qt::Horizontal);
252  m_scaling_y_slider->setRange((1 - maxScaleRatio) * 100, (maxScaleRatio - 1) * 100);
253  m_scaling_y_slider->setValue(0);
254  layout->addWidget(m_scaling_y_slider);
255 
256  connect(m_scaling_y_spin_box, SIGNAL(valueChanged(double)), this, SLOT(UpdateScalingY(double)));
257  connect(m_scaling_y_slider, SIGNAL(valueChanged(int)), this, SLOT(UpdateScalingY(int)));
258 
259  QCheckBox *aspectRatio = new QCheckBox("Maintain aspect ratio");
260  aspectRatio->setChecked(m_aspect_ratio_maintained);
261  UpdateAspectRatioMaintained(m_aspect_ratio_maintained);
262  connect(aspectRatio, SIGNAL(toggled(bool)), this, SLOT(UpdateAspectRatioMaintained(bool)));
263 
264  layout->addWidget(aspectRatio);
265  // < Scaling
266 
267  line = new QFrame();
268  line->setFrameShape(QFrame::HLine);
269  line->setFrameShadow(QFrame::Sunken);
270  layout->addWidget(line);
271 
272  // > Translation
273  QHBoxLayout *translationXLayout = new QHBoxLayout();
274  translationXLayout->addWidget(new QLabel("x offset"));
275  translationXLayout->addStretch();
276 
277  m_translation_x_spin_box = new QDoubleSpinBox();
278  m_translation_x_spin_box->setRange(-maxTranslationX, maxTranslationX);
279  m_translation_x_spin_box->setValue(m_translation_x);
280  m_translation_x_spin_box->setDecimals(2);
281  translationXLayout->addWidget(m_translation_x_spin_box);
282  layout->addLayout(translationXLayout);
283 
284  m_translation_x_slider = new QSlider(Qt::Horizontal);
285  m_translation_x_slider->setRange(-std::nearbyint(maxTranslationX * 100), std::nearbyint(maxTranslationX * 100));
286  m_translation_x_slider->setValue(0);
287  layout->addWidget(m_translation_x_slider);
288 
289  connect(m_translation_x_spin_box, SIGNAL(valueChanged(double)), this, SLOT(UpdateTranslationX(double)));
290  connect(m_translation_x_slider, SIGNAL(valueChanged(int)), this, SLOT(UpdateTranslationX(int)));
291 
292  QHBoxLayout *translationYLayout = new QHBoxLayout();
293  translationYLayout->addWidget(new QLabel("y offset"));
294  translationYLayout->addStretch();
295 
296  m_translation_y_spin_box = new QDoubleSpinBox();
297  m_translation_y_spin_box->setRange(-maxTranslationY, maxTranslationY);
298  m_translation_y_spin_box->setValue(m_translation_y);
299  m_translation_y_spin_box->setDecimals(2);
300  translationYLayout->addWidget(m_translation_y_spin_box);
301  layout->addLayout(translationYLayout);
302 
303  m_translation_y_slider = new QSlider(Qt::Horizontal);
304  m_translation_y_slider->setRange(-std::nearbyint(maxTranslationY * 100), std::nearbyint(maxTranslationY * 100));
305  m_translation_y_slider->setValue(0);
306  layout->addWidget(m_translation_y_slider);
307 
308  connect(m_translation_y_spin_box, SIGNAL(valueChanged(double)), this, SLOT(UpdateTranslationY(double)));
309  connect(m_translation_y_slider, SIGNAL(valueChanged(int)), this, SLOT(UpdateTranslationY(int)));
310  // < Translation
311 
312  setLayout(layout); // < GUI Layout
313 }
314 
315 } // namespace
void TransformationChanged()
Emitted when the transformation is changed by the user.
Namespace for SimPT tissue editor package.
Definition: Cell.h:32
Interface for TransformationWidget.
TransformationWidget(int maxScaleRatio, double maxTranslationX, double maxTranslationY, QWidget *parent=nullptr)
Constructor.
see the online Qt documentation