mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-23 14:06:26 +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:
|
else:
|
||||||
valid_file = IfcImport.Init(filename)
|
valid_file = IfcImport.Init(filename)
|
||||||
if not valid_file:
|
if not valid_file:
|
||||||
|
IfcImport.CleanUp()
|
||||||
return False
|
return False
|
||||||
print("Done reading file")
|
print("Done reading file")
|
||||||
id_to_object = {}
|
id_to_object = {}
|
||||||
@@ -136,6 +137,7 @@ def import_ifc(filename, use_names, process_relations):
|
|||||||
ob.id, ob_guid, ob_name, ob_type
|
ob.id, ob_guid, ob_name, ob_type
|
||||||
|
|
||||||
bob.hide = ob_type == 'IfcSpace' or ob_type == 'IfcOpeningElement'
|
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] = []
|
if ob.id not in id_to_object: id_to_object[ob.id] = []
|
||||||
id_to_object[ob.id].append(bob)
|
id_to_object[ob.id].append(bob)
|
||||||
|
|||||||
@@ -42,6 +42,8 @@
|
|||||||
|
|
||||||
#include "../ifcgeom/IfcShapeList.h"
|
#include "../ifcgeom/IfcShapeList.h"
|
||||||
|
|
||||||
|
#define FACESET_AS_COMPOUND 1
|
||||||
|
|
||||||
namespace IfcGeom {
|
namespace IfcGeom {
|
||||||
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
|
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
|
||||||
bool convert_shapes(const IfcUtil::IfcBaseClass* L, ShapeList& result);
|
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_curve(const IfcUtil::IfcBaseClass* L, Handle(Geom_Curve)& result);
|
||||||
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 entity, const Ifc2x3::IfcRelVoidsElement::list& openings, const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes);
|
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);
|
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);
|
float shape_volume(const TopoDS_Shape& s);
|
||||||
namespace Cache {
|
namespace Cache {
|
||||||
|
|||||||
@@ -82,6 +82,40 @@
|
|||||||
|
|
||||||
#include "../ifcgeom/IfcGeom.h"
|
#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,
|
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) {
|
const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes) {
|
||||||
// Iterate over IfcOpeningElements
|
// 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
|
// Iterate over the shapes of the IfcProduct
|
||||||
for ( IfcGeom::ShapeList::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) {
|
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);
|
const gp_GTrsf& entity_shape_gtrsf = *(it3->first);
|
||||||
TopoDS_Shape entity_shape;
|
TopoDS_Shape entity_shape;
|
||||||
if ( entity_shape_gtrsf.Form() == gp_Other ) {
|
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
|
// Iterate over the shapes of the IfcOpeningElements
|
||||||
for ( IfcGeom::ShapeList::const_iterator it4 = opening_shapes.begin(); it4 != opening_shapes.end(); ++ it4 ) {
|
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);
|
const gp_GTrsf& opening_shape_gtrsf = *(it4->first);
|
||||||
if ( opening_shape_gtrsf.Form() == gp_Other ) {
|
if ( opening_shape_gtrsf.Form() == gp_Other ) {
|
||||||
Ifc::LogMessage("warning","Applying non uniform transformation to opening of:",entity->entity);
|
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);
|
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) )
|
if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) )
|
||||||
Ifc::LogMessage("warning","Warning subtraction yields unchanged volume:",entity->entity);
|
Ifc::LogMessage("warning","Warning subtraction yields unchanged volume:",entity->entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cut_shapes.push_back(IfcGeom::LocationShape(new gp_GTrsf(),new TopoDS_Shape(entity_shape)));
|
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?
|
// Has the list of IfcProducts for this representation been initialized?
|
||||||
if ( ! entities ) {
|
if ( ! entities ) {
|
||||||
if ( shaperep->RepresentationIdentifier() != "Body" &&
|
if ( shaperep->hasRepresentationIdentifier() ) {
|
||||||
shaperep->RepresentationIdentifier() != "Facetation" ) {
|
const std::string representation_identifier = shaperep->RepresentationIdentifier();
|
||||||
_nextShape();
|
if ( shaperep->hasRepresentationType() && representation_identifier == "IAI" && shaperep->RepresentationType() != "BoundingBox" ) {
|
||||||
continue;
|
// Allow for Ifc 2x compatibility
|
||||||
|
} else if ( representation_identifier != "Body" &&
|
||||||
|
representation_identifier != "Facetation" ) {
|
||||||
|
_nextShape();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ifc2x3::IfcProductRepresentation::list prodreps = shaperep->OfProductRepresentation();
|
Ifc2x3::IfcProductRepresentation::list prodreps = shaperep->OfProductRepresentation();
|
||||||
entities = Ifc2x3::IfcProduct::list( new IfcTemplatedEntityList<Ifc2x3::IfcProduct>() );
|
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;
|
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,200.0));
|
||||||
gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-10000.0));
|
gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0));
|
||||||
extrusion.Move(down*trsf);
|
extrusion.Move(down*trsf);
|
||||||
shape = BRepAlgoAPI_Cut(extrusion,halfspace);
|
shape = BRepAlgoAPI_Cut(extrusion,halfspace);
|
||||||
return true;
|
return true;
|
||||||
@@ -179,20 +179,33 @@ bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shap
|
|||||||
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) {
|
||||||
|
#ifdef FACESET_AS_COMPOUND
|
||||||
|
TopoDS_Compound compound;
|
||||||
|
BRep_Builder builder;
|
||||||
|
builder.MakeCompound(compound);
|
||||||
|
#else
|
||||||
BRepOffsetAPI_Sewing builder;
|
BRepOffsetAPI_Sewing builder;
|
||||||
builder.SetTolerance(0.01);
|
builder.SetTolerance(0.01);
|
||||||
|
#endif
|
||||||
Ifc2x3::IfcFace::list faces = l->CfsFaces();
|
Ifc2x3::IfcFace::list faces = l->CfsFaces();
|
||||||
bool facesAdded = false;
|
bool facesAdded = false;
|
||||||
for( Ifc2x3::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) {
|
for( Ifc2x3::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) {
|
||||||
TopoDS_Face face;
|
TopoDS_Face face;
|
||||||
if ( IfcGeom::convert_face(*it,face) ) {
|
if ( IfcGeom::convert_face(*it,face) ) {
|
||||||
|
#ifdef FACESET_AS_COMPOUND
|
||||||
|
builder.Add(compound,face);
|
||||||
|
#else
|
||||||
builder.Add(face);
|
builder.Add(face);
|
||||||
|
#endif
|
||||||
facesAdded = true;
|
facesAdded = true;
|
||||||
} else {
|
} else {
|
||||||
Ifc::LogMessage("Warning","Invalid face:",(*it)->entity);
|
Ifc::LogMessage("Warning","Invalid face:",(*it)->entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( ! facesAdded ) return false;
|
if ( ! facesAdded ) return false;
|
||||||
|
#ifdef FACESET_AS_COMPOUND
|
||||||
|
shape = compound;
|
||||||
|
#else
|
||||||
builder.Perform();
|
builder.Perform();
|
||||||
shape = builder.SewedShape();
|
shape = builder.SewedShape();
|
||||||
try {
|
try {
|
||||||
@@ -200,6 +213,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
|
|||||||
solid.LimitTolerance(0.01);
|
solid.LimitTolerance(0.01);
|
||||||
shape = solid.SolidFromShell(TopoDS::Shell(shape));
|
shape = solid.SolidFromShell(TopoDS::Shell(shape));
|
||||||
} catch(...) {}
|
} catch(...) {}
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, ShapeList& shapes) {
|
bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, ShapeList& shapes) {
|
||||||
|
|||||||
+119
@@ -0,0 +1,119 @@
|
|||||||
|
###############################################################################
|
||||||
|
# #
|
||||||
|
# This file is part of IfcOpenShell. #
|
||||||
|
# #
|
||||||
|
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||||
|
# it under the terms of the Lesser GNU General Public License as published by #
|
||||||
|
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||||
|
# (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||||
|
# Lesser GNU General Public License for more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the Lesser GNU General Public License #
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||||
|
# #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# #
|
||||||
|
# Do not run this script directly, it is called by run.py #
|
||||||
|
# #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
import os
|
||||||
|
import bpy
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
try: from io_import_scene_ifc import import_ifc
|
||||||
|
except:
|
||||||
|
print("[Error] Unable to import IfcOpenShell")
|
||||||
|
sys.exit(1)
|
||||||
|
from mathutils import Vector as V
|
||||||
|
from math import radians
|
||||||
|
|
||||||
|
scn = bpy.context.scene
|
||||||
|
|
||||||
|
for ob in bpy.data.objects:
|
||||||
|
scn.objects.unlink(ob)
|
||||||
|
|
||||||
|
if sys.argv[-2] != 'render': sys.exit(0)
|
||||||
|
|
||||||
|
fn = sys.argv[-1]
|
||||||
|
t1 = time.time()
|
||||||
|
succes = import_ifc(fn,True,False)
|
||||||
|
if not succes:
|
||||||
|
print("[Error] Import of %s failed"%fn)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
dt = time.time()-t1
|
||||||
|
print ("[Notice] Conversion took %.2f seconds"%dt)
|
||||||
|
|
||||||
|
cam = bpy.data.cameras.new('cam')
|
||||||
|
cam.angle = radians(45)
|
||||||
|
cam_ob = bpy.data.objects.new('cam',cam)
|
||||||
|
scn.objects.link(cam_ob)
|
||||||
|
cam_ob.rotation_euler = (radians(67),0,radians(45))
|
||||||
|
|
||||||
|
scn.camera = cam_ob
|
||||||
|
scn.render.resolution_percentage = 100
|
||||||
|
scn.render.resolution_x = 2048
|
||||||
|
scn.render.resolution_y = 2048
|
||||||
|
scn.world.horizon_color = (1,1,1)
|
||||||
|
scn.world.ambient_color = (0.05,0.05,0.05)
|
||||||
|
scn.render.color_mode = 'RGBA'
|
||||||
|
|
||||||
|
for m in bpy.data.materials: m.specular_intensity = 0
|
||||||
|
def material(name,settings):
|
||||||
|
m = bpy.data.materials.get(name)
|
||||||
|
if not m: return
|
||||||
|
for k,v in settings.items():
|
||||||
|
setattr(m,k,v)
|
||||||
|
|
||||||
|
material("IfcWall",{"diffuse_color":[1,1,1],"diffuse_intensity":1})
|
||||||
|
material("IfcWallStandardCase",{"diffuse_color":[1,1,1],"diffuse_intensity":1})
|
||||||
|
material("IfcSite",{"diffuse_color":[0.4,0.5,0.25]})
|
||||||
|
material("IfcSlab",{"diffuse_color":[0.2,0.2,0.2]})
|
||||||
|
material("IfcDoor",{"diffuse_color":[0.25,0.1,0.05]})
|
||||||
|
material("IfcWindow",{"diffuse_color":[0.5,0.7,0.5],"use_transparency":True,"alpha":0.3})
|
||||||
|
material("IfcRoof",{"diffuse_color":[0.35,0.2,0.2]})
|
||||||
|
material("IfcFurnishingElement",{"diffuse_color":[0.8,0.7,0.5]})
|
||||||
|
material("IfcBuildingElementPro",{"diffuse_intensity":0.6})
|
||||||
|
|
||||||
|
def create_lamp(eul):
|
||||||
|
l = bpy.data.lamps.new('l','SUN')
|
||||||
|
l.energy = 1.3
|
||||||
|
l_ob = bpy.data.objects.new('l',l)
|
||||||
|
scn.objects.link(l_ob)
|
||||||
|
l_ob.rotation_euler = [radians(e) for e in eul]
|
||||||
|
|
||||||
|
create_lamp((20,0,60))
|
||||||
|
create_lamp((0,-120,-50))
|
||||||
|
|
||||||
|
A = V([1e9]*3)
|
||||||
|
B = V([-1e9]*3)
|
||||||
|
|
||||||
|
for ob in scn.objects:
|
||||||
|
if ob.type != 'MESH': continue
|
||||||
|
if ob.hide: continue
|
||||||
|
bb = [ob.matrix_world*V(x) for x in ob.bound_box]
|
||||||
|
for b in bb:
|
||||||
|
for i in range(3):
|
||||||
|
if b[i] < A[i]: A[i] = b[i]
|
||||||
|
if b[i] > B[i]: B[i] = b[i]
|
||||||
|
|
||||||
|
C = V((1.2,-1.2,0.6))
|
||||||
|
D = B-A
|
||||||
|
E = max(D)*C + (A+B)/2
|
||||||
|
|
||||||
|
cam_ob.location = E
|
||||||
|
cam.clip_end = max(D) * 10
|
||||||
|
|
||||||
|
scn.render.filepath = os.path.join("output",os.path.basename(fn)+".png")
|
||||||
|
|
||||||
|
bpy.ops.render.render(write_still=True)
|
||||||
|
bpy.ops.wm.save_mainfile(filepath=os.path.join("output",os.path.basename(fn)+".blend"),compress=True)
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
+198
@@ -0,0 +1,198 @@
|
|||||||
|
###############################################################################
|
||||||
|
# #
|
||||||
|
# This file is part of IfcOpenShell. #
|
||||||
|
# #
|
||||||
|
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||||
|
# it under the terms of the Lesser GNU General Public License as published by #
|
||||||
|
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||||
|
# (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||||
|
# Lesser GNU General Public License for more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the Lesser GNU General Public License #
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||||
|
# #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# #
|
||||||
|
# The IfcOpenShell test suite downloads IFC files that are publicely #
|
||||||
|
# available on the internet and uses Blender and IfcOpenShell to generate a #
|
||||||
|
# render of the parsed file. For the script to run, Blender needs to be #
|
||||||
|
# installed and added to PATH. #
|
||||||
|
# #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
import inspect
|
||||||
|
import subprocess
|
||||||
|
from zipfile import ZipFile
|
||||||
|
from urllib.request import urlretrieve
|
||||||
|
|
||||||
|
# Test whether Blender and IfcOpenShell are installed
|
||||||
|
if subprocess.call(['blender','-b','-P','bpy.py','TEST']) != 0:
|
||||||
|
print("[Error] Failed to launch Blender")
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print("[Notice] Found Blender and IfcOpenShell on system")
|
||||||
|
|
||||||
|
# Global variables for keeping track of test cases
|
||||||
|
test_cases = []
|
||||||
|
failed = []
|
||||||
|
|
||||||
|
# Create the ouput directory
|
||||||
|
cwd = os.path.abspath(os.path.dirname(inspect.getfile(inspect.currentframe())))
|
||||||
|
os.chdir(cwd)
|
||||||
|
if not os.path.exists("output"): os.mkdir("output")
|
||||||
|
if not os.path.exists("input"): os.mkdir("input")
|
||||||
|
|
||||||
|
def extension(fn):
|
||||||
|
return os.path.splitext(fn)[-1].lower()
|
||||||
|
|
||||||
|
# Class to download extract and convert IFC files
|
||||||
|
class TestFile:
|
||||||
|
def __init__(self,fn,store_as=None):
|
||||||
|
global test_cases
|
||||||
|
self.fn = fn
|
||||||
|
self.store_as = store_as
|
||||||
|
self.failed = []
|
||||||
|
test_cases.append(self)
|
||||||
|
def __call__(self):
|
||||||
|
if self.fn.startswith("http://") or self.fn.startswith("ftp://"):
|
||||||
|
fn = self.store_as if self.store_as else self.fn.split("/")[-1]
|
||||||
|
if os.path.exists(os.path.join("input",fn)):
|
||||||
|
print ("[Notice] Already downloaded:",fn)
|
||||||
|
else:
|
||||||
|
print ("[Notice] Downloading:",fn)
|
||||||
|
urlretrieve(self.fn,os.path.join("input",fn))
|
||||||
|
self.fn = fn
|
||||||
|
if extension(self.fn) == '.zip':
|
||||||
|
print ("[Notice] Extracting:",self.fn)
|
||||||
|
zf = ZipFile(os.path.join("input",self.fn))
|
||||||
|
self.fn = [n for n in zf.namelist() if extension(n) == '.ifc' and not n.startswith('__') and not n.startswith('.')]
|
||||||
|
for fn in self.fn:
|
||||||
|
if not os.path.exists(os.path.join("input",fn)): zf.extract(fn,"input")
|
||||||
|
zf.close()
|
||||||
|
else: self.fn = [self.fn]
|
||||||
|
for fn in self.fn:
|
||||||
|
print ("[Notice] Rendering:",fn)
|
||||||
|
succes = subprocess.call(['blender','-b','-P','bpy.py','render',os.path.join("input",fn)]) == 0
|
||||||
|
if not succes: self.failed.append(fn)
|
||||||
|
return len(self.failed) == 0
|
||||||
|
def __str__(self): return "\n".join(self.failed) if len(self.failed) else ""
|
||||||
|
|
||||||
|
# Karlsruher Institut fuer Technologie
|
||||||
|
TestFile("http://iai-typo3.iai.fzk.de/www-extern-kit/fileadmin/download/download-vrsys/ADT-FZK-Haus-2005-2006.zip")
|
||||||
|
TestFile("http://iai-typo3.iai.fzk.de/www-extern-kit/fileadmin/download/download-vrsys/Nem-FZK-Haus-2x3.zip")
|
||||||
|
TestFile("http://iai-typo3.iai.fzk.de/www-extern-kit/fileadmin/download/download-vrsys/AC14-FZK-Haus.zip")
|
||||||
|
TestFile("http://iai-typo3.iai.fzk.de/www-extern-kit/fileadmin/download/download-vrsys/FZK-Haus-EliteCAD.zip")
|
||||||
|
|
||||||
|
TestFile("http://iai-typo3.iai.fzk.de/www-extern-kit/fileadmin/download/download-vrsys/FJK-Project-Final.zip")
|
||||||
|
|
||||||
|
TestFile("http://www.iai.fzk.de/www-extern-kit/fileadmin/download/download-vrsys/Bien-Zenker_Jasmin-Sun-AC14-V2-IFC.zip")
|
||||||
|
|
||||||
|
TestFile("http://www.iai.fzk.de/www-extern-kit/fileadmin/download/download-vrsys/ADT-Smiley-West-Project-14-10-2005.zip")
|
||||||
|
TestFile("http://www.iai.fzk.de/www-extern-kit/fileadmin/download/download-vrsys/Allplan-Smiley-West.zip")
|
||||||
|
TestFile("http://www.iai.fzk.de/www-extern-kit/fileadmin/download/download-vrsys/AC-11-Smiley-West-04-07-2007-IFC.zip")
|
||||||
|
|
||||||
|
TestFile("http://www.iai.fzk.de/www-extern-kit/fileadmin/download/download-vrsys/Allplan-2008-Institute-Var-2-IFC.zip")
|
||||||
|
TestFile("http://www.iai.fzk.de/www-extern-kit/fileadmin/download/download-vrsys/AC11-Institute-Var-2-IFC.zip")
|
||||||
|
|
||||||
|
TestFile("http://iai-typo3.iai.fzk.de/www-extern-kit/fileadmin/download/download-vrsys/PART02_Wilfer_200302_20070209_IFC.zip")
|
||||||
|
TestFile("http://iai-typo3.iai.fzk.de/www-extern-kit/fileadmin/download/download-vrsys/PART06_Kermi_200405_20070401_IFC.zip")
|
||||||
|
|
||||||
|
TestFile("http://iai-typo3.iai.fzk.de/www-extern-kit/fileadmin/download/download-vrsys/Ettenheim-GIS-05-11-2006_optimized.zip")
|
||||||
|
|
||||||
|
# Selvaag Gruppen
|
||||||
|
TestFile("ftp://ftp.dds.no/pub/ifc/Munkerud/Munkerud_hus6_BE.zip")
|
||||||
|
|
||||||
|
# Statsbygg
|
||||||
|
TestFile("ftp://ftp.dds.no/pub/ifc/HiTOS/2x3_HiTOS_EL_new.zip")
|
||||||
|
TestFile("ftp://ftp.dds.no/pub/ifc/HiTOS/2x3_HiTOS_HVAC_new.zip")
|
||||||
|
TestFile("ftp://ftp.dds.no/pub/ifc/HiTOS/HITOS_Architectural_2006-10-25.zip")
|
||||||
|
|
||||||
|
# Nemetschek Vectorworks
|
||||||
|
TestFile("http://download2cf.nemetschek.net/www_misc/bim/DCR-LOD_100.zip")
|
||||||
|
TestFile("http://download2cf.nemetschek.net/www_misc/bim/DCR-LOD_200.zip")
|
||||||
|
# Rather large:
|
||||||
|
# TestFile("http://download2cf.nemetschek.net/www_misc/bim/DCR-LOD_300.zip")
|
||||||
|
|
||||||
|
# Data Design Systems
|
||||||
|
TestFile("ftp://ftp.dds.no/pub/ifc/BardNa/Dds_BardNa.zip")
|
||||||
|
|
||||||
|
# Common Building Information Model Files
|
||||||
|
TestFile("http://projects.buildingsmartalliance.org/files/?artifact_id=4278","2011-09-14-Duplex-IFC.zip")
|
||||||
|
TestFile("http://projects.buildingsmartalliance.org/files/?artifact_id=4284","2011-09-14-Office-IFC.zip")
|
||||||
|
# Rather large
|
||||||
|
# TestFile("http://projects.buildingsmartalliance.org/files/?artifact_id=4289","2011-09-14-Clinic-IFC.zip")
|
||||||
|
|
||||||
|
# http://openifcmodel.cs.auckland.ac.nz IAI
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912101-01wall_layers_number_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912101-02wall_opening_straight_ac_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912101-03wall_recess_ben_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912101-04wall_L-shape_all_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912102-01beam_profile_basic_rev_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912102-01beam_profile_para_ac_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912102-02brep_beams_opening_ben_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912102-02extruded_beam_open_tek_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912103-01col_profile_clip_ben_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912103-01columns_basic_all_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912103-02col_brep_opening_ben_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912103-02OpeningsInExtrudedColumns_rev_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912104-01slab_profile_basic_ac_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912104-03extruded_slab_openings_all_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912104-04slab_recess_tek_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912105-01doors_explicit_geom_all_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912105-02DoorOperationsPlacementInsideWall_rev_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912106-01window_brep_ac_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912106-02windows_placement_inside_wall_all_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912107-01stair_geom_ac_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912107-01stair_geometry_ben_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912108-01ramp_geometry_ben_2.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912108-01RampAsContainer_rev_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912109-01railing_brep_ac_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/0912109-01railing_extrusion_tek_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/09121010-01RoofWithGeometry_rev_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/09121010-02roof_with_openings_ben_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/09121011curtain_wall_basic_rev_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/09121012mem_profile_basic_tek_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/09121013plate_steel_exam_tek_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/09121014pile_basic_tek_1.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/09121015footing_ac_1.ifc")
|
||||||
|
|
||||||
|
# http://openifcmodel.cs.auckland.ac.nz NIST
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210AISC_Sculpture_brep.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210AISC_Sculpture_param.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210analysis_brep.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210analysis_param.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210Bentley1_brep.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210Bentley1_param.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210CADstudio_brep.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210cutouts_brep.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210DesignData1_brep.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210DesignData3_brep.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210PlayersTheater_param.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210profiles_brep.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210profilescp1_brep.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210sections_brep.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210threebeams_brep.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210TrainingStructure_brep.ifc")
|
||||||
|
TestFile("http://openifcmodel.cs.auckland.ac.nz/_models/171210eccentricity_physical.ifc")
|
||||||
|
|
||||||
|
for test in test_cases:
|
||||||
|
succes = test()
|
||||||
|
if not succes:
|
||||||
|
failed.append(test)
|
||||||
|
|
||||||
|
if len(failed):
|
||||||
|
print("[Notice] Conversion failed for the following cases:")
|
||||||
|
for test in failed:
|
||||||
|
print (test)
|
||||||
|
else:
|
||||||
|
print("[Notice] All cases succeeded")
|
||||||
|
|
||||||
Reference in New Issue
Block a user