FreeCAD

Форк
0
/
DlgEvaluateMeshImp.cpp 
1412 строк · 52.5 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2006 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
#ifndef _PreComp_
25
#include <QDockWidget>
26
#include <QMessageBox>
27
#include <QPointer>
28
#include <QScrollArea>
29
#endif
30

31
#include <Gui/Application.h>
32
#include <Gui/Command.h>
33
#include <Gui/Document.h>
34
#include <Gui/DockWindowManager.h>
35
#include <Gui/MainWindow.h>
36
#include <Gui/WaitCursor.h>
37
#include <Gui/View3DInventor.h>
38
#include <Gui/View3DInventorViewer.h>
39
#include <Mod/Mesh/App/MeshFeature.h>
40
#include <Mod/Mesh/App/Core/Evaluation.h>
41
#include <Mod/Mesh/App/Core/Degeneration.h>
42

43
#include "DlgEvaluateMeshImp.h"
44
#include "ui_DlgEvaluateMesh.h"
45
#include "DlgEvaluateSettings.h"
46
#include "ViewProviderDefects.h"
47

48

49
using namespace MeshCore;
50
using namespace Mesh;
51
using namespace MeshGui;
52

53
CleanupHandler::CleanupHandler()
54
    : QObject(qApp)
55
{
56
    // connect to lstWindowClosed signal
57
    connect(qApp, &QApplication::lastWindowClosed, this, &CleanupHandler::cleanup);
58
}
59

60
// The lastWindowClosed signal will be emitted recursively and before the cleanup slot is finished
61
// therefore all code inside this function must handle this case!
62
void CleanupHandler::cleanup()
63
{
64
    DockEvaluateMeshImp::destruct();
65
}
66

67
// -------------------------------------------------------------
68

69
class DlgEvaluateMeshImp::Private
70
{
71
public:
72
    Private()
73
        : view(nullptr)
74
    {}
75

76
    void showFoldsFunction(bool on)
77
    {
78
        ui.label_9->setVisible(on);
79
        ui.line_9->setVisible(on);
80
        ui.checkFoldsButton->setVisible(on);
81
        ui.analyzeFoldsButton->setVisible(on);
82
        ui.repairFoldsButton->setVisible(on);
83
    }
84

85
    Ui_DlgEvaluateMesh ui {};
86
    std::map<std::string, ViewProviderMeshDefects*> vp;
87
    Mesh::Feature* meshFeature {nullptr};
88
    QPointer<Gui::View3DInventor> view;
89
    std::vector<Mesh::FacetIndex> self_intersections;
90
    bool enableFoldsCheck {false};
91
    bool checkNonManfoldPoints {false};
92
    bool strictlyDegenerated {true};
93
    float epsilonDegenerated {0.0F};
94
};
95

96
/* TRANSLATOR MeshGui::DlgEvaluateMeshImp */
97

98
/**
99
 *  Constructs a DlgEvaluateMeshImp which is a child of 'parent', with the
100
 *  widget flags set to 'f'.
101
 */
102
DlgEvaluateMeshImp::DlgEvaluateMeshImp(QWidget* parent, Qt::WindowFlags fl)
103
    : QDialog(parent, fl)
104
    , d(new Private())
105
{
106
    d->ui.setupUi(this);
107
    setupConnections();
108

109
    d->ui.line->setFrameShape(QFrame::HLine);
110
    d->ui.line->setFrameShadow(QFrame::Sunken);
111
    d->ui.line_2->setFrameShape(QFrame::HLine);
112
    d->ui.line_2->setFrameShadow(QFrame::Sunken);
113
    d->ui.line_3->setFrameShape(QFrame::HLine);
114
    d->ui.line_3->setFrameShadow(QFrame::Sunken);
115
    d->ui.line_4->setFrameShape(QFrame::HLine);
116
    d->ui.line_4->setFrameShadow(QFrame::Sunken);
117
    d->ui.line_5->setFrameShape(QFrame::HLine);
118
    d->ui.line_5->setFrameShadow(QFrame::Sunken);
119
    d->ui.line_6->setFrameShape(QFrame::HLine);
120
    d->ui.line_6->setFrameShadow(QFrame::Sunken);
121
    d->ui.line_7->setFrameShape(QFrame::HLine);
122
    d->ui.line_7->setFrameShadow(QFrame::Sunken);
123
    d->ui.line_8->setFrameShape(QFrame::HLine);
124
    d->ui.line_8->setFrameShadow(QFrame::Sunken);
125

126
    ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
127
        "User parameter:BaseApp/Preferences/Mod/Mesh/Evaluation");
128
    d->checkNonManfoldPoints = hGrp->GetBool("CheckNonManifoldPoints", false);
129
    d->enableFoldsCheck = hGrp->GetBool("EnableFoldsCheck", false);
130
    d->strictlyDegenerated = hGrp->GetBool("StrictlyDegenerated", true);
131
    if (d->strictlyDegenerated) {
132
        d->epsilonDegenerated = 0.0F;
133
    }
134
    else {
135
        d->epsilonDegenerated = MeshCore::MeshDefinitions::_fMinPointDistanceP2;
136
    }
137

138
    d->showFoldsFunction(d->enableFoldsCheck);
139

140
    QPushButton* button = d->ui.buttonBox->button(QDialogButtonBox::Open);
141
    button->setText(tr("Settings..."));
142

143
    // try to attach to the active document
144
    this->onRefreshButtonClicked();
145
}
146

147
/**
148
 *  Destroys the object and frees any allocated resources
149
 */
150
DlgEvaluateMeshImp::~DlgEvaluateMeshImp()
151
{
152
    // no need to delete child widgets, Qt does it all for us
153
    for (const auto& it : d->vp) {
154
        if (d->view) {
155
            d->view->getViewer()->removeViewProvider(it.second);
156
        }
157
        delete it.second;
158
    }
159

160
    try {
161
        ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
162
            "User parameter:BaseApp/Preferences/Mod/Mesh/Evaluation");
163
        hGrp->SetBool("CheckNonManifoldPoints", d->checkNonManfoldPoints);
164
        hGrp->SetBool("EnableFoldsCheck", d->enableFoldsCheck);
165
        hGrp->SetBool("StrictlyDegenerated", d->strictlyDegenerated);
166
    }
167
    catch (...) {
168
    }
169

170
    d->vp.clear();
171
    delete d;
172
}
173

174
void DlgEvaluateMeshImp::setupConnections()
175
{
176
    // clang-format off
177
    connect(d->ui.checkOrientationButton, &QCheckBox::clicked,
178
            this, &DlgEvaluateMeshImp::onCheckOrientationButtonClicked);
179
    connect(d->ui.analyzeOrientationButton, &QPushButton::clicked,
180
            this, &DlgEvaluateMeshImp::onAnalyzeOrientationButtonClicked);
181
    connect(d->ui.repairOrientationButton, &QPushButton::clicked,
182
            this, &DlgEvaluateMeshImp::onRepairOrientationButtonClicked);
183

184
    connect(d->ui.checkDuplicatedFacesButton, &QCheckBox::clicked,
185
            this, &DlgEvaluateMeshImp::onCheckDuplicatedFacesButtonClicked);
186
    connect(d->ui.analyzeDuplicatedFacesButton, &QPushButton::clicked,
187
            this, &DlgEvaluateMeshImp::onAnalyzeDuplicatedFacesButtonClicked);
188
    connect(d->ui.repairDuplicatedFacesButton, &QPushButton::clicked,
189
            this, &DlgEvaluateMeshImp::onRepairDuplicatedFacesButtonClicked);
190

191
    connect(d->ui.checkDuplicatedPointsButton, &QCheckBox::clicked,
192
            this, &DlgEvaluateMeshImp::onCheckDuplicatedPointsButtonClicked);
193
    connect(d->ui.analyzeDuplicatedPointsButton, &QPushButton::clicked,
194
            this, &DlgEvaluateMeshImp::onAnalyzeDuplicatedPointsButtonClicked);
195
    connect(d->ui.repairDuplicatedPointsButton, &QPushButton::clicked,
196
            this, &DlgEvaluateMeshImp::onRepairDuplicatedPointsButtonClicked);
197

198
    connect(d->ui.checkNonmanifoldsButton, &QCheckBox::clicked,
199
            this, &DlgEvaluateMeshImp::onCheckNonmanifoldsButtonClicked);
200
    connect(d->ui.analyzeNonmanifoldsButton, &QPushButton::clicked,
201
            this, &DlgEvaluateMeshImp::onAnalyzeNonmanifoldsButtonClicked);
202
    connect(d->ui.repairNonmanifoldsButton, &QPushButton::clicked,
203
            this, &DlgEvaluateMeshImp::onRepairNonmanifoldsButtonClicked);
204

205
    connect(d->ui.checkDegenerationButton, &QCheckBox::clicked,
206
            this, &DlgEvaluateMeshImp::onCheckDegenerationButtonClicked);
207
    connect(d->ui.analyzeDegeneratedButton, &QPushButton::clicked,
208
            this, &DlgEvaluateMeshImp::onAnalyzeDegeneratedButtonClicked);
209
    connect(d->ui.repairDegeneratedButton, &QPushButton::clicked,
210
            this, &DlgEvaluateMeshImp::onRepairDegeneratedButtonClicked);
211

212
    connect(d->ui.checkIndicesButton, &QCheckBox::clicked,
213
            this, &DlgEvaluateMeshImp::onCheckIndicesButtonClicked);
214
    connect(d->ui.analyzeIndicesButton, &QPushButton::clicked,
215
            this, &DlgEvaluateMeshImp::onAnalyzeIndicesButtonClicked);
216
    connect(d->ui.repairIndicesButton, &QPushButton::clicked,
217
            this, &DlgEvaluateMeshImp::onRepairIndicesButtonClicked);
218

219
    connect(d->ui.checkSelfIntersectionButton, &QCheckBox::clicked,
220
            this, &DlgEvaluateMeshImp::onCheckSelfIntersectionButtonClicked);
221
    connect(d->ui.analyzeSelfIntersectionButton, &QPushButton::clicked,
222
            this, &DlgEvaluateMeshImp::onAnalyzeSelfIntersectionButtonClicked);
223
    connect(d->ui.repairSelfIntersectionButton, &QPushButton::clicked,
224
            this, &DlgEvaluateMeshImp::onRepairSelfIntersectionButtonClicked);
225

226
    connect(d->ui.checkFoldsButton, &QCheckBox::clicked,
227
            this, &DlgEvaluateMeshImp::onCheckFoldsButtonClicked);
228
    connect(d->ui.analyzeFoldsButton, &QPushButton::clicked,
229
            this, &DlgEvaluateMeshImp::onAnalyzeFoldsButtonClicked);
230
    connect(d->ui.repairFoldsButton, &QPushButton::clicked,
231
            this, &DlgEvaluateMeshImp::onRepairFoldsButtonClicked);
232

233
    connect(d->ui.analyzeAllTogether, &QPushButton::clicked,
234
            this, &DlgEvaluateMeshImp::onAnalyzeAllTogetherClicked);
235
    connect(d->ui.repairAllTogether, &QPushButton::clicked,
236
            this, &DlgEvaluateMeshImp::onRepairAllTogetherClicked);
237

238
    connect(d->ui.refreshButton, &QPushButton::clicked,
239
            this, &DlgEvaluateMeshImp::onRefreshButtonClicked);
240
    connect(d->ui.meshNameButton, qOverload<int>(&QComboBox::activated),
241
            this, &DlgEvaluateMeshImp::onMeshNameButtonActivated);
242
    connect(d->ui.buttonBox, &QDialogButtonBox::clicked,
243
            this, &DlgEvaluateMeshImp::onButtonBoxClicked);
244
    connect(d->ui.buttonBox, &QDialogButtonBox::helpRequested,
245
            Gui::getMainWindow(), &Gui::MainWindow::whatsThis);
246
    // clang-format on
247
}
248

249
void DlgEvaluateMeshImp::changeEvent(QEvent* e)
250
{
251
    if (e->type() == QEvent::LanguageChange) {
252
        d->ui.retranslateUi(this);
253
        d->ui.meshNameButton->setItemText(0, tr("No selection"));
254
    }
255
    QDialog::changeEvent(e);
256
}
257

258
void DlgEvaluateMeshImp::slotCreatedObject(const App::DocumentObject& Obj)
259
{
260
    // add new mesh object to the list
261
    if (Obj.isDerivedFrom<Mesh::Feature>()) {
262
        QString label = QString::fromUtf8(Obj.Label.getValue());
263
        QString name = QString::fromLatin1(Obj.getNameInDocument());
264
        d->ui.meshNameButton->addItem(label, name);
265
    }
266
}
267

268
void DlgEvaluateMeshImp::slotDeletedObject(const App::DocumentObject& Obj)
269
{
270
    // remove mesh objects from the list
271
    if (Obj.isDerivedFrom<Mesh::Feature>()) {
272
        int index = d->ui.meshNameButton->findData(QString::fromLatin1(Obj.getNameInDocument()));
273
        if (index > 0) {
274
            d->ui.meshNameButton->removeItem(index);
275
            d->ui.meshNameButton->setDisabled(d->ui.meshNameButton->count() < 2);
276
        }
277
    }
278

279
    // is it the current mesh object then clear everything
280
    if (&Obj == d->meshFeature) {
281
        removeViewProviders();
282
        d->meshFeature = nullptr;
283
        d->ui.meshNameButton->setCurrentIndex(0);
284
        cleanInformation();
285
        d->self_intersections.clear();
286
    }
287
}
288

289
void DlgEvaluateMeshImp::slotChangedObject(const App::DocumentObject& Obj,
290
                                           const App::Property& Prop)
291
{
292
    // if the current mesh object was modified update everything
293
    if (&Obj == d->meshFeature && Prop.is<Mesh::PropertyMeshKernel>()) {
294
        removeViewProviders();
295
        cleanInformation();
296
        showInformation();
297
        d->self_intersections.clear();
298
    }
299
    else if (Obj.isDerivedFrom<Mesh::Feature>()) {
300
        // if the label has changed update the entry in the list
301
        if (Prop.is<App::PropertyString>() && strcmp(Prop.getName(), "Label") == 0) {
302
            QString label = QString::fromUtf8(Obj.Label.getValue());
303
            QString name = QString::fromLatin1(Obj.getNameInDocument());
304
            int index = d->ui.meshNameButton->findData(name);
305
            d->ui.meshNameButton->setItemText(index, label);
306
        }
307
    }
308
}
309

310
void DlgEvaluateMeshImp::slotDeletedDocument(const App::Document& Doc)
311
{
312
    if (&Doc == getDocument()) {
313
        // the view is already destroyed
314
        for (const auto& it : d->vp) {
315
            delete it.second;
316
        }
317

318
        d->vp.clear();
319

320
        // try to attach to the active document
321
        this->detachDocument();
322
        d->view = nullptr;
323
        onRefreshButtonClicked();
324
    }
325
}
326

327
void DlgEvaluateMeshImp::setMesh(Mesh::Feature* m)
328
{
329
    App::Document* doc = m->getDocument();
330
    if (doc != getDocument()) {
331
        attachDocument(doc);
332
    }
333

334
    refreshList();
335

336
    int ct = d->ui.meshNameButton->count();
337
    QString objName = QString::fromLatin1(m->getNameInDocument());
338
    for (int i = 1; i < ct; i++) {
339
        if (d->ui.meshNameButton->itemData(i).toString() == objName) {
340
            d->ui.meshNameButton->setCurrentIndex(i);
341
            onMeshNameButtonActivated(i);
342
            break;
343
        }
344
    }
345
}
346

347
void DlgEvaluateMeshImp::addViewProvider(const char* name,
348
                                         const std::vector<Mesh::ElementIndex>& indices)
349
{
350
    removeViewProvider(name);
351

352
    if (d->view) {
353
        auto vp = static_cast<ViewProviderMeshDefects*>(Base::Type::createInstanceByName(name));
354
        assert(vp->isDerivedFrom<Gui::ViewProvider>());
355
        vp->attach(d->meshFeature);
356
        d->view->getViewer()->addViewProvider(vp);
357
        vp->showDefects(indices);
358
        d->vp[name] = vp;
359
    }
360
}
361

362
void DlgEvaluateMeshImp::removeViewProvider(const char* name)
363
{
364
    auto it = d->vp.find(name);
365
    if (it != d->vp.end()) {
366
        if (d->view) {
367
            d->view->getViewer()->removeViewProvider(it->second);
368
        }
369
        delete it->second;
370
        d->vp.erase(it);
371
    }
372
}
373

374
void DlgEvaluateMeshImp::removeViewProviders()
375
{
376
    for (const auto& it : d->vp) {
377
        if (d->view) {
378
            d->view->getViewer()->removeViewProvider(it.second);
379
        }
380
        delete it.second;
381
    }
382
    d->vp.clear();
383
}
384

385
void DlgEvaluateMeshImp::onMeshNameButtonActivated(int i)
386
{
387
    QString item = d->ui.meshNameButton->itemData(i).toString();
388

389
    d->meshFeature = nullptr;
390
    std::vector<App::DocumentObject*> objs =
391
        getDocument()->getObjectsOfType(Mesh::Feature::getClassTypeId());
392
    for (auto obj : objs) {
393
        if (item == QLatin1String(obj->getNameInDocument())) {
394
            d->meshFeature = static_cast<Mesh::Feature*>(obj);
395
            break;
396
        }
397
    }
398

399
    if (i == 0) {
400
        cleanInformation();
401
    }
402
    else {
403
        showInformation();
404
    }
405
}
406

407
void DlgEvaluateMeshImp::refreshList()
408
{
409
    QVector<QPair<QString, QString>> items;
410
    if (this->getDocument()) {
411
        std::vector<App::DocumentObject*> objs =
412
            this->getDocument()->getObjectsOfType(Mesh::Feature::getClassTypeId());
413
        for (auto obj : objs) {
414
            items.push_back(qMakePair(QString::fromUtf8(obj->Label.getValue()),
415
                                      QString::fromLatin1(obj->getNameInDocument())));
416
        }
417
    }
418

419
    d->ui.meshNameButton->clear();
420
    d->ui.meshNameButton->addItem(tr("No selection"));
421
    for (const auto& item : items) {
422
        d->ui.meshNameButton->addItem(item.first, item.second);
423
    }
424
    d->ui.meshNameButton->setDisabled(items.empty());
425
    cleanInformation();
426
}
427

428
void DlgEvaluateMeshImp::showInformation()
429
{
430
    d->ui.analyzeOrientationButton->setEnabled(true);
431
    d->ui.analyzeDuplicatedFacesButton->setEnabled(true);
432
    d->ui.analyzeDuplicatedPointsButton->setEnabled(true);
433
    d->ui.analyzeNonmanifoldsButton->setEnabled(true);
434
    d->ui.analyzeDegeneratedButton->setEnabled(true);
435
    d->ui.analyzeIndicesButton->setEnabled(true);
436
    d->ui.analyzeSelfIntersectionButton->setEnabled(true);
437
    d->ui.analyzeFoldsButton->setEnabled(true);
438
    d->ui.analyzeAllTogether->setEnabled(true);
439

440
    if (d->meshFeature) {
441
        const MeshKernel& rMesh = d->meshFeature->Mesh.getValue().getKernel();
442
        d->ui.textLabel4->setText(QString::fromLatin1("%1").arg(rMesh.CountFacets()));
443
        d->ui.textLabel5->setText(QString::fromLatin1("%1").arg(rMesh.CountEdges()));
444
        d->ui.textLabel6->setText(QString::fromLatin1("%1").arg(rMesh.CountPoints()));
445
    }
446
}
447

448
void DlgEvaluateMeshImp::cleanInformation()
449
{
450
    d->ui.textLabel4->setText(tr("No information"));
451
    d->ui.textLabel5->setText(tr("No information"));
452
    d->ui.textLabel6->setText(tr("No information"));
453
    d->ui.checkOrientationButton->setText(tr("No information"));
454
    d->ui.checkDuplicatedFacesButton->setText(tr("No information"));
455
    d->ui.checkDuplicatedPointsButton->setText(tr("No information"));
456
    d->ui.checkNonmanifoldsButton->setText(tr("No information"));
457
    d->ui.checkDegenerationButton->setText(tr("No information"));
458
    d->ui.checkIndicesButton->setText(tr("No information"));
459
    d->ui.checkSelfIntersectionButton->setText(tr("No information"));
460
    d->ui.checkFoldsButton->setText(tr("No information"));
461
    d->ui.analyzeOrientationButton->setDisabled(true);
462
    d->ui.repairOrientationButton->setDisabled(true);
463
    d->ui.analyzeDuplicatedFacesButton->setDisabled(true);
464
    d->ui.repairDuplicatedFacesButton->setDisabled(true);
465
    d->ui.analyzeDuplicatedPointsButton->setDisabled(true);
466
    d->ui.repairDuplicatedPointsButton->setDisabled(true);
467
    d->ui.analyzeNonmanifoldsButton->setDisabled(true);
468
    d->ui.repairNonmanifoldsButton->setDisabled(true);
469
    d->ui.analyzeDegeneratedButton->setDisabled(true);
470
    d->ui.repairDegeneratedButton->setDisabled(true);
471
    d->ui.analyzeIndicesButton->setDisabled(true);
472
    d->ui.repairIndicesButton->setDisabled(true);
473
    d->ui.analyzeSelfIntersectionButton->setDisabled(true);
474
    d->ui.repairSelfIntersectionButton->setDisabled(true);
475
    d->ui.analyzeFoldsButton->setDisabled(true);
476
    d->ui.repairFoldsButton->setDisabled(true);
477
    d->ui.analyzeAllTogether->setDisabled(true);
478
    d->ui.repairAllTogether->setDisabled(true);
479
}
480

481
void DlgEvaluateMeshImp::onRefreshButtonClicked()
482
{
483
    // Connect to application and active document
484
    Gui::Document* gui = Gui::Application::Instance->activeDocument();
485
    if (gui) {
486
        App::Document* doc = gui->getDocument();
487

488
        // switch to the active document
489
        if (doc && doc != this->getDocument()) {
490
            attachDocument(doc);
491
            removeViewProviders();
492
            d->view = dynamic_cast<Gui::View3DInventor*>(gui->getActiveView());
493
        }
494
    }
495

496
    refreshList();
497
}
498

499
void DlgEvaluateMeshImp::onCheckOrientationButtonClicked()
500
{
501
    auto it = d->vp.find("MeshGui::ViewProviderMeshOrientation");
502
    if (it != d->vp.end()) {
503
        if (d->ui.checkOrientationButton->isChecked()) {
504
            it->second->show();
505
        }
506
        else {
507
            it->second->hide();
508
        }
509
    }
510
}
511

512
void DlgEvaluateMeshImp::onAnalyzeOrientationButtonClicked()
513
{
514
    if (d->meshFeature) {
515
        d->ui.analyzeOrientationButton->setEnabled(false);
516
        qApp->processEvents();
517
        qApp->setOverrideCursor(Qt::WaitCursor);
518

519
        const MeshKernel& rMesh = d->meshFeature->Mesh.getValue().getKernel();
520
        MeshEvalOrientation eval(rMesh);
521
        std::vector<MeshCore::FacetIndex> inds = eval.GetIndices();
522

523
        if (inds.empty()) {
524
            d->ui.checkOrientationButton->setText(tr("No flipped normals"));
525
            d->ui.checkOrientationButton->setChecked(false);
526
            d->ui.repairOrientationButton->setEnabled(false);
527
            removeViewProvider("MeshGui::ViewProviderMeshOrientation");
528
        }
529
        else {
530
            d->ui.checkOrientationButton->setText(tr("%1 flipped normals").arg(inds.size()));
531
            d->ui.checkOrientationButton->setChecked(true);
532
            d->ui.repairOrientationButton->setEnabled(true);
533
            d->ui.repairAllTogether->setEnabled(true);
534
            addViewProvider("MeshGui::ViewProviderMeshOrientation", eval.GetIndices());
535
        }
536

537
        qApp->restoreOverrideCursor();
538
        d->ui.analyzeOrientationButton->setEnabled(true);
539
    }
540
}
541

542
void DlgEvaluateMeshImp::onRepairOrientationButtonClicked()
543
{
544
    if (d->meshFeature) {
545
        const char* docName = App::GetApplication().getDocumentName(d->meshFeature->getDocument());
546
        const char* objName = d->meshFeature->getNameInDocument();
547
        Gui::Document* doc = Gui::Application::Instance->getDocument(docName);
548
        doc->openCommand(QT_TRANSLATE_NOOP("Command", "Harmonize normals"));
549
        try {
550
            Gui::Command::doCommand(Gui::Command::App,
551
                                    R"(App.getDocument("%s").getObject("%s").harmonizeNormals())",
552
                                    docName,
553
                                    objName);
554
        }
555
        catch (const Base::Exception& e) {
556
            QMessageBox::warning(this, tr("Orientation"), QString::fromLatin1(e.what()));
557
        }
558

559
        doc->commitCommand();
560
        doc->getDocument()->recompute();
561

562
        d->ui.repairOrientationButton->setEnabled(false);
563
        d->ui.checkOrientationButton->setChecked(false);
564
        removeViewProvider("MeshGui::ViewProviderMeshOrientation");
565
    }
566
}
567

568
void DlgEvaluateMeshImp::onCheckNonmanifoldsButtonClicked()
569
{
570
    // non-manifold edges
571
    std::map<std::string, ViewProviderMeshDefects*>::iterator it;
572
    it = d->vp.find("MeshGui::ViewProviderMeshNonManifolds");
573
    if (it != d->vp.end()) {
574
        if (d->ui.checkNonmanifoldsButton->isChecked()) {
575
            it->second->show();
576
        }
577
        else {
578
            it->second->hide();
579
        }
580
    }
581

582
    // non-manifold points
583
    it = d->vp.find("MeshGui::ViewProviderMeshNonManifoldPoints");
584
    if (it != d->vp.end()) {
585
        if (d->ui.checkNonmanifoldsButton->isChecked()) {
586
            it->second->show();
587
        }
588
        else {
589
            it->second->hide();
590
        }
591
    }
592
}
593

594
void DlgEvaluateMeshImp::onAnalyzeNonmanifoldsButtonClicked()
595
{
596
    if (d->meshFeature) {
597
        d->ui.analyzeNonmanifoldsButton->setEnabled(false);
598
        qApp->processEvents();
599
        qApp->setOverrideCursor(Qt::WaitCursor);
600

601
        const MeshKernel& rMesh = d->meshFeature->Mesh.getValue().getKernel();
602
        MeshEvalTopology f_eval(rMesh);
603
        bool ok1 = f_eval.Evaluate();
604
        bool ok2 = true;
605
        std::vector<Mesh::PointIndex> point_indices;
606

607
        if (d->checkNonManfoldPoints) {
608
            MeshEvalPointManifolds p_eval(rMesh);
609
            ok2 = p_eval.Evaluate();
610
            if (!ok2) {
611
                point_indices = p_eval.GetIndices();
612
            }
613
        }
614

615
        if (ok1 && ok2) {
616
            d->ui.checkNonmanifoldsButton->setText(tr("No non-manifolds"));
617
            d->ui.checkNonmanifoldsButton->setChecked(false);
618
            d->ui.repairNonmanifoldsButton->setEnabled(false);
619
            removeViewProvider("MeshGui::ViewProviderMeshNonManifolds");
620
            removeViewProvider("MeshGui::ViewProviderMeshNonManifoldPoints");
621
        }
622
        else {
623
            d->ui.checkNonmanifoldsButton->setText(
624
                tr("%1 non-manifolds").arg(f_eval.CountManifolds() + point_indices.size()));
625
            d->ui.checkNonmanifoldsButton->setChecked(true);
626
            d->ui.repairNonmanifoldsButton->setEnabled(true);
627
            d->ui.repairAllTogether->setEnabled(true);
628

629
            if (!ok1) {
630
                const std::vector<std::pair<Mesh::FacetIndex, Mesh::FacetIndex>>& inds =
631
                    f_eval.GetIndices();
632
                std::vector<Mesh::FacetIndex> indices;
633
                indices.reserve(2 * inds.size());
634
                std::vector<std::pair<Mesh::FacetIndex, Mesh::FacetIndex>>::const_iterator it;
635
                for (it = inds.begin(); it != inds.end(); ++it) {
636
                    indices.push_back(it->first);
637
                    indices.push_back(it->second);
638
                }
639

640
                addViewProvider("MeshGui::ViewProviderMeshNonManifolds", indices);
641
            }
642

643
            if (!ok2) {
644
                addViewProvider("MeshGui::ViewProviderMeshNonManifoldPoints", point_indices);
645
            }
646
        }
647

648
        qApp->restoreOverrideCursor();
649
        d->ui.analyzeNonmanifoldsButton->setEnabled(true);
650
    }
651
}
652

653
void DlgEvaluateMeshImp::onRepairNonmanifoldsButtonClicked()
654
{
655
    if (d->meshFeature) {
656
        const char* docName = App::GetApplication().getDocumentName(d->meshFeature->getDocument());
657
        const char* objName = d->meshFeature->getNameInDocument();
658
        Gui::Document* doc = Gui::Application::Instance->getDocument(docName);
659
        doc->openCommand(QT_TRANSLATE_NOOP("Command", "Remove non-manifolds"));
660
        try {
661
            Gui::Command::doCommand(Gui::Command::App,
662
                                    R"(App.getDocument("%s").getObject("%s").removeNonManifolds())",
663
                                    docName,
664
                                    objName);
665

666
            if (d->checkNonManfoldPoints) {
667
                Gui::Command::doCommand(
668
                    Gui::Command::App,
669
                    R"(App.getDocument("%s").getObject("%s").removeNonManifoldPoints())",
670
                    docName,
671
                    objName);
672
            }
673
        }
674
        catch (const Base::Exception& e) {
675
            QMessageBox::warning(this, tr("Non-manifolds"), QString::fromLatin1(e.what()));
676
        }
677
        catch (...) {
678
            QMessageBox::warning(this, tr("Non-manifolds"), tr("Cannot remove non-manifolds"));
679
        }
680

681
        doc->commitCommand();
682
        doc->getDocument()->recompute();
683

684
        d->ui.repairNonmanifoldsButton->setEnabled(false);
685
        d->ui.checkNonmanifoldsButton->setChecked(false);
686
        removeViewProvider("MeshGui::ViewProviderMeshNonManifolds");
687
        removeViewProvider("MeshGui::ViewProviderMeshNonManifoldsPoints");
688
    }
689
}
690

691
void DlgEvaluateMeshImp::onCheckIndicesButtonClicked()
692
{
693
    auto it = d->vp.find("MeshGui::ViewProviderMeshIndices");
694
    if (it != d->vp.end()) {
695
        if (d->ui.checkIndicesButton->isChecked()) {
696
            it->second->show();
697
        }
698
        else {
699
            it->second->hide();
700
        }
701
    }
702
}
703

704
void DlgEvaluateMeshImp::onAnalyzeIndicesButtonClicked()
705
{
706
    if (d->meshFeature) {
707
        d->ui.analyzeIndicesButton->setEnabled(false);
708
        qApp->processEvents();
709
        qApp->setOverrideCursor(Qt::WaitCursor);
710

711
        const MeshKernel& rMesh = d->meshFeature->Mesh.getValue().getKernel();
712
        MeshEvalRangeFacet rf(rMesh);
713
        MeshEvalRangePoint rp(rMesh);
714
        MeshEvalCorruptedFacets cf(rMesh);
715
        MeshEvalNeighbourhood nb(rMesh);
716

717
        if (!rf.Evaluate()) {
718
            d->ui.checkIndicesButton->setText(tr("Invalid face indices"));
719
            d->ui.checkIndicesButton->setChecked(true);
720
            d->ui.repairIndicesButton->setEnabled(true);
721
            d->ui.repairAllTogether->setEnabled(true);
722
            addViewProvider("MeshGui::ViewProviderMeshIndices", rf.GetIndices());
723
        }
724
        else if (!rp.Evaluate()) {
725
            d->ui.checkIndicesButton->setText(tr("Invalid point indices"));
726
            d->ui.checkIndicesButton->setChecked(true);
727
            d->ui.repairIndicesButton->setEnabled(true);
728
            d->ui.repairAllTogether->setEnabled(true);
729
            // addViewProvider("MeshGui::ViewProviderMeshIndices", rp.GetIndices());
730
        }
731
        else if (!cf.Evaluate()) {
732
            d->ui.checkIndicesButton->setText(tr("Multiple point indices"));
733
            d->ui.checkIndicesButton->setChecked(true);
734
            d->ui.repairIndicesButton->setEnabled(true);
735
            d->ui.repairAllTogether->setEnabled(true);
736
            addViewProvider("MeshGui::ViewProviderMeshIndices", cf.GetIndices());
737
        }
738
        else if (!nb.Evaluate()) {
739
            d->ui.checkIndicesButton->setText(tr("Invalid neighbour indices"));
740
            d->ui.checkIndicesButton->setChecked(true);
741
            d->ui.repairIndicesButton->setEnabled(true);
742
            d->ui.repairAllTogether->setEnabled(true);
743
            addViewProvider("MeshGui::ViewProviderMeshIndices", nb.GetIndices());
744
        }
745
        else {
746
            d->ui.checkIndicesButton->setText(tr("No invalid indices"));
747
            d->ui.checkIndicesButton->setChecked(false);
748
            d->ui.repairIndicesButton->setEnabled(false);
749
            removeViewProvider("MeshGui::ViewProviderMeshIndices");
750
        }
751

752
        qApp->restoreOverrideCursor();
753
        d->ui.analyzeIndicesButton->setEnabled(true);
754
    }
755
}
756

757
void DlgEvaluateMeshImp::onRepairIndicesButtonClicked()
758
{
759
    if (d->meshFeature) {
760
        const char* docName = App::GetApplication().getDocumentName(d->meshFeature->getDocument());
761
        const char* objName = d->meshFeature->getNameInDocument();
762
        Gui::Document* doc = Gui::Application::Instance->getDocument(docName);
763
        doc->openCommand(QT_TRANSLATE_NOOP("Command", "Fix indices"));
764
        try {
765
            Gui::Command::doCommand(Gui::Command::App,
766
                                    R"(App.getDocument("%s").getObject("%s").fixIndices())",
767
                                    docName,
768
                                    objName);
769
        }
770
        catch (const Base::Exception& e) {
771
            QMessageBox::warning(this, tr("Indices"), QString::fromLatin1(e.what()));
772
        }
773

774
        doc->commitCommand();
775
        doc->getDocument()->recompute();
776

777
        d->ui.repairIndicesButton->setEnabled(false);
778
        d->ui.checkIndicesButton->setChecked(false);
779
        removeViewProvider("MeshGui::ViewProviderMeshIndices");
780
    }
781
}
782

783
void DlgEvaluateMeshImp::onCheckDegenerationButtonClicked()
784
{
785
    auto it = d->vp.find("MeshGui::ViewProviderMeshDegenerations");
786
    if (it != d->vp.end()) {
787
        if (d->ui.checkDegenerationButton->isChecked()) {
788
            it->second->show();
789
        }
790
        else {
791
            it->second->hide();
792
        }
793
    }
794
}
795

796
void DlgEvaluateMeshImp::onAnalyzeDegeneratedButtonClicked()
797
{
798
    if (d->meshFeature) {
799
        d->ui.analyzeDegeneratedButton->setEnabled(false);
800
        qApp->processEvents();
801
        qApp->setOverrideCursor(Qt::WaitCursor);
802

803
        const MeshKernel& rMesh = d->meshFeature->Mesh.getValue().getKernel();
804
        MeshEvalDegeneratedFacets eval(rMesh, d->epsilonDegenerated);
805
        std::vector<Mesh::FacetIndex> degen = eval.GetIndices();
806

807
        if (degen.empty()) {
808
            d->ui.checkDegenerationButton->setText(tr("No degenerations"));
809
            d->ui.checkDegenerationButton->setChecked(false);
810
            d->ui.repairDegeneratedButton->setEnabled(false);
811
            removeViewProvider("MeshGui::ViewProviderMeshDegenerations");
812
        }
813
        else {
814
            d->ui.checkDegenerationButton->setText(tr("%1 degenerated faces").arg(degen.size()));
815
            d->ui.checkDegenerationButton->setChecked(true);
816
            d->ui.repairDegeneratedButton->setEnabled(true);
817
            d->ui.repairAllTogether->setEnabled(true);
818
            addViewProvider("MeshGui::ViewProviderMeshDegenerations", degen);
819
        }
820

821
        qApp->restoreOverrideCursor();
822
        d->ui.analyzeDegeneratedButton->setEnabled(true);
823
    }
824
}
825

826
void DlgEvaluateMeshImp::onRepairDegeneratedButtonClicked()
827
{
828
    if (d->meshFeature) {
829
        const char* docName = App::GetApplication().getDocumentName(d->meshFeature->getDocument());
830
        const char* objName = d->meshFeature->getNameInDocument();
831
        Gui::Document* doc = Gui::Application::Instance->getDocument(docName);
832
        doc->openCommand(QT_TRANSLATE_NOOP("Command", "Remove degenerated faces"));
833
        try {
834
            Gui::Command::doCommand(Gui::Command::App,
835
                                    R"(App.getDocument("%s").getObject("%s").fixDegenerations(%f))",
836
                                    docName,
837
                                    objName,
838
                                    d->epsilonDegenerated);
839
        }
840
        catch (const Base::Exception& e) {
841
            QMessageBox::warning(this, tr("Degenerations"), QString::fromLatin1(e.what()));
842
        }
843

844
        doc->commitCommand();
845
        doc->getDocument()->recompute();
846

847
        d->ui.repairDegeneratedButton->setEnabled(false);
848
        d->ui.checkDegenerationButton->setChecked(false);
849
        removeViewProvider("MeshGui::ViewProviderMeshDegenerations");
850
    }
851
}
852

853
void DlgEvaluateMeshImp::onCheckDuplicatedFacesButtonClicked()
854
{
855
    auto it = d->vp.find("MeshGui::ViewProviderMeshDuplicatedFaces");
856
    if (it != d->vp.end()) {
857
        if (d->ui.checkDuplicatedFacesButton->isChecked()) {
858
            it->second->show();
859
        }
860
        else {
861
            it->second->hide();
862
        }
863
    }
864
}
865

866
void DlgEvaluateMeshImp::onAnalyzeDuplicatedFacesButtonClicked()
867
{
868
    if (d->meshFeature) {
869
        d->ui.analyzeDuplicatedFacesButton->setEnabled(false);
870
        qApp->processEvents();
871
        qApp->setOverrideCursor(Qt::WaitCursor);
872

873
        const MeshKernel& rMesh = d->meshFeature->Mesh.getValue().getKernel();
874
        MeshEvalDuplicateFacets eval(rMesh);
875
        std::vector<Mesh::FacetIndex> dupl = eval.GetIndices();
876

877
        if (dupl.empty()) {
878
            d->ui.checkDuplicatedFacesButton->setText(tr("No duplicated faces"));
879
            d->ui.checkDuplicatedFacesButton->setChecked(false);
880
            d->ui.repairDuplicatedFacesButton->setEnabled(false);
881
            removeViewProvider("MeshGui::ViewProviderMeshDuplicatedFaces");
882
        }
883
        else {
884
            d->ui.checkDuplicatedFacesButton->setText(tr("%1 duplicated faces").arg(dupl.size()));
885
            d->ui.checkDuplicatedFacesButton->setChecked(true);
886
            d->ui.repairDuplicatedFacesButton->setEnabled(true);
887
            d->ui.repairAllTogether->setEnabled(true);
888

889
            addViewProvider("MeshGui::ViewProviderMeshDuplicatedFaces", dupl);
890
        }
891

892
        qApp->restoreOverrideCursor();
893
        d->ui.analyzeDuplicatedFacesButton->setEnabled(true);
894
    }
895
}
896

897
void DlgEvaluateMeshImp::onRepairDuplicatedFacesButtonClicked()
898
{
899
    if (d->meshFeature) {
900
        const char* docName = App::GetApplication().getDocumentName(d->meshFeature->getDocument());
901
        const char* objName = d->meshFeature->getNameInDocument();
902
        Gui::Document* doc = Gui::Application::Instance->getDocument(docName);
903
        doc->openCommand(QT_TRANSLATE_NOOP("Command", "Remove duplicated faces"));
904
        try {
905
            Gui::Command::doCommand(
906
                Gui::Command::App,
907
                R"(App.getDocument("%s").getObject("%s").removeDuplicatedFacets())",
908
                docName,
909
                objName);
910
        }
911
        catch (const Base::Exception& e) {
912
            QMessageBox::warning(this, tr("Duplicated faces"), QString::fromLatin1(e.what()));
913
        }
914

915
        doc->commitCommand();
916
        doc->getDocument()->recompute();
917

918
        d->ui.repairDuplicatedFacesButton->setEnabled(false);
919
        d->ui.checkDuplicatedFacesButton->setChecked(false);
920
        removeViewProvider("MeshGui::ViewProviderMeshDuplicatedFaces");
921
    }
922
}
923

924
void DlgEvaluateMeshImp::onCheckDuplicatedPointsButtonClicked()
925
{
926
    auto it = d->vp.find("MeshGui::ViewProviderMeshDuplicatedPoints");
927
    if (it != d->vp.end()) {
928
        if (d->ui.checkDuplicatedPointsButton->isChecked()) {
929
            it->second->show();
930
        }
931
        else {
932
            it->second->hide();
933
        }
934
    }
935
}
936

937
void DlgEvaluateMeshImp::onAnalyzeDuplicatedPointsButtonClicked()
938
{
939
    if (d->meshFeature) {
940
        d->ui.analyzeDuplicatedPointsButton->setEnabled(false);
941
        qApp->processEvents();
942
        qApp->setOverrideCursor(Qt::WaitCursor);
943

944
        const MeshKernel& rMesh = d->meshFeature->Mesh.getValue().getKernel();
945
        MeshEvalDuplicatePoints eval(rMesh);
946

947
        if (eval.Evaluate()) {
948
            d->ui.checkDuplicatedPointsButton->setText(tr("No duplicated points"));
949
            d->ui.checkDuplicatedPointsButton->setChecked(false);
950
            d->ui.repairDuplicatedPointsButton->setEnabled(false);
951
            removeViewProvider("MeshGui::ViewProviderMeshDuplicatedPoints");
952
        }
953
        else {
954
            d->ui.checkDuplicatedPointsButton->setText(tr("Duplicated points"));
955
            d->ui.checkDuplicatedPointsButton->setChecked(true);
956
            d->ui.repairDuplicatedPointsButton->setEnabled(true);
957
            d->ui.repairAllTogether->setEnabled(true);
958
            addViewProvider("MeshGui::ViewProviderMeshDuplicatedPoints", eval.GetIndices());
959
        }
960

961
        qApp->restoreOverrideCursor();
962
        d->ui.analyzeDuplicatedPointsButton->setEnabled(true);
963
    }
964
}
965

966
void DlgEvaluateMeshImp::onRepairDuplicatedPointsButtonClicked()
967
{
968
    if (d->meshFeature) {
969
        const char* docName = App::GetApplication().getDocumentName(d->meshFeature->getDocument());
970
        const char* objName = d->meshFeature->getNameInDocument();
971
        Gui::Document* doc = Gui::Application::Instance->getDocument(docName);
972
        doc->openCommand(QT_TRANSLATE_NOOP("Command", "Remove duplicated points"));
973
        try {
974
            Gui::Command::doCommand(
975
                Gui::Command::App,
976
                R"(App.getDocument("%s").getObject("%s").removeDuplicatedPoints())",
977
                docName,
978
                objName);
979
        }
980
        catch (const Base::Exception& e) {
981
            QMessageBox::warning(this, tr("Duplicated points"), QString::fromLatin1(e.what()));
982
        }
983

984
        doc->commitCommand();
985
        doc->getDocument()->recompute();
986

987
        d->ui.repairDuplicatedPointsButton->setEnabled(false);
988
        d->ui.checkDuplicatedPointsButton->setChecked(false);
989
        removeViewProvider("MeshGui::ViewProviderMeshDuplicatedPoints");
990
    }
991
}
992

993
void DlgEvaluateMeshImp::onCheckSelfIntersectionButtonClicked()
994
{
995
    auto it = d->vp.find("MeshGui::ViewProviderMeshSelfIntersections");
996
    if (it != d->vp.end()) {
997
        if (d->ui.checkSelfIntersectionButton->isChecked()) {
998
            it->second->show();
999
        }
1000
        else {
1001
            it->second->hide();
1002
        }
1003
    }
1004
}
1005

1006
void DlgEvaluateMeshImp::onAnalyzeSelfIntersectionButtonClicked()
1007
{
1008
    if (d->meshFeature) {
1009
        d->ui.analyzeSelfIntersectionButton->setEnabled(false);
1010
        qApp->processEvents();
1011
        qApp->setOverrideCursor(Qt::WaitCursor);
1012

1013
        const MeshKernel& rMesh = d->meshFeature->Mesh.getValue().getKernel();
1014
        MeshEvalSelfIntersection eval(rMesh);
1015
        std::vector<std::pair<Mesh::FacetIndex, Mesh::FacetIndex>> intersection;
1016
        try {
1017
            eval.GetIntersections(intersection);
1018
        }
1019
        catch (const Base::AbortException&) {
1020
            Base::Console().Message("The self-intersection analysis was aborted by the user\n");
1021
        }
1022

1023
        if (intersection.empty()) {
1024
            d->ui.checkSelfIntersectionButton->setText(tr("No self-intersections"));
1025
            d->ui.checkSelfIntersectionButton->setChecked(false);
1026
            d->ui.repairSelfIntersectionButton->setEnabled(false);
1027
            removeViewProvider("MeshGui::ViewProviderMeshSelfIntersections");
1028
        }
1029
        else {
1030
            d->ui.checkSelfIntersectionButton->setText(tr("Self-intersections"));
1031
            d->ui.checkSelfIntersectionButton->setChecked(true);
1032
            d->ui.repairSelfIntersectionButton->setEnabled(true);
1033
            d->ui.repairAllTogether->setEnabled(true);
1034

1035
            std::vector<Mesh::FacetIndex> indices;
1036
            indices.reserve(2 * intersection.size());
1037
            std::vector<std::pair<Mesh::FacetIndex, Mesh::FacetIndex>>::iterator it;
1038
            for (it = intersection.begin(); it != intersection.end(); ++it) {
1039
                indices.push_back(it->first);
1040
                indices.push_back(it->second);
1041
            }
1042

1043
            addViewProvider("MeshGui::ViewProviderMeshSelfIntersections", indices);
1044
            d->self_intersections.swap(indices);
1045
        }
1046

1047
        qApp->restoreOverrideCursor();
1048
        d->ui.analyzeSelfIntersectionButton->setEnabled(true);
1049
    }
1050
}
1051

1052
void DlgEvaluateMeshImp::onRepairSelfIntersectionButtonClicked()
1053
{
1054
    if (d->meshFeature) {
1055
        const char* docName = App::GetApplication().getDocumentName(d->meshFeature->getDocument());
1056
        Gui::Document* doc = Gui::Application::Instance->getDocument(docName);
1057
        doc->openCommand(QT_TRANSLATE_NOOP("Command", "Fix self-intersections"));
1058

1059
        Mesh::MeshObject* mesh = d->meshFeature->Mesh.startEditing();
1060
        mesh->removeSelfIntersections(d->self_intersections);
1061
        d->meshFeature->Mesh.finishEditing();
1062
        doc->commitCommand();
1063
        doc->getDocument()->recompute();
1064

1065
        d->ui.repairSelfIntersectionButton->setEnabled(false);
1066
        d->ui.checkSelfIntersectionButton->setChecked(false);
1067
        removeViewProvider("MeshGui::ViewProviderMeshSelfIntersections");
1068
    }
1069
}
1070

1071
void DlgEvaluateMeshImp::onCheckFoldsButtonClicked()
1072
{
1073
    auto it = d->vp.find("MeshGui::ViewProviderMeshFolds");
1074
    if (it != d->vp.end()) {
1075
        if (d->ui.checkFoldsButton->isChecked()) {
1076
            it->second->show();
1077
        }
1078
        else {
1079
            it->second->hide();
1080
        }
1081
    }
1082
}
1083

1084
void DlgEvaluateMeshImp::onAnalyzeFoldsButtonClicked()
1085
{
1086
    if (d->meshFeature) {
1087
        d->ui.analyzeFoldsButton->setEnabled(false);
1088
        qApp->processEvents();
1089
        qApp->setOverrideCursor(Qt::WaitCursor);
1090

1091
        const MeshKernel& rMesh = d->meshFeature->Mesh.getValue().getKernel();
1092
        MeshEvalFoldsOnSurface s_eval(rMesh);
1093
        MeshEvalFoldsOnBoundary b_eval(rMesh);
1094
        MeshEvalFoldOversOnSurface f_eval(rMesh);
1095
        bool ok1 = s_eval.Evaluate();
1096
        bool ok2 = b_eval.Evaluate();
1097
        bool ok3 = f_eval.Evaluate();
1098

1099
        if (ok1 && ok2 && ok3) {
1100
            d->ui.checkFoldsButton->setText(tr("No folds on surface"));
1101
            d->ui.checkFoldsButton->setChecked(false);
1102
            d->ui.repairFoldsButton->setEnabled(false);
1103
            removeViewProvider("MeshGui::ViewProviderMeshFolds");
1104
        }
1105
        else {
1106
            std::vector<Mesh::FacetIndex> inds = f_eval.GetIndices();
1107
            std::vector<Mesh::FacetIndex> inds1 = s_eval.GetIndices();
1108
            std::vector<Mesh::FacetIndex> inds2 = b_eval.GetIndices();
1109
            inds.insert(inds.end(), inds1.begin(), inds1.end());
1110
            inds.insert(inds.end(), inds2.begin(), inds2.end());
1111

1112
            // remove duplicates
1113
            std::sort(inds.begin(), inds.end());
1114
            inds.erase(std::unique(inds.begin(), inds.end()), inds.end());
1115

1116
            d->ui.checkFoldsButton->setText(tr("%1 folds on surface").arg(inds.size()));
1117
            d->ui.checkFoldsButton->setChecked(true);
1118
            d->ui.repairFoldsButton->setEnabled(true);
1119
            d->ui.repairAllTogether->setEnabled(true);
1120
            addViewProvider("MeshGui::ViewProviderMeshFolds", inds);
1121
        }
1122

1123
        qApp->restoreOverrideCursor();
1124
        d->ui.analyzeFoldsButton->setEnabled(true);
1125
    }
1126
}
1127

1128
void DlgEvaluateMeshImp::onRepairFoldsButtonClicked()
1129
{
1130
    if (d->meshFeature) {
1131
        const char* docName = App::GetApplication().getDocumentName(d->meshFeature->getDocument());
1132
        const char* objName = d->meshFeature->getNameInDocument();
1133
        Gui::Document* doc = Gui::Application::Instance->getDocument(docName);
1134
        qApp->setOverrideCursor(Qt::WaitCursor);
1135
        doc->openCommand(QT_TRANSLATE_NOOP("Command", "Remove folds"));
1136
        try {
1137
            Gui::Command::doCommand(
1138
                Gui::Command::App,
1139
                R"(App.getDocument("%s").getObject("%s").removeFoldsOnSurface())",
1140
                docName,
1141
                objName);
1142
        }
1143
        catch (const Base::Exception& e) {
1144
            QMessageBox::warning(this, tr("Folds"), QString::fromLatin1(e.what()));
1145
        }
1146

1147
        doc->commitCommand();
1148
        doc->getDocument()->recompute();
1149

1150
        qApp->restoreOverrideCursor();
1151
        d->ui.repairFoldsButton->setEnabled(false);
1152
        d->ui.checkFoldsButton->setChecked(false);
1153
        removeViewProvider("MeshGui::ViewProviderMeshFolds");
1154
    }
1155
}
1156

1157
void DlgEvaluateMeshImp::onAnalyzeAllTogetherClicked()
1158
{
1159
    onAnalyzeOrientationButtonClicked();
1160
    onAnalyzeDuplicatedFacesButtonClicked();
1161
    onAnalyzeDuplicatedPointsButtonClicked();
1162
    onAnalyzeNonmanifoldsButtonClicked();
1163
    onAnalyzeDegeneratedButtonClicked();
1164
    onAnalyzeIndicesButtonClicked();
1165
    onAnalyzeSelfIntersectionButtonClicked();
1166
    if (d->enableFoldsCheck) {
1167
        onAnalyzeFoldsButtonClicked();
1168
    }
1169
}
1170

1171
void DlgEvaluateMeshImp::onRepairAllTogetherClicked()
1172
{
1173
    // clang-format off
1174
    if (d->meshFeature) {
1175
        Gui::WaitCursor wc;
1176
        const char* docName = App::GetApplication().getDocumentName(d->meshFeature->getDocument());
1177
        const char* objName = d->meshFeature->getNameInDocument();
1178
        Gui::Document* doc = Gui::Application::Instance->getDocument(docName);
1179
        doc->openCommand(QT_TRANSLATE_NOOP("Command", "Repair mesh"));
1180

1181
        bool run = false;
1182
        bool self = true;
1183
        int max_iter = 10;
1184
        const MeshKernel& rMesh = d->meshFeature->Mesh.getValue().getKernel();
1185
        try {
1186
            do {
1187
                run = false;
1188
                {
1189
                    MeshEvalSelfIntersection eval(rMesh);
1190
                    if (self && !eval.Evaluate()) {
1191
                        Gui::Command::doCommand(Gui::Command::App,
1192
                            "App.getDocument(\"%s\").getObject(\"%s\").fixSelfIntersections()",
1193
                            docName, objName);
1194
                        run = true;
1195
                    }
1196
                    else {
1197
                        self = false; // once no self-intersections found do not repeat it later on
1198
                    }
1199
                    qApp->processEvents();
1200
                }
1201
                if (d->enableFoldsCheck) {
1202
                    MeshEvalFoldsOnSurface s_eval(rMesh);
1203
                    MeshEvalFoldsOnBoundary b_eval(rMesh);
1204
                    MeshEvalFoldOversOnSurface f_eval(rMesh);
1205
                    if (!s_eval.Evaluate() || !b_eval.Evaluate() || !f_eval.Evaluate()) {
1206
                        Gui::Command::doCommand(Gui::Command::App,
1207
                            "App.getDocument(\"%s\").getObject(\"%s\").removeFoldsOnSurface()",
1208
                            docName, objName);
1209
                        run = true;
1210
                    }
1211
                    qApp->processEvents();
1212
                }
1213
                {
1214
                    MeshEvalOrientation eval(rMesh);
1215
                    if (!eval.Evaluate()) {
1216
                        Gui::Command::doCommand(Gui::Command::App,
1217
                            "App.getDocument(\"%s\").getObject(\"%s\").harmonizeNormals()",
1218
                            docName, objName);
1219
                        run = true;
1220
                    }
1221
                    qApp->processEvents();
1222
                }
1223
                {
1224
                    MeshEvalTopology eval(rMesh);
1225
                    if (!eval.Evaluate()) {
1226
                        Gui::Command::doCommand(Gui::Command::App,
1227
                            "App.getDocument(\"%s\").getObject(\"%s\").removeNonManifolds()",
1228
                            docName, objName);
1229
                        run = true;
1230
                    }
1231
                    qApp->processEvents();
1232
                }
1233
                {
1234
                    MeshEvalRangeFacet rf(rMesh);
1235
                    MeshEvalRangePoint rp(rMesh);
1236
                    MeshEvalCorruptedFacets cf(rMesh);
1237
                    MeshEvalNeighbourhood nb(rMesh);
1238
                    if (!rf.Evaluate() || !rp.Evaluate() || !cf.Evaluate() || !nb.Evaluate()) {
1239
                        Gui::Command::doCommand(Gui::Command::App,
1240
                            "App.getDocument(\"%s\").getObject(\"%s\").fixIndices()",
1241
                            docName, objName);
1242
                        run = true;
1243
                    }
1244
                }
1245
                {
1246
                    MeshEvalDegeneratedFacets eval(rMesh, d->epsilonDegenerated);
1247
                    if (!eval.Evaluate()) {
1248
                        Gui::Command::doCommand(Gui::Command::App,
1249
                            "App.getDocument(\"%s\").getObject(\"%s\").fixDegenerations(%f)",
1250
                            docName, objName, d->epsilonDegenerated);
1251
                        run = true;
1252
                    }
1253
                    qApp->processEvents();
1254
                }
1255
                {
1256
                    MeshEvalDuplicateFacets eval(rMesh);
1257
                    if (!eval.Evaluate()) {
1258
                        Gui::Command::doCommand(Gui::Command::App,
1259
                            "App.getDocument(\"%s\").getObject(\"%s\").removeDuplicatedFacets()",
1260
                            docName, objName);
1261
                        run = true;
1262
                    }
1263
                    qApp->processEvents();
1264
                }
1265
                {
1266
                    MeshEvalDuplicatePoints eval(rMesh);
1267
                    if (!eval.Evaluate()) {
1268
                        Gui::Command::doCommand(Gui::Command::App,
1269
                            "App.getDocument(\"%s\").getObject(\"%s\").removeDuplicatedPoints()",
1270
                            docName, objName);
1271
                        run = true;
1272
                    }
1273
                    qApp->processEvents();
1274
                }
1275
            } while(d->ui.checkRepeatButton->isChecked() && run && (--max_iter > 0));
1276
        }
1277
        catch (const Base::Exception& e) {
1278
            QMessageBox::warning(this, tr("Mesh repair"), QString::fromLatin1(e.what()));
1279
        }
1280
        catch (...) {
1281
            QMessageBox::warning(this, tr("Mesh repair"), QString::fromLatin1("Unknown error occurred."));
1282
        }
1283

1284
        doc->commitCommand();
1285
        doc->getDocument()->recompute();
1286
    }
1287
    // clang-format on
1288
}
1289

1290
void DlgEvaluateMeshImp::onButtonBoxClicked(QAbstractButton* button)
1291
{
1292
    QDialogButtonBox::StandardButton type = d->ui.buttonBox->standardButton(button);
1293
    if (type == QDialogButtonBox::Open) {
1294
        DlgEvaluateSettings dlg(this);
1295
        dlg.setNonmanifoldPointsChecked(d->checkNonManfoldPoints);
1296
        dlg.setFoldsChecked(d->enableFoldsCheck);
1297
        dlg.setDegeneratedFacetsChecked(d->strictlyDegenerated);
1298
        if (dlg.exec() == QDialog::Accepted) {
1299
            d->checkNonManfoldPoints = dlg.isNonmanifoldPointsChecked();
1300
            d->enableFoldsCheck = dlg.isFoldsChecked();
1301
            d->showFoldsFunction(d->enableFoldsCheck);
1302
            d->strictlyDegenerated = dlg.isDegeneratedFacetsChecked();
1303
            if (d->strictlyDegenerated) {
1304
                d->epsilonDegenerated = 0.0F;
1305
            }
1306
            else {
1307
                d->epsilonDegenerated = MeshCore::MeshDefinitions::_fMinPointDistanceP2;
1308
            }
1309
        }
1310
    }
1311
    else if (type == QDialogButtonBox::Reset) {
1312
        removeViewProviders();
1313
        cleanInformation();
1314
        showInformation();
1315
        d->self_intersections.clear();
1316
        QList<QCheckBox*> cbs = this->findChildren<QCheckBox*>();
1317
        Q_FOREACH (QCheckBox* cb, cbs) {
1318
            cb->setChecked(false);
1319
        }
1320
    }
1321
}
1322

1323
// -------------------------------------------------------------
1324

1325
/* TRANSLATOR MeshGui::DockEvaluateMeshImp */
1326

1327
#if 0  // needed for Qt's lupdate utility
1328
    qApp->translate("QDockWidget", "Evaluate & Repair Mesh");
1329
#endif
1330

1331
DockEvaluateMeshImp* DockEvaluateMeshImp::_instance = nullptr;
1332

1333
DockEvaluateMeshImp* DockEvaluateMeshImp::instance()
1334
{
1335
    // not initialized?
1336
    if (!_instance) {
1337
        _instance = new DockEvaluateMeshImp(Gui::getMainWindow());
1338
        _instance->setSizeGripEnabled(false);
1339
    }
1340

1341
    return _instance;
1342
}
1343

1344
void DockEvaluateMeshImp::destruct()
1345
{
1346
    if (_instance) {
1347
        DockEvaluateMeshImp* pTmp = _instance;
1348
        _instance = nullptr;
1349
        delete pTmp;
1350
    }
1351
}
1352

1353
bool DockEvaluateMeshImp::hasInstance()
1354
{
1355
    return _instance != nullptr;
1356
}
1357

1358
/**
1359
 *  Constructs a DockEvaluateMeshImp which is a child of 'parent', with the
1360
 *  name 'name' and widget flags set to 'f'
1361
 */
1362
DockEvaluateMeshImp::DockEvaluateMeshImp(QWidget* parent, Qt::WindowFlags fl)
1363
    : DlgEvaluateMeshImp(parent, fl)
1364
{
1365
    scrollArea = new QScrollArea();  // NOLINT
1366
    scrollArea->setObjectName(QLatin1String("scrollArea"));
1367
    scrollArea->setFrameShape(QFrame::NoFrame);
1368
    scrollArea->setFrameShadow(QFrame::Plain);
1369
    scrollArea->setWidgetResizable(true);
1370
    scrollArea->setWidget(this);
1371

1372
    // embed this dialog into a dockable widget container
1373
    Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance();
1374
    // use Qt macro for preparing for translation stuff (but not translating yet)
1375
    QDockWidget* dw =
1376
        pDockMgr->addDockWindow("Evaluate & Repair Mesh", scrollArea, Qt::RightDockWidgetArea);
1377
    dw->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
1378
    dw->show();
1379
}
1380

1381
/**
1382
 *  Destroys the object and frees any allocated resources
1383
 */
1384
DockEvaluateMeshImp::~DockEvaluateMeshImp()
1385
{
1386
    _instance = nullptr;
1387
}
1388

1389
/**
1390
 * Destroys the dock window this object is embedded into without destroying itself.
1391
 */
1392
void DockEvaluateMeshImp::closeEvent(QCloseEvent* event)
1393
{
1394
    Q_UNUSED(event)
1395
    // closes the dock window
1396
    Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance();
1397
    pDockMgr->removeDockWindow(scrollArea);
1398

1399
    // make sure to also delete the scroll area
1400
    scrollArea->setWidget(nullptr);
1401
    scrollArea->deleteLater();
1402
}
1403

1404
/**
1405
 * Returns an appropriate size hint for the dock window.
1406
 */
1407
QSize DockEvaluateMeshImp::sizeHint() const
1408
{
1409
    return {371, 579};
1410
}
1411

1412
#include "moc_DlgEvaluateMeshImp.cpp"
1413

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

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

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

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