NOTE: From now on Boost is required in order to compile IfcOpenShell

====================================================================

- Use boost::optional for optional IFC arguments
- Use boost::uuid for the creation of GlobalIds
- New IfcGeomObjects setting to force alignment of TopoDS_Face normal to CCW orientation
- Removed static Ifc class, renamed to non-static IfcFile. IfcFile renamed to IfcSpfStream
- Introduced Logger class
- Introduced EntityBuffer class that keeps track of all writable entities created to add them all in once to the IfcFile class
This commit is contained in:
Thomas Krijnen
2012-08-11 13:24:08 +00:00
parent 31daf8dd20
commit 6f1e1c3bad
29 changed files with 2933 additions and 2684 deletions
+18 -2
View File
@@ -47,16 +47,32 @@ namespace IfcGeom {
// Tolerances and settings for various geometrical operations:
enum GeomValue {
// Specifies the deflection of the mesher
// Default: 0.001m / 1mm
GV_DEFLECTION_TOLERANCE,
// Specifies the tolerance of the wire builder, most notably for trimmed curves
// Defailt: 0.0001m / 0.1mm
GV_WIRE_CREATION_TOLERANCE,
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
// Default: 0.000001m 0.01cm2
GV_MINIMAL_FACE_AREA,
// Specifies the treshold distance under which cartesian points are deemed equal
// Default: 0.00001m / 0.01mm
GV_POINT_EQUALITY_TOLERANCE,
// Specifies maximum number of faces for a shell to be sewed. Sewing shells
// that consist of many faces is really detrimental for the performance.
GV_MAX_FACES_TO_SEW
// Default: 1000
GV_MAX_FACES_TO_SEW,
// By default singular faces have no explicitly defined orientation, to
// force faces to be defined CounterClockWise, set this value greater than zero.
GV_FORCE_CCW_FACE_ORIENTATION,
// The length unit used the creation of TopoDS_Shapes, primarily affects the
// interpretation of IfcCartesianPoints and IfcVector magnitudes
// DefaultL 1.0
GV_LENGTH_UNIT,
// The plane angle unit used for the creation of TopoDS_Shapes, primarily affects
// the interpretation of IfcParamaterValues of IfcTrimmedCurves
// Default: -1.0 (= not set, fist try degrees, then radians)
GV_PLANEANGLE_UNIT,
};
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
@@ -80,7 +96,7 @@ namespace IfcGeom {
double face_area(const TopoDS_Face& f);
void SetValue(GeomValue var, double value);
double GetValue(GeomValue var);
namespace Cache {
void Purge();
void PurgeShapeCache();
+3 -3
View File
@@ -78,7 +78,7 @@
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::convert(const Ifc2x3::IfcCircle::ptr l, Handle(Geom_Curve)& curve) {
const double r = l->Radius() * Ifc::LengthUnit;
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( r <= 0.0f ) { return false; }
gp_Trsf trsf;
Ifc2x3::IfcAxis2Placement placement = l->Position();
@@ -94,8 +94,8 @@ bool IfcGeom::convert(const Ifc2x3::IfcCircle::ptr l, Handle(Geom_Curve)& curve)
return true;
}
bool IfcGeom::convert(const Ifc2x3::IfcEllipse::ptr l, Handle(Geom_Curve)& curve) {
double x = l->SemiAxis1() * Ifc::LengthUnit;
double y = l->SemiAxis2() * Ifc::LengthUnit;
double x = l->SemiAxis1() * IfcGeom::GetValue(GV_LENGTH_UNIT);
double y = l->SemiAxis2() * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( x == 0.0f || y == 0.0f || y > x ) { return false; }
gp_Trsf trsf;
Ifc2x3::IfcAxis2Placement placement = l->Position();
+91 -31
View File
@@ -74,6 +74,7 @@
#include <ShapeFix_Solid.hxx>
#include <TopLoc_Location.hxx>
#include <BRepGProp_Face.hxx>
#include "../ifcgeom/IfcGeom.h"
@@ -81,15 +82,15 @@ bool IfcGeom::convert(const Ifc2x3::IfcFace::ptr l, TopoDS_Face& face) {
Ifc2x3::IfcFaceBound::list bounds = l->Bounds();
Ifc2x3::IfcFaceBound::it it = bounds->begin();
Ifc2x3::IfcLoop::ptr loop = (*it)->Bound();
TopoDS_Wire wire;
if ( ! IfcGeom::convert_wire(loop,wire) ) return false;
BRepBuilderAPI_MakeFace mf (wire);
TopoDS_Wire outer_wire;
if ( ! IfcGeom::convert_wire(loop,outer_wire) ) return false;
BRepBuilderAPI_MakeFace mf (outer_wire);
BRepBuilderAPI_FaceError er = mf.Error();
if ( er == BRepBuilderAPI_NotPlanar ) {
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire, 0.01, TopAbs_WIRE);
FTol.SetTolerance(outer_wire, 0.01, TopAbs_WIRE);
mf.~BRepBuilderAPI_MakeFace();
new (&mf) BRepBuilderAPI_MakeFace(wire);
new (&mf) BRepBuilderAPI_MakeFace(outer_wire);
er = mf.Error();
}
if ( er != BRepBuilderAPI_FaceDone ) return false;
@@ -116,6 +117,65 @@ bool IfcGeom::convert(const Ifc2x3::IfcFace::ptr l, TopoDS_Face& face) {
return false;
}
}
if ( IfcGeom::GetValue(GV_FORCE_CCW_FACE_ORIENTATION)>0 ) {
// Check the orientation of the face by comparing the
// normal of the topological surface to the Newell's Method's
// normal. Newell's Method is used for the normal calculation
// as a simple edge cross product can give opposite results
// for a concave face boundary.
// Reference: Graphics Gems III p. 231
BRepGProp_Face prop(face);
gp_Vec normal_direction;
gp_Pnt center;
double u1,u2,v1,v2;
prop.Bounds(u1,u2,v1,v2);
prop.Normal((u1+u2)/2.0,(v1+v2)/2.0,center,normal_direction);
gp_Dir face_normal1 = gp_Dir(normal_direction.XYZ());
double x = 0, y = 0, z = 0;
gp_Pnt current, previous, first;
int n = 0;
// Iterate over the vertices of the outer wire (discarding
// any potential holes)
for ( TopExp_Explorer exp(outer_wire,TopAbs_VERTEX);; exp.Next()) {
unsigned has_more = exp.More();
if ( has_more ) {
const TopoDS_Vertex& v = TopoDS::Vertex(exp.Current());
current = BRep_Tool::Pnt(v);
} else {
current = first;
}
if ( n ) {
const double& xn = previous.X();
const double& yn = previous.Y();
const double& zn = previous.Z();
const double& xn1 = current.X();
const double& yn1 = current.Y();
const double& zn1 = current.Z();
x += (yn-yn1)*(zn+zn1);
y += (xn+xn1)*(zn-zn1);
z += (xn-xn1)*(yn+yn1);
} else {
first = current;
}
if ( !has_more ) {
break;
}
previous = current;
++n;
}
// If Newell's normal does not point in the same direction
// as the topological face normal the face orientation is
// reversed
gp_Vec face_normal2(x,y,z);
if ( face_normal1.Dot(face_normal2) < 0 ) {
TopAbs_Orientation o = face.Orientation();
face.Orientation(o == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
}
}
// It might be a good idea to globally discard faces
// smaller than a certain treshold value. But for now
// only when processing IfcConnectedFacesets the small
@@ -145,11 +205,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcArbitraryProfileDefWithVoids::ptr l, Topo
return true;
}
bool IfcGeom::convert(const Ifc2x3::IfcRectangleProfileDef::ptr l, TopoDS_Face& face) {
const double x = l->XDim() / 2.0f * Ifc::LengthUnit;
const double y = l->YDim() / 2.0f * Ifc::LengthUnit;
const double x = l->XDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( x == 0.0f || y == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -159,18 +219,18 @@ bool IfcGeom::convert(const Ifc2x3::IfcRectangleProfileDef::ptr l, TopoDS_Face&
return IfcGeom::profile_helper(4,coords,0,0,0,trsf2d,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcIShapeProfileDef::ptr l, TopoDS_Face& face) {
const double x = l->OverallWidth() / 2.0f * Ifc::LengthUnit;
const double y = l->OverallDepth() / 2.0f * Ifc::LengthUnit;
const double d1 = l->WebThickness() / 2.0f * Ifc::LengthUnit;
const double d2 = l->FlangeThickness() * Ifc::LengthUnit;
const double x = l->OverallWidth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->OverallDepth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool doFillet = l->hasFilletRadius();
double f;
if ( doFillet ) {
f = l->FilletRadius() * Ifc::LengthUnit;
f = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
if ( x == 0.0f || y == 0.0f || d1 == 0.0f || d2 == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -183,19 +243,19 @@ bool IfcGeom::convert(const Ifc2x3::IfcIShapeProfileDef::ptr l, TopoDS_Face& fac
return IfcGeom::profile_helper(12,coords,doFillet ? 4 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcCShapeProfileDef::ptr l, TopoDS_Face& face) {
const double x = l->Depth() / 2.0f * Ifc::LengthUnit;
const double y = l->Width() / 2.0f * Ifc::LengthUnit;
const double d1 = l->WallThickness() * Ifc::LengthUnit;
const double d2 = l->Girth() * Ifc::LengthUnit;
const double x = l->Depth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->Width() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d1 = l->WallThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d2 = l->Girth() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool doFillet = l->hasInternalFilletRadius();
double f1,f2;
if ( doFillet ) {
f1 = l->InternalFilletRadius() * Ifc::LengthUnit;
f1 = l->InternalFilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
f2 = f1 + d1;
}
if ( x == 0.0f || y == 0.0f || d1 == 0.0f || d2 == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -208,21 +268,21 @@ bool IfcGeom::convert(const Ifc2x3::IfcCShapeProfileDef::ptr l, TopoDS_Face& fac
return IfcGeom::profile_helper(12,coords,doFillet ? 8 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcLShapeProfileDef::ptr l, TopoDS_Face& face) {
const double y = l->Depth() / 2.0f * Ifc::LengthUnit;
const double x = l->Width() / 2.0f * Ifc::LengthUnit;
const double d = l->Thickness() * Ifc::LengthUnit;
const double y = l->Depth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double x = l->Width() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d = l->Thickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool doEdgeFillet = l->hasEdgeRadius();
bool doFillet = l->hasFilletRadius();
double f1 = 0.0f;
double f2 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * Ifc::LengthUnit;
f1 = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
if ( doEdgeFillet) {
f2 = l->EdgeRadius() * Ifc::LengthUnit;
f2 = l->EdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
if ( x == 0.0f || y == 0.0f || d == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -235,9 +295,9 @@ bool IfcGeom::convert(const Ifc2x3::IfcLShapeProfileDef::ptr l, TopoDS_Face& fac
return IfcGeom::profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcCircleProfileDef::ptr l, TopoDS_Face& face) {
const double r = l->Radius() * Ifc::LengthUnit;
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( r == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -252,11 +312,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcCircleProfileDef::ptr l, TopoDS_Face& fac
return IfcGeom::convert_wire_to_face(w,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcCircleHollowProfileDef::ptr l, TopoDS_Face& face) {
const double r = l->Radius() * Ifc::LengthUnit;
const double t = l->WallThickness() * Ifc::LengthUnit;
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double t = l->WallThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( r == 0.0f || t == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
+32 -11
View File
@@ -163,7 +163,7 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x
const gp_GTrsf& entity_shape_gtrsf = *(it3->first);
TopoDS_Shape entity_shape;
if ( entity_shape_gtrsf.Form() == gp_Other ) {
Ifc::LogMessage("Warning","Applying non uniform transformation to:",entity->entity);
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());
@@ -175,17 +175,17 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x
const TopoDS_Shape& opening_shape_unlocated = IfcGeom::ensure_fit_for_subtraction(*(it4->second),opening_shape_solid);
const gp_GTrsf& opening_shape_gtrsf = *(it4->first);
if ( opening_shape_gtrsf.Form() == gp_Other ) {
Ifc::LogMessage("Warning","Applying non uniform transformation to opening of:",entity->entity);
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 ( Ifc::Verbosity > 1 ) {
if ( Logger::Verbosity() >= Logger::LOG_WARNING ) {
opening_volume = shape_volume(opening_shape);
if ( opening_volume <= ALMOST_ZERO )
Ifc::LogMessage("Warning","Empty opening for:",entity->entity);
Logger::Message(Logger::LOG_WARNING,"Empty opening for:",entity->entity);
original_shape_volume = shape_volume(entity_shape);
}
@@ -198,17 +198,17 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x
bool is_valid = analyser.IsValid() != 0;
if ( is_valid ) {
entity_shape = brep_cut;
if ( Ifc::Verbosity > 1 ) {
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) )
Ifc::LogMessage("Warning","Subtraction yields unchanged volume:",entity->entity);
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",entity->entity);
}
} else {
Ifc::LogMessage("Error","Invalid result from subtraction:",entity->entity);
Logger::Message(Logger::LOG_ERROR,"Invalid result from subtraction:",entity->entity);
}
} else {
Ifc::LogMessage("Error","Failed to process subtraction:",entity->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",entity->entity);
}
}
@@ -274,7 +274,7 @@ bool IfcGeom::convert_openings_fast(const Ifc2x3::IfcProduct::ptr entity, const
const gp_GTrsf& entity_shape_gtrsf = *(it3->first);
TopoDS_Shape entity_shape;
if ( entity_shape_gtrsf.Form() == gp_Other ) {
Ifc::LogMessage("Warning","Applying non uniform transformation to:",entity->entity);
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());
@@ -295,7 +295,7 @@ bool IfcGeom::convert_openings_fast(const Ifc2x3::IfcProduct::ptr entity, const
// Apparently processing the boolean operation failed or resulted in an invalid result
// in which case the original shape without the subtractions is returned instead
// we try convert the openings in the original way, one by one.
Ifc::LogMessage("Warning","Subtracting combined openings compound failed:",entity->entity);
Logger::Message(Logger::LOG_WARNING,"Subtracting combined openings compound failed:",entity->entity);
return false;
}
@@ -429,7 +429,10 @@ static double deflection_tolerance = 0.001;
static double wire_creation_tolerance = 0.0001;
static double minimal_face_area = 0.000001;
static double point_equality_tolerance = 0.00001;
static double max_faces_to_sew = 1000;
static double max_faces_to_sew = -1.0;
static double ifc_length_unit = 1.0;
static double ifc_planeangle_unit = -1.0;
static double force_ccw_face_orientation = -1.0;
void IfcGeom::SetValue(GeomValue var, double value) {
switch (var) {
@@ -448,6 +451,15 @@ void IfcGeom::SetValue(GeomValue var, double value) {
case GV_MAX_FACES_TO_SEW:
max_faces_to_sew = value;
break;
case GV_LENGTH_UNIT:
ifc_length_unit = value;
break;
case GV_PLANEANGLE_UNIT:
ifc_planeangle_unit = value;
break;
case GV_FORCE_CCW_FACE_ORIENTATION:
force_ccw_face_orientation = value;
break;
default:
assert(!"never reach here");
}
@@ -465,6 +477,15 @@ double IfcGeom::GetValue(GeomValue var) {
return point_equality_tolerance;
case GV_MAX_FACES_TO_SEW:
return max_faces_to_sew;
case GV_LENGTH_UNIT:
return ifc_length_unit;
break;
case GV_PLANEANGLE_UNIT:
return ifc_planeangle_unit;
break;
case GV_FORCE_CCW_FACE_ORIENTATION:
return force_ccw_face_orientation;
break;
}
assert(!"never reach here");
return 0;
+4 -4
View File
@@ -91,9 +91,9 @@ bool IfcGeom::convert(const Ifc2x3::IfcCartesianPoint::ptr l, gp_Pnt& point) {
IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point)
std::vector<double> xyz = l->Coordinates();
point = gp_Pnt(
xyz.size() ? (xyz[0]*Ifc::LengthUnit) : 0.0f,
xyz.size() > 1 ? (xyz[1]*Ifc::LengthUnit) : 0.0f,
xyz.size() > 2 ? (xyz[2]*Ifc::LengthUnit) : 0.0f
xyz.size() ? (xyz[0]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f,
xyz.size() > 1 ? (xyz[1]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f,
xyz.size() > 2 ? (xyz[2]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f
);
CACHE(IfcCartesianPoint,l,point)
return true;
@@ -113,7 +113,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcVector::ptr l, gp_Vec& v) {
IN_CACHE(IfcVector,l,gp_Vec,v)
gp_Dir d;
IfcGeom::convert(l->Orientation(),d);
v = l->Magnitude() * Ifc::LengthUnit * d;
v = l->Magnitude() * IfcGeom::GetValue(GV_LENGTH_UNIT) * d;
CACHE(IfcVector,l,v)
return true;
}
+108 -17
View File
@@ -51,9 +51,9 @@ bool convert_back_units = false;
bool use_faster_booleans = false;
int IfcGeomObjects::IfcMesh::addvert(const gp_XYZ& p) {
const float X = convert_back_units ? (float) (p.X() / Ifc::LengthUnit) : (float)p.X();
const float Y = convert_back_units ? (float) (p.Y() / Ifc::LengthUnit) : (float)p.Y();
const float Z = convert_back_units ? (float) (p.Z() / Ifc::LengthUnit) : (float)p.Z();
const float X = convert_back_units ? (float) (p.X() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.X();
const float Y = convert_back_units ? (float) (p.Y() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.Y();
const float Z = convert_back_units ? (float) (p.Z() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.Z();
int i = (int) verts.size() / 3;
if ( weld_vertices ) {
const VertKey key = VertKey(X,std::pair<float,float>(Y,Z));
@@ -71,6 +71,8 @@ int IfcGeomObjects::IfcMesh::addvert(const gp_XYZ& p) {
bool use_world_coords = false;
bool use_brep_data = false;
static IfcParse::IfcFile* ifc_file = 0;
IfcGeomObjects::IfcMesh::IfcMesh(int i, const IfcGeom::ShapeList& shapes) {
id = i;
@@ -102,10 +104,10 @@ IfcGeomObjects::IfcMesh::IfcMesh(int i, const IfcGeom::ShapeList& shapes) {
// Triangulate the shape
try {
//BRepTools::Clean(s);
// BRepTools::Clean(s);
BRepMesh::Mesh(s, IfcGeom::GetValue(IfcGeom::GV_DEFLECTION_TOLERANCE));
} catch(...) {
Ifc::LogMessage("Error","Failed to triangulate mesh:",Ifc::EntityById(i)->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to triangulate mesh:",ifc_file->EntityById(i)->entity);
continue;
}
TopExp_Explorer exp;
@@ -401,7 +403,7 @@ IfcGeomObjects::IfcGeomObject* _get() {
IfcGeom::convert_openings(ifc_product,openings,shapes,trsf,opened_shapes);
}
} catch(...) {
Ifc::LogMessage("Error","Error processing openings for:",ifc_product->entity);
Logger::Message(Logger::LOG_ERROR,"Error processing openings for:",ifc_product->entity);
}
if ( use_world_coords ) {
for ( IfcGeom::ShapeList::const_iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
@@ -452,7 +454,8 @@ bool IfcGeomObjects::Next() {
}
std::vector<IfcGeomObjects::IfcObject*> returned_objects;
bool IfcGeomObjects::CleanUp() {
Ifc::Dispose();
// TODO: Correctly implement destructor for IfcFile
delete ifc_file;
IfcGeom::Cache::Purge();
for ( std::vector<IfcGeomObjects::IfcObject*>::const_iterator it = returned_objects.begin();
it != returned_objects.end();
@@ -465,7 +468,7 @@ bool IfcGeomObjects::CleanUp() {
const IfcGeomObjects::IfcObject* IfcGeomObjects::GetObject(int id) {
IfcObject* ifc_object = 0;
try {
const IfcEntity& ifc_entity = Ifc::EntityById(id);
const IfcParse::IfcEntity& ifc_entity = ifc_file->EntityById(id);
if ( ifc_entity->is(Ifc2x3::Type::IfcProduct) ) {
Ifc2x3::IfcProduct::ptr ifc_product = reinterpret_pointer_cast<IfcUtil::IfcBaseClass,Ifc2x3::IfcProduct>(ifc_entity);
int parent_id = -1;
@@ -488,11 +491,93 @@ const IfcGeomObjects::IfcObject* IfcGeomObjects::GetObject(int id) {
const IfcGeomObjects::IfcGeomObject* IfcGeomObjects::Get() {
return current_geom_obj;
}
double UnitPrefixToValue( Ifc2x3::IfcSIPrefix::IfcSIPrefix v ) {
if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_EXA ) return (double) 1e18;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_PETA ) return (double) 1e15;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_TERA ) return (double) 1e12;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_GIGA ) return (double) 1e9;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_MEGA ) return (double) 1e6;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_KILO ) return (double) 1e3;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_HECTO ) return (double) 1e2;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_DECA ) return (double) 1;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_DECI ) return (double) 1e-1;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_CENTI ) return (double) 1e-2;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_MILLI ) return (double) 1e-3;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_MICRO ) return (double) 1e-6;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_NANO ) return (double) 1e-9;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_PICO ) return (double) 1e-12;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_FEMTO ) return (double) 1e-15;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_ATTO ) return (double) 1e-18;
else return 1.0f;
}
void IfcGeomObjects::InitUnits() {
// Set default units, set length to meters, angles to undefined
IfcGeom::SetValue(IfcGeom::GV_LENGTH_UNIT,1.0);
IfcGeom::SetValue(IfcGeom::GV_PLANEANGLE_UNIT,-1.0);
Ifc2x3::IfcUnitAssignment::list unit_assignments = ifc_file->EntitiesByType<Ifc2x3::IfcUnitAssignment>();
IfcUtil::IfcAbstractSelect::list units = IfcUtil::IfcAbstractSelect::list();
if ( unit_assignments->Size() ) {
Ifc2x3::IfcUnitAssignment::ptr unit_assignment = *unit_assignments->begin();
units = unit_assignment->Units();
}
if ( ! units ) {
// No units eh... Since tolerances and deflection are specified internally in meters
// we will try to find another indication of the model size.
Ifc2x3::IfcExtrudedAreaSolid::list extrusions = ifc_file->EntitiesByType<Ifc2x3::IfcExtrudedAreaSolid>();
if ( ! extrusions->Size() ) return;
double max_height = -1.0f;
for ( Ifc2x3::IfcExtrudedAreaSolid::it it = extrusions->begin(); it != extrusions->end(); ++ it ) {
const double depth = (*it)->Depth();
if ( depth > max_height ) max_height = depth;
}
if ( max_height > 100.0f ) IfcGeom::SetValue(IfcGeom::GV_LENGTH_UNIT,0.001);
return;
}
try {
for ( IfcUtil::IfcAbstractSelect::it it = units->begin(); it != units->end(); ++ it ) {
const IfcUtil::IfcAbstractSelect::ptr base = *it;
Ifc2x3::IfcSIUnit::ptr unit = Ifc2x3::IfcSIUnit::ptr();
double value = 1.0f;
if ( base->is(Ifc2x3::Type::IfcConversionBasedUnit) ) {
const Ifc2x3::IfcConversionBasedUnit::ptr u = reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcConversionBasedUnit>(base);
const Ifc2x3::IfcMeasureWithUnit::ptr u2 = u->ConversionFactor();
Ifc2x3::IfcUnit u3 = u2->UnitComponent();
if ( u3->is(Ifc2x3::Type::IfcSIUnit) ) {
unit = (Ifc2x3::IfcSIUnit*) u3;
}
Ifc2x3::IfcValue v = u2->ValueComponent();
IfcUtil::IfcArgumentSelect* v2 = (IfcUtil::IfcArgumentSelect*) v;
const double f = *v2->wrappedValue();
value *= f;
} else if ( base->is(Ifc2x3::Type::IfcSIUnit) ) {
unit = reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcSIUnit>(base);
}
if ( unit ) {
if ( unit->hasPrefix() ) {
value *= UnitPrefixToValue(unit->Prefix());
}
Ifc2x3::IfcUnitEnum::IfcUnitEnum type = unit->UnitType();
if ( type == Ifc2x3::IfcUnitEnum::IfcUnit_LENGTHUNIT ) {
IfcGeom::SetValue(IfcGeom::GV_LENGTH_UNIT,value);
} else if ( type == Ifc2x3::IfcUnitEnum::IfcUnit_PLANEANGLEUNIT ) {
IfcGeom::SetValue(IfcGeom::GV_PLANEANGLE_UNIT,value);
}
}
}
} catch ( IfcException ex ) {
Logger::Message(Logger::LOG_ERROR,ex.what());
}
}
bool IfcGeomObjects::Init(const std::string fn) {
return IfcGeomObjects::Init(fn, 0, 0);
}
bool _Init() {
shapereps = Ifc::EntitiesByType<Ifc2x3::IfcShapeRepresentation>();
IfcGeomObjects::InitUnits();
shapereps = ifc_file->EntitiesByType<Ifc2x3::IfcShapeRepresentation>();
if ( ! shapereps ) return false;
outer = shapereps->begin();
@@ -506,18 +591,21 @@ bool _Init() {
return true;
}
bool IfcGeomObjects::Init(const std::string fn, std::ostream* log1, std::ostream* log2) {
Ifc::SetOutput(log1,log2);
if ( !Ifc::Init(fn) ) return false;
Logger::SetOutput(log1,log2);
ifc_file = new IfcParse::IfcFile();
if ( !ifc_file->Init(fn) ) return false;
return _Init();
}
bool IfcGeomObjects::Init(std::istream& f, int len, std::ostream* log1, std::ostream* log2) {
Ifc::SetOutput(log1,log2);
if ( !Ifc::Init(f, len) ) return false;
Logger::SetOutput(log1,log2);
ifc_file = new IfcParse::IfcFile();
if ( !ifc_file->Init(f, len) ) return false;
return _Init();
}
bool IfcGeomObjects::Init(void* data, int len) {
Ifc::SetOutput(0,0);
if ( !Ifc::Init(data, len) ) return false;
Logger::SetOutput(0,0);
ifc_file = new IfcParse::IfcFile();
if ( !ifc_file->Init(data, len) ) return false;
return _Init();
}
void IfcGeomObjects::Settings(int setting, bool value) {
@@ -538,7 +626,10 @@ void IfcGeomObjects::Settings(int setting, bool value) {
use_faster_booleans = value;
break;
case SEW_SHELLS:
Ifc::SewShells = value;
IfcGeom::SetValue(IfcGeom::GV_MAX_FACES_TO_SEW,value ? 1000 : -1);
break;
case IfcGeomObjects::FORCE_CCW_FACE_ORIENTATION:
IfcGeom::SetValue(IfcGeom::GV_FORCE_CCW_FACE_ORIENTATION,value ? 1 : -1);
break;
}
}
@@ -546,5 +637,5 @@ int IfcGeomObjects::Progress() {
return 100 * done / total;
}
std::string IfcGeomObjects::GetLog() {
return Ifc::GetLog();
return Logger::GetLog();
}
+4
View File
@@ -94,6 +94,9 @@ namespace IfcGeomObjects {
// Specifies whether to compose IfcOpeningElements into a single compound
// in order to speed up the processing of opening subtractions.
const int FASTER_BOOLEANS = 6;
// By default singular faces have no explicitly defined orientation, to
// force faces to be defined CounterClockWise set this to true.
const int FORCE_CCW_FACE_ORIENTATION = 7;
// End of settings enumeration.
@@ -143,6 +146,7 @@ namespace IfcGeomObjects {
IfcGeomObject(int my_id, int p_id, const std::string& n, const std::string& t, const std::string& g, const gp_Trsf& trsf, IfcMesh* m);
};
void InitUnits();
bool Init(const std::string fn);
bool Init(void* data, int len);
bool Init(const std::string fn, std::ostream* log1= 0, std::ostream* log2= 0);
+10 -10
View File
@@ -81,7 +81,7 @@
bool IfcGeom::convert(const Ifc2x3::IfcExtrudedAreaSolid::ptr l, TopoDS_Shape& shape) {
TopoDS_Face face;
if ( ! IfcGeom::convert_face(l->SweptArea(),face) ) return false;
const double height = l->Depth() * Ifc::LengthUnit;
const double height = l->Depth() * IfcGeom::GetValue(GV_LENGTH_UNIT);
gp_Trsf trsf;
IfcGeom::convert(l->Position(),trsf);
@@ -158,11 +158,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shap
const double first_operand_volume = shape_volume(s1);
if ( first_operand_volume <= ALMOST_ZERO )
Ifc::LogMessage("Warning","Empty solid for:",l->FirstOperand()->entity);
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity);
if ( !IfcGeom::convert_shape(l->SecondOperand(),s2) ) {
shape = s1;
Ifc::LogMessage("Error","Failed to convert SecondOperand of:",l->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity);
return true;
}
@@ -176,7 +176,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shap
if ( ! is_halfspace ) {
const double second_operand_volume = shape_volume(s2);
if ( second_operand_volume <= ALMOST_ZERO )
Ifc::LogMessage("Warning","Empty solid for:",operand2->entity);
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity);
}
bool valid_cut = false;
@@ -211,7 +211,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shap
if ( is_valid ) {
shape = result;
valid_cut = true;
Ifc::LogMessage("Warning","Slightly nudged the SecondOperand of:",l->entity);
Logger::Message(Logger::LOG_WARNING,"Slightly nudged the SecondOperand of:",l->entity);
}
}
}
@@ -281,9 +281,9 @@ bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shap
if ( valid_cut ) {
const double volume_after_subtraction = shape_volume(shape);
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
Ifc::LogMessage("Warning","Subtraction yields unchanged volume:",l->entity);
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l->entity);
} else {
Ifc::LogMessage("Error","Failed to process subtraction:",l->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l->entity);
shape = s1;
}
@@ -294,7 +294,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
Ifc2x3::IfcFace::list faces = l->CfsFaces();
bool facesAdded = false;
const unsigned int num_faces = faces->Size();
if ( Ifc::SewShells && num_faces < GetValue(GV_MAX_FACES_TO_SEW) ) {
if ( num_faces < GetValue(GV_MAX_FACES_TO_SEW) ) {
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMaxTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
@@ -305,7 +305,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
builder.Add(face);
facesAdded = true;
} else {
Ifc::LogMessage("Warning","Invalid face:",(*it)->entity);
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
}
}
if ( ! facesAdded ) return false;
@@ -326,7 +326,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
builder.Add(compound,face);
facesAdded = true;
} else {
Ifc::LogMessage("Warning","Invalid face:",(*it)->entity);
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
}
}
if ( ! facesAdded ) return false;
+39 -43
View File
@@ -83,62 +83,58 @@
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::convert(const Ifc2x3::IfcCompositeCurve::ptr l, TopoDS_Wire& wire) {
if ( ! Ifc::hasPlaneAngleUnit ) {
Ifc::LogMessage("Warning","Creating a composite curve without unit information:",l->entity);
// Temporarily pretend we do have unit information
Ifc::hasPlaneAngleUnit = true;
if ( IfcGeom::GetValue(GV_PLANEANGLE_UNIT)>0 ) {
Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity);
bool succes_radians = false;
// Temporarily pretend we do have unit information
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,1.0);
bool succes_radians = false;
bool succes_degrees = false;
bool use_radians = false;
bool use_degrees = false;
// First try radians
Ifc::PlaneAngleUnit = 1.0f;
TopoDS_Wire wire_radians, wire_degrees;
// First try radians
TopoDS_Wire wire_radians, wire_degrees;
try {
succes_radians = IfcGeom::convert(l,wire_radians);
} catch (...) {}
// Now try degrees
Ifc::PlaneAngleUnit = 0.0174532925199433f;
// Now try degrees
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
try {
succes_degrees = IfcGeom::convert(l,wire_degrees);
} catch (...) {}
// Restore to unknown unit state
Ifc::PlaneAngleUnit = 1.0f;
Ifc::hasPlaneAngleUnit = false;
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,-1.0);
if ( succes_degrees && ! succes_radians ) {
if ( succes_degrees && ! succes_radians ) {
use_degrees = true;
} else if ( succes_radians && ! succes_degrees ) {
use_radians = true;
} else if ( succes_radians && succes_degrees ) {
if ( wire_degrees.Closed() && ! wire_radians.Closed() ) {
use_degrees = true;
} else if ( wire_radians.Closed() && ! wire_degrees.Closed() ) {
use_radians = true;
} else {
// No heuristic left to prefer the one over the other,
// apparently both variants are equally succesful.
// The curve might be composed of only straight segments.
// Let's go with the wire created using radians as that
// at least is a SI unit.
use_radians = true;
}
}
if ( use_radians ) {
Ifc::LogMessage("Notice","Used radians to create composite curve");
wire = wire_radians;
} else if ( use_degrees ) {
Ifc::LogMessage("Notice","Used degrees to create composite curve");
wire = wire_degrees;
use_radians = true;
} else if ( succes_radians && succes_degrees ) {
if ( wire_degrees.Closed() && ! wire_radians.Closed() ) {
use_degrees = true;
} else if ( wire_radians.Closed() && ! wire_degrees.Closed() ) {
use_radians = true;
} else {
// No heuristic left to prefer the one over the other,
// apparently both variants are equally succesful.
// The curve might be composed of only straight segments.
// Let's go with the wire created using radians as that
// at least is a SI unit.
use_radians = true;
}
}
return succes_radians || succes_degrees;
if ( use_radians ) {
Logger::Message(Logger::LOG_NOTICE,"Used radians to create composite curve");
wire = wire_radians;
} else if ( use_degrees ) {
Logger::Message(Logger::LOG_NOTICE,"Used degrees to create composite curve");
wire = wire_degrees;
}
}
Ifc2x3::IfcCompositeCurveSegment::list segments = l->Segments();
BRepBuilderAPI_MakeWire w;
@@ -147,7 +143,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcCompositeCurve::ptr l, TopoDS_Wire& wire)
const Ifc2x3::IfcCurve::ptr curve = (*it)->ParentCurve();
TopoDS_Wire wire2;
if ( ! IfcGeom::convert_wire(curve,wire2) ) {
Ifc::LogMessage("Error","Failed to convert curve:",curve->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity);
continue;
}
if ( ! (*it)->SameSense() ) wire2.Reverse();
@@ -166,7 +162,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcCompositeCurve::ptr l, TopoDS_Wire& wire)
w.Add(wire2);
//last_vertex = w.Vertex();
if ( w.Error() != BRepBuilderAPI_WireDone ) {
Ifc::LogMessage("Error","Failed to join curve segments:",l->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to join curve segments:",l->entity);
return false;
}
}
@@ -176,7 +172,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcCompositeCurve::ptr l, TopoDS_Wire& wire)
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 ? Ifc::PlaneAngleUnit : Ifc::LengthUnit;
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;
@@ -209,7 +205,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire) {
BRepBuilderAPI_EdgeError err = e.Error();
if ( err == BRepBuilderAPI_PointProjectionFailed ) {
w.Add(BRepBuilderAPI_MakeEdge(sense_agreement ? pnt1 : pnt2,sense_agreement ? pnt2 : pnt1));
Ifc::LogMessage("Warning","Point projection failed for:",l->entity);
Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l->entity);
}
} else {
w.Add(e.Edge());
+5 -5
View File
@@ -33,7 +33,7 @@ using namespace IfcUtil;
bool IfcGeom::convert_shapes(const IfcBaseClass* l, ShapeList& r) {
#include "IfcRegisterConvertShapes.h"
Ifc::LogMessage("Error","No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
bool IfcGeom::is_shape_collection(const IfcBaseClass* l) {
@@ -45,21 +45,21 @@ const TopoDS_Shape* IfcGeom::convert_shape(const IfcBaseClass* l, TopoDS_Shape&
std::map<int,TopoDS_Shape>::const_iterator it = Cache::Shape.find(id);
if ( it != Cache::Shape.end() ) { r = it->second; return &(it->second); }
#include "IfcRegisterConvertShape.h"
Ifc::LogMessage("Error","No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return 0;
}
bool IfcGeom::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) {
#include "IfcRegisterConvertWire.h"
Ifc::LogMessage("Error","No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
bool IfcGeom::convert_face(const IfcBaseClass* l, TopoDS_Face& r) {
#include "IfcRegisterConvertFace.h"
Ifc::LogMessage("Error","No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
bool IfcGeom::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) {
#include "IfcRegisterConvertCurve.h"
Ifc::LogMessage("Error","No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
+1
View File
@@ -38,6 +38,7 @@
#include <gp_Trsf.hxx>
#include <gp_Trsf2d.hxx>
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcParse.h"
using namespace Ifc2x3;
+1 -1
View File
@@ -7,7 +7,7 @@
return &(Cache::Shape[id]); \
} \
} catch(...) { } \
Ifc::LogMessage("Error","Failed to convert:",l->entity); \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
return false; \
}
#include "IfcRegisterDef.h"
+1 -1
View File
@@ -4,7 +4,7 @@
try { \
return IfcGeom::convert((T*)l,r); \
} catch (...) { } \
Ifc::LogMessage("Error","Failed to convert:",l->entity); \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
return false; \
}
#include "IfcRegisterDef.h"