Exemple #1
0
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;
}