Adaptive tolerance boolean ops

This commit is contained in:
Thomas Krijnen
2017-02-16 15:54:34 +01:00
parent e2cf5f4826
commit 8ce4bbdf61
3 changed files with 133 additions and 70 deletions
+9
View File
@@ -44,6 +44,7 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO
#include <gp_Pln.hxx>
#include <TColgp_SequenceOfPnt.hxx>
#include <TopTools_ListOfShape.hxx>
#include <BOPAlgo_Operation.hxx>
#include "../ifcparse/IfcParse.h"
#include "../ifcparse/IfcUtil.h"
@@ -181,6 +182,14 @@ public:
bool split_solid_by_surface(const TopoDS_Shape&, const Handle_Geom_Surface&, TopoDS_Shape&, TopoDS_Shape&);
bool split_solid_by_shell(const TopoDS_Shape&, const TopoDS_Shape& s, TopoDS_Shape&, TopoDS_Shape&);
#if OCC_VERSION_HEX < 0x60900
bool boolean_operation(const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&);
bool boolean_operation(const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&);
#else
bool boolean_operation(const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
bool boolean_operation(const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
#endif
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&);
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&);
const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&);
+108
View File
@@ -86,6 +86,7 @@
#include <BRepAlgoAPI_Cut.hxx>
#include <BRepAlgoAPI_Fuse.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include <BRepAlgoAPI_BooleanOperation.hxx>
#include <BRepAlgo_NormalProjection.hxx>
@@ -95,6 +96,7 @@
#include <ShapeAnalysis_Curve.hxx>
#include <ShapeAnalysis_Surface.hxx>
#include <ShapeAnalysis_ShapeTolerance.hxx>
#include <BRepFilletAPI_MakeFillet2d.hxx>
@@ -2413,3 +2415,109 @@ TopoDS_Shape IfcGeom::Kernel::apply_transformation(const TopoDS_Shape& s, const
}
}
#if OCC_VERSION_HEX < 0x60900
bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopTools_ListOfShape& b, BOPAlgo_Operation op, TopoDS_Shape& result) {
result = a;
TopTools_ListIteratorOfListOfShape it(b);
for (; it.More(); it.Next()) {
TopoDS_Shape r;
if (!boolean_operation(result, it.Value(), op, r)) {
return false;
}
result = r;
}
return true;
}
bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopoDS_Shape& b, BOPAlgo_Operation op, TopoDS_Shape& result) {
bool succesful = true;
BRepAlgoAPI_BooleanOperation* builder;
if (op == BOPAlgo_CUT) {
builder = new BRepAlgoAPI_Cut(a, b);
} else if (op == BOPAlgo_COMMON) {
builder = new BRepAlgoAPI_Common(a, b);
} else if (op == BOPAlgo_FUSE) {
builder = new BRepAlgoAPI_Fuse(a, b);
} else {
return false;
}
if (builder->IsDone()) {
TopoDS_Shape r = *builder;
succesful = BRepCheck_Analyzer(r).IsValid() != 0;
if (succesful) {
result = r;
ShapeFix_Shape fix(result);
try {
fix.Perform();
result = fix.Shape();
} catch (...) {
Logger::Message(Logger::LOG_WARNING, "Shape healing failed on boolean result");
}
} else {
// Increase tolerance max 3 times until succesful
TopoDS_Shape a2 = a;
TopoDS_Shape b2 = b;
ShapeAnalysis_ShapeTolerance tolerance;
const double t1 = tolerance.Tolerance(a, 1) * 10.;
const double t2 = tolerance.Tolerance(b, 1) * 10.;
if (((std::max)(t1, t2) + 1e-15) > getValue(GV_PRECISION) * 1000.) {
return false;
}
apply_tolerance(a2, t1);
apply_tolerance(b2, t2);
succesful = boolean_operation(a2, b2, op, result);
}
}
delete builder;
return succesful;
}
#else
bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopTools_ListOfShape& b, BOPAlgo_Operation op, TopoDS_Shape& result, double fuzziness) {
bool success = false;
BRepAlgoAPI_BooleanOperation* builder;
if (op == BOPAlgo_CUT) {
builder = new BRepAlgoAPI_Cut();
} else if (op == BOPAlgo_COMMON) {
builder = new BRepAlgoAPI_Common();
} else if (op == BOPAlgo_FUSE) {
builder = new BRepAlgoAPI_Fuse();
} else {
return false;
}
if (fuzziness < 0.) {
fuzziness = getValue(GV_PRECISION);
}
TopTools_ListOfShape s1s;
s1s.Append(a);
builder->SetFuzzyValue(fuzziness);
builder->SetArguments(s1s);
builder->SetTools(b);
builder->Build();
if (builder->IsDone()) {
TopoDS_Shape r = *builder;
success = BRepCheck_Analyzer(r).IsValid() != 0;
if (success) {
result = r;
ShapeFix_Shape fix(result);
try {
fix.Perform();
result = fix.Shape();
} catch (...) {
Logger::Message(Logger::LOG_WARNING, "Shape healing failed on boolean result");
}
}
}
delete builder;
if (!success) {
return boolean_operation(a, b, op, result, fuzziness * 10.);
}
return success;
}
bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopoDS_Shape& b, BOPAlgo_Operation op, TopoDS_Shape& result, double fuzziness) {
TopTools_ListOfShape bs;
bs.Append(b);
return boolean_operation(a, bs, op, result, fuzziness);
}
#endif
+16 -70
View File
@@ -538,43 +538,22 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
return true;
*/
BOPAlgo_Operation occ_op;
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
occ_op = BOPAlgo_CUT;
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
occ_op = BOPAlgo_COMMON;
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) {
occ_op = BOPAlgo_FUSE;
} else {
return false;
}
bool valid_cut = false;
bool valid_result = boolean_operation(s1, s2, occ_op, shape);
#if OCC_VERSION_HEX < 0x60900
BRepAlgoAPI_Cut brep_cut(s1, s2);
#else
BRepAlgoAPI_Cut brep_cut;
TopTools_ListOfShape s1s;
s1s.Append(s1);
TopTools_ListOfShape s2s;
s2s.Append(s2);
brep_cut.SetFuzzyValue(getValue(GV_PRECISION));
brep_cut.SetArguments(s1s);
brep_cut.SetTools(s2s);
brep_cut.Build();
#endif
if ( brep_cut.IsDone() ) {
TopoDS_Shape result = brep_cut;
ShapeFix_Shape fix(result);
try {
fix.Perform();
result = fix.Shape();
} catch (...) {
Logger::Message(Logger::LOG_WARNING, "Shape healing failed on boolean result", l->entity);
}
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
valid_cut = true;
}
}
if ( valid_cut ) {
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
// In case of a subtraction, a check on volume is performed.
if (valid_result) {
const double volume_after_subtraction = shape_volume(shape);
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l->entity);
@@ -582,43 +561,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l->entity);
shape = s1;
}
// NB: After issuing error the first operand is returned!
return true;
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) {
BRepAlgoAPI_Fuse brep_fuse(s1,s2);
if ( brep_fuse.IsDone() ) {
TopoDS_Shape result = brep_fuse;
ShapeFix_Shape fix(result);
fix.Perform();
result = fix.Shape();
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
return true;
}
}
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
BRepAlgoAPI_Common brep_common(s1,s2);
if ( brep_common.IsDone() ) {
TopoDS_Shape result = brep_common;
ShapeFix_Shape fix(result);
fix.Perform();
result = fix.Shape();
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
return true;
}
}
} else {
return valid_result;
}
return false;
}