mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-17 02:49:12 +00:00
- IfcGeom: Major performance improvement by only sewing faces of IfcConnectedFaceSets when needed for boolean operations
- Automatic tests for several well known IFC files on the Internet - IfcBlender: Make visibility in render consistent with 3d view - Some compatibility for Ifc2x files with IfcShapeRepresentations and RepresentationIdentifier 'IAI'
This commit is contained in:
@@ -78,6 +78,7 @@ def import_ifc(filename, use_names, process_relations):
|
||||
else:
|
||||
valid_file = IfcImport.Init(filename)
|
||||
if not valid_file:
|
||||
IfcImport.CleanUp()
|
||||
return False
|
||||
print("Done reading file")
|
||||
id_to_object = {}
|
||||
@@ -136,6 +137,7 @@ def import_ifc(filename, use_names, process_relations):
|
||||
ob.id, ob_guid, ob_name, ob_type
|
||||
|
||||
bob.hide = ob_type == 'IfcSpace' or ob_type == 'IfcOpeningElement'
|
||||
bob.hide_render = bob.hide
|
||||
|
||||
if ob.id not in id_to_object: id_to_object[ob.id] = []
|
||||
id_to_object[ob.id].append(bob)
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
#include "../ifcgeom/IfcShapeList.h"
|
||||
|
||||
#define FACESET_AS_COMPOUND 1
|
||||
|
||||
namespace IfcGeom {
|
||||
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
|
||||
bool convert_shapes(const IfcUtil::IfcBaseClass* L, ShapeList& result);
|
||||
@@ -51,6 +53,9 @@ namespace IfcGeom {
|
||||
bool convert_curve(const IfcUtil::IfcBaseClass* L, Handle(Geom_Curve)& result);
|
||||
bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Face& result);
|
||||
bool convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes);
|
||||
bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid);
|
||||
bool is_compound(const TopoDS_Shape& shape);
|
||||
const TopoDS_Shape& ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid);
|
||||
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 {
|
||||
|
||||
@@ -82,6 +82,40 @@
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
bool IfcGeom::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) {
|
||||
BRepOffsetAPI_Sewing builder;
|
||||
builder.SetTolerance(0.01);
|
||||
TopExp_Explorer exp(compound,TopAbs_FACE);
|
||||
if ( ! exp.More() ) return false;
|
||||
for ( ; exp.More(); exp.Next() ) {
|
||||
TopoDS_Face face = TopoDS::Face(exp.Current());
|
||||
builder.Add(face);
|
||||
}
|
||||
builder.Perform();
|
||||
shape = builder.SewedShape();
|
||||
try {
|
||||
ShapeFix_Solid sf_solid;
|
||||
sf_solid.LimitTolerance(0.01);
|
||||
shape = sf_solid.SolidFromShell(TopoDS::Shell(shape));
|
||||
} catch(...) {}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::is_compound(const TopoDS_Shape& shape) {
|
||||
bool has_solids = TopExp_Explorer(shape,TopAbs_SHELL).More() != 0;
|
||||
bool has_shells = TopExp_Explorer(shape,TopAbs_SHELL).More() != 0;
|
||||
bool has_compounds = TopExp_Explorer(shape,TopAbs_COMPOUND).More() != 0;
|
||||
bool has_faces = TopExp_Explorer(shape,TopAbs_FACE).More() != 0;
|
||||
return has_compounds && has_faces && !has_solids && !has_shells;
|
||||
}
|
||||
|
||||
const TopoDS_Shape& IfcGeom::ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid) {
|
||||
const bool is_comp = IfcGeom::is_compound(shape);
|
||||
if ( ! is_comp ) return shape;
|
||||
IfcGeom::create_solid_from_compound(shape,solid);
|
||||
return solid;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings,
|
||||
const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes) {
|
||||
// Iterate over IfcOpeningElements
|
||||
@@ -116,7 +150,8 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x
|
||||
|
||||
// Iterate over the shapes of the IfcProduct
|
||||
for ( IfcGeom::ShapeList::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) {
|
||||
const TopoDS_Shape& entity_shape_unlocated = *(it3->second);
|
||||
TopoDS_Shape entity_shape_solid;
|
||||
const TopoDS_Shape& entity_shape_unlocated = IfcGeom::ensure_fit_for_subtraction(*(it3->second),entity_shape_solid);
|
||||
const gp_GTrsf& entity_shape_gtrsf = *(it3->first);
|
||||
TopoDS_Shape entity_shape;
|
||||
if ( entity_shape_gtrsf.Form() == gp_Other ) {
|
||||
@@ -128,7 +163,8 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x
|
||||
|
||||
// Iterate over the shapes of the IfcOpeningElements
|
||||
for ( IfcGeom::ShapeList::const_iterator it4 = opening_shapes.begin(); it4 != opening_shapes.end(); ++ it4 ) {
|
||||
const TopoDS_Shape& opening_shape_unlocated = *(it4->second);
|
||||
TopoDS_Shape opening_shape_solid;
|
||||
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);
|
||||
@@ -143,12 +179,16 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x
|
||||
|
||||
const float original_shape_volume = shape_volume(entity_shape);
|
||||
|
||||
entity_shape = BRepAlgoAPI_Cut(entity_shape,opening_shape);
|
||||
BRepAlgoAPI_Cut brep_cut(entity_shape,opening_shape);
|
||||
|
||||
if ( brep_cut.IsDone() ) {
|
||||
entity_shape = brep_cut;
|
||||
|
||||
const float volume_after_subtraction = shape_volume(entity_shape);
|
||||
const float volume_after_subtraction = shape_volume(entity_shape);
|
||||
|
||||
if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) )
|
||||
Ifc::LogMessage("warning","Warning subtraction yields unchanged volume:",entity->entity);
|
||||
if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) )
|
||||
Ifc::LogMessage("warning","Warning subtraction yields unchanged volume:",entity->entity);
|
||||
}
|
||||
}
|
||||
cut_shapes.push_back(IfcGeom::LocationShape(new gp_GTrsf(),new TopoDS_Shape(entity_shape)));
|
||||
}
|
||||
|
||||
@@ -299,10 +299,15 @@ IfcGeomObjects::IfcGeomObject* _get() {
|
||||
|
||||
// Has the list of IfcProducts for this representation been initialized?
|
||||
if ( ! entities ) {
|
||||
if ( shaperep->RepresentationIdentifier() != "Body" &&
|
||||
shaperep->RepresentationIdentifier() != "Facetation" ) {
|
||||
_nextShape();
|
||||
continue;
|
||||
if ( shaperep->hasRepresentationIdentifier() ) {
|
||||
const std::string representation_identifier = shaperep->RepresentationIdentifier();
|
||||
if ( shaperep->hasRepresentationType() && representation_identifier == "IAI" && shaperep->RepresentationType() != "BoundingBox" ) {
|
||||
// Allow for Ifc 2x compatibility
|
||||
} else if ( representation_identifier != "Body" &&
|
||||
representation_identifier != "Facetation" ) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Ifc2x3::IfcProductRepresentation::list prodreps = shaperep->OfProductRepresentation();
|
||||
entities = Ifc2x3::IfcProduct::list( new IfcTemplatedEntityList<Ifc2x3::IfcProduct>() );
|
||||
|
||||
@@ -132,8 +132,8 @@ bool IfcGeom::convert(const Ifc2x3::IfcPolygonalBoundedHalfSpace::ptr l, TopoDS_
|
||||
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));
|
||||
gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-10000.0));
|
||||
TopoDS_Shape extrusion = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200.0));
|
||||
gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0));
|
||||
extrusion.Move(down*trsf);
|
||||
shape = BRepAlgoAPI_Cut(extrusion,halfspace);
|
||||
return true;
|
||||
@@ -179,20 +179,33 @@ bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shap
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& shape) {
|
||||
#ifdef FACESET_AS_COMPOUND
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
#else
|
||||
BRepOffsetAPI_Sewing builder;
|
||||
builder.SetTolerance(0.01);
|
||||
#endif
|
||||
Ifc2x3::IfcFace::list faces = l->CfsFaces();
|
||||
bool facesAdded = false;
|
||||
for( Ifc2x3::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) {
|
||||
TopoDS_Face face;
|
||||
if ( IfcGeom::convert_face(*it,face) ) {
|
||||
#ifdef FACESET_AS_COMPOUND
|
||||
builder.Add(compound,face);
|
||||
#else
|
||||
builder.Add(face);
|
||||
#endif
|
||||
facesAdded = true;
|
||||
} else {
|
||||
Ifc::LogMessage("Warning","Invalid face:",(*it)->entity);
|
||||
}
|
||||
}
|
||||
if ( ! facesAdded ) return false;
|
||||
#ifdef FACESET_AS_COMPOUND
|
||||
shape = compound;
|
||||
#else
|
||||
builder.Perform();
|
||||
shape = builder.SewedShape();
|
||||
try {
|
||||
@@ -200,6 +213,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
|
||||
solid.LimitTolerance(0.01);
|
||||
shape = solid.SolidFromShell(TopoDS::Shell(shape));
|
||||
} catch(...) {}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, ShapeList& shapes) {
|
||||
|
||||
Reference in New Issue
Block a user