FreeCAD

Форк
0
/
Transform.cpp 
456 строк · 15.4 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2009 Werner Mayer <wmayer[at]users.sourceforge.net>     *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
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.      *
10
 *                                                                         *
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.                  *
15
 *                                                                         *
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                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24

25
#include <QDialogButtonBox>
26
#include <QKeyEvent>
27
#include <QSignalMapper>
28

29
#include <App/GeoFeature.h>
30
#include <App/PropertyGeo.h>
31

32
#include "Transform.h"
33
#include "Application.h"
34
#include "Document.h"
35
#include "Selection.h"
36
#include "ui_Placement.h"
37
#include "ViewProvider.h"
38
#include "WaitCursor.h"
39

40

41
using namespace Gui::Dialog;
42

43
namespace Gui { namespace Dialog {
44
class find_transform
45
{
46
public:
47
    bool operator () (const std::pair<std::string, App::Property*>& elem) const
48
    {
49
        if (elem.first == "Placement") {
50
            return elem.second->isDerivedFrom
51
                (Base::Type::fromName("App::PropertyPlacement"));
52
        }
53

54
        return false;
55
    }
56
};
57
}
58
}
59

60
// ----------------------------------------------------------------------------
61

62
TransformStrategy::TransformStrategy() = default;
63

64
TransformStrategy::~TransformStrategy() = default;
65

66
Base::Vector3d TransformStrategy::getRotationCenter() const
67
{
68
    // get the global bounding box of all selected objects and use its center as
69
    // rotation center
70
    std::set<App::DocumentObject*> objects = transformObjects();
71
    if (!objects.empty()) {
72
        Base::BoundBox3d bbox;
73
        bool first=true;
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();
78
                if (geo) {
79
                    if (first)
80
                        bbox = geo->getBoundingBox();
81
                    else
82
                        bbox.Add(geo->getBoundingBox());
83
                    first = false;
84
                }
85
            }
86
        }
87

88
        return Base::Vector3d((bbox.MinX+bbox.MaxX)/2,
89
                              (bbox.MinY+bbox.MaxY)/2,
90
                              (bbox.MinZ+bbox.MaxZ)/2);
91
    }
92

93
    return Base::Vector3d();
94
}
95

96
void TransformStrategy::commitTransform(const Base::Matrix4D& mat)
97
{
98
    std::set<App::DocumentObject*> objects = transformObjects();
99
    Gui::Document* doc = Gui::Application::Instance->activeDocument();
100
    if (doc) {
101
        doc->openCommand(QT_TRANSLATE_NOOP("Command", "Transform"));
102
        for (const auto & object : objects) {
103
            acceptDataTransform(mat, object);
104
        }
105
        doc->commitCommand();
106
    }
107
}
108

109
void TransformStrategy::acceptDataTransform(const Base::Matrix4D& mat, App::DocumentObject* obj)
110
{
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());
121
    }
122
    else {
123
        // No placement found
124
        Gui::ViewProvider* vp = doc->getViewProvider(obj);
125
        if (vp) vp->setTransformation(Base::Matrix4D());
126
    }
127

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();
132
        if (geo) {
133
            const_cast<App::PropertyGeometry*>(geo)->transformGeometry(mat);
134
        }
135
    }
136
}
137

138
void TransformStrategy::applyTransform(const Base::Placement& plm)
139
{
140
    std::set<App::DocumentObject*> objects = transformObjects();
141
    for (const auto & object : objects) {
142
        applyViewTransform(plm, object);
143
    }
144
}
145

146
void TransformStrategy::resetTransform()
147
{
148
    std::set<App::DocumentObject*> objects = transformObjects();
149
    for (const auto & object : objects) {
150
        resetViewTransform(object);
151
    }
152
}
153

154
void TransformStrategy::applyViewTransform(const Base::Placement& plm, App::DocumentObject* obj)
155
{
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());
167
    }
168
    else {
169
        // No placement found, so apply the transformation directly
170
        Gui::ViewProvider* vp = doc->getViewProvider(obj);
171
        if (vp) vp->setTransformation(plm.toMatrix());
172
    }
173
}
174

175
void TransformStrategy::resetViewTransform(App::DocumentObject* obj)
176
{
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());
187
    }
188
    else {
189
        // No placement found
190
        Gui::ViewProvider* vp = doc->getViewProvider(obj);
191
        if (vp) vp->setTransformation(Base::Matrix4D());
192
    }
193
}
194

195
// ----------------------------------------------------------------------------
196

197
DefaultTransformStrategy::DefaultTransformStrategy(QWidget* w) : widget(w)
198
{
199
    Gui::SelectionChanges mod;
200
    mod.Type = Gui::SelectionChanges::SetSelection;
201
    onSelectionChanged(mod);
202
}
203

204
DefaultTransformStrategy::~DefaultTransformStrategy() = default;
205

206
std::set<App::DocumentObject*> DefaultTransformStrategy::transformObjects() const
207
{
208
    return selection;
209
}
210

211
void DefaultTransformStrategy::onSelectionChanged(const Gui::SelectionChanges& msg)
212
{
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);
220
        selection.clear();
221
        return;
222
    }
223

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();
231
            if (geo) {
232
                update_selection.insert(it);
233
            }
234
        }
235
    }
236

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()) {
247
                filter.insert(*it);
248
                break;
249
            }
250
        }
251
    }
252

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;
259
    }
260

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;
269

270
    widget->setDisabled(selection.empty());
271
}
272

273
// ----------------------------------------------------------------------------
274

275
/* TRANSLATOR Gui::Dialog::Transform */
276

277
Transform::Transform(QWidget* parent, Qt::WindowFlags fl)
278
  : QDialog(parent, fl), strategy(nullptr)
279
{
280
    ui = new Ui_Placement();
281
    ui->setupUi(this);
282
    QPushButton* applyButton = ui->buttonBox->button(QDialogButtonBox::Apply);
283
    connect(applyButton, &QPushButton::clicked,
284
            this, &Transform::onApplyButtonClicked);
285

286
    ui->resetButton->hide();
287
    ui->applyIncrementalPlacement->hide();
288
    this->setWindowTitle(tr("Transform"));
289

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);
293

294
    int id = 1;
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++);
299
    }
300

301
#if QT_VERSION < QT_VERSION_CHECK(5,15,0)
302
    connect(signalMapper, qOverload<int>(&QSignalMapper::mapped),
303
            this, &Transform::onTransformChanged);
304
#else
305
    connect(signalMapper, &QSignalMapper::mappedInt,
306
            this, &Transform::onTransformChanged);
307
#endif
308

309
    setTransformStrategy(new DefaultTransformStrategy(this));
310
}
311

312
Transform::~Transform()
313
{
314
    delete ui;
315
    delete strategy;
316
}
317

318
void Transform::setTransformStrategy(TransformStrategy* ts)
319
{
320
    if (!ts || ts == strategy)
321
        return;
322
    if (strategy)
323
        delete strategy;
324
    strategy = ts;
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());
330
}
331

332
void Transform::showStandardButtons(bool b)
333
{
334
    ui->buttonBox->setVisible(b);
335
}
336

337
void Transform::onTransformChanged(int)
338
{
339
    Base::Placement plm = this->getPlacementData();
340
    strategy->applyTransform(plm);
341
}
342

343
void Transform::accept()
344
{
345
    onApplyButtonClicked();
346
    QDialog::accept();
347
}
348

349
void Transform::reject()
350
{
351
    strategy->resetTransform();
352
    QDialog::reject();
353
}
354

355
void Transform::onApplyButtonClicked()
356
{
357
    Gui::WaitCursor wc;
358
    Base::Placement plm = this->getPlacementData();
359
    Base::Matrix4D mat = plm.toMatrix();
360
    strategy->commitTransform(mat);
361

362
    // nullify the values
363
    QList<Gui::QuantitySpinBox*> sb = this->findChildren<Gui::QuantitySpinBox*>();
364
    for (auto & it : sb) {
365
        it->blockSignals(true);
366
        it->setValue(0.0);
367
        it->blockSignals(false);
368
    }
369

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));
374
}
375

376
Base::Vector3d Transform::getDirection() const
377
{
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);
382
}
383

384
Base::Placement Transform::getPlacementData() const
385
{
386
    int index = ui->rotationInput->currentIndex();
387
    Base::Rotation rot;
388
    Base::Vector3d pos;
389
    Base::Vector3d cnt;
390

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());
393

394
    if (index == 0) {
395
        Base::Vector3d dir = getDirection();
396
        rot.setValue(Base::Vector3d(dir.x,dir.y,dir.z),ui->angle->value().getValue()*D_PI/180.0);
397
    }
398
    else if (index == 1) {
399
        rot.setYawPitchRoll(
400
            ui->yawAngle->value().getValue(),
401
            ui->pitchAngle->value().getValue(),
402
            ui->rollAngle->value().getValue());
403
    }
404

405
    Base::Placement p(pos, rot, cnt);
406
    return p;
407
}
408

409
void Transform::changeEvent(QEvent *e)
410
{
411
    if (e->type() == QEvent::LanguageChange) {
412
        ui->retranslateUi(this);
413
        this->setWindowTitle(tr("Transform"));
414
    }
415
    else {
416
        QDialog::changeEvent(e);
417
    }
418
}
419

420
// ---------------------------------------
421

422
TaskTransform::TaskTransform()
423
{
424
    this->setButtonPosition(TaskTransform::South);
425
    dialog = new Transform();
426
    dialog->showStandardButtons(false);
427
    addTaskBox(dialog);
428
}
429

430
TaskTransform::~TaskTransform() = default;
431

432
void TaskTransform::setTransformStrategy(TransformStrategy* ts)
433
{
434
    dialog->setTransformStrategy(ts);
435
}
436

437
bool TaskTransform::accept()
438
{
439
    dialog->accept();
440
    return (dialog->result() == QDialog::Accepted);
441
}
442

443
bool TaskTransform::reject()
444
{
445
    dialog->reject();
446
    return (dialog->result() == QDialog::Rejected);
447
}
448

449
void TaskTransform::clicked(int id)
450
{
451
    if (id == QDialogButtonBox::Apply) {
452
        dialog->onApplyButtonClicked();
453
    }
454
}
455

456
#include "moc_Transform.cpp"
457

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.