mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 22:33:33 +00:00
- 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
This commit is contained in:
@@ -20,6 +20,9 @@
|
|||||||
#ifndef IFCGEOM_H
|
#ifndef IFCGEOM_H
|
||||||
#define IFCGEOM_H
|
#define IFCGEOM_H
|
||||||
|
|
||||||
|
#define ALMOST_ZERO (1e-9)
|
||||||
|
#define ALMOST_THE_SAME(a,b) (fabs(a-b) < ALMOST_ZERO)
|
||||||
|
|
||||||
#include <gp_Pnt.hxx>
|
#include <gp_Pnt.hxx>
|
||||||
#include <gp_Vec.hxx>
|
#include <gp_Vec.hxx>
|
||||||
#include <gp_Trsf.hxx>
|
#include <gp_Trsf.hxx>
|
||||||
@@ -41,6 +44,7 @@ namespace IfcGeom {
|
|||||||
bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Face& result);
|
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 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);
|
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 {
|
namespace Cache {
|
||||||
void Purge();
|
void Purge();
|
||||||
void PurgeShapeCache();
|
void PurgeShapeCache();
|
||||||
|
|||||||
@@ -72,6 +72,9 @@
|
|||||||
|
|
||||||
#include <TopLoc_Location.hxx>
|
#include <TopLoc_Location.hxx>
|
||||||
|
|
||||||
|
#include <GProp_GProps.hxx>
|
||||||
|
#include <BRepGProp.hxx>
|
||||||
|
|
||||||
#include "../ifcgeom/IfcGeom.h"
|
#include "../ifcgeom/IfcGeom.h"
|
||||||
|
|
||||||
bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity,
|
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;
|
TopoDS_Shape s;
|
||||||
IfcGeom::convert_shape(*it2,s);
|
IfcGeom::convert_shape(*it2,s);
|
||||||
s.Move(trsf);
|
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);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,3 +151,8 @@ bool IfcGeom::profile_helper(int numVerts, float* verts, int numFillets, int* fi
|
|||||||
delete[] vertices;
|
delete[] vertices;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
float IfcGeom::shape_volume(const TopoDS_Shape& s) {
|
||||||
|
GProp_GProps System;
|
||||||
|
BRepGProp::VolumeProperties(s, System);
|
||||||
|
return (float) System.Mass();
|
||||||
|
}
|
||||||
@@ -59,7 +59,7 @@ IfcGeomObjects::IfcMesh::IfcMesh(int i, TopoDS_Shape s) {
|
|||||||
BRepTools::Clean(s);
|
BRepTools::Clean(s);
|
||||||
BRepMesh::Mesh(s,0.001f);
|
BRepMesh::Mesh(s,0.001f);
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
Ifc::LogMessage("Error","Failed to triangulate mesh");
|
Ifc::LogMessage("Error","Failed to triangulate mesh:",Ifc::EntityById(i)->entity);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TopExp_Explorer exp;
|
TopExp_Explorer exp;
|
||||||
@@ -267,7 +267,7 @@ IfcGeomObjects::IfcGeomObject* _get() {
|
|||||||
IfcGeom::convert_openings(ifc_product,openings,temp_shape,trsf);
|
IfcGeom::convert_openings(ifc_product,openings,temp_shape,trsf);
|
||||||
}
|
}
|
||||||
} catch( IfcParse::IfcException& e ) {
|
} catch( IfcParse::IfcException& e ) {
|
||||||
Ifc::LogMessage("Warning",e.what());
|
Ifc::LogMessage("Error",e.what(),ifc_product->entity);
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
Ifc::LogMessage("Error","Error processing openings for:",ifc_product->entity);
|
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);
|
return IfcGeomObjects::Init(fn, world_coords, 0, 0);
|
||||||
}
|
}
|
||||||
bool IfcGeomObjects::Init(const char* fn, bool world_coords, std::ostream* log1, std::ostream* log2) {
|
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;
|
use_world_coords = world_coords;
|
||||||
if ( !Ifc::Init(fn) ) return false;
|
if ( !Ifc::Init(fn) ) return false;
|
||||||
|
|
||||||
@@ -375,7 +375,7 @@ bool IfcGeomObjects::Init(const char* fn, bool world_coords, std::ostream* log1,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool IfcGeomObjects::Init(std::istream& f, int len, bool world_coords, std::ostream* log1, std::ostream* log2) {
|
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;
|
use_world_coords = world_coords;
|
||||||
if ( !Ifc::Init(f, len) ) return false;
|
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() {
|
int IfcGeomObjects::Progress() {
|
||||||
return 100 * done / total;
|
return 100 * done / total;
|
||||||
}
|
}
|
||||||
|
std::string IfcGeomObjects::GetLog() {
|
||||||
|
return Ifc::GetLog();
|
||||||
|
}
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ namespace IfcGeomObjects {
|
|||||||
bool Next();
|
bool Next();
|
||||||
int Progress();
|
int Progress();
|
||||||
const IfcObject* GetObject(int id);
|
const IfcObject* GetObject(int id);
|
||||||
|
std::string GetLog();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcPolygonalBoundedHalfSpace::ptr l, TopoDS_
|
|||||||
TopoDS_Shape halfspace;
|
TopoDS_Shape halfspace;
|
||||||
if ( ! IfcGeom::convert(reinterpret_pointer_cast<Ifc2x3::IfcPolygonalBoundedHalfSpace,Ifc2x3::IfcHalfSpaceSolid>(l),halfspace) ) return false;
|
if ( ! IfcGeom::convert(reinterpret_pointer_cast<Ifc2x3::IfcPolygonalBoundedHalfSpace,Ifc2x3::IfcHalfSpaceSolid>(l),halfspace) ) return false;
|
||||||
TopoDS_Wire wire;
|
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;
|
gp_Trsf trsf;
|
||||||
convert(l->Position(),trsf);
|
convert(l->Position(),trsf);
|
||||||
TopoDS_Shape extrusion = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,20000.0));
|
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) {
|
bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shape& shape) {
|
||||||
TopoDS_Shape s1, s2;
|
TopoDS_Shape s1, s2;
|
||||||
|
|
||||||
if ( ! IfcGeom::convert_shape(l->FirstOperand(),s1) )
|
if ( ! IfcGeom::convert_shape(l->FirstOperand(),s1) )
|
||||||
return false;
|
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);
|
shape = BRepAlgoAPI_Cut(s1,s2);
|
||||||
return true;
|
|
||||||
}
|
const float volume_after_subtraction = shape_volume(shape);
|
||||||
bool IfcGeom::convert(const Ifc2x3::IfcClosedShell::ptr l, TopoDS_Shape& shape) {
|
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
|
||||||
if ( ! IfcGeom::convert((Ifc2x3::IfcConnectedFaceSet::ptr)l,shape) ) return false;
|
Ifc::LogMessage("warning","Warning subtraction yields unchanged volume:",l->entity);
|
||||||
try {
|
|
||||||
ShapeFix_Solid solid;
|
|
||||||
solid.LimitTolerance(0.01);
|
|
||||||
shape = solid.SolidFromShell(TopoDS::Shell(shape));
|
|
||||||
} catch(...) {}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& shape) {
|
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;
|
if ( ! facesAdded ) return false;
|
||||||
builder.Perform();
|
builder.Perform();
|
||||||
shape = builder.SewedShape();
|
shape = builder.SewedShape();
|
||||||
|
try {
|
||||||
|
ShapeFix_Solid solid;
|
||||||
|
solid.LimitTolerance(0.01);
|
||||||
|
shape = solid.SolidFromShell(TopoDS::Shell(shape));
|
||||||
|
} catch(...) {}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, TopoDS_Shape& shape) {
|
bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, TopoDS_Shape& shape) {
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ bool IfcGeom::convert(const Ifc2x3::IfcCompositeCurve::ptr l, TopoDS_Wire& wire)
|
|||||||
const Ifc2x3::IfcCurve::ptr curve = (*it)->ParentCurve();
|
const Ifc2x3::IfcCurve::ptr curve = (*it)->ParentCurve();
|
||||||
TopoDS_Wire wire2;
|
TopoDS_Wire wire2;
|
||||||
if ( ! IfcGeom::convert_wire(curve,wire2) ) continue;
|
if ( ! IfcGeom::convert_wire(curve,wire2) ) continue;
|
||||||
ShapeFix_ShapeTolerance FTol;
|
//ShapeFix_ShapeTolerance FTol;
|
||||||
FTol.SetTolerance(wire2, 0.01, TopAbs_WIRE);
|
//FTol.SetTolerance(wire2, 0.01, TopAbs_WIRE);
|
||||||
w.Add(wire2);
|
w.Add(wire2);
|
||||||
if ( w.Error() != BRepBuilderAPI_WireDone ) {
|
if ( w.Error() != BRepBuilderAPI_WireDone ) {
|
||||||
Ifc::LogMessage("Error","Failed to join curve segments:",l->entity);
|
Ifc::LogMessage("Error","Failed to join curve segments:",l->entity);
|
||||||
|
|||||||
@@ -39,7 +39,6 @@
|
|||||||
using namespace Ifc2x3;
|
using namespace Ifc2x3;
|
||||||
|
|
||||||
SHAPE(IfcExtrudedAreaSolid);
|
SHAPE(IfcExtrudedAreaSolid);
|
||||||
SHAPE(IfcClosedShell);
|
|
||||||
SHAPE(IfcConnectedFaceSet);
|
SHAPE(IfcConnectedFaceSet);
|
||||||
SHAPE(IfcFacetedBrep);
|
SHAPE(IfcFacetedBrep);
|
||||||
SHAPE(IfcShellBasedSurfaceModel);
|
SHAPE(IfcShellBasedSurfaceModel);
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
#define SHAPE(T) \
|
#define SHAPE(T) \
|
||||||
if ( l->is(T::Class()) ) { \
|
if ( l->is(T::Class()) ) { \
|
||||||
try { \
|
try { \
|
||||||
bool b = convert((T*)l,r); \
|
if ( convert((T*)l,r) ) { \
|
||||||
if ( b ) { \
|
|
||||||
Cache::Shape[l->entity->id()] = r; \
|
Cache::Shape[l->entity->id()] = r; \
|
||||||
return true; \
|
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"
|
#include "IfcRegisterDef.h"
|
||||||
|
|
||||||
|
|||||||
@@ -677,10 +677,11 @@ void Ifc::Dispose() {
|
|||||||
bytype.clear();
|
bytype.clear();
|
||||||
byid.clear();
|
byid.clear();
|
||||||
byref.clear();
|
byref.clear();
|
||||||
file->Close();
|
file->Close();
|
||||||
delete file;
|
delete file;
|
||||||
delete tokens;
|
delete tokens;
|
||||||
offsets.clear();
|
offsets.clear();
|
||||||
|
log_stream.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
float UnitPrefixToValue( Ifc2x3::IfcSIPrefix::IfcSIPrefix v ) {
|
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 if ( v == Ifc2x3::IfcSIPrefix::ATTO ) return (float) 1e-18;
|
||||||
else return 1.0f;
|
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) {
|
void Ifc::LogMessage(const std::string& type, const std::string& message, const IfcAbstractEntityPtr entity) {
|
||||||
if ( log2 ) {
|
if ( log2 ) {
|
||||||
(*log2) << "[" << type << "] " << message << std::endl;
|
(*log2) << "[" << type << "] " << message << std::endl;
|
||||||
if ( entity ) (*log2) << entity->toString() << std::endl;
|
if ( entity ) (*log2) << entity->toString() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::string Ifc::GetLog() {
|
||||||
|
return log_stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
File* Ifc::file = 0;
|
File* Ifc::file = 0;
|
||||||
std::ostream* Ifc::log1 = 0;
|
std::ostream* Ifc::log1 = 0;
|
||||||
@@ -722,3 +732,4 @@ MapEntitiesByType Ifc::bytype;
|
|||||||
MapEntityById Ifc::byid;
|
MapEntityById Ifc::byid;
|
||||||
MapEntitiesByRef Ifc::byref;
|
MapEntitiesByRef Ifc::byref;
|
||||||
MapOffsetById Ifc::offsets;
|
MapOffsetById Ifc::offsets;
|
||||||
|
std::stringstream Ifc::log_stream;
|
||||||
|
|||||||
@@ -222,6 +222,7 @@ private:
|
|||||||
static unsigned int lastId;
|
static unsigned int lastId;
|
||||||
static std::ostream* log1;
|
static std::ostream* log1;
|
||||||
static std::ostream* log2;
|
static std::ostream* log2;
|
||||||
|
static std::stringstream log_stream;
|
||||||
public:
|
public:
|
||||||
static void SetOutput(std::ostream* l1, std::ostream* l2);
|
static void SetOutput(std::ostream* l1, std::ostream* l2);
|
||||||
static void LogMessage(const std::string& type, const std::string& message, const IfcAbstractEntityPtr entity=0);
|
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(const std::string& fn);
|
||||||
static bool Init(std::istream& fn, int len);
|
static bool Init(std::istream& fn, int len);
|
||||||
static bool Init(IfcParse::File* f);
|
static bool Init(IfcParse::File* f);
|
||||||
|
static std::string GetLog();
|
||||||
static void Dispose();
|
static void Dispose();
|
||||||
static float LengthUnit;
|
static float LengthUnit;
|
||||||
static float PlaneAngleUnit;
|
static float PlaneAngleUnit;
|
||||||
|
|||||||
@@ -47,4 +47,6 @@ namespace IfcGeomObjects {
|
|||||||
int Progress();
|
int Progress();
|
||||||
const IfcObject* GetObject(int id);
|
const IfcObject* GetObject(int id);
|
||||||
bool CleanUp();
|
bool CleanUp();
|
||||||
|
std::string GetLog();
|
||||||
|
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user