28 reference {reference}, |
28 reference {reference}, |
29 ui {*new Ui::SubfileReferenceEditor} |
29 ui {*new Ui::SubfileReferenceEditor} |
30 { |
30 { |
31 this->ui.setupUi(this); |
31 this->ui.setupUi(this); |
32 this->ui.referenceName->setText(reference->referenceName()); |
32 this->ui.referenceName->setText(reference->referenceName()); |
|
33 this->ui.matrixEditor->setPosition(reference->position()); |
|
34 this->ui.matrixEditor->setMatrix(reference->transformationMatrix()); |
33 this->color = reference->color(); |
35 this->color = reference->color(); |
34 ::setColorButton(this->ui.colorButton, this->color); |
36 ::setColorButton(this->ui.colorButton, this->color); |
35 this->ui.positionX->setValue(reference->position().x); |
|
36 this->ui.positionY->setValue(reference->position().y); |
|
37 this->ui.positionZ->setValue(reference->position().z); |
|
38 connect( |
37 connect( |
39 this->ui.colorButton, |
38 this->ui.colorButton, |
40 &QPushButton::clicked, |
39 &QPushButton::clicked, |
41 [&]() |
40 [&]() |
42 { |
41 { |
43 if (ColorSelector::selectColor(this, this->color, this->color)) |
42 if (ColorSelector::selectColor(this, this->color, this->color)) |
44 ::setColorButton(this->ui.colorButton, this->color); |
43 ::setColorButton(this->ui.colorButton, this->color); |
45 } |
44 } |
46 ); |
45 ); |
47 for (int i : {0, 1, 2}) |
|
48 for (int j : {0, 1, 2}) |
|
49 { |
|
50 QLayoutItem* item = this->ui.matrixLayout->itemAtPosition(i, j); |
|
51 QDoubleSpinBox* spinbox = item ? qobject_cast<QDoubleSpinBox*>(item->widget()) : nullptr; |
|
52 withSignalsBlocked(spinbox, [&]() |
|
53 { |
|
54 spinbox->setValue(reference->transformationMatrix()(i, j)); |
|
55 }); |
|
56 connect( |
|
57 spinbox, |
|
58 qOverload<double>(&QDoubleSpinBox::valueChanged), |
|
59 this, |
|
60 &SubfileReferenceEditor::matrixChanged |
|
61 ); |
|
62 } |
|
63 connect( |
46 connect( |
64 this->ui.primitivesTreeView, |
47 this->ui.primitivesTreeView, |
65 &QTreeView::clicked, |
48 &QTreeView::clicked, |
66 [&](const QModelIndex& index) |
49 [&](const QModelIndex& index) |
67 { |
50 { |
70 |
53 |
71 if (primitiveName.isValid()) |
54 if (primitiveName.isValid()) |
72 this->ui.referenceName->setText(primitiveName.toString()); |
55 this->ui.referenceName->setText(primitiveName.toString()); |
73 } |
56 } |
74 ); |
57 ); |
75 |
|
76 for (QDoubleSpinBox* spinbox : {this->ui.scalingX, this->ui.scalingY, this->ui.scalingZ}) |
|
77 { |
|
78 connect( |
|
79 spinbox, |
|
80 qOverload<double>(&QDoubleSpinBox::valueChanged), |
|
81 this, |
|
82 &SubfileReferenceEditor::scalingChanged |
|
83 ); |
|
84 } |
|
85 |
|
86 // Fill in the initial scaling values |
|
87 for (int column : {0, 1, 2}) |
|
88 { |
|
89 QDoubleSpinBox* spinbox = this->vectorElement(column); |
|
90 withSignalsBlocked(spinbox, [&]() |
|
91 { |
|
92 spinbox->setValue(this->matrixScaling(column)); |
|
93 }); |
|
94 } |
|
95 } |
58 } |
96 |
59 |
97 SubfileReferenceEditor::~SubfileReferenceEditor() |
60 SubfileReferenceEditor::~SubfileReferenceEditor() |
98 { |
61 { |
99 delete &this->ui; |
62 delete &this->ui; |
100 } |
63 } |
101 |
64 |
102 /* |
|
103 * Returns a spinbox from the matrix grid at position (row, column). |
|
104 * Row and column must be within [0, 2]. |
|
105 */ |
|
106 QDoubleSpinBox* SubfileReferenceEditor::matrixCell(int row, int column) const |
|
107 { |
|
108 if (qBound(0, row, 2) != row or qBound(0, column, 2) != column) |
|
109 { |
|
110 throw std::out_of_range {"bad row and column values"}; |
|
111 } |
|
112 else |
|
113 { |
|
114 QLayoutItem* item = this->ui.matrixLayout->itemAtPosition(row, column); |
|
115 return item ? qobject_cast<QDoubleSpinBox*>(item->widget()) : nullptr; |
|
116 } |
|
117 } |
|
118 |
|
119 /* |
|
120 * Returns a spinbox for the vector element at the given position |
|
121 * Index must be within [0, 2] |
|
122 */ |
|
123 QDoubleSpinBox* SubfileReferenceEditor::vectorElement(int index) |
|
124 { |
|
125 switch (index) |
|
126 { |
|
127 case 0: |
|
128 return this->ui.scalingX; |
|
129 |
|
130 case 1: |
|
131 return this->ui.scalingY; |
|
132 |
|
133 case 2: |
|
134 return this->ui.scalingZ; |
|
135 |
|
136 default: |
|
137 throw std::out_of_range {"bad index"}; |
|
138 } |
|
139 } |
|
140 |
|
141 void SubfileReferenceEditor::accept() |
65 void SubfileReferenceEditor::accept() |
142 { |
66 { |
143 this->reference->setReferenceName(this->ui.referenceName->text()); |
67 this->reference->setReferenceName(this->ui.referenceName->text()); |
144 Matrix transformationMatrix; |
|
145 for (int i : {0, 1, 2}) |
|
146 for (int j : {0, 1, 2}) |
|
147 { |
|
148 transformationMatrix(i, j) = this->matrixCell(i, j)->value(); |
|
149 } |
|
150 this->reference->setTransformationMatrix(transformationMatrix); |
|
151 this->reference->setPosition({ |
|
152 this->ui.positionX->value(), |
|
153 this->ui.positionY->value(), |
|
154 this->ui.positionZ->value() |
|
155 }); |
|
156 this->reference->setColor(this->color); |
68 this->reference->setColor(this->color); |
|
69 this->reference->setTransformationMatrix(this->ui.matrixEditor->matrix()); |
|
70 this->reference->setPosition(this->ui.matrixEditor->position()); |
157 QDialog::accept(); |
71 QDialog::accept(); |
158 } |
72 } |
159 |
73 |
160 void SubfileReferenceEditor::setPrimitivesTree(PrimitiveManager* primitives) |
74 void SubfileReferenceEditor::setPrimitivesTree(PrimitiveManager* primitives) |
161 { |
75 { |
162 this->ui.primitivesTreeView->setModel(primitives); |
76 this->ui.primitivesTreeView->setModel(primitives); |
163 } |
77 } |
164 |
|
165 double SubfileReferenceEditor::matrixScaling(int column) const |
|
166 { |
|
167 return sqrt( |
|
168 pow(this->matrixCell(0, column)->value(), 2) + |
|
169 pow(this->matrixCell(1, column)->value(), 2) + |
|
170 pow(this->matrixCell(2, column)->value(), 2) |
|
171 ); |
|
172 } |
|
173 |
|
174 /* |
|
175 * Updates the appropriate matrix column when a scaling vector element is changed. |
|
176 */ |
|
177 void SubfileReferenceEditor::scalingChanged() |
|
178 { |
|
179 for (int column : {0, 1, 2}) |
|
180 { |
|
181 if (this->sender() == this->vectorElement(column)) |
|
182 { |
|
183 double oldScaling = this->matrixScaling(column); |
|
184 double newScaling = static_cast<QDoubleSpinBox*>(this->sender())->value(); |
|
185 |
|
186 if (not qFuzzyCompare(newScaling, 0.0)) |
|
187 { |
|
188 for (int row : {0, 1, 2}) |
|
189 { |
|
190 double cellValue = this->matrixCell(row, column)->value(); |
|
191 cellValue *= newScaling / oldScaling; |
|
192 QDoubleSpinBox* cellWidget = this->matrixCell(row, column); |
|
193 withSignalsBlocked(cellWidget, [&]() |
|
194 { |
|
195 cellWidget->setValue(cellValue); |
|
196 }); |
|
197 } |
|
198 } |
|
199 |
|
200 break; |
|
201 } |
|
202 } |
|
203 } |
|
204 |
|
205 /* |
|
206 * Finds the position for the given cell widget. |
|
207 */ |
|
208 QPair<int, int> SubfileReferenceEditor::cellPosition(QDoubleSpinBox* cellWidget) |
|
209 { |
|
210 for (int row : {0, 1, 2}) |
|
211 for (int column : {0, 1, 2}) |
|
212 { |
|
213 if (this->matrixCell(row, column) == cellWidget) |
|
214 return {row, column}; |
|
215 } |
|
216 |
|
217 throw std::out_of_range {"widget is not in the matrix"}; |
|
218 } |
|
219 |
|
220 /* |
|
221 * Updates the appropriate scaling vector element when a matrix cell is changed. |
|
222 */ |
|
223 void SubfileReferenceEditor::matrixChanged() |
|
224 { |
|
225 QDoubleSpinBox* cellWidget = static_cast<QDoubleSpinBox*>(this->sender()); |
|
226 |
|
227 try |
|
228 { |
|
229 int column = this->cellPosition(cellWidget).second; |
|
230 QDoubleSpinBox* spinbox = this->vectorElement(column); |
|
231 withSignalsBlocked(spinbox, [&]() |
|
232 { |
|
233 spinbox->setValue(this->matrixScaling(column)); |
|
234 }); |
|
235 } |
|
236 catch (const std::out_of_range&) {} |
|
237 } |
|