Files
create/src/Mod/Part/Gui/TaskCheckGeometry.cpp
Ladislav Michl d95b56137b Base: Implement TimeElapsed
Some instances of TimeInfo serve the sole purpose of measuring time
duration. Using system time is unfortunate as it returns wall clock,
which is not guaranteed to be monotonic. Replace such a usage with
the new TimeElapsed class based on steady clock.
2024-03-05 12:29:24 +01:00

1426 lines
56 KiB
C++

/***************************************************************************
* Copyright (c) 2012 Thomas Anderson <blobfish[at]gmx.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QCheckBox>
# include <QCoreApplication>
# include <QHeaderView>
# include <QPushButton>
# include <QScrollBar>
# include <QTextEdit>
# include <QTextStream>
# include <QThread>
# include <QTreeView>
# include <Standard_Version.hxx>
# include <Bnd_Box.hxx>
# include <BOPAlgo_ArgumentAnalyzer.hxx>
# include <BOPAlgo_ListOfCheckResult.hxx>
# include <BRepBndLib.hxx>
# include <BRepBuilderAPI_Copy.hxx>
# include <BRepCheck_Analyzer.hxx>
# include <BRepCheck_ListIteratorOfListOfStatus.hxx>
# include <BRepCheck_Result.hxx>
# include <BRepTools_ShapeSet.hxx>
# include <ShapeAnalysis_FreeBounds.hxx>
# include <TopoDS.hxx>
# include <TopoDS_Compound.hxx>
# include <TopTools_IndexedMapOfShape.hxx>
# include <TopExp.hxx>
# include <TopExp_Explorer.hxx>
# include <Inventor/nodes/SoCube.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <Inventor/nodes/SoMaterial.h>
# include <Inventor/nodes/SoResetTransform.h>
# include <Inventor/nodes/SoSeparator.h>
# include <Inventor/nodes/SoSwitch.h>
# include <Inventor/nodes/SoTransform.h>
#endif //_PreComp_
#include <Base/Interpreter.h>
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
#include <Gui/Document.h>
#include <Gui/MainWindow.h>
#include <Gui/Selection.h>
#include <Gui/ViewProvider.h>
#include <Gui/WaitCursor.h>
#include <Mod/Part/App/PartFeature.h>
#include "TaskCheckGeometry.h"
using namespace PartGui;
QVector<QString> buildShapeEnumVector()
{
QVector<QString>names;
names.push_back(QObject::tr("Compound")); //TopAbs_COMPOUND
names.push_back(QObject::tr("Compound Solid")); //TopAbs_COMPSOLID
names.push_back(QObject::tr("Solid")); //TopAbs_SOLID
names.push_back(QObject::tr("Shell")); //TopAbs_SHELL
names.push_back(QObject::tr("Face")); //TopAbs_FACE
names.push_back(QObject::tr("Wire")); //TopAbs_WIRE
names.push_back(QObject::tr("Edge")); //TopAbs_EDGE
names.push_back(QObject::tr("Vertex")); //TopAbs_VERTEX
names.push_back(QObject::tr("Shape")); //TopAbs_SHAPE
return names;
}
QString shapeEnumToString(const int &index)
{
static QVector<QString> names = buildShapeEnumVector();
if (index < 0 || index > TopAbs_SHAPE)
return names.at(8);
return names.at(index);
}
QVector<QString> buildCheckStatusStringVector()
{
QVector<QString>names;
names.push_back(QObject::tr("No Error")); // BRepCheck_NoError
names.push_back(QObject::tr("Invalid Point On Curve")); // BRepCheck_InvalidPointOnCurve
names.push_back(QObject::tr("Invalid Point On Curve On Surface")); // BRepCheck_InvalidPointOnCurveOnSurface
names.push_back(QObject::tr("Invalid Point On Surface")); // BRepCheck_InvalidPointOnSurface
names.push_back(QObject::tr("No 3D Curve")); // BRepCheck_No3DCurve
names.push_back(QObject::tr("Multiple 3D Curve")); // BRepCheck_Multiple3DCurve
names.push_back(QObject::tr("Invalid 3D Curve")); // BRepCheck_Invalid3DCurve
names.push_back(QObject::tr("No Curve On Surface")); // BRepCheck_NoCurveOnSurface
names.push_back(QObject::tr("Invalid Curve On Surface")); // BRepCheck_InvalidCurveOnSurface
names.push_back(QObject::tr("Invalid Curve On Closed Surface")); // BRepCheck_InvalidCurveOnClosedSurface
names.push_back(QObject::tr("Invalid Same Range Flag")); // BRepCheck_InvalidSameRangeFlag
names.push_back(QObject::tr("Invalid Same Parameter Flag")); // BRepCheck_InvalidSameParameterFlag
names.push_back(QObject::tr("Invalid Degenerated Flag")); // BRepCheck_InvalidDegeneratedFlag
names.push_back(QObject::tr("Free Edge")); // BRepCheck_FreeEdge
names.push_back(QObject::tr("Invalid MultiConnexity")); // BRepCheck_InvalidMultiConnexity
names.push_back(QObject::tr("Invalid Range")); // BRepCheck_InvalidRange
names.push_back(QObject::tr("Empty Wire")); // BRepCheck_EmptyWire
names.push_back(QObject::tr("Redundant Edge")); // BRepCheck_RedundantEdge
names.push_back(QObject::tr("Self Intersecting Wire")); // BRepCheck_SelfIntersectingWire
names.push_back(QObject::tr("No Surface")); // BRepCheck_NoSurface
names.push_back(QObject::tr("Invalid Wire")); // BRepCheck_InvalidWire
names.push_back(QObject::tr("Redundant Wire")); // BRepCheck_RedundantWire
names.push_back(QObject::tr("Intersecting Wires")); // BRepCheck_IntersectingWires
names.push_back(QObject::tr("Invalid Imbrication Of Wires")); // BRepCheck_InvalidImbricationOfWires
names.push_back(QObject::tr("Empty Shell")); // BRepCheck_EmptyShell
names.push_back(QObject::tr("Redundant Face")); // BRepCheck_RedundantFace
names.push_back(QObject::tr("Unorientable Shape")); // BRepCheck_UnorientableShape
names.push_back(QObject::tr("Not Closed")); // BRepCheck_NotClosed
names.push_back(QObject::tr("Not Connected")); // BRepCheck_NotConnected
names.push_back(QObject::tr("Sub Shape Not In Shape")); // BRepCheck_SubshapeNotInShape
names.push_back(QObject::tr("Bad Orientation")); // BRepCheck_BadOrientation
names.push_back(QObject::tr("Bad Orientation Of Sub Shape")); // BRepCheck_BadOrientationOfSubshape
names.push_back(QObject::tr("Invalid Tolerance Value")); // BRepCheck_InvalidToleranceValue
names.push_back(QObject::tr("Check Failed")); // BRepCheck_CheckFail
return names;
}
QString checkStatusToString(const int &index)
{
static QVector<QString> names = buildCheckStatusStringVector();
if (index == -1)
{
return QString(QObject::tr("No Result"));
}
if (index > 33 || index < 0)
{
QString message(QObject::tr("Out Of Enum Range:") + QStringLiteral(" "));
QString number;
number.setNum(index);
message += number;
return message;
}
return names.at(index);
}
QVector<QString> buildBOPCheckResultVector()
{
QVector<QString> results;
results.push_back(QObject::tr("Boolean operation: Unknown check")); //BOPAlgo_CheckUnknown
results.push_back(QObject::tr("Boolean operation: Bad type")); //BOPAlgo_BadType
results.push_back(QObject::tr("Boolean operation: Self-intersection found")); //BOPAlgo_SelfIntersect
results.push_back(QObject::tr("Boolean operation: Edge too small")); //BOPAlgo_TooSmallEdge
results.push_back(QObject::tr("Boolean operation: Non-recoverable face")); //BOPAlgo_NonRecoverableFace
results.push_back(QObject::tr("Boolean operation: Incompatibility of vertex")); //BOPAlgo_IncompatibilityOfVertex
results.push_back(QObject::tr("Boolean operation: Incompatibility of edge")); //BOPAlgo_IncompatibilityOfEdge
results.push_back(QObject::tr("Boolean operation: Incompatibility of face")); //BOPAlgo_IncompatibilityOfFace
results.push_back(QObject::tr("Boolean operation: Aborted")); //BOPAlgo_OperationAborted
results.push_back(QObject::tr("Boolean operation: GeomAbs_C0")); //BOPAlgo_GeomAbs_C0
results.push_back(QObject::tr("Boolean operation: Invalid curve on surface")); //BOPAlgo_InvalidCurveOnSurface
results.push_back(QObject::tr("Boolean operation: Not valid")); //BOPAlgo_NotValid
return results;
}
QString getBOPCheckString(const BOPAlgo_CheckStatus &status)
{
static QVector<QString> strings = buildBOPCheckResultVector();
int index = static_cast<int>(status);
if (index < 0 || index > strings.size())
index = 0;
return strings.at(index);
}
ResultEntry::ResultEntry()
{
viewProviderRoot = nullptr;
boxSep = nullptr;
boxSwitch = nullptr;
parent = nullptr;
children.clear();
selectionStrings.clear();
}
ResultEntry::~ResultEntry()
{
if (boxSep && viewProviderRoot)
viewProviderRoot->removeChild(boxSep);
if (viewProviderRoot)
viewProviderRoot->unref();
qDeleteAll(children);
}
void ResultEntry::buildEntryName()
{
ResultEntry* parentEntry = this;
while (parentEntry->parent) {
ResultEntry* temp = parentEntry->parent;
if (!temp->parent)
break;
parentEntry = parentEntry->parent;
}
QString stringOut;
QTextStream stream(&stringOut);
TopTools_IndexedMapOfShape shapeMap;
int index(-1);
switch (this->shape.ShapeType())
{
case TopAbs_COMPOUND:
TopExp::MapShapes(parentEntry->shape, TopAbs_COMPOUND, shapeMap);
stream << "Compound";
break;
case TopAbs_COMPSOLID:
TopExp::MapShapes(parentEntry->shape, TopAbs_COMPSOLID, shapeMap);
stream << "CompSolid";
break;
case TopAbs_SOLID:
TopExp::MapShapes(parentEntry->shape, TopAbs_SOLID, shapeMap);
stream << "Solid";
break;
case TopAbs_SHELL:
TopExp::MapShapes(parentEntry->shape, TopAbs_SHELL, shapeMap);
stream << "Shell";
break;
case TopAbs_WIRE:
TopExp::MapShapes(parentEntry->shape, TopAbs_WIRE, shapeMap);
stream << "Wire";
break;
case TopAbs_FACE:
TopExp::MapShapes(parentEntry->shape, TopAbs_FACE, shapeMap);
stream << "Face";
break;
case TopAbs_EDGE:
TopExp::MapShapes(parentEntry->shape, TopAbs_EDGE, shapeMap);
stream << "Edge";
break;
case TopAbs_VERTEX:
TopExp::MapShapes(parentEntry->shape, TopAbs_VERTEX, shapeMap);
stream << "Vertex";
break;
default:
stream << "Unexpected shape type";
break;
}
index = shapeMap.FindIndex(this->shape);
stream << index;
this->name = stringOut;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
ResultModel::ResultModel(QObject *parent) : QAbstractItemModel(parent)
{
root = nullptr;
}
ResultModel::~ResultModel()
{
if (root)
delete root;
}
QModelIndex ResultModel::index(int row, int column, const QModelIndex &parent) const
{
if (!root)
return {};
ResultEntry *parentNode = nodeFromIndex(parent);
if (!parentNode)
return {};
return createIndex(row, column, parentNode->children.at(row));
}
QModelIndex ResultModel::parent(const QModelIndex &child) const
{
ResultEntry *childNode = nodeFromIndex(child);
if (!childNode)
return {};
ResultEntry *parentNode = childNode->parent;
if (!parentNode)
return {};
ResultEntry *grandParentNode = parentNode->parent;
if (!grandParentNode)
return {};
int row = grandParentNode->children.indexOf(parentNode);
return createIndex(row, 0, parentNode);
}
int ResultModel::rowCount(const QModelIndex &parent) const
{
ResultEntry *parentNode = nodeFromIndex(parent);
if (!parentNode)
return 0;
return parentNode->children.size();
}
int ResultModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 3;
}
QVariant ResultModel::data(const QModelIndex &index, int role) const
{
if (role != Qt::DisplayRole)
return {};
ResultEntry *node = nodeFromIndex(index);
if (!node)
return {};
switch (index.column())
{
case 0:
return QVariant(node->name);
case 1:
return QVariant(node->type);
case 2:
return QVariant(node->error);
}
return {};
}
QVariant ResultModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
return {};
switch (section)
{
case 0:
return QVariant(QString(tr("Name")));
case 1:
return QVariant(QString(tr("Type")));
case 2:
return QVariant(QString(tr("Error")));
}
return {};
}
void ResultModel::setResults(ResultEntry *resultsIn)
{
this->beginResetModel();
if (root)
delete root;
root = resultsIn;
this->endResetModel();
}
ResultEntry* ResultModel::getEntry(const QModelIndex &index)
{
return nodeFromIndex(index);
}
ResultEntry* ResultModel::nodeFromIndex(const QModelIndex &index) const
{
if (index.isValid())
return static_cast<ResultEntry *>(index.internalPointer());
else
return root;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
TaskCheckGeometryResults::TaskCheckGeometryResults(QWidget *parent) : QWidget(parent)
{
this->setWindowTitle(tr("Check Geometry Results"));
setupInterface();
setupFunctionMap();
}
TaskCheckGeometryResults::~TaskCheckGeometryResults()
{
try {
Gui::Selection().clearSelection();
}
catch (const Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
void TaskCheckGeometryResults::setupInterface()
{
message = new QLabel(this);
message->setText(tr("Check is running..."));
model = new ResultModel(this);
treeView = new QTreeView(this);
treeView->setModel(model);
treeView->setSelectionMode(QAbstractItemView::SingleSelection);
treeView->setSelectionBehavior(QAbstractItemView::SelectRows);
connect(treeView->selectionModel(), &QItemSelectionModel::currentRowChanged,
this, &TaskCheckGeometryResults::currentRowChanged);
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(message);
layout->addWidget(treeView);
this->setLayout(layout);
}
void TaskCheckGeometryResults::goCheck()
{
Gui::WaitCursor wc;
auto selection = Gui::Selection().getSelection();
int selectedCount(0), checkedCount(0), invalidShapes(0);
ResultEntry *theRoot = new ResultEntry();
std::string scopeName {tr("Boolean operation check...").toStdString()};
#if OCC_VERSION_HEX < 0x070500
Handle(Message_ProgressIndicator) theProgress = new BOPProgressIndicator(tr("Check geometry"),
Gui::getMainWindow());
theProgress->NewScope(scopeName.c_str());
theProgress->Show();
#else
Handle(Message_ProgressIndicator) theProgress = new BOPProgressIndicator(tr("Check geometry"),
Gui::getMainWindow());
Message_ProgressRange theRange(theProgress->Start());
Message_ProgressScope theScope(theRange,
TCollection_AsciiString(scopeName.c_str()),
selection.size());
theScope.Show();
#endif // 0x070500
for(const auto &sel : selection) {
selectedCount++;
TopoDS_Shape shape = Part::Feature::getShape(sel.pObject,sel.SubName,true);
if (shape.IsNull())
continue;
currentSeparator = Gui::Application::Instance->getViewProvider(sel.pObject)->getRoot();
if (!currentSeparator)
continue;
QString baseName;
QTextStream baseStream(&baseName);
baseStream << sel.DocName;
baseStream << "." << sel.FeatName;
checkedCount++;
checkedMap.Clear();
buildShapeContent(sel.pObject, baseName, shape);
BRepCheck_Analyzer shapeCheck(shape);
if (!shapeCheck.IsValid())
{
invalidShapes++;
ResultEntry *entry = new ResultEntry();
entry->parent = theRoot;
entry->shape = shape;
entry->name = baseName;
entry->type = shapeEnumToString(shape.ShapeType());
entry->error = tr("Invalid");
entry->viewProviderRoot = currentSeparator;
entry->viewProviderRoot->ref();
goSetupResultBoundingBox(entry);
theRoot->children.push_back(entry);
recursiveCheck(shapeCheck, shape, entry);
continue; //don't run BOPAlgo_ArgumentAnalyzer if BRepCheck_Analyzer finds something.
}
else
{
//BOPAlgo_ArgumentAnalyzer can be really slow!
//so only run it when the shape seems valid to BRepCheck_Analyzer And
//when the option is set.
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
bool runSignal = group->GetBool("RunBOPCheck", false);
group->SetBool("RunBOPCheck", runSignal);
if (runSignal) {
std::string label = tr("Checking").toStdString() + " ";
label += sel.pObject->Label.getStrValue();
label += "...";
#if OCC_VERSION_HEX < 0x070500
theProgress->NewScope(label.c_str());
invalidShapes += goBOPSingleCheck(shape, theRoot, baseName, theProgress);
theProgress->EndScope();
if (theProgress->UserBreak())
break;
#else
Message_ProgressScope theInnerScope(theScope.Next(), TCollection_AsciiString(label.c_str()), 1);
theInnerScope.Show();
invalidShapes += goBOPSingleCheck(shape, theRoot, baseName, theInnerScope);
theInnerScope.Close();
if (theScope.UserBreak())
break;
#endif
}
}
}
model->setResults(theRoot);
treeView->expandAll();
treeView->header()->resizeSections(QHeaderView::ResizeToContents);
QString aMessage {tr("%1 processed out of %2 selected").arg(checkedCount).arg(selectedCount)};
aMessage += QLatin1String("\n ") + tr("%n invalid shapes.", "", invalidShapes);
message->setText(aMessage);
}
void TaskCheckGeometryResults::recursiveCheck(const BRepCheck_Analyzer &shapeCheck, const TopoDS_Shape &shape,
ResultEntry *parent)
{
ResultEntry *branchNode = parent;
BRepCheck_ListIteratorOfListOfStatus listIt;
if (!shapeCheck.Result(shape).IsNull() && !checkedMap.Contains(shape))
{
listIt.Initialize(shapeCheck.Result(shape)->Status());
if (listIt.Value() != BRepCheck_NoError)
{
ResultEntry *entry = new ResultEntry();
entry->parent = parent;
entry->shape = shape;
entry->buildEntryName();
entry->type = shapeEnumToString(shape.ShapeType());
entry->error = checkStatusToString(listIt.Value());
entry->viewProviderRoot = currentSeparator;
entry->viewProviderRoot->ref();
dispatchError(entry, listIt.Value());
parent->children.push_back(entry);
branchNode = entry;
}
}
checkedMap.Add(shape);
if (shape.ShapeType() == TopAbs_SOLID)
checkSub(shapeCheck, shape, TopAbs_SHELL, branchNode);
if (shape.ShapeType() == TopAbs_EDGE)
checkSub(shapeCheck, shape, TopAbs_VERTEX, branchNode);
if (shape.ShapeType() == TopAbs_FACE)
{
checkSub(shapeCheck, shape, TopAbs_WIRE, branchNode);
checkSub(shapeCheck, shape, TopAbs_EDGE, branchNode);
checkSub(shapeCheck, shape, TopAbs_VERTEX, branchNode);
}
for (TopoDS_Iterator it(shape); it.More(); it.Next())
recursiveCheck(shapeCheck, it.Value(), branchNode);
}
void TaskCheckGeometryResults::checkSub(const BRepCheck_Analyzer &shapeCheck, const TopoDS_Shape &shape,
const TopAbs_ShapeEnum subType, ResultEntry *parent)
{
BRepCheck_ListIteratorOfListOfStatus itl;
TopExp_Explorer exp;
for (exp.Init(shape,subType); exp.More(); exp.Next())
{
const Handle(BRepCheck_Result)& res = shapeCheck.Result(exp.Current());
const TopoDS_Shape& sub = exp.Current();
for (res->InitContextIterator(); res->MoreShapeInContext(); res->NextShapeInContext())
{
if (res->ContextualShape().IsSame(shape))
{
for (itl.Initialize(res->StatusOnShape()); itl.More(); itl.Next())
{
if (itl.Value() == BRepCheck_NoError)
break;
checkedMap.Add(sub);
ResultEntry *entry = new ResultEntry();
entry->parent = parent;
entry->shape = sub;
entry->buildEntryName();
entry->type = shapeEnumToString(sub.ShapeType());
entry->error = checkStatusToString(itl.Value());
entry->viewProviderRoot = currentSeparator;
entry->viewProviderRoot->ref();
dispatchError(entry, itl.Value());
parent->children.push_back(entry);
}
}
}
}
}
void TaskCheckGeometryResults::buildShapeContent(App::DocumentObject *pObject, const QString &baseName, const TopoDS_Shape &shape)
{
bool advancedShapeContent = App::GetApplication().GetUserParameter().GetGroup("BaseApp")->GetGroup("Preferences")->
GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry")->GetBool("AdvancedShapeContent", true);
int decimals = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Units")->GetInt("Decimals", 2);
std::ostringstream stream;
if (!shapeContentString.empty())
stream << std::endl << std::endl;
stream << tr("Checked object").toStdString() << ": ";
Base::PyGILStateLocker lock;
try {
PyObject* module = PyImport_ImportModule("BasicShapes.ShapeContent");
if (!module) {
throw Py::Exception();
}
Py::Tuple args(3);
args.setItem(0, Py::asObject(pObject->getPyObject()));
args.setItem(1, Py::Long(decimals));
args.setItem(2, Py::Boolean(advancedShapeContent));
Py::Module shapecontent(module, true);
Py::String result(shapecontent.callMemberFunction("buildShapeContent", args));
stream << result.as_std_string("utf-8");
}
catch (Py::Exception&) {
Base::PyException e;
e.ReportException();
stream << baseName.toLatin1().data() << std::endl;
BRepTools_ShapeSet set;
set.Add(shape);
set.DumpExtent(stream);
}
shapeContentString += stream.str();
}
QString TaskCheckGeometryResults::getShapeContentString()
{
return QString::fromStdString(shapeContentString);
}
#if OCC_VERSION_HEX < 0x070500
int TaskCheckGeometryResults::goBOPSingleCheck(const TopoDS_Shape& shapeIn, ResultEntry *theRoot, const QString &baseName,
const Handle(Message_ProgressIndicator)& theProgress)
#else
int TaskCheckGeometryResults::goBOPSingleCheck(const TopoDS_Shape& shapeIn, ResultEntry *theRoot, const QString &baseName,
const Message_ProgressScope& theScope)
#endif
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
bool runSingleThreaded = group->GetBool("RunBOPCheckSingleThreaded", false);
bool logErrors = group->GetBool("LogErrors", true);
bool argumentTypeMode = group->GetBool("ArgumentTypeMode", true);
bool selfInterMode = group->GetBool("SelfInterMode", true);
bool smallEdgeMode = group->GetBool("SmallEdgeMode", true);
bool rebuildFaceMode = group->GetBool("RebuildFaceMode", true);
bool continuityMode = group->GetBool("ContinuityMode", true);
bool tangentMode = group->GetBool("TangentMode", true);
bool mergeVertexMode = group->GetBool("MergeVertexMode", true);
bool mergeEdgeMode = group->GetBool("MergeEdgeMode", true);
bool curveOnSurfaceMode = group->GetBool("CurveOnSurfaceMode", true);
//Reference use: src/BOPTest/BOPTest_CheckCommands.cxx
//I don't why we need to make a copy, but it doesn't work without it.
//BRepAlgoAPI_Check also makes a copy of the shape.
//didn't use BRepAlgoAPI_Check because it calls BRepCheck_Analyzer itself and
//doesn't give us access to it. so I didn't want to run BRepCheck_Analyzer twice to get invalid results.
//BOPAlgo_ArgumentAnalyzer can check 2 objects with respect to a boolean op.
//this is left for another time.
TopoDS_Shape BOPCopy = BRepBuilderAPI_Copy(shapeIn).Shape();
BOPAlgo_ArgumentAnalyzer BOPCheck;
#if OCC_VERSION_HEX < 0x070500
BOPCheck.SetProgressIndicator(theProgress);
#elif OCC_VERSION_HEX < 0x070600
BOPCheck.SetProgressIndicator(theScope);
#else
Q_UNUSED(theScope)
#endif // 0x070500
BOPCheck.SetShape1(BOPCopy);
//all settings are false by default. so only turn on what we want.
BOPCheck.ArgumentTypeMode() = argumentTypeMode;
BOPCheck.SelfInterMode() = selfInterMode;
BOPCheck.SmallEdgeMode() = smallEdgeMode;
BOPCheck.RebuildFaceMode() = rebuildFaceMode;
BOPCheck.ContinuityMode() = continuityMode;
BOPCheck.SetParallelMode(!runSingleThreaded); //this doesn't help for speed right now(occt 6.9.1).
BOPCheck.SetRunParallel(!runSingleThreaded); //performance boost, use all available cores
BOPCheck.TangentMode() = tangentMode; //these 4 new tests add about 5% processing time.
BOPCheck.MergeVertexMode() = mergeVertexMode;
BOPCheck.MergeEdgeMode() = mergeEdgeMode;
BOPCheck.CurveOnSurfaceMode() = curveOnSurfaceMode;
#ifdef FC_DEBUG
Base::TimeElapsed start_time;
#endif
BOPCheck.Perform();
#ifdef FC_DEBUG
float bopAlgoTime = Base::TimeElapsed::diffTimeF(start_time, Base::TimeElapsed());
std::cout << std::endl << "BopAlgo check time is: " << bopAlgoTime << std::endl << std::endl;
#endif
if (!BOPCheck.HasFaulty())
return 0;
ResultEntry *entry = new ResultEntry();
entry->parent = theRoot;
entry->shape = BOPCopy; //this will cause a problem, with existing entry. i.e. entry is true.
entry->name = baseName;
entry->type = shapeEnumToString(shapeIn.ShapeType());
entry->error = QObject::tr("Invalid");
entry->viewProviderRoot = currentSeparator;
entry->viewProviderRoot->ref();
goSetupResultBoundingBox(entry);
theRoot->children.push_back(entry);
const BOPAlgo_ListOfCheckResult &BOPResults = BOPCheck.GetCheckResult();
BOPAlgo_ListIteratorOfListOfCheckResult BOPResultsIt(BOPResults);
for (; BOPResultsIt.More(); BOPResultsIt.Next())
{
const BOPAlgo_CheckResult &current = BOPResultsIt.Value();
const TopTools_ListOfShape &faultyShapes1 = current.GetFaultyShapes1();
TopTools_ListIteratorOfListOfShape faultyShapes1It(faultyShapes1);
for (;faultyShapes1It.More(); faultyShapes1It.Next())
{
const TopoDS_Shape &faultyShape = faultyShapes1It.Value();
ResultEntry *faultyEntry = new ResultEntry();
faultyEntry->parent = entry;
faultyEntry->shape = faultyShape;
faultyEntry->buildEntryName();
faultyEntry->type = shapeEnumToString(faultyShape.ShapeType());
faultyEntry->error = getBOPCheckString(current.GetCheckStatus());
faultyEntry->viewProviderRoot = currentSeparator;
entry->viewProviderRoot->ref();
goSetupResultBoundingBox(faultyEntry);
if (faultyShape.ShapeType() == TopAbs_FACE)
{
goSetupResultTypedSelection(faultyEntry, faultyShape, TopAbs_FACE);
}
else if (faultyShape.ShapeType() == TopAbs_EDGE)
{
goSetupResultTypedSelection(faultyEntry, faultyShape, TopAbs_EDGE);
}
else if (faultyShape.ShapeType() == TopAbs_VERTEX)
{
goSetupResultTypedSelection(faultyEntry, faultyShape, TopAbs_VERTEX);
}
entry->children.push_back(faultyEntry);
/*log BOPCheck errors to report view*/
if (logErrors){
std::clog << faultyEntry->parent->name.toStdString().c_str() << " : "
<< faultyEntry->name.toStdString().c_str() << " : "
<< faultyEntry->type.toStdString().c_str() << " : "
<< faultyEntry->error.toStdString().c_str()
<< std::endl;
}
}
}
return 1;
}
void TaskCheckGeometryResults::dispatchError(ResultEntry *entry, const BRepCheck_Status &stat)
{
std::vector<FunctionMapType>::iterator mapIt;
for (mapIt = functionMap.begin(); mapIt != functionMap.end(); ++mapIt)
{
if (std::get<0>(*mapIt) == entry->shape.ShapeType() && std::get<1>(*mapIt) == stat)
{
(std::get<2>(*mapIt))(entry);
return;
}
}
goSetupResultBoundingBox(entry);
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
bool logErrors = group->GetBool("LogErrors", true); //log errors to report view
/*log BRepCheck errors to report view*/
if (logErrors){
std::clog << entry->parent->name.toStdString().c_str() << " : "
<< entry->name.toStdString().c_str() << " : "
<< entry->type.toStdString().c_str() << " : "
<< entry->error.toStdString().c_str() << " (BRepCheck)"
<< std::endl;
}
}
void TaskCheckGeometryResults::setupFunctionMap()
{
functionMap.emplace_back(TopAbs_SHELL, BRepCheck_NotClosed, goSetupResultShellNotClosed);
functionMap.emplace_back(TopAbs_WIRE, BRepCheck_NotClosed, goSetupResultWireNotClosed);
functionMap.emplace_back(TopAbs_VERTEX, BRepCheck_InvalidPointOnCurve, goSetupResultInvalidPointCurve);
functionMap.emplace_back(TopAbs_FACE, BRepCheck_IntersectingWires, goSetupResultIntersectingWires);
functionMap.emplace_back(TopAbs_EDGE, BRepCheck_InvalidCurveOnSurface, goSetupResultInvalidCurveSurface);
functionMap.emplace_back(TopAbs_EDGE, BRepCheck_InvalidSameParameterFlag, goSetupResultInvalidSameParameterFlag);
functionMap.emplace_back(TopAbs_FACE, BRepCheck_UnorientableShape, goSetupResultUnorientableShapeFace);
}
void TaskCheckGeometryResults::currentRowChanged (const QModelIndex &current, const QModelIndex &previous)
{
Gui::Selection().clearSelection();
if (previous.isValid())
{
ResultEntry *entry = model->getEntry(previous);
if (entry)
{
if (entry->boxSwitch)
entry->boxSwitch->whichChild.setValue(SO_SWITCH_NONE);
}
}
if (current.isValid())
{
ResultEntry *entry = model->getEntry(current);
if (entry)
{
if (entry->boxSwitch)
entry->boxSwitch->whichChild.setValue(0);
QStringList::Iterator stringIt;
for (stringIt = entry->selectionStrings.begin(); stringIt != entry->selectionStrings.end(); ++stringIt)
{
//need unique delimiter.
QString doc, object, sub;
if (!this->split((*stringIt), doc, object, sub))
continue;
Gui::Selection().addSelection(doc.toLatin1(), object.toLatin1(), sub.toLatin1());
}
}
}
}
bool TaskCheckGeometryResults::split(QString &input, QString &doc, QString &object, QString &sub)
{
QStringList strings = input.split(QString::fromLatin1("."));
if (strings.size() != 3)
return false;
doc = strings.at(0);
object = strings.at(1);
sub = strings.at(2);
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////
QString PartGui::buildSelectionName(const ResultEntry *entry, const TopoDS_Shape &shape)
{
const ResultEntry *parentEntry = entry;
while(parentEntry->parent)
{
ResultEntry *temp = parentEntry->parent;
if (!temp->parent)
break;
parentEntry = parentEntry->parent;
}
QString stringOut;
QTextStream stream(&stringOut);
stream << parentEntry->name;
stream << '.';
TopTools_IndexedMapOfShape shapeMap;
int index(-1);
switch (shape.ShapeType())
{
case TopAbs_FACE:
TopExp::MapShapes(parentEntry->shape, TopAbs_FACE, shapeMap);
stream << "Face";
break;
case TopAbs_EDGE:
TopExp::MapShapes(parentEntry->shape, TopAbs_EDGE, shapeMap);
stream << "Edge";
break;
case TopAbs_VERTEX:
TopExp::MapShapes(parentEntry->shape, TopAbs_VERTEX, shapeMap);
stream << "Vertex";
break;
default:
stream << "Unexpected shape type";
break;
}
index = shapeMap.FindIndex(shape);
stream << index;
return stringOut;
}
void PartGui::goSetupResultTypedSelection(ResultEntry* entry, const TopoDS_Shape& shape, TopAbs_ShapeEnum type)
{
TopExp_Explorer it;
for (it.Init(shape, type); it.More(); it.Next())
{
QString name = buildSelectionName(entry, (it.Current()));
if (!name.isEmpty())
entry->selectionStrings.append(name);
}
}
void PartGui::goSetupResultBoundingBox(ResultEntry *entry)
{
//empty compound throws bounding box error. Mantis #0001426
try
{
Bnd_Box boundingBox;
BRepBndLib::Add(entry->shape, boundingBox);
Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
boundingBox.Get(xmin, ymin, zmin, xmax, ymax, zmax);
SbVec3f boundCenter((xmax - xmin)/2 + xmin, (ymax - ymin)/2 + ymin, (zmax - zmin)/2 + zmin);
entry->boxSep = new SoSeparator();
entry->viewProviderRoot->addChild(entry->boxSep);
entry->boxSwitch = new SoSwitch();
entry->boxSep->addChild(entry->boxSwitch);
SoGroup *group = new SoGroup();
entry->boxSwitch->addChild(group);
entry->boxSwitch->whichChild.setValue(SO_SWITCH_NONE);
SoDrawStyle *dStyle = new SoDrawStyle();
dStyle->style.setValue(SoDrawStyle::LINES);
dStyle->linePattern.setValue(0xc0c0);
group->addChild(dStyle);
SoMaterial *material = new SoMaterial();
material->diffuseColor.setValue(255.0, 255.0, 255.0);
material->ambientColor.setValue(255.0, 255.0, 255.0);
group->addChild(material);
SoResetTransform *reset = new SoResetTransform();
group->addChild(reset);
SoTransform *position = new SoTransform();
position->translation.setValue(boundCenter);
group->addChild(position);
SoCube *cube = new SoCube();
cube->width.setValue(xmax - xmin);
cube->height.setValue(ymax - ymin);
cube->depth.setValue(zmax - zmin);
group->addChild(cube);
}
catch (const Standard_Failure &){}
}
void PartGui::goSetupResultShellNotClosed(ResultEntry *entry)
{
ShapeAnalysis_FreeBounds shellCheck(entry->shape);
TopoDS_Compound closedWires = shellCheck.GetClosedWires();
TopoDS_Compound openWires = shellCheck.GetOpenWires();
goSetupResultTypedSelection(entry, closedWires, TopAbs_EDGE);
goSetupResultTypedSelection(entry, openWires, TopAbs_EDGE);
goSetupResultBoundingBox(entry);
}
void PartGui::goSetupResultWireNotClosed(ResultEntry *entry)
{
goSetupResultTypedSelection(entry, entry->shape, TopAbs_EDGE);
goSetupResultBoundingBox(entry);
}
void PartGui::goSetupResultInvalidPointCurve(ResultEntry *entry)
{
goSetupResultTypedSelection(entry, entry->shape, TopAbs_VERTEX);
goSetupResultBoundingBox(entry);
}
void PartGui::goSetupResultIntersectingWires(ResultEntry *entry)
{
goSetupResultTypedSelection(entry, entry->shape, TopAbs_FACE);
goSetupResultBoundingBox(entry);
}
void PartGui::goSetupResultInvalidCurveSurface(ResultEntry *entry)
{
goSetupResultTypedSelection(entry, entry->shape, TopAbs_EDGE);
goSetupResultBoundingBox(entry);
}
void PartGui::goSetupResultInvalidSameParameterFlag(ResultEntry *entry)
{
goSetupResultTypedSelection(entry, entry->shape, TopAbs_EDGE);
goSetupResultBoundingBox(entry);
}
void PartGui::goSetupResultUnorientableShapeFace(ResultEntry *entry)
{
goSetupResultTypedSelection(entry, entry->shape, TopAbs_FACE);
goSetupResultBoundingBox(entry);
}
////////////////////////////////////////////////////////////////////////////////////////////////
TaskCheckGeometryDialog::TaskCheckGeometryDialog()
: widget(nullptr), contentLabel(nullptr), okBtn(nullptr), settingsBtn(nullptr), resultsBtn(nullptr)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
bool expandShapeContent = group->GetBool("ExpandShapeContent", false);
this->setButtonPosition(TaskDialog::South);
widget = new TaskCheckGeometryResults();
taskbox = new Gui::TaskView::TaskBox(
Gui::BitmapFactory().pixmap("Part_CheckGeometry"),
widget->windowTitle(), true, nullptr);
taskbox->groupLayout()->addWidget(widget);
Content.push_back(taskbox);
contentLabel = new QTextEdit();
contentLabel->setText(widget->getShapeContentString());
shapeContentBox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("Part_CheckGeometry"),
tr("Shape Content"), true, nullptr);
shapeContentBox->groupLayout()->addWidget(contentLabel);
if (!expandShapeContent){
shapeContentBox->hideGroupBox();
}
Content.push_back(shapeContentBox);
settingsBox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("Part_CheckGeometry"),
tr("Settings"), true, nullptr);
Content.push_back(settingsBox);
autoRunCheckBox = new QCheckBox();
autoRunCheckBox->setText(tr("Skip settings page"));
autoRunCheckBox->setToolTip(
tr("Skip this settings page and run the geometry check automatically.")
+ QStringLiteral("\n")
+ tr("Default: false"));
autoRunCheckBox->setChecked(group->GetBool("AutoRun", false));
connect(autoRunCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onAutoRunCheckBoxToggled);
settingsBox->groupLayout()->addWidget(autoRunCheckBox);
runBOPCheckBox = new QCheckBox();
runBOPCheckBox->setText(tr("Run boolean operation check"));
runBOPCheckBox->setToolTip(tr(
"Extra boolean operations check that can sometimes find errors that\n"
"the standard BRep geometry check misses. These errors do not always\n"
"mean the checked object is unusable. Default: false"));
runBOPCheckBox->setChecked(group->GetBool("RunBOPCheck", false));
connect(runBOPCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onRunBOPCheckBoxToggled);
settingsBox->groupLayout()->addWidget(runBOPCheckBox);
runSingleThreadedCheckBox = new QCheckBox();
runSingleThreadedCheckBox->setText(tr("Single-threaded"));
runSingleThreadedCheckBox->setToolTip(tr(
"Run the geometry check in a single thread. This is slower,\n"
"but more stable. Default: false"));
runSingleThreadedCheckBox->setChecked(group->GetBool("RunSingleThreaded", false));
connect(runSingleThreadedCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onRunSingleThreadedCheckBoxToggled);
settingsBox->groupLayout()->addWidget(runSingleThreadedCheckBox);
logErrorsCheckBox = new QCheckBox();
logErrorsCheckBox->setText(tr("Log errors"));
logErrorsCheckBox->setToolTip(tr("Log errors to report view. Default: true"));
logErrorsCheckBox->setChecked(group->GetBool("LogErrors", true));
connect(logErrorsCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onLogErrorsCheckBoxToggled);
settingsBox->groupLayout()->addWidget(logErrorsCheckBox);
expandShapeContentCheckBox = new QCheckBox();
expandShapeContentCheckBox->setText(tr("Expand shape content"));
expandShapeContentCheckBox->setToolTip(tr(
"Expand shape content. Changes will take effect next time you use \n"
"the check geometry tool. Default: false"));
expandShapeContentCheckBox->setChecked(group->GetBool("ExpandShapeContent", false));
connect(expandShapeContentCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onExpandShapeContentCheckBoxToggled);
settingsBox->groupLayout()->addWidget(expandShapeContentCheckBox);
advancedShapeContentCheckBox = new QCheckBox();
advancedShapeContentCheckBox->setText(tr("Advanced shape content"));
advancedShapeContentCheckBox->setToolTip(tr(
"Show advanced shape content. Changes will take effect next time you use \n"
"the check geometry tool. Default: false"));
advancedShapeContentCheckBox->setChecked(group->GetBool("AdvancedShapeContent", true));
connect(advancedShapeContentCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onAdvancedShapeContentCheckBoxToggled);
settingsBox->groupLayout()->addWidget(advancedShapeContentCheckBox);
settingsBox->groupLayout()->addWidget(new QLabel(tr("\nIndividual boolean operation checks:")));
argumentTypeModeCheckBox = new QCheckBox();
argumentTypeModeCheckBox->setText(QStringLiteral(" ") + tr("Bad type"));
argumentTypeModeCheckBox->setToolTip(tr("Check for bad argument types. Default: true"));
argumentTypeModeCheckBox->setChecked(group->GetBool("ArgumentTypeMode", true));
connect(argumentTypeModeCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onArgumentTypeModeCheckBoxToggled);
settingsBox->groupLayout()->addWidget(argumentTypeModeCheckBox);
selfInterModeCheckBox = new QCheckBox();
selfInterModeCheckBox->setText(QStringLiteral(" ") + tr("Self-intersect"));
selfInterModeCheckBox->setToolTip(tr("Check for self-intersections. Default: true"));
selfInterModeCheckBox->setChecked(group->GetBool("SelfInterMode", true));
connect(selfInterModeCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onSelfInterModeCheckBoxToggled);
settingsBox->groupLayout()->addWidget(selfInterModeCheckBox);
smallEdgeModeCheckBox = new QCheckBox();
smallEdgeModeCheckBox->setText(QStringLiteral(" ") + tr("Too small edge"));
smallEdgeModeCheckBox->setToolTip(tr("Check for edges that are too small. Default: true"));
smallEdgeModeCheckBox->setChecked(group->GetBool("SmallEdgeMode", true));
connect(smallEdgeModeCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onSmallEdgeModeCheckBoxToggled);
settingsBox->groupLayout()->addWidget(smallEdgeModeCheckBox);
rebuildFaceModeCheckBox = new QCheckBox();
rebuildFaceModeCheckBox->setText(QStringLiteral(" ") + tr("Nonrecoverable face"));
rebuildFaceModeCheckBox->setToolTip(tr("Check for nonrecoverable faces. Default: true"));
rebuildFaceModeCheckBox->setChecked(group->GetBool("RebuildFaceMode", true));
connect(rebuildFaceModeCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onRebuildFaceModeCheckBoxToggled);
settingsBox->groupLayout()->addWidget(rebuildFaceModeCheckBox);
continuityModeCheckBox = new QCheckBox();
continuityModeCheckBox->setText(QStringLiteral(" ") + tr("Continuity"));
continuityModeCheckBox->setToolTip(tr("Check for continuity. Default: true"));
continuityModeCheckBox->setChecked(group->GetBool("ContinuityMode", true));
connect(continuityModeCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onContinuityModeCheckBoxToggled);
settingsBox->groupLayout()->addWidget(continuityModeCheckBox);
tangentModeCheckBox = new QCheckBox();
tangentModeCheckBox->setText(QStringLiteral(" ") + tr("Incompatibility of face"));
tangentModeCheckBox->setToolTip(tr("Check for incompatible faces. Default: true"));
tangentModeCheckBox->setChecked(group->GetBool("TangentMode", true));
connect(tangentModeCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onTangentModeCheckBoxToggled);
settingsBox->groupLayout()->addWidget(tangentModeCheckBox);
mergeVertexModeCheckBox = new QCheckBox();
mergeVertexModeCheckBox->setText(QStringLiteral(" ") + tr("Incompatibility of vertex"));
mergeVertexModeCheckBox->setToolTip(tr("Check for incompatible vertices. Default: true"));
mergeVertexModeCheckBox->setChecked(group->GetBool("MergeVertexMode", true));
connect(mergeVertexModeCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onMergeVertexModeCheckBoxToggled);
settingsBox->groupLayout()->addWidget(mergeVertexModeCheckBox);
mergeEdgeModeCheckBox = new QCheckBox();
mergeEdgeModeCheckBox->setText(QStringLiteral(" ") + tr("Incompatibility of edge"));
mergeEdgeModeCheckBox->setToolTip(tr("Check for incompatible edges. Default: true"));
mergeEdgeModeCheckBox->setChecked(group->GetBool("MergeEdgeMode", true));
connect(mergeEdgeModeCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onMergeEdgeModeCheckBoxToggled);
settingsBox->groupLayout()->addWidget(mergeEdgeModeCheckBox);
curveOnSurfaceModeCheckBox = new QCheckBox();
curveOnSurfaceModeCheckBox->setText(QStringLiteral(" ") + tr("Invalid curve on surface"));
curveOnSurfaceModeCheckBox->setToolTip(tr("Check for invalid curves on surfaces. Default: true"));
curveOnSurfaceModeCheckBox->setChecked(group->GetBool("CurveOnSurfaceMode", true));
connect(curveOnSurfaceModeCheckBox, &QCheckBox::toggled,
this, &TaskCheckGeometryDialog::onCurveOnSurfaceModeCheckBoxToggled);
settingsBox->groupLayout()->addWidget(curveOnSurfaceModeCheckBox);
if (group->GetBool("AutoRun",false)){
settingsBox->hide();
widget->goCheck();
contentLabel->setText(widget->getShapeContentString());
} else {
taskbox->hide();
shapeContentBox->hide();
}
}
bool TaskCheckGeometryDialog::accept()
{
settingsBtn->setEnabled(true);
settingsBox->hide();
shapeContentBox->show();
taskbox->show();
widget->goCheck();
QScrollBar *v = contentLabel->verticalScrollBar();
v->setValue(v->maximum()); //scroll to bottom
int curval = v->value(); //save position
contentLabel->setText(widget->getShapeContentString());
v->setValue(curval+(v->maximum()-curval)/5);
return false;
}
bool TaskCheckGeometryDialog::reject()
{
return true;
}
void TaskCheckGeometryDialog::onClicked(QAbstractButton *btn)
{
/** when ok (run check) is clicked or when close is clicked
* the appropriate accept() or reject() is called already
* all we need to do here is enable / disable / show / hide
* ui elements
*/
if(btn == okBtn){
settingsBtn->setEnabled(true);
} else if (btn == settingsBtn){
settingsBtn->setEnabled(false);
taskbox->hide();
shapeContentBox->hide();
settingsBox->show();
resultsBtn->setEnabled(true);
} else if (btn == resultsBtn){
settingsBtn->setEnabled(true);
taskbox->show();
shapeContentBox->show();
settingsBox->hide();
resultsBtn->setEnabled(false);
}
}
void TaskCheckGeometryDialog::modifyStandardButtons(QDialogButtonBox* box)
{
okBtn = box->button(QDialogButtonBox::Ok);
okBtn->setText(tr("Run check"));
settingsBtn = box->addButton(tr("Settings"),QDialogButtonBox::ActionRole);
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
if(!group->GetBool("AutoRun",false))
settingsBtn->setEnabled(false);
resultsBtn = box->addButton(tr("Results"),QDialogButtonBox::ActionRole);
resultsBtn->setEnabled(false);
connect(box, &QDialogButtonBox::clicked, this, &TaskCheckGeometryDialog::onClicked);
}
void TaskCheckGeometryDialog::onAutoRunCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("AutoRun", isOn);
}
void TaskCheckGeometryDialog::onRunBOPCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("RunBOPCheck", isOn);
}
void TaskCheckGeometryDialog::onRunSingleThreadedCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("RunSingleThreaded", isOn);
}
void TaskCheckGeometryDialog::onLogErrorsCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("LogErrors", isOn);
}
void TaskCheckGeometryDialog::onArgumentTypeModeCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("ArgumentTypeMode", isOn);
}
void TaskCheckGeometryDialog::onExpandShapeContentCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("ExpandShapeContent", isOn);
}
void TaskCheckGeometryDialog::onAdvancedShapeContentCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("AdvancedShapeContent", isOn);
}
void TaskCheckGeometryDialog::onSelfInterModeCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("SelfInterMode", isOn);
}
void TaskCheckGeometryDialog::onSmallEdgeModeCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("SmallEdgeMode", isOn);
}
void TaskCheckGeometryDialog::onRebuildFaceModeCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("RebuildFaceMode", isOn);
}
void TaskCheckGeometryDialog::onContinuityModeCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("ContinuityMode", isOn);
}
void TaskCheckGeometryDialog::onTangentModeCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("TangentMode", isOn);
}
void TaskCheckGeometryDialog::onMergeVertexModeCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("MergeVertexMode", isOn);
}
void TaskCheckGeometryDialog::onMergeEdgeModeCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("MergeEdgeMode", isOn);
}
void TaskCheckGeometryDialog::onCurveOnSurfaceModeCheckBoxToggled(bool isOn)
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod")->GetGroup("Part")->GetGroup("CheckGeometry");
group->SetBool("CurveOnSurfaceMode", isOn);
}
TaskCheckGeometryDialog::~TaskCheckGeometryDialog()
{
if (widget)
{
delete widget;
widget = nullptr;
}
if (contentLabel)
{
delete contentLabel;
contentLabel = nullptr;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
BOPProgressIndicator::BOPProgressIndicator (const QString& title, QWidget* parent)
{
steps = 0;
canceled = false;
myProgress = new QProgressDialog(parent);
myProgress->setWindowTitle(title);
myProgress->setAttribute(Qt::WA_DeleteOnClose);
}
BOPProgressIndicator::~BOPProgressIndicator ()
{
myProgress->close();
}
#if OCC_VERSION_HEX < 0x070500
Standard_Boolean BOPProgressIndicator::Show (const Standard_Boolean theForce)
{
if (theForce) {
steps = 0;
canceled = false;
time.start();
myProgress->show();
myProgress->setRange(0, 0);
myProgress->setValue(0);
}
else {
Handle(TCollection_HAsciiString) aName = GetScope(1).GetName(); //current step
if (!aName.IsNull())
myProgress->setLabelText (QString::fromUtf8(aName->ToCString()));
}
return Standard_True;
}
#else
void BOPProgressIndicator::Show (const Message_ProgressScope& theScope,
const Standard_Boolean isForce)
{
Standard_CString aName = theScope.Name(); //current step
myProgress->setLabelText (QString::fromUtf8(aName));
if (isForce) {
myProgress->show();
}
QCoreApplication::processEvents();
}
void BOPProgressIndicator::Reset()
{
steps = 0;
canceled = false;
time.start();
myProgress->setRange(0, 0);
myProgress->setValue(0);
}
#endif
Standard_Boolean BOPProgressIndicator::UserBreak()
{
QThread *currentThread = QThread::currentThread();
if (currentThread == myProgress->thread()) {
// this is needed to check the status outside BOPAlgo_ArgumentAnalyzer
//
// Hint: We must make sure to do this only when calling from the GUI
// thread because when calling it from a worker thread the thrown
// exception isn't handled anywhere and thus std::terminate is called
if (canceled)
return Standard_True;
// it suffices to update only every second
// to avoid to unnecessarily process events
steps++;
myProgress->setValue(steps);
if (time.elapsed() > 1000) {
time.restart();
QCoreApplication::processEvents();
canceled = myProgress->wasCanceled();
return canceled;
}
}
return Standard_False;
}
#include "moc_TaskCheckGeometry.cpp"