mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 02:47:48 +00:00
Fix #1786. Swap out sub-operators with refactored core calls.
This commit is contained in:
@@ -21,6 +21,7 @@ import importlib
|
||||
from . import handler, ui, prop, operator
|
||||
|
||||
modules = {
|
||||
"lendlease": None,
|
||||
"project": None,
|
||||
"search": None,
|
||||
"bcf": None,
|
||||
@@ -74,8 +75,6 @@ classes = [
|
||||
operator.SelectDataDir,
|
||||
operator.SelectSchemaDir,
|
||||
operator.SelectIfcFile,
|
||||
operator.ExportIFC,
|
||||
operator.ImportIFC,
|
||||
operator.OpenUpstream,
|
||||
operator.AddSectionPlane,
|
||||
operator.RemoveSectionPlane,
|
||||
@@ -105,13 +104,6 @@ for mod in modules.values():
|
||||
classes.extend(mod.classes)
|
||||
|
||||
|
||||
def menu_func_export(self, context):
|
||||
self.layout.operator(operator.ExportIFC.bl_idname, text="Industry Foundation Classes (.ifc/.ifczip/.ifcjson)")
|
||||
|
||||
|
||||
def menu_func_import(self, context):
|
||||
self.layout.operator(operator.ImportIFC.bl_idname, text="Industry Foundation Classes (.ifc/.ifczip/.ifcxml)")
|
||||
|
||||
|
||||
def on_register(scene):
|
||||
handler.setDefaultProperties(scene)
|
||||
@@ -129,8 +121,6 @@ def register():
|
||||
bpy.app.handlers.load_post.append(handler.setDefaultProperties)
|
||||
bpy.app.handlers.load_post.append(handler.loadIfcStore)
|
||||
bpy.app.handlers.save_pre.append(handler.ensureIfcExported)
|
||||
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=prop.BIMProperties)
|
||||
bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
|
||||
bpy.types.Material.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
|
||||
@@ -151,8 +141,6 @@ def unregister():
|
||||
bpy.app.handlers.load_post.remove(handler.setDefaultProperties)
|
||||
bpy.app.handlers.load_post.remove(handler.loadIfcStore)
|
||||
bpy.app.handlers.save_pre.remove(handler.ensureIfcExported)
|
||||
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.Object.BIMObjectProperties
|
||||
del bpy.types.Material.BIMObjectProperties
|
||||
|
||||
@@ -28,6 +28,8 @@ import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.placement
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.aggregate
|
||||
import blenderbim.core.spatial
|
||||
import blenderbim.core.style
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
@@ -135,7 +137,7 @@ class IfcExporter:
|
||||
float(props.blender_x_axis_ordinate),
|
||||
)
|
||||
if not np.allclose(ifc_matrix, blender_matrix, atol=0.0001):
|
||||
bpy.ops.bim.edit_object_placement(obj=obj.name)
|
||||
blenderbim.core.geometry.edit_object_placement(tool.Ifc, tool.Surveyor, obj=obj)
|
||||
|
||||
def sync_object_container(self, guid, obj):
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
@@ -166,9 +168,13 @@ class IfcExporter:
|
||||
|
||||
if parent.is_a("IfcSpatialStructureElement") and not element.is_a("IfcSpatialStructureElement"):
|
||||
if parent != ifcopenshell.util.element.get_container(element):
|
||||
bpy.ops.bim.assign_container(relating_structure=parent.id(), related_element=obj.name)
|
||||
blenderbim.core.spatial.assign_container(
|
||||
tool.Ifc, tool.Collector, tool.Container, structure_obj=parent_obj, element_obj=obj
|
||||
)
|
||||
elif parent != ifcopenshell.util.element.get_aggregate(element):
|
||||
bpy.ops.bim.assign_object(relating_object=parent_obj.name, related_object=obj.name)
|
||||
blenderbim.core.aggregate.assign_object(
|
||||
tool.Ifc, tool.Aggregate, tool.Collector, relating_obj=parent_obj, related_obj=obj
|
||||
)
|
||||
|
||||
def should_delete(self, obj):
|
||||
try:
|
||||
|
||||
@@ -305,7 +305,7 @@ class UpdateRepresentation(bpy.types.Operator):
|
||||
ifcopenshell.api.run("grid.create_axis_curve", self.file, **{"axis_curve": obj, "grid_axis": product})
|
||||
return
|
||||
|
||||
bpy.ops.bim.edit_object_placement(obj=obj.name)
|
||||
core.edit_object_placement(tool.Ifc, tool.Surveyor, obj=obj)
|
||||
|
||||
old_representation = self.file.by_id(obj.data.BIMMeshProperties.ifc_definition_id)
|
||||
context_of_items = old_representation.ContextOfItems
|
||||
@@ -335,7 +335,7 @@ class UpdateRepresentation(bpy.types.Operator):
|
||||
new_representation = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
|
||||
|
||||
[
|
||||
bpy.ops.bim.add_style(material=s.material.name)
|
||||
blenderbim.core.style.add_style(tool.Ifc, tool.Style, obj=s.material)
|
||||
for s in obj.material_slots
|
||||
if s.material and not s.material.BIMMaterialProperties.ifc_style_id
|
||||
]
|
||||
|
||||
@@ -39,6 +39,8 @@ classes = (
|
||||
operator.EnableEditingHeader,
|
||||
operator.DisableEditingHeader,
|
||||
operator.EditHeader,
|
||||
operator.ExportIFC,
|
||||
operator.ImportIFC,
|
||||
prop.LibraryElement,
|
||||
prop.FilterCategory,
|
||||
prop.Link,
|
||||
@@ -51,10 +53,21 @@ classes = (
|
||||
ui.BIM_UL_links,
|
||||
)
|
||||
|
||||
def menu_func_export(self, context):
|
||||
self.layout.operator(operator.ExportIFC.bl_idname, text="Industry Foundation Classes (.ifc/.ifczip/.ifcjson)")
|
||||
|
||||
|
||||
def menu_func_import(self, context):
|
||||
self.layout.operator(operator.ImportIFC.bl_idname, text="Industry Foundation Classes (.ifc/.ifczip/.ifcxml)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Scene.BIMProjectProperties = bpy.props.PointerProperty(type=prop.BIMProjectProperties)
|
||||
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
|
||||
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
|
||||
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
|
||||
del bpy.types.Scene.BIMProjectProperties
|
||||
|
||||
@@ -31,6 +31,7 @@ import blenderbim.core.context
|
||||
import blenderbim.core.owner
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim import import_ifc
|
||||
from blenderbim.bim import export_ifc
|
||||
|
||||
|
||||
class CreateProject(bpy.types.Operator):
|
||||
@@ -729,3 +730,79 @@ class LoadLink(bpy.types.Operator):
|
||||
link = context.scene.BIMProjectProperties.links.get(self.filepath)
|
||||
link.is_loaded = True
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class ExportIFC(bpy.types.Operator):
|
||||
bl_idname = "export_ifc.bim"
|
||||
bl_label = "Export IFC"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filename_ext = ".ifc"
|
||||
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml;*.ifcjson", options={"HIDDEN"})
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
json_version: bpy.props.EnumProperty(items=[("4", "4", ""), ("5a", "5a", "")], name="IFC JSON Version")
|
||||
json_compact: bpy.props.BoolProperty(name="Export Compact IFCJSON", default=False)
|
||||
|
||||
def invoke(self, context, event):
|
||||
if not IfcStore.get_file():
|
||||
self.report({"ERROR"}, "No IFC project is available for export - create or import a project first.")
|
||||
return {"FINISHED"}
|
||||
if context.scene.BIMProperties.ifc_file:
|
||||
self.filepath = context.scene.BIMProperties.ifc_file
|
||||
return self.execute(context)
|
||||
if not self.filepath:
|
||||
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".ifc")
|
||||
WindowManager = context.window_manager
|
||||
WindowManager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
start = time.time()
|
||||
logger = logging.getLogger("ExportIFC")
|
||||
path_log = os.path.join(context.scene.BIMProperties.data_dir, "process.log")
|
||||
if not os.access(context.scene.BIMProperties.data_dir, os.W_OK):
|
||||
path_log = os.path.join(tempfile.mkdtemp(), "process.log")
|
||||
logging.basicConfig(
|
||||
filename=path_log,
|
||||
filemode="a",
|
||||
level=logging.DEBUG,
|
||||
)
|
||||
extension = self.filepath.split(".")[-1]
|
||||
if extension == "ifczip":
|
||||
output_file = bpy.path.ensure_ext(self.filepath, ".ifczip")
|
||||
elif extension == "ifcjson":
|
||||
output_file = bpy.path.ensure_ext(self.filepath, ".ifcjson")
|
||||
else:
|
||||
output_file = bpy.path.ensure_ext(self.filepath, ".ifc")
|
||||
|
||||
settings = export_ifc.IfcExportSettings.factory(context, output_file, logger)
|
||||
settings.json_version = self.json_version
|
||||
settings.json_compact = self.json_compact
|
||||
|
||||
ifc_exporter = export_ifc.IfcExporter(settings)
|
||||
settings.logger.info("Starting export")
|
||||
ifc_exporter.export()
|
||||
settings.logger.info("Export finished in {:.2f} seconds".format(time.time() - start))
|
||||
print("Export finished in {:.2f} seconds".format(time.time() - start))
|
||||
scene = context.scene
|
||||
if not scene.DocProperties.ifc_files:
|
||||
new = scene.DocProperties.ifc_files.add()
|
||||
new.name = output_file
|
||||
if not scene.BIMProperties.ifc_file:
|
||||
scene.BIMProperties.ifc_file = output_file
|
||||
if bpy.data.is_saved and bpy.data.is_dirty and bpy.data.filepath:
|
||||
bpy.ops.wm.save_mainfile(filepath=bpy.data.filepath)
|
||||
blenderbim.bim.handler.purge_module_data()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class ImportIFC(bpy.types.Operator):
|
||||
bl_idname = "import_ifc.bim"
|
||||
bl_label = "Import IFC"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
bpy.ops.bim.load_project("INVOKE_DEFAULT")
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -43,11 +43,7 @@ class AssignContainer(bpy.types.Operator, Operator):
|
||||
structure_obj = tool.Ifc.get_object(tool.Ifc.get().by_id(self.structure))
|
||||
for element_obj in context.selected_objects:
|
||||
core.assign_container(
|
||||
tool.Ifc,
|
||||
tool.Collector,
|
||||
tool.Container,
|
||||
structure_obj=structure_obj,
|
||||
element_obj=element_obj,
|
||||
tool.Ifc, tool.Collector, tool.Container, structure_obj=structure_obj, element_obj=element_obj
|
||||
)
|
||||
|
||||
|
||||
@@ -127,6 +123,8 @@ class CopyToContainer(bpy.types.Operator):
|
||||
new_obj.data = obj.data.copy()
|
||||
new_obj.matrix_world = container_obj.matrix_world @ local_position
|
||||
bpy.ops.bim.copy_class(obj=new_obj.name)
|
||||
bpy.ops.bim.assign_container(relating_structure=container_id, related_element=new_obj.name)
|
||||
core.assign_container(
|
||||
tool.Ifc, tool.Collector, tool.Container, structure_obj=container_obj, element_obj=new_obj
|
||||
)
|
||||
obj.BIMObjectSpatialProperties.is_editing = False
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -25,89 +25,12 @@ import logging
|
||||
import webbrowser
|
||||
import ifcopenshell
|
||||
import blenderbim.bim.handler
|
||||
from . import export_ifc
|
||||
from . import schema
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from mathutils import Vector, Matrix, Euler
|
||||
from math import radians
|
||||
|
||||
|
||||
class ExportIFC(bpy.types.Operator):
|
||||
bl_idname = "export_ifc.bim"
|
||||
bl_label = "Export IFC"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filename_ext = ".ifc"
|
||||
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml;*.ifcjson", options={"HIDDEN"})
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
json_version: bpy.props.EnumProperty(items=[("4", "4", ""), ("5a", "5a", "")], name="IFC JSON Version")
|
||||
json_compact: bpy.props.BoolProperty(name="Export Compact IFCJSON", default=False)
|
||||
|
||||
def invoke(self, context, event):
|
||||
if not IfcStore.get_file():
|
||||
self.report({"ERROR"}, "No IFC project is available for export - create or import a project first.")
|
||||
return {"FINISHED"}
|
||||
if context.scene.BIMProperties.ifc_file:
|
||||
self.filepath = context.scene.BIMProperties.ifc_file
|
||||
return self.execute(context)
|
||||
if not self.filepath:
|
||||
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".ifc")
|
||||
WindowManager = context.window_manager
|
||||
WindowManager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
start = time.time()
|
||||
logger = logging.getLogger("ExportIFC")
|
||||
path_log = os.path.join(context.scene.BIMProperties.data_dir, "process.log")
|
||||
if not os.access(context.scene.BIMProperties.data_dir, os.W_OK):
|
||||
path_log = os.path.join(tempfile.mkdtemp(), "process.log")
|
||||
logging.basicConfig(
|
||||
filename=path_log,
|
||||
filemode="a",
|
||||
level=logging.DEBUG,
|
||||
)
|
||||
extension = self.filepath.split(".")[-1]
|
||||
if extension == "ifczip":
|
||||
output_file = bpy.path.ensure_ext(self.filepath, ".ifczip")
|
||||
elif extension == "ifcjson":
|
||||
output_file = bpy.path.ensure_ext(self.filepath, ".ifcjson")
|
||||
else:
|
||||
output_file = bpy.path.ensure_ext(self.filepath, ".ifc")
|
||||
|
||||
settings = export_ifc.IfcExportSettings.factory(context, output_file, logger)
|
||||
settings.json_version = self.json_version
|
||||
settings.json_compact = self.json_compact
|
||||
|
||||
ifc_exporter = export_ifc.IfcExporter(settings)
|
||||
settings.logger.info("Starting export")
|
||||
ifc_exporter.export()
|
||||
settings.logger.info("Export finished in {:.2f} seconds".format(time.time() - start))
|
||||
print("Export finished in {:.2f} seconds".format(time.time() - start))
|
||||
scene = context.scene
|
||||
if not scene.DocProperties.ifc_files:
|
||||
new = scene.DocProperties.ifc_files.add()
|
||||
new.name = output_file
|
||||
if not scene.BIMProperties.ifc_file:
|
||||
scene.BIMProperties.ifc_file = output_file
|
||||
if bpy.data.is_saved and bpy.data.is_dirty and bpy.data.filepath:
|
||||
bpy.ops.wm.save_mainfile(filepath=bpy.data.filepath)
|
||||
blenderbim.bim.handler.purge_module_data()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class ImportIFC(bpy.types.Operator):
|
||||
bl_idname = "import_ifc.bim"
|
||||
bl_label = "Import IFC"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
bpy.ops.bim.load_project("INVOKE_DEFAULT")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class OpenUri(bpy.types.Operator):
|
||||
bl_idname = "bim.open_uri"
|
||||
bl_label = "Open URI"
|
||||
|
||||
@@ -275,3 +275,14 @@ Scenario: Unlink IFC
|
||||
When I press "bim.unlink_ifc(filepath='{cwd}/test/files/basic.blend')"
|
||||
Then "scene.BIMProjectProperties.links.get('{cwd}/test/files/basic.blend')" is "None"
|
||||
And "scene.collection.children.get('IfcProject/My Project')" is "None"
|
||||
|
||||
Scenario: Export IFC - blank project
|
||||
Given an empty IFC project
|
||||
When I press "export_ifc.bim(filepath='{cwd}/test/files/export.ifc')"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Export IFC - with basic contents
|
||||
Given an empty Blender session
|
||||
And I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc')"
|
||||
When I press "export_ifc.bim(filepath='{cwd}/test/files/export.ifc')"
|
||||
Then nothing happens
|
||||
|
||||
Reference in New Issue
Block a user