Esempio n. 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::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) {
	IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
	bool isConic = basis_curve->is(IfcSchema::Type::IfcConic);
	double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
	Handle(Geom_Curve) curve;
	if ( !convert_curve(basis_curve,curve) ) return false;
	bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
	IfcEntityList::ptr trims1 = l->Trim1();
	IfcEntityList::ptr trims2 = l->Trim2();
	bool trimmed1 = false;
	bool trimmed2 = false;
	unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
	double flts[2];
	gp_Pnt pnts[2];
	bool has_flts[2] = {false,false};
	bool has_pnts[2] = {false,false};
	BRepBuilderAPI_MakeWire w;
	for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
		IfcUtil::IfcBaseClass* i = *it;
		if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
			IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] );
			has_pnts[sense_agreement] = true;
		} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
			const double value = *((IfcSchema::IfcParameterValue*)i);
			flts[sense_agreement] = value * parameterFactor;
			has_flts[sense_agreement] = true;
		}
	}
	for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
		IfcUtil::IfcBaseClass* i = *it;
		if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
			IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] );
			has_pnts[1-sense_agreement] = true;
		} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
			const double value = *((IfcSchema::IfcParameterValue*)i);
			flts[1-sense_agreement] = value * parameterFactor;
			has_flts[1-sense_agreement] = true;
		}
	}
	trim_cartesian &= has_pnts[0] && has_pnts[1];
	bool trim_cartesian_failed = !trim_cartesian;
	if ( trim_cartesian ) {
		if ( pnts[0].Distance(pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE) ) {
			Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity);
			return false;
		}
		ShapeFix_ShapeTolerance FTol;
		TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
		TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
		FTol.SetTolerance(v1, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
		FTol.SetTolerance(v2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
		BRepBuilderAPI_MakeEdge e (curve,v1,v2);
		if ( ! e.IsDone() ) {
			BRepBuilderAPI_EdgeError err = e.Error();
			if ( err == BRepBuilderAPI_PointProjectionFailed ) {
				Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l->entity);
				trim_cartesian_failed = true;
			}
		} else {
			w.Add(e.Edge());
		}
	}
	if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
		// The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine
		// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
		// the vector is normalised when passed to Geom_Line constructor the magnitude
		// needs to be factored in with the IfcParameterValue here.
		if ( basis_curve->is(IfcSchema::Type::IfcLine) ) {
			IfcSchema::IfcLine* line = static_cast<IfcSchema::IfcLine*>(basis_curve);
			const double magnitude = line->Dir()->Magnitude();
			flts[0] *= magnitude; flts[1] *= magnitude;
		}
		if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) {
			IfcSchema::IfcEllipse* ellipse = static_cast<IfcSchema::IfcEllipse*>(basis_curve);
			double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT);
			double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT);
			const bool rotated = y > x;
			if (rotated) {
				flts[0] -= M_PI / 2.;
				flts[1] -= M_PI / 2.;
			}
		}
		if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],(double)(M_PI*2.0)),0.0f) ) {
			w.Add(BRepBuilderAPI_MakeEdge(curve));
		} else {
			BRepBuilderAPI_MakeEdge e (curve,flts[0],flts[1]);
			w.Add(e.Edge());
		}			
	} else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) {
		w.Add(BRepBuilderAPI_MakeEdge(pnts[0],pnts[1]));
	}
	if ( w.IsDone() ) {
		wire = w.Wire();
		return true;
	} else {
		return false;
	}
}
Esempio n. 3
0
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Shape& face) {
	const bool doFlangeEdgeFillet = l->hasFlangeEdgeRadius();
	const bool doWebEdgeFillet = l->hasWebEdgeRadius();
	const bool doFillet = l->hasFilletRadius();
	const bool hasFlangeSlope = l->hasFlangeSlope();
	const bool hasWebSlope = l->hasWebSlope();

	const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
	const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
	const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT);
	const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
	const double flangeSlope = hasFlangeSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
	const double webSlope = hasWebSlope ? (l->WebSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;

	if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
		Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
		return false;
	}
	
	double dy1 = 0.0f;
	double dy2 = 0.0f;
	double dx1 = 0.0f;
	double dx2 = 0.0f;
	double f1 = 0.0f;
	double f2 = 0.0f;
	double f3 = 0.0f;

	if (doFillet) {
		f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
	}
	if (doWebEdgeFillet) {
		f2 = l->WebEdgeRadius() * getValue(GV_LENGTH_UNIT);
	}
	if (doFlangeEdgeFillet) {
		f3 = l->FlangeEdgeRadius() * getValue(GV_LENGTH_UNIT);
	}

	double xx, xy;
	if (hasFlangeSlope) {
		dy1 = (x / 2. - d1) * tan(flangeSlope);
		dy2 = x / 2. * tan(flangeSlope);
	}
	if (hasWebSlope) {
		dx1 = (y - d2) * tan(webSlope);
		dx2 = y * tan(webSlope);
	}
	if (hasWebSlope || hasFlangeSlope) {
		const double x1s = d1/2. - dx2; const double y1s = -y;
		const double x1e = d1/2. + dx1; const double y1e = y - d2;
		const double x2s = x; const double y2s = y - d2 + dy2;
		const double x2e = d1/2.; const double y2e = y - d2 - dy1;

		const double a1 = y1e - y1s;
		const double b1 = x1s - x1e;
		const double c1 = a1*x1s + b1*y1s;

		const double a2 = y2e - y2s;
		const double b2 = x2s - x2e;
		const double c2 = a2*x2s + b2*y2s;

		const double det = a1*b2 - a2*b1;

		if (ALMOST_THE_SAME(det, 0.)) {
			Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l->entity);
			return false;
		}

		xx = (b2*c1 - b1*c2) / det;
		xy = (a1*c2 - a2*c1) / det;
	} else {
		xx = d1 / 2;
		xy = y - d2;
	}

	gp_Trsf2d trsf2d;
	bool has_position = true;
#ifdef USE_IFC4
	has_position = l->hasPosition();
#endif
	if (has_position) {
		IfcGeom::Kernel::convert(l->Position(), trsf2d);
	}

	double coords[16] = {d1/2.-dx2,-y, xx,xy, x,y-d2+dy2, x,y, -x,y, -x,y-d2+dy2, -xx,xy, -d1/2.+dx2,-y};
	int fillets[6] = {0,1,2,5,6,7};
	double radii[6] = {f2,f1,f3,f3,f1,f2};
	return profile_helper(8, coords, (doFillet || doWebEdgeFillet || doFlangeEdgeFillet) ? 6 : 0, fillets, radii, trsf2d, face);
}
Esempio n. 4
0
bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Shape& face) {
	const bool hasSlope = l->hasLegSlope();
	const bool doEdgeFillet = l->hasEdgeRadius();
	const bool doFillet = l->hasFilletRadius();

	const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
	const double x = (l->hasWidth() ? l->Width() : l->Depth()) / 2.0f * getValue(GV_LENGTH_UNIT);
	const double d = l->Thickness() * getValue(GV_LENGTH_UNIT);
	const double slope = hasSlope ? (l->LegSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
	
	double f1 = 0.0f;
	double f2 = 0.0f;
	if (doFillet) {
		f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
	}
	if ( doEdgeFillet) {
		f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
	}

	if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d < ALMOST_ZERO ) {
		Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
		return false;
	}

	double xx = -x+d;
	double xy = -y+d;
	double dy1 = 0.;
	double dy2 = 0.;
	double dx1 = 0.;
	double dx2 = 0.;
	if (hasSlope) {
		dy1 = tan(slope) * x;
		dy2 = tan(slope) * (x - d);
		dx1 = tan(slope) * y;
		dx2 = tan(slope) * (y - d);

		const double x1s = x; const double y1s = -y + d - dy1;
		const double x1e = -x + d; const double y1e = -y + d + dy2;
		const double x2s = -x + d - dx1; const double y2s = y;
		const double x2e = -x + d + dx2; const double y2e = -y + d;

		const double a1 = y1e - y1s;
		const double b1 = x1s - x1e;
		const double c1 = a1*x1s + b1*y1s;

		const double a2 = y2e - y2s;
		const double b2 = x2s - x2e;
		const double c2 = a2*x2s + b2*y2s;

		const double det = a1*b2 - a2*b1;

		if (ALMOST_THE_SAME(det, 0.)) {
			Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l->entity);
			return false;
		}

		xx = (b2*c1 - b1*c2) / det;
		xy = (a1*c2 - a2*c1) / det;
	}

	gp_Trsf2d trsf2d;
	bool has_position = true;
#ifdef USE_IFC4
	has_position = l->hasPosition();
#endif
	if (has_position) {
		IfcGeom::Kernel::convert(l->Position(), trsf2d);
	}

	double coords[12] = {-x,-y, x,-y, x,-y+d-dy1, xx, xy, -x+d-dx1,y, -x,y};
	int fillets[3] = {2,3,4};
	double radii[3] = {f2,f1,f2};
	return profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face);
}
Esempio n. 5
0
bool IfcGeom::convert(const Ifc2x3::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire) {
	Ifc2x3::IfcCurve::ptr basis_curve = l->BasisCurve();
	bool isConic = basis_curve->is(Ifc2x3::Type::IfcConic);
	double parameterFactor = isConic ? IfcGeom::GetValue(GV_PLANEANGLE_UNIT) : IfcGeom::GetValue(GV_LENGTH_UNIT);
	Handle(Geom_Curve) curve;
	if ( ! IfcGeom::convert_curve(basis_curve,curve) ) return false;
	bool trim_cartesian = l->MasterRepresentation() == Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
	IfcUtil::IfcAbstractSelect::list trims1 = l->Trim1();
	IfcUtil::IfcAbstractSelect::list trims2 = l->Trim2();
	bool trimmed1 = false;
	bool trimmed2 = false;
	unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
	double flts[2];
	gp_Pnt pnts[2];
	bool has_flts[2] = {false,false};
	bool has_pnts[2] = {false,false};
	BRepBuilderAPI_MakeWire w;
	for ( IfcUtil::IfcAbstractSelect::it it = trims1->begin(); it != trims1->end(); it ++ ) {
		const IfcUtil::IfcAbstractSelect::ptr i = *it;
		if ( i->is(Ifc2x3::Type::IfcCartesianPoint) ) {
			IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcCartesianPoint>(i), pnts[sense_agreement] );
			has_pnts[sense_agreement] = true;
		} else if ( i->is(Ifc2x3::Type::IfcParameterValue) ) {
			const double value = *reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcUtil::IfcArgumentSelect>(i)->wrappedValue();
			flts[sense_agreement] = value * parameterFactor;
			has_flts[sense_agreement] = true;
		}
	}
	for ( IfcUtil::IfcAbstractSelect::it it = trims2->begin(); it != trims2->end(); it ++ ) {
		const IfcUtil::IfcAbstractSelect::ptr i = *it;
		if ( i->is(Ifc2x3::Type::IfcCartesianPoint) ) {
			IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcCartesianPoint>(i), pnts[1-sense_agreement] );
			has_pnts[1-sense_agreement] = true;
		} else if ( i->is(Ifc2x3::Type::IfcParameterValue) ) {
			const double value = *reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcUtil::IfcArgumentSelect>(i)->wrappedValue();
			flts[1-sense_agreement] = value * parameterFactor;
			has_flts[1-sense_agreement] = true;
		}
	}
	trim_cartesian &= has_pnts[0] && has_pnts[1];
	bool trim_cartesian_failed = !trim_cartesian;
	if ( trim_cartesian ) {
		if ( pnts[0].Distance(pnts[1]) < GetValue(GV_WIRE_CREATION_TOLERANCE) ) {
			Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity);
			return false;
		}
		ShapeFix_ShapeTolerance FTol;
		TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
		TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
		FTol.SetTolerance(v1, GetValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
		FTol.SetTolerance(v2, GetValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
		BRepBuilderAPI_MakeEdge e (curve,v1,v2);
		if ( ! e.IsDone() ) {
			BRepBuilderAPI_EdgeError err = e.Error();
			if ( err == BRepBuilderAPI_PointProjectionFailed ) {
				Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l->entity);
				trim_cartesian_failed = true;
			}
		} else {
			w.Add(e.Edge());
		}
	}
	if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
		if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],(double)(M_PI*2.0)),0.0f) ) {
			w.Add(BRepBuilderAPI_MakeEdge(curve));
		} else {
			BRepBuilderAPI_MakeEdge e (curve,flts[0],flts[1]);
			w.Add(e.Edge());
		}			
	} else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) {
		w.Add(BRepBuilderAPI_MakeEdge(pnts[0],pnts[1]));
	}
	if ( w.IsDone() ) {
		wire = w.Wire();
		return true;
	} else {
		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;
}