Fix #1786. Swap out sub-operators with refactored core calls.

This commit is contained in:
Dion Moult
2021-10-13 10:49:28 +11:00
parent 13725411c9
commit dba6a8d0b4
8 changed files with 117 additions and 101 deletions
+1 -13
View File
@@ -21,6 +21,7 @@ import importlib
from . import handler, ui, prop, operator from . import handler, ui, prop, operator
modules = { modules = {
"lendlease": None,
"project": None, "project": None,
"search": None, "search": None,
"bcf": None, "bcf": None,
@@ -74,8 +75,6 @@ classes = [
operator.SelectDataDir, operator.SelectDataDir,
operator.SelectSchemaDir, operator.SelectSchemaDir,
operator.SelectIfcFile, operator.SelectIfcFile,
operator.ExportIFC,
operator.ImportIFC,
operator.OpenUpstream, operator.OpenUpstream,
operator.AddSectionPlane, operator.AddSectionPlane,
operator.RemoveSectionPlane, operator.RemoveSectionPlane,
@@ -105,13 +104,6 @@ for mod in modules.values():
classes.extend(mod.classes) 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): def on_register(scene):
handler.setDefaultProperties(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.setDefaultProperties)
bpy.app.handlers.load_post.append(handler.loadIfcStore) bpy.app.handlers.load_post.append(handler.loadIfcStore)
bpy.app.handlers.save_pre.append(handler.ensureIfcExported) 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.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties) bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
bpy.types.Material.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.setDefaultProperties)
bpy.app.handlers.load_post.remove(handler.loadIfcStore) bpy.app.handlers.load_post.remove(handler.loadIfcStore)
bpy.app.handlers.save_pre.remove(handler.ensureIfcExported) 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.Scene.BIMProperties
del bpy.types.Object.BIMObjectProperties del bpy.types.Object.BIMObjectProperties
del bpy.types.Material.BIMObjectProperties del bpy.types.Material.BIMObjectProperties
+9 -3
View File
@@ -28,6 +28,8 @@ import ifcopenshell
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.util.placement import ifcopenshell.util.placement
import blenderbim.tool as tool import blenderbim.tool as tool
import blenderbim.core.aggregate
import blenderbim.core.spatial
import blenderbim.core.style import blenderbim.core.style
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
@@ -135,7 +137,7 @@ class IfcExporter:
float(props.blender_x_axis_ordinate), float(props.blender_x_axis_ordinate),
) )
if not np.allclose(ifc_matrix, blender_matrix, atol=0.0001): 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): def sync_object_container(self, guid, obj):
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) 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.is_a("IfcSpatialStructureElement") and not element.is_a("IfcSpatialStructureElement"):
if parent != ifcopenshell.util.element.get_container(element): 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): 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): def should_delete(self, obj):
try: 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}) ifcopenshell.api.run("grid.create_axis_curve", self.file, **{"axis_curve": obj, "grid_axis": product})
return 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) old_representation = self.file.by_id(obj.data.BIMMeshProperties.ifc_definition_id)
context_of_items = old_representation.ContextOfItems 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) 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 for s in obj.material_slots
if s.material and not s.material.BIMMaterialProperties.ifc_style_id if s.material and not s.material.BIMMaterialProperties.ifc_style_id
] ]
@@ -39,6 +39,8 @@ classes = (
operator.EnableEditingHeader, operator.EnableEditingHeader,
operator.DisableEditingHeader, operator.DisableEditingHeader,
operator.EditHeader, operator.EditHeader,
operator.ExportIFC,
operator.ImportIFC,
prop.LibraryElement, prop.LibraryElement,
prop.FilterCategory, prop.FilterCategory,
prop.Link, prop.Link,
@@ -51,10 +53,21 @@ classes = (
ui.BIM_UL_links, 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(): def register():
bpy.types.Scene.BIMProjectProperties = bpy.props.PointerProperty(type=prop.BIMProjectProperties) 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(): 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 del bpy.types.Scene.BIMProjectProperties
@@ -31,6 +31,7 @@ import blenderbim.core.context
import blenderbim.core.owner import blenderbim.core.owner
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from blenderbim.bim import import_ifc from blenderbim.bim import import_ifc
from blenderbim.bim import export_ifc
class CreateProject(bpy.types.Operator): class CreateProject(bpy.types.Operator):
@@ -729,3 +730,79 @@ class LoadLink(bpy.types.Operator):
link = context.scene.BIMProjectProperties.links.get(self.filepath) link = context.scene.BIMProjectProperties.links.get(self.filepath)
link.is_loaded = True link.is_loaded = True
return {"FINISHED"} 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)) structure_obj = tool.Ifc.get_object(tool.Ifc.get().by_id(self.structure))
for element_obj in context.selected_objects: for element_obj in context.selected_objects:
core.assign_container( core.assign_container(
tool.Ifc, tool.Ifc, tool.Collector, tool.Container, structure_obj=structure_obj, element_obj=element_obj
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.data = obj.data.copy()
new_obj.matrix_world = container_obj.matrix_world @ local_position new_obj.matrix_world = container_obj.matrix_world @ local_position
bpy.ops.bim.copy_class(obj=new_obj.name) 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 obj.BIMObjectSpatialProperties.is_editing = False
return {"FINISHED"} return {"FINISHED"}
-77
View File
@@ -25,89 +25,12 @@ import logging
import webbrowser import webbrowser
import ifcopenshell import ifcopenshell
import blenderbim.bim.handler import blenderbim.bim.handler
from . import export_ifc
from . import schema from . import schema
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from mathutils import Vector, Matrix, Euler from mathutils import Vector, Matrix, Euler
from math import radians 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): class OpenUri(bpy.types.Operator):
bl_idname = "bim.open_uri" bl_idname = "bim.open_uri"
bl_label = "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')" When I press "bim.unlink_ifc(filepath='{cwd}/test/files/basic.blend')"
Then "scene.BIMProjectProperties.links.get('{cwd}/test/files/basic.blend')" is "None" Then "scene.BIMProjectProperties.links.get('{cwd}/test/files/basic.blend')" is "None"
And "scene.collection.children.get('IfcProject/My Project')" 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