diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index 0cf6c0bfd3..540c9fd2ae 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -20,6 +20,9 @@ #ifndef IFCGEOM_H #define IFCGEOM_H +#define ALMOST_ZERO (1e-9) +#define ALMOST_THE_SAME(a,b) (fabs(a-b) < ALMOST_ZERO) + #include #include #include @@ -41,6 +44,7 @@ namespace IfcGeom { bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Face& result); bool convert_openings(const Ifc2x3::IfcProduct::ptr L, const Ifc2x3::IfcRelVoidsElement::list& openings, TopoDS_Shape& result, const gp_Trsf& trsf); bool profile_helper(int numVerts, float* verts, int numFillets, int* filletIndices, float* filletRadii, gp_Trsf2d trsf, TopoDS_Face& face); + float shape_volume(const TopoDS_Shape& s); namespace Cache { void Purge(); void PurgeShapeCache(); diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 556dda313a..4497e9e327 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -72,6 +72,9 @@ #include +#include +#include + #include "../ifcgeom/IfcGeom.h" bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, @@ -91,7 +94,14 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, TopoDS_Shape s; IfcGeom::convert_shape(*it2,s); s.Move(trsf); + const float opening_volume = shape_volume(s); + if ( opening_volume <= ALMOST_ZERO ) + Ifc::LogMessage("warning","Empty solid for:",fes->entity); + const float original_shape_volume = shape_volume(result); result = BRepAlgoAPI_Cut(result,s); + const float volume_after_subtraction = shape_volume(result); + if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) ) + Ifc::LogMessage("warning","Warning subtraction yields unchanged volume:",entity->entity); } } } @@ -140,4 +150,9 @@ bool IfcGeom::profile_helper(int numVerts, float* verts, int numFillets, int* fi delete[] vertices; return true; +} +float IfcGeom::shape_volume(const TopoDS_Shape& s) { + GProp_GProps System; + BRepGProp::VolumeProperties(s, System); + return (float) System.Mass(); } \ No newline at end of file diff --git a/src/ifcgeom/IfcGeomObjects.cpp b/src/ifcgeom/IfcGeomObjects.cpp index c65555c61f..b2f1d57d22 100644 --- a/src/ifcgeom/IfcGeomObjects.cpp +++ b/src/ifcgeom/IfcGeomObjects.cpp @@ -59,7 +59,7 @@ IfcGeomObjects::IfcMesh::IfcMesh(int i, TopoDS_Shape s) { BRepTools::Clean(s); BRepMesh::Mesh(s,0.001f); } catch(...) { - Ifc::LogMessage("Error","Failed to triangulate mesh"); + Ifc::LogMessage("Error","Failed to triangulate mesh:",Ifc::EntityById(i)->entity); return; } TopExp_Explorer exp; @@ -267,7 +267,7 @@ IfcGeomObjects::IfcGeomObject* _get() { IfcGeom::convert_openings(ifc_product,openings,temp_shape,trsf); } } catch( IfcParse::IfcException& e ) { - Ifc::LogMessage("Warning",e.what()); + Ifc::LogMessage("Error",e.what(),ifc_product->entity); } catch(...) { Ifc::LogMessage("Error","Error processing openings for:",ifc_product->entity); } @@ -357,7 +357,7 @@ bool IfcGeomObjects::Init(const char* fn, bool world_coords) { return IfcGeomObjects::Init(fn, world_coords, 0, 0); } bool IfcGeomObjects::Init(const char* fn, bool world_coords, std::ostream* log1, std::ostream* log2) { - if ( log1 || log2 ) Ifc::SetOutput(log1,log2); + Ifc::SetOutput(log1,log2); use_world_coords = world_coords; if ( !Ifc::Init(fn) ) return false; @@ -375,7 +375,7 @@ bool IfcGeomObjects::Init(const char* fn, bool world_coords, std::ostream* log1, return true; } bool IfcGeomObjects::Init(std::istream& f, int len, bool world_coords, std::ostream* log1, std::ostream* log2) { - if ( log1 || log2 ) Ifc::SetOutput(log1,log2); + Ifc::SetOutput(log1,log2); use_world_coords = world_coords; if ( !Ifc::Init(f, len) ) return false; @@ -395,3 +395,6 @@ bool IfcGeomObjects::Init(std::istream& f, int len, bool world_coords, std::ostr int IfcGeomObjects::Progress() { return 100 * done / total; } +std::string IfcGeomObjects::GetLog() { + return Ifc::GetLog(); +} diff --git a/src/ifcgeom/IfcGeomObjects.h b/src/ifcgeom/IfcGeomObjects.h index 42169ae500..da60d3f8f6 100644 --- a/src/ifcgeom/IfcGeomObjects.h +++ b/src/ifcgeom/IfcGeomObjects.h @@ -113,6 +113,7 @@ namespace IfcGeomObjects { bool Next(); int Progress(); const IfcObject* GetObject(int id); + std::string GetLog(); } diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index 529f66d2d7..61691d497d 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -125,7 +125,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcPolygonalBoundedHalfSpace::ptr l, TopoDS_ TopoDS_Shape halfspace; if ( ! IfcGeom::convert(reinterpret_pointer_cast(l),halfspace) ) return false; TopoDS_Wire wire; - if ( ! IfcGeom::convert_wire(l->PolygonalBoundary(),wire) ) return false; + if ( ! IfcGeom::convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false; gp_Trsf trsf; convert(l->Position(),trsf); TopoDS_Shape extrusion = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,20000.0)); @@ -150,20 +150,30 @@ bool IfcGeom::convert(const Ifc2x3::IfcShellBasedSurfaceModel::ptr l, TopoDS_Sha } bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shape& shape) { TopoDS_Shape s1, s2; + if ( ! IfcGeom::convert_shape(l->FirstOperand(),s1) ) return false; - if ( ! IfcGeom::convert_shape(l->SecondOperand(),s2) ) - return false; + + const float first_operand_volume = shape_volume(s1); + if ( first_operand_volume <= ALMOST_ZERO ) + Ifc::LogMessage("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->SecondOperand()->entity); + return true; + } + + const float second_operand_volume = shape_volume(s2); + if ( second_operand_volume <= ALMOST_ZERO ) + Ifc::LogMessage("warning","Empty solid for:",l->SecondOperand()->entity); + shape = BRepAlgoAPI_Cut(s1,s2); - return true; -} -bool IfcGeom::convert(const Ifc2x3::IfcClosedShell::ptr l, TopoDS_Shape& shape) { - if ( ! IfcGeom::convert((Ifc2x3::IfcConnectedFaceSet::ptr)l,shape) ) return false; - try { - ShapeFix_Solid solid; - solid.LimitTolerance(0.01); - shape = solid.SolidFromShell(TopoDS::Shell(shape)); - } catch(...) {} + + const float volume_after_subtraction = shape_volume(shape); + if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) ) + Ifc::LogMessage("warning","Warning subtraction yields unchanged volume:",l->entity); + return true; } bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& shape) { @@ -183,6 +193,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh if ( ! facesAdded ) return false; builder.Perform(); shape = builder.SewedShape(); + try { + ShapeFix_Solid solid; + solid.LimitTolerance(0.01); + shape = solid.SolidFromShell(TopoDS::Shell(shape)); + } catch(...) {} return true; } bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, TopoDS_Shape& shape) { diff --git a/src/ifcgeom/IfcGeomWires.cpp b/src/ifcgeom/IfcGeomWires.cpp index edacb470e4..6d908ffbf6 100644 --- a/src/ifcgeom/IfcGeomWires.cpp +++ b/src/ifcgeom/IfcGeomWires.cpp @@ -81,8 +81,8 @@ 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) ) continue; - ShapeFix_ShapeTolerance FTol; - FTol.SetTolerance(wire2, 0.01, TopAbs_WIRE); + //ShapeFix_ShapeTolerance FTol; + //FTol.SetTolerance(wire2, 0.01, TopAbs_WIRE); w.Add(wire2); if ( w.Error() != BRepBuilderAPI_WireDone ) { Ifc::LogMessage("Error","Failed to join curve segments:",l->entity); diff --git a/src/ifcgeom/IfcRegister.h b/src/ifcgeom/IfcRegister.h index be851e1581..b17fc1a583 100644 --- a/src/ifcgeom/IfcRegister.h +++ b/src/ifcgeom/IfcRegister.h @@ -39,7 +39,6 @@ using namespace Ifc2x3; SHAPE(IfcExtrudedAreaSolid); -SHAPE(IfcClosedShell); SHAPE(IfcConnectedFaceSet); SHAPE(IfcFacetedBrep); SHAPE(IfcShellBasedSurfaceModel); diff --git a/src/ifcgeom/IfcRegisterConvertShape.h b/src/ifcgeom/IfcRegisterConvertShape.h index 0940020a91..9655755d6b 100644 --- a/src/ifcgeom/IfcRegisterConvertShape.h +++ b/src/ifcgeom/IfcRegisterConvertShape.h @@ -2,12 +2,13 @@ #define SHAPE(T) \ if ( l->is(T::Class()) ) { \ try { \ - bool b = convert((T*)l,r); \ - if ( b ) { \ + if ( convert((T*)l,r) ) { \ Cache::Shape[l->entity->id()] = r; \ return true; \ - } else { return false; }\ - } catch(...) { Ifc::LogMessage("Error","Failed to convert:",l->entity); } \ + } \ + } catch(...) { } \ + Ifc::LogMessage("Error","Failed to convert:",l->entity); \ + return false; \ } #include "IfcRegisterDef.h" diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index 7505296eb3..ca7964ffd8 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -677,10 +677,11 @@ void Ifc::Dispose() { bytype.clear(); byid.clear(); byref.clear(); - file->Close(); + file->Close(); delete file; delete tokens; offsets.clear(); + log_stream.clear(); } float UnitPrefixToValue( Ifc2x3::IfcSIPrefix::IfcSIPrefix v ) { @@ -702,13 +703,22 @@ float UnitPrefixToValue( Ifc2x3::IfcSIPrefix::IfcSIPrefix v ) { else if ( v == Ifc2x3::IfcSIPrefix::ATTO ) return (float) 1e-18; else return 1.0f; } -void Ifc::SetOutput(std::ostream* l1, std::ostream* l2) { log1 = l1; log2 = l2; } +void Ifc::SetOutput(std::ostream* l1, std::ostream* l2) { + log1 = l1; + log2 = l2; + if ( ! log2 ) { + log2 = &log_stream; + } +} void Ifc::LogMessage(const std::string& type, const std::string& message, const IfcAbstractEntityPtr entity) { if ( log2 ) { (*log2) << "[" << type << "] " << message << std::endl; if ( entity ) (*log2) << entity->toString() << std::endl; } } +std::string Ifc::GetLog() { + return log_stream.str(); +} File* Ifc::file = 0; std::ostream* Ifc::log1 = 0; @@ -722,3 +732,4 @@ MapEntitiesByType Ifc::bytype; MapEntityById Ifc::byid; MapEntitiesByRef Ifc::byref; MapOffsetById Ifc::offsets; +std::stringstream Ifc::log_stream; diff --git a/src/ifcparse/IfcParse.h b/src/ifcparse/IfcParse.h index 6ac14909d7..effeae5bb6 100644 --- a/src/ifcparse/IfcParse.h +++ b/src/ifcparse/IfcParse.h @@ -222,6 +222,7 @@ private: static unsigned int lastId; static std::ostream* log1; static std::ostream* log2; + static std::stringstream log_stream; public: static void SetOutput(std::ostream* l1, std::ostream* l2); static void LogMessage(const std::string& type, const std::string& message, const IfcAbstractEntityPtr entity=0); @@ -243,6 +244,7 @@ public: static bool Init(const std::string& fn); static bool Init(std::istream& fn, int len); static bool Init(IfcParse::File* f); + static std::string GetLog(); static void Dispose(); static float LengthUnit; static float PlaneAngleUnit; diff --git a/src/ifcwrap/Interface.h b/src/ifcwrap/Interface.h index 908592449c..4428bac54c 100644 --- a/src/ifcwrap/Interface.h +++ b/src/ifcwrap/Interface.h @@ -47,4 +47,6 @@ namespace IfcGeomObjects { int Progress(); const IfcObject* GetObject(int id); bool CleanUp(); + std::string GetLog(); + }; \ No newline at end of file