bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) { TopoDS_Shape s1, s2; IfcRepresentationShapeItems items1, items2; TopoDS_Wire boundary_wire; IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand(); IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand(); bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid); if ( shape_type(operand1) == ST_SHAPELIST ) { if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) { return false; } } else if ( shape_type(operand1) == ST_SHAPE ) { if ( ! convert_shape(operand1, s1) ) { return false; } { TopoDS_Solid temp_solid; s1 = ensure_fit_for_subtraction(s1, temp_solid); } } else { Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand1->entity); return false; } const double first_operand_volume = shape_volume(s1); if ( first_operand_volume <= ALMOST_ZERO ) Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity); bool shape2_processed = false; if ( shape_type(operand2) == ST_SHAPELIST ) { shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true); } else if ( shape_type(operand2) == ST_SHAPE ) { shape2_processed = convert_shape(operand2,s2); if (shape2_processed && !is_halfspace) { TopoDS_Solid temp_solid; s2 = ensure_fit_for_subtraction(s2, temp_solid); } } else { Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand2->entity); } if (!shape2_processed) { shape = s1; Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity); return true; } if (!is_halfspace) { const double second_operand_volume = shape_volume(s2); if ( second_operand_volume <= ALMOST_ZERO ) Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity); } const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator(); if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { bool valid_cut = false; BRepAlgoAPI_Cut brep_cut(s1,s2); 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 ) { 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); } else { Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l->entity); shape = s1; } 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; } } } return false; }
bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes) { // Iterate over IfcOpeningElements IfcGeom::IfcRepresentationShapeItems opening_shapes; unsigned int last_size = 0; for ( Ifc2x3::IfcRelVoidsElement::it it = openings->begin(); it != openings->end(); ++ it ) { Ifc2x3::IfcRelVoidsElement::ptr v = *it; Ifc2x3::IfcFeatureElementSubtraction::ptr fes = v->RelatedOpeningElement(); if ( fes->is(Ifc2x3::Type::IfcOpeningElement) ) { // Convert the IfcRepresentation of the IfcOpeningElement gp_Trsf opening_trsf; IfcGeom::convert(fes->ObjectPlacement(),opening_trsf); // Move the opening into the coordinate system of the IfcProduct opening_trsf.PreMultiply(entity_trsf.Inverted()); Ifc2x3::IfcProductRepresentation::ptr prodrep = fes->Representation(); Ifc2x3::IfcRepresentation::list reps = prodrep->Representations(); for ( Ifc2x3::IfcRepresentation::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) { IfcGeom::convert_shapes(*it2,opening_shapes); } const unsigned int current_size = (const unsigned int) opening_shapes.size(); for ( unsigned int i = last_size; i < current_size; ++ i ) { opening_shapes[i].prepend(opening_trsf); } last_size = current_size; } } // Iterate over the shapes of the IfcProduct for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { TopoDS_Shape entity_shape_solid; const TopoDS_Shape& entity_shape_unlocated = IfcGeom::ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid); const gp_GTrsf& entity_shape_gtrsf = it3->Placement(); TopoDS_Shape entity_shape; if ( entity_shape_gtrsf.Form() == gp_Other ) { Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to:",entity->entity); entity_shape = BRepBuilderAPI_GTransform(entity_shape_unlocated,entity_shape_gtrsf,true).Shape(); } else { entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf()); } // Iterate over the shapes of the IfcOpeningElements for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it4 = opening_shapes.begin(); it4 != opening_shapes.end(); ++ it4 ) { TopoDS_Shape opening_shape_solid; const TopoDS_Shape& opening_shape_unlocated = IfcGeom::ensure_fit_for_subtraction(it4->Shape(),opening_shape_solid); const gp_GTrsf& opening_shape_gtrsf = it4->Placement(); if ( opening_shape_gtrsf.Form() == gp_Other ) { Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to opening of:",entity->entity); } const TopoDS_Shape& opening_shape = opening_shape_gtrsf.Form() == gp_Other ? BRepBuilderAPI_GTransform(opening_shape_unlocated,opening_shape_gtrsf,true).Shape() : opening_shape_unlocated.Moved(opening_shape_gtrsf.Trsf()); double opening_volume, original_shape_volume; if ( Logger::Verbosity() >= Logger::LOG_WARNING ) { opening_volume = shape_volume(opening_shape); if ( opening_volume <= ALMOST_ZERO ) Logger::Message(Logger::LOG_WARNING,"Empty opening for:",entity->entity); original_shape_volume = shape_volume(entity_shape); } BRepAlgoAPI_Cut brep_cut(entity_shape,opening_shape); if ( brep_cut.IsDone() ) { TopoDS_Shape brep_cut_result = brep_cut; BRepCheck_Analyzer analyser(brep_cut_result); bool is_valid = analyser.IsValid() != 0; if ( is_valid ) { entity_shape = brep_cut; if ( Logger::Verbosity() >= Logger::LOG_WARNING ) { const double volume_after_subtraction = shape_volume(entity_shape); if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) ) Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",entity->entity); } } else { Logger::Message(Logger::LOG_ERROR,"Invalid result from subtraction:",entity->entity); } } else { Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",entity->entity); } } cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(entity_shape, &it3->Style())); } return true; }