0000727: Keep faces colors on boolean operations

This commit is contained in:
wmayer 2012-06-04 11:43:20 +02:00
parent b701bfd1e1
commit f8f498a4f9
7 changed files with 302 additions and 64 deletions

View File

@ -28,6 +28,9 @@
#endif
#include "FeaturePartBoolean.h"
#include "modelRefine.h"
#include <App/Application.h>
#include <Base/Parameter.h>
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<ParameterGrp> 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;

View File

@ -30,7 +30,9 @@
#include "FeaturePartCommon.h"
#include "modelRefine.h"
#include <App/Application.h>
#include <Base/Parameter.h>
#include <Base/Exception.h>
using namespace Part;
@ -84,17 +86,17 @@ App::DocumentObjectExecReturn *MultiCommon::execute(void)
if (s.size() >= 2) {
try {
std::vector<ShapeHistory> history;
TopoDS_Shape res = s.front();
TopoDS_Shape resShape = s.front();
for (std::vector<TopoDS_Shape>::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<ParameterGrp> 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<ShapeHistory>::iterator jt = history.begin(); jt != history.end(); ++jt)
*jt = joinHistory(*jt, hist);
}
this->Shape.setValue(resShape);
this->History.setValues(history);
}
catch (Standard_Failure) {

View File

@ -29,7 +29,9 @@
#include "FeaturePartFuse.h"
#include "modelRefine.h"
#include <App/Application.h>
#include <Base/Parameter.h>
#include <Base/Exception.h>
using namespace Part;
@ -83,17 +85,17 @@ App::DocumentObjectExecReturn *MultiFuse::execute(void)
if (s.size() >= 2) {
try {
std::vector<ShapeHistory> history;
TopoDS_Shape res = s.front();
TopoDS_Shape resShape = s.front();
for (std::vector<TopoDS_Shape>::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<ParameterGrp> 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<ShapeHistory>::iterator jt = history.begin(); jt != history.end(); ++jt)
*jt = joinHistory(*jt, hist);
}
this->Shape.setValue(resShape);
this->History.setValues(history);
}
catch (Standard_Failure) {

View File

@ -31,6 +31,7 @@
#include <gp_Pln.hxx>
#include <gp_Cylinder.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
@ -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 &currentShell = 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 &currentShell = 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<ShapePairType>& modShapes = uniter.getModifiedShapes();
for (std::vector<ShapePairType>::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;
}

View File

@ -36,12 +36,15 @@
#include <TopTools_DataMapOfShapeListOfShape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <TopTools_MapOfShape.hxx>
#include <TopTools_ListOfShape.hxx>
namespace ModelRefine
{
typedef std::vector<TopoDS_Face> FaceVectorType;
typedef std::vector<TopoDS_Edge> EdgeVectorType;
typedef std::vector<TopoDS_Face> FaceVectorType;
typedef std::vector<TopoDS_Edge> EdgeVectorType;
typedef std::vector<TopoDS_Shape> ShapeVectorType;
typedef std::pair<TopoDS_Shape, TopoDS_Shape> 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<ShapePairType>& getModifiedShapes() const
{return modifiedShapes;}
const ShapeVectorType& getDeletedShapes() const
{return deletedShapes;}
private:
TopoDS_Shell workShell;
std::vector<FaceTypedBase *> typeObjects;
std::vector<ShapePairType> 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

View File

@ -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();
}
/**

View File

@ -1,10 +1,8 @@
<ui version="4.0" >
<author></author>
<comment></comment>
<exportmacro></exportmacro>
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PartGui::DlgSettingsGeneral</class>
<widget class="QWidget" name="PartGui::DlgSettingsGeneral" >
<property name="geometry" >
<widget class="QWidget" name="PartGui::DlgSettingsGeneral">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
@ -12,73 +10,54 @@
<height>333</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>General</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="1" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" >
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Export</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<layout class="QGridLayout">
<property name="margin">
<number>9</number>
</property>
<property name="spacing" >
<property name="spacing">
<number>6</number>
</property>
<item row="0" column="2" >
<widget class="QComboBox" name="comboBoxUnits" >
<item row="0" column="2">
<widget class="QComboBox" name="comboBoxUnits">
<item>
<property name="text" >
<property name="text">
<string>Millimeter</string>
</property>
</item>
<item>
<property name="text" >
<property name="text">
<string>Meter</string>
</property>
</item>
<item>
<property name="text" >
<property name="text">
<string>Inch</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Units for export of STEP/IGES</string>
</property>
</widget>
</item>
<item row="0" column="1" >
<item row="0" column="1">
<spacer>
<property name="orientation" >
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
@ -89,9 +68,50 @@
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Boolean operation</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="Gui::PrefCheckBox" name="checkBooleanRefine">
<property name="text">
<string>Automatically refine model after boolean operation</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>RefineModel</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Part/Boolean</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<pixmapfunction></pixmapfunction>
<customwidgets>
<customwidget>
<class>Gui::PrefCheckBox</class>
<extends>QCheckBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>