diff --git a/src/Mod/Part/App/FeaturePartBoolean.cpp b/src/Mod/Part/App/FeaturePartBoolean.cpp index 1a2608797..2a1781b6c 100644 --- a/src/Mod/Part/App/FeaturePartBoolean.cpp +++ b/src/Mod/Part/App/FeaturePartBoolean.cpp @@ -28,6 +28,9 @@ #endif #include "FeaturePartBoolean.h" +#include "modelRefine.h" +#include +#include using namespace Part; @@ -75,7 +78,7 @@ App::DocumentObjectExecReturn *Boolean::execute(void) if (!mkBool->IsDone()) { return new App::DocumentObjectExecReturn("Boolean operation failed"); } - const TopoDS_Shape& resShape = mkBool->Shape(); + TopoDS_Shape resShape = mkBool->Shape(); if (resShape.IsNull()) { return new App::DocumentObjectExecReturn("Resulting shape is invalid"); } @@ -84,6 +87,17 @@ App::DocumentObjectExecReturn *Boolean::execute(void) history.push_back(buildHistory(*mkBool.get(), TopAbs_FACE, resShape, BaseShape)); history.push_back(buildHistory(*mkBool.get(), TopAbs_FACE, resShape, ToolShape)); + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part/Boolean"); + if (hGrp->GetBool("RefineModel", false)) { + TopoDS_Shape oldShape = resShape; + BRepBuilderAPI_RefineModel mkRefine(oldShape); + resShape = mkRefine.Shape(); + ShapeHistory hist = buildHistory(mkRefine, TopAbs_FACE, resShape, oldShape); + history[0] = joinHistory(history[0], hist); + history[1] = joinHistory(history[1], hist); + } + this->Shape.setValue(resShape); this->History.setValues(history); return App::DocumentObject::StdReturn; diff --git a/src/Mod/Part/App/FeaturePartCommon.cpp b/src/Mod/Part/App/FeaturePartCommon.cpp index 44c93a01c..01ef09e41 100644 --- a/src/Mod/Part/App/FeaturePartCommon.cpp +++ b/src/Mod/Part/App/FeaturePartCommon.cpp @@ -30,7 +30,9 @@ #include "FeaturePartCommon.h" - +#include "modelRefine.h" +#include +#include #include using namespace Part; @@ -84,17 +86,17 @@ App::DocumentObjectExecReturn *MultiCommon::execute(void) if (s.size() >= 2) { try { std::vector history; - TopoDS_Shape res = s.front(); + TopoDS_Shape resShape = s.front(); for (std::vector::iterator it = s.begin()+1; it != s.end(); ++it) { // Let's call algorithm computing a fuse operation: - BRepAlgoAPI_Common mkCommon(res, *it); + BRepAlgoAPI_Common mkCommon(resShape, *it); // Let's check if the fusion has been successful if (!mkCommon.IsDone()) throw Base::Exception("Intersection failed"); - res = mkCommon.Shape(); + resShape = mkCommon.Shape(); - ShapeHistory hist1 = buildHistory(mkCommon, TopAbs_FACE, res, mkCommon.Shape1()); - ShapeHistory hist2 = buildHistory(mkCommon, TopAbs_FACE, res, mkCommon.Shape2()); + ShapeHistory hist1 = buildHistory(mkCommon, TopAbs_FACE, resShape, mkCommon.Shape1()); + ShapeHistory hist2 = buildHistory(mkCommon, TopAbs_FACE, resShape, mkCommon.Shape2()); if (history.empty()) { history.push_back(hist1); history.push_back(hist2); @@ -105,9 +107,21 @@ App::DocumentObjectExecReturn *MultiCommon::execute(void) history.push_back(hist2); } } - if (res.IsNull()) + if (resShape.IsNull()) throw Base::Exception("Resulting shape is invalid"); - this->Shape.setValue(res); + + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part/Boolean"); + if (hGrp->GetBool("RefineModel", false)) { + TopoDS_Shape oldShape = resShape; + BRepBuilderAPI_RefineModel mkRefine(oldShape); + resShape = mkRefine.Shape(); + ShapeHistory hist = buildHistory(mkRefine, TopAbs_FACE, resShape, oldShape); + for (std::vector::iterator jt = history.begin(); jt != history.end(); ++jt) + *jt = joinHistory(*jt, hist); + } + + this->Shape.setValue(resShape); this->History.setValues(history); } catch (Standard_Failure) { diff --git a/src/Mod/Part/App/FeaturePartFuse.cpp b/src/Mod/Part/App/FeaturePartFuse.cpp index 47efb7a44..ba73877ea 100644 --- a/src/Mod/Part/App/FeaturePartFuse.cpp +++ b/src/Mod/Part/App/FeaturePartFuse.cpp @@ -29,7 +29,9 @@ #include "FeaturePartFuse.h" - +#include "modelRefine.h" +#include +#include #include using namespace Part; @@ -83,17 +85,17 @@ App::DocumentObjectExecReturn *MultiFuse::execute(void) if (s.size() >= 2) { try { std::vector history; - TopoDS_Shape res = s.front(); + TopoDS_Shape resShape = s.front(); for (std::vector::iterator it = s.begin()+1; it != s.end(); ++it) { // Let's call algorithm computing a fuse operation: - BRepAlgoAPI_Fuse mkFuse(res, *it); + BRepAlgoAPI_Fuse mkFuse(resShape, *it); // Let's check if the fusion has been successful if (!mkFuse.IsDone()) throw Base::Exception("Fusion failed"); - res = mkFuse.Shape(); + resShape = mkFuse.Shape(); - ShapeHistory hist1 = buildHistory(mkFuse, TopAbs_FACE, res, mkFuse.Shape1()); - ShapeHistory hist2 = buildHistory(mkFuse, TopAbs_FACE, res, mkFuse.Shape2()); + ShapeHistory hist1 = buildHistory(mkFuse, TopAbs_FACE, resShape, mkFuse.Shape1()); + ShapeHistory hist2 = buildHistory(mkFuse, TopAbs_FACE, resShape, mkFuse.Shape2()); if (history.empty()) { history.push_back(hist1); history.push_back(hist2); @@ -104,9 +106,21 @@ App::DocumentObjectExecReturn *MultiFuse::execute(void) history.push_back(hist2); } } - if (res.IsNull()) + if (resShape.IsNull()) throw Base::Exception("Resulting shape is invalid"); - this->Shape.setValue(res); + + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part/Boolean"); + if (hGrp->GetBool("RefineModel", false)) { + TopoDS_Shape oldShape = resShape; + BRepBuilderAPI_RefineModel mkRefine(oldShape); + resShape = mkRefine.Shape(); + ShapeHistory hist = buildHistory(mkRefine, TopAbs_FACE, resShape, oldShape); + for (std::vector::iterator jt = history.begin(); jt != history.end(); ++jt) + *jt = joinHistory(*jt, hist); + } + + this->Shape.setValue(resShape); this->History.setValues(history); } catch (Standard_Failure) { diff --git a/src/Mod/Part/App/modelRefine.cpp b/src/Mod/Part/App/modelRefine.cpp index 1a68b8ffe..516cf0551 100644 --- a/src/Mod/Part/App/modelRefine.cpp +++ b/src/Mod/Part/App/modelRefine.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -547,6 +548,8 @@ bool FaceUniter::process() { if (workShell.IsNull()) return false; + modifiedShapes.clear(); + deletedShapes.clear(); typeObjects.push_back(&getPlaneObject()); typeObjects.push_back(&getCylinderObject()); //add more face types. @@ -583,6 +586,12 @@ bool FaceUniter::process() facesToRemove.reserve(facesToRemove.size() + adjacencySplitter.getGroup(adjacentIndex).size()); FaceVectorType temp = adjacencySplitter.getGroup(adjacentIndex); facesToRemove.insert(facesToRemove.end(), temp.begin(), temp.end()); + // the first shape will be marked as modified, i.e. replaced by newFace, all others are marked as deleted + if (!temp.empty()) + { + modifiedShapes.push_back(std::make_pair(temp.front(), newFace)); + deletedShapes.insert(deletedShapes.end(), temp.begin()+1, temp.end()); + } } } } @@ -632,3 +641,141 @@ bool FaceUniter::process() } return true; } + +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +//TODO: Implement a way to log all modifications + +Part::BRepBuilderAPI_RefineModel::BRepBuilderAPI_RefineModel(const TopoDS_Shape& shape) +{ + myShape = shape; + Build(); +} + +void Part::BRepBuilderAPI_RefineModel::Build() +{ + if (myShape.IsNull()) + Standard_Failure::Raise("Cannot remove splitter from empty shape"); + + if (myShape.ShapeType() == TopAbs_SOLID) { + const TopoDS_Solid &solid = TopoDS::Solid(myShape); + BRepTools_ReShape reshape; + TopExp_Explorer it; + for (it.Init(solid, TopAbs_SHELL); it.More(); it.Next()) { + const TopoDS_Shell ¤tShell = TopoDS::Shell(it.Current()); + ModelRefine::FaceUniter uniter(currentShell); + if (uniter.process()) { + if (uniter.isModified()) { + const TopoDS_Shell &newShell = uniter.getShell(); + reshape.Replace(currentShell, newShell); + LogModifications(uniter); + } + } + else { + Standard_Failure::Raise("Removing splitter failed"); + } + } + myShape = reshape.Apply(solid); + } + else if (myShape.ShapeType() == TopAbs_SHELL) { + const TopoDS_Shell& shell = TopoDS::Shell(myShape); + ModelRefine::FaceUniter uniter(shell); + if (uniter.process()) { + myShape = uniter.getShell(); + LogModifications(uniter); + } + else { + Standard_Failure::Raise("Removing splitter failed"); + } + } + else if (myShape.ShapeType() == TopAbs_COMPOUND) { + BRep_Builder builder; + TopoDS_Compound comp; + builder.MakeCompound(comp); + + TopExp_Explorer xp; + // solids + for (xp.Init(myShape, TopAbs_SOLID); xp.More(); xp.Next()) { + const TopoDS_Solid &solid = TopoDS::Solid(xp.Current()); + BRepTools_ReShape reshape; + TopExp_Explorer it; + for (it.Init(solid, TopAbs_SHELL); it.More(); it.Next()) { + const TopoDS_Shell ¤tShell = TopoDS::Shell(it.Current()); + ModelRefine::FaceUniter uniter(currentShell); + if (uniter.process()) { + if (uniter.isModified()) { + const TopoDS_Shell &newShell = uniter.getShell(); + reshape.Replace(currentShell, newShell); + LogModifications(uniter); + } + } + } + builder.Add(comp, reshape.Apply(solid)); + } + // free shells + for (xp.Init(myShape, TopAbs_SHELL, TopAbs_SOLID); xp.More(); xp.Next()) { + const TopoDS_Shell& shell = TopoDS::Shell(xp.Current()); + ModelRefine::FaceUniter uniter(shell); + if (uniter.process()) { + builder.Add(comp, uniter.getShell()); + LogModifications(uniter); + } + } + // the rest + for (xp.Init(myShape, TopAbs_FACE, TopAbs_SHELL); xp.More(); xp.Next()) { + if (!xp.Current().IsNull()) + builder.Add(comp, xp.Current()); + } + for (xp.Init(myShape, TopAbs_WIRE, TopAbs_FACE); xp.More(); xp.Next()) { + if (!xp.Current().IsNull()) + builder.Add(comp, xp.Current()); + } + for (xp.Init(myShape, TopAbs_EDGE, TopAbs_WIRE); xp.More(); xp.Next()) { + if (!xp.Current().IsNull()) + builder.Add(comp, xp.Current()); + } + for (xp.Init(myShape, TopAbs_VERTEX, TopAbs_EDGE); xp.More(); xp.Next()) { + if (!xp.Current().IsNull()) + builder.Add(comp, xp.Current()); + } + + myShape = comp; + } + + Done(); +} + +void Part::BRepBuilderAPI_RefineModel::LogModifications(const ModelRefine::FaceUniter& uniter) +{ + const std::vector& modShapes = uniter.getModifiedShapes(); + for (std::vector::const_iterator it = modShapes.begin(); it != modShapes.end(); ++it) { + TopTools_ListOfShape list; + list.Append(it->second); + myModified.Bind(it->first, list); + } + const ShapeVectorType& delShapes = uniter.getDeletedShapes(); + for (ShapeVectorType::const_iterator it = delShapes.begin(); it != delShapes.end(); ++it) { + myDeleted.Append(*it); + } +} + +const TopTools_ListOfShape& Part::BRepBuilderAPI_RefineModel::Modified(const TopoDS_Shape& S) +{ + if (myModified.IsBound(S)) + return myModified.Find(S); + else + return myEmptyList; +} + +Standard_Boolean Part::BRepBuilderAPI_RefineModel::IsDeleted(const TopoDS_Shape& S) +{ + TopTools_ListIteratorOfListOfShape it; + for (it.Initialize(myDeleted); it.More(); it.Next()) + { + if (it.Value().IsSame(S)) + return Standard_True; + } + + return Standard_False; +} + diff --git a/src/Mod/Part/App/modelRefine.h b/src/Mod/Part/App/modelRefine.h index ed1267f98..32c897ff7 100644 --- a/src/Mod/Part/App/modelRefine.h +++ b/src/Mod/Part/App/modelRefine.h @@ -36,12 +36,15 @@ #include #include #include +#include namespace ModelRefine { - typedef std::vector FaceVectorType; - typedef std::vector EdgeVectorType; + typedef std::vector FaceVectorType; + typedef std::vector EdgeVectorType; + typedef std::vector ShapeVectorType; + typedef std::pair ShapePairType; void getFaceEdges(const TopoDS_Face &face, EdgeVectorType &edges); void boundaryEdges(const FaceVectorType &faces, EdgeVectorType &edgesOut); @@ -147,10 +150,16 @@ namespace ModelRefine bool process(); const TopoDS_Shell& getShell() const {return workShell;} bool isModified(){return modifiedSignal;} + const std::vector& getModifiedShapes() const + {return modifiedShapes;} + const ShapeVectorType& getDeletedShapes() const + {return deletedShapes;} private: TopoDS_Shell workShell; std::vector typeObjects; + std::vector modifiedShapes; + ShapeVectorType deletedShapes; bool modifiedSignal; }; } @@ -170,5 +179,23 @@ GeomAbs_OffsetSurface, GeomAbs_OtherSurface }; */ +namespace Part { +class BRepBuilderAPI_RefineModel : public BRepBuilderAPI_MakeShape +{ +public: + BRepBuilderAPI_RefineModel(const TopoDS_Shape&); + void Build(); + const TopTools_ListOfShape& Modified(const TopoDS_Shape& S); + Standard_Boolean IsDeleted(const TopoDS_Shape& S); + +private: + void LogModifications(const ModelRefine::FaceUniter& uniter); + +private: + TopTools_DataMapOfShapeListOfShape myModified; + TopTools_ListOfShape myEmptyList; + TopTools_ListOfShape myDeleted; +}; +} #endif // MODELREFINE_H diff --git a/src/Mod/Part/Gui/DlgSettingsGeneral.cpp b/src/Mod/Part/Gui/DlgSettingsGeneral.cpp index 61bce31f2..a9c917a86 100644 --- a/src/Mod/Part/Gui/DlgSettingsGeneral.cpp +++ b/src/Mod/Part/Gui/DlgSettingsGeneral.cpp @@ -69,6 +69,7 @@ void DlgSettingsGeneral::saveSettings() Interface_Static::SetCVal("write.step.unit","MM"); break; } + ui->checkBooleanRefine->onSave(); } void DlgSettingsGeneral::loadSettings() @@ -77,6 +78,7 @@ void DlgSettingsGeneral::loadSettings() .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part"); int unit = hGrp->GetInt("Unit", 0); ui->comboBoxUnits->setCurrentIndex(unit); + ui->checkBooleanRefine->onRestore(); } /** diff --git a/src/Mod/Part/Gui/DlgSettingsGeneral.ui b/src/Mod/Part/Gui/DlgSettingsGeneral.ui index 4bca9519f..4ea3f5222 100644 --- a/src/Mod/Part/Gui/DlgSettingsGeneral.ui +++ b/src/Mod/Part/Gui/DlgSettingsGeneral.ui @@ -1,10 +1,8 @@ - - - - + + PartGui::DlgSettingsGeneral - - + + 0 0 @@ -12,73 +10,54 @@ 333 - + General - - - 9 - - - 6 - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - + + + + Export - - + + 9 - + 6 - - + + - + Millimeter - + Meter - + Inch - - - + + + Units for export of STEP/IGES - + - + Qt::Horizontal - + 40 20 @@ -89,9 +68,50 @@ + + + + Boolean operation + + + + + + Automatically refine model after boolean operation + + + RefineModel + + + Mod/Part/Boolean + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + - + + + Gui::PrefCheckBox + QCheckBox +
Gui/PrefWidgets.h
+
+