Skip to content

Commit 34efb48

Browse files
committed
- Provide logging information to IfcBlender
- Disallow open curves for IfcPolygonalBoundedHalfSpace [fixes #3405490 Incorrectly rendered wall in FZK-Haus-EliteCAD.ifc] - Disable tolerance on IfcCompositeCurve - Try to convert IfcConnectedFaceSets to TopoDS_Solids regardless of whether they are open or closed shells, improves openings in IFC files exported by Revit - Provide debugging information based on shape volume on IfcBooleanClippingResult and IfcOpeningElement
1 parent e6c5e5e commit 34efb48

11 files changed

Lines changed: 78 additions & 25 deletions

src/ifcgeom/IfcGeom.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#ifndef IFCGEOM_H
2121
#define IFCGEOM_H
2222

23+
#define ALMOST_ZERO (1e-9)
24+
#define ALMOST_THE_SAME(a,b) (fabs(a-b) < ALMOST_ZERO)
25+
2326
#include <gp_Pnt.hxx>
2427
#include <gp_Vec.hxx>
2528
#include <gp_Trsf.hxx>
@@ -41,6 +44,7 @@ namespace IfcGeom {
4144
bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Face& result);
4245
bool convert_openings(const Ifc2x3::IfcProduct::ptr L, const Ifc2x3::IfcRelVoidsElement::list& openings, TopoDS_Shape& result, const gp_Trsf& trsf);
4346
bool profile_helper(int numVerts, float* verts, int numFillets, int* filletIndices, float* filletRadii, gp_Trsf2d trsf, TopoDS_Face& face);
47+
float shape_volume(const TopoDS_Shape& s);
4448
namespace Cache {
4549
void Purge();
4650
void PurgeShapeCache();

src/ifcgeom/IfcGeomFunctions.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@
7272

7373
#include <TopLoc_Location.hxx>
7474

75+
#include <GProp_GProps.hxx>
76+
#include <BRepGProp.hxx>
77+
7578
#include "../ifcgeom/IfcGeom.h"
7679

7780
bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity,
@@ -91,7 +94,14 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity,
9194
TopoDS_Shape s;
9295
IfcGeom::convert_shape(*it2,s);
9396
s.Move(trsf);
97+
const float opening_volume = shape_volume(s);
98+
if ( opening_volume <= ALMOST_ZERO )
99+
Ifc::LogMessage("warning","Empty solid for:",fes->entity);
100+
const float original_shape_volume = shape_volume(result);
94101
result = BRepAlgoAPI_Cut(result,s);
102+
const float volume_after_subtraction = shape_volume(result);
103+
if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) )
104+
Ifc::LogMessage("warning","Warning subtraction yields unchanged volume:",entity->entity);
95105
}
96106
}
97107
}
@@ -140,4 +150,9 @@ bool IfcGeom::profile_helper(int numVerts, float* verts, int numFillets, int* fi
140150

141151
delete[] vertices;
142152
return true;
153+
}
154+
float IfcGeom::shape_volume(const TopoDS_Shape& s) {
155+
GProp_GProps System;
156+
BRepGProp::VolumeProperties(s, System);
157+
return (float) System.Mass();
143158
}

src/ifcgeom/IfcGeomObjects.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ IfcGeomObjects::IfcMesh::IfcMesh(int i, TopoDS_Shape s) {
5959
BRepTools::Clean(s);
6060
BRepMesh::Mesh(s,0.001f);
6161
} catch(...) {
62-
Ifc::LogMessage("Error","Failed to triangulate mesh");
62+
Ifc::LogMessage("Error","Failed to triangulate mesh:",Ifc::EntityById(i)->entity);
6363
return;
6464
}
6565
TopExp_Explorer exp;
@@ -267,7 +267,7 @@ IfcGeomObjects::IfcGeomObject* _get() {
267267
IfcGeom::convert_openings(ifc_product,openings,temp_shape,trsf);
268268
}
269269
} catch( IfcParse::IfcException& e ) {
270-
Ifc::LogMessage("Warning",e.what());
270+
Ifc::LogMessage("Error",e.what(),ifc_product->entity);
271271
} catch(...) {
272272
Ifc::LogMessage("Error","Error processing openings for:",ifc_product->entity);
273273
}
@@ -357,7 +357,7 @@ bool IfcGeomObjects::Init(const char* fn, bool world_coords) {
357357
return IfcGeomObjects::Init(fn, world_coords, 0, 0);
358358
}
359359
bool IfcGeomObjects::Init(const char* fn, bool world_coords, std::ostream* log1, std::ostream* log2) {
360-
if ( log1 || log2 ) Ifc::SetOutput(log1,log2);
360+
Ifc::SetOutput(log1,log2);
361361
use_world_coords = world_coords;
362362
if ( !Ifc::Init(fn) ) return false;
363363

@@ -375,7 +375,7 @@ bool IfcGeomObjects::Init(const char* fn, bool world_coords, std::ostream* log1,
375375
return true;
376376
}
377377
bool IfcGeomObjects::Init(std::istream& f, int len, bool world_coords, std::ostream* log1, std::ostream* log2) {
378-
if ( log1 || log2 ) Ifc::SetOutput(log1,log2);
378+
Ifc::SetOutput(log1,log2);
379379
use_world_coords = world_coords;
380380
if ( !Ifc::Init(f, len) ) return false;
381381

@@ -395,3 +395,6 @@ bool IfcGeomObjects::Init(std::istream& f, int len, bool world_coords, std::ostr
395395
int IfcGeomObjects::Progress() {
396396
return 100 * done / total;
397397
}
398+
std::string IfcGeomObjects::GetLog() {
399+
return Ifc::GetLog();
400+
}

src/ifcgeom/IfcGeomObjects.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ namespace IfcGeomObjects {
113113
bool Next();
114114
int Progress();
115115
const IfcObject* GetObject(int id);
116+
std::string GetLog();
116117

117118
}
118119

src/ifcgeom/IfcGeomShapes.cpp

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcPolygonalBoundedHalfSpace::ptr l, TopoDS_
125125
TopoDS_Shape halfspace;
126126
if ( ! IfcGeom::convert(reinterpret_pointer_cast<Ifc2x3::IfcPolygonalBoundedHalfSpace,Ifc2x3::IfcHalfSpaceSolid>(l),halfspace) ) return false;
127127
TopoDS_Wire wire;
128-
if ( ! IfcGeom::convert_wire(l->PolygonalBoundary(),wire) ) return false;
128+
if ( ! IfcGeom::convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false;
129129
gp_Trsf trsf;
130130
convert(l->Position(),trsf);
131131
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
150150
}
151151
bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shape& shape) {
152152
TopoDS_Shape s1, s2;
153+
153154
if ( ! IfcGeom::convert_shape(l->FirstOperand(),s1) )
154155
return false;
155-
if ( ! IfcGeom::convert_shape(l->SecondOperand(),s2) )
156-
return false;
156+
157+
const float first_operand_volume = shape_volume(s1);
158+
if ( first_operand_volume <= ALMOST_ZERO )
159+
Ifc::LogMessage("warning","Empty solid for:",l->FirstOperand()->entity);
160+
161+
if ( ! IfcGeom::convert_shape(l->SecondOperand(),s2) ) {
162+
shape = s1;
163+
Ifc::LogMessage("Error","Failed to convert SecondOperand of:",l->SecondOperand()->entity);
164+
return true;
165+
}
166+
167+
const float second_operand_volume = shape_volume(s2);
168+
if ( second_operand_volume <= ALMOST_ZERO )
169+
Ifc::LogMessage("warning","Empty solid for:",l->SecondOperand()->entity);
170+
157171
shape = BRepAlgoAPI_Cut(s1,s2);
158-
return true;
159-
}
160-
bool IfcGeom::convert(const Ifc2x3::IfcClosedShell::ptr l, TopoDS_Shape& shape) {
161-
if ( ! IfcGeom::convert((Ifc2x3::IfcConnectedFaceSet::ptr)l,shape) ) return false;
162-
try {
163-
ShapeFix_Solid solid;
164-
solid.LimitTolerance(0.01);
165-
shape = solid.SolidFromShell(TopoDS::Shell(shape));
166-
} catch(...) {}
172+
173+
const float volume_after_subtraction = shape_volume(shape);
174+
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
175+
Ifc::LogMessage("warning","Warning subtraction yields unchanged volume:",l->entity);
176+
167177
return true;
168178
}
169179
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
183193
if ( ! facesAdded ) return false;
184194
builder.Perform();
185195
shape = builder.SewedShape();
196+
try {
197+
ShapeFix_Solid solid;
198+
solid.LimitTolerance(0.01);
199+
shape = solid.SolidFromShell(TopoDS::Shell(shape));
200+
} catch(...) {}
186201
return true;
187202
}
188203
bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, TopoDS_Shape& shape) {

src/ifcgeom/IfcGeomWires.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ bool IfcGeom::convert(const Ifc2x3::IfcCompositeCurve::ptr l, TopoDS_Wire& wire)
8181
const Ifc2x3::IfcCurve::ptr curve = (*it)->ParentCurve();
8282
TopoDS_Wire wire2;
8383
if ( ! IfcGeom::convert_wire(curve,wire2) ) continue;
84-
ShapeFix_ShapeTolerance FTol;
85-
FTol.SetTolerance(wire2, 0.01, TopAbs_WIRE);
84+
//ShapeFix_ShapeTolerance FTol;
85+
//FTol.SetTolerance(wire2, 0.01, TopAbs_WIRE);
8686
w.Add(wire2);
8787
if ( w.Error() != BRepBuilderAPI_WireDone ) {
8888
Ifc::LogMessage("Error","Failed to join curve segments:",l->entity);

src/ifcgeom/IfcRegister.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
using namespace Ifc2x3;
4040

4141
SHAPE(IfcExtrudedAreaSolid);
42-
SHAPE(IfcClosedShell);
4342
SHAPE(IfcConnectedFaceSet);
4443
SHAPE(IfcFacetedBrep);
4544
SHAPE(IfcShellBasedSurfaceModel);

src/ifcgeom/IfcRegisterConvertShape.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
#define SHAPE(T) \
33
if ( l->is(T::Class()) ) { \
44
try { \
5-
bool b = convert((T*)l,r); \
6-
if ( b ) { \
5+
if ( convert((T*)l,r) ) { \
76
Cache::Shape[l->entity->id()] = r; \
87
return true; \
9-
} else { return false; }\
10-
} catch(...) { Ifc::LogMessage("Error","Failed to convert:",l->entity); } \
8+
} \
9+
} catch(...) { } \
10+
Ifc::LogMessage("Error","Failed to convert:",l->entity); \
11+
return false; \
1112
}
1213
#include "IfcRegisterDef.h"
1314

src/ifcparse/IfcParse.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -677,10 +677,11 @@ void Ifc::Dispose() {
677677
bytype.clear();
678678
byid.clear();
679679
byref.clear();
680-
file->Close();
680+
file->Close();
681681
delete file;
682682
delete tokens;
683683
offsets.clear();
684+
log_stream.clear();
684685
}
685686

686687
float UnitPrefixToValue( Ifc2x3::IfcSIPrefix::IfcSIPrefix v ) {
@@ -702,13 +703,22 @@ float UnitPrefixToValue( Ifc2x3::IfcSIPrefix::IfcSIPrefix v ) {
702703
else if ( v == Ifc2x3::IfcSIPrefix::ATTO ) return (float) 1e-18;
703704
else return 1.0f;
704705
}
705-
void Ifc::SetOutput(std::ostream* l1, std::ostream* l2) { log1 = l1; log2 = l2; }
706+
void Ifc::SetOutput(std::ostream* l1, std::ostream* l2) {
707+
log1 = l1;
708+
log2 = l2;
709+
if ( ! log2 ) {
710+
log2 = &log_stream;
711+
}
712+
}
706713
void Ifc::LogMessage(const std::string& type, const std::string& message, const IfcAbstractEntityPtr entity) {
707714
if ( log2 ) {
708715
(*log2) << "[" << type << "] " << message << std::endl;
709716
if ( entity ) (*log2) << entity->toString() << std::endl;
710717
}
711718
}
719+
std::string Ifc::GetLog() {
720+
return log_stream.str();
721+
}
712722

713723
File* Ifc::file = 0;
714724
std::ostream* Ifc::log1 = 0;
@@ -722,3 +732,4 @@ MapEntitiesByType Ifc::bytype;
722732
MapEntityById Ifc::byid;
723733
MapEntitiesByRef Ifc::byref;
724734
MapOffsetById Ifc::offsets;
735+
std::stringstream Ifc::log_stream;

src/ifcparse/IfcParse.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ class Ifc {
222222
static unsigned int lastId;
223223
static std::ostream* log1;
224224
static std::ostream* log2;
225+
static std::stringstream log_stream;
225226
public:
226227
static void SetOutput(std::ostream* l1, std::ostream* l2);
227228
static void LogMessage(const std::string& type, const std::string& message, const IfcAbstractEntityPtr entity=0);
@@ -243,6 +244,7 @@ class Ifc {
243244
static bool Init(const std::string& fn);
244245
static bool Init(std::istream& fn, int len);
245246
static bool Init(IfcParse::File* f);
247+
static std::string GetLog();
246248
static void Dispose();
247249
static float LengthUnit;
248250
static float PlaneAngleUnit;

0 commit comments

Comments
 (0)