FreeCAD

Форк
0
/
Transform.cpp 
460 строк · 15.5 Кб
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
    connect(ui->applyButton, &QPushButton::clicked,
283
            this, &Transform::onApplyButtonClicked);
284

285
    ui->resetButton->hide();
286
    ui->applyIncrementalPlacement->hide();
287

288
    ui->closeButton->setText(tr("Cancel"));
289
    this->setWindowTitle(tr("Transform"));
290

291
    // create a signal mapper in order to have one slot to perform the change
292
    auto signalMapper = new QSignalMapper(this);
293
    signalMapper->setMapping(this, 0);
294

295
    int id = 1;
296
    QList<Gui::QuantitySpinBox*> sb = this->findChildren<Gui::QuantitySpinBox*>();
297
    for (const auto & it : sb) {
298
        connect(it, qOverload<double>(&QuantitySpinBox::valueChanged), signalMapper, qOverload<>(&QSignalMapper::map));
299
        signalMapper->setMapping(it, id++);
300
    }
301

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

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

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

319
void Transform::setTransformStrategy(TransformStrategy* ts)
320
{
321
    if (!ts || ts == strategy)
322
        return;
323
    if (strategy)
324
        delete strategy;
325
    strategy = ts;
326
    Base::Vector3d cnt = strategy->getRotationCenter();
327
    ui->xCnt->setValue(Base::Quantity(cnt.x, Base::Unit::Length));
328
    ui->yCnt->setValue(Base::Quantity(cnt.y, Base::Unit::Length));
329
    ui->zCnt->setValue(Base::Quantity(cnt.z, Base::Unit::Length));
330
    this->setDisabled(strategy->transformObjects().empty());
331
}
332

333
void Transform::showStandardButtons(bool b)
334
{
335
    ui->closeButton->setVisible(b);
336
    ui->oKButton->setVisible(b);
337
    ui->applyButton->setVisible(b);
338
}
339

340
void Transform::onTransformChanged(int)
341
{
342
    Base::Placement plm = this->getPlacementData();
343
    strategy->applyTransform(plm);
344
}
345

346
void Transform::accept()
347
{
348
    onApplyButtonClicked();
349
    QDialog::accept();
350
}
351

352
void Transform::reject()
353
{
354
    strategy->resetTransform();
355
    QDialog::reject();
356
}
357

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

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

373
    Base::Vector3d cnt = strategy->getRotationCenter();
374
    ui->xCnt->setValue(Base::Quantity(cnt.x, Base::Unit::Length));
375
    ui->yCnt->setValue(Base::Quantity(cnt.y, Base::Unit::Length));
376
    ui->zCnt->setValue(Base::Quantity(cnt.z, Base::Unit::Length));
377
}
378

379
Base::Vector3d Transform::getDirection() const
380
{
381
    double x = ui->xAxis->value().getValue();
382
    double y = ui->yAxis->value().getValue();
383
    double z = ui->zAxis->value().getValue();
384
    return Base::Vector3d(x, y, z);
385
}
386

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

394
    pos = Base::Vector3d(ui->xPos->value().getValue(),ui->yPos->value().getValue(),ui->zPos->value().getValue());
395
    cnt = Base::Vector3d(ui->xCnt->value().getValue(),ui->yCnt->value().getValue(),ui->zCnt->value().getValue());
396

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

408
    Base::Placement p(pos, rot, cnt);
409
    return p;
410
}
411

412
void Transform::changeEvent(QEvent *e)
413
{
414
    if (e->type() == QEvent::LanguageChange) {
415
        ui->retranslateUi(this);
416
        ui->closeButton->setText(tr("Cancel"));
417
        this->setWindowTitle(tr("Transform"));
418
    }
419
    else {
420
        QDialog::changeEvent(e);
421
    }
422
}
423

424
// ---------------------------------------
425

426
TaskTransform::TaskTransform()
427
{
428
    this->setButtonPosition(TaskTransform::South);
429
    dialog = new Transform();
430
    dialog->showStandardButtons(false);
431
    addTaskBox(dialog);
432
}
433

434
TaskTransform::~TaskTransform() = default;
435

436
void TaskTransform::setTransformStrategy(TransformStrategy* ts)
437
{
438
    dialog->setTransformStrategy(ts);
439
}
440

441
bool TaskTransform::accept()
442
{
443
    dialog->accept();
444
    return (dialog->result() == QDialog::Accepted);
445
}
446

447
bool TaskTransform::reject()
448
{
449
    dialog->reject();
450
    return (dialog->result() == QDialog::Rejected);
451
}
452

453
void TaskTransform::clicked(int id)
454
{
455
    if (id == QDialogButtonBox::Apply) {
456
        dialog->onApplyButtonClicked();
457
    }
458
}
459

460
#include "moc_Transform.cpp"
461

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

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

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

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