1
/***************************************************************************
2
* Copyright (c) 2009 Werner Mayer <wmayer[at]users.sourceforge.net> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
25
#include <QDialogButtonBox>
27
#include <QSignalMapper>
29
#include <App/GeoFeature.h>
30
#include <App/PropertyGeo.h>
33
#include "Application.h"
36
#include "ui_Placement.h"
37
#include "ViewProvider.h"
38
#include "WaitCursor.h"
41
using namespace Gui::Dialog;
43
namespace Gui { namespace Dialog {
47
bool operator () (const std::pair<std::string, App::Property*>& elem) const
49
if (elem.first == "Placement") {
50
return elem.second->isDerivedFrom
51
(Base::Type::fromName("App::PropertyPlacement"));
60
// ----------------------------------------------------------------------------
62
TransformStrategy::TransformStrategy() = default;
64
TransformStrategy::~TransformStrategy() = default;
66
Base::Vector3d TransformStrategy::getRotationCenter() const
68
// get the global bounding box of all selected objects and use its center as
70
std::set<App::DocumentObject*> objects = transformObjects();
71
if (!objects.empty()) {
72
Base::BoundBox3d bbox;
74
for (const auto & object : objects) {
75
if (object->isDerivedFrom<App::GeoFeature>()) {
76
// search for a data property
77
const App::PropertyGeometry* geo = static_cast<App::GeoFeature*>(object)->getPropertyOfGeometry();
80
bbox = geo->getBoundingBox();
82
bbox.Add(geo->getBoundingBox());
88
return Base::Vector3d((bbox.MinX+bbox.MaxX)/2,
89
(bbox.MinY+bbox.MaxY)/2,
90
(bbox.MinZ+bbox.MaxZ)/2);
93
return Base::Vector3d();
96
void TransformStrategy::commitTransform(const Base::Matrix4D& mat)
98
std::set<App::DocumentObject*> objects = transformObjects();
99
Gui::Document* doc = Gui::Application::Instance->activeDocument();
101
doc->openCommand(QT_TRANSLATE_NOOP("Command", "Transform"));
102
for (const auto & object : objects) {
103
acceptDataTransform(mat, object);
105
doc->commitCommand();
109
void TransformStrategy::acceptDataTransform(const Base::Matrix4D& mat, App::DocumentObject* obj)
111
Gui::Document* doc = Gui::Application::Instance->getDocument(obj->getDocument());
112
std::map<std::string,App::Property*> props;
113
obj->getPropertyMap(props);
114
// search for the placement property
115
std::map<std::string,App::Property*>::iterator jt;
116
jt = std::find_if(props.begin(), props.end(), find_transform());
117
if (jt != props.end()) {
118
Base::Placement local = static_cast<App::PropertyPlacement*>(jt->second)->getValue();
119
Gui::ViewProvider* vp = doc->getViewProvider(obj);
120
if (vp) vp->setTransformation(local.toMatrix());
123
// No placement found
124
Gui::ViewProvider* vp = doc->getViewProvider(obj);
125
if (vp) vp->setTransformation(Base::Matrix4D());
128
// Apply the transformation
129
if (obj->isDerivedFrom<App::GeoFeature>()) {
130
// search for a data property
131
const App::PropertyGeometry* geo = static_cast<App::GeoFeature*>(obj)->getPropertyOfGeometry();
133
const_cast<App::PropertyGeometry*>(geo)->transformGeometry(mat);
138
void TransformStrategy::applyTransform(const Base::Placement& plm)
140
std::set<App::DocumentObject*> objects = transformObjects();
141
for (const auto & object : objects) {
142
applyViewTransform(plm, object);
146
void TransformStrategy::resetTransform()
148
std::set<App::DocumentObject*> objects = transformObjects();
149
for (const auto & object : objects) {
150
resetViewTransform(object);
154
void TransformStrategy::applyViewTransform(const Base::Placement& plm, App::DocumentObject* obj)
156
Gui::Document* doc = Gui::Application::Instance->getDocument(obj->getDocument());
157
std::map<std::string,App::Property*> props;
158
obj->getPropertyMap(props);
159
// search for the placement property
160
std::map<std::string,App::Property*>::iterator jt;
161
jt = std::find_if(props.begin(), props.end(), find_transform());
162
if (jt != props.end()) {
163
Base::Placement local = static_cast<App::PropertyPlacement*>(jt->second)->getValue();
164
local *= plm; // in case a placement is already set
165
Gui::ViewProvider* vp = doc->getViewProvider(obj);
166
if (vp) vp->setTransformation(local.toMatrix());
169
// No placement found, so apply the transformation directly
170
Gui::ViewProvider* vp = doc->getViewProvider(obj);
171
if (vp) vp->setTransformation(plm.toMatrix());
175
void TransformStrategy::resetViewTransform(App::DocumentObject* obj)
177
Gui::Document* doc = Gui::Application::Instance->getDocument(obj->getDocument());
178
std::map<std::string,App::Property*> props;
179
obj->getPropertyMap(props);
180
// search for the placement property
181
std::map<std::string,App::Property*>::iterator jt;
182
jt = std::find_if(props.begin(), props.end(), find_transform());
183
if (jt != props.end()) {
184
Base::Placement local = static_cast<App::PropertyPlacement*>(jt->second)->getValue();
185
Gui::ViewProvider* vp = doc->getViewProvider(obj);
186
if (vp) vp->setTransformation(local.toMatrix());
189
// No placement found
190
Gui::ViewProvider* vp = doc->getViewProvider(obj);
191
if (vp) vp->setTransformation(Base::Matrix4D());
195
// ----------------------------------------------------------------------------
197
DefaultTransformStrategy::DefaultTransformStrategy(QWidget* w) : widget(w)
199
Gui::SelectionChanges mod;
200
mod.Type = Gui::SelectionChanges::SetSelection;
201
onSelectionChanged(mod);
204
DefaultTransformStrategy::~DefaultTransformStrategy() = default;
206
std::set<App::DocumentObject*> DefaultTransformStrategy::transformObjects() const
211
void DefaultTransformStrategy::onSelectionChanged(const Gui::SelectionChanges& msg)
213
if (msg.Type == SelectionChanges::SetPreselect ||
214
msg.Type == SelectionChanges::RmvPreselect)
215
return; // nothing to do
216
if (msg.Type == SelectionChanges::ClrSelection) {
217
widget->setDisabled(true);
218
for (const auto & it : selection)
219
resetViewTransform(it);
224
std::set<App::DocumentObject*> update_selection;
225
std::vector<App::DocumentObject*> sel = Gui::Selection().getObjectsOfType
226
(App::DocumentObject::getClassTypeId());
227
for (const auto & it : sel) {
228
if (it->isDerivedFrom<App::GeoFeature>()) {
229
// search for a data property
230
const App::PropertyGeometry* geo = static_cast<App::GeoFeature*>(it)->getPropertyOfGeometry();
232
update_selection.insert(it);
237
// now we remove all objects which links to another object
238
// of the selected objects because if the source object changes
239
// it is touched and thus a recompute later would overwrite the
240
// changes here anyway
241
std::set<App::DocumentObject*> filter;
242
for (auto it = update_selection.begin(); it != update_selection.end(); ++it) {
243
std::vector<App::DocumentObject*> deps = (*it)->getOutList();
244
std::vector<App::DocumentObject*>::iterator jt;
245
for (jt = deps.begin(); jt != deps.end(); ++jt) {
246
if (update_selection.find(*jt) != update_selection.end()) {
253
if (!filter.empty()) {
254
std::set<App::DocumentObject*> diff;
255
std::insert_iterator< std::set<App::DocumentObject*> > biit(diff, diff.begin());
256
std::set_difference(update_selection.begin(), update_selection.end(),
257
filter.begin(), filter.end(), biit);
258
update_selection = diff;
261
// reset transform for all deselected objects
262
std::vector<App::DocumentObject*> diff;
263
std::back_insert_iterator< std::vector<App::DocumentObject*> > biit(diff);
264
std::set_difference(selection.begin(), selection.end(),
265
update_selection.begin(), update_selection.end(), biit);
266
for (const auto & it : diff)
267
resetViewTransform(it);
268
selection = update_selection;
270
widget->setDisabled(selection.empty());
273
// ----------------------------------------------------------------------------
275
/* TRANSLATOR Gui::Dialog::Transform */
277
Transform::Transform(QWidget* parent, Qt::WindowFlags fl)
278
: QDialog(parent, fl), strategy(nullptr)
280
ui = new Ui_Placement();
282
QPushButton* applyButton = ui->buttonBox->button(QDialogButtonBox::Apply);
283
connect(applyButton, &QPushButton::clicked,
284
this, &Transform::onApplyButtonClicked);
286
ui->resetButton->hide();
287
ui->applyIncrementalPlacement->hide();
288
this->setWindowTitle(tr("Transform"));
290
// create a signal mapper in order to have one slot to perform the change
291
auto signalMapper = new QSignalMapper(this);
292
signalMapper->setMapping(this, 0);
295
QList<Gui::QuantitySpinBox*> sb = this->findChildren<Gui::QuantitySpinBox*>();
296
for (const auto & it : sb) {
297
connect(it, qOverload<double>(&QuantitySpinBox::valueChanged), signalMapper, qOverload<>(&QSignalMapper::map));
298
signalMapper->setMapping(it, id++);
301
#if QT_VERSION < QT_VERSION_CHECK(5,15,0)
302
connect(signalMapper, qOverload<int>(&QSignalMapper::mapped),
303
this, &Transform::onTransformChanged);
305
connect(signalMapper, &QSignalMapper::mappedInt,
306
this, &Transform::onTransformChanged);
309
setTransformStrategy(new DefaultTransformStrategy(this));
312
Transform::~Transform()
318
void Transform::setTransformStrategy(TransformStrategy* ts)
320
if (!ts || ts == strategy)
325
Base::Vector3d cnt = strategy->getRotationCenter();
326
ui->xCnt->setValue(Base::Quantity(cnt.x, Base::Unit::Length));
327
ui->yCnt->setValue(Base::Quantity(cnt.y, Base::Unit::Length));
328
ui->zCnt->setValue(Base::Quantity(cnt.z, Base::Unit::Length));
329
this->setDisabled(strategy->transformObjects().empty());
332
void Transform::showStandardButtons(bool b)
334
ui->buttonBox->setVisible(b);
337
void Transform::onTransformChanged(int)
339
Base::Placement plm = this->getPlacementData();
340
strategy->applyTransform(plm);
343
void Transform::accept()
345
onApplyButtonClicked();
349
void Transform::reject()
351
strategy->resetTransform();
355
void Transform::onApplyButtonClicked()
358
Base::Placement plm = this->getPlacementData();
359
Base::Matrix4D mat = plm.toMatrix();
360
strategy->commitTransform(mat);
362
// nullify the values
363
QList<Gui::QuantitySpinBox*> sb = this->findChildren<Gui::QuantitySpinBox*>();
364
for (auto & it : sb) {
365
it->blockSignals(true);
367
it->blockSignals(false);
370
Base::Vector3d cnt = strategy->getRotationCenter();
371
ui->xCnt->setValue(Base::Quantity(cnt.x, Base::Unit::Length));
372
ui->yCnt->setValue(Base::Quantity(cnt.y, Base::Unit::Length));
373
ui->zCnt->setValue(Base::Quantity(cnt.z, Base::Unit::Length));
376
Base::Vector3d Transform::getDirection() const
378
double x = ui->xAxis->value().getValue();
379
double y = ui->yAxis->value().getValue();
380
double z = ui->zAxis->value().getValue();
381
return Base::Vector3d(x, y, z);
384
Base::Placement Transform::getPlacementData() const
386
int index = ui->rotationInput->currentIndex();
391
pos = Base::Vector3d(ui->xPos->value().getValue(),ui->yPos->value().getValue(),ui->zPos->value().getValue());
392
cnt = Base::Vector3d(ui->xCnt->value().getValue(),ui->yCnt->value().getValue(),ui->zCnt->value().getValue());
395
Base::Vector3d dir = getDirection();
396
rot.setValue(Base::Vector3d(dir.x,dir.y,dir.z),ui->angle->value().getValue()*D_PI/180.0);
398
else if (index == 1) {
400
ui->yawAngle->value().getValue(),
401
ui->pitchAngle->value().getValue(),
402
ui->rollAngle->value().getValue());
405
Base::Placement p(pos, rot, cnt);
409
void Transform::changeEvent(QEvent *e)
411
if (e->type() == QEvent::LanguageChange) {
412
ui->retranslateUi(this);
413
this->setWindowTitle(tr("Transform"));
416
QDialog::changeEvent(e);
420
// ---------------------------------------
422
TaskTransform::TaskTransform()
424
this->setButtonPosition(TaskTransform::South);
425
dialog = new Transform();
426
dialog->showStandardButtons(false);
430
TaskTransform::~TaskTransform() = default;
432
void TaskTransform::setTransformStrategy(TransformStrategy* ts)
434
dialog->setTransformStrategy(ts);
437
bool TaskTransform::accept()
440
return (dialog->result() == QDialog::Accepted);
443
bool TaskTransform::reject()
446
return (dialog->result() == QDialog::Rejected);
449
void TaskTransform::clicked(int id)
451
if (id == QDialogButtonBox::Apply) {
452
dialog->onApplyButtonClicked();
456
#include "moc_Transform.cpp"