FreeCAD

Форк
0
/
TaskSketcherValidation.cpp 
528 строк · 16.9 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2013 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 <Precision.hxx>
26
#include <QDoubleValidator>
27
#include <QLocale>
28
#include <QMessageBox>
29
#include <algorithm>
30
#include <array>
31

32
#include <Inventor/nodes/SoBaseColor.h>
33
#include <Inventor/nodes/SoCoordinate3.h>
34
#include <Inventor/nodes/SoDrawStyle.h>
35
#include <Inventor/nodes/SoMarkerSet.h>
36
#include <Inventor/nodes/SoSeparator.h>
37
#endif
38

39
#include <App/Document.h>
40
#include <Gui/Application.h>
41
#include <Gui/CommandT.h>
42
#include <Gui/Inventor/MarkerBitmaps.h>
43
#include <Gui/Notifications.h>
44
#include <Gui/TaskView/TaskView.h>
45
#include <Gui/ViewProvider.h>
46
#include <Gui/WaitCursor.h>
47
#include <Mod/Sketcher/App/SketchObject.h>
48

49
#include "TaskSketcherValidation.h"
50
#include "ui_TaskSketcherValidation.h"
51

52

53
using namespace SketcherGui;
54
using namespace Gui::TaskView;
55

56
/* TRANSLATOR SketcherGui::SketcherValidation */
57

58
SketcherValidation::SketcherValidation(Sketcher::SketchObject* Obj, QWidget* parent)
59
    : QWidget(parent)
60
    , ui(new Ui_TaskSketcherValidation())
61
    , sketch(Obj)
62
    , coincidenceRoot(nullptr)
63
{
64
    ui->setupUi(this);
65
    setupConnections();
66

67
    ui->fixButton->setEnabled(false);
68
    ui->fixConstraint->setEnabled(false);
69
    ui->fixDegenerated->setEnabled(false);
70
    ui->swapReversed->setEnabled(false);
71
    ui->checkBoxIgnoreConstruction->setEnabled(true);
72
    std::array tolerances = {
73
        // NOLINTBEGIN
74
        Precision::Confusion() / 100.0,
75
        Precision::Confusion() / 10.0,
76
        Precision::Confusion(),
77
        Precision::Confusion() * 10.0,
78
        Precision::Confusion() * 100.0,
79
        Precision::Confusion() * 1000.0,
80
        Precision::Confusion() * 10000.0,
81
        Precision::Confusion() * 100000.0
82
        // NOLINTEND
83
    };
84

85
    QLocale loc;
86
    for (double it : tolerances) {
87
        ui->comboBoxTolerance->addItem(loc.toString(it), QVariant(it));
88
    }
89
    ui->comboBoxTolerance->setCurrentIndex(5);
90
    ui->comboBoxTolerance->setEditable(true);
91
    const double bottom = 0.0;
92
    const double top = 10.0;
93
    const int decimals = 10;
94
    ui->comboBoxTolerance->setValidator(new QDoubleValidator(bottom, top, decimals, this));
95
}
96

97
SketcherValidation::~SketcherValidation()
98
{
99
    hidePoints();
100
}
101

102
void SketcherValidation::setupConnections()
103
{
104
    // clang-format off
105
    connect(ui->findButton, &QPushButton::clicked,
106
            this, &SketcherValidation::onFindButtonClicked);
107
    connect(ui->fixButton, &QPushButton::clicked,
108
            this, &SketcherValidation::onFixButtonClicked);
109
    connect(ui->highlightButton, &QPushButton::clicked,
110
            this, &SketcherValidation::onHighlightButtonClicked);
111
    connect(ui->findConstraint, &QPushButton::clicked,
112
            this, &SketcherValidation::onFindConstraintClicked);
113
    connect(ui->fixConstraint, &QPushButton::clicked,
114
            this, &SketcherValidation::onFixConstraintClicked);
115
    connect(ui->findReversed, &QPushButton::clicked,
116
            this, &SketcherValidation::onFindReversedClicked);
117
    connect(ui->swapReversed, &QPushButton::clicked,
118
            this, &SketcherValidation::onSwapReversedClicked);
119
    connect(ui->orientLockEnable, &QPushButton::clicked,
120
            this, &SketcherValidation::onOrientLockEnableClicked);
121
    connect(ui->orientLockDisable, &QPushButton::clicked,
122
            this, &SketcherValidation::onOrientLockDisableClicked);
123
    connect(ui->delConstrExtr, &QPushButton::clicked,
124
            this, &SketcherValidation::onDelConstrExtrClicked);
125
    connect(ui->findDegenerated, &QPushButton::clicked,
126
            this, &SketcherValidation::onFindDegeneratedClicked);
127
    connect(ui->fixDegenerated, &QPushButton::clicked,
128
            this, &SketcherValidation::onFixDegeneratedClicked);
129
    // clang-format on
130
}
131

132
void SketcherValidation::changeEvent(QEvent* e)
133
{
134
    if (e->type() == QEvent::LanguageChange) {
135
        ui->retranslateUi(this);
136
    }
137
    QWidget::changeEvent(e);
138
}
139

140
void SketcherValidation::onFindButtonClicked()
141
{
142
    if (sketch.expired()) {
143
        return;
144
    }
145

146
    double prec = Precision::Confusion();
147
    bool ok {};
148
    double conv {};
149

150
    conv = QLocale::system().toDouble(ui->comboBoxTolerance->currentText(), &ok);
151

152
    if (ok) {
153
        prec = conv;
154
    }
155
    else {
156
        QVariant v = ui->comboBoxTolerance->itemData(ui->comboBoxTolerance->currentIndex());
157
        if (v.isValid()) {
158
            prec = v.toDouble();
159
        }
160
    }
161

162
    sketch->detectMissingPointOnPointConstraints(prec,
163
                                                 !ui->checkBoxIgnoreConstruction->isChecked());
164

165
    std::vector<Sketcher::ConstraintIds>& vertexConstraints =
166
        sketch->getMissingPointOnPointConstraints();
167

168
    std::vector<Base::Vector3d> points;
169
    points.reserve(vertexConstraints.size());
170

171
    for (auto vc : vertexConstraints) {
172
        points.push_back(vc.v);
173
    }
174

175
    hidePoints();
176
    if (vertexConstraints.empty()) {
177
        Gui::TranslatedNotification(*sketch,
178
                                    tr("No missing coincidences"),
179
                                    tr("No missing coincidences found"));
180

181
        ui->fixButton->setEnabled(false);
182
    }
183
    else {
184
        showPoints(points);
185
        Gui::TranslatedUserWarning(
186
            *sketch,
187
            tr("Missing coincidences"),
188
            tr("%1 missing coincidences found").arg(vertexConstraints.size()));
189

190
        ui->fixButton->setEnabled(true);
191
    }
192
}
193

194
void SketcherValidation::onFixButtonClicked()
195
{
196
    if (sketch.expired()) {
197
        return;
198
    }
199

200
    // undo command open
201
    App::Document* doc = sketch->getDocument();
202
    doc->openTransaction("Add coincident constraint");
203

204
    Gui::cmdAppObjectArgs(sketch.get(), "makeMissingPointOnPointCoincident()");
205

206
    ui->fixButton->setEnabled(false);
207
    hidePoints();
208

209
    // finish the transaction and update
210
    Gui::WaitCursor wc;
211
    doc->commitTransaction();
212
    doc->recompute();
213
}
214

215
void SketcherValidation::onHighlightButtonClicked()
216
{
217
    if (sketch.expired()) {
218
        return;
219
    }
220

221
    std::vector<Base::Vector3d> points;
222

223
    points = sketch->getOpenVertices();
224

225
    hidePoints();
226
    if (!points.empty()) {
227
        showPoints(points);
228
    }
229
}
230

231
void SketcherValidation::onFindConstraintClicked()
232
{
233
    if (sketch.expired()) {
234
        return;
235
    }
236

237
    if (sketch->evaluateConstraints()) {
238
        Gui::TranslatedNotification(*sketch,
239
                                    tr("No invalid constraints"),
240
                                    tr("No invalid constraints found"));
241

242
        ui->fixConstraint->setEnabled(false);
243
    }
244
    else {
245
        Gui::TranslatedUserError(*sketch,
246
                                 tr("Invalid constraints"),
247
                                 tr("Invalid constraints found"));
248

249
        ui->fixConstraint->setEnabled(true);
250
    }
251
}
252

253
void SketcherValidation::onFixConstraintClicked()
254
{
255
    if (sketch.expired()) {
256
        return;
257
    }
258

259
    Gui::cmdAppObjectArgs(sketch.get(), "validateConstraints()");
260
    ui->fixConstraint->setEnabled(false);
261
}
262

263
void SketcherValidation::onFindReversedClicked()
264
{
265
    if (sketch.expired()) {
266
        return;
267
    }
268

269
    std::vector<Base::Vector3d> points;
270
    const std::vector<Part::Geometry*>& geom = sketch->getExternalGeometry();
271
    for (const auto geo : geom) {
272
        // only arcs of circles need to be repaired. Arcs of ellipse were so broken there should be
273
        // nothing to repair from.
274
        if (const auto segm = dynamic_cast<const Part::GeomArcOfCircle*>(geo)) {
275
            if (segm->isReversed()) {
276
                points.push_back(segm->getStartPoint(/*emulateCCWXY=*/true));
277
                points.push_back(segm->getEndPoint(/*emulateCCWXY=*/true));
278
            }
279
        }
280
    }
281
    hidePoints();
282
    if (!points.empty()) {
283
        int nc = sketch->port_reversedExternalArcs(/*justAnalyze=*/true);
284
        showPoints(points);
285
        if (nc > 0) {
286
            Gui::TranslatedUserWarning(
287
                *sketch,
288
                tr("Reversed external geometry"),
289
                tr("%1 reversed external-geometry arcs were found. Their endpoints are"
290
                   " encircled in 3d view.\n\n"
291
                   "%2 constraints are linking to the endpoints. The constraints have"
292
                   " been listed in Report view (menu View -> Panels -> Report view).\n\n"
293
                   "Click \"Swap endpoints in constraints\" button to reassign endpoints."
294
                   " Do this only once to sketches created in FreeCAD older than v0.15")
295
                    .arg(points.size() / 2)
296
                    .arg(nc));
297

298
            ui->swapReversed->setEnabled(true);
299
        }
300
        else {
301
            Gui::TranslatedUserWarning(
302
                *sketch,
303
                tr("Reversed external geometry"),
304
                tr("%1 reversed external-geometry arcs were found. Their endpoints are "
305
                   "encircled in 3d view.\n\n"
306
                   "However, no constraints linking to the endpoints were found.")
307
                    .arg(points.size() / 2));
308

309
            ui->swapReversed->setEnabled(false);
310
        }
311
    }
312
    else {
313
        Gui::TranslatedNotification(*sketch,
314
                                    tr("Reversed external geometry"),
315
                                    tr("No reversed external-geometry arcs were found."));
316
    }
317
}
318

319
void SketcherValidation::onSwapReversedClicked()
320
{
321
    if (sketch.expired()) {
322
        return;
323
    }
324

325
    App::Document* doc = sketch->getDocument();
326
    doc->openTransaction("Sketch porting");
327

328
    int n = sketch->port_reversedExternalArcs(/*justAnalyze=*/false);
329
    Gui::TranslatedNotification(
330
        *sketch,
331
        tr("Reversed external geometry"),
332
        tr("%1 changes were made to constraints linking to endpoints of reversed arcs.").arg(n));
333

334
    hidePoints();
335
    ui->swapReversed->setEnabled(false);
336

337
    doc->commitTransaction();
338
}
339

340
void SketcherValidation::onOrientLockEnableClicked()
341
{
342
    if (sketch.expired()) {
343
        return;
344
    }
345

346
    App::Document* doc = sketch->getDocument();
347
    doc->openTransaction("Constraint orientation lock");
348

349
    int n = sketch->changeConstraintsLocking(/*bLock=*/true);
350
    Gui::TranslatedNotification(
351
        *sketch,
352
        tr("Constraint orientation locking"),
353
        tr("Orientation locking was enabled and recomputed for %1 constraints. The"
354
           " constraints have been listed in Report view (menu View -> Panels ->"
355
           " Report view).")
356
            .arg(n));
357

358
    doc->commitTransaction();
359
}
360

361
void SketcherValidation::onOrientLockDisableClicked()
362
{
363
    if (sketch.expired()) {
364
        return;
365
    }
366

367
    App::Document* doc = sketch->getDocument();
368
    doc->openTransaction("Constraint orientation unlock");
369

370
    int n = sketch->changeConstraintsLocking(/*bLock=*/false);
371
    Gui::TranslatedNotification(
372
        *sketch,
373
        tr("Constraint orientation locking"),
374
        tr("Orientation locking was disabled for %1 constraints. The"
375
           " constraints have been listed in Report view (menu View -> Panels ->"
376
           " Report view). Note that for all future constraints, the locking still"
377
           " defaults to ON.")
378
            .arg(n));
379

380
    doc->commitTransaction();
381
}
382

383
void SketcherValidation::onDelConstrExtrClicked()
384
{
385
    if (sketch.expired()) {
386
        return;
387
    }
388

389
    int reply = QMessageBox::question(
390
        this,
391
        tr("Delete constraints to external geom."),
392
        tr("You are about to delete ALL constraints that deal with external geometry. This is "
393
           "useful to rescue a sketch with broken/changed links to external geometry. Are you sure "
394
           "you want to delete the constraints?"),
395
        QMessageBox::No | QMessageBox::Yes,
396
        QMessageBox::No);
397
    if (reply != QMessageBox::Yes) {
398
        return;
399
    }
400

401
    App::Document* doc = sketch->getDocument();
402
    doc->openTransaction("Delete constraints");
403

404
    Gui::cmdAppObjectArgs(sketch.get(), "delConstraintsToExternal()");
405

406
    doc->commitTransaction();
407

408
    Gui::TranslatedNotification(
409
        *sketch,
410
        tr("Delete constraints to external geom."),
411
        tr("All constraints that deal with external geometry were deleted."));
412
}
413

414
void SketcherValidation::showPoints(const std::vector<Base::Vector3d>& pts)
415
{
416
    auto coords = new SoCoordinate3();
417
    auto drawStyle = new SoDrawStyle();
418
    drawStyle->pointSize = 6;
419
    auto pcPoints = new SoPointSet();
420

421
    coincidenceRoot = new SoGroup();
422

423
    coincidenceRoot->addChild(drawStyle);
424
    auto pointsep = new SoSeparator();
425
    auto basecol = new SoBaseColor();
426
    basecol->rgb.setValue(1.0F, 0.5F, 0.0F);
427
    pointsep->addChild(basecol);
428
    pointsep->addChild(coords);
429
    pointsep->addChild(pcPoints);
430
    coincidenceRoot->addChild(pointsep);
431

432
    // Draw markers
433
    auto markcol = new SoBaseColor();
434
    markcol->rgb.setValue(1.0F, 1.0F, 0.0F);
435
    auto marker = new SoMarkerSet();
436
    long markerSize = App::GetApplication()
437
                          .GetParameterGroupByPath("User parameter:BaseApp/Preferences/View")
438
                          ->GetInt("MarkerSize", 9);
439
    marker->markerIndex = Gui::Inventor::MarkerBitmaps::getMarkerIndex("PLUS", int(markerSize));
440
    pointsep->addChild(markcol);
441
    pointsep->addChild(marker);
442

443
    int pts_size = (int)pts.size();
444
    coords->point.setNum(pts_size);
445
    SbVec3f* c = coords->point.startEditing();
446
    for (int i = 0; i < pts_size; i++) {
447
        const Base::Vector3d& v = pts[i];
448
        c[i].setValue((float)v.x, (float)v.y, (float)v.z);
449
    }
450
    coords->point.finishEditing();
451

452
    if (!sketch.expired()) {
453
        Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(sketch.get());
454
        vp->getRoot()->addChild(coincidenceRoot);
455
    }
456
}
457

458
void SketcherValidation::hidePoints()
459
{
460
    if (coincidenceRoot) {
461
        if (!sketch.expired()) {
462
            Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(sketch.get());
463
            vp->getRoot()->removeChild(coincidenceRoot);
464
        }
465
        coincidenceRoot = nullptr;
466
    }
467
}
468

469
void SketcherValidation::onFindDegeneratedClicked()
470
{
471
    if (sketch.expired()) {
472
        return;
473
    }
474

475
    double prec = Precision::Confusion();
476
    int count = sketch->detectDegeneratedGeometries(prec);
477

478
    if (count == 0) {
479
        Gui::TranslatedNotification(*sketch,
480
                                    tr("No degenerated geometry"),
481
                                    tr("No degenerated geometry found"));
482

483
        ui->fixDegenerated->setEnabled(false);
484
    }
485
    else {
486
        Gui::TranslatedUserWarning(*sketch,
487
                                   tr("Degenerated geometry"),
488
                                   tr("%1 degenerated geometry found").arg(count));
489

490
        ui->fixDegenerated->setEnabled(true);
491
    }
492
}
493

494
void SketcherValidation::onFixDegeneratedClicked()
495
{
496
    if (sketch.expired()) {
497
        return;
498
    }
499

500
    // undo command open
501
    App::Document* doc = sketch->getDocument();
502
    doc->openTransaction("Remove degenerated geometry");
503

504
    double prec = Precision::Confusion();
505
    Gui::cmdAppObjectArgs(sketch.get(), "removeDegeneratedGeometries(%.12f)", prec);
506

507
    ui->fixButton->setEnabled(false);
508
    hidePoints();
509

510
    // finish the transaction and update
511
    Gui::WaitCursor wc;
512
    doc->commitTransaction();
513
    doc->recompute();
514
}
515

516
// -----------------------------------------------
517

518
TaskSketcherValidation::TaskSketcherValidation(Sketcher::SketchObject* Obj)
519
{
520
    QWidget* widget = new SketcherValidation(Obj);
521
    auto taskbox = new Gui::TaskView::TaskBox(QPixmap(), widget->windowTitle(), true, nullptr);
522
    taskbox->groupLayout()->addWidget(widget);
523
    Content.push_back(taskbox);
524
}
525

526
TaskSketcherValidation::~TaskSketcherValidation() = default;
527

528
#include "moc_TaskSketcherValidation.cpp"
529

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

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

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

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