diff --git a/src/Mod/Part/Gui/CMakeLists.txt b/src/Mod/Part/Gui/CMakeLists.txt
index ec068eb957..f6a41f935f 100644
--- a/src/Mod/Part/Gui/CMakeLists.txt
+++ b/src/Mod/Part/Gui/CMakeLists.txt
@@ -42,6 +42,7 @@ set(PartGui_MOC_HDRS
TaskShapeBuilder.h
TaskLoft.h
TaskSweep.h
+ TaskCheckGeometry.h
)
fc_wrap_cpp(PartGui_MOC_SRCS ${PartGui_MOC_HDRS})
SOURCE_GROUP("Moc" FILES ${PartGui_MOC_SRCS})
@@ -160,6 +161,8 @@ SET(PartGui_SRCS
TaskSweep.cpp
TaskSweep.h
TaskSweep.ui
+ TaskCheckGeometry.cpp
+ TaskCheckGeometry.h
)
SET(PartGui_Scripts
diff --git a/src/Mod/Part/Gui/Command.cpp b/src/Mod/Part/Gui/Command.cpp
index edd0c41e60..11164ce67a 100644
--- a/src/Mod/Part/Gui/Command.cpp
+++ b/src/Mod/Part/Gui/Command.cpp
@@ -62,6 +62,7 @@
#include "TaskShapeBuilder.h"
#include "TaskLoft.h"
#include "TaskSweep.h"
+#include "TaskCheckGeometry.h"
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -1199,6 +1200,39 @@ bool CmdPartRuledSurface::isActive(void)
return getActiveGuiDocument();
}
+//===========================================================================
+// Part_CheckGeometry
+//===========================================================================
+
+DEF_STD_CMD_A(CmdCheckGeometry);
+
+CmdCheckGeometry::CmdCheckGeometry()
+ : Command("Part_CheckGeometry")
+{
+ sAppModule = "Part";
+ sGroup = QT_TR_NOOP("Part");
+ sMenuText = QT_TR_NOOP("Check Geometry");
+ sToolTipText = QT_TR_NOOP("Analyzes Geometry For Errors");
+ sWhatsThis = sToolTipText;
+ sStatusTip = sToolTipText;
+ sPixmap = "Part_CheckGeometry";
+}
+
+void CmdCheckGeometry::activated(int iMsg)
+{
+ Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog();
+ if (!dlg)
+ dlg = new PartGui::TaskCheckGeometryDialog();
+ Gui::Control().showDialog(dlg);
+}
+
+bool CmdCheckGeometry::isActive(void)
+{
+ Base::Type partid = Base::Type::fromName("Part::Feature");
+ bool objectsSelected = Gui::Selection().countObjectsOfType(partid) > 0;
+ return (hasActiveDocument() && !Gui::Control().activeDialog() && objectsSelected);
+}
+
void CreatePartCommands(void)
{
@@ -1230,5 +1264,5 @@ void CreatePartCommands(void)
rcCmdMgr.addCommand(new CmdPartBuilder());
rcCmdMgr.addCommand(new CmdPartLoft());
rcCmdMgr.addCommand(new CmdPartSweep());
+ rcCmdMgr.addCommand(new CmdCheckGeometry());
}
-
diff --git a/src/Mod/Part/Gui/Resources/Part.qrc b/src/Mod/Part/Gui/Resources/Part.qrc
index f6fbdf0c33..93c983dc24 100644
--- a/src/Mod/Part/Gui/Resources/Part.qrc
+++ b/src/Mod/Part/Gui/Resources/Part.qrc
@@ -1,48 +1,49 @@
-
-
- icons/PartFeature.svg
- icons/PartFeature.xpm
- icons/PartFeatureImport.xpm
- icons/Part_Booleans.svg
- icons/Part_Box.svg
- icons/Part_Chamfer.svg
- icons/Part_Common.svg
- icons/Part_Cone.svg
- icons/Part_Cut.svg
- icons/Part_CreatePrimitives.png
- icons/Part_CreatePrimitives.svg
- icons/Part_Cylinder.svg
- icons/Part_Extrude.svg
- icons/Part_Fillet.svg
- icons/Part_Fuse.svg
- icons/Part_Import.svg
- icons/Part_Loft.svg
- icons/Part_Mirror.svg
- icons/Part_MirrorPNG.png
- icons/Part_Revolve.svg
- icons/Part_RuledSurface.svg
- icons/Part_Section.svg
- icons/Part_Shapebuilder.png
- icons/Part_ShapeInfo.svg
- icons/Part_Sphere.svg
- icons/Part_Sweep.svg
- icons/Part_Torus.svg
- icons/preferences-part_design.svg
- icons/Tree_Part.svg
- translations/Part_af.qm
- translations/Part_de.qm
- translations/Part_es.qm
- translations/Part_fi.qm
- translations/Part_fr.qm
- translations/Part_hr.qm
- translations/Part_it.qm
- translations/Part_nl.qm
- translations/Part_no.qm
- translations/Part_pl.qm
- translations/Part_pt.qm
- translations/Part_ru.qm
- translations/Part_se.qm
- translations/Part_uk.qm
- translations/Part_zh.qm
-
-
+
+
+ icons/PartFeature.svg
+ icons/PartFeature.xpm
+ icons/PartFeatureImport.xpm
+ icons/Part_Booleans.svg
+ icons/Part_Box.svg
+ icons/Part_Chamfer.svg
+ icons/Part_Common.svg
+ icons/Part_Cone.svg
+ icons/Part_Cut.svg
+ icons/Part_CreatePrimitives.png
+ icons/Part_CreatePrimitives.svg
+ icons/Part_Cylinder.svg
+ icons/Part_Extrude.svg
+ icons/Part_Fillet.svg
+ icons/Part_Fuse.svg
+ icons/Part_Import.svg
+ icons/Part_Loft.svg
+ icons/Part_Mirror.svg
+ icons/Part_MirrorPNG.png
+ icons/Part_Revolve.svg
+ icons/Part_RuledSurface.svg
+ icons/Part_Section.svg
+ icons/Part_Shapebuilder.png
+ icons/Part_ShapeInfo.svg
+ icons/Part_Sphere.svg
+ icons/Part_Sweep.svg
+ icons/Part_Torus.svg
+ icons/preferences-part_design.svg
+ icons/Tree_Part.svg
+ icons/Part_CheckGeometry.svg
+ translations/Part_af.qm
+ translations/Part_de.qm
+ translations/Part_es.qm
+ translations/Part_fi.qm
+ translations/Part_fr.qm
+ translations/Part_hr.qm
+ translations/Part_it.qm
+ translations/Part_nl.qm
+ translations/Part_no.qm
+ translations/Part_pl.qm
+ translations/Part_pt.qm
+ translations/Part_ru.qm
+ translations/Part_se.qm
+ translations/Part_uk.qm
+ translations/Part_zh.qm
+
+
diff --git a/src/Mod/Part/Gui/Resources/icons/Part_CheckGeometry.svg b/src/Mod/Part/Gui/Resources/icons/Part_CheckGeometry.svg
new file mode 100644
index 0000000000..975ce58071
--- /dev/null
+++ b/src/Mod/Part/Gui/Resources/icons/Part_CheckGeometry.svg
@@ -0,0 +1,286 @@
+
+
+
+
diff --git a/src/Mod/Part/Gui/TaskCheckGeometry.cpp b/src/Mod/Part/Gui/TaskCheckGeometry.cpp
new file mode 100644
index 0000000000..f647b3c8b7
--- /dev/null
+++ b/src/Mod/Part/Gui/TaskCheckGeometry.cpp
@@ -0,0 +1,687 @@
+/***************************************************************************
+ * 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
+#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);
+}
+
+ResultEntry::ResultEntry()
+{
+ viewProvider = 0;
+ boxSep = 0;
+ boxSwitch = 0;
+ parent = 0;
+ children.clear();
+ selectionStrings.clear();
+}
+
+ResultEntry::~ResultEntry()
+{
+ if (boxSep)
+ viewProvider->getRoot()->removeChild(boxSep);
+ qDeleteAll(children);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+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)
+{
+ 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(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;
+ getSetupResultBoundingBoxObject().go(entry);
+ theRoot->children.push_back(entry);
+ recursiveCheck(shapeCheck, shape, entry);
+ }
+ }
+ 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->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->type = shapeEnumToString(sub.ShapeType());
+ entry->error = checkStatusToString(itl.Value());
+ entry->viewProvider = currentProvider;
+ dispatchError(entry, itl.Value());
+ parent->children.push_back(entry);
+ }
+ }
+ }
+ }
+}
+
+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>())->go(entry);
+ return;
+ }
+ }
+ getSetupResultBoundingBoxObject().go(entry);
+}
+
+void TaskCheckGeometryResults::setupFunctionMap()
+{
+ functionMap.push_back(FunctionMapType(TopAbs_SHELL, BRepCheck_NotClosed, &getSetupResultShellNotClosedObject()));
+ functionMap.push_back(FunctionMapType(TopAbs_WIRE, BRepCheck_NotClosed, &getSetupResultWireNotClosedObject()));
+ functionMap.push_back(FunctionMapType(TopAbs_VERTEX, BRepCheck_InvalidPointOnCurve, &getSetupResultInvalidPointCurveObject()));
+ functionMap.push_back(FunctionMapType(TopAbs_FACE, BRepCheck_IntersectingWires, &getSetupResultIntersectingWiresObject()));
+ functionMap.push_back(FunctionMapType(TopAbs_EDGE, BRepCheck_InvalidCurveOnSurface, &getSetupResultInvalidCurveSurfaceObject()));
+ functionMap.push_back(FunctionMapType(TopAbs_EDGE, BRepCheck_InvalidSameParameterFlag, &getSetupResultInvalidSameParameterFlagObject()));
+ functionMap.push_back(FunctionMapType(TopAbs_FACE, BRepCheck_UnorientableShape, &getSetupResultUnorientableShapeFaceObject()));
+}
+
+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 SetupResultBase::selectionName(ResultEntry *entry, const TopoDS_Shape &shape)
+{
+ ResultEntry *parentEntry = entry;
+ while(parentEntry->name.isEmpty())
+ 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;
+ }
+
+ index = shapeMap.FindIndex(shape);
+ stream << index;
+ return stringOut;
+}
+
+void SetupResultBase::addTypedSelection(ResultEntry *entry, const TopoDS_Shape &shape, TopAbs_ShapeEnum type)
+{
+ TopExp_Explorer it;
+ for (it.Init(shape, type); it.More(); it.Next())
+ {
+ QString name = selectionName(entry, (it.Current()));
+ if (!name.isEmpty())
+ entry->selectionStrings.append(name);
+ }
+}
+
+void SetupResultBoundingBox::go(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);
+
+ Bnd_Box boundingBox;
+ BRepBndLib::Add(entry->shape, boundingBox);
+ Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
+ boundingBox.Get(xmin, ymin, zmin, xmax, ymax, zmax);
+
+ double xCenter, yCenter, zCenter;
+ xCenter = (xmax - xmin)/2 + xmin;
+ yCenter = (ymax - ymin)/2 + ymin;
+ zCenter = (zmax - zmin)/2 + zmin;
+
+ SbVec3f boundCenter(xCenter, yCenter, zCenter);
+ Standard_Real x, y, z;
+ entry->shape.Location().Transformation().TranslationPart().Coord(x, y, z);
+ boundCenter -= SbVec3f(x, y, z);
+
+ 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);
+}
+
+SetupResultBoundingBox& PartGui::getSetupResultBoundingBoxObject()
+{
+ static SetupResultBoundingBox object;
+ return object;
+}
+
+void SetupResultShellNotClosed::go(ResultEntry *entry)
+{
+ ShapeAnalysis_FreeBounds shellCheck(entry->shape);
+ TopoDS_Compound closedWires = shellCheck.GetClosedWires();
+ TopoDS_Compound openWires = shellCheck.GetOpenWires();
+
+ addTypedSelection(entry, closedWires, TopAbs_EDGE);
+ addTypedSelection(entry, openWires, TopAbs_EDGE);
+}
+
+SetupResultShellNotClosed& PartGui::getSetupResultShellNotClosedObject()
+{
+ static SetupResultShellNotClosed object;
+ return object;
+}
+
+void SetupResultWireNotClosed::go(ResultEntry *entry)
+{
+ addTypedSelection(entry, entry->shape, TopAbs_EDGE);
+}
+
+SetupResultWireNotClosed& PartGui::getSetupResultWireNotClosedObject()
+{
+ static SetupResultWireNotClosed object;
+ return object;
+}
+
+void SetupResultInvalidPointCurve::go(ResultEntry *entry)
+{
+ addTypedSelection(entry, entry->shape, TopAbs_VERTEX);
+}
+
+SetupResultInvalidPointCurve& PartGui::getSetupResultInvalidPointCurveObject()
+{
+ static SetupResultInvalidPointCurve object;
+ return object;
+}
+
+void SetupResultIntersectingWires::go(ResultEntry *entry)
+{
+ addTypedSelection(entry, entry->shape, TopAbs_FACE);
+}
+
+SetupResultIntersectingWires& PartGui::getSetupResultIntersectingWiresObject()
+{
+ static SetupResultIntersectingWires object;
+ return object;
+}
+
+void SetupResultInvalidCurveSurface::go(ResultEntry *entry)
+{
+ addTypedSelection(entry, entry->shape, TopAbs_EDGE);
+}
+
+SetupResultInvalidCurveSurface& PartGui::getSetupResultInvalidCurveSurfaceObject()
+{
+ static SetupResultInvalidCurveSurface object;
+ return object;
+}
+
+void SetupResultInvalidSameParameterFlag::go(ResultEntry *entry)
+{
+ addTypedSelection(entry, entry->shape, TopAbs_EDGE);
+}
+
+SetupResultInvalidSameParameterFlag& PartGui::getSetupResultInvalidSameParameterFlagObject()
+{
+ static SetupResultInvalidSameParameterFlag object;
+ return object;
+}
+
+void SetupResultUnorientableShapeFace::go(ResultEntry *entry)
+{
+ addTypedSelection(entry, entry->shape, TopAbs_FACE);
+ getSetupResultBoundingBoxObject().go(entry);
+}
+
+SetupResultUnorientableShapeFace& PartGui::getSetupResultUnorientableShapeFaceObject()
+{
+ static SetupResultUnorientableShapeFace object;
+ return object;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+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"
diff --git a/src/Mod/Part/Gui/TaskCheckGeometry.h b/src/Mod/Part/Gui/TaskCheckGeometry.h
new file mode 100644
index 0000000000..287300cbe3
--- /dev/null
+++ b/src/Mod/Part/Gui/TaskCheckGeometry.h
@@ -0,0 +1,218 @@
+/***************************************************************************
+ * 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 *
+ * *
+ ***************************************************************************/
+
+#ifndef TASKCHECKGEOMETRY_H
+#define TASKCHECKGEOMETRY_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+class SoSeparator;
+class SoSwitch;
+
+namespace PartGui {
+
+class ResultEntry
+{
+public:
+ ResultEntry();
+ ~ResultEntry();
+
+ TopoDS_Shape shape;//invisible
+ QString name;
+ QString type;
+ QString error;
+ Gui::ViewProvider *viewProvider;
+ SoSeparator *boxSep;
+ SoSwitch *boxSwitch;
+ ResultEntry *parent;
+ QList children;
+ QStringList selectionStrings;
+};
+
+class SetupResultBase
+{
+protected:
+ SetupResultBase(){}
+public:
+ virtual void go(ResultEntry *entry) = 0;
+protected:
+ QString selectionName(ResultEntry *entry, const TopoDS_Shape &shape);
+ void addTypedSelection(ResultEntry *entry, const TopoDS_Shape &shape, TopAbs_ShapeEnum type);
+};
+
+class SetupResultBoundingBox : public SetupResultBase
+{
+private:
+ SetupResultBoundingBox(){}
+public:
+ virtual void go(ResultEntry *entry);
+ friend SetupResultBoundingBox& getSetupResultBoundingBoxObject();
+};
+SetupResultBoundingBox& getSetupResultBoundingBoxObject();
+
+class SetupResultShellNotClosed : public SetupResultBase
+{
+private:
+ SetupResultShellNotClosed(){}
+public:
+ virtual void go(ResultEntry *entry);
+ friend SetupResultShellNotClosed& getSetupResultShellNotClosedObject();
+};
+SetupResultShellNotClosed& getSetupResultShellNotClosedObject();
+
+class SetupResultWireNotClosed : public SetupResultBase
+{
+private:
+ SetupResultWireNotClosed(){}
+public:
+ virtual void go(ResultEntry *entry);
+ friend SetupResultWireNotClosed& getSetupResultWireNotClosedObject();
+};
+SetupResultWireNotClosed& getSetupResultWireNotClosedObject();
+
+class SetupResultInvalidPointCurve : public SetupResultBase
+{
+private:
+ SetupResultInvalidPointCurve(){}
+public:
+ virtual void go(ResultEntry *entry);
+ friend SetupResultInvalidPointCurve& getSetupResultInvalidPointCurveObject();
+};
+SetupResultInvalidPointCurve& getSetupResultInvalidPointCurveObject();
+
+class SetupResultIntersectingWires : public SetupResultBase
+{
+private:
+ SetupResultIntersectingWires(){}
+public:
+ virtual void go(ResultEntry *entry);
+ friend SetupResultIntersectingWires& getSetupResultIntersectingWiresObject();
+};
+SetupResultIntersectingWires& getSetupResultIntersectingWiresObject();
+
+class SetupResultInvalidCurveSurface : public SetupResultBase
+{
+private:
+ SetupResultInvalidCurveSurface(){}
+public:
+ virtual void go(ResultEntry *entry);
+ friend SetupResultInvalidCurveSurface& getSetupResultInvalidCurveSurfaceObject();
+};
+SetupResultInvalidCurveSurface& getSetupResultInvalidCurveSurfaceObject();
+
+class SetupResultInvalidSameParameterFlag : public SetupResultBase
+{
+private:
+ SetupResultInvalidSameParameterFlag(){}
+public:
+ virtual void go(ResultEntry *entry);
+ friend SetupResultInvalidSameParameterFlag& getSetupResultInvalidSameParameterFlagObject();
+};
+SetupResultInvalidSameParameterFlag& getSetupResultInvalidSameParameterFlagObject();
+
+class SetupResultUnorientableShapeFace : public SetupResultBase
+{
+private:
+ SetupResultUnorientableShapeFace(){}
+public:
+ virtual void go(ResultEntry *entry);
+ friend SetupResultUnorientableShapeFace& getSetupResultUnorientableShapeFaceObject();
+};
+SetupResultUnorientableShapeFace& getSetupResultUnorientableShapeFaceObject();
+
+typedef boost::tuple FunctionMapType;
+
+class ResultModel : public QAbstractItemModel
+{
+ Q_OBJECT
+public:
+ ResultModel(QObject *parent = 0);
+ ~ResultModel();
+ QModelIndex index(int row, int column, const QModelIndex &parent) const;
+ QModelIndex parent(const QModelIndex &child) const;
+ virtual int rowCount(const QModelIndex &parent) const;
+ virtual int columnCount(const QModelIndex &parent) const;
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+// virtual Qt::ItemFlags flags (const QModelIndex &index) const;
+
+ void setResults(ResultEntry *resultsIn);
+ ResultEntry* getEntry(const QModelIndex &index);
+private:
+ ResultEntry* nodeFromIndex(const QModelIndex &index) const;
+ ResultEntry *root;
+};
+
+class TaskCheckGeometryResults : public QWidget
+{
+ Q_OBJECT
+public:
+ TaskCheckGeometryResults(QWidget *parent = 0);
+ ~TaskCheckGeometryResults();
+
+private slots:
+ void currentRowChanged (const QModelIndex ¤t, const QModelIndex &previous);
+
+private:
+ void setupInterface();
+ void goCheck();
+ void recursiveCheck(const BRepCheck_Analyzer &shapeCheck, const TopoDS_Shape &shape,
+ ResultEntry *parent);
+ void checkSub(const BRepCheck_Analyzer &shapeCheck, const TopoDS_Shape &shape,
+ const TopAbs_ShapeEnum subType, ResultEntry *parent);
+ void dispatchError(ResultEntry *entry, const BRepCheck_Status &stat);
+ bool split(QString &input, QString &doc, QString &object, QString &sub);
+ void setupFunctionMap();
+ ResultModel *model;
+ QTreeView *treeView;
+ QLabel *message;
+ TopTools_MapOfShape checkedMap;
+ Gui::ViewProvider *currentProvider;
+ std::vector functionMap;
+};
+
+class TaskCheckGeometryDialog : public Gui::TaskView::TaskDialog
+{
+ Q_OBJECT
+public:
+ TaskCheckGeometryDialog();
+ ~TaskCheckGeometryDialog();
+
+ virtual QDialogButtonBox::StandardButtons getStandardButtons() const
+ {return QDialogButtonBox::Close;}
+ virtual bool isAllowedAlterDocument(void) const
+ {return false;}
+ virtual bool needsFullSpace() const {return true;}
+
+private:
+ TaskCheckGeometryResults* widget;
+ Gui::TaskView::TaskBox* taskbox;
+};
+
+}
+
+#endif // TASKCHECKGEOMETRY_H
diff --git a/src/Mod/Part/Gui/Workbench.cpp b/src/Mod/Part/Gui/Workbench.cpp
index d6b6b113a2..ddd441b7d4 100644
--- a/src/Mod/Part/Gui/Workbench.cpp
+++ b/src/Mod/Part/Gui/Workbench.cpp
@@ -69,7 +69,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
*part << "Part_Import" << "Part_Export" << "Separator";
*part << prim << "Part_Primitives" << "Part_Builder" << "Separator"
<< "Part_ShapeFromMesh" << "Part_MakeSolid" << "Part_ReverseShape"
- << "Part_SimpleCopy" << "Part_RefineShape" << "Separator"
+ << "Part_SimpleCopy" << "Part_RefineShape" << "Part_CheckGeometry" << "Separator"
<< "Part_Boolean" << "Part_CrossSections" << "Part_Extrude"
<< "Part_Revolve" << "Part_Mirror" << "Part_Fillet" << "Part_Chamfer"
<< "Part_RuledSurface" << "Part_Loft" << "Part_Sweep";
@@ -94,7 +94,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
Gui::ToolBarItem* boolop = new Gui::ToolBarItem(root);
boolop->setCommand("Boolean");
*boolop << "Part_Boolean" << "Part_Cut" << "Part_Fuse" << "Part_Common"
- << "Part_Section" << "Part_CrossSections";
+ << "Part_CheckGeometry" << "Part_Section" << "Part_CrossSections";
return root;
}