mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
#2237 workaround for openings on extrusions of compound profiles
This commit is contained in:
@@ -1375,78 +1375,115 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity,
|
||||
std::sort(opening_vector.begin(), opening_vector.end(), opening_sorter());
|
||||
|
||||
// Iterate over the shapes of the IfcProduct
|
||||
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) {
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++it3) {
|
||||
|
||||
bool is_manifold = Kernel::is_manifold(it3->Shape());
|
||||
TopoDS_Compound C;
|
||||
BRep_Builder B;
|
||||
B.MakeCompound(C);
|
||||
TopoDS_Shape combined_result;
|
||||
|
||||
if (!is_manifold) {
|
||||
Logger::Warning("Non-manifold first operand");
|
||||
std::list<TopoDS_Shape> parts;
|
||||
|
||||
bool is_multiple = it3->Shape().ShapeType() == TopAbs_COMPOUND && TopoDS_Iterator(it3->Shape()).More() && util::is_nested_compound_of_solid(it3->Shape());
|
||||
|
||||
if (is_multiple) {
|
||||
TopoDS_Iterator sit(it3->Shape());
|
||||
for (; sit.More(); sit.Next()) {
|
||||
parts.push_back(sit.Value());
|
||||
}
|
||||
} else {
|
||||
parts.push_back(it3->Shape());
|
||||
}
|
||||
|
||||
for (int as_shell = 0; as_shell < 2; ++as_shell) {
|
||||
for (auto& entity_part : parts) {
|
||||
|
||||
TopoDS_Shape entity_shape_solid;
|
||||
TopoDS_Shape entity_shape_unlocated;
|
||||
if (as_shell) {
|
||||
entity_shape_unlocated = it3->Shape();
|
||||
|
||||
bool is_manifold = Kernel::is_manifold(entity_part);
|
||||
|
||||
if (!is_manifold) {
|
||||
Logger::Warning("Non-manifold first operand");
|
||||
}
|
||||
|
||||
TopoDS_Shape entity_part_result;
|
||||
|
||||
for (int as_shell = 0; as_shell < 2; ++as_shell) {
|
||||
|
||||
TopoDS_Shape entity_shape_solid;
|
||||
TopoDS_Shape entity_shape_unlocated;
|
||||
if (as_shell) {
|
||||
entity_shape_unlocated = entity_part;
|
||||
} else {
|
||||
entity_shape_unlocated = ensure_fit_for_subtraction(entity_part, entity_shape_solid);
|
||||
}
|
||||
const gp_GTrsf& entity_shape_gtrsf = it3->Placement();
|
||||
if (entity_shape_gtrsf.Form() == gp_Other) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation to:", entity);
|
||||
}
|
||||
TopoDS_Shape entity_shape = apply_transformation(entity_shape_unlocated, entity_shape_gtrsf);
|
||||
|
||||
TopoDS_Shape result = entity_shape;
|
||||
|
||||
auto it = opening_vector.begin();
|
||||
auto jt = it;
|
||||
|
||||
for (;; ++it) {
|
||||
if (it == opening_vector.end() || jt->first / it->first > 10.) {
|
||||
|
||||
TopTools_ListOfShape opening_list;
|
||||
for (auto kt = jt; kt < it; ++kt) {
|
||||
opening_list.Append(kt->second);
|
||||
}
|
||||
|
||||
TopoDS_Shape intermediate_result;
|
||||
if (boolean_operation(result, opening_list, BOPAlgo_CUT, intermediate_result)) {
|
||||
result = intermediate_result;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Opening subtraction failed for " + boost::lexical_cast<std::string>(std::distance(jt, it)) + " openings", entity);
|
||||
}
|
||||
|
||||
jt = it;
|
||||
}
|
||||
|
||||
if (it == opening_vector.end()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int result_n_faces = count(result, TopAbs_FACE);
|
||||
|
||||
if (!is_manifold && as_shell == 0 && result_n_faces == 0) {
|
||||
// If we have a non-manifold first operand and our first attempt
|
||||
// on a Solid-Solid subtraction yielded a empty result (no faces)
|
||||
// or a strange result, a larger number of faces with the original input
|
||||
// included. Then retry (another iteration on the for-loop on as-shell)
|
||||
// where we keep the first operand as is (a compound of faces probably,
|
||||
// unless --orient-shells was activated in which case we're already lost).
|
||||
if (!is_manifold) {
|
||||
Logger::Warning("Retrying boolean operation on individual faces");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
entity_part_result = result;
|
||||
|
||||
// For manifold first operands we're not even going to try if processing
|
||||
// as loose faces gives a better result.
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_multiple) {
|
||||
B.Add(C, entity_part_result);
|
||||
} else {
|
||||
entity_shape_unlocated = ensure_fit_for_subtraction(it3->Shape(), entity_shape_solid);
|
||||
}
|
||||
const gp_GTrsf& entity_shape_gtrsf = it3->Placement();
|
||||
if (entity_shape_gtrsf.Form() == gp_Other) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation to:", entity);
|
||||
}
|
||||
TopoDS_Shape entity_shape = apply_transformation(entity_shape_unlocated, entity_shape_gtrsf);
|
||||
|
||||
TopoDS_Shape result = entity_shape;
|
||||
|
||||
auto it = opening_vector.begin();
|
||||
auto jt = it;
|
||||
|
||||
for (;; ++it) {
|
||||
if (it == opening_vector.end() || jt->first / it->first > 10.) {
|
||||
|
||||
TopTools_ListOfShape opening_list;
|
||||
for (auto kt = jt; kt < it; ++kt) {
|
||||
opening_list.Append(kt->second);
|
||||
}
|
||||
|
||||
TopoDS_Shape intermediate_result;
|
||||
if (boolean_operation(result, opening_list, BOPAlgo_CUT, intermediate_result)) {
|
||||
result = intermediate_result;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Opening subtraction failed for " + boost::lexical_cast<std::string>(std::distance(jt, it)) + " openings", entity);
|
||||
}
|
||||
|
||||
jt = it;
|
||||
}
|
||||
|
||||
if (it == opening_vector.end()) {
|
||||
break;
|
||||
}
|
||||
combined_result = entity_part_result;
|
||||
}
|
||||
|
||||
int result_n_faces = count(result, TopAbs_FACE);
|
||||
|
||||
if (!is_manifold && as_shell == 0 && result_n_faces == 0) {
|
||||
// If we have a non-manifold first operand and our first attempt
|
||||
// on a Solid-Solid subtraction yielded a empty result (no faces)
|
||||
// or a strange result, a larger number of faces with the original input
|
||||
// included. Then retry (another iteration on the for-loop on as-shell)
|
||||
// where we keep the first operand as is (a compound of faces probably,
|
||||
// unless --orient-shells was activated in which case we're already lost).
|
||||
if (!is_manifold) {
|
||||
Logger::Warning("Retrying boolean operation on individual faces");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(it3->ItemId(), result, it3->StylePtr()));
|
||||
|
||||
// For manifold first operands we're not even going to try if processing
|
||||
// as loose faces gives a better result.
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_multiple) {
|
||||
combined_result = C;
|
||||
}
|
||||
|
||||
cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(it3->ItemId(), combined_result, it3->StylePtr()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -541,24 +541,6 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, Ifc
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool is_nested_compound_of_solid(const TopoDS_Shape& s, int depth=0) {
|
||||
if (s.ShapeType() == TopAbs_COMPOUND) {
|
||||
TopoDS_Iterator it(s);
|
||||
for (; it.More(); it.Next()) {
|
||||
if (!is_nested_compound_of_solid(it.Value(), depth + 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (s.ShapeType() == TopAbs_SOLID) {
|
||||
return depth > 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) {
|
||||
|
||||
TopoDS_Shape s1;
|
||||
@@ -715,7 +697,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
|
||||
|
||||
bool valid_result;
|
||||
|
||||
if (s1.ShapeType() == TopAbs_COMPOUND && TopoDS_Iterator(s1).More() && is_nested_compound_of_solid(s1)) {
|
||||
if (s1.ShapeType() == TopAbs_COMPOUND && TopoDS_Iterator(s1).More() && util::is_nested_compound_of_solid(s1)) {
|
||||
TopoDS_Compound C;
|
||||
BRep_Builder B;
|
||||
B.MakeCompound(C);
|
||||
|
||||
@@ -353,4 +353,20 @@ bool IfcGeom::Kernel::is_manifold(const TopoDS_Shape& a) {
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::util::is_nested_compound_of_solid(const TopoDS_Shape& s, int depth) {
|
||||
if (s.ShapeType() == TopAbs_COMPOUND) {
|
||||
TopoDS_Iterator it(s);
|
||||
for (; it.More(); it.Next()) {
|
||||
if (!is_nested_compound_of_solid(it.Value(), depth + 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (s.ShapeType() == TopAbs_SOLID) {
|
||||
return depth > 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +130,10 @@ namespace IfcGeom {
|
||||
|
||||
KernelFactoryImplementation& kernel_implementations();
|
||||
}
|
||||
|
||||
namespace util {
|
||||
bool is_nested_compound_of_solid(const TopoDS_Shape& s, int depth = 0);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user