/*************************************************************************** * Copyright (c) 2012 Thomas Anderson * * * * 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" #include #include #include #include #include #if OCC_VERSION_HEX >= 0x060600 #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../App/PartFeature.h" #include #include #include #include #include #include #include "TaskCheckGeometry.h" using namespace PartGui; QVector buildShapeEnumVector() { QVectornames; 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 names = buildShapeEnumVector(); if (index < 0 || index > TopAbs_SHAPE) return names.at(8); return names.at(index); } QVector buildCheckStatusStringVector() { QVectornames; 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 names = buildCheckStatusStringVector(); if (index == -1) { return QString(QObject::tr("No Result")); } if (index > 33 || index < 0) { QString message(QObject::tr("Out Of Enum Range: ")); QString number; number.setNum(index); message += number; return message; } return names.at(index); } QVector buildBOPCheckResultVector() { QVector results; results.push_back(QObject::tr("BOPAlgo CheckUnknown")); //BOPAlgo_CheckUnknown results.push_back(QObject::tr("BOPAlgo BadType")); //BOPAlgo_BadType results.push_back(QObject::tr("BOPAlgo SelfIntersect")); //BOPAlgo_SelfIntersect results.push_back(QObject::tr("BOPAlgo TooSmallEdge")); //BOPAlgo_TooSmallEdge results.push_back(QObject::tr("BOPAlgo NonRecoverableFace")); //BOPAlgo_NonRecoverableFace results.push_back(QObject::tr("BOPAlgo IncompatibilityOfVertex")); //BOPAlgo_IncompatibilityOfVertex results.push_back(QObject::tr("BOPAlgo IncompatibilityOfEdge")); //BOPAlgo_IncompatibilityOfEdge results.push_back(QObject::tr("BOPAlgo IncompatibilityOfFace")); //BOPAlgo_IncompatibilityOfFace results.push_back(QObject::tr("BOPAlgo OperationAborted")); //BOPAlgo_OperationAborted results.push_back(QObject::tr("BOPAlgo GeomAbs_C0")); //BOPAlgo_GeomAbs_C0 results.push_back(QObject::tr("BOPAlgo NotValid")); //BOPAlgo_NotValid return results; } #if OCC_VERSION_HEX >= 0x060600 QString getBOPCheckString(const BOPAlgo_CheckStatus &status) { static QVector strings = buildBOPCheckResultVector(); int index = static_cast(status); if (index < 0 || index > 10) index = 0; return strings.at(index); } #endif ResultEntry::ResultEntry() { viewProvider = 0; boxSep = 0; boxSwitch = 0; parent = 0; children.clear(); selectionStrings.clear(); } ResultEntry::~ResultEntry() { if (boxSep) viewProvider->getRoot()->removeChild(boxSep); qDeleteAll(children); } void ResultEntry::buildEntryName() { ResultEntry *parentEntry = this; while(parentEntry->parent != 0) { ResultEntry *temp = parentEntry->parent; if (temp->parent == 0) 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 = 0; } ResultModel::~ResultModel() { if (root) delete root; } QModelIndex ResultModel::index(int row, int column, const QModelIndex &parent) const { if (!root) return QModelIndex(); ResultEntry *parentNode = nodeFromIndex(parent); if (!parentNode) return QModelIndex(); return createIndex(row, column, parentNode->children.at(row)); } QModelIndex ResultModel::parent(const QModelIndex &child) const { ResultEntry *childNode = nodeFromIndex(child); if (!childNode) return QModelIndex(); ResultEntry *parentNode = childNode->parent; if (!parentNode) return QModelIndex(); ResultEntry *grandParentNode = parentNode->parent; if (!grandParentNode) return QModelIndex(); 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 { return 3; } QVariant ResultModel::data(const QModelIndex &index, int role) const { if (role != Qt::DisplayRole) return QVariant(); ResultEntry *node = nodeFromIndex(index); if (!node) return QVariant(); switch (index.column()) { case 0: return QVariant(node->name); case 1: return QVariant(node->type); case 2: return QVariant(node->error); } return QVariant(); } QVariant ResultModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation != Qt::Horizontal || role != Qt::DisplayRole) return QVariant(); switch (section) { case 0: return QVariant(QString(tr("Name"))); case 1: return QVariant(QString(tr("Type"))); case 2: return QVariant(QString(tr("Error"))); } return QVariant(); } void ResultModel::setResults(ResultEntry *resultsIn) { #if QT_VERSION >= 0x040600 this->beginResetModel(); #endif if (root) delete root; root = resultsIn; #if QT_VERSION >= 0x040600 this->endResetModel(); #else this->reset(); #endif } ResultEntry* ResultModel::getEntry(const QModelIndex &index) { return nodeFromIndex(index); } ResultEntry* ResultModel::nodeFromIndex(const QModelIndex &index) const { if (index.isValid()) return static_cast(index.internalPointer()); else return root; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// TaskCheckGeometryResults::TaskCheckGeometryResults(QWidget *parent) : QWidget(parent) { this->setWindowTitle(tr("Check Geometry")); setupInterface(); setupFunctionMap(); goCheck(); } TaskCheckGeometryResults::~TaskCheckGeometryResults() { Gui::Selection().clearSelection(); } void TaskCheckGeometryResults::setupInterface() { message = new QLabel(this); model = new ResultModel(this); treeView = new QTreeView(this); treeView->setModel(model); treeView->setSelectionMode(QAbstractItemView::SingleSelection); treeView->setSelectionBehavior(QAbstractItemView::SelectRows); connect(treeView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SLOT(currentRowChanged(QModelIndex,QModelIndex))); QVBoxLayout *layout = new QVBoxLayout(); layout->addWidget(message); layout->addWidget(treeView); this->setLayout(layout); } void TaskCheckGeometryResults::goCheck() { Gui::WaitCursor wc; int selectedCount(0), checkedCount(0), invalidShapes(0); std::vector selection = Gui::Selection().getSelection(); std::vector::iterator it; ResultEntry *theRoot = new ResultEntry(); for (it = selection.begin(); it != selection.end(); ++it) { selectedCount++; Part::Feature *feature = dynamic_cast((*it).pObject); if (!feature) continue; currentProvider = Gui::Application::Instance->activeDocument()->getViewProvider(feature); if (!currentProvider) continue; TopoDS_Shape shape = feature->Shape.getValue(); QString baseName; QTextStream baseStream(&baseName); baseStream << (*it).DocName; baseStream << "." << (*it).FeatName; if (strlen((*it).SubName) > 0) { shape = feature->Shape.getShape().getSubShape((*it).SubName); baseStream << "." << (*it).SubName; } if (shape.IsNull()) continue; checkedCount++; checkedMap.Clear(); 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 = QObject::tr("Invalid"); entry->viewProvider = currentProvider; 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 invalidShapes += goBOPSingleCheck(shape, theRoot, baseName); } } model->setResults(theRoot); treeView->expandAll(); treeView->header()->resizeSections(QHeaderView::ResizeToContents); QString aMessage; QTextStream aStream(&aMessage); aStream << checkedCount << " processed out of " << selectedCount << " selected\n"; aStream << invalidShapes << " invalid shapes."; message->setText(aMessage); Gui::Selection().clearSelection(); } 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->viewProvider = currentProvider; 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->viewProvider = currentProvider; dispatchError(entry, itl.Value()); parent->children.push_back(entry); } } } } } int TaskCheckGeometryResults::goBOPSingleCheck(const TopoDS_Shape& shapeIn, ResultEntry *theRoot, const QString &baseName) { //ArgumentAnalyser was moved at version 6.6. no back port for now. #if OCC_VERSION_HEX >= 0x060600 //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 //doesnt 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; BOPCheck.SetShape1(BOPCopy); //all settings are false by default. so only turn on what we want. BOPCheck.ArgumentTypeMode() = true; BOPCheck.SelfInterMode() = true; BOPCheck.SmallEdgeMode() = true; BOPCheck.RebuildFaceMode() = true; BOPCheck.ContinuityMode() = true; BOPCheck.Perform(); 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->viewProvider = currentProvider; 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 ¤t = BOPResultsIt.Value(); const BOPCol_ListOfShape &faultyShapes1 = current.GetFaultyShapes1(); BOPCol_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->viewProvider = currentProvider; 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); } } return 1; #else return 0; #endif } void TaskCheckGeometryResults::dispatchError(ResultEntry *entry, const BRepCheck_Status &stat) { std::vector::iterator mapIt; for (mapIt = functionMap.begin(); mapIt != functionMap.end(); ++mapIt) { if ((*mapIt).get<0>() == entry->shape.ShapeType() && (*mapIt).get<1>() == stat) { ((*mapIt).get<2>())(entry); return; } } goSetupResultBoundingBox(entry); } void TaskCheckGeometryResults::setupFunctionMap() { functionMap.push_back(FunctionMapType(TopAbs_SHELL, BRepCheck_NotClosed, goSetupResultShellNotClosed)); functionMap.push_back(FunctionMapType(TopAbs_WIRE, BRepCheck_NotClosed, goSetupResultWireNotClosed)); functionMap.push_back(FunctionMapType(TopAbs_VERTEX, BRepCheck_InvalidPointOnCurve, goSetupResultInvalidPointCurve)); functionMap.push_back(FunctionMapType(TopAbs_FACE, BRepCheck_IntersectingWires, goSetupResultIntersectingWires)); functionMap.push_back(FunctionMapType(TopAbs_EDGE, BRepCheck_InvalidCurveOnSurface, goSetupResultInvalidCurveSurface)); functionMap.push_back(FunctionMapType(TopAbs_EDGE, BRepCheck_InvalidSameParameterFlag, goSetupResultInvalidSameParameterFlag)); functionMap.push_back(FunctionMapType(TopAbs_FACE, BRepCheck_UnorientableShape, goSetupResultUnorientableShapeFace)); } void TaskCheckGeometryResults::currentRowChanged (const QModelIndex ¤t, 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.toAscii(), object.toAscii(), sub.toAscii()); } } } } bool TaskCheckGeometryResults::split(QString &input, QString &doc, QString &object, QString &sub) { QStringList strings = input.split(QString::fromAscii(".")); 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 != 0) { ResultEntry *temp = parentEntry->parent; if (temp->parent == 0) 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) { entry->boxSep = new SoSeparator(); entry->viewProvider->getRoot()->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); 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); 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); } 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() { this->setButtonPosition(TaskDialog::South); widget = new TaskCheckGeometryResults(); taskbox = new Gui::TaskView::TaskBox( Gui::BitmapFactory().pixmap("Part_CheckGeometry"), widget->windowTitle(), false, 0); taskbox->groupLayout()->addWidget(widget); Content.push_back(taskbox); } TaskCheckGeometryDialog::~TaskCheckGeometryDialog() { } #include "moc_TaskCheckGeometry.cpp"