FreeCAD

Форк
0
/
DlgScale.cpp 
359 строк · 12.8 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2023 Wanderer Fan <wandererfan@gmail.com>               *
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
#ifndef _PreComp_
25
# include <BRepAdaptor_Curve.hxx>
26
# include <BRep_Tool.hxx>
27
# include <Precision.hxx>
28
# include <ShapeExtend_Explorer.hxx>
29
# include <TopExp_Explorer.hxx>
30
# include <TopoDS.hxx>
31
# include <TopTools_HSequenceOfShape.hxx>
32
# include <QKeyEvent>
33
# include <QMessageBox>
34
#include <QTreeWidget>
35
#include <QTreeWidgetItem>
36
#endif
37

38
#include <App/Application.h>
39
#include <App/Document.h>
40
#include <App/DocumentObject.h>
41
#include <App/Link.h>
42
#include <App/Part.h>
43
#include <Base/UnitsApi.h>
44
#include <Gui/Application.h>
45
#include <Gui/BitmapFactory.h>
46
#include <Gui/Command.h>
47
#include <Gui/Document.h>
48
#include <Gui/Utilities.h>
49
#include <Gui/ViewProvider.h>
50
#include <Gui/WaitCursor.h>
51

52
#include "ui_DlgScale.h"
53
#include "DlgScale.h"
54

55

56
FC_LOG_LEVEL_INIT("Part",true,true)
57

58
using namespace PartGui;
59

60
DlgScale::DlgScale(QWidget* parent, Qt::WindowFlags fl)
61
  : QDialog(parent, fl), ui(new Ui_DlgScale)
62
{
63
    ui->setupUi(this);
64
    setupConnections();
65

66
    ui->dsbUniformScale->setDecimals(Base::UnitsApi::getDecimals());
67
    ui->dsbXScale->setDecimals(Base::UnitsApi::getDecimals());
68
    ui->dsbYScale->setDecimals(Base::UnitsApi::getDecimals());
69
    ui->dsbZScale->setDecimals(Base::UnitsApi::getDecimals());
70
    findShapes();
71

72
    // this will mark as selected all the items in treeWidget that are selected in the document
73
    Gui::ItemViewSelection sel(ui->treeWidget);
74
    sel.applyFrom(Gui::Selection().getObjectsOfType(Part::Feature::getClassTypeId()));
75
    sel.applyFrom(Gui::Selection().getObjectsOfType(App::Link::getClassTypeId()));
76
    sel.applyFrom(Gui::Selection().getObjectsOfType(App::Part::getClassTypeId()));
77
}
78

79
void DlgScale::setupConnections()
80
{
81
    connect(ui->rbUniform, &QRadioButton::toggled,
82
            this, &DlgScale::onUniformScaleToggled);
83
}
84

85
void DlgScale::changeEvent(QEvent *e)
86
{
87
    if (e->type() == QEvent::LanguageChange) {
88
        ui->retranslateUi(this);
89
    }
90
    QDialog::changeEvent(e);
91
}
92

93
void DlgScale::onUniformScaleToggled(bool state)
94
{
95
//    Base::Console().Message("DS::onUniformScaleToggled()\n");
96
    if (state) {
97
        // this is uniform scaling, so hide the non-uniform input fields
98
        ui->dsbUniformScale->setEnabled(true);
99
        ui->dsbXScale->setEnabled(false);
100
        ui->dsbYScale->setEnabled(false);
101
        ui->dsbZScale->setEnabled(false);
102
    } else {
103
        // this is non-uniform scaling, so hide the uniform input fields
104
        ui->dsbUniformScale->setEnabled(false);
105
        ui->dsbXScale->setEnabled(true);
106
        ui->dsbYScale->setEnabled(true);
107
        ui->dsbZScale->setEnabled(true);
108
    }
109
}
110

111
//! find all the scalable objects in the active document and load them into the
112
//! list widget
113
void DlgScale::findShapes()
114
{
115
//    Base::Console().Message("DS::findShapes()\n");
116
    App::Document* activeDoc = App::GetApplication().getActiveDocument();
117
    if (!activeDoc)
118
        return;
119
    Gui::Document* activeGui = Gui::Application::Instance->getDocument(activeDoc);
120
    m_document = activeDoc->getName();
121
    m_label = activeDoc->Label.getValue();
122

123
    std::vector<App::DocumentObject*> objs = activeDoc->getObjectsOfType<App::DocumentObject>();
124

125
    for (auto obj : objs) {
126
        Part::TopoShape topoShape = Part::Feature::getTopoShape(obj);
127
        if (topoShape.isNull()) {
128
            continue;
129
        }
130
        TopoDS_Shape shape = topoShape.getShape();
131
        if (shape.IsNull()) continue;
132
        if (canScale(shape)) {
133
            QTreeWidgetItem* item = new QTreeWidgetItem(ui->treeWidget);
134
            item->setText(0, QString::fromUtf8(obj->Label.getValue()));
135
            item->setData(0, Qt::UserRole, QString::fromLatin1(obj->getNameInDocument()));
136
            Gui::ViewProvider* vp = activeGui->getViewProvider(obj);
137
            if (vp)
138
                item->setIcon(0, vp->getIcon());
139
        }
140
    }
141
}
142

143
//! return true if shape can be scaled.
144
bool DlgScale::canScale(const TopoDS_Shape& shape) const
145
{
146
    if (shape.IsNull()) {
147
        return false;
148
    }
149
    // if the shape is a solid or a compound containing shapes, then we can scale it
150
    TopAbs_ShapeEnum type = shape.ShapeType();
151

152
    if (type == TopAbs_VERTEX) {
153
        return false;
154
    }
155

156
    if (type == TopAbs_COMPOUND ||
157
        type == TopAbs_COMPSOLID) {
158
        TopExp_Explorer xp;
159
        xp.Init(shape, TopAbs_EDGE);
160
        for ( ; xp.More() ; xp.Next()) {
161
            // there is at least 1 edge inside the compound, so as long as it isn't null,
162
            // we can scale this shape.  We can stop looking as soon as we find a non-null
163
            // edge.
164
            if (!xp.Current().IsNull()) {
165
                // found a non-null edge
166
                return true;
167
            }
168
        }
169
        // did not find a non-null shape
170
        return false;
171
    } else {
172
        // not a Vertex, Compound or CompSolid, must be one of Edge, Wire, Face, Shell or
173
        // Solid, all of which we can scale.
174
        return true;
175
    }
176

177
    return false;
178
}
179

180
void DlgScale::accept()
181
{
182
//    Base::Console().Message("DS::accept()\n");
183
    try{
184
        apply();
185
        QDialog::accept();
186
    } catch (Base::AbortException&){
187
        Base::Console().Message("DS::accept - apply failed!\n");
188
    };
189
}
190

191
// create a FeatureScale for each scalable object
192
void DlgScale::apply()
193
{
194
//    Base::Console().Message("DS::apply()\n");
195
    try{
196
        if (!validate()) {
197
            QMessageBox::critical(this, windowTitle(),
198
                tr("No scalable shapes selected"));
199
            return;
200
        }
201

202
        Gui::WaitCursor wc;
203
        App::Document* activeDoc = App::GetApplication().getDocument(m_document.c_str());
204
        if (!activeDoc) {
205
            QMessageBox::critical(this, windowTitle(),
206
                tr("The document '%1' doesn't exist.").arg(QString::fromUtf8(m_label.c_str())));
207
            return;
208
        }
209
        activeDoc->openTransaction("Scale");
210

211
        Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
212
            .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part");
213
        bool addBaseName = hGrp->GetBool("AddBaseObjectName", false);
214

215
        std::vector<App::DocumentObject*> objects = this->getShapesToScale();
216
        for (App::DocumentObject* sourceObj: objects) {
217
            assert(sourceObj);
218

219
            if (Part::Feature::getTopoShape(sourceObj).isNull()){
220
                FC_ERR("Object " << sourceObj->getFullName()
221
                        << " is not Part object (has no OCC shape). Can't scale it.");
222
                continue;
223
            }
224

225
            std::string name;
226
            name = sourceObj->getDocument()->getUniqueObjectName("Scale").c_str();
227
            if (addBaseName) {
228
                //FIXME: implement
229
                //QString baseName = QString::fromLatin1("Scale_%1").arg(sourceObjectName);
230
                //label = QString::fromLatin1("%1_Scale").arg((*it)->text(0));
231
            }
232

233
            FCMD_OBJ_DOC_CMD(sourceObj,"addObject('Part::Scale','" << name << "')");
234
            auto newObj = sourceObj->getDocument()->getObject(name.c_str());
235

236
            this->writeParametersToFeature(*newObj, sourceObj);
237

238
            Gui::Command::copyVisual(newObj, "ShapeAppearance", sourceObj);
239
            Gui::Command::copyVisual(newObj, "LineColor", sourceObj);
240
            Gui::Command::copyVisual(newObj, "PointColor", sourceObj);
241

242
            FCMD_OBJ_HIDE(sourceObj);
243
        }
244

245
        activeDoc->commitTransaction();
246
        Gui::Command::updateActive();
247
    }
248
    catch (Base::AbortException&){
249
        throw;
250
    }
251
    catch (Base::Exception &err){
252
        QMessageBox::critical(this,
253
                              windowTitle(),
254
                              tr("Creating Scale failed.\n%1")
255
                                  .arg(QCoreApplication::translate("Exception", err.what())));
256
        return;
257
    }
258
    catch(...) {
259
        QMessageBox::critical(this, windowTitle(),
260
            tr("Creating Scale failed.\n%1").arg(QString::fromUtf8("Unknown error")));
261
        return;
262
    }
263
}
264

265
void DlgScale::reject()
266
{
267
    QDialog::reject();
268
}
269

270
//! retrieve the document objects associated with the selected items in the list
271
//! widget
272
std::vector<App::DocumentObject*> DlgScale::getShapesToScale() const
273
{
274
//    Base::Console().Message("DS::getShapesToScale()\n");
275
    QList<QTreeWidgetItem *> items = ui->treeWidget->selectedItems();
276
    App::Document* doc = App::GetApplication().getDocument(m_document.c_str());
277
    if (!doc)
278
        throw Base::RuntimeError("Document lost");
279

280
    std::vector<App::DocumentObject*> objects;
281
    for (auto item : items) {
282
        App::DocumentObject* obj = doc->getObject(item->data(0, Qt::UserRole).toString().toLatin1());
283
        if (!obj)
284
            throw Base::RuntimeError("Object not found");
285
        objects.push_back(obj);
286
    }
287
    return objects;
288
}
289

290
//! return true if at least one item in the list widget corresponds to an
291
//! available document object in the document
292
bool DlgScale::validate()
293
{
294
    QList<QTreeWidgetItem *> items = ui->treeWidget->selectedItems();
295
    App::Document* doc = App::GetApplication().getDocument(m_document.c_str());
296
    if (!doc)
297
        throw Base::RuntimeError("Document lost");
298

299
    std::vector<App::DocumentObject*> objects;
300
    for (auto item : items) {
301
        App::DocumentObject* obj = doc->getObject(item->data(0, Qt::UserRole).toString().toLatin1());
302
        if (!obj)
303
            throw Base::RuntimeError("Object not found");
304
        objects.push_back(obj);
305
    }
306
    return !objects.empty();
307
}
308

309
//! update a FeatureScale with the parameters from the UI
310
void DlgScale::writeParametersToFeature(App::DocumentObject &feature, App::DocumentObject* base) const
311
{
312
//    Base::Console().Message("DS::writeParametersToFeature()\n");
313
    Gui::Command::doCommand(Gui::Command::Doc,"f = App.getDocument('%s').getObject('%s')", feature.getDocument()->getName(), feature.getNameInDocument());
314

315
    if (!base) {
316
        return;
317
    }
318

319
    Gui::Command::doCommand(Gui::Command::Doc,"f.Base = App.getDocument('%s').getObject('%s')", base->getDocument()->getName(), base->getNameInDocument());
320

321
    Gui::Command::doCommand(Gui::Command::Doc,"f.Uniform = %s", ui->rbUniform->isChecked() ? "True" : "False");
322
    Gui::Command::doCommand(Gui::Command::Doc,"f.UniformScale = %.7f", ui->dsbUniformScale->value());
323
    Gui::Command::doCommand(Gui::Command::Doc,"f.XScale = %.7f", ui->dsbXScale->value());
324
    Gui::Command::doCommand(Gui::Command::Doc,"f.YScale = %.7f", ui->dsbYScale->value());
325
    Gui::Command::doCommand(Gui::Command::Doc,"f.ZScale = %.7f", ui->dsbZScale->value());
326
}
327

328
// ---------------------------------------
329

330
TaskScale::TaskScale()
331
{
332
    widget = new DlgScale();
333
    addTaskBox(Gui::BitmapFactory().pixmap("Part_Scale"), widget);
334
}
335

336
bool TaskScale::accept()
337
{
338
    widget->accept();
339
    return (widget->result() == QDialog::Accepted);
340
}
341

342
bool TaskScale::reject()
343
{
344
    widget->reject();
345
    return true;
346
}
347

348
void TaskScale::clicked(int id)
349
{
350
    if (id == QDialogButtonBox::Apply) {
351
        try{
352
            widget->apply();
353
        } catch (Base::AbortException&){
354

355
        };
356
    }
357
}
358

359
#include "moc_DlgScale.cpp"
360

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

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

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

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