mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 22:33:33 +00:00
Merge branch 'v0.6.0' of https://github.com/IfcOpenShell/IfcOpenShell into v0.6.0
This commit is contained in:
@@ -1,84 +0,0 @@
|
|||||||
#import sys
|
|
||||||
#sys.path.append('C:/Program Files/Python37/Lib/site-packages')
|
|
||||||
import ifcopenshell
|
|
||||||
import ifcopenshell.geom
|
|
||||||
import bpy
|
|
||||||
import time
|
|
||||||
import mathutils
|
|
||||||
|
|
||||||
class ImportIFC():
|
|
||||||
def __init__(self):
|
|
||||||
self.file = None
|
|
||||||
self.settings = ifcopenshell.geom.settings()
|
|
||||||
self.meshes = {}
|
|
||||||
|
|
||||||
def execute(self):
|
|
||||||
self.load_file()
|
|
||||||
n = 0
|
|
||||||
elements = self.file.by_type('IfcElement') + self.file.by_type('IfcSpace')
|
|
||||||
for element in elements:
|
|
||||||
self.create_object(element)
|
|
||||||
n += 1
|
|
||||||
if n > 1000:
|
|
||||||
break
|
|
||||||
|
|
||||||
def load_file(self):
|
|
||||||
self.file = ifcopenshell.open('C:/cygwin64/home/moud308/Projects/IFCAudit/big.ifc')
|
|
||||||
|
|
||||||
def create_object(self, element):
|
|
||||||
try:
|
|
||||||
if element.is_a('IfcOpeningElement'):
|
|
||||||
return
|
|
||||||
|
|
||||||
shape = ifcopenshell.geom.create_shape(self.settings, element)
|
|
||||||
mesh_name = 'mesh-{}'.format(shape.geometry.id)
|
|
||||||
|
|
||||||
mesh = self.meshes.get(mesh_name)
|
|
||||||
if mesh is None:
|
|
||||||
mesh = self.create_mesh(element, shape)
|
|
||||||
self.meshes[mesh_name] = mesh
|
|
||||||
else:
|
|
||||||
print('we reused a mesh!')
|
|
||||||
|
|
||||||
materials = shape.geometry.materials
|
|
||||||
for material in materials:
|
|
||||||
if material.has_diffuse:
|
|
||||||
alpha = 1.
|
|
||||||
blender_material = bpy.data.materials.new('mymaterial')
|
|
||||||
blender_material.diffuse_color = material.diffuse + (alpha,)
|
|
||||||
mesh.materials.append(blender_material)
|
|
||||||
|
|
||||||
object = bpy.data.objects.new('{}/{}'.format(element.is_a(), element.Name), mesh)
|
|
||||||
m = shape.transformation.matrix.data
|
|
||||||
matrix = mathutils.Matrix((
|
|
||||||
[m[0], m[1], m[2], 0],
|
|
||||||
[m[3], m[4], m[5], 0],
|
|
||||||
[m[6], m[7], m[8], 0],
|
|
||||||
[m[9], m[10], m[11], 1]))
|
|
||||||
matrix.transpose()
|
|
||||||
object.matrix_world = matrix
|
|
||||||
bpy.context.scene.collection.objects.link(object)
|
|
||||||
except:
|
|
||||||
print('Could not create object for {}: {}/{}'.format(
|
|
||||||
element.GlobalId, element.is_a(), element.Name))
|
|
||||||
|
|
||||||
def create_mesh(self, element, shape):
|
|
||||||
try:
|
|
||||||
mesh = bpy.data.meshes.new(shape.geometry.id)
|
|
||||||
f = shape.geometry.faces
|
|
||||||
v = shape.geometry.verts
|
|
||||||
vertices = [[v[i], v[i + 1], v[i + 2]]
|
|
||||||
for i in range(0, len(v), 3)]
|
|
||||||
faces = [[f[i], f[i + 1], f[i + 2]]
|
|
||||||
for i in range(0, len(f), 3)]
|
|
||||||
mesh.from_pydata(vertices, [], faces)
|
|
||||||
return mesh
|
|
||||||
except:
|
|
||||||
print('Could not create mesh for {}: {}/{}'.format(
|
|
||||||
element.GlobalId, element.is_a(), element.Name))
|
|
||||||
|
|
||||||
print('# Starting import')
|
|
||||||
start = time.time()
|
|
||||||
import_ifc = ImportIFC()
|
|
||||||
import_ifc.execute()
|
|
||||||
print('# Finished in {}s'.format(time.time() - start))
|
|
||||||
@@ -16,28 +16,37 @@ from . import operator
|
|||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
operator.AssignClass,
|
operator.AssignClass,
|
||||||
|
operator.SelectClass,
|
||||||
|
operator.SelectType,
|
||||||
operator.SelectDataDir,
|
operator.SelectDataDir,
|
||||||
operator.SelectSchemaDir,
|
operator.SelectSchemaDir,
|
||||||
operator.ExportIFC,
|
operator.ExportIFC,
|
||||||
|
operator.ImportIFC,
|
||||||
ui.BIMProperties,
|
ui.BIMProperties,
|
||||||
ui.BIMPanel,
|
ui.BIMPanel,
|
||||||
ui.MVDPanel,
|
ui.MVDPanel,
|
||||||
)
|
)
|
||||||
|
|
||||||
def menu_func(self, context):
|
def menu_func_export(self, context):
|
||||||
self.layout.operator(operator.ExportIFC.bl_idname,
|
self.layout.operator(operator.ExportIFC.bl_idname,
|
||||||
text="Industry Foundation Classes (.ifc)")
|
text="Industry Foundation Classes (.ifc)")
|
||||||
|
|
||||||
|
def menu_func_import(self, context):
|
||||||
|
self.layout.operator(operator.ImportIFC.bl_idname,
|
||||||
|
text="Industry Foundation Classes (.ifc)")
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
for cls in classes:
|
for cls in classes:
|
||||||
bpy.utils.register_class(cls)
|
bpy.utils.register_class(cls)
|
||||||
bpy.types.TOPBAR_MT_file_export.append(menu_func)
|
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
|
||||||
|
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
|
||||||
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=ui.BIMProperties)
|
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=ui.BIMProperties)
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
for cls in reversed(classes):
|
for cls in reversed(classes):
|
||||||
bpy.utils.unregister_class(cls)
|
bpy.utils.unregister_class(cls)
|
||||||
bpy.types.TOPBAR_MT_file_export.remove(menu_func)
|
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
|
||||||
|
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
|
||||||
del(bpy.types.Scene.BIMProperties)
|
del(bpy.types.Scene.BIMProperties)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
+1
-2
@@ -747,7 +747,6 @@ class SIUnitHelper:
|
|||||||
class IfcExporter():
|
class IfcExporter():
|
||||||
def __init__(self, ifc_export_settings, ifc_schema, ifc_parser, qto_calculator):
|
def __init__(self, ifc_export_settings, ifc_schema, ifc_parser, qto_calculator):
|
||||||
self.template_file = '{}template.ifc'.format(ifc_export_settings.schema_dir)
|
self.template_file = '{}template.ifc'.format(ifc_export_settings.schema_dir)
|
||||||
self.output_file = ifc_export_settings.output_file
|
|
||||||
self.ifc_export_settings = ifc_export_settings
|
self.ifc_export_settings = ifc_export_settings
|
||||||
self.ifc_schema = ifc_schema
|
self.ifc_schema = ifc_schema
|
||||||
self.ifc_parser = ifc_parser
|
self.ifc_parser = ifc_parser
|
||||||
@@ -790,7 +789,7 @@ class IfcExporter():
|
|||||||
self.relate_to_classifications(self.ifc_parser.rel_associates_classification_type)
|
self.relate_to_classifications(self.ifc_parser.rel_associates_classification_type)
|
||||||
self.relate_to_objectives(self.ifc_parser.rel_associates_constraint_objective_object)
|
self.relate_to_objectives(self.ifc_parser.rel_associates_constraint_objective_object)
|
||||||
self.relate_to_objectives(self.ifc_parser.rel_associates_constraint_objective_type)
|
self.relate_to_objectives(self.ifc_parser.rel_associates_constraint_objective_type)
|
||||||
self.file.write(self.output_file)
|
self.file.write(self.ifc_export_settings.output_file)
|
||||||
|
|
||||||
def set_common_definitions(self):
|
def set_common_definitions(self):
|
||||||
# Owner history doesn't actually work like this, but for now, it does :)
|
# Owner history doesn't actually work like this, but for now, it does :)
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
from . import ifcopenshell
|
||||||
|
from .ifcopenshell import geom
|
||||||
|
import bpy
|
||||||
|
import mathutils
|
||||||
|
|
||||||
|
class IfcImporter():
|
||||||
|
def __init__(self, ifc_import_settings):
|
||||||
|
self.ifc_import_settings = ifc_import_settings
|
||||||
|
self.file = None
|
||||||
|
self.settings = ifcopenshell.geom.settings()
|
||||||
|
self.project = None
|
||||||
|
self.spatial_structure_elements = {}
|
||||||
|
self.elements = {}
|
||||||
|
self.meshes = {}
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
self.load_file()
|
||||||
|
self.create_project()
|
||||||
|
self.create_spatial_hierarchy()
|
||||||
|
elements = self.file.by_type('IfcElement') + self.file.by_type('IfcSpace')
|
||||||
|
for element in elements:
|
||||||
|
self.create_object(element)
|
||||||
|
|
||||||
|
def load_file(self):
|
||||||
|
print('loading file {}'.format(self.ifc_import_settings.input_file))
|
||||||
|
self.file = ifcopenshell.open(self.ifc_import_settings.input_file)
|
||||||
|
|
||||||
|
def create_project(self):
|
||||||
|
self.project = { 'ifc': self.file.by_type('IfcProject')[0] }
|
||||||
|
self.project['blender'] = bpy.data.collections.new('IfcProject/{}'.format(self.project['ifc'].Name))
|
||||||
|
bpy.context.scene.collection.children.link(self.project['blender'])
|
||||||
|
|
||||||
|
def create_spatial_hierarchy(self):
|
||||||
|
elements = self.file.by_type('IfcSpatialStructureElement')
|
||||||
|
while len(self.spatial_structure_elements) < len(elements):
|
||||||
|
for element in elements:
|
||||||
|
parent = element.Decomposes[0].RelatingObject
|
||||||
|
parent_name = self.get_name(parent)
|
||||||
|
name = self.get_name(element)
|
||||||
|
if name in self.spatial_structure_elements:
|
||||||
|
continue
|
||||||
|
if parent.is_a('IfcProject'):
|
||||||
|
self.spatial_structure_elements[name] = {
|
||||||
|
'blender': bpy.data.collections.new(name)}
|
||||||
|
self.project['blender'].children.link(self.spatial_structure_elements[name]['blender'])
|
||||||
|
elif parent_name in self.spatial_structure_elements:
|
||||||
|
self.spatial_structure_elements[name] = {
|
||||||
|
'blender': bpy.data.collections.new(name)}
|
||||||
|
self.spatial_structure_elements[parent_name]['blender'].children.link(
|
||||||
|
self.spatial_structure_elements[name]['blender'])
|
||||||
|
|
||||||
|
def get_name(self, element):
|
||||||
|
return '{}/{}'.format(element.is_a(), element.Name)
|
||||||
|
|
||||||
|
def create_object(self, element):
|
||||||
|
if element.is_a('IfcOpeningElement'):
|
||||||
|
return
|
||||||
|
|
||||||
|
shape = ifcopenshell.geom.create_shape(self.settings, element)
|
||||||
|
mesh_name = 'mesh-{}'.format(shape.geometry.id)
|
||||||
|
|
||||||
|
mesh = self.meshes.get(mesh_name)
|
||||||
|
if mesh is None:
|
||||||
|
mesh = self.create_mesh(element, shape)
|
||||||
|
self.meshes[mesh_name] = mesh
|
||||||
|
else:
|
||||||
|
print('we reused a mesh!')
|
||||||
|
|
||||||
|
materials = shape.geometry.materials
|
||||||
|
for material in materials:
|
||||||
|
if material.has_diffuse:
|
||||||
|
alpha = 1.
|
||||||
|
blender_material = bpy.data.materials.new('mymaterial')
|
||||||
|
blender_material.diffuse_color = material.diffuse + (alpha,)
|
||||||
|
mesh.materials.append(blender_material)
|
||||||
|
|
||||||
|
object = bpy.data.objects.new(self.get_name(element), mesh)
|
||||||
|
m = shape.transformation.matrix.data
|
||||||
|
matrix = mathutils.Matrix((
|
||||||
|
[m[0], m[1], m[2], 0],
|
||||||
|
[m[3], m[4], m[5], 0],
|
||||||
|
[m[6], m[7], m[8], 0],
|
||||||
|
[m[9], m[10], m[11], 1]))
|
||||||
|
matrix.transpose()
|
||||||
|
object.matrix_world = matrix
|
||||||
|
|
||||||
|
if element.ContainedInStructure \
|
||||||
|
and element.ContainedInStructure[0].RelatingStructure:
|
||||||
|
structure_name = self.get_name(element.ContainedInStructure[0].RelatingStructure)
|
||||||
|
if structure_name in self.spatial_structure_elements:
|
||||||
|
self.spatial_structure_elements[structure_name]['blender'].objects.link(object)
|
||||||
|
else:
|
||||||
|
bpy.context.scene.collection.objects.link(object)
|
||||||
|
|
||||||
|
def create_mesh(self, element, shape):
|
||||||
|
try:
|
||||||
|
mesh = bpy.data.meshes.new(shape.geometry.id)
|
||||||
|
f = shape.geometry.faces
|
||||||
|
v = shape.geometry.verts
|
||||||
|
vertices = [[v[i], v[i + 1], v[i + 2]]
|
||||||
|
for i in range(0, len(v), 3)]
|
||||||
|
faces = [[f[i], f[i + 1], f[i + 2]]
|
||||||
|
for i in range(0, len(f), 3)]
|
||||||
|
mesh.from_pydata(vertices, [], faces)
|
||||||
|
return mesh
|
||||||
|
except:
|
||||||
|
print('Could not create mesh for {}: {}/{}'.format(
|
||||||
|
element.GlobalId, self.get_name(element)))
|
||||||
|
|
||||||
|
class IfcImportSettings:
|
||||||
|
def __init__(self):
|
||||||
|
self.logger = None
|
||||||
|
self.input_file = None
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import bpy
|
import bpy
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
from . import export
|
from . import export_ifc
|
||||||
|
from . import import_ifc
|
||||||
|
from bpy_extras.io_utils import ImportHelper
|
||||||
|
|
||||||
class ExportIFC(bpy.types.Operator):
|
class ExportIFC(bpy.types.Operator):
|
||||||
bl_idname = "export.ifc"
|
bl_idname = "export.ifc"
|
||||||
@@ -18,9 +20,9 @@ class ExportIFC(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
start = time.time()
|
start = time.time()
|
||||||
ifc_export_settings = export.IfcExportSettings()
|
ifc_export_settings = export_ifc.IfcExportSettings()
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
filename=bpy.context.scene.BIMProperties.data_dir + 'export.log',
|
filename=bpy.context.scene.BIMProperties.data_dir + 'process.log',
|
||||||
filemode='a', level=logging.DEBUG)
|
filemode='a', level=logging.DEBUG)
|
||||||
ifc_export_settings.logger = logging.getLogger('ExportIFC')
|
ifc_export_settings.logger = logging.getLogger('ExportIFC')
|
||||||
ifc_export_settings.logger.info('Starting export')
|
ifc_export_settings.logger.info('Starting export')
|
||||||
@@ -28,14 +30,35 @@ class ExportIFC(bpy.types.Operator):
|
|||||||
ifc_export_settings.schema_dir = bpy.context.scene.BIMProperties.schema_dir
|
ifc_export_settings.schema_dir = bpy.context.scene.BIMProperties.schema_dir
|
||||||
ifc_export_settings.output_file = bpy.path.ensure_ext(self.filepath, '.ifc')
|
ifc_export_settings.output_file = bpy.path.ensure_ext(self.filepath, '.ifc')
|
||||||
ifc_export_settings.has_representations = bpy.context.scene.BIMProperties.export_has_representations
|
ifc_export_settings.has_representations = bpy.context.scene.BIMProperties.export_has_representations
|
||||||
ifc_parser = export.IfcParser(ifc_export_settings)
|
ifc_parser = export_ifc.IfcParser(ifc_export_settings)
|
||||||
ifc_schema = export.IfcSchema(ifc_export_settings)
|
ifc_schema = export_ifc.IfcSchema(ifc_export_settings)
|
||||||
qto_calculator = export.QtoCalculator()
|
qto_calculator = export_ifc.QtoCalculator()
|
||||||
ifc_exporter = export.IfcExporter(ifc_export_settings, ifc_schema, ifc_parser, qto_calculator)
|
ifc_exporter = export_ifc.IfcExporter(ifc_export_settings, ifc_schema, ifc_parser, qto_calculator)
|
||||||
ifc_exporter.export()
|
ifc_exporter.export()
|
||||||
ifc_export_settings.logger.info('Export finished in {:.2f} seconds'.format(time.time() - start))
|
ifc_export_settings.logger.info('Export finished in {:.2f} seconds'.format(time.time() - start))
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
class ImportIFC(bpy.types.Operator, ImportHelper):
|
||||||
|
bl_idname = "import.ifc"
|
||||||
|
bl_label = "Import .ifc file"
|
||||||
|
|
||||||
|
filename_ext = ".ifc"
|
||||||
|
filter_glob: bpy.props.StringProperty(default="*.ifc", options={'HIDDEN'})
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
start = time.time()
|
||||||
|
ifc_import_settings = import_ifc.IfcImportSettings()
|
||||||
|
logging.basicConfig(
|
||||||
|
filename=bpy.context.scene.BIMProperties.data_dir + 'process.log',
|
||||||
|
filemode='a', level=logging.DEBUG)
|
||||||
|
ifc_import_settings.logger = logging.getLogger('ImportIFC')
|
||||||
|
ifc_import_settings.logger.info('Starting import')
|
||||||
|
ifc_import_settings.input_file = self.filepath
|
||||||
|
ifc_importer = import_ifc.IfcImporter(ifc_import_settings)
|
||||||
|
ifc_importer.execute()
|
||||||
|
ifc_import_settings.logger.info('Import finished in {:.2f} seconds'.format(time.time() - start))
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
class AssignClass(bpy.types.Operator):
|
class AssignClass(bpy.types.Operator):
|
||||||
bl_idname = 'bim.assign_class'
|
bl_idname = 'bim.assign_class'
|
||||||
bl_label = 'Assign IFC Class'
|
bl_label = 'Assign IFC Class'
|
||||||
@@ -64,6 +87,35 @@ class AssignClass(bpy.types.Operator):
|
|||||||
del(object['IfcObjectType'])
|
del(object['IfcObjectType'])
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
class SelectClass(bpy.types.Operator):
|
||||||
|
bl_idname = 'bim.select_class'
|
||||||
|
bl_label = 'Select IFC Class'
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
for object in bpy.context.visible_objects:
|
||||||
|
if '/' in object.name \
|
||||||
|
and object.name[0:3] == 'Ifc' \
|
||||||
|
and object.name.split('/')[0] == bpy.context.scene.BIMProperties.ifc_class:
|
||||||
|
object.select_set(True)
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
class SelectType(bpy.types.Operator):
|
||||||
|
bl_idname = 'bim.select_type'
|
||||||
|
bl_label = 'Select IFC Type'
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
for object in bpy.context.visible_objects:
|
||||||
|
if '/' in object.name \
|
||||||
|
and object.name[0:3] == 'Ifc' \
|
||||||
|
and object.name.split('/')[0] == bpy.context.scene.BIMProperties.ifc_class \
|
||||||
|
and 'IfcPredefinedType' in object.keys() \
|
||||||
|
and object['IfcPredefinedType'] == bpy.context.scene.BIMProperties.ifc_predefined_type:
|
||||||
|
if bpy.context.scene.BIMProperties.ifc_predefined_type != 'USERDEFINED':
|
||||||
|
object.select_set(True)
|
||||||
|
elif object['IfcObjectType'] == bpy.context.scene.BIMProperties.ifc_userdefined_type:
|
||||||
|
object.select_set(True)
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
class SelectDataDir(bpy.types.Operator):
|
class SelectDataDir(bpy.types.Operator):
|
||||||
bl_idname = "bim.select_data_dir"
|
bl_idname = "bim.select_data_dir"
|
||||||
bl_label = "Select Data Directory"
|
bl_label = "Select Data Directory"
|
||||||
|
|||||||
@@ -70,6 +70,10 @@ class BIMPanel(bpy.types.Panel):
|
|||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.operator("bim.assign_class")
|
row.operator("bim.assign_class")
|
||||||
|
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.operator("bim.select_class")
|
||||||
|
row.operator("bim.select_type")
|
||||||
|
|
||||||
class MVDPanel(bpy.types.Panel):
|
class MVDPanel(bpy.types.Panel):
|
||||||
bl_label = "Model View Definitions"
|
bl_label = "Model View Definitions"
|
||||||
bl_idname = "mvd.panel"
|
bl_idname = "mvd.panel"
|
||||||
|
|||||||
Reference in New Issue
Block a user