diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index 898da0642b..2d7ab5bc4e 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -5,63 +5,18 @@ bpy = sys.modules.get("bpy") if bpy is not None: import bpy + import blenderbim.bim.module.covetool as module_covetool + import blenderbim.bim.module.model as module_model + import blenderbim.bim.module.bcf as module_bcf from . import ui, prop, operator - from .module.covetool import prop as covetool_prop - from .module.covetool import ui as covetool_ui - from .module.covetool import operator as covetool_operator - - from .module.model import grid as model_grid - from .module.model import wall as model_wall - from .module.model import stair as model_stair - from .module.model import door as model_door - from .module.model import window as model_window - from .module.model import slab as model_slab - from .module.model import opening as model_opening - - classes = ( + classes = [ operator.ReassignClass, operator.AssignClass, operator.UnassignClass, operator.SelectClass, operator.SelectType, - operator.NewBcfProject, - operator.LoadBcfProject, - operator.LoadBcfTopics, - operator.LoadBcfTopic, - operator.LoadBcfComments, - operator.EditBcfProjectName, - operator.EditBcfAuthor, - operator.EditBcfTopicName, - operator.EditBcfTopic, - operator.SaveBcfProject, - operator.AddBcfTopic, - operator.AddBcfHeaderFile, - operator.AddBcfBimSnippet, - operator.AddBcfReferenceLink, - operator.AddBcfDocumentReference, - operator.AddBcfLabel, - operator.AddBcfRelatedTopic, - operator.ViewBcfTopic, - operator.RemoveBcfComment, - operator.RemoveBcfBimSnippet, - operator.RemoveBcfReferenceLink, - operator.RemoveBcfDocumentReference, - operator.RemoveBcfRelatedTopic, - operator.EditBcfReferenceLinks, - operator.EditBcfLabels, - operator.RemoveBcfLabel, - operator.EditBcfComment, - operator.AddBcfComment, - operator.ActivateBcfViewpoint, - operator.AddBcfViewpoint, - operator.RemoveBcfViewpoint, - operator.RemoveBcfFile, operator.OpenUri, - operator.OpenBcfReferenceLink, - operator.SelectBcfHeaderFile, - operator.SelectBcfBimSnippetReference, - operator.SelectBcfDocumentReference, operator.SelectFeaturesDir, operator.SelectDiffJsonFile, operator.SelectDiffNewFile, @@ -160,6 +115,7 @@ if bpy is not None: operator.AddDrawingToSheet, operator.CreateSheets, operator.OpenView, + operator.OpenViewCamera, operator.ActivateView, operator.ExecuteIfcDiff, operator.VisualiseDiff, @@ -264,8 +220,6 @@ if bpy is not None: operator.SnapSpacesTogether, operator.CopyGrid, prop.StrProperty, - prop.BcfReferenceLink, - prop.BcfLabel, prop.Attribute, prop.MaterialLayer, prop.MaterialConstituent, @@ -291,15 +245,10 @@ if bpy is not None: prop.Schedule, prop.DrawingStyle, prop.Sheet, - prop.BcfBimSnippet, - prop.BcfDocumentReference, - prop.BcfComment, - prop.BcfTopic, prop.Subcontext, prop.PresentationLayer, prop.BIMProperties, prop.BIMDebugProperties, - prop.BCFProperties, prop.DocProperties, prop.BIMLibrary, prop.MapConversion, @@ -328,9 +277,6 @@ if bpy is not None: ui.BIM_PT_search, ui.BIM_PT_ifccsv, ui.BIM_PT_ifcclash, - ui.BIM_PT_bcf, - ui.BIM_PT_bcf_metadata, - ui.BIM_PT_bcf_comments, ui.BIM_PT_owner, ui.BIM_PT_people, ui.BIM_PT_organisations, @@ -364,6 +310,7 @@ if bpy is not None: ui.BIM_PT_clash_manager, ui.BIM_PT_misc_utilities, ui.BIM_UL_generic, + ui.BIM_UL_drawinglist, ui.BIM_UL_clash_sets, ui.BIM_UL_smart_groups, ui.BIM_UL_constraints, @@ -372,22 +319,11 @@ if bpy is not None: ui.BIM_UL_topics, ui.BIM_UL_classifications, ui.BIM_ADDON_preferences, - covetool_prop.CoveToolProject, - covetool_prop.CoveToolSimpleAnalysis, - covetool_prop.CoveToolProperties, - covetool_ui.BIM_UL_covetool_projects, - covetool_ui.BIM_PT_covetool, - covetool_operator.Login, - covetool_operator.RunSimpleAnalysis, - covetool_operator.RunAnalysis, - model_grid.BIM_OT_add_object, - model_wall.BIM_OT_add_object, - model_stair.BIM_OT_add_object, - model_door.BIM_OT_add_object, - model_window.BIM_OT_add_object, - model_slab.BIM_OT_add_object, - model_opening.BIM_OT_add_object, - ) + ] + + classes.extend(module_bcf.classes) + classes.extend(module_covetool.classes) + classes.extend(module_model.classes) def menu_func_export(self, context): self.layout.operator(operator.ExportIFC.bl_idname, text="Industry Foundation Classes (.ifc/.ifczip/.ifcjson)") @@ -408,7 +344,6 @@ if bpy is not None: bpy.types.TOPBAR_MT_file_import.append(menu_func_import) bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties) bpy.types.Scene.BIMDebugProperties = bpy.props.PointerProperty(type=prop.BIMDebugProperties) - bpy.types.Scene.BCFProperties = bpy.props.PointerProperty(type=prop.BCFProperties) bpy.types.Scene.DocProperties = bpy.props.PointerProperty(type=prop.DocProperties) bpy.types.Scene.BIMLibrary = bpy.props.PointerProperty(type=prop.BIMLibrary) bpy.types.Scene.MapConversion = bpy.props.PointerProperty(type=prop.MapConversion) @@ -419,15 +354,10 @@ if bpy is not None: bpy.types.Mesh.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties) bpy.types.Camera.BIMCameraProperties = bpy.props.PointerProperty(type=prop.BIMCameraProperties) bpy.types.TextCurve.BIMTextProperties = bpy.props.PointerProperty(type=prop.BIMTextProperties) - bpy.types.Scene.CoveToolProperties = bpy.props.PointerProperty(type=covetool_prop.CoveToolProperties) bpy.types.SCENE_PT_unit.append(ui.ifc_units) - bpy.types.VIEW3D_MT_mesh_add.append(model_grid.add_object_button) - bpy.types.VIEW3D_MT_mesh_add.append(model_wall.add_object_button) - bpy.types.VIEW3D_MT_mesh_add.append(model_stair.add_object_button) - bpy.types.VIEW3D_MT_mesh_add.append(model_door.add_object_button) - bpy.types.VIEW3D_MT_mesh_add.append(model_window.add_object_button) - bpy.types.VIEW3D_MT_mesh_add.append(model_slab.add_object_button) - bpy.types.VIEW3D_MT_mesh_add.append(model_opening.add_object_button) + module_bcf.register() + module_covetool.register() + module_model.register() bpy.app.handlers.depsgraph_update_pre.append(operator.depsgraph_update_pre_handler) def unregister(): @@ -438,7 +368,6 @@ if bpy is not None: bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) del bpy.types.Scene.BIMProperties del bpy.types.Scene.BIMDebugProperties - del bpy.types.Scene.BCFProperties del bpy.types.Scene.DocProperties del bpy.types.Scene.MapConversion del bpy.types.Scene.TargetCRS @@ -449,11 +378,7 @@ if bpy is not None: del bpy.types.Camera.BIMCameraProperties del bpy.types.TextCurve.BIMTextProperties bpy.types.SCENE_PT_unit.remove(ui.ifc_units) - bpy.types.VIEW3D_MT_mesh_add.remove(model_grid.add_object_button) - bpy.types.VIEW3D_MT_mesh_add.remove(model_wall.add_object_button) - bpy.types.VIEW3D_MT_mesh_add.remove(model_stair.add_object_button) - bpy.types.VIEW3D_MT_mesh_add.remove(model_door.add_object_button) - bpy.types.VIEW3D_MT_mesh_add.remove(model_window.add_object_button) - bpy.types.VIEW3D_MT_mesh_add.remove(model_slab.add_object_button) - bpy.types.VIEW3D_MT_mesh_add.remove(model_opening.add_object_button) + module_model.unregister() + module_covetool.unregister() + module_bcf.unregister() bpy.app.handlers.depsgraph_update_pre.remove(operator.depsgraph_update_pre_handler) diff --git a/src/ifcblenderexport/blenderbim/bim/module/bcf/__init__.py b/src/ifcblenderexport/blenderbim/bim/module/bcf/__init__.py new file mode 100644 index 0000000000..ab9af36d50 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/bcf/__init__.py @@ -0,0 +1,59 @@ +import bpy +from . import ui, prop, operator + +classes = ( + operator.NewBcfProject, + operator.LoadBcfProject, + operator.LoadBcfTopics, + operator.LoadBcfTopic, + operator.LoadBcfComments, + operator.EditBcfProjectName, + operator.EditBcfAuthor, + operator.EditBcfTopicName, + operator.EditBcfTopic, + operator.SaveBcfProject, + operator.AddBcfTopic, + operator.AddBcfHeaderFile, + operator.AddBcfBimSnippet, + operator.AddBcfReferenceLink, + operator.AddBcfDocumentReference, + operator.AddBcfLabel, + operator.AddBcfRelatedTopic, + operator.ViewBcfTopic, + operator.RemoveBcfComment, + operator.RemoveBcfBimSnippet, + operator.RemoveBcfReferenceLink, + operator.RemoveBcfDocumentReference, + operator.RemoveBcfRelatedTopic, + operator.EditBcfReferenceLinks, + operator.EditBcfLabels, + operator.RemoveBcfLabel, + operator.EditBcfComment, + operator.AddBcfComment, + operator.ActivateBcfViewpoint, + operator.AddBcfViewpoint, + operator.RemoveBcfViewpoint, + operator.RemoveBcfFile, + operator.OpenBcfReferenceLink, + operator.SelectBcfHeaderFile, + operator.SelectBcfBimSnippetReference, + operator.SelectBcfDocumentReference, + prop.BcfReferenceLink, + prop.BcfLabel, + prop.BcfBimSnippet, + prop.BcfDocumentReference, + prop.BcfComment, + prop.BcfTopic, + prop.BCFProperties, + ui.BIM_PT_bcf, + ui.BIM_PT_bcf_metadata, + ui.BIM_PT_bcf_comments, +) + + +def register(): + bpy.types.Scene.BCFProperties = bpy.props.PointerProperty(type=prop.BCFProperties) + + +def unregister(): + del bpy.types.Scene.BCFProperties diff --git a/src/ifcblenderexport/blenderbim/bim/bcfstore.py b/src/ifcblenderexport/blenderbim/bim/module/bcf/bcfstore.py similarity index 100% rename from src/ifcblenderexport/blenderbim/bim/bcfstore.py rename to src/ifcblenderexport/blenderbim/bim/module/bcf/bcfstore.py diff --git a/src/ifcblenderexport/blenderbim/bim/module/bcf/operator.py b/src/ifcblenderexport/blenderbim/bim/module/bcf/operator.py new file mode 100644 index 0000000000..e953023915 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/bcf/operator.py @@ -0,0 +1,868 @@ +import os +import bpy +import bcf +from . import bcfstore + +class NewBcfProject(bpy.types.Operator): + bl_idname = "bim.new_bcf_project" + bl_label = "New BCF Project" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + bcfxml.new_project() + bpy.ops.bim.load_bcf_project() + return {"FINISHED"} + + +class LoadBcfProject(bpy.types.Operator): + bl_idname = "bim.load_bcf_project" + bl_label = "Load BCF Project" + filepath: bpy.props.StringProperty(subtype="FILE_PATH") + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + if self.filepath: + bcfxml.get_project(self.filepath) + bpy.context.scene.BCFProperties.name = bcfxml.project.name + bpy.ops.bim.load_bcf_topics() + bpy.context.scene.BCFProperties.is_loaded = True + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {"RUNNING_MODAL"} + + +class LoadBcfTopics(bpy.types.Operator): + bl_idname = "bim.load_bcf_topics" + bl_label = "Load BCF Topics" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + bcfxml.get_topics() + while len(bpy.context.scene.BCFProperties.topics) > 0: + bpy.context.scene.BCFProperties.topics.remove(0) + index = 0 + for topic_guid in bcfxml.topics.keys(): + new = bpy.context.scene.BCFProperties.topics.add() + bpy.ops.bim.load_bcf_topic(topic_guid = topic_guid, topic_index = index) + index += 1 + return {"FINISHED"} + + +class LoadBcfTopic(bpy.types.Operator): + bl_idname = "bim.load_bcf_topic" + bl_label = "Load BCF Topics" + topic_guid: bpy.props.StringProperty() + topic_index: bpy.props.IntProperty() + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + topic = bcfxml.get_topic(self.topic_guid) + new = bpy.context.scene.BCFProperties.topics[self.topic_index] + data_map = { + "name": topic.guid, + "title": topic.title, + "type": topic.topic_type, + "status": topic.topic_status, + "priority": topic.priority, + "stage": topic.stage, + "creation_date": topic.creation_date, + "creation_author": topic.creation_author, + "modified_date": topic.modified_date, + "modified_author": topic.modified_author, + "assigned_to": topic.assigned_to, + "due_date": topic.due_date, + "description": topic.description + } + for key, value in data_map.items(): + if value is not None: + setattr(new, key, str(value)) + while len(new.reference_links) > 0: + new.reference_links.remove(0) + for reference_link in topic.reference_links: + new2 = new.reference_links.add() + new2.name = reference_link + while len(new.labels) > 0: + new.labels.remove(0) + for label in topic.labels: + new2 = new.labels.add() + new2.name = label + if topic.bim_snippet: + data_map = { + "type": topic.bim_snippet.snippet_type, + "is_external": topic.bim_snippet.is_external, + "reference": topic.bim_snippet.reference, + "schema": topic.bim_snippet.reference_schema + } + for key, value in data_map.items(): + if value is not None: + setattr(new.bim_snippet, key, value) + while len(new.document_references) > 0: + new.document_references.remove(0) + for doc in topic.document_references: + new2 = new.document_references.add() + data_map = { + "reference": doc.referenced_document, + "description": doc.description, + "guid": doc.guid, + "is_external": doc.is_external + } + for key, value in data_map.items(): + if value is not None: + setattr(new2, key, value) + while len(new.related_topics) > 0: + new.related_topics.remove(0) + for related_topic in topic.related_topics: + new2 = new.related_topics.add() + new2.name = related_topic.guid + bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid) + return {"FINISHED"} + + +class LoadBcfComments(bpy.types.Operator): + bl_idname = "bim.load_bcf_comments" + bl_label = "Load BCF Comments" + topic_guid: bpy.props.StringProperty() + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + bcfxml.get_comments(self.topic_guid) + blender_topic = bpy.context.scene.BCFProperties.topics.get(self.topic_guid) + while len(blender_topic.comments) > 0: + blender_topic.comments.remove(0) + for comment in bcfxml.topics[self.topic_guid].comments.values(): + new = blender_topic.comments.add() + data_map = { + "name": comment.guid, + "comment": comment.comment, + "viewpoint": comment.viewpoint.guid if comment.viewpoint else None, + "date": comment.date, + "author": comment.author, + "modified_date": comment.modified_date, + "modified_author": comment.modified_author, + } + for key, value in data_map.items(): + if value is not None: + setattr(new, key, str(value)) + return {"FINISHED"} + + +class EditBcfProjectName(bpy.types.Operator): + bl_idname = "bim.edit_bcf_project_name" + bl_label = "Edit BCF Project Name" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + bcfxml.project.name = bpy.context.scene.BCFProperties.name + bcfxml.edit_project() + return {"FINISHED"} + + +class EditBcfAuthor(bpy.types.Operator): + bl_idname = "bim.edit_bcf_author" + bl_label = "Edit BCF Author" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + bcfxml.author = bpy.context.scene.BCFProperties.author + return {"FINISHED"} + + +class EditBcfTopicName(bpy.types.Operator): + bl_idname = "bim.edit_bcf_topic_name" + bl_label = "Edit BCF Topic Name" + + def execute(self, context): + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + bcfxml = bcfstore.BcfStore.get_bcfxml() + topic = bcfxml.topics[blender_topic.name] + topic.title = blender_topic.title + bcfxml.edit_topic(topic) + return {"FINISHED"} + + +class EditBcfTopic(bpy.types.Operator): + bl_idname = "bim.edit_bcf_topic" + bl_label = "Edit BCF Topic" + + def execute(self, context): + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + bcfxml = bcfstore.BcfStore.get_bcfxml() + + topic = bcfxml.topics[blender_topic.name] + topic.title = blender_topic.title or None + topic.priority = blender_topic.priority or None + topic.due_date = blender_topic.due_date or None + topic.assigned_to = blender_topic.assigned_to or None + topic.stage = blender_topic.stage or None + topic.description = blender_topic.description or None + topic.topic_status = blender_topic.status or None + topic.topic_type = blender_topic.type or None + + bcfxml.edit_topic(topic) + props.active_topic_index = props.active_topic_index # Refreshes the BCF Topic + return {"FINISHED"} + + +class SaveBcfProject(bpy.types.Operator): + bl_idname = "bim.save_bcf_project" + bl_label = "Save BCF Project" + filepath: bpy.props.StringProperty(subtype="FILE_PATH") + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + bcfxml.save_project(self.filepath) + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {"RUNNING_MODAL"} + + +class AddBcfTopic(bpy.types.Operator): + bl_idname = "bim.add_bcf_topic" + bl_label = "Add BCF Topic" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + bcfxml.add_topic() + new = bpy.context.scene.BCFProperties.topics.add() + new.name = "New Topic" + bpy.ops.bim.load_bcf_topics() + return {"FINISHED"} + + +class AddBcfBimSnippet(bpy.types.Operator): + bl_idname = "bim.add_bcf_bim_snippet" + bl_label = "Add BCF BIM Snippet" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + bim_snippet = bcf.data.BimSnippet() + bim_snippet.reference = blender_topic.bim_snippet_reference + bim_snippet.reference_schema = blender_topic.bim_snippet_schema + bim_snippet.snippet_type = blender_topic.bim_snippet_type + bcfxml.add_bim_snippet(topic, bim_snippet) + bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index) + return {"FINISHED"} + + +class AddBcfRelatedTopic(bpy.types.Operator): + bl_idname = "bim.add_bcf_related_topic" + bl_label = "Add BCF Related Topic" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + related_topic = None + for topic in bcfxml.topics.values(): + if topic.title == blender_topic.related_topic: + related_topic = bcf.data.RelatedTopic() + related_topic.guid = topic.guid + break + if not related_topic: + return {"FINISHED"} + topic = bcfxml.topics[blender_topic.name] + topic.related_topics.append(related_topic) + bcfxml.edit_topic(topic) + bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index) + return {"FINISHED"} + + +class AddBcfHeaderFile(bpy.types.Operator): + bl_idname = "bim.add_bcf_header_file" + bl_label = "Add BCF Header File" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + header_file = bcf.data.HeaderFile() + header_file.reference = blender_topic.file_reference + if not os.path.exists(header_file.reference): + header_file.filename = header_file.reference + if len(blender_topic.file_ifc_project) == 22: + header_file.ifc_project = blender_topic.file_ifc_project + if len(blender_topic.file_ifc_spatial_structure_element) == 22: + header_file.ifc_spatial_structure_element = blender_topic.file_ifc_spatial_structure_element + bcfxml.add_file(topic, header_file) + props.active_topic_index = props.active_topic_index # refreshes the BCF Topic + return {"FINISHED"} + + +class ViewBcfTopic(bpy.types.Operator): + bl_idname = "bim.view_bcf_topic" + bl_label = "Get BCF Topic" + topic_guid: bpy.props.StringProperty() + + def execute(self, context): + for index, topic in enumerate(bpy.context.scene.BCFProperties.topics): + if topic.guid.lower() == self.topic_guid.lower(): + bpy.context.scene.BCFProperties.active_topic_index = index + return {"FINISHED"} + + +class AddBcfViewpoint(bpy.types.Operator): + bl_idname = "bim.add_bcf_viewpoint" + bl_label = "Add BCF Viewpoint" + + def execute(self, context): + if not bpy.context.scene.camera: + return {"FINISHED"} + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + viewpoint = bcf.data.Viewpoint() + + if bpy.context.scene.camera.data.type == "ORTHO": + camera = bcf.data.OrthogonalCamera() + camera.view_to_world_scale = bpy.context.scene.camera.data.ortho_scale + viewpoint.orthogonal_camera = camera + elif bpy.context.scene.camera.data.type == "PERSP": + camera = bcf.data.PerspectiveCamera() + camera.field_of_view = degrees(bpy.context.scene.camera.data.angle) + viewpoint.perspective_camera = camera + camera.camera_view_point.x = bpy.context.scene.camera.location.x + camera.camera_view_point.y = bpy.context.scene.camera.location.y + camera.camera_view_point.z = bpy.context.scene.camera.location.z + direction = bpy.context.scene.camera.matrix_world.to_quaternion() @ Vector((0.0, 0.0, -1.0)) + camera.camera_direction.x = direction.x + camera.camera_direction.y = direction.y + camera.camera_direction.z = direction.z + up = bpy.context.scene.camera.matrix_world.to_quaternion() @ Vector((0.0, 1.0, 0.0)) + camera.camera_up_vector.x = up.x + camera.camera_up_vector.y = up.y + camera.camera_up_vector.z = up.z + + old_file_format = bpy.context.scene.render.image_settings.file_format + bpy.context.scene.render.image_settings.file_format = "PNG" + old_filepath = bpy.context.scene.render.filepath + bpy.context.scene.render.filepath = os.path.join(bpy.context.scene.BIMProperties.data_dir, "snapshot.png") + bpy.ops.render.opengl(write_still=True) + viewpoint.snapshot = bpy.context.scene.render.filepath + + bcfxml.add_viewpoint(topic, viewpoint) + bpy.context.scene.render.filepath = old_filepath + bpy.context.scene.render.image_settings.file_format = old_file_format + props.active_topic_index = props.active_topic_index # refreshes the BCF Topic + return {"FINISHED"} + + +class RemoveBcfViewpoint(bpy.types.Operator): + bl_idname = "bim.remove_bcf_viewpoint" + bl_label = "Remove BCF Viewpoint" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + viewpoint_guid = blender_topic.viewpoints + topic = bcfxml.topics[blender_topic.name] + bcfxml.delete_viewpoint(viewpoint_guid, topic) + props.active_topic_index = props.active_topic_index # Refreshes the BCF Topic + return {"FINISHED"} + + +class RemoveBcfFile(bpy.types.Operator): + bl_idname = "bim.remove_bcf_file" + bl_label = "Remove BCF File" + index: bpy.props.IntProperty() + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + bcfxml.delete_file(topic, self.index) + props.active_topic_index = props.active_topic_index # Refreshes the BCF Topic + return {"FINISHED"} + + +class AddBcfReferenceLink(bpy.types.Operator): + bl_idname = "bim.add_bcf_reference_link" + bl_label = "Add BCF Reference Link" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + if not blender_topic.reference_link: + return {"FINISHED"} + topic.reference_links.append(blender_topic.reference_link) + bcfxml.edit_topic(topic) + bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index) + blender_topic.reference_link = "" + return {"FINISHED"} + + +class AddBcfDocumentReference(bpy.types.Operator): + bl_idname = "bim.add_bcf_document_reference" + bl_label = "Add BCF Document Reference" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + if not blender_topic.document_reference: + return {"FINISHED"} + document_reference = bcf.data.DocumentReference() + document_reference.referenced_document = blender_topic.document_reference + document_reference.description = blender_topic.document_reference_description or None + bcfxml.add_document_reference(topic, document_reference) + bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index) + blender_topic.document_reference = "" + blender_topic.document_reference_description = "" + return {"FINISHED"} + + +class AddBcfLabel(bpy.types.Operator): + bl_idname = "bim.add_bcf_label" + bl_label = "Add BCF Label" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + if not blender_topic.label: + return {"FINISHED"} + new = blender_topic.labels.add() + new.name = blender_topic.label + topic.labels.append(blender_topic.label) + bcfxml.edit_topic(topic) + blender_topic.label = "" + return {"FINISHED"} + + +class EditBcfReferenceLinks(bpy.types.Operator): + bl_idname = "bim.edit_bcf_reference_links" + bl_label = "Edit BCF Reference Link" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + for index, reference_link in enumerate(topic.reference_links): + if reference_link == blender_topic.reference_links[index].name: + continue + topic.reference_links[index] = blender_topic.reference_links[index].name + bcfxml.edit_topic(topic) + return {"FINISHED"} + + +class EditBcfLabels(bpy.types.Operator): + bl_idname = "bim.edit_bcf_labels" + bl_label = "Edit BCF Labels" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + for index, label in enumerate(blender_topic.labels): + if label.name == topic.labels[index]: + continue + topic.labels[index] = blender_topic.labels[index].name + bcfxml.edit_topic(topic) + return {"FINISHED"} + + +class RemoveBcfReferenceLink(bpy.types.Operator): + bl_idname = "bim.remove_bcf_reference_link" + bl_label = "Remove BCF Reference Link" + index: bpy.props.IntProperty() + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + del topic.reference_links[self.index] + bcfxml.edit_topic(topic) + blender_topic.reference_links.remove(self.index) + return {"FINISHED"} + + +class RemoveBcfLabel(bpy.types.Operator): + bl_idname = "bim.remove_bcf_label" + bl_label = "Remove BCF Label" + index: bpy.props.IntProperty() + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + del topic.labels[self.index] + bcfxml.edit_topic(topic) + blender_topic.labels.remove(self.index) + return {"FINISHED"} + + +class RemoveBcfBimSnippet(bpy.types.Operator): + bl_idname = "bim.remove_bcf_bim_snippet" + bl_label = "Remove BCF BIM Snippet" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + bcfxml.delete_bim_snippet(topic) + blender_topic.bim_snippet.schema = "" + blender_topic.bim_snippet.reference = "" + blender_topic.bim_snippet.type = "" + return {"FINISHED"} + + +class RemoveBcfDocumentReference(bpy.types.Operator): + bl_idname = "bim.remove_bcf_document_reference" + bl_label = "Remove BCF Document Reference" + index: bpy.props.IntProperty() + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + bcfxml.delete_document_reference(topic, self.index) + bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index) + return {"FINISHED"} + + +class RemoveBcfRelatedTopic(bpy.types.Operator): + bl_idname = "bim.remove_bcf_related_topic" + bl_label = "Remove BCF Related Topic" + index: bpy.props.IntProperty() + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + del topic.related_topics[self.index] + bcfxml.edit_topic(topic) + bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index) + return {"FINISHED"} + + +class RemoveBcfComment(bpy.types.Operator): + bl_idname = "bim.remove_bcf_comment" + bl_label = "Remove BCF Comment" + comment_guid: bpy.props.StringProperty() + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + bcfxml.delete_comment(self.comment_guid, topic) + bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid) + return {"FINISHED"} + + +class EditBcfComment(bpy.types.Operator): + bl_idname = "bim.edit_bcf_comment" + bl_label = "Edit BCF Comment" + comment_guid: bpy.props.StringProperty() + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + blender_comment = blender_topic.comments.get(self.comment_guid) + topic = bcfxml.topics[blender_topic.name] + comment = topic.comments[self.comment_guid] + comment.comment = blender_comment.comment + bcfxml.edit_comment(comment, topic) + bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid) + return {"FINISHED"} + + +class AddBcfComment(bpy.types.Operator): + bl_idname = "bim.add_bcf_comment" + bl_label = "Add BCF Comment" + comment_guid: bpy.props.StringProperty() + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + if not blender_topic.comment: + return {"FINISHED"} + comment = bcf.data.Comment() + comment.comment = blender_topic.comment + if blender_topic.has_related_viewpoint and blender_topic.viewpoints: + comment.viewpoint = bcf.data.Viewpoint() + comment.viewpoint.guid = blender_topic.viewpoints + bcfxml.add_comment(topic, comment) + bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid) + print(bcfxml.filepath) + return {"FINISHED"} + + +class ActivateBcfViewpoint(bpy.types.Operator): + bl_idname = "bim.activate_bcf_viewpoint" + bl_label = "Activate BCF Viewpoint" + + def execute(self, context): + bcfxml = bcfstore.BcfStore.get_bcfxml() + props = bpy.context.scene.BCFProperties + blender_topic = props.topics[props.active_topic_index] + topic = bcfxml.topics[blender_topic.name] + if not topic.viewpoints: + return {"FINISHED"} + + viewpoint_guid = blender_topic.viewpoints + viewpoint = topic.viewpoints[viewpoint_guid] + obj = bpy.data.objects.get("Viewpoint") + if not obj: + obj = bpy.data.objects.new("Viewpoint", bpy.data.cameras.new("Viewpoint")) + bpy.context.scene.collection.objects.link(obj) + bpy.context.scene.camera = obj + + cam_width = bpy.context.scene.render.resolution_x + cam_height = bpy.context.scene.render.resolution_y + cam_aspect = cam_width / cam_height + + if viewpoint.snapshot: + obj.data.show_background_images = True + while len(obj.data.background_images) > 0: + obj.data.background_images.remove(obj.data.background_images[0]) + background = obj.data.background_images.new() + background.image = bpy.data.images.load( + os.path.join(bcfxml.filepath, topic.guid, viewpoint.snapshot) + ) + src_width = background.image.size[0] + src_height = background.image.size[1] + src_aspect = src_width / src_height + + if src_aspect > cam_aspect: + background.frame_method = "FIT" + else: + background.frame_method = "CROP" + background.display_depth = "FRONT" + area = next(area for area in bpy.context.screen.areas if area.type == "VIEW_3D") + area.spaces[0].region_3d.view_perspective = "CAMERA" + + if viewpoint.orthogonal_camera: + camera = viewpoint.orthogonal_camera + obj.data.type = "ORTHO" + obj.data.ortho_scale = viewpoint.orthogonal_camera.view_to_world_scale + elif viewpoint.perspective_camera: + camera = viewpoint.perspective_camera + obj.data.type = "PERSP" + if cam_aspect >= 1: + obj.data.angle = radians(camera.field_of_view) + else: + # https://blender.stackexchange.com/questions/23431/how-to-set-camera-horizontal-and-vertical-fov + obj.data.angle = 2 * atan((0.5 * cam_height) / (0.5 * cam_width / tan(radians(camera.field_of_view) / 2))) + + self.set_viewpoint_components(viewpoint) + + gp = bpy.data.grease_pencils.get("BCF") + if gp: + bpy.data.grease_pencils.remove(gp) + if viewpoint.lines: + self.draw_lines(viewpoint) + + self.delete_clipping_planes() + if viewpoint.clipping_planes: + self.create_clipping_planes(viewpoint) + + self.delete_bitmaps() + if viewpoint.bitmaps: + self.create_bitmaps(bcfxml, viewpoint, topic) + + z_axis = Vector((-camera.camera_direction.x, -camera.camera_direction.y, -camera.camera_direction.z)).normalized() + y_axis = Vector((camera.camera_up_vector.x, camera.camera_up_vector.y, camera.camera_up_vector.z)).normalized() + x_axis = y_axis.cross(z_axis).normalized() + rotation = Matrix((x_axis, y_axis, z_axis)) + rotation.invert() + location = Vector((camera.camera_view_point.x, camera.camera_view_point.y, camera.camera_view_point.z)) + obj.matrix_world = rotation.to_4x4() + obj.location = location + return {"FINISHED"} + + def set_viewpoint_components(self, viewpoint): + if not viewpoint.components: + return + selected_global_ids = [s.ifc_guid for s in viewpoint.components.selection] + exception_global_ids = [v.ifc_guid for v in viewpoint.components.visibility.exceptions] + global_id_colours = {} + for coloring in viewpoint.components.coloring: + for component in coloring.components: + global_id_colours.setdefault(component.ifc_guid, coloring.color) + + for obj in bpy.data.objects: + global_id = obj.BIMObjectProperties.attributes.get("GlobalId") + if not global_id: + continue + global_id = global_id.string_value + is_visible = viewpoint.components.visibility.default_visibility + if global_id in exception_global_ids: + is_visible = not is_visible + if not is_visible: + obj.hide_set(True) + continue + if "IfcSpace" in obj.name: + is_visible = viewpoint.components.viewSetuphints.spacesVisible + elif "IfcOpeningElement" in obj.name: + is_visible = viewpoint.components.viewSetuphints.openingsVisible + obj.hide_set(not is_visible) + if not is_visible: + continue + obj.select_set(global_id in selected_global_ids) + if global_id in global_id_colours: + obj.color = self.hex_to_rgb(global_id_colours[global_id]) + + def draw_lines(self, viewpoint): + gp = bpy.data.grease_pencils.new("BCF") + scene = bpy.context.scene + scene.grease_pencil = gp + scene.frame_set(1) + layer = gp.layers.new("BCF Annotation", set_active=True) + layer.thickness = 3 + layer.color = (1, 0, 0) + frame = layer.frames.new(1) + stroke = frame.strokes.new() + stroke.display_mode = "3DSPACE" + stroke.points.add(len(viewpoint.lines) * 2) + coords = [] + for l in viewpoint.lines: + coords.extend([l.start_point.x, l.start_point.y, l.start_point.z, l.end_point.x, l.end_point.y, l.end_point.z]) + stroke.points.foreach_set("co", coords) + + def create_clipping_planes(self, viewpoint): + n = 0 + for plane in viewpoint.clipping_planes: + bpy.ops.bim.add_section_plane() + if n == 0: + obj = bpy.data.objects["Section"] + else: + obj = bpy.data.objects["Section.{:03d}".format(n)] + obj.location = (plane.location.x, plane.location.y, plane.location.z) + obj.rotation_mode = "QUATERNION" + obj.rotation_quaternion = Vector((plane.direction.x, plane.direction.y, plane.direction.z)).to_track_quat( + "Z", "Y" + ) + n += 1 + + def delete_clipping_planes(self): + collection = bpy.data.collections.get("Sections") + if not collection: + return + for section in collection.objects: + bpy.context.view_layer.objects.active = section + bpy.ops.bim.remove_section_plane() + + def delete_bitmaps(self): + collection = bpy.data.collections.get("Bitmaps") + if not collection: + collection = bpy.data.collections.new("Bitmaps") + bpy.context.scene.collection.children.link(collection) + for bitmap in collection.objects: + bpy.data.objects.remove(bitmap) + + def create_bitmaps(self, bcfxml, viewpoint, topic): + collection = bpy.data.collections.get("Bitmaps") + if not collection: + collection = bpy.data.collections.new("Bitmaps") + for bitmap in viewpoint.bitmaps: + obj = bpy.data.objects.new("Bitmap", None) + obj.empty_display_type = "IMAGE" + image = bpy.data.images.load(os.path.join(bcfxml.filepath, topic.guid, bitmap.reference)) + src_width = image.size[0] + src_height = image.size[1] + if src_height > src_width: + obj.empty_display_size = bitmap.height + else: + obj.empty_display_size = bitmap.height * (src_width / src_height) + obj.data = image + y = Vector((bitmap.up.x, bitmap.up.y, bitmap.up.z)) + z = Vector((bitmap.normal.x, bitmap.normal.y, bitmap.normal.z)) + x = y.cross(z) + obj.matrix_world = Matrix( + [[x[0], y[0], z[0], 0], [x[1], y[1], z[1], 0], [x[2], y[2], z[2], 0], [0, 0, 0, 1]] + ) + obj.location = (bitmap.location.x, bitmap.location.y, bitmap.location.z) + collection.objects.link(obj) + + def hex_to_rgb(self, value): + value = value.lstrip("#") + lv = len(value) + t = tuple(int(value[i : i + lv // 3], 16) for i in range(0, lv, lv // 3)) + return [t[0] / 255.0, t[1] / 255.0, t[2] / 255.0, 1] + +class OpenBcfReferenceLink(bpy.types.Operator): + bl_idname = "bim.open_bcf_reference_link" + bl_label = "Open BCF Reference Link" + index: bpy.props.IntProperty() + + def execute(self, context): + webbrowser.open(bpy.context.scene.BCFProperties.topic_links[self.index].name) + return {"FINISHED"} + + +class SelectBcfHeaderFile(bpy.types.Operator): + bl_idname = "bim.select_bcf_header_file" + bl_label = "Select BCF Header File" + filepath: bpy.props.StringProperty(subtype="FILE_PATH") + + def execute(self, context): + if self.filepath: + props = bpy.context.scene.BCFProperties + topic = props.topics[props.active_topic_index] + topic.file_reference = self.filepath + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {"RUNNING_MODAL"} + + +class SelectBcfBimSnippetReference(bpy.types.Operator): + bl_idname = "bim.select_bcf_bim_snippet_reference" + bl_label = "Select BCF BIM Snippet Reference" + filepath: bpy.props.StringProperty(subtype="FILE_PATH") + + def execute(self, context): + if self.filepath: + props = bpy.context.scene.BCFProperties + topic = props.topics[props.active_topic_index] + topic.bim_snippet_reference = self.filepath + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {"RUNNING_MODAL"} + + +class SelectBcfDocumentReference(bpy.types.Operator): + bl_idname = "bim.select_bcf_document_reference" + bl_label = "Select BCF Document Reference" + filepath: bpy.props.StringProperty(subtype="FILE_PATH") + + def execute(self, context): + if self.filepath: + props = bpy.context.scene.BCFProperties + topic = props.topics[props.active_topic_index] + topic.document_reference = self.filepath + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {"RUNNING_MODAL"} diff --git a/src/ifcblenderexport/blenderbim/bim/module/bcf/prop.py b/src/ifcblenderexport/blenderbim/bim/module/bcf/prop.py new file mode 100644 index 0000000000..8401a069f5 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/bcf/prop.py @@ -0,0 +1,150 @@ +import bpy +from . import bcfstore +from blenderbim.bim.prop import StrProperty +from bpy.types import PropertyGroup +from bpy.props import ( + PointerProperty, + StringProperty, + EnumProperty, + BoolProperty, + IntProperty, + FloatProperty, + FloatVectorProperty, + CollectionProperty, +) + + +bcfviewpoints_enum = None + + +def updateBcfReferenceLink(self, context): + bpy.ops.bim.edit_bcf_reference_links() + + +def updateBcfLabel(self, context): + bpy.ops.bim.edit_bcf_labels() + + +def updateBcfProjectName(self, context): + bpy.ops.bim.edit_bcf_project_name() + + +def updateBcfAuthor(self, context): + bpy.ops.bim.edit_bcf_author() + + +def updateBcfTopicName(self, context): + bpy.ops.bim.edit_bcf_topic_name() + + +def updateBcfTopicIsEditable(self, context): + if not self.is_editable: + bpy.ops.bim.edit_bcf_topic() + + +def updateBcfCommentIsEditable(self, context): + if not self.is_editable: + bpy.ops.bim.edit_bcf_comment(comment_guid = self.name) + + +def refreshBcfTopic(self, context): + global bcfviewpoints_enum + bcfviewpoints_enum = None + + props = bpy.context.scene.BCFProperties + bcfxml = bcfstore.BcfStore.get_bcfxml() + topic = props.topics[props.active_topic_index] + header = bcfxml.get_header(topic.name) + getBcfViewpoints(self, context) + + +class BcfReferenceLink(PropertyGroup): + name: StringProperty(name="Name", update=updateBcfReferenceLink) + + +class BcfLabel(PropertyGroup): + name: StringProperty(name="Name", update=updateBcfLabel) + + +def getBcfViewpoints(self, context): + global bcfviewpoints_enum + if bcfviewpoints_enum is None: + bcfviewpoints_enum = [] + props = bpy.context.scene.BCFProperties + bcfxml = bcfstore.BcfStore.get_bcfxml() + topic = props.topics[props.active_topic_index] + viewpoints = bcfxml.get_viewpoints(topic.name) + bcfviewpoints_enum.extend([(v, f"Viewpoint {i+1}", "") for i, v in enumerate(viewpoints.keys())]) + return bcfviewpoints_enum + + +class BcfBimSnippet(PropertyGroup): + schema: StringProperty(name="Schema") + reference: StringProperty(name="Reference") + type: StringProperty(name="Type") + is_external: BoolProperty(name="Is External") + + +class BcfDocumentReference(PropertyGroup): + reference: StringProperty(name="Reference") + description: StringProperty(name="Description") + guid: StringProperty(name="GUID") + is_external: BoolProperty(name="Is External") + + +class BcfComment(PropertyGroup): + name: StringProperty(name="GUID") + date: StringProperty(name="Date") + author: StringProperty(name="Author") + comment: StringProperty(name="Comment") + viewpoint: StringProperty(name="Viewpoint") + modified_date: StringProperty(name="Modified Date") + modified_author: StringProperty(name="Modified Author") + is_editable: BoolProperty(name="Is Editable", default=False, update=updateBcfCommentIsEditable) + + +class BcfTopic(PropertyGroup): + name: StringProperty(name="GUID") + title: StringProperty(default="", name="Title", update=updateBcfTopicName) + type: StringProperty(default="", name="Type") + status: StringProperty(default="", name="Status") + priority: StringProperty(default="", name="Priority") + stage: StringProperty(default="", name="Stage") + creation_date: StringProperty(default="", name="Date") + creation_author: StringProperty(default="", name="Author") + modified_date: StringProperty(default="", name="Modified Date") + modified_author: StringProperty(default="", name="Modified By") + assigned_to: StringProperty(default="", name="Assigned To") + due_date: StringProperty(default="", name="Due Date") + description: StringProperty(default="", name="Description") + viewpoints: EnumProperty(items=getBcfViewpoints, name="BCF Viewpoints") + files: CollectionProperty(name="Files", type=StrProperty) + file_reference: StringProperty(default="", name="Reference") + file_ifc_project: StringProperty(default="", name="IFC Project") + file_ifc_spatial_structure_element: StringProperty(default="", name="IFC Spatial Structure Element") + reference_links: CollectionProperty(name="Reference Links", type=BcfReferenceLink) + reference_link: StringProperty(default="", name="Reference Link") + labels: CollectionProperty(name="Labels", type=BcfLabel) + label: StringProperty(default="", name="Label") + bim_snippet: PointerProperty(type=BcfBimSnippet) + bim_snippet_type: StringProperty(default="", name="Type") + bim_snippet_reference: StringProperty(default="", name="Reference") + bim_snippet_schema: StringProperty(default="", name="Schema") + document_references: CollectionProperty(name="Document References", type=BcfDocumentReference) + document_reference: StringProperty(default="", name="Referenced Document") + document_reference_description: StringProperty(default="", name="Description") + related_topics: CollectionProperty(name="Related Topics", type=StrProperty) + related_topic: StringProperty(default="", name="Related Topic") + comments: CollectionProperty(name="Comments", type=BcfComment) + is_editable: BoolProperty(name="Is Editable", default=False, update=updateBcfTopicIsEditable) + comment: StringProperty(default="", name="Comment") + has_related_viewpoint: BoolProperty(name="Has Related Viewpoint", default=False) + + +class BCFProperties(PropertyGroup): + is_loaded: BoolProperty(name="Is Loaded", default=False) + comment_text_width: IntProperty(name="Comment Text Width", default=40) + name: StringProperty(default="", name="Project Name", update=updateBcfProjectName) + author: StringProperty(default="john@doe.com", name="Author Email", update=updateBcfAuthor) + topics: CollectionProperty(name="BCF Topics", type=BcfTopic) + active_topic_index: IntProperty(name="Active BCF Topic Index", update=refreshBcfTopic) diff --git a/src/ifcblenderexport/blenderbim/bim/module/bcf/ui.py b/src/ifcblenderexport/blenderbim/bim/module/bcf/ui.py new file mode 100644 index 0000000000..f2d22c08ee --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/bcf/ui.py @@ -0,0 +1,283 @@ +import os +import bpy +from . import bcfstore +from bpy.types import Panel + +class BIM_PT_bcf(Panel): + bl_label = "BIM Collaboration Format (BCF)" + bl_idname = "BIM_PT_bcf" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + props = bpy.context.scene.BCFProperties + + row = layout.row(align=True) + row.operator("bim.new_bcf_project", text="New Project") + row.operator("bim.load_bcf_project", text="Load Project") + + if not props.is_loaded: + return + + row.operator("bim.save_bcf_project", text="Save Project") + + row = layout.row() + row.prop(props, "name") + + row = layout.row() + row.prop(props, "author") + + props = bpy.context.scene.BCFProperties + row = layout.row() + row.template_list("BIM_UL_topics", "", props, "topics", props, "active_topic_index") + col = row.column(align=True) + col.operator("bim.add_bcf_topic", icon="ADD", text="") + if props.active_topic_index < len(props.topics): + topic = props.topics[props.active_topic_index] + col.prop(topic, "is_editable", icon="CHECKMARK" if topic.is_editable else "GREASEPENCIL", icon_only=True) + + if props.active_topic_index < len(props.topics): + topic = props.topics[props.active_topic_index] + row = layout.row() + row.enabled = topic.is_editable + row.prop(topic, "description", text="") + + row = layout.row() + row.prop(topic, "viewpoints") + row.operator("bim.activate_bcf_viewpoint", icon="SCENE", text="") + row.operator("bim.add_bcf_viewpoint", icon="ADD", text="") + row.operator("bim.remove_bcf_viewpoint", icon="X", text="") + + col = layout.column(align=True) + if topic.type: + col.prop(topic, "type", emboss=topic.is_editable) + if topic.status: + col.prop(topic, "status", emboss=topic.is_editable) + if topic.priority: + col.prop(topic, "priority", emboss=topic.is_editable) + if topic.stage: + col.prop(topic, "stage", emboss=topic.is_editable) + if topic.assigned_to: + col.prop(topic, "assigned_to", emboss=topic.is_editable) + if topic.due_date: + col.prop(topic, "due_date", emboss=topic.is_editable) + + col = layout.column(align=True) + if topic.modified_date: + col.prop(topic, "modified_date", emboss=False) + col.prop(topic, "modified_author", emboss=False) + else: + col.prop(topic, "creation_date", emboss=False) + col.prop(topic, "creation_author", emboss=False) + + +class BIM_PT_bcf_metadata(Panel): + bl_label = "BCF Metadata" + bl_idname = "BIM_PT_bcf_metadata" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + bl_parent_id = "BIM_PT_bcf" + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + props = bpy.context.scene.BCFProperties + + if props.active_topic_index >= len(props.topics): + layout.label(text="No BCF project is loaded") + return + + topic = props.topics[props.active_topic_index] + bcfxml = bcfstore.BcfStore.get_bcfxml() + bcf_topic = bcfxml.topics[topic.name] + + layout.label(text="Header Files:") + + if bcf_topic.header: + for index, f in enumerate(bcf_topic.header.files): + box = self.layout.box() + row = box.row(align=True) + row.label(text=f.filename, icon="FILE_BLANK") + if f.is_external: + row.operator("bim.open_uri", icon="URL", text="").uri = f.reference + else: + op = row.operator("bim.open_uri", icon="FILE_FOLDER", text="") + op.uri = os.path.join(bcfxml.filepath, topic.name, f.reference) + row.operator("bim.remove_bcf_file", icon="X", text="").index = index + + row = box.row() + row.label(text="Date") + row.label(text=f.date) + + if f.ifc_project: + row = box.row() + row.label(text="IFC Project") + row.label(text=f.ifc_project) + + if f.ifc_spatial_structure_element: + row = box.row() + row.label(text="IFC Spatial Structure Element") + row.label(text=f.ifc_spatial_structure_element) + + row = layout.row(align=True) + row.prop(topic, "file_reference") + row.operator("bim.select_bcf_header_file", icon="FILE_FOLDER", text="") + row = layout.row() + row.prop(topic, "file_ifc_project") + row = layout.row() + row.prop(topic, "file_ifc_spatial_structure_element") + + row = layout.row() + row.operator("bim.add_bcf_header_file") + + layout.label(text="Reference Links:") + for index, link in enumerate(topic.reference_links): + row = layout.row(align=True) + row.prop(link, "name") + row.operator("bim.open_uri", icon="URL", text="").uri = link.name + row.operator("bim.remove_bcf_reference_link", icon="X", text="").index = index + row = layout.row() + row.prop(topic, "reference_link") + row = layout.row() + row.operator("bim.add_bcf_reference_link") + + layout.label(text="Labels:") + for index, label in enumerate(topic.labels): + row = layout.row(align=True) + row.prop(label, "name", text="") + row.operator("bim.remove_bcf_label", icon="X", text="").index = index + row = layout.row() + row.prop(topic, "label") + row = layout.row() + row.operator("bim.add_bcf_label") + + layout.label(text="BIM Snippet:") + if topic.bim_snippet.schema: + row = layout.row(align=True) + row.prop(topic.bim_snippet, "type", emboss=False) + if topic.bim_snippet.schema: + row.operator("bim.open_uri", icon="URL", text="").uri = topic.bim_snippet.schema + + row = layout.row(align=True) + row.prop(topic.bim_snippet, "reference", emboss=False) + if topic.bim_snippet.is_external: + row.operator("bim.open_uri", icon="URL", text="").uri = topic.bim_snippet.reference + else: + op = row.operator("bim.open_uri", icon="FILE_FOLDER", text="") + op.uri = os.path.join(bcfxml.filepath, topic.name, topic.bim_snippet.reference) + row.operator("bim.remove_bcf_bim_snippet", icon="X", text="") + else: + row = layout.row(align=True) + row.prop(topic, "bim_snippet_reference") + row.operator("bim.select_bcf_bim_snippet_reference", icon="FILE_FOLDER", text="") + row = layout.row() + row.prop(topic, "bim_snippet_type") + row = layout.row() + row.prop(topic, "bim_snippet_schema") + row = layout.row() + row.operator("bim.add_bcf_bim_snippet") + + layout.label(text="Document References:") + for index, doc in enumerate(topic.document_references): + box = self.layout.box() + row = box.row(align=True) + row.prop(doc, "reference") + if doc.is_external: + row.operator("bim.open_uri", icon="URL", text="").uri = doc.reference + else: + op = row.operator("bim.open_uri", icon="FILE_FOLDER", text="") + op.uri = os.path.join(bcfxml.filepath, topic.name, doc.reference) + row.operator("bim.remove_bcf_document_reference", icon="X", text="").index = index + row = box.row(align=True) + row.prop(doc, "description") + row = layout.row(align=True) + row.prop(topic, "document_reference") + row.operator("bim.select_bcf_document_reference", icon="FILE_FOLDER", text="") + row = layout.row() + row.prop(topic, "document_reference_description") + row = layout.row() + row.operator("bim.add_bcf_document_reference") + + layout.label(text="Related Topics:") + for index, related_topic in enumerate(topic.related_topics): + row = layout.row(align=True) + row.operator("bim.view_bcf_topic", text=bcfxml.topics[related_topic.name.lower()].title).topic_guid = related_topic.name + row.operator("bim.remove_bcf_related_topic", icon="X", text="").index = index + row = layout.row() + row.prop(topic, "related_topic") + row = layout.row() + row.operator("bim.add_bcf_related_topic") + + +class BIM_PT_bcf_comments(Panel): + bl_label = "BCF Comments" + bl_idname = "BIM_PT_bcf_comments" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + bl_parent_id = "BIM_PT_bcf" + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + props = bpy.context.scene.BCFProperties + + if props.active_topic_index >= len(props.topics): + layout.label(text="No BCF project is loaded") + return + + row = layout.row() + row.prop(props, "comment_text_width") + + topic = props.topics[props.active_topic_index] + for comment in topic.comments: + box = self.layout.box() + + author_text = "{} ({})".format(comment.author, comment.date) + if comment.modified_author: + author_text = "*{} ({})".format(comment.modified_author, comment.modified_date) + row = box.row(align=True) + row.label(text=author_text, icon="WORDWRAP_ON") + row.prop( + comment, "is_editable", icon="CHECKMARK" if comment.is_editable else "GREASEPENCIL", icon_only=True + ) + row.operator("bim.remove_bcf_comment", icon="X", text="").comment_guid = comment.name + + if comment.is_editable: + row = box.row() + row.prop(comment, "comment", text="") + else: + col = box.column(align=True) + col.scale_y = 0.8 + words = comment.comment.split() + while words: + total_line_chars = 0 + line_words = [] + while words and total_line_chars < props.comment_text_width: + word = words.pop(0) + line_words.append(word) + total_line_chars += len(word) + 1 # 1 is for the space + col.label(text=" ".join(line_words)) + + row = layout.row() + row.prop(topic, "comment") + row = layout.row() + row.prop(topic, "has_related_viewpoint") + row = layout.row() + row.operator("bim.add_bcf_comment") diff --git a/src/ifcblenderexport/blenderbim/bim/module/covetool/__init__.py b/src/ifcblenderexport/blenderbim/bim/module/covetool/__init__.py new file mode 100644 index 0000000000..0113965696 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/covetool/__init__.py @@ -0,0 +1,21 @@ +import bpy +from . import ui, prop, operator + +classes = ( + prop.CoveToolProject, + prop.CoveToolSimpleAnalysis, + prop.CoveToolProperties, + ui.BIM_UL_covetool_projects, + ui.BIM_PT_covetool, + operator.Login, + operator.RunSimpleAnalysis, + operator.RunAnalysis, +) + + +def register(): + bpy.types.Scene.CoveToolProperties = bpy.props.PointerProperty(type=prop.CoveToolProperties) + + +def unregister(): + del bpy.types.Scene.CoveToolProperties diff --git a/src/ifcblenderexport/blenderbim/bim/module/model/__init__.py b/src/ifcblenderexport/blenderbim/bim/module/model/__init__.py new file mode 100644 index 0000000000..09c610553b --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/model/__init__.py @@ -0,0 +1,32 @@ +import bpy +from . import grid, wall, stair, door, window, slab, opening + +classes = ( + grid.BIM_OT_add_object, + wall.BIM_OT_add_object, + stair.BIM_OT_add_object, + door.BIM_OT_add_object, + window.BIM_OT_add_object, + slab.BIM_OT_add_object, + opening.BIM_OT_add_object, +) + + +def register(): + bpy.types.VIEW3D_MT_mesh_add.append(grid.add_object_button) + bpy.types.VIEW3D_MT_mesh_add.append(wall.add_object_button) + bpy.types.VIEW3D_MT_mesh_add.append(stair.add_object_button) + bpy.types.VIEW3D_MT_mesh_add.append(door.add_object_button) + bpy.types.VIEW3D_MT_mesh_add.append(window.add_object_button) + bpy.types.VIEW3D_MT_mesh_add.append(slab.add_object_button) + bpy.types.VIEW3D_MT_mesh_add.append(opening.add_object_button) + + +def unregister(): + bpy.types.VIEW3D_MT_mesh_add.remove(grid.add_object_button) + bpy.types.VIEW3D_MT_mesh_add.remove(wall.add_object_button) + bpy.types.VIEW3D_MT_mesh_add.remove(stair.add_object_button) + bpy.types.VIEW3D_MT_mesh_add.remove(door.add_object_button) + bpy.types.VIEW3D_MT_mesh_add.remove(window.add_object_button) + bpy.types.VIEW3D_MT_mesh_add.remove(slab.add_object_button) + bpy.types.VIEW3D_MT_mesh_add.remove(opening.add_object_button) diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index e420db8628..9b22b668ae 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -1,7 +1,6 @@ from itertools import chain import os import bpy -import bcf import uuid import time import json @@ -22,7 +21,6 @@ from . import svgwriter from . import sheeter from . import scheduler from . import schema -from . import bcfstore from . import ifc from . import annotation from . import helper @@ -522,811 +520,6 @@ class RejectElement(bpy.types.Operator): return {"FINISHED"} -class NewBcfProject(bpy.types.Operator): - bl_idname = "bim.new_bcf_project" - bl_label = "New BCF Project" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - bcfxml.new_project() - bpy.ops.bim.load_bcf_project() - return {"FINISHED"} - - -class LoadBcfProject(bpy.types.Operator): - bl_idname = "bim.load_bcf_project" - bl_label = "Load BCF Project" - filepath: bpy.props.StringProperty(subtype="FILE_PATH") - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - if self.filepath: - bcfxml.get_project(self.filepath) - bpy.context.scene.BCFProperties.name = bcfxml.project.name - bpy.ops.bim.load_bcf_topics() - bpy.context.scene.BCFProperties.is_loaded = True - return {"FINISHED"} - - def invoke(self, context, event): - context.window_manager.fileselect_add(self) - return {"RUNNING_MODAL"} - - -class LoadBcfTopics(bpy.types.Operator): - bl_idname = "bim.load_bcf_topics" - bl_label = "Load BCF Topics" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - bcfxml.get_topics() - while len(bpy.context.scene.BCFProperties.topics) > 0: - bpy.context.scene.BCFProperties.topics.remove(0) - index = 0 - for topic_guid in bcfxml.topics.keys(): - new = bpy.context.scene.BCFProperties.topics.add() - bpy.ops.bim.load_bcf_topic(topic_guid = topic_guid, topic_index = index) - index += 1 - return {"FINISHED"} - - -class LoadBcfTopic(bpy.types.Operator): - bl_idname = "bim.load_bcf_topic" - bl_label = "Load BCF Topics" - topic_guid: bpy.props.StringProperty() - topic_index: bpy.props.IntProperty() - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - topic = bcfxml.get_topic(self.topic_guid) - new = bpy.context.scene.BCFProperties.topics[self.topic_index] - data_map = { - "name": topic.guid, - "title": topic.title, - "type": topic.topic_type, - "status": topic.topic_status, - "priority": topic.priority, - "stage": topic.stage, - "creation_date": topic.creation_date, - "creation_author": topic.creation_author, - "modified_date": topic.modified_date, - "modified_author": topic.modified_author, - "assigned_to": topic.assigned_to, - "due_date": topic.due_date, - "description": topic.description - } - for key, value in data_map.items(): - if value is not None: - setattr(new, key, str(value)) - while len(new.reference_links) > 0: - new.reference_links.remove(0) - for reference_link in topic.reference_links: - new2 = new.reference_links.add() - new2.name = reference_link - while len(new.labels) > 0: - new.labels.remove(0) - for label in topic.labels: - new2 = new.labels.add() - new2.name = label - if topic.bim_snippet: - data_map = { - "type": topic.bim_snippet.snippet_type, - "is_external": topic.bim_snippet.is_external, - "reference": topic.bim_snippet.reference, - "schema": topic.bim_snippet.reference_schema - } - for key, value in data_map.items(): - if value is not None: - setattr(new.bim_snippet, key, value) - while len(new.document_references) > 0: - new.document_references.remove(0) - for doc in topic.document_references: - new2 = new.document_references.add() - data_map = { - "reference": doc.referenced_document, - "description": doc.description, - "guid": doc.guid, - "is_external": doc.is_external - } - for key, value in data_map.items(): - if value is not None: - setattr(new2, key, value) - while len(new.related_topics) > 0: - new.related_topics.remove(0) - for related_topic in topic.related_topics: - new2 = new.related_topics.add() - new2.name = related_topic.guid - bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid) - return {"FINISHED"} - - -class LoadBcfComments(bpy.types.Operator): - bl_idname = "bim.load_bcf_comments" - bl_label = "Load BCF Comments" - topic_guid: bpy.props.StringProperty() - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - bcfxml.get_comments(self.topic_guid) - blender_topic = bpy.context.scene.BCFProperties.topics.get(self.topic_guid) - while len(blender_topic.comments) > 0: - blender_topic.comments.remove(0) - for comment in bcfxml.topics[self.topic_guid].comments.values(): - new = blender_topic.comments.add() - data_map = { - "name": comment.guid, - "comment": comment.comment, - "viewpoint": comment.viewpoint.guid if comment.viewpoint else None, - "date": comment.date, - "author": comment.author, - "modified_date": comment.modified_date, - "modified_author": comment.modified_author, - } - for key, value in data_map.items(): - if value is not None: - setattr(new, key, str(value)) - return {"FINISHED"} - - -class EditBcfProjectName(bpy.types.Operator): - bl_idname = "bim.edit_bcf_project_name" - bl_label = "Edit BCF Project Name" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - bcfxml.project.name = bpy.context.scene.BCFProperties.name - bcfxml.edit_project() - return {"FINISHED"} - - -class EditBcfAuthor(bpy.types.Operator): - bl_idname = "bim.edit_bcf_author" - bl_label = "Edit BCF Author" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - bcfxml.author = bpy.context.scene.BCFProperties.author - return {"FINISHED"} - - -class EditBcfTopicName(bpy.types.Operator): - bl_idname = "bim.edit_bcf_topic_name" - bl_label = "Edit BCF Topic Name" - - def execute(self, context): - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - bcfxml = bcfstore.BcfStore.get_bcfxml() - topic = bcfxml.topics[blender_topic.name] - topic.title = blender_topic.title - bcfxml.edit_topic(topic) - return {"FINISHED"} - - -class EditBcfTopic(bpy.types.Operator): - bl_idname = "bim.edit_bcf_topic" - bl_label = "Edit BCF Topic" - - def execute(self, context): - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - bcfxml = bcfstore.BcfStore.get_bcfxml() - - topic = bcfxml.topics[blender_topic.name] - topic.title = blender_topic.title or None - topic.priority = blender_topic.priority or None - topic.due_date = blender_topic.due_date or None - topic.assigned_to = blender_topic.assigned_to or None - topic.stage = blender_topic.stage or None - topic.description = blender_topic.description or None - topic.topic_status = blender_topic.status or None - topic.topic_type = blender_topic.type or None - - bcfxml.edit_topic(topic) - props.active_topic_index = props.active_topic_index # Refreshes the BCF Topic - return {"FINISHED"} - - -class SaveBcfProject(bpy.types.Operator): - bl_idname = "bim.save_bcf_project" - bl_label = "Save BCF Project" - filepath: bpy.props.StringProperty(subtype="FILE_PATH") - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - bcfxml.save_project(self.filepath) - return {"FINISHED"} - - def invoke(self, context, event): - context.window_manager.fileselect_add(self) - return {"RUNNING_MODAL"} - - -class AddBcfTopic(bpy.types.Operator): - bl_idname = "bim.add_bcf_topic" - bl_label = "Add BCF Topic" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - bcfxml.add_topic() - new = bpy.context.scene.BCFProperties.topics.add() - new.name = "New Topic" - bpy.ops.bim.load_bcf_topics() - return {"FINISHED"} - - -class AddBcfBimSnippet(bpy.types.Operator): - bl_idname = "bim.add_bcf_bim_snippet" - bl_label = "Add BCF BIM Snippet" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - bim_snippet = bcf.data.BimSnippet() - bim_snippet.reference = blender_topic.bim_snippet_reference - bim_snippet.reference_schema = blender_topic.bim_snippet_schema - bim_snippet.snippet_type = blender_topic.bim_snippet_type - bcfxml.add_bim_snippet(topic, bim_snippet) - bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index) - return {"FINISHED"} - - -class AddBcfRelatedTopic(bpy.types.Operator): - bl_idname = "bim.add_bcf_related_topic" - bl_label = "Add BCF Related Topic" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - related_topic = None - for topic in bcfxml.topics.values(): - if topic.title == blender_topic.related_topic: - related_topic = bcf.data.RelatedTopic() - related_topic.guid = topic.guid - break - if not related_topic: - return {"FINISHED"} - topic = bcfxml.topics[blender_topic.name] - topic.related_topics.append(related_topic) - bcfxml.edit_topic(topic) - bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index) - return {"FINISHED"} - - -class AddBcfHeaderFile(bpy.types.Operator): - bl_idname = "bim.add_bcf_header_file" - bl_label = "Add BCF Header File" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - header_file = bcf.data.HeaderFile() - header_file.reference = blender_topic.file_reference - if not os.path.exists(header_file.reference): - header_file.filename = header_file.reference - if len(blender_topic.file_ifc_project) == 22: - header_file.ifc_project = blender_topic.file_ifc_project - if len(blender_topic.file_ifc_spatial_structure_element) == 22: - header_file.ifc_spatial_structure_element = blender_topic.file_ifc_spatial_structure_element - bcfxml.add_file(topic, header_file) - props.active_topic_index = props.active_topic_index # refreshes the BCF Topic - return {"FINISHED"} - - -class ViewBcfTopic(bpy.types.Operator): - bl_idname = "bim.view_bcf_topic" - bl_label = "Get BCF Topic" - topic_guid: bpy.props.StringProperty() - - def execute(self, context): - for index, topic in enumerate(bpy.context.scene.BCFProperties.topics): - if topic.guid.lower() == self.topic_guid.lower(): - bpy.context.scene.BCFProperties.active_topic_index = index - return {"FINISHED"} - - -class AddBcfViewpoint(bpy.types.Operator): - bl_idname = "bim.add_bcf_viewpoint" - bl_label = "Add BCF Viewpoint" - - def execute(self, context): - if not bpy.context.scene.camera: - return {"FINISHED"} - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - viewpoint = bcf.data.Viewpoint() - - if bpy.context.scene.camera.data.type == "ORTHO": - camera = bcf.data.OrthogonalCamera() - camera.view_to_world_scale = bpy.context.scene.camera.data.ortho_scale - viewpoint.orthogonal_camera = camera - elif bpy.context.scene.camera.data.type == "PERSP": - camera = bcf.data.PerspectiveCamera() - camera.field_of_view = degrees(bpy.context.scene.camera.data.angle) - viewpoint.perspective_camera = camera - camera.camera_view_point.x = bpy.context.scene.camera.location.x - camera.camera_view_point.y = bpy.context.scene.camera.location.y - camera.camera_view_point.z = bpy.context.scene.camera.location.z - direction = bpy.context.scene.camera.matrix_world.to_quaternion() @ Vector((0.0, 0.0, -1.0)) - camera.camera_direction.x = direction.x - camera.camera_direction.y = direction.y - camera.camera_direction.z = direction.z - up = bpy.context.scene.camera.matrix_world.to_quaternion() @ Vector((0.0, 1.0, 0.0)) - camera.camera_up_vector.x = up.x - camera.camera_up_vector.y = up.y - camera.camera_up_vector.z = up.z - - old_file_format = bpy.context.scene.render.image_settings.file_format - bpy.context.scene.render.image_settings.file_format = "PNG" - old_filepath = bpy.context.scene.render.filepath - bpy.context.scene.render.filepath = os.path.join(bpy.context.scene.BIMProperties.data_dir, "snapshot.png") - bpy.ops.render.opengl(write_still=True) - viewpoint.snapshot = bpy.context.scene.render.filepath - - bcfxml.add_viewpoint(topic, viewpoint) - bpy.context.scene.render.filepath = old_filepath - bpy.context.scene.render.image_settings.file_format = old_file_format - props.active_topic_index = props.active_topic_index # refreshes the BCF Topic - return {"FINISHED"} - - -class RemoveBcfViewpoint(bpy.types.Operator): - bl_idname = "bim.remove_bcf_viewpoint" - bl_label = "Remove BCF Viewpoint" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - viewpoint_guid = blender_topic.viewpoints - topic = bcfxml.topics[blender_topic.name] - bcfxml.delete_viewpoint(viewpoint_guid, topic) - props.active_topic_index = props.active_topic_index # Refreshes the BCF Topic - return {"FINISHED"} - - -class RemoveBcfFile(bpy.types.Operator): - bl_idname = "bim.remove_bcf_file" - bl_label = "Remove BCF File" - index: bpy.props.IntProperty() - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - bcfxml.delete_file(topic, self.index) - props.active_topic_index = props.active_topic_index # Refreshes the BCF Topic - return {"FINISHED"} - - -class AddBcfReferenceLink(bpy.types.Operator): - bl_idname = "bim.add_bcf_reference_link" - bl_label = "Add BCF Reference Link" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - if not blender_topic.reference_link: - return {"FINISHED"} - topic.reference_links.append(blender_topic.reference_link) - bcfxml.edit_topic(topic) - bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index) - blender_topic.reference_link = "" - return {"FINISHED"} - - -class AddBcfDocumentReference(bpy.types.Operator): - bl_idname = "bim.add_bcf_document_reference" - bl_label = "Add BCF Document Reference" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - if not blender_topic.document_reference: - return {"FINISHED"} - document_reference = bcf.data.DocumentReference() - document_reference.referenced_document = blender_topic.document_reference - document_reference.description = blender_topic.document_reference_description or None - bcfxml.add_document_reference(topic, document_reference) - bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index) - blender_topic.document_reference = "" - blender_topic.document_reference_description = "" - return {"FINISHED"} - - -class AddBcfLabel(bpy.types.Operator): - bl_idname = "bim.add_bcf_label" - bl_label = "Add BCF Label" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - if not blender_topic.label: - return {"FINISHED"} - new = blender_topic.labels.add() - new.name = blender_topic.label - topic.labels.append(blender_topic.label) - bcfxml.edit_topic(topic) - blender_topic.label = "" - return {"FINISHED"} - - -class EditBcfReferenceLinks(bpy.types.Operator): - bl_idname = "bim.edit_bcf_reference_links" - bl_label = "Edit BCF Reference Link" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - for index, reference_link in enumerate(topic.reference_links): - if reference_link == blender_topic.reference_links[index].name: - continue - topic.reference_links[index] = blender_topic.reference_links[index].name - bcfxml.edit_topic(topic) - return {"FINISHED"} - - -class EditBcfLabels(bpy.types.Operator): - bl_idname = "bim.edit_bcf_labels" - bl_label = "Edit BCF Labels" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - for index, label in enumerate(blender_topic.labels): - if label.name == topic.labels[index]: - continue - topic.labels[index] = blender_topic.labels[index].name - bcfxml.edit_topic(topic) - return {"FINISHED"} - - -class RemoveBcfReferenceLink(bpy.types.Operator): - bl_idname = "bim.remove_bcf_reference_link" - bl_label = "Remove BCF Reference Link" - index: bpy.props.IntProperty() - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - del topic.reference_links[self.index] - bcfxml.edit_topic(topic) - blender_topic.reference_links.remove(self.index) - return {"FINISHED"} - - -class RemoveBcfLabel(bpy.types.Operator): - bl_idname = "bim.remove_bcf_label" - bl_label = "Remove BCF Label" - index: bpy.props.IntProperty() - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - del topic.labels[self.index] - bcfxml.edit_topic(topic) - blender_topic.labels.remove(self.index) - return {"FINISHED"} - - -class RemoveBcfBimSnippet(bpy.types.Operator): - bl_idname = "bim.remove_bcf_bim_snippet" - bl_label = "Remove BCF BIM Snippet" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - bcfxml.delete_bim_snippet(topic) - blender_topic.bim_snippet.schema = "" - blender_topic.bim_snippet.reference = "" - blender_topic.bim_snippet.type = "" - return {"FINISHED"} - - -class RemoveBcfDocumentReference(bpy.types.Operator): - bl_idname = "bim.remove_bcf_document_reference" - bl_label = "Remove BCF Document Reference" - index: bpy.props.IntProperty() - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - bcfxml.delete_document_reference(topic, self.index) - bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index) - return {"FINISHED"} - - -class RemoveBcfRelatedTopic(bpy.types.Operator): - bl_idname = "bim.remove_bcf_related_topic" - bl_label = "Remove BCF Related Topic" - index: bpy.props.IntProperty() - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - del topic.related_topics[self.index] - bcfxml.edit_topic(topic) - bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index) - return {"FINISHED"} - - -class RemoveBcfComment(bpy.types.Operator): - bl_idname = "bim.remove_bcf_comment" - bl_label = "Remove BCF Comment" - comment_guid: bpy.props.StringProperty() - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - bcfxml.delete_comment(self.comment_guid, topic) - bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid) - return {"FINISHED"} - - -class EditBcfComment(bpy.types.Operator): - bl_idname = "bim.edit_bcf_comment" - bl_label = "Edit BCF Comment" - comment_guid: bpy.props.StringProperty() - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - blender_comment = blender_topic.comments.get(self.comment_guid) - topic = bcfxml.topics[blender_topic.name] - comment = topic.comments[self.comment_guid] - comment.comment = blender_comment.comment - bcfxml.edit_comment(comment, topic) - bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid) - return {"FINISHED"} - - -class AddBcfComment(bpy.types.Operator): - bl_idname = "bim.add_bcf_comment" - bl_label = "Add BCF Comment" - comment_guid: bpy.props.StringProperty() - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - if not blender_topic.comment: - return {"FINISHED"} - comment = bcf.data.Comment() - comment.comment = blender_topic.comment - if blender_topic.has_related_viewpoint and blender_topic.viewpoints: - comment.viewpoint = bcf.data.Viewpoint() - comment.viewpoint.guid = blender_topic.viewpoints - bcfxml.add_comment(topic, comment) - bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid) - print(bcfxml.filepath) - return {"FINISHED"} - - -class ActivateBcfViewpoint(bpy.types.Operator): - bl_idname = "bim.activate_bcf_viewpoint" - bl_label = "Activate BCF Viewpoint" - - def execute(self, context): - bcfxml = bcfstore.BcfStore.get_bcfxml() - props = bpy.context.scene.BCFProperties - blender_topic = props.topics[props.active_topic_index] - topic = bcfxml.topics[blender_topic.name] - if not topic.viewpoints: - return {"FINISHED"} - - viewpoint_guid = blender_topic.viewpoints - viewpoint = topic.viewpoints[viewpoint_guid] - obj = bpy.data.objects.get("Viewpoint") - if not obj: - obj = bpy.data.objects.new("Viewpoint", bpy.data.cameras.new("Viewpoint")) - bpy.context.scene.collection.objects.link(obj) - bpy.context.scene.camera = obj - - cam_width = bpy.context.scene.render.resolution_x - cam_height = bpy.context.scene.render.resolution_y - cam_aspect = cam_width / cam_height - - if viewpoint.snapshot: - obj.data.show_background_images = True - while len(obj.data.background_images) > 0: - obj.data.background_images.remove(obj.data.background_images[0]) - background = obj.data.background_images.new() - background.image = bpy.data.images.load( - os.path.join(bcfxml.filepath, topic.guid, viewpoint.snapshot) - ) - src_width = background.image.size[0] - src_height = background.image.size[1] - src_aspect = src_width / src_height - - if src_aspect > cam_aspect: - background.frame_method = "FIT" - else: - background.frame_method = "CROP" - background.display_depth = "FRONT" - area = next(area for area in bpy.context.screen.areas if area.type == "VIEW_3D") - area.spaces[0].region_3d.view_perspective = "CAMERA" - - if viewpoint.orthogonal_camera: - camera = viewpoint.orthogonal_camera - obj.data.type = "ORTHO" - obj.data.ortho_scale = viewpoint.orthogonal_camera.view_to_world_scale - elif viewpoint.perspective_camera: - camera = viewpoint.perspective_camera - obj.data.type = "PERSP" - if cam_aspect >= 1: - obj.data.angle = radians(camera.field_of_view) - else: - # https://blender.stackexchange.com/questions/23431/how-to-set-camera-horizontal-and-vertical-fov - obj.data.angle = 2 * atan((0.5 * cam_height) / (0.5 * cam_width / tan(radians(camera.field_of_view) / 2))) - - self.set_viewpoint_components(viewpoint) - - gp = bpy.data.grease_pencils.get("BCF") - if gp: - bpy.data.grease_pencils.remove(gp) - if viewpoint.lines: - self.draw_lines(viewpoint) - - self.delete_clipping_planes() - if viewpoint.clipping_planes: - self.create_clipping_planes(viewpoint) - - self.delete_bitmaps() - if viewpoint.bitmaps: - self.create_bitmaps(bcfxml, viewpoint, topic) - - z_axis = Vector((-camera.camera_direction.x, -camera.camera_direction.y, -camera.camera_direction.z)).normalized() - y_axis = Vector((camera.camera_up_vector.x, camera.camera_up_vector.y, camera.camera_up_vector.z)).normalized() - x_axis = y_axis.cross(z_axis).normalized() - rotation = Matrix((x_axis, y_axis, z_axis)) - rotation.invert() - location = Vector((camera.camera_view_point.x, camera.camera_view_point.y, camera.camera_view_point.z)) - obj.matrix_world = rotation.to_4x4() - obj.location = location - return {"FINISHED"} - - def set_viewpoint_components(self, viewpoint): - if not viewpoint.components: - return - selected_global_ids = [s.ifc_guid for s in viewpoint.components.selection] - exception_global_ids = [v.ifc_guid for v in viewpoint.components.visibility.exceptions] - global_id_colours = {} - for coloring in viewpoint.components.coloring: - for component in coloring.components: - global_id_colours.setdefault(component.ifc_guid, coloring.color) - - for obj in bpy.data.objects: - global_id = obj.BIMObjectProperties.attributes.get("GlobalId") - if not global_id: - continue - global_id = global_id.string_value - is_visible = viewpoint.components.visibility.default_visibility - if global_id in exception_global_ids: - is_visible = not is_visible - if not is_visible: - obj.hide_set(True) - continue - if "IfcSpace" in obj.name: - is_visible = viewpoint.components.viewSetuphints.spacesVisible - elif "IfcOpeningElement" in obj.name: - is_visible = viewpoint.components.viewSetuphints.openingsVisible - obj.hide_set(not is_visible) - if not is_visible: - continue - obj.select_set(global_id in selected_global_ids) - if global_id in global_id_colours: - obj.color = self.hex_to_rgb(global_id_colours[global_id]) - - def draw_lines(self, viewpoint): - gp = bpy.data.grease_pencils.new("BCF") - scene = bpy.context.scene - scene.grease_pencil = gp - scene.frame_set(1) - layer = gp.layers.new("BCF Annotation", set_active=True) - layer.thickness = 3 - layer.color = (1, 0, 0) - frame = layer.frames.new(1) - stroke = frame.strokes.new() - stroke.display_mode = "3DSPACE" - stroke.points.add(len(viewpoint.lines) * 2) - coords = [] - for l in viewpoint.lines: - coords.extend([l.start_point.x, l.start_point.y, l.start_point.z, l.end_point.x, l.end_point.y, l.end_point.z]) - stroke.points.foreach_set("co", coords) - - def create_clipping_planes(self, viewpoint): - n = 0 - for plane in viewpoint.clipping_planes: - bpy.ops.bim.add_section_plane() - if n == 0: - obj = bpy.data.objects["Section"] - else: - obj = bpy.data.objects["Section.{:03d}".format(n)] - obj.location = (plane.location.x, plane.location.y, plane.location.z) - obj.rotation_mode = "QUATERNION" - obj.rotation_quaternion = Vector((plane.direction.x, plane.direction.y, plane.direction.z)).to_track_quat( - "Z", "Y" - ) - n += 1 - - def delete_clipping_planes(self): - collection = bpy.data.collections.get("Sections") - if not collection: - return - for section in collection.objects: - bpy.context.view_layer.objects.active = section - bpy.ops.bim.remove_section_plane() - - def delete_bitmaps(self): - collection = bpy.data.collections.get("Bitmaps") - if not collection: - collection = bpy.data.collections.new("Bitmaps") - bpy.context.scene.collection.children.link(collection) - for bitmap in collection.objects: - bpy.data.objects.remove(bitmap) - - def create_bitmaps(self, bcfxml, viewpoint, topic): - collection = bpy.data.collections.get("Bitmaps") - if not collection: - collection = bpy.data.collections.new("Bitmaps") - for bitmap in viewpoint.bitmaps: - obj = bpy.data.objects.new("Bitmap", None) - obj.empty_display_type = "IMAGE" - image = bpy.data.images.load(os.path.join(bcfxml.filepath, topic.guid, bitmap.reference)) - src_width = image.size[0] - src_height = image.size[1] - if src_height > src_width: - obj.empty_display_size = bitmap.height - else: - obj.empty_display_size = bitmap.height * (src_width / src_height) - obj.data = image - y = Vector((bitmap.up.x, bitmap.up.y, bitmap.up.z)) - z = Vector((bitmap.normal.x, bitmap.normal.y, bitmap.normal.z)) - x = y.cross(z) - obj.matrix_world = Matrix( - [[x[0], y[0], z[0], 0], [x[1], y[1], z[1], 0], [x[2], y[2], z[2], 0], [0, 0, 0, 1]] - ) - obj.location = (bitmap.location.x, bitmap.location.y, bitmap.location.z) - collection.objects.link(obj) - - def hex_to_rgb(self, value): - value = value.lstrip("#") - lv = len(value) - t = tuple(int(value[i : i + lv // 3], 16) for i in range(0, lv, lv // 3)) - return [t[0] / 255.0, t[1] / 255.0, t[2] / 255.0, 1] - - class OpenUri(bpy.types.Operator): bl_idname = "bim.open_uri" bl_label = "Open URI" @@ -1337,16 +530,6 @@ class OpenUri(bpy.types.Operator): return {"FINISHED"} -class OpenBcfReferenceLink(bpy.types.Operator): - bl_idname = "bim.open_bcf_reference_link" - bl_label = "Open BCF Reference Link" - index: bpy.props.IntProperty() - - def execute(self, context): - webbrowser.open(bpy.context.scene.BCFProperties.topic_links[self.index].name) - return {"FINISHED"} - - class SelectAudited(bpy.types.Operator): bl_idname = "bim.select_audited" bl_label = "Select Audited" @@ -2566,57 +1749,6 @@ class SelectSmartGroup(bpy.types.Operator): return {"FINISHED"} -class SelectBcfHeaderFile(bpy.types.Operator): - bl_idname = "bim.select_bcf_header_file" - bl_label = "Select BCF Header File" - filepath: bpy.props.StringProperty(subtype="FILE_PATH") - - def execute(self, context): - if self.filepath: - props = bpy.context.scene.BCFProperties - topic = props.topics[props.active_topic_index] - topic.file_reference = self.filepath - return {"FINISHED"} - - def invoke(self, context, event): - context.window_manager.fileselect_add(self) - return {"RUNNING_MODAL"} - - -class SelectBcfBimSnippetReference(bpy.types.Operator): - bl_idname = "bim.select_bcf_bim_snippet_reference" - bl_label = "Select BCF BIM Snippet Reference" - filepath: bpy.props.StringProperty(subtype="FILE_PATH") - - def execute(self, context): - if self.filepath: - props = bpy.context.scene.BCFProperties - topic = props.topics[props.active_topic_index] - topic.bim_snippet_reference = self.filepath - return {"FINISHED"} - - def invoke(self, context, event): - context.window_manager.fileselect_add(self) - return {"RUNNING_MODAL"} - - -class SelectBcfDocumentReference(bpy.types.Operator): - bl_idname = "bim.select_bcf_document_reference" - bl_label = "Select BCF Document Reference" - filepath: bpy.props.StringProperty(subtype="FILE_PATH") - - def execute(self, context): - if self.filepath: - props = bpy.context.scene.BCFProperties - topic = props.topics[props.active_topic_index] - topic.document_reference = self.filepath - return {"FINISHED"} - - def invoke(self, context, event): - context.window_manager.fileselect_add(self) - return {"RUNNING_MODAL"} - - class SelectFeaturesDir(bpy.types.Operator): bl_idname = "bim.select_features_dir" bl_label = "Select Features Directory" @@ -2981,6 +2113,25 @@ class OpenView(bpy.types.Operator): return {"FINISHED"} +class OpenViewCamera(bpy.types.Operator): + bl_idname = "bim.open_view_camera" + bl_label = "Open View Camera" + view_name: bpy.props.StringProperty() + + def execute(self, context): + new_drawing_index = bpy.context.scene.DocProperties.drawings.find(self.view_name) + bpy.context.scene.DocProperties.active_drawing_index = new_drawing_index + drawing = bpy.context.scene.DocProperties.drawings[new_drawing_index] + bpy.context.view_layer.objects.active = drawing.camera + bpy.ops.object.select_all(action="DESELECT") + drawing.camera.select_set(True) + for area in bpy.context.screen.areas: + if area.ui_type == "PROPERTIES": + for space in area.spaces: + space.context = "DATA" + return {"FINISHED"} + + class CutSection(bpy.types.Operator): bl_idname = "bim.cut_section" bl_label = "Cut Section" diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index 64d2b61907..2f5e19e6f2 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -5,7 +5,6 @@ import ifcopenshell.util.pset from pathlib import Path from . import export_ifc from . import schema -from . import bcfstore from . import ifc from . import annotation from . import decoration @@ -52,7 +51,6 @@ persons_enum = [] organisations_enum = [] sheets_enum = [] vector_styles_enum = [] -bcfviewpoints_enum = None @persistent @@ -167,14 +165,6 @@ def refreshPredefinedTypes(self, context): context.scene.BIMProperties.ifc_predefined_type = enum[0][0] -def updateBcfReferenceLink(self, context): - bpy.ops.bim.edit_bcf_reference_links() - - -def updateBcfLabel(self, context): - bpy.ops.bim.edit_bcf_labels() - - def getDiagramScales(self, context): global diagram_scales_enum if ( @@ -562,47 +552,6 @@ def refreshFontSize(self, context): annotation.Annotator.resize_text(context.active_object) -def updateBcfProjectName(self, context): - bpy.ops.bim.edit_bcf_project_name() - - -def updateBcfAuthor(self, context): - bpy.ops.bim.edit_bcf_author() - - -def updateBcfTopicName(self, context): - bpy.ops.bim.edit_bcf_topic_name() - - -def updateBcfTopicIsEditable(self, context): - if not self.is_editable: - bpy.ops.bim.edit_bcf_topic() - - -def updateBcfCommentIsEditable(self, context): - if not self.is_editable: - bpy.ops.bim.edit_bcf_comment(comment_guid = self.name) - - -def refreshBcfTopic(self, context): - global bcfviewpoints_enum - bcfviewpoints_enum = None - - props = bpy.context.scene.BCFProperties - bcfxml = bcfstore.BcfStore.get_bcfxml() - topic = props.topics[props.active_topic_index] - header = bcfxml.get_header(topic.name) - getBcfViewpoints(self, context) - - -class BcfReferenceLink(PropertyGroup): - name: StringProperty(name="Name", update=updateBcfReferenceLink) - - -class BcfLabel(PropertyGroup): - name: StringProperty(name="Name", update=updateBcfLabel) - - class StrProperty(PropertyGroup): pass @@ -976,81 +925,6 @@ class Constraint(PropertyGroup): user_defined_qualifier: StringProperty(name="Custom Qualifier") -def getBcfViewpoints(self, context): - global bcfviewpoints_enum - if bcfviewpoints_enum is None: - bcfviewpoints_enum = [] - props = bpy.context.scene.BCFProperties - bcfxml = bcfstore.BcfStore.get_bcfxml() - topic = props.topics[props.active_topic_index] - viewpoints = bcfxml.get_viewpoints(topic.name) - bcfviewpoints_enum.extend([(v, f"Viewpoint {i+1}", "") for i, v in enumerate(viewpoints.keys())]) - return bcfviewpoints_enum - - -class BcfBimSnippet(PropertyGroup): - schema: StringProperty(name="Schema") - reference: StringProperty(name="Reference") - type: StringProperty(name="Type") - is_external: BoolProperty(name="Is External") - - -class BcfDocumentReference(PropertyGroup): - reference: StringProperty(name="Reference") - description: StringProperty(name="Description") - guid: StringProperty(name="GUID") - is_external: BoolProperty(name="Is External") - - -class BcfComment(PropertyGroup): - name: StringProperty(name="GUID") - date: StringProperty(name="Date") - author: StringProperty(name="Author") - comment: StringProperty(name="Comment") - viewpoint: StringProperty(name="Viewpoint") - modified_date: StringProperty(name="Modified Date") - modified_author: StringProperty(name="Modified Author") - is_editable: BoolProperty(name="Is Editable", default=False, update=updateBcfCommentIsEditable) - - -class BcfTopic(PropertyGroup): - name: StringProperty(name="GUID") - title: StringProperty(default="", name="Title", update=updateBcfTopicName) - type: StringProperty(default="", name="Type") - status: StringProperty(default="", name="Status") - priority: StringProperty(default="", name="Priority") - stage: StringProperty(default="", name="Stage") - creation_date: StringProperty(default="", name="Date") - creation_author: StringProperty(default="", name="Author") - modified_date: StringProperty(default="", name="Modified Date") - modified_author: StringProperty(default="", name="Modified By") - assigned_to: StringProperty(default="", name="Assigned To") - due_date: StringProperty(default="", name="Due Date") - description: StringProperty(default="", name="Description") - viewpoints: EnumProperty(items=getBcfViewpoints, name="BCF Viewpoints") - files: CollectionProperty(name="Files", type=StrProperty) - file_reference: StringProperty(default="", name="Reference") - file_ifc_project: StringProperty(default="", name="IFC Project") - file_ifc_spatial_structure_element: StringProperty(default="", name="IFC Spatial Structure Element") - reference_links: CollectionProperty(name="Reference Links", type=BcfReferenceLink) - reference_link: StringProperty(default="", name="Reference Link") - labels: CollectionProperty(name="Labels", type=BcfLabel) - label: StringProperty(default="", name="Label") - bim_snippet: PointerProperty(type=BcfBimSnippet) - bim_snippet_type: StringProperty(default="", name="Type") - bim_snippet_reference: StringProperty(default="", name="Reference") - bim_snippet_schema: StringProperty(default="", name="Schema") - document_references: CollectionProperty(name="Document References", type=BcfDocumentReference) - document_reference: StringProperty(default="", name="Referenced Document") - document_reference_description: StringProperty(default="", name="Description") - related_topics: CollectionProperty(name="Related Topics", type=StrProperty) - related_topic: StringProperty(default="", name="Related Topic") - comments: CollectionProperty(name="Comments", type=BcfComment) - is_editable: BoolProperty(name="Is Editable", default=False, update=updateBcfTopicIsEditable) - comment: StringProperty(default="", name="Comment") - has_related_viewpoint: BoolProperty(name="Has Related Viewpoint", default=False) - - class PropertySetTemplate(PropertyGroup): global_id: StringProperty(name="Global ID") name: StringProperty(name="Name") @@ -1562,15 +1436,6 @@ class BIMProperties(PropertyGroup): presentation_layers: CollectionProperty(name="Presentation Layers", type=PresentationLayer) -class BCFProperties(PropertyGroup): - is_loaded: BoolProperty(name="Is Loaded", default=False) - comment_text_width: IntProperty(name="Comment Text Width", default=40) - name: StringProperty(default="", name="Project Name", update=updateBcfProjectName) - author: StringProperty(default="john@doe.com", name="Author Email", update=updateBcfAuthor) - topics: CollectionProperty(name="BCF Topics", type=BcfTopic) - active_topic_index: IntProperty(name="Active BCF Topic Index", update=refreshBcfTopic) - - class MapConversion(PropertyGroup): eastings: StringProperty(name="Eastings") northings: StringProperty(name="Northings") diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index d00b48ba97..7537e5731f 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -1,6 +1,5 @@ import os import bpy -from . import bcfstore from bpy.types import Panel from bpy.props import StringProperty @@ -1652,286 +1651,6 @@ class BIM_PT_ifccsv(Panel): row.operator("bim.import_ifccsv", icon="IMPORT") -class BIM_PT_bcf(Panel): - bl_label = "BIM Collaboration Format (BCF)" - bl_idname = "BIM_PT_bcf" - bl_options = {"DEFAULT_CLOSED"} - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_context = "scene" - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - layout.use_property_decorate = False - - scene = context.scene - props = bpy.context.scene.BCFProperties - - row = layout.row(align=True) - row.operator("bim.new_bcf_project", text="New Project") - row.operator("bim.load_bcf_project", text="Load Project") - - if not props.is_loaded: - return - - row.operator("bim.save_bcf_project", text="Save Project") - - row = layout.row() - row.prop(props, "name") - - row = layout.row() - row.prop(props, "author") - - props = bpy.context.scene.BCFProperties - row = layout.row() - row.template_list("BIM_UL_topics", "", props, "topics", props, "active_topic_index") - col = row.column(align=True) - col.operator("bim.add_bcf_topic", icon="ADD", text="") - if props.active_topic_index < len(props.topics): - topic = props.topics[props.active_topic_index] - col.prop(topic, "is_editable", icon="CHECKMARK" if topic.is_editable else "GREASEPENCIL", icon_only=True) - - if props.active_topic_index < len(props.topics): - topic = props.topics[props.active_topic_index] - row = layout.row() - row.enabled = topic.is_editable - row.prop(topic, "description", text="") - - row = layout.row() - row.prop(topic, "viewpoints") - row.operator("bim.activate_bcf_viewpoint", icon="SCENE", text="") - row.operator("bim.add_bcf_viewpoint", icon="ADD", text="") - row.operator("bim.remove_bcf_viewpoint", icon="X", text="") - - col = layout.column(align=True) - if topic.type: - col.prop(topic, "type", emboss=topic.is_editable) - if topic.status: - col.prop(topic, "status", emboss=topic.is_editable) - if topic.priority: - col.prop(topic, "priority", emboss=topic.is_editable) - if topic.stage: - col.prop(topic, "stage", emboss=topic.is_editable) - if topic.assigned_to: - col.prop(topic, "assigned_to", emboss=topic.is_editable) - if topic.due_date: - col.prop(topic, "due_date", emboss=topic.is_editable) - - col = layout.column(align=True) - if topic.modified_date: - col.prop(topic, "modified_date", emboss=False) - col.prop(topic, "modified_author", emboss=False) - else: - col.prop(topic, "creation_date", emboss=False) - col.prop(topic, "creation_author", emboss=False) - - -class BIM_PT_bcf_metadata(Panel): - bl_label = "BCF Metadata" - bl_idname = "BIM_PT_bcf_metadata" - bl_options = {"DEFAULT_CLOSED"} - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_context = "scene" - bl_parent_id = "BIM_PT_bcf" - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - layout.use_property_decorate = False - - scene = context.scene - props = bpy.context.scene.BCFProperties - - if props.active_topic_index >= len(props.topics): - layout.label(text="No BCF project is loaded") - return - - topic = props.topics[props.active_topic_index] - bcfxml = bcfstore.BcfStore.get_bcfxml() - bcf_topic = bcfxml.topics[topic.name] - - layout.label(text="Header Files:") - - if bcf_topic.header: - for index, f in enumerate(bcf_topic.header.files): - box = self.layout.box() - row = box.row(align=True) - row.label(text=f.filename, icon="FILE_BLANK") - if f.is_external: - row.operator("bim.open_uri", icon="URL", text="").uri = f.reference - else: - op = row.operator("bim.open_uri", icon="FILE_FOLDER", text="") - op.uri = os.path.join(bcfxml.filepath, topic.name, f.reference) - row.operator("bim.remove_bcf_file", icon="X", text="").index = index - - row = box.row() - row.label(text="Date") - row.label(text=f.date) - - if f.ifc_project: - row = box.row() - row.label(text="IFC Project") - row.label(text=f.ifc_project) - - if f.ifc_spatial_structure_element: - row = box.row() - row.label(text="IFC Spatial Structure Element") - row.label(text=f.ifc_spatial_structure_element) - - row = layout.row(align=True) - row.prop(topic, "file_reference") - row.operator("bim.select_bcf_header_file", icon="FILE_FOLDER", text="") - row = layout.row() - row.prop(topic, "file_ifc_project") - row = layout.row() - row.prop(topic, "file_ifc_spatial_structure_element") - - row = layout.row() - row.operator("bim.add_bcf_header_file") - - layout.label(text="Reference Links:") - for index, link in enumerate(topic.reference_links): - row = layout.row(align=True) - row.prop(link, "name") - row.operator("bim.open_uri", icon="URL", text="").uri = link.name - row.operator("bim.remove_bcf_reference_link", icon="X", text="").index = index - row = layout.row() - row.prop(topic, "reference_link") - row = layout.row() - row.operator("bim.add_bcf_reference_link") - - layout.label(text="Labels:") - for index, label in enumerate(topic.labels): - row = layout.row(align=True) - row.prop(label, "name", text="") - row.operator("bim.remove_bcf_label", icon="X", text="").index = index - row = layout.row() - row.prop(topic, "label") - row = layout.row() - row.operator("bim.add_bcf_label") - - layout.label(text="BIM Snippet:") - if topic.bim_snippet.schema: - row = layout.row(align=True) - row.prop(topic.bim_snippet, "type", emboss=False) - if topic.bim_snippet.schema: - row.operator("bim.open_uri", icon="URL", text="").uri = topic.bim_snippet.schema - - row = layout.row(align=True) - row.prop(topic.bim_snippet, "reference", emboss=False) - if topic.bim_snippet.is_external: - row.operator("bim.open_uri", icon="URL", text="").uri = topic.bim_snippet.reference - else: - op = row.operator("bim.open_uri", icon="FILE_FOLDER", text="") - op.uri = os.path.join(bcfxml.filepath, topic.name, topic.bim_snippet.reference) - row.operator("bim.remove_bcf_bim_snippet", icon="X", text="") - else: - row = layout.row(align=True) - row.prop(topic, "bim_snippet_reference") - row.operator("bim.select_bcf_bim_snippet_reference", icon="FILE_FOLDER", text="") - row = layout.row() - row.prop(topic, "bim_snippet_type") - row = layout.row() - row.prop(topic, "bim_snippet_schema") - row = layout.row() - row.operator("bim.add_bcf_bim_snippet") - - layout.label(text="Document References:") - for index, doc in enumerate(topic.document_references): - box = self.layout.box() - row = box.row(align=True) - row.prop(doc, "reference") - if doc.is_external: - row.operator("bim.open_uri", icon="URL", text="").uri = doc.reference - else: - op = row.operator("bim.open_uri", icon="FILE_FOLDER", text="") - op.uri = os.path.join(bcfxml.filepath, topic.name, doc.reference) - row.operator("bim.remove_bcf_document_reference", icon="X", text="").index = index - row = box.row(align=True) - row.prop(doc, "description") - row = layout.row(align=True) - row.prop(topic, "document_reference") - row.operator("bim.select_bcf_document_reference", icon="FILE_FOLDER", text="") - row = layout.row() - row.prop(topic, "document_reference_description") - row = layout.row() - row.operator("bim.add_bcf_document_reference") - - layout.label(text="Related Topics:") - for index, related_topic in enumerate(topic.related_topics): - row = layout.row(align=True) - row.operator("bim.view_bcf_topic", text=bcfxml.topics[related_topic.name.lower()].title).topic_guid = related_topic.name - row.operator("bim.remove_bcf_related_topic", icon="X", text="").index = index - row = layout.row() - row.prop(topic, "related_topic") - row = layout.row() - row.operator("bim.add_bcf_related_topic") - - -class BIM_PT_bcf_comments(Panel): - bl_label = "BCF Comments" - bl_idname = "BIM_PT_bcf_comments" - bl_options = {"DEFAULT_CLOSED"} - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_context = "scene" - bl_parent_id = "BIM_PT_bcf" - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - layout.use_property_decorate = False - - scene = context.scene - props = bpy.context.scene.BCFProperties - - if props.active_topic_index >= len(props.topics): - layout.label(text="No BCF project is loaded") - return - - row = layout.row() - row.prop(props, "comment_text_width") - - topic = props.topics[props.active_topic_index] - for comment in topic.comments: - box = self.layout.box() - - author_text = "{} ({})".format(comment.author, comment.date) - if comment.modified_author: - author_text = "*{} ({})".format(comment.modified_author, comment.modified_date) - row = box.row(align=True) - row.label(text=author_text, icon="WORDWRAP_ON") - row.prop( - comment, "is_editable", icon="CHECKMARK" if comment.is_editable else "GREASEPENCIL", icon_only=True - ) - row.operator("bim.remove_bcf_comment", icon="X", text="").comment_guid = comment.name - - if comment.is_editable: - row = box.row() - row.prop(comment, "comment", text="") - else: - col = box.column(align=True) - col.scale_y = 0.8 - words = comment.comment.split() - while words: - total_line_chars = 0 - line_words = [] - while words and total_line_chars < props.comment_text_width: - word = words.pop(0) - line_words.append(word) - total_line_chars += len(word) + 1 # 1 is for the space - col.label(text=" ".join(line_words)) - - row = layout.row() - row.prop(topic, "comment") - row = layout.row() - row.prop(topic, "has_related_viewpoint") - row = layout.row() - row.operator("bim.add_bcf_comment") - - class BIM_PT_qa(Panel): bl_label = "BIMTester Quality Auditing" bl_idname = "BIM_PT_qa" @@ -2259,6 +1978,17 @@ class BIM_UL_generic(bpy.types.UIList): layout.label(text="", translate=False) +class BIM_UL_drawinglist(bpy.types.UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + if item: + row = layout.row(align=True) + row.prop(item, "name", text="", emboss=False) + op = row.operator("bim.open_view_camera", icon="OUTLINER_OB_CAMERA", text="") + op.view_name = item.name + else: + layout.label(text="", translate=False) + + class BIM_UL_topics(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): ob = data @@ -2529,7 +2259,7 @@ class BIM_PT_annotation_utilities(Panel): op = row.operator("bim.open_view", icon="URL", text="") op.view = props.drawings[props.active_drawing_index].name row.operator("bim.remove_drawing", icon="X", text="").index = props.active_drawing_index - layout.template_list("BIM_UL_generic", "", props, "drawings", props, "active_drawing_index") + layout.template_list("BIM_UL_drawinglist", "", props, "drawings", props, "active_drawing_index") layout.prop(props, "should_draw_decorations") layout.prop(props, "decorations_colour")