1
/***************************************************************************
2
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
4
* This file is part of the FreeCAD CAx development system. *
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. *
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. *
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 *
21
***************************************************************************/
23
#include "PreCompiled.h"
25
#include <Precision.hxx>
26
#include <QDoubleValidator>
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>
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>
49
#include "TaskSketcherValidation.h"
50
#include "ui_TaskSketcherValidation.h"
53
using namespace SketcherGui;
54
using namespace Gui::TaskView;
56
/* TRANSLATOR SketcherGui::SketcherValidation */
58
SketcherValidation::SketcherValidation(Sketcher::SketchObject* Obj, QWidget* parent)
60
, ui(new Ui_TaskSketcherValidation())
62
, coincidenceRoot(nullptr)
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 = {
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
86
for (double it : tolerances) {
87
ui->comboBoxTolerance->addItem(loc.toString(it), QVariant(it));
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));
97
SketcherValidation::~SketcherValidation()
102
void SketcherValidation::setupConnections()
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);
132
void SketcherValidation::changeEvent(QEvent* e)
134
if (e->type() == QEvent::LanguageChange) {
135
ui->retranslateUi(this);
137
QWidget::changeEvent(e);
140
void SketcherValidation::onFindButtonClicked()
142
if (sketch.expired()) {
146
double prec = Precision::Confusion();
150
conv = QLocale::system().toDouble(ui->comboBoxTolerance->currentText(), &ok);
156
QVariant v = ui->comboBoxTolerance->itemData(ui->comboBoxTolerance->currentIndex());
162
sketch->detectMissingPointOnPointConstraints(prec,
163
!ui->checkBoxIgnoreConstruction->isChecked());
165
std::vector<Sketcher::ConstraintIds>& vertexConstraints =
166
sketch->getMissingPointOnPointConstraints();
168
std::vector<Base::Vector3d> points;
169
points.reserve(vertexConstraints.size());
171
for (auto vc : vertexConstraints) {
172
points.push_back(vc.v);
176
if (vertexConstraints.empty()) {
177
Gui::TranslatedNotification(*sketch,
178
tr("No missing coincidences"),
179
tr("No missing coincidences found"));
181
ui->fixButton->setEnabled(false);
185
Gui::TranslatedUserWarning(
187
tr("Missing coincidences"),
188
tr("%1 missing coincidences found").arg(vertexConstraints.size()));
190
ui->fixButton->setEnabled(true);
194
void SketcherValidation::onFixButtonClicked()
196
if (sketch.expired()) {
201
App::Document* doc = sketch->getDocument();
202
doc->openTransaction("Add coincident constraint");
204
Gui::cmdAppObjectArgs(sketch.get(), "makeMissingPointOnPointCoincident()");
206
ui->fixButton->setEnabled(false);
209
// finish the transaction and update
211
doc->commitTransaction();
215
void SketcherValidation::onHighlightButtonClicked()
217
if (sketch.expired()) {
221
std::vector<Base::Vector3d> points;
223
points = sketch->getOpenVertices();
226
if (!points.empty()) {
231
void SketcherValidation::onFindConstraintClicked()
233
if (sketch.expired()) {
237
if (sketch->evaluateConstraints()) {
238
Gui::TranslatedNotification(*sketch,
239
tr("No invalid constraints"),
240
tr("No invalid constraints found"));
242
ui->fixConstraint->setEnabled(false);
245
Gui::TranslatedUserError(*sketch,
246
tr("Invalid constraints"),
247
tr("Invalid constraints found"));
249
ui->fixConstraint->setEnabled(true);
253
void SketcherValidation::onFixConstraintClicked()
255
if (sketch.expired()) {
259
Gui::cmdAppObjectArgs(sketch.get(), "validateConstraints()");
260
ui->fixConstraint->setEnabled(false);
263
void SketcherValidation::onFindReversedClicked()
265
if (sketch.expired()) {
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));
282
if (!points.empty()) {
283
int nc = sketch->port_reversedExternalArcs(/*justAnalyze=*/true);
286
Gui::TranslatedUserWarning(
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)
298
ui->swapReversed->setEnabled(true);
301
Gui::TranslatedUserWarning(
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));
309
ui->swapReversed->setEnabled(false);
313
Gui::TranslatedNotification(*sketch,
314
tr("Reversed external geometry"),
315
tr("No reversed external-geometry arcs were found."));
319
void SketcherValidation::onSwapReversedClicked()
321
if (sketch.expired()) {
325
App::Document* doc = sketch->getDocument();
326
doc->openTransaction("Sketch porting");
328
int n = sketch->port_reversedExternalArcs(/*justAnalyze=*/false);
329
Gui::TranslatedNotification(
331
tr("Reversed external geometry"),
332
tr("%1 changes were made to constraints linking to endpoints of reversed arcs.").arg(n));
335
ui->swapReversed->setEnabled(false);
337
doc->commitTransaction();
340
void SketcherValidation::onOrientLockEnableClicked()
342
if (sketch.expired()) {
346
App::Document* doc = sketch->getDocument();
347
doc->openTransaction("Constraint orientation lock");
349
int n = sketch->changeConstraintsLocking(/*bLock=*/true);
350
Gui::TranslatedNotification(
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 ->"
358
doc->commitTransaction();
361
void SketcherValidation::onOrientLockDisableClicked()
363
if (sketch.expired()) {
367
App::Document* doc = sketch->getDocument();
368
doc->openTransaction("Constraint orientation unlock");
370
int n = sketch->changeConstraintsLocking(/*bLock=*/false);
371
Gui::TranslatedNotification(
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"
380
doc->commitTransaction();
383
void SketcherValidation::onDelConstrExtrClicked()
385
if (sketch.expired()) {
389
int reply = QMessageBox::question(
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,
397
if (reply != QMessageBox::Yes) {
401
App::Document* doc = sketch->getDocument();
402
doc->openTransaction("Delete constraints");
404
Gui::cmdAppObjectArgs(sketch.get(), "delConstraintsToExternal()");
406
doc->commitTransaction();
408
Gui::TranslatedNotification(
410
tr("Delete constraints to external geom."),
411
tr("All constraints that deal with external geometry were deleted."));
414
void SketcherValidation::showPoints(const std::vector<Base::Vector3d>& pts)
416
auto coords = new SoCoordinate3();
417
auto drawStyle = new SoDrawStyle();
418
drawStyle->pointSize = 6;
419
auto pcPoints = new SoPointSet();
421
coincidenceRoot = new SoGroup();
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);
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);
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);
450
coords->point.finishEditing();
452
if (!sketch.expired()) {
453
Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(sketch.get());
454
vp->getRoot()->addChild(coincidenceRoot);
458
void SketcherValidation::hidePoints()
460
if (coincidenceRoot) {
461
if (!sketch.expired()) {
462
Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(sketch.get());
463
vp->getRoot()->removeChild(coincidenceRoot);
465
coincidenceRoot = nullptr;
469
void SketcherValidation::onFindDegeneratedClicked()
471
if (sketch.expired()) {
475
double prec = Precision::Confusion();
476
int count = sketch->detectDegeneratedGeometries(prec);
479
Gui::TranslatedNotification(*sketch,
480
tr("No degenerated geometry"),
481
tr("No degenerated geometry found"));
483
ui->fixDegenerated->setEnabled(false);
486
Gui::TranslatedUserWarning(*sketch,
487
tr("Degenerated geometry"),
488
tr("%1 degenerated geometry found").arg(count));
490
ui->fixDegenerated->setEnabled(true);
494
void SketcherValidation::onFixDegeneratedClicked()
496
if (sketch.expired()) {
501
App::Document* doc = sketch->getDocument();
502
doc->openTransaction("Remove degenerated geometry");
504
double prec = Precision::Confusion();
505
Gui::cmdAppObjectArgs(sketch.get(), "removeDegeneratedGeometries(%.12f)", prec);
507
ui->fixButton->setEnabled(false);
510
// finish the transaction and update
512
doc->commitTransaction();
516
// -----------------------------------------------
518
TaskSketcherValidation::TaskSketcherValidation(Sketcher::SketchObject* Obj)
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);
526
TaskSketcherValidation::~TaskSketcherValidation() = default;
528
#include "moc_TaskSketcherValidation.cpp"